[Richard Suchenwirth] - LISP (for LISt Processing) is one of the oldest computer languages, dating back to c. 1956, but still having a following (all of Emacs is configured in a LISP dialect) and evolution. Though I like to play with other languages in Tcl, I never really bothered to "play LISP". Is it because LISP and Tcl are at least superficially so similar that there is little to give or take? Both languages treat program code like data, and build strongly on lists as major data structure. In LISP as in Tcl, a command is a list where the first element ("CAR") is the command name and the others are its arguments. LISP's "property lists" are a mapping from strings to lists, or what Tcl'ers know as an array. So "playing LISP" would start with just some vocabulary exercises: proc car L {lindex $L 0} ;# "catch address register" proc cdr L {lrange $L 1 end} ;# "catch data register" LISP is more consequent in enclosing each and every list in parens, so you'll see much more of those in any LISP code (and typically have to close one or two handful at the end the file ;-). By adding the commonsense ''\n'' and even semicolon as command delimiters, Tcl can do with much less enclosing. Compare LISP's (PROGN (DO THIS) (DO THAT) ) to Tcl's { do $this do $that } But Tcl lists are not exactly as powerful as LISP's, since they are "just" flat sequences, not made up of cons cells (something like pairs of pointers) - so in LISP you can have mutable list parts, circular lists... Didn't miss that yet, however. See also * [Block-local variables] for how to model Lisp's LET construct * [Backquoting] for selective substution in a quoted list * [Modeling COND with expr] * [How do I read and write files in Tcl] for ''with-open-file'' ---- ''KBK'' (27 Feb 2000) -- Oh, but of course you can have mutable lists. Take a look at the following code. (Of course, for it to not leak memory, we need anonymous lambdas that are garbage collected. Feather?) # Create a word to represent an anonymous lambda proc fwcons {} { variable cell if { [info exists cell] } { incr cell } else { set cell 1 } return cell$cell } # LAMBDA - Create an anonymous function proc lambda { args body } { set p [fwcons] proc $p $args $body return $p } # CONS - Return a pair consisting of x and y. Implemented as an anonymous # function proc cons { x y } { lambda { a } [list if {$a} [list return $x] [list return $y]] } ''Isn't the above an implementation of "COND", not "CONS"? - [JCW]'' ''[RS]: it creates an anonymous proc that returns either CAR or CDR, so the "cons cell" is implemented as proc body, and returns the generated (lambda) name. But see [Modeling CONS with expr]'' # CAR/CDR - Dissect a pair by calling the anonymous function returned by CONS proc car { x } { $x 1 } proc cdr { x } { $x 0 } # NIL - The null list proc nil { a } { return nil } # NULL - Test if a list is empty proc null { l } { string equal nil $l } # MAP - Apply a function to each member of a list proc map { f l } { if { ! [null $l] } { $f [car $l] map $f [cdr $l] } } # PRIN1 - Print a thing with no newline proc prin1 { thing } { puts -nonewline $thing puts -nonewline { } } # PRINTLIST - Print each element of a list proc printlist { l } { map prin1 $l puts {} } # RPLACA - Replace the CAR of a list proc rplaca { l x } { proc $l [info args $l] [lreplace [info body $l] 2 2 [list return $x]] return $l } # RPLACD - Replace the CDR of a list proc rplacd { l y } { proc $l [info args $l] [lreplace [info body $l] 3 3 [list return $y]] return $l } set list [cons a [cons b [cons c nil]]] prin1 {Before:} printlist $list rplaca $list d rplacd [cdr [cdr $list]] [cons a nil] prin1 {After:} printlist $list ---- [Arts and crafts of Tcl-Tk programming]