Lightweight Lambda

Richard Suchenwirth 2002-11-30 - Lambdas are anonymous functions - "procs with no name" (see Lambda in Tcl), or put the other way, functions are just named lambdas. A few ways of bringing Lambdas to Tcl have been proposed, which were most concerned with picking a name, and then defining a proc. This however leads to a garbage collection problem, as such procs live in the global namespace and are never cleared up. Here I try a different approach - let lambdas be just strings (everything is a string) that can be parsed as a list of two elements - the argument list and the body. For instance, here's a squarer:

 {x} {expr $x*$x}

One may assign such values to a variable (or array element), or pass them around by value:

 set sq {{x} {expr $x*$x}}

To "run" a lambda, to make it execute like a Tcl command, the first take is an explicit apply:}

 proc apply {lambda args} {
    foreach {argl body} $lambda break
    if {[llength $argl] != [llength $args]} {
        error "argument mismatch, expected $argl"
    }
    foreach $argl $args break
    if 1 $body
 }

if 0 {Testing:

 % set sq {x {expr {$x*$x}}}
 x {expr {$x*$x}}
 % apply $sq 5
 25

But to prefix each lambda invocation with apply seems like back in the dark (Fortran CALL, Basic GOSUB) ages... So let's see how to get Tcl to call apply automatically when meeting a lambda. Lambdas are lists of two elements, so if we assert that "normal" command names do not contain exactly one space, we can extend unknown to apply commands whose name happens to be a list of length 2: }

 proc unknown args [string map [list @ [info body unknown]] {
    if {[llength [lindex $args 0]]==2} {
        return [uplevel 1 apply $args]
    }
 @}]

if 0 {Now we can call our lambdas by given name:

 % $sq 5
 25

or, if we don't bother picking a name, by explicit specification:

 % {x {expr sqrt($x)}} 25
 5.0

The drawback is that the lambda body goes through eval every time, so is slower than a byte-compiled proc body. On the other hand, we don't have to worry about garbage, as local variables are disposed of automatically - and we finally have real local procedures... }


DKF - Another possibility is to use the auto-expanding unknown also used in Hot Curry and to create the lambda "function" with apply pre-applied:

 proc lambda {arguments body} {
    return [list apply [list $arguments $body]]
 }

I always prefer to use a mechanism that is useful in more than one way. :^) RS: Yes - my original proposal had the drawback of conflicting semantics for unknown (if used together with Hot curry). Your change is indeed better.