Scala 是否有相当于 C# 的产量?
我是 Scala 的新手,据我了解,Scala 中的ield 并不像C# 中的yield,它更像是select。
Scala有类似C#的yield的东西吗? C# 的yield 非常好,因为它使编写迭代器变得非常容易。
更新:这是一个来自 C# 的伪代码示例,我希望能够在 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;
}
}
}
此代码使用yield 实现图的迭代广度优先遍历,它返回一个迭代器,以便调用者可以使用常规的 for 循环遍历图形,例如:
graph.BreadthFirstIterator().foreach( n => Console.WriteLine( n ) );
在 C# 中,yield 只是语法糖,可以轻松编写迭代器(.Net 中的 IEnumerable
,类似于 Java 中可迭代)。作为一个迭代器,它的计算是惰性的。
更新 II: 我在这里可能是错的,但我认为 C# 中的yield 的全部意义在于让您不必编写更高阶的函数。例如,您可以编写常规 for 循环或使用诸如 select
/map
/filter
/where
之类的方法而不是传入一个函数,然后该函数将遍历该序列。
例如,graph.iterator().foreach(n => println(n))
而不是 graph.iterator( n => println(n))
。
这样你就可以轻松链接它们,例如 graph.iterator().map(x => x.foo).filter(y => y.bar >= 2).foreach(z => println(z))。
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, e.g.:
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. E.g. 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.
E.g. graph.iterator().foreach(n => println(n))
instead of graph.iterator( n => println(n))
.
This way you can chain them easily, e.g graph.iterator().map(x => x.foo).filter(y => y.bar >= 2).foreach(z => println(z))
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
这里对单词“yield”的劫持偏离了它通常的意图:作为 协程。上面示例中的 C#
BreadthFirstIterator
似乎在协程意义上使用了yield
;在yield
返回值后,对活动BreadthFirstIterator
的IEnumerable
的下一次调用将继续执行yield< 之后的下一条语句/代码>。
在 C# 中,
yield
与迭代的思想相结合< /a> 不是一个更通用的控制流语句,但在该有限域内,它的行为是协程的行为。 Scala 的分隔延续可以允许定义协程。在那之前,Scala 缺乏这样的功能,特别是考虑到它的yield
的替代含义。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 useyield
in its coroutine sense; after a value is returned byyield
, the next call to activeBreadthFirstIterator
'sIEnumerable
will continue with the next statement afteryield
.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 foryield
.是的,您可能想看看这个问题的答案:
Scala 的产量是多少?
以下是 Scala 中针对此类构造的文档:
http://www.scala-lang.org/node/111
更新:
此博客讨论了 C# Yield 和 Scala:
http: //hestia.typepad.com/flatlander/2009/01/scala-for-c-programmers-part-1-mixins-and-traits.html
他详细介绍了如何使用扩展来制作与在 Scala 中使用 Traits 相比,IEnumerable 的工作量更大。
所以,你是对的,yield 在 Scala 中的功能与 C# 不同,但那是因为它们非常不同,所以如果你想将 BreadthFirst 作为 Trait 来执行,那么你可以调用
map( )
和filter
和foreach
方法,就像在 C# 中一样,但该特征将有助于解决如何遍历集合的问题。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()
andfilter
andforeach
methods, just as you would in C#, but the trait will help solve the problem of how to traverse the collection.我认为答案(除非 2.8 中发生变化)答案是否定的,Scala 没有类似于 C# 的yield 的语法糖来编写迭代器(IEumerable 或 Iterable 的实现)。
然而,在 Scala 中,您可以通过向遍历传递一个函数来实现类似的结果,该函数将在遍历中的每个项目上调用该函数。这种方法也可以在 C# 中以相同的方式实现。
以下是我在 C# 中编写 Traverse 的方法,而不使用 Yield:
然后您可以像这样使用它:
或者像这样:
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:
You could then use it like this:
Or like this:
尽管 Scala 有一个关键字
yield
,但它与 C#yield
有很大不同,Ruby 的yield
也与两者不同。这似乎是一个被过度使用的关键字。乍一看,yield
在 C# 中的使用似乎非常有限。要在 Scala 中执行相同的操作,您可以定义自己的高阶函数。在英语中,这意味着一个以函数作为参数的函数。
要采用 Microsoft 的示例,这里有一个 Scala 方法:
现在你有了你的“迭代器”:
注意:
Powers(2,8)
与Powers.apply(2,8)
相同。这只是一个编译器技巧。Powers(2, 8){ println(_) }
而不是Powers(2, 8, {println(_)})
Scala: 1,C#:0
更新:
对于您刚刚添加的示例,编写
traverse
来执行您想要的遍历,而无需考虑如何使用它。然后通过在traverse
参数列表后面添加(f(Node) => Any)
来添加额外的参数,例如在
traverse
中的点如果您有一个在 C# 中yield
的值,请调用f(yieldValue)
。当您想要使用此“迭代器”时,请调用 traverse 并向其传递一个函数,该函数可以为迭代器中的每个元素执行您想要执行的操作。
这是“函数式编程”的基本案例,您应该确保理解它才能成功使用 Scala。
Even though Scala has a keyword
yield
, it's quite different from the C#yield
, and Ruby'syield
is different from both. It seems to be a wildly overused keyword. The use ofyield
in C# appears very limited at first glance.To do the same in Scala, you could define your own high-order function. In English, that means a function that takes a function as a parameter.
To take Microsoft's example, here's a Scala method:
Now you have your "iterator":
Notes:
Powers(2,8)
is the same asPowers.apply(2,8)
. That's just a compiler trick.Powers(2, 8){ println(_) }
instead ofPowers(2, 8, {println(_)})
Scala: 1, C#: 0
Update:
For your just-added example, write
traverse
that does the traversal you want without thinking about how you are going to use it. Then add an extra parameter by adding(f(Node) => Any)
after thetraverse
parameter list, e.g.At the point in
traverse
where you have a value you wouldyield
with in C#, callf(yieldValue)
.When you want to use this "iterator," call
traverse
and pass a function to it that does whatever it is you want to do for each element in the iterator.This is a basic case for "functional programming" and you should make sure you understand it to be successful with Scala.
您可以在 Scala >= 2.8 中使用分隔延续的生成器实现来执行此操作。您需要延续插件,然后是类似的东西,
You can do this in Scala >= 2.8 using an implementation of generators in terms of delimited continuations. You'll need the continuations plugin and then something along these lines,
正如已经提到的,您可以使用 continuations-plugin 创建一个生成器来创建一个yield,其行为与 C# 完全相同:
As already mentioned you could create a Generator using the continuations-plugin to create a yield which is exactly behaving like C#:
来自 C# 背景并从 hotzen 调试了 Scala 代码(适应 Scala 2.11.6),我必须说这种延续用法接近于 C#-yield 的等价物。我不知道如果需要多个生成器,以相同的方法运行所有生成器,或者可能分布在不同的方法中,连续性是否仍然会发挥类似的作用,但我很高兴连续性确实存在,这样我就不必被迫使用多个线程来实现类似的,或者传递回调。
Coming from a C# background and having debugged the Scala code from hotzen(adapted to Scala 2.11.6), I must say this continuations usage comes close to the C#-yield equivalent. I do not know if continuations still would function similarly if multiple Generators were needed, running all in the same methods or possibly spread over different methods, but I am happy continuations do exist, so that I am not forced to work with multiple threads to achieve similar, or pass along call-backs.