Does Scala have an equivalent to C# yield?

I'm new to Scala, and from what I understand yield in Scala is not like yield in C#, it is more like select.

Does Scala have something similar to C#'s yield? C#'s yield is great because it makes writing iterators very easy.

Update: here's a pseudo code example from C# I'd like to be able to implement in Scala:

public class Graph<T> {
   public IEnumerable<T> BreadthFirstIterator() {
      List<T> currentLevel = new List<T>();
      currentLevel.add(_root);

      while ( currentLevel.count > 0 ) {
         List<T> nextLevel = new List<T>();
         foreach( var node in currentLevel ) {
            yield return node;
            nextLevel.addRange( node.Children );
         }
         currentLevel = nextLevel;
      }
   }
}

This code implements an iterative breadth first traversal of a graph, using yield, it returns an iterator, so that callers can traverse the graph using a regular for loop, eg:

graph.BreadthFirstIterator().foreach( n => Console.WriteLine( n ) );

In C#, yield is just syntactic sugar to make it easy to write an iterator ( IEnumerable<T> in .Net, similar to Iterable in Java). As an iterator, its evaluated lazily.

Update II: I could be wrong here, but I think the whole point of yield in C# is so that you don't have to write a higher order function. Eg you can write a regular for loop or use a method like select / map / filter / where instead of passing in a function which will then traverse the sequence.

Eg graph.iterator().foreach(n => println(n)) instead of graph.iterator( n => println(n)) .

This way you can chain them easily, eg graph.iterator().map(x => x.foo).filter(y => y.bar >= 2).foreach(z => println(z)) .


The hijacking of the word yield here distracts from its usual intent: as an entry/exit marker in a coroutine. The C# BreadthFirstIterator in the example above appears to use yield in its coroutine sense; after a value is returned by yield , the next call to active BreadthFirstIterator 's IEnumerable will continue with the next statement after yield .

In C#, yield is coupled to the idea of iteration rather than being a more general control flow statement, but within that limited domain its behavior is that of a coroutine. Scala's delimited continuations may allow one to define coroutines. Until then, Scala lacks such a capability, especially given its alternate meaning for yield .


Yes it does, you may want to look at this question for the answer: What is Scala's yield?

Here is the docs from Scala for this type of construct: http://www.scala-lang.org/node/111

UPDATE:

This blog talks about C# yield and Scala: http://hestia.typepad.com/flatlander/2009/01/scala-for-c-programmers-part-1-mixins-and-traits.html

He goes into some detail about how extensions are being used to make IENumerable work compared to using Traits in Scala.

So, you are correct that yield won't function the same way in Scala as C#, but that is because they are very different, and so if you want to do this BreadthFirst as a Trait then you can call the map() and filter and foreach methods, just as you would in C#, but the trait will help solve the problem of how to traverse the collection.


I think the answer (barring changes in 2.8) is that the answer is no, Scala does not have syntactic sugar similar to C#'s yield to write iterators (implementations of IEumerable or Iterable).

However, in Scala you could instead achieve a similar result by passing in a function to the traversal which it would invoke on each item in the traversal. This approach could also be implemented in the same fashion in C#.

Here is how I'd write Traverse in C# without the use of yield:

public class Graph<T> {
   public void BreadthFirstTraversal( Action<T> f) {
      List<T> currentLevel = new List<T>();
      currentLevel.add(_root);

      while ( currentLevel.count > 0 ) {
         List<T> nextLevel = new List<T>();
         foreach( var node in currentLevel ) {
            f(node);
            nextLevel.addRange( node.Children );
         }
         currentLevel = nextLevel;
      }
   }
}

You could then use it like this:

graph.BreadthFirstTraversal( n => Console.WriteLine( n ) );

Or like this:

graph.BreadthFirstTraversal( n =>
{
   Console.WriteLine(n);
   DoSomeOtherStuff(n);
});
链接地址: http://www.djcxy.com/p/54332.html

上一篇: 在Python中产生突破

下一篇: Scala是否具有与C#收益等价的功能?