Version 2 of Tip187 in pure Tcl

Updated 2004-04-23 07:06:12

SS: This is a Pure TCL implementation of TIP187. Note that the semantic is the same, including the fact that lambda will never leak. The only difference with the TIP is the "prcedence" of lambda. In this implementation the order is: command lookup, lambda lookup, unknonw call. This should not make any difference.

 # Pure Tcl implementation of TIP 187 (Procedures as Values)
 # Copyright(C) 2004 Salvatore Sanfilippo <antirez (at) invece (dot) org>
 # Under the Same license as Tcl8.4

 namespace eval tip187 {set counter 0}
 rename unknown tip187_orig_unknown

 proc unknown args {
     set func [lindex $args 0]
     set funcargs [lrange $args 1 end]
     if {[llength $func] == 3 && [lindex $func 0] eq {lambda}} {
         set c [incr ::tip187::counter]
         set t [list proc ::tip187::lambda$c [lindex $func 1] [lindex $func 2]]
         if {![catch {uplevel $t}]} {
             set retval [uplevel ::tip187::lambda$c $funcargs]
             rename ::tip187::lambda$c {}
             return $retval
         }
         catch {rename ::tip187::lambda$c {}}
     } else {
         uplevel tip187_orig_unknown $args
     }
 }

 proc lambda {arglist body} {
     list lambda $arglist $body
 }

 ### Variadic MAP version
 proc map {func args} {
     if {[llength $args] > 1} {
         for {set j 1} {$j < [llength $args]} {incr j} {
             if {[llength [lindex $args $j]] != [llength [lindex $args 0]]} {
                 error "Lists of different length as input for \[map\]"
             }
         }
     }
     set result {}
     for {set i 0} {$i < [llength [lindex $args 0]]} {incr i} {
         set callargs {}
         for {set j 0} {$j < [llength $args]} {incr j} {
             lappend callargs [lindex [lindex $args $j] $i]
         }
         lappend result [eval [list $func] $callargs]
     }
     return $result
 }

 ### Examples ###

 set l1 {1 2 3 4 5}
 set l2 {10 20 30 40 50}
 set l3 [map [lambda {x y} {expr $x+$y}] $l1 $l2]
 puts $l3

EB: These examples fails:

 % map [list string length] {az bn dfg}
 invalid command name "string length"
 % lsort -command [lambda {x y} {expr {$x < $y}}] {2 4 1}
 wrong # args: should be "lambda arglist body"

[map] must be used with with a command or a lambda, not a command prefix, and lambda must be list-quoted. Sounds counter-intuitive to me.

 % lsort -command [list [lambda {x y} {expr {$x < $y}}]] {2 4 1}
 4 2 1