[Richard Suchenwirth] 2002-05-05 - Reading chapter 1.3 of [SICP], a highly educational introduction to programming based on the [LISP] dialect Scheme, I felt challenged to try to reproduce the Scheme examples for summation of a series in Tcl, for example: b --- \ / f(n) = f(a) + ... + f(b) --- n=a Here's what I have so far (both ''f'' and ''next'' are "functional objects", which in Tcl just means "strings that happen to be the name of a proc": proc sum {f a next b} { expr {$a>$b? 0 : [$f $a] + [sum $f [$next $a] $next $b]} } # --------------------------- small building blocks: proc cube x {expr {$x*$x*$x}} proc inc x {incr x} ;# argument x is value, instead of name proc lambda {argl body} { set name [info level 0] proc $name $argl $body set name } if 0 {This handful of code allows us to reproduce the Scheme results from SICP - for more info, see there: * sum the cubes of 1..10: sum cube 1 inc 10 ==> 3025, or: sum cube 1 [lambda x {incr x}] 10 * sum the integers from 1 to 10: proc identity x {set x} sum identity 1 inc 10 ==> 55; or: sum [lambda x {set x}] 1 [lambda x {incr x}] 10 * approximate ''Pi'' one slow way: proc pi-term x {expr {1.0 / ($x * ($x+2))}} proc pi-next x {expr {$x + 4}} expr {[sum pi-term 1 pi-next 1000]*8} ==> 3.1395926555897828 whose run limit could be increased from 1000 until 2756 before raising the "too many nested calls..." error ;-( and still gave a less precise approximation than the good old ''atan(1)*4''... * '''integrate a function''' f between limits a and b: proc integral0 {f a b dx} { set ::globaldx $dx expr {[sum $f [expr {$a+$::globaldx/2}] add-dx $b] * $dx} } proc add-dx x {expr {$x+$::globaldx}} % integral0 cube 0 1 .0016 ==> 0.2499996800000055 Here however I had to start to compromise: instead of Scheme's lexical scoping, where dx is visible everywhere inside integral's body, including the add-dx function, I had to elevate dx to global status, which is ugly; and Tcl's recursion depth limit caught me before I could try SICP's dx value of 0.001 - the result is still close (but no cigar) to the correct result of 0.25. Oh wait, at least in this case we can emulate lexical scoping more closely, by embodying $dx into a "live proc body" of add-dx: proc integral {f a b dx} { proc add-dx x "expr {\$x+$dx}" expr {[sum $f [expr {$a+$dx/2}] add-dx $b] * $dx} } % integral cube 0 1 .00146 ==> 0.25009974849771255 ---- Slightly off-topic, but as all building blocks are there, here's a stint on the ''derivative'' of a function. However, we've reached a certain bound of convolution and ugliness here, escaping and bracing like below (it produces the approximately correct result, but still...): proc deriv g { lambda x "expr {(\[{$g} \[expr {\$x+$::dx}]]-\[{$g} \$x])/$::dx}" } % set dx 0.00001 ;# well, in SICP they have it global too... % [deriv [lambda x {expr $x*$x*$x}]] 5 ==> 75.0001499966 Anyway, I'm again surprised how many [steps towards functional programming] are possible with Tcl .. and more to come. ---- [Tcl and LISP] | [Arts and crafts of Tcl-Tk programming]