[Part 3 of the FScheme series]
Continuing along in Bill Hails’ book. Be sure to follow the previous posts.
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:
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 [] [ "*", Function(Multiply) "-", Function(Subtract) "if", Special(If) "let", Special(Let) "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
Next>