A lambda is just an anonymous function - a function defined with no name. In some languages, such as Scheme, they are equivalent to named functions. In fact, the function definition is re-written as binding a lambda to a variable internally. In other languages, like Python, there are some (rather needless) distinctions between them, but they behave the same way otherwise.
A closure is any function which closes over the environment in which it was defined. This means that it can access variables not in its parameter list. Examples:
def func(): return h
def anotherfunc(h):
return func()
This will cause an error, because func
does not close over the environment in anotherfunc
- h
is undefined. func
only closes over the global environment. This will work:
def anotherfunc(h):
def func(): return h
return func()
Because here, func
is defined in anotherfunc
, and in python 2.3 and greater (or some number like this) when they almost got closures correct (mutation still doesn't work), this means that it closes over anotherfunc
's environment and can access variables inside of it. In Python 3.1+, mutation works too when using the nonlocal
keyword.
Another important point - func
will continue to close over anotherfunc
's environment even when it's no longer being evaluated in anotherfunc
. This code will also work:
def anotherfunc(h):
def func(): return h
return func
print anotherfunc(10)()
This will print 10.
This, as you notice, has nothing to do with lambdas - they are two different (although related) concepts.
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's do
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
and filter
. Or foreach
. Scala actually translates a for
-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
for(x <- c1; y <- c2; z <-c3) {...}
is translated into
c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))
This
for(x <- c1; y <- c2; z <- c3) yield {...}
is translated into
c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))
This
for(x <- c; if cond) yield {...}
is translated on Scala 2.7 into
c.filter(x => cond).map(x => {...})
or, on Scala 2.8, into
c.withFilter(x => cond).map(x => {...})
with a fallback into the former if method withFilter
is not available but filter
is. Please see the section below for more information on this.
This
for(x <- c; y = ...) yield {...}
is translated into
c.map(x => (x, ...)).map((x,y) => {...})
When you look at very simple for
comprehensions, the map
/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.
l.flatMap(sl => sl.filter(el => el > 0).map(el => el.toString.length))
or
for {
sl <- l
el <- sl
if el > 0
} yield el.toString.length
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. The filter
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 with List
(strict) and Stream
(non-strict):
scala> var found = false
found: Boolean = false
scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9
scala> found = false
found: Boolean = false
scala> Stream.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
The difference happens because filter
is immediately applied with List
, returning a list of odds -- since found
is false
. Only then foreach
is executed, but, by this time, changing found
is meaningless, as filter
has already executed.
In the case of Stream
, the condition is not immediatelly applied. Instead, as each element is requested by foreach
, filter
tests the condition, which enables foreach
to influence it through found
. Just to make it clear, here is the equivalent for-comprehension code:
for (x <- List.range(1, 10); if x % 2 == 1 && !found)
if (x == 5) found = true else println(x)
for (x <- Stream.range(1, 10); if x % 2 == 1 && !found)
if (x == 5) found = true else println(x)
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 shows List
with both methods on Scala 2.8:
scala> var found = false
found: Boolean = false
scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9
scala> found = false
found: Boolean = false
scala> List.range(1,10).withFilter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
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.
Best Answer
Case classes can be seen as plain and immutable data-holding objects that should exclusively depend on their constructor arguments.
This functional concept allows us to
Node(1, Leaf(2), None))
)In combination with inheritance, case classes are used to mimic algebraic datatypes.
If an object performs stateful computations on the inside or exhibits other kinds of complex behaviour, it should be an ordinary class.