I understand Ruby and Python's yield. What does Scala's yield do?
相关问题
- Unusual use of the new keyword
- Get Runtime Type picked by implicit evidence
- What's the point of nonfinal singleton objects
- PlayFramework: how to transform each element of a
- Error in Scala Compiler: java.lang.AssertionError:
相关文章
- Gatling拓展插件开发,check(bodyString.saveAs("key"))怎么实现
- RDF libraries for Scala [closed]
- Why is my Dispatching on Actors scaled down in Akk
- Is there something like the threading macro from C
- How do you run cucumber with Scala 2.11 and sbt 0.
- Learning F#: What books using other programming la
- Creating a list of functions using a loop in R
- GRPC: make high-throughput client in Java/Scala
Consider the following for-comprehension
It may be helpful to read it out loud as follows
"For each integer
i
, if it is greater than3
, then yield (produce)i
and add it to the listA
."In terms of mathematical set-builder notation, the above for-comprehension is analogous to
which may be read as
"For each integer , if it is greater than , then it is a member of the set ."
or alternatively as
" is the set of all integers , such that each is greater than ."
I think the accepted answer is great, but it seems many people have failed to grasp some fundamental points.
First, Scala's
for
comprehensions are equivalent to Haskell'sdo
notation, and it is nothing more than a syntactic sugar for composition of multiple monadic operations. As this statement will most likely not help anyone who needs help, let's try again… :-)Scala's
for
comprehensions is syntactic sugar for composition of multiple operations with map,flatMap
andfilter
. Orforeach
. Scala actually translates afor
-expression into calls to those methods, so any class providing them, or a subset of them, can be used with for comprehensions.First, let's talk about the translations. There are very simple rules:
This
is translated into
This
is translated into
This
is translated on Scala 2.7 into
or, on Scala 2.8, into
with a fallback into the former if method
withFilter
is not available butfilter
is. Please see the section below for more information on this.This
is translated into
When you look at very simple
for
comprehensions, themap
/foreach
alternatives look, indeed, better. Once you start composing them, though, you can easily get lost in parenthesis and nesting levels. When that happens,for
comprehensions are usually much clearer.I'll show one simple example, and intentionally omit any explanation. You can decide which syntax was easier to understand.
or
withFilter
Scala 2.8 introduced a method called
withFilter
, whose main difference is that, instead of returning a new, filtered, collection, it filters on-demand. Thefilter
method has its behavior defined based on the strictness of the collection. To understand this better, let's take a look at some Scala 2.7 withList
(strict) andStream
(non-strict):The difference happens because
filter
is immediately applied withList
, returning a list of odds -- sincefound
isfalse
. Only thenforeach
is executed, but, by this time, changingfound
is meaningless, asfilter
has already executed.In the case of
Stream
, the condition is not immediatelly applied. Instead, as each element is requested byforeach
,filter
tests the condition, which enablesforeach
to influence it throughfound
. Just to make it clear, here is the equivalent for-comprehension code:This caused many problems, because people expected the
if
to be considered on-demand, instead of being applied to the whole collection beforehand.Scala 2.8 introduced
withFilter
, which is always non-strict, no matter the strictness of the collection. The following example showsList
with both methods on Scala 2.8:This produces the result most people expect, without changing how
filter
behaves. As a side note,Range
was changed from non-strict to strict between Scala 2.7 and Scala 2.8.Yes, as Earwicker said, it's pretty much the equivalent to LINQ's
select
and has very little to do with Ruby's and Python'syield
. Basically, where in C# you would writein Scala you have instead
It's also important to understand that
for
-comprehensions don't just work with sequences, but with any type which defines certain methods, just like LINQ:map
, it allowsfor
-expressions consisting of a single generator.flatMap
as well asmap
, it allowsfor
-expressions consisting of several generators.foreach
, it allowsfor
-loops without yield (both with single and multiple generators).filter
, it allowsfor
-filter expressions starting with anif
in thefor
expression.Unless you get a better answer from a Scala user (which I'm not), here's my understanding.
It only appears as part of an expression beginning with
for
, which states how to generate a new list from an existing list.Something like:
So there's one output item for each input (although I believe there's a way of dropping duplicates).
This is quite different from the "imperative continuations" enabled by yield in other languages, where it provides a way to generate a list of any length, from some imperative code with almost any structure.
(If you're familiar with C#, it's closer to LINQ's
select
operator than it is toyield return
).Yield is similar to for loop which has a buffer that we cannot see and for each increment, it keeps adding next item to the buffer. When the for loop finishes running, it would return the collection of all the yielded values. Yield can be used as simple arithmetic operators or even in combination with arrays. Here are two simple examples for your better understanding
res: scala.collection.immutable.IndexedSeq[Int] = Vector(3, 6, 9, 12, 15)
res: Seq[(Int, Char)] = List((1,a), (1,b), (1,c), (2,a), (2,b), (2,c), (3,a), (3,b), (3,c))
Hope this helps!!
It is used in sequence comprehensions (like Python's list-comprehensions and generators, where you may use
yield
too).It is applied in combination with
for
and writes a new element into the resulting sequence.Simple example (from scala-lang)
The corresponding expression in F# would be
or
in Linq.
Ruby's
yield
has a different effect.