4

C# には、次のような構文を持つジェネレーター関数があります。

IEnumerable<int> GetNats(int max)
{
   for (int i=0; i < max; ++i)
      yield return i;
}

私のプログラミング言語 (Java、Scala、ActionScript、および C# に似た単純なオブジェクト指向プログラミング) で私が興味を持っている機能は、ジェネレータ式です。これらは本質的に、ジェネレータ関数のシンタックス シュガーです。

私の現在のお気に入りの候補は、次の構文です。

IEnumerable<int> nats = 
  witheach (i in range(0, 42)) 
     yield i * 2; 

range(0, 42)は組み込みのジェネレーター関数です。

私の質問は、C#/Java/Scala/ActionScript 型言語で、ジェネレーター式にどの構文を使用することを希望しますか? また、その理由は何ですか?

応答に影響を与える可能性のあるいくつかの要因は、Scala や ActionScript のように、私の言語の型は型の後に宣言されることです。例えば:

var myVar : SomeType = initialValue;

また、無名関数は次のようになります。

var myFunc = function(int x) { 
  return x + 1; 
}

それ以外は、言語構文の残りの部分は Java または C# に似ています。私の言語には、foreachC# に非常によく似たステートメントがあります。

4

3 に答える 3

3

Python のアプローチもあります。ジェネレーター用の特別な構文はありません。「yield」ステートメントが存在するだけで十分です。実際に使用されるループのみを見つけることを期待していますが、ブロックを取るステートメントはすべて使用できます。

IEnumerable<int> nats = 
    for (i in range(0,42))
        yield i*2

String phrase = "I want to buy some cheese.";
IEnumerable<int> substrs =
    for (i in 0 .. phrase.length)
        for (j in i .. phrase.length+1)
            yield phrase[i..j]

ここでは、正しいエンドポイントが範囲に含まれていないと想定しています。

正直なところ、これを Python で見たときは、「どのくらいの費用がかかるの?」と疑問に思う必要がありました。

于 2009-10-24T14:31:20.333 に答える
2

F# の機能を確認してください。できるよ

seq { seq-expr }    // IEnumerable<T>, a.k.a. seq<T>
[ seq-expr ]        // list<T>
[| seq-expr |]      // array<T>

ここで、seq-expr は「yield」とともにほとんどの言語構造を含む形式です。だから例えばあなたは書くことができます

seq {
    for i in 0..9 do
        for j in someColl do
            if i <> j then
                yield i*j
}

F# コンパイラは、このコードを IEnumerable のステート マシン実装に変換します (C# が反復子ブロックに対して行うように)。

私がこの構文を気に入っているのは、たとえば、「今すぐ命令的なことを行う」ために書くのとまったく同じコードを書くことができることを意味するからです。

    for i in 0..9 do
        for j in someColl do
            if i <> j then
                printfn "%d" i*j

しかし、そのコードを seq{} でラップして 'yield' を使用すると、コードは代わりに遅延 IEnumerable になります。

于 2009-10-24T19:34:58.140 に答える