Lambda the Ultimate!
[Part 3 of the FScheme series ]
Now we’re going to add the all-powerful ‘lambda’! Since we’ve already done all the environment-passing plumbing from the last post, this will be straight forward. Lambda creates closures (read Bill’s book for an excellent description with pictures).
Essentially, it returns a new function that when called will do the following:
- Create a new environment frame, binding parameter to call-time arguments which are evaluated in the caller’s environment
- Extend the captured definition-time environment with this new frame
- Finally, eval the body in this extended environment
and Lambda env = function
| [List(parameters); body] – >
let closure env' args = // bind parameters to actual arguments (evaluated in the caller's environment)
let bindings = List.zip parameters args
let bind = function Symbol(p), a -> p, (eval env' a)
| _ -> failwith "Malformed 'lambda' parameter."
let env'' = List.map bind bindings |> extend env // extend the captured env
eval env'' body
Special(closure) | _ -> failwith "Malformed Lambda."
When Lambda is called, it’s given the definition-time environment as env. We capture this by way of the inner ‘closure’ function immediately returned as a Function(closure) Expression. Notice that ‘closure’ itself takes the call-time environment as env’ (with a prime mark). Later, when the function happens to be called (potentially in a completely different scope) it is passed the caller’s environment and does it’s magic.
We just need to add this guy to the global environment as a special form and we’re done:
and environment =
extend  [
"lambda", Special(Lambda) ]
If you want to marvel at the beauty and power of lambda, check out this previous post :-)
As usual, more tests:
case "(let ((square (lambda (x) (* x x)))) (square 4))" "16" // lambda
case "(let ((square (lambda (x) (* x x)))) square)" "Function" // print lambda
case "(let ((times3 (let ((n 3)) (lambda (x) (* n x))))) (times3 4))" "12" // closure
case "(let ((times3 (let ((makemultiplier (lambda (n) (lambda (x) (* n x))))) (makemultiplier 3)))) (times3 5))" "15" // higher order functions