我遇到了这个问题
例如我有
(define (mypow x) (* x x))
我需要从给定列表中评估表达式。 (我正在编写一个模拟器,我在列表中得到一系列命令作为参数)
我已经读过R5RS标准需要包含在函数eval中作为第二个arg(scheme-report-environment 5),但我仍然遇到这个问题。
这适用(带标准功能):
(eval '(sqrt 5) (scheme-report-environment 5))
但这不是:
(eval '(mypow 5) (scheme-report-environment 5))
它说:
../../../../../../usr/share/racket/collects/racket/private/kw.rkt:923:25:mypow:undefined;无法引用未定义的标识符
尽管在提示返回时简单地调用了mypow:
#<procedure:mypow>
请问有什么建议吗? (顺便说一句我需要使用R5RS)
(scheme-report-environment 5)
返回R5RS Scheme标准中定义的所有绑定,而不是任何用户定义的绑定。这是设计的。使用它作为eval
的第二个参数,你永远无法做你想做的事。
该报告提到(interaction-environment)
是可选的。因此,您无法保证实现具有它,但它将具有来自(scheme-report-environment 5)
的所有绑定
为了完整性,有(null-environment 5)
只有语法绑定。例如。 (eval '(lambda (v) "constan) (null-environment 5))
工作,但(eval '(lambda (v) (+ 5 v)) (null-environment 5))
将不会因为+
不在最终的程序关闭。
完成任务的其他方法
通常你可以在不使用eval
的情况下离开。应该几乎不惜一切代价避免使用eval
。在过去的16年里,我曾两次在生产代码中故意使用eval
。
通过使用thunk
而不是数据:
(define todo
(lambda () ; a thunk is just a procedure that takes no arguments
(mypow 5))
(todo) ; ==> result from mypow
现在想象一下,你有一个你想做的操作列表:
(define ops
`((inc . ,(lambda (v) (+ v 1))) ; notice I'm unquoting.
(dec . ,(lambda (v) (- v 1))) ; eg. need the result of the
(square . ,(lambda (v) (* v v))))) ; evaluation
(define todo '(inc square dec))
(define with 5)
;; not standard, but often present as either fold or foldl
;; if not fetch from SRFI-1 https://srfi.schemers.org/srfi-1/srfi-1.html
(fold (lambda (e a)
((cdr (assq e ops)) a))
with
todo)
; ==> 35 ((5+1)^2)-1