我正在使用Scheme中的metacircular评估器进行家庭作业,我需要允许用户通过将特殊表单添加到表中来安装它们。我们的想法是,当用户输入类似(square 5)
的内容时,评估者将查找名为square
的表单。如果找到了,它将返回lambda
语句,例如(lambda (x) (* x x))
。
当代码返回lambda
语句时,我遇到了问题。我收到以下错误消息:
Error: Bad function object:(lambda (x) (* x x))
真正奇怪的是我可以将参数传递给从我的表中检索的函数,只是我必须先将过程体定义为lambda语句,而不是以{{1开头的列表}}
供参考,这里的代码不起作用。 lambda
类似于exp
,因此在这种情况下,(install-special-form 'square (lambda (x) (* x x)))
评估为name
,square
评估为func
:
(lambda (x) (* x x))
这里有一些有用的代码:
(define (install-eval exp)
(define name (cadadr exp))
(define func (caddr exp))
(if (special-form-lookup (list name func))
#f
(begin
(append! special-forms-table (list name func))
name)))
我猜测我的问题是,在使用不起作用的代码时,(define (install exp-list)
(append! special-forms-table exp-list))
(install (list 'square (lambda (x) (* x x))))
被评估为引用,而不是实际的lambda
?如何获取用户输入以存储可以检索和使用的实际lambda
语句?
答案 0 :(得分:1)
您可能将lambda存储为符号列表,而不是实际过程。这就是为什么这不起作用的原因:
(define f '(lambda (x) (* x x)))
(f 10)
=> Error: Bad function object: (lambda (x) (* x x))
首先尝试评估它:
((eval f) 10)
=> 100
答案 1 :(得分:1)
当您返回列表 (lambda (x) (* x x))
时,您无法将其应用于主机,因为它就像执行('(lambda (x) (* x x)) 5)
一样。试试吧。你会得到同样的错误。
当Scheme计算特殊形式(lambda (x) (* x x))
时,它返回一个封闭对象,其环境为创建时的环境。当你调用它时,它将运行具有该环境的主体,并添加了bingind到x
。这需要在您的口译员中进行模拟,因此(lamba (args ...) body)
通常会评估为(closure-tag (args ...) environment body)
。您的申请需要这些能够在正确的环境中呼叫身体上的eval
。奥斯卡建议使用eval
从长远来看是行不通的,因为你无法使用eval
在解释器中进行闭包,如果你侥幸逃脱,我会认为它是作弊的。