5

Lisp のリストは一連のコンス セルですが、Tcl のリストは要素を空白で区切った文字列です。コードを Lisp から Tcl に変換するには、単純に Lisp リストを Tcl リストに変換します。ただし、これは副作用のあるコンス セルが Tcl コードに到達しないという問題に遭遇します。たとえば、次のコードを Lisp で考えてみましょう。

(setq a (list 1 2 3 4))
(let ((b a)
      (a (cddr a)))
  (declare (special a b))
  (setf (cadr b) ‘b)
  (setf (cadr a) ‘d)
  (print a))
(print a)

;; Results in:
(3 d)
(1 b 3 d)

Tcl で Lisp リストのより良いエミュレーションを提供する Tcl パッケージはありますか? そのようなパッケージは、通常の Tcl リストへの簡単な変換を提供しますか?

上記のコードは、そのようなパッケージを使用した Tcl ではどのように見えるでしょうか?

4

1 に答える 1

8

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 では、リストをどのようにフォーマットするかという考え方が異なるため)。

于 2010-09-10T10:00:08.383 に答える