Version 5 of Playing LISP

Updated 2002-12-05 16:32:53

Richard Suchenwirth - Here's a first approximation of making Tcl simulate LISP - there are subtle differences yet to solve, e.g. the $x formulation below - but build on it, and enjoy!

The wrapper proc is called, like in LISP, progn ("evaluate the following sequentially, and return the n-th(=last) result"). It takes care of paren-to-brace mapping, and then does that:

 proc progn body {
     regsub -all {;[^\n]*\n} $body \n body
     set body [string map {( \{ ) "\} "} $body]
     foreach cmd $body {
         set _ [uplevel 1 $cmd]
     }
     set _
 }

# Setting up Polish-style arithmetic prefix operators...

 foreach op {+ - * /} {
     proc $op args [string map [list @op@ $op] {expr [join $args @op@]}]
 }

# Some vocabulary exercises...

 interp alias {} defun {} proc
 interp alias {} setq  {} set

# Now testing...

 set res [progn {
     ;; LISPish comments, removed before bracing
     (defun sq (x) (* $x $x))
     (setq y 3)
     (sq $y)
 }]
 puts $res,y:$y

Disclaimer: This example happens to work, but to emulate LISP is still a long way to go. Lists in parens would have to be translated to stand in brackets (if not the outermost one), while quote-parened lists would have to be braced. Quoted strings should be distinguished from unquoted ones, which would have to get a dollar sign in front, and much more...


If execution of a list of commands is all you want, an easy way is to join them with newlines as separators, and eval them. The last result is returned as result of the eval:

 % lappend cmd {set foo 42}
 {set foo 42}
 % lappend cmd {puts foo:$foo}
 {set foo 42} {puts foo:$foo}
 % lappend cmd {if {$foo==42} {puts Yes!}}
 {set foo 42} {puts foo:$foo} {if {$foo==42} {puts Yes!}}
 % lappend cmd {set bar 2002}
 {set foo 42} {puts foo:$foo} {if {$foo==42} {puts Yes!}} {set bar 2002}

 % eval [join $cmd \n]
 foo:42
 Yes!
 2002

Tcl and LISP - Arts and crafts of Tcl-Tk programming