if 0 {
Richard Suchenwirth 2004-04-22 - A
lambda is an anonymous function described as a pair
argl body, just as a named function can be described as a triple
name argl body (that's the arguments to Tcl's
proc), or as a pair
name lambda. The argument list
argl is matched with the actual arguments at call time. However, there is a certain arbitrariness in the contents of
argl due to the selection of formal argument names, which leads to the question whether
lambda x {expr $x*$x}, and
lambda y {expr $y*$y}
are the same lambda, or different. Reading about TRAC, I found that the creation of the body, and half of the argument assignment happen in two steps there:
#(DS,square,(#(mu,x,x)))
#(SS,square,x)
#(CL,square,5)'25
The first line defines a "form" (a string, which can serve as variable or function body), while the second line rewrites the form by replacing all occurrences of "x" with the non-character \1\ (more arguments would be rewritten to \2\, \3\,...). The string value of
square is now #(mu,\1\,\1\).
In the third line, the form is called, and the second half of the argument assignment takes place: all occurrences of \1\ in the form are replaced with the first argument, "5", and the multiplication primitive
#(mu,5,5) is evaluated, returning 25. This sounds vaguely familiar to Tcl'ers, yet strange. But we can join the DS and SS steps into one by just using the argument index as name, so the definition of a "form" in Tcl is just
set square {expr {$1*$1}}
which relieves us of the
argl body dichotomy, and the arbitrariness mentioned above - some discipline in argument names (integers corresponding to their position in the argument list, starting from 1) allows us to have a single string as full definition of an anonymous function, the body only. That's what I half-jokingly call a "half-lambda".
The idea is not new, of course - Unix and DOS shells, as well as awk and
SQL functions, have been using such numeric parameter names for a long time. In a different vein,
RPN languages can do without argument names by using stack operations instead (see
RPN again) - the corresponding half-lambda in RPN would be {dup mul}. In
Playing bytecode, a different flavor of RPN, with numbered arguments again, would have the
square example come out as "1@d*", probably one of the shortest ways to write a square function.
What's only left to be done is to implement the second half of the assignment, with the actual arguments, but that's easy:}
proc call {form args} {
set i 0
foreach arg $args {set [incr i] $arg}
eval $form
}
set square {expr {$1*$1}}
% call $square 5
25
if 0 {Alternatively, if you have an
integer range generator handy:
proc call {form args} {
foreach [range 1 [llength $args]] $args break
eval $form
}
proc range {from to} {
for {set i $from; set res {}} {$i<=$to} {incr i} {lappend res $i}
set res
}
% call {expr $1*$1} 5
25
% call {expr hypot($1,$2)} 3 4
5.0
Argument names of course have their good sides too, as they can document the purpose of an argument, so I'm not going to rewrite my Tcl code base in terms of "forms". But exploring different ways is always fun with Tcl... :)
RS 2007-10-24: Afterthought - now that we have
apply in Tcl 8.5, the
call could now be called
apply/2 ... :^)