2010-10-04 16 views
27

Voici un générateur simple en C#.Qu'est-ce qu'un équivalent «yield return» dans le langage de programmation D?

IEnumerable<int> Foo() 
    { 
     int a = 1, b = 1; 
     while(true) 
     { 
      yield return b; 
      int temp = a + b; 
      a = b; 
      b = temp; 
     } 
    } 

Comment puis-je écrire un générateur similaire dans Digital Mars D?

(La question est au sujet de la déclaration de retour de rendement )

Merci!


Mise à jour. C'est intéressant. Comme je ne fais que générer une séquence mathématique, utiliser recurrence peut être une bonne option.

auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1); 

foreach (e; take(fib, 10)) // <- prints first ten numbers from the sequence 
{ 
    writeln(e); 
} 
+0

Notez que vous devriez être capable d'écrire fib.take (10) car maintenant la syntaxe de l'appel de fonction uniforme a été améliorée. – Trass3r

+0

Même trouvé l'article: http://www.drdobbs.com/blogs/cpp/232700394 – Trass3r

Répondre

20

Il n'y a pas exacte équivalent en D. Voici quelques équivalents rugueux:

Utilisation itération interne de style opApply. Cela ne permet cependant pas d'itérer sur deux itérateurs, bien que:

struct Foo { 
    int opApply(int delegate(ref int) dg) { 
     int a = 1, b = 1; 
     int result; 
     while(true) { 
      result = dg(b); 
      if(result) break; 
      int temp = a + b; 
      a = b; 
      b = temp; 
     } 

     return result; 
    } 
} 

void main() { 
    // Show usage: 
    Foo foo; 
    foreach(elem; foo) { 
     // Do stuff. 
    } 
} 

Utiliser les plages. Ceux-ci sont légèrement plus difficiles à écrire dans certains cas, mais sont très efficaces et permettent une itération de verrouillage. Cela peut aussi être itéré avec une boucle foreach, exactement comme la version opApply:

struct Foo { 
    int a = 1, b = 1; 

    int front() @property { 
     return b; 
    } 

    void popFront() { 
     int temp = a + b; 
     a = b; 
     b = temp; 
    } 

    // This range is infinite, i.e. never empty. 
    enum bool empty = false; 

    typeof(this) save() @property { return this; } 
} 

Si vous vraiment besoin des trucs de style coroutine, vous pouvez combiner les gammes et opApply ensemble à l'aide core.thread.Fiber, mais vous trouverez probablement Que ce soit les gammes ou opApply fait ce dont vous avez besoin presque tout le temps.

+0

Alors que la version D est un peu plus verbeux, il est au moins plus lisible: Je ne peux pas me surpasser cette Foo devrait retourne 1 à chaque fois (b est assigné 1 au tout début). De plus, chaque langage fait les choses un peu différemment, par exemple Ruby est essentiellement la version opApply sans la surcharge de la structure. –

+5

@he_the_great: L'autre compromis est que les deux versions D sont beaucoup plus efficaces. Tandis que l'itération du style coroutine/générateur peut être simulée en utilisant des fibres, je pense que la syntaxe a été intentionnellement omise car elle coûte environ un changement de contexte de cent cycles à chaque itération. La version opApply coûte peut-être 5 ou 10 cycles pour l'appel délégué, et la version de gamme ne peut rien coûter par rapport à une version codée à la main, car toutes les primitives de gamme sont admissibles à l'inlining. Un de ces deux styles fera ce dont vous avez besoin sans beaucoup de problèmes dans 99,9% des cas. – dsimcha

+0

Merci, dsimcha.Utiliser des gammes est très prometteur, je vais chercher. – Lurkeroid

19

Voir here; exemple extrait ci-dessous:

module main; 

import std.stdio; 
import generators; 

void genSquares(out int result, int from, int to) 
{ 
    foreach (x; from .. to + 1) 
     yield!result(x * x); 
} 

void main(string[] argv) 
{ 
    foreach (sqr; generator(&genSquares, 10, 20)) 
     writeln(sqr); 
} 
15

Le module std.concurrency dispose désormais d'une classe Generator ce qui rend encore plus facile (et vous n'avez pas besoin d'une bibliothèque tierce).

La classe est une plage d'entrée, elle peut donc être utilisée avec des boucles for et toutes les fonctions std.range/std.algorithm standard.

import std.stdio; 
import std.range; 
import std.algorithm; 
import std.concurrency : Generator, yield; 

void main(string[] args) { 
    auto gen = new Generator!int({ 
     foreach(i; 1..10) 
      yield(i); 
    }); 

    gen 
     .map!(x => x*2) 
     .each!writeln 
    ; 
} 
+1

Cela devrait être la réponse acceptée, je pense. –

+1

Je suis certain que le modèle 'Generator' n'existait pas quand une question a été posée ... – DejanLekic