Functional programming languages (and others) have a so-called "lambda" abstraction
which allows to dynamically create an anonnymnous function. This is often used when
a function has to be applied to a collection of entities, and this function is passed
as a parameter to another function (e.g., sorting the elements of a list according to
a comparision function).
Unfortunately, such a lambda abstraction is not present in Tcl, but I assume it should
be possible to build on. I have something like the following in mind:
lambda {args} body
would return a command which takes {args} as its arguments and executes body when
it is invoked. An example
proc apply {func list} {
foreach val $args {lappend res [$fun $val]}
return $res
}
apply [lambda x {return expr "($x + 2) * $x"}] {1 2 3 4 5}
--> {3 8 15 24 35}
There are other areas where such a lambda abstraction would be helpful.
Any hints for a solution are welcome.
Jean-Guy
______________________________________________________________
Jean-Guy Schneider Software Composition Group (SCG)
E-mail: schn...@iam.unibe.ch
WWW: http://www.iam.unibe.ch/~schneidr
Tel: +41 31 631.48.68 --- IAM: 86.81 --- Fax: 39.65
Mail: Institut fuer Informatik (IAM), Universitaet Bern
Neubrueckstrasse 10, CH-3012 BERN, SWITZERLAND
______________________________________________________________
proc lambda {_vars _script args} {
if {[llength $_vars] == [llength $args]} {
foreach _v [uplevel 1 {info locals}] { upvar 1 $_v $_v }
foreach _v $_vars _a $args { set $_v $_a }
return [eval $_script]
} else {
error "wrong number of values passed to lambda function"
}
}
Rather than returning a new command, this must be passed to a proc
as a literal script and eval'd within the proc to be applied to
arguments. This is not actually much of a problem -- most Tcl commands
which are passed as arguments need to be eval'd, and so lambda
functions can be passed as callbacks to Tk widgets and so on.
E.g:
proc do_1_2 {cmd} {
return [eval $cmd 1 2]
}
do_1_2 {lambda {x y} {expr {$x + $y}}}
do_1_2 {lambda {x y} {expr {$x * $y}}}
do_1_2 {lambda {x y} {puts "$x $y"}}
If you are used to lazy functional languages, be warned that this
implementation does not create a closure over local variables and
can not be curried.
Cheers,
Nat.
--
+------------------------------------------+---------------------+
| Name: Nat Pryce MEng ACGI | Dept. of Computing, |
| Email: n...@doc.ic.ac.uk | Imperial College, |
| Tel: +44 (0)171 594 8394 | 180 Queen's Gate, |
| Fax: +44 (0)171 581 8024 | London SW7 2BZ, |
| WWW: http://www-dse.doc.ic.ac.uk/~np2 | United Kingdom |
+------------------------------------------+---------------------+
There is no built-in support for lambdas per se, but the accepted idiom
of "arguments appended to script" (frequent in Tk) approximates it,
though to a lesser degree of generality. However, the ease of
introspection of Tcl leads me to believe that a proper combination of
[concat] [list] and [uplevel] could do the trick. A beginning could be:
proc lambda {x s} {return [list lambdaeval $x $s]}
proc lambdaeval {x s val} {
# set $x (I insist on the $) in the proper frame (uplevel) and eval $s
# sorry - no time to delve into that :)
}
proc apply {func list} {
foreach val $args {lappend res [eval $fun $val]}
return $res
}
-Alex
As is almost always the case with tcl, this function can be easily
written. The only caveat is that the created functions aren't completely
anonymous -- commands such as "info commands" would notice them. But
that's a small matter, I suppose.
Here's one quick hack:
proc lambda {arglist body} {
set prefix "__lambda__"
set count 0
while {[llength [info commands "$prefix$count"]] != 0} {
incr count
}
proc "$prefix$count" $arglist $body
return "$prefix$count"
}
proc apply {func arglist} {
foreach val $arglist {
lappend res [$func $val]
}
return $res
}
Here's the output, using your example:
% apply [lambda x {return [expr {($x + 2) * $x}]}] {1 2 3 4 5}
3 8 15 24 35
%
Does that meet your needs?
--
Bryan Oakley
ChannelPoint, Inc.
The most simple approach (I haven't used namespaces yet):
% set anon.counter 0
0
% proc lambda {Args Body} {
global anon.counter
incr anon.counter
proc anon.${anon.counter} $Args $Body
return anon.${anon.counter}
}
% proc apply {func list} {
foreach val $list {lappend res [$func $val]}
return $res
}
% apply [lambda x {return [expr "($x + 2) * $x"]}] {1 2 3 4 5}
3 8 15 24 35
Of course, this leaves all those anonymous procs around -- but I
don't see any straightforward way of knowing when to clean them up.
It just isn't built into the language (though you probably could
do it conservatively by looking at [info level] -- mmm, probably
not because of global vars...I don't know...you could do it
explicitly...an "unlambda $func" command?)
JonCook.
> Functional programming languages (and others) have a so-called "lambda" abstraction
> which allows to dynamically create an anonnymnous function.
>
>
Here is mine solution, which is a melt of Alex
and Nat Pryce ideas and solution :
# create a lambda function
proc lambda { arglist body } {
return [list lambdaeval {} {} $arglist $body]
}
# call lambda function
# arglist0 / vallist0 -> known arguments
# arglist1 -> missing arguments varname
proc lambdaeval { arglist0 vallist0 arglist1 body args } {
set arglen1 [llength $arglist1]
set vallen1 [llength $args]
if { $vallen1 > $arglen1 } {
return -code error "too many argument"
}
if { $vallen1 < $arglen1 } {
# curried it
return [list lambdaeval \
[concat $arglist0 [lrange $arglist1 0 [expr {$vallen1-1}]]] \
[concat $vallist0 $args] \
[lrange $arglist1 $vallen1 end] \
$body]
}
foreach varname [concat $arglist0 $arglist1] value [concat $vallist0 $args] {
set $varname $value
}
eval $body
}
-example
% set sum [lambda {x y} {return [expr {$x+$y}]}]
lambdaeval {} {} {x y} {return [expr {$x+$y}]}
% eval $sum 2 5
7
% set myincr [eval $sum 1]
lambdaeval x 1 y {return [expr {$x+$y}]}
% eval $myincr 3
4
-eric
Besides the 4 samples provided so far, note that I see a number of
references to lamda in
<URL:http://www.purl.org/NET/Tcl-FAQ/part5.html>
Also, if others who contributed to this thread want to make your
implementation available via ftp or http drop me a note and I can
add a reference to your URL to the software catalog.
--
<URL:mailto:lvi...@cas.org> Quote: In heaven, there is no panic,
<*> O- <URL:http://www.purl.org/NET/lvirden/> | only planning.
Unless explicitly stated to the contrary, nothing in this posting
should be construed as representing my employer's opinions.