LEG: Some references to variable scope in Tcl, especially with lexical scope in mind:
Included for no special reason is also a cond implementation. See Modeling COND with expr for some explanation. However I wanted a very simple implementation with the following features:
Well, putting this together with pnfp's or [L1 ]'s prefix notation for math expresions would come close to Playing Scheme. One would still need to choose an appropiate lambda implementation, however...
# LEG20081206 -*- tcl -*- # # lexically/statically-scoped variables # if 0 { This is yet another approach to lexical scoped variables in Tcl. It introduces a special, yet Tcl conform syntax: static variable names are enclosed within parentheses, e.g.: set (x) 5; puts $(x) => 5 We add an implementation of 'let' which evaluates a script in a new environment, as well as a definition function 'def' which is a proc with all args interpreted as lexically scoped variables. let {x 1 y 2} {expr {$(x)+$(y)}} => 3 def sumsquares {x y} { let { x2 {[expr {$(x)**2}]} y2 {[expr {$(y)**2}]} } { expr {$(x2)+$(y2)} } } This all is accomplished by mainting static variables in the globally scoped array with name {}. We maintain state/call frames with another global array named static. This means you can mess arround with the static variables in a normal proc by declaring global {}. In the following, a binding is a list of {var value} pairs. As an addon a simple implementation of a cond construct is implemented. it is used in one of the following ways: cond cond1 body1 cond2 body2 .. condn bodyn cond cond1 body1 ... else bodyn 'else' is a helper script which evaluates to true } if 1 { if {[info exists {}]} {array unset {}} if {[info exists static]} {array unset static} } global {} global static set static() 0 proc push bindings { # save environment, set new bindings global {} static; set i [incr static()] foreach {name value} $bindings { if {[info exists ($name)]} {set static($name,$i) $($name)} set ($name) [subst $value] } } proc pop bindings { # restore environment, discard previous bindings global {} static; set i $static() foreach {name value} $bindings { if {[info exists static($name,$i)]} { set ($name) $static($name,$i) unset static($name,$i); # optional } else {unset ($name)} } incr static() -1 } proc let {bindings body} { # eval the body after adding the bindings to the environment push $bindings global {}; set r [eval $body] pop $bindings; return $r } proc def {name args body} { foreach v $args {append script "lappend bindings $v \$$v" \n} append script "let \$bindings {$body}" proc $name $args $script } proc else {} {return 1} proc cond args { global {} foreach {predicate body} $args { if {[uplevel $predicate]} {break} unset body } uplevel subst $body }