代码之家  ›  专栏  ›  技术社区  ›  WilliamKF

TCL中Lisp-Cons细胞的仿真

  •  5
  • WilliamKF  · 技术社区  · 15 年前

    lisp中的list是一系列cons单元格,但在tcl中,list是一个用空格分隔元素的字符串。对于从lisp到tcl的代码转换,可以简单地将lisp列表转换为tcl列表。但是,这会遇到副作用的cons单元无法到达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包可以更好地模拟tcl中的lisp列表?这样的软件包是否可以方便地转换为常规的TCL列表?

    在使用这样的包的tcl中,上面的代码看起来是什么样的?

    1 回复  |  直到 11 年前
        1
  •  7
  •   Donal Fellows    15 年前

    由于语义模型的本质不同,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对于如何格式化列表有不同的想法)。

    推荐文章