我正在编写一个Lisp(GitHub处的代码),我想实现本地绑定。目前我有两种语法:
(let <var> <val> <expr>)
用于绑定单个变量或函数,
(with (<var1> <val1> ... <varN> <valN>) <expr>)
一次绑定多个值。
目前,绑定是按顺序评估的,每个新的函数绑定都会保留其定义的环境的副本,因此<var2>
可以引用<var1>
,但反之亦然。
我想修改代码,以便在一次绑定多个值时有效地同时绑定。例如,我希望能够写(这是一个简单的例子,但它应该说明这个想法):
(define (h y)
(with ((f x) (if (eq? x 0) #t (g (- x 1)))
(g x) (if (eq? x 0) #f (f (- x 1))))
(f y))
目前此代码未运行 - g
关闭f
,但不是相反。
在Lisp中实现同步绑定是否有规范方法?
答案 0 :(得分:1)
在SICP中,internal definitions部分介绍了此主题。特别是,练习4.16,4.18,4.19告诉您如何实现不同的策略以实现同时定义。
语法略有不同,但书中的想法归结为转换此代码:
(lambda <vars>
(define u <e1>)
(define v <e2>)
<e3>)
进入此代码:
(lambda <vars>
(let ((u '*unassigned*)
(v '*unassigned*))
(set! u <e1>)
(set! v <e2>)
<e3>))
同样的想法适用于您的with
特殊表单。请查看链接的书籍以获取更多实施细节。
答案 1 :(得分:1)
在(with (a (+ 2 2)))
中,我们将a
绑定到表达式(+ 2 2)
的值,因此a
变为4.但在(with ((f x) (+ x x)))
我们正在做其他事情:我们将f
绑定到一个函数。这是(with (f (lambda (x) (+ x x))))
的语法糖。
要处理这种情况,您必须在两次传递中处理绑定。首先收集所有变量并创建包含所有变量的环境。然后评估初始化的表达式并将它们的值存储在相应的变量中。这些表达式的评估在 环境中进行,因此每个表达式都可以看到所有变量。初始化是通过赋值完成的。变量最初可以是nil
,或者有一些陷阱值,如果它们被访问就会爆炸。