Lambda 艾伦·凯';s评估/应用爱因斯坦矩

Lambda 艾伦·凯';s评估/应用爱因斯坦矩,lambda,lisp,eval,interpreter,metacircular,Lambda,Lisp,Eval,Interpreter,Metacircular,艾伦·凯是这么说的 所讨论的代码是eval和apply的第一个版本,它看起来非常像现代lisp(我知道) 因为正确的答案很可能是已知的,但丢失了(我的google fu很不错,我至少搜索了20分钟) 我将尽快奖励第一个正确答案(我将查看编辑时间,所以不要试图作弊)250分奖励 我建议其他人也为赏金捐款, 从上面的视频中还记得吗?这些东西让人想起了他发现这颗行星时所处的环境 文本中的代码是用M表达式编写的。我正在做一个翻译,将m表达式翻译成S表达式(lisp代码) 无论如何,这里是第13页的翻译引

艾伦·凯是这么说的

所讨论的代码是
eval
apply
的第一个版本,它看起来非常像现代lisp(我知道)

因为正确的答案很可能是已知的,但丢失了(我的google fu很不错,我至少搜索了20分钟) 我将尽快奖励第一个正确答案(我将查看编辑时间,所以不要试图作弊)250分奖励

我建议其他人也为赏金捐款, 从上面的视频中还记得吗?这些东西让人想起了他发现这颗行星时所处的环境

文本中的代码是用M表达式编写的。我正在做一个翻译,将m表达式翻译成S表达式(lisp代码)

无论如何,这里是第13页的翻译引语:

;______________________________________Lisp Meta-Circular Evaluator S-Expression
;this code is written in the order it appears on pages 10-13 in the Lisp 1.5 Manual 
;and is translated from the m-expressions into s-expressions

(label mc.equal (lambda (x y)
    (mc.cond
        ((atom x) ((mc.cond ((atom y) (eq x y)) ((quote t) (quote f)))))
        ((equal (car x)(car y)) (equal (cdr x) (cdr y)))
        ((quote t) (quote f)))))

(label mc.subst (lambda (x y z)
    (mc.cond
        ((equal y z) (x))
        ((atom z) (z))
        ((quote t) (cons (subst x y (car z))(subst x y (cdr z)))))))

(label mc.append (lambda (x y)
    (mc.cond 
        ((null x) (y))
        ((quote t) (cons (car x)) (append (cdr x) y)))))

(label mc.member (lambda (x y)
    (mc.cond ((null y) (quote f))
    ((equal x (car y)) (quote t))
    ((quote t) (member x (cdr y))))))

(label mc.pairlis (lambda (x  y  a)
    (mc.cond ((null x) (a)) ((quote t) (cons (cons (car x)(car y))
    (pairlis (cdr x)(cdr y) a)))))

(label mc.assoc (lambda (x a)
    (mc.cond ((equal (caar a) x) (car a)) ((quote t) (assoc x (cdr a))))))

(label mc.sub2 (lambda (a z)
    (mc.cond ((null a) (z)) (((eq (caar a) z)) (cdar a)) ((quote t) (
    sub2 (cdr a) z)))))

(label mc.sublis (lambda (a y)
    (mc.cond ((atom y) (sub2 a y)) ((quote t) (cons (sublis a (car y))))
    (sublis a (cdr y)))))

(label mc.evalquote (lambda (fn x)
    (apply fn x nil)))

(label mc.apply (lambda (fn x a)
    (mc.cond ((atom fn) (
        (mc.cond
            ((eq fn car) (caar x))
            ((eq fn cdr) (cdar x))
            ((eq fn cons) (cons (car x)(cadr x)))
            ((eq fn atom) (atom (car x)))
            ((eq fn eq) (eq (car x)(cadr x)))
            ((quote t) (apply (eval (fn a)x a))))))
        ((eq (car fn) lambda) (eval (caddr fn) (parlis (cadr fn) x a)))
        ((eq (car fn) label) (apply (caddr (fn)x cons (cons (cadr (fn)))
            (caddr fn))a)))))

(label mc.eval (lambda (e a)
    (mc.cond
        ((atom e) (cdr (assoc e a)))
        ((atom (car e)) (mc.cond
            ((eq (car e) quote) (cadr e))
            ((eq (car e) cond) (evcon (cdr e) a))
            ((quote t) (apply (car e) (evlis (cdr e) a) a))))
        ((quote t) (apply (car e) (evlis (cdr e) a) a))))))

(label mc.evcon (lambda (c a)
    (mc.cond 
        ((eval (caar c) a) (eval (cadar c) a))
        ((quote t) (evcon (cdr c) a)))))

(label mc.evlis (lambda (m a)
    (mc.cond
        ((null m) (nil))
        ((quote t) (cons (eval (car m) a) (evlis (cdr m) a)))))))

