在 Tcl 中模拟 lisp cons 单元

发布于 2024-09-18 11:01:21 字数 461 浏览 6 评论 0原文

Lisp 中的列表是一系列 cons 单元,但在 Tcl 中,列表是一个用空格分隔元素的字符串。为了将代码从 lisp 转换为 tcl,可以简单地将 lisp 列表转换为 Tcl 列表。然而,这会遇到麻烦,因为 Tcl 代码不会遇到副作用 cons 单元。例如,考虑 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 包可以在 Tcl 中提供更好的 lisp 列表模拟?这样的包是否可以轻松转换为常规 Tcl 列表?

使用这样的包,上面的代码在 Tcl 中会是什么样子?

A list in lisp is a series of cons cells, but in Tcl, a list is a string with whitespace separating the elements. For translating code from lisp to tcl, one might simply take lisp lists and translate them to Tcl lists. However, this runs into trouble with side effecting cons cells not coming across to the Tcl code. For example, consider this code in 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)

Is there a Tcl package that would provide a better emulation of lisp lists in Tcl? Does such package offer easy conversion to regular Tcl lists?

What might the above code look like in Tcl using such package?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

百善笑为先 2024-09-25 11:01:21

由于根本不同的语义模型,Lisp cons 单元不能直接建模为 Tcl 值。 Lisp 使用一种模型,其中值可以直接更新;该值是存储单元。 Tcl 使用不同的模型,其值在概念上是不可变的,并且任何恰好位于周围的“1 2 3 4”之间在原则上没有区别; Tcl 中的可变实体是带有名称的变量(当然,名称字符串本身是不可变的……)这种不可变性在简单值的级别上是有意义的,但它也扩展到 Tcl 的列表和字典;变异操作要么返回一个新值,要么更新一个变量。 (实现比这更有效,使用写时复制策略来保留不变性的语义模型,同时能够在实际上已知语义上等效的情况下通过值本身的突变来实现事物。)

因此,您必须将可更新的 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 对于如何格式化列表有不同的想法)。

Lisp cons cells can't be directly modeled as Tcl values because of fundamentally different semantic models. Lisp uses a model whereby values are directly updatable; the value is the memory cell. Tcl uses a different model with values which are conceptually immutable and where there is no difference in principle between any “1 2 3 4” that happens to be lying around from any other; mutable entities in Tcl are variables with names (the name strings themselves are immutable, of course…) This immutability makes sense at the level of simple values, but it extends also to Tcl's lists and dictionaries; mutation operations all either return a new value or update a variable. (The implementation is more efficient than this, using a copy-on-write strategy to preserve the semantic model of immutability while being able to implement things with mutation of the value itself when that is actually known to be semantically equivalent.)

Because of this, you have to construct updatable cons cells as variables. Here's how you might do it:

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]

This produces the expected output (given that Lisp and Tcl have different ideas how a list should be formatted).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文