Lambdas and blocks
From Reia
Contents |
Lambdas
Lambdas close over the enclosing lexical scope at the time they are declared, however state mutations inside lambda expressions do not effect the outer scope.
Lambdas return the value of the last expression evaluated:
>> f = fun do .. 10 .. 20 .. 30 .. #<Lambda -expr/5-fun-1- (module: erl_eval, arity: 0)> >> f() 30
Lambdas support a return keyword providing an early exit:
>> l = fun do .. 10 .. return 20 .. 30 .. #Fun >> f() 20
Blocks
Blocks in Reia are somewhat different from languages like Smalltalk and Ruby. They are semantically equivalent to lambdas. However, rather than being passed as formal arguments, blocks are given a special syntax for the purposes of improving code clarity and syntactic simplicity.
Blocks are passed with the following syntax:
mymethod(arg1, arg2) do |val1, val2| ...
Blocks may also be called inline using braces:
mymethod(arg1, arg2) { |val1, val2| ... }
When no parameters are being passed to a method that takes a block, parens may be omitted:
[1,2,3].map { |n| n + 1 }
The block passed to a method can be intercepted as a lambda by placing an & in front of a variable name:
def mymethod(arg1, arg2, &block) block(arg1 + 1, arg2 + 2)
Why blocks?
Why does a lambda need to be disintermediated from other formal parameters?
Block syntax eliminates a lot of syntactic noise associated with passing lambdas as function arguments using the traditional lambda syntax, and furthermore makes it extremely convenient to nest blocks within each other. The Ruby language and tools written within it make extensive use of nested blocks. Two examples of this are the RSpec behavior-driven development DSL and the Builder DSL for generating XML.
Blocks also make it convenient to do quick hacks by chaining several block-based operations together in the interactive interpreter. This is great if you want to make quick deductions about complex state in the program. You're not forced to type a lot of lambda boilerplate and parens to figure out what's going on, and can instead just chain up a lot of operations quickly.
Why can't you just use named functions? Isn't everything clearer that way? Then every transformation automatically has a label for what it's doing.
Named functions make you jump around in the program to understand its logic. Sometimes function labels are enough to infer what is happening, but often you just want to see the code. For more complex operations, code is easier to read than other people's labels. Why should you have to jump back and forth in the program to figure out what's going on?
But beyond that, chances are you're already binding the output of these operations to variables and thus describing the output of already, and in the process providing labels for both the transformation and its output in the form of a named function and the variable bound to its output. The name you bind to the output already provides the clarity of a label describing what the operation is doing. Why do you need to name both the transformation and its output every time? Isn't that tedious, and more information to process? You have what the output is, a hint at what the transformation is doing, and if you want to jump down or up a little bit the actual implementation. Wouldn't just a variable describing the output and the actual implementation of the transformation right there next to each other suffice?
By providing a convenient syntax for the lambda being used for the transformation you get both information about the output and the operation producing it inline and in the logical order of the operations being performed with no jumping back and forth between named functions.

