Version 1 of named let

Updated 2014-10-26 03:04:53 by xan

So, I've been on a weird tear this weekend to implement some random bits of pieces of Scheme in Tcl for no particular reason whatsoever. I figured some might find some novelty in my implementation of (let), with the named three-argument form supported using tail recursion trampolines.

namespace eval ::lambda {
    variable symbol 0
}

proc ::lambda::gensym {} {
    variable symbol

    return "[namespace current]::symbol[incr symbol]"
}

proc ::lambda::let {args} {
    set varNames   [list]
    set varValues  [list]
    set trampoline break

    switch -- [llength $args] 2 {
        lassign $args bindings script

        set name {}
    } 3 {
        lassign $args bindings name script
    } default {
        error "Invalid command invocation"
    }

    foreach binding $bindings {
        lappend varNames  [lindex $binding 0]
        lappend varValues [uplevel 1 expr [lindex $binding 1]]
    }

    set ns     [::lambda::gensym]
    set result [list]

    namespace eval $ns {
        variable triggered 1
    }

    proc "${ns}::triggered" {args} {
        variable triggered

        if {[llength $args] > 0} {
            set triggered [lindex $args 0]
        }

        return $triggered
    }

    proc "${ns}::${name}" {args} {
        variable triggered 1
        uplevel 2 [list set varValues $args]
    }

    while {[namespace eval $ns triggered]} {
        namespace eval $ns {triggered 0}

        set result [apply [list $varNames $script $ns] {*}$varValues]

        if {[namespace eval $ns triggered]} {
            continue
        }
    }

    namespace forget $ns

    return $result
}

#
# Example usage
#
::lambda::let {{a 5}
     {b 6}} loop {
        puts "$a => $b"
        loop 7 8} ; # Loops forever