[LEG]: Some references to variable scope in Tcl, especially with lexical scope in mind: * [let2]: practically I re-invented let almost the same way as [SS] does there, however with some differences which make my implementation smaller and with (arguably) less syntax overhead. * [Block-local variables]: seem to start the discussion. Several different implementations and much discussion. 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: * The condition can be any function invocation. If you want it to be an expression you must state it explicitly * The cond shall throw an error if invoked with an odd number of arguments * The cond shall throw an error if we fall through all conditions Well, putting this together with [pnfp]'s or [http://www.tcl.tk/cgi-bin/tct/tip/174.html]'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 } ====== <> Language