Version 0 of Playing newLISP

Updated 2014-08-09 03:00:39 by pooryorick

In Playing newLISP, Tcl takes on some of the features of that language.

One unique feature of newLISP is that the definition of a function can be modified during the evaluation of the function. stepeval implements this behaviour, with the small twist that it discards the commands of the script as it evaluates them. This shifts some of the management overhead into stepeval, allowing the Tcl examples below to be more concise than their newLISP counterparts.

#requires cmdSplit from wiki.tcl.tk/cmdSplit
proc evaluator {procns name} {
        upvar $name lines
        set lines [cmdSplit [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 [L1 ]):

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 tractor

Here is a Tcl implementation of the self-modifying newLISP "factorial" function from [L2 ]:

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