if [llength [info commands p7proc]] { set Compiling true } else { set Compiling false source testing.tcl } if $Compiling { # # The good form of p7 lambda. # # Notice it needs a verb, such as "call", when it is invoked. # # It has its own copies of outer variables, so changing them # does not change other users of the scope, # and should probably be forbidden. # p7proc tolower_lambda { (int)a (tcl)b (utf*)c } { lambda (tcl)call { (tcl)s } { ::string tolower "$a/$b/$c/$s" } } } else { # It would probably, therefore, be better and *faster* to just use # AssertEq 4 { call $sl "bird" } # # so my Lambda Functions $sl require "call" # rather than require [list ] # # In P7, we can have either the slower swizzling "call" # or the faster, strongly-typed "call" version: # set len [ call $sl "bird" ] # set len [ call $sl "bird" ] # The parameters in <> are # # What $sl is, now, is just an anoymous p7class unique # to that occurrance of lambda. # Here's the latest form of lambda, a function object. # it requires a verb (e.g. "call") in front of the function object. set f [ tolower_lambda 2001 A Space ] AssertEq "2001/a/space/odessy" { call $f Odessy } } if $Compiling { p7proc trim_left {} { lambda call { s } { ::string trimleft $s } } p7proc trim_right {} { lambda call { s } { ::string trimright $s } } p7proc compose { f g } { lambda call { x } { call $f [ call $g $x ] } } } else { proc call_compose { f g x } { call $f [ call $g $x ] } AssertEq "yellow green" { call_compose [trim_left] [trim_right] " yellow green " } set trim [ compose [trim_left] [trim_right] ] AssertEq "yellow green" { call $trim " yellow green " } } if $Compiling { # now rather than the most generic kind of "takes (tcl) returns (tcl)" lambda functions, # define a strongly-typed "takes (uni*) returns (uni*)" lambda function # and a compose function for them. # We need a new "call verb" named call_uni, since "call" already has a different type. # Does this prove the (uni*) doesn't shimmer? I'd like to prove that. p7proc incr_first_char { (int)n } { # return a func that incrs first char by $n lambda (uni*)call_uni { (uni*)s } { set s(0) ( s(0) + n ) ; return $s } } p7proc compose_uni { f g } { lambda (uni*)call_uni { (uni*)x } { call_uni $f [ call_uni $g $x ] } } } else { set incr_uni_6 [ compose_uni [incr_first_char 2] [incr_first_char 4] ] set 8fish [ call_uni $incr_uni_6 "2 fish" ] AssertEq "8 fish" { set 8fish } # There is a nasty memory problem that seems to be triggered by shimmering the lambda object following way" AssertEq "8 fish" { call_uni $incr_uni_6 "2 fish" } AssertEq "8 fish" { call_uni $incr_uni_6 "2 fish" } AssertEq "8 fish" { call_uni $incr_uni_6 "2 fish" } AssertEq "8 fish" { call_uni $incr_uni_6 "2 fish" } set incr_uni_6 [ compose_uni [incr_first_char 2] [incr_first_char 4] ] set 2sheep "2sheep" set 8sheep [call_uni $incr_uni_6 $2sheep ] AssertEq "8sheep" { set 8sheep } } if $Compiling { # See LUA equivalent below, from which this was transcribed. p7proc makeY {} { lambda call {g} { set (tcl)a [ lambda call {f} {call $f $f} ] call $a [set (tcl) [ lambda call {f} { # take out the set (tcl) to find a bug call $g [set (tcl) [ lambda call {x} { # take out the set (tcl) to find a bug set (tcl)c [ call $f $f ] call $c $x } ] ] } ] ] } } p7proc makeF {} { lambda call {f} { return [lambda call {_n} { set (int)n $_n if ( n == 0 ) { return 1 } else { return ( n * [set (int) [ call $f [set (tcl) (n-1)] ]] ) } } ] } } } else { set factorial [ call [makeY] [makeF] ] proc simple_factorial n { set z 1 for {set i 1} { $i <= $n } {incr i} { set z [ expr { $z * $i } ] } set z } for {set i 0} {$i <= 12} {incr i} { set z [call $factorial $i] puts "factorial ( $i ) = $z" AssertEq [simple_factorial $i] {set z} } #################################################### factorial.lua #### -- function closures are powerful #### #### -- traditional fixed-point operator from functional programming #### Y = function (g) #### local a = function (f) return f(f) end #### return a(function (f) #### return g(function (x) #### local c=f(f) #### return c(x) #### end) #### end) #### end #### #### #### -- factorial without recursion #### F = function (f) #### return function (n) #### if n == 0 then return 1 #### else return n*f(n-1) end #### end #### end #### #### factorial = Y(F) -- factorial is the fixed point of F #### #### -- now test it #### function test(x) #### io.write(x,"! = ",factorial(x),"\n") #### end #### #### for n=0,16 do #### test(n) #### end #################################################### factorial.lua Okay }