由于语义模型的本质不同,Lisp-Cons单元不能直接建模为tcl值。lisp使用一个模型,其中值可以直接更新;该值是内存单元。Tcl使用不同的模型,其值在概念上是不可变的,原则上,任何恰好与其他任何模型存在差异的1 2 3 4;Tcl中的可变实体是
变量
对于名称(名称字符串本身是不可变的,当然是不可变的),这种不可变在简单值的级别上是有意义的,但它也扩展到了TCL的列表和字典;突变操作都会返回一个新值或更新一个变量。(实现比这更有效,使用copy-on-write策略来保存不可变的语义模型,同时能够在已知的语义等价的情况下实现值本身发生变化的事物。)
因此,必须将可更新的cons单元格构造为变量。你可以这样做:
proc cons {a b} {
global gensym cons
set handle G[incr gensym]
set cons($handle) [list $a $b]
return $handle
}
proc car {handle} {
global cons
return [lindex $cons($handle) 0]
}
proc cdr {handle} {
global cons
return [lindex $cons($handle) 1]
}
proc setCar {handle value} {
global cons
lset cons($handle) 0 $value
}
# Convenience procedures
proc makeFromList args {
set result "!nil"
foreach value [lreverse $args] {
set result [cons $value $result]
}
return $result
}
proc getAsList {handle} {
set result {}
while {$handle ne "!nil"} {
lappend result [car $handle]
set handle [cdr $handle]
}
return $result
}
set a [makeFromList 1 2 3 4]
# Use some local context; Tcl doesn't have anything exactly like Lisp's "let"
apply {a {
set b $a
set a [cdr [cdr $a]]
setCar [cdr $b] "b"
setCar [cdr $a] "d"
puts [getAsList $a]
}} $a
puts [getAsList $a]
这就产生了预期的输出(鉴于lisp和tcl对于如何格式化列表有不同的想法)。