在Tcl中模拟lisp-cons单元

在Tcl中模拟lisp-cons单元,lisp,tcl,dynamic-scope,Lisp,Tcl,Dynamic Scope,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

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中,上面的代码可能是什么样子的?

Lisp cons单元格不能直接建模为Tcl值,因为语义模型根本不同。Lisp使用一个模型,其中的值是可直接更新的;该值是存储单元。Tcl使用了一个不同的模型,其值在概念上是不变的,并且在原则上,任何“1、2、3、4”与其他“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对列表的格式有不同的想法)。

我从这里开始: