我正在尝试一个关于SICP第4章的例子(编写LISP解释器的一部分)
(define (definition-value exp)
(if (symbol? (cadr exp))
(caddr exp)
(make-lambda
(cdadr exp) ; formal parameters
(cddr exp) ; body
)
)
)
(define (make-lambda parameters body)
(cons 'lambda (cons parameters body))
)
我测试过它,'(define(double x)(+ x x))上的definition-value应该返回一个lambda函数
( (definition-value '(define (double x) (+ x x))) 10)
球拍输出
procedure application: expected procedure, given: (lambda (x) (+ x x)); arguments were: 10
不是“(lambda(x)(+ x x))”程序?或者它是一个参考?如果它是一个参考,任何“取消引用”它的方式?
答案 0 :(得分:2)
definition-value
返回给定的定义表达式中的值作为参数:
(definition-value '(define x 42))
=> 42
(definition-value '(define (qq x) (+ x y 42)))
=> (make-lambda '(x) '((+ x y 42)))
=> '(lambda (x) (+ x y 42))
您不能像以下那样将引用列表作为函数调用:( '(lambda (x) (+ x y 42)) 10)
无效。它不是一个函数,它只是一个s-expression。
definition-value
是an interpreter的一部分。这种解释器是“解除引用”的方式,即解释函数定义。不同的解释器可以有不同的方式来解释相同的函数定义,为结果语言提供不同的语义。
表达式的评估必须在上下文中完成 - 它们出现在某些lexical scope(代码中的区域,其中变量可见)内,这会产生environments(也是,this)。在上面的示例中,y
在正在解释的程序中的某个封闭范围中定义。试着通过调用Racket's eval
来解释REPL中的表达式,y
会有什么价值?
答案 1 :(得分:0)
我想到了答案,如果在文件中执行一个Racket脚本,racket解释器不知道命名空间,但是,REPL知道它。解决方案是在文件的开头添加此行
(define ns (make-base-namespace))
然后在使用时将ns传递给eval
(eval <what ever code reference here> ns)
这将使我上面提到的例子起作用。