Lisp のコンス セルは、セマンティック モデルが根本的に異なるため、Tcl 値として直接モデル化することはできません。Lisp は、値を直接更新できるモデルを使用します。値はメモリセルです。Tcl は、概念的に不変の値を持つ別のモデルを使用します。ここでは、たまたま横たわっている「1 2 3 4」と他の値との間に原則として違いはありません。Tcl の変更可能なエンティティは変数です名前付き (もちろん、名前文字列自体は不変です…) この不変性は、単純な値のレベルでは理にかなっていますが、Tcl のリストや辞書にも拡張されています。ミューテーション操作はすべて、新しい値を返すか、変数を更新します。(実装はこれよりも効率的です。コピー オン ライト戦略を使用して、不変性のセマンティック モデルを保持しながら、意味的に同等であることが実際にわかっている場合、値自体の変更を伴うものを実装できます。)
このため、更新可能なコンス セルを変数として構築する必要があります。これを行う方法は次のとおりです。
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 では、リストをどのようにフォーマットするかという考え方が異なるため)。