#requires scriptSplit from wiki.tcl.tk/cmdSplit proc evaluator {procns name} { upvar $name lines set lines [scriptSplit [info body ${procns}::$name]] while {[llength $lines]} { set cmd [lindex $lines 0] uplevel 1 $cmd set lines [lreplace $lines[set lines {}] 0 0] } } proc stepeval {proc args} { set fullname [uplevel [list namespace which $proc]] set procns [namespace qualifiers $fullname] set procname [namespace tail $proc] set argspec {} foreach arg [info args $fullname] { if {[info default $fullname $arg val] == 1} { lappend arg $val } lappend argspec $arg } tailcall apply [list $argspec [ list [namespace current]::evaluator $procns $procname] $procns] {*}$args }Here is the Tcl version of the crawler tractor (see also [1]):
proc tractor {} { eval { puts [incr counter] lappend tractor [lindex $tractor end] #not needed because $tractor is automatically "consumed" by the evaluator #if {[llength $tractor] > 3} { # set tractor [lreplace $tractor[set tractor {}] 0 0] #} } }To execute tractor newLISP-style:
stepeval tractorHere is a Tcl implementation of the self-modifying newLISP "factorial" function from [2]:
proc factorial int { if {$int > 1} { set factorial [linsert $factorial end-1 [lindex $factorial 0]] set factorial [lreplace $factorial end end [list return [expr { $int * [lindex $factorial end end]}]]] incr int -1 } return 1 } stepeval factorial 5 ;# -> 120
[KazimirMajorinc] - 2015-12-26 03:42:53You wrote special version of eval. There is no doubt it is possible; interpreter for every language can be written in any language. Can you do the same by only defining function crawler-tractor?PYK 2015-12-26: There's more than that going on here. This is another example of how Tcl surfaces just the right primitives to extend it in any direction. Newlisp touts the ability to redefine the currently-running function as one of the unique features of the language. Tcl is a DSL for creating DSL's; extensibility is the name of the game. In this case, uplevel is the primitive that makes it almost trivial to extend Tcl to feature this Newlisp capability. It wasn't even necessary to drop down to the implementation level of Tcl. Time after time, the primitives Tcl provides turn out to be an eerily judicious set of tools to allow one to perform almost any computing task in almost any programming style. It's the chameleon, the Tcl Timeless Machine. It would probably be a lot of work extend Newlisp to have an uplevel capability. Maybe it would break the the way NewLisp currently works, causing one to argue that it doesn't fit the paradigm. In Tcl, it's Choose Your Own Paradigm.