有两个不同的问题:

第一:动态绑定作为一个bug

不确定他的意思,但通常在麦卡锡的
EVAL
中,使用
动态绑定可以被视为一个bug。他没有实现变量的词法作用域。例如,该错误出现在此处:

请参阅函数
maplist
diff
。两者都使用
x
。这不会如图所示工作,因为早期的Lisp提供了动态绑定

一个更简单的示例,显示计算器使用动态绑定

注意
eval.
的用法,这是麦卡锡的
eval

CL-USER 36 > (eval. '((lambda (f)
                        ((lambda (x) (f))
                         'foo))
                      '(lambda () x))
                    nil)
这将返回
FOO
,因为
X
的值是从动态绑定中查找的

如果我们查看代码,它要求我们以列表的形式传递函数:
”(lambda()x))
。这将计算为一个列表。稍后将通过
(f)
-调用该列表,不带任何参数。然后,该列表被解释为lambda表达式,
x
将通过查看
x
的当前动态绑定来解析。
((lambda(x)(f))'FOO)
引入了
x
FOO的绑定。这将在那时使用

在60年代的Lisp 1.5实现中,可能会编写类似于:

((lambda (f)
   ((lambda (x) (f))
    'foo))
 (function (lambda () x)))
请注意,
(函数(lambda()x))
的计算结果是标记、动态环境和函数的列表。不幸的是,Lisp1.5实现仍然使用动态绑定。所以这已经是正确的方向了,但是这个错误当时并没有被真正修复。改进了一个函数作为参数传递给其他函数的情况

FUNARG问题

在60年代/70年代初,人们花了相当长的时间才解决这个问题。这被称为FUNARG问题。例如,见Joel Moses文件:。有各种各样的解决方案来创建闭包和使用词汇绑定。通常,解释器使用动态绑定,编译器使用词汇绑定。在Lisp世界中,这基本上是通过Scheme解决的,Scheme默认引入词汇绑定。然后,这种词法绑定允许使用闭包来模拟对象系统(Kay可能认为这很有用)。见报纸:从1975年开始

在Common Lisp中,默认情况下使用词法范围,就像Lisp方言方案一样,上面的示例是一个错误(这里我们使用Common Lisp中的
eval
,稍微更改代码,使其成为合法的Common Lisp代码):

正如您在Common Lisp(和Scheme)中所看到的,
(lambda()x)
是一个真正的lambda表达式,而不是一个带引号的列表,
(function(lambda()x))
计算为一个函数对象-如果有绑定,那么它就是一个闭包-一个函数对象及其绑定。此函数对象/clojure被传递,然后通过
(funcall f)
调用。由于
x
没有引用任何内容(它是一个自由变量),并且没有通过绑定进行查找,因此在执行代码时会发生错误。这就是我们想要的:我们想要词法绑定,代码中的这个错误就是一个结果。这个错误没有发生在McCarthy原来的Lisp中,这是这个错误的一个结果。修复这个bug(花了十多年的时间才完全满意),使我们能够在Lisp中使用闭包,就像在CommonLisp中一样,它从Scheme中学习闭包

Kay可能也认为动态绑定是一个bug。这是一个非常基本的问题,理解/解决它有助于设计和开发更好的编程语言

注意,典型的早期Smalltalk实现(例如Xerox的Smalltalk 80)也使用动态绑定

麦卡锡关于那只虫子的事

在(1979年)麦卡锡写道(我用粗体字):

d自由变量。毫无疑问,James R.Slagle编程了以下LISP函数定义,并在它无法正常工作时抱怨:

函数的目标是找到满足p[x]且返回f[x]的x的子表达式。如果搜索不成功,则将计算无参数的连续函数u[],并返回其值。困难在于,当发生内部递归时,car[x]的值是外部值,但实际使用的是内部值。在现代术语中,需要词汇范围界定,并获得动态范围界定

我必须承认,我认为这个困难只是一个缺陷,并表示相信史蒂夫·拉塞尔很快就会解决它。他确实解决了这个问题,但他发明了所谓的FUNARG设备,将词汇环境与函数参数结合起来。类似的困难后来在Algol60中也出现了,而罗素的方法是解决这个问题的更全面的方法之一。虽然它在解释器中运行良好,但在编译代码中,全面性和速度似乎是对立的,这导致了一系列折衷。不幸的是,时间不允许写一个附录,给出问题的历史和感兴趣的读者
CL-USER 43 > (eval '((lambda (f)
                       ((lambda (x) (funcall f))
                        'foo))
                     (function (lambda () x))))

Error: The variable X is unbound.
((eq (car fn) lambda) (eval (caddr fn) (parlis (cadr fn) x a)))
                                      ;^^^^^^^^^^^^^^^^^^^^^^