What fun can be had with lambda-definitions?

You can use them for control flow. For example, in Smalltalk, the "ifTrue:ifFalse:" method is a method on Boolean objects, with a different implementation on each of True and False classes. The expression

someBoolean ifTrue: [self doSomething] ifFalse: [self doSomethingElse]

uses two closures---blocks, in [square brackets] in Smalltalk syntax---one for the true branch, and one for the false branch. The implementation of "ifTrue:ifFalse:" for instances of class True is

ifTrue: block1 ifFalse: block2
    ^ block1 value

and for class False:

ifTrue: block1 ifFalse: block2
    ^ block2 value

Closures, here, are used to delay evaluation so that a decision about control flow can be taken, without any specialised syntax at all (besides the syntax for blocks).

Haskell is a little different, with its lazy evaluation model effectively automatically producing the effect of closures in many cases, but in Scheme you end up using lambdas for control flow a lot. For example, here is a utility to retrieve a value from an association-list, supplying an optionally-computed default in the case where the value is not present:

(define (assq/default key lst default-thunk)
  (cond
    ((null? lst) (default-thunk)) ;; actually invoke the default-value-producer
    ((eq? (caar lst) key) (car lst))
    (else (assq/default key (cdr lst) default-thunk))))

It would be called like this:

(assq/default 'mykey my-alist (lambda () (+ 3 4 5)))

The key here is the use of the lambda to delay computation of the default value until it's actually known to be required.

See also continuation-passing-style, which takes this to an extreme. Javascript, for instance, relies on continuation-passing-style and closures to perform all of its blocking operations (like sleeping, I/O, etc).

ETA: Where I've said closures above, I mean lexically scoped closures. It's the lexical scope that's key, often.


You can make a functional data structure out of lambdas. Here is a simple one - a functional list (Python), supporting add and contains methods:

empty = lambda x : None

def add(lst, item) :
    return lambda x : x == item or lst(x)

def contains(lst, item) :
    return lst(item) or False

I just coded this quickly for fun - notice that you're not allowed to add any falsy values as is. It also is not tail-recursive, as a good functional structure should be. Exercises for the reader!