评估程序环境中的存储过程导致无限循环
Storing procedure in environment of evaluator leads to infinite loop
我转换了 Structure and Interpretation of Computer Programs (SICP) version of the meta-circular evaluator to Clojure. The main difference (besides syntax) is the handling of the environment structure. Since you cannot use set-car!
and set-cdr!
in Clojure, these are implemented via an atom holding a map (copied from the code of Greg Sexton's chapter 4 notes on GitHub,我认为它与无法定义过程有同样的问题。
两个评估者的代码可以在这里找到:
不幸的是,定义过程无法正常工作。我期望发生的是:
;;; M-Eval input:
(defn (add1 x) (+ x 1))
;;; M-Eval value:
< Environment printed >
;;; M-Eval input:
(add1 10)
;;; M-Eval value:
11
注:除了define叫defn外,基本都是Scheme代码输入。
此处定义 add1
在环境结构中存储过程,当使用 (add1 10
) 调用时,符号 add1
在环境中查找,过程由求值器应用于 10,结果为 11。
然而我看到的是这样的:
;;; M-Eval input:
(defn (add1 x) (+ x 1))
;;; M-Eval value:
{add1 (procedure (x) (((+ x 1))) (#object[clojure.lang.Atom 0x7c197838 {:status :ready, :val {add1 (procedure (x) (((+ x 1))) (#object[clojure.lang.Atom 0x7c197838 {:status :ready, :val {add1 (procedure (x) (((+ x 1))) (#object[clojure.lang.Atom 0x7c197838 {:status :ready, :val {add1 (procedure (x) (((+ x 1))) (#object[clojure.lang.Atom 0x7c197838 {:status :ready, :val {add1 (procedure (x) (((+ x 1))) (... et cetera)
我得到一个很长的环境输出(看起来创建的过程有一个包含过程本身的环境),然后是 WhosebugError。
- Unhandled clojure.lang.Compiler$CompilerException
Error compiling:
scheme-evaluator.clj:316:1
(...)
- Caused by java.lang.WhosebugError
(No message)
为清楚起见,我将 eval
放在下面。但我认为 the whole code 需要 运行 才能正确查看问题所在。
(defn eval [exp env]
(cond (self-evaluating? exp) exp
(variable? exp) (lookup-variable-value exp env)
(quoted? exp) (text-of-quotation exp)
(assignment? exp) (eval-assignment exp env)
(definition? exp) (eval-definition exp env)
(if? exp) (eval-if exp env)
(lambda? exp) (make-procedure (lambda-parameters exp)
(lambda-body exp)
env)
(begin? exp) (eval-sequence (begin-actions exp) env)
(cond? exp) (eval (cond->if exp) env)
(application? exp) (apply (eval (operator exp) env)
(list-of-values (operands exp) env))
:else (throw (Throwable. (str "Unknown expression type \"" exp "\" -- EVAL")))))
我希望有人能帮我解决这个问题,或许还能阐明这里出了什么问题。
问题是 lambda-body
程序。 lambda
列表包含 3 个元素;标记、参数及其主体。然而,通过 lambda-body
检索正文使用 cddr
而不是 caddr
,因此结果被额外的列表包裹。因此,如果您像这样更改 lambda-body
的定义:
(defn lambda-body [exp] (third exp))
然后就可以计算出结果了。
注意:如果你想避免堆栈溢出错误,那么你可以将 eval-definition
或 define-variable!
更改为 return 其他内容,例如给定的名称 exp
.
我转换了 Structure and Interpretation of Computer Programs (SICP) version of the meta-circular evaluator to Clojure. The main difference (besides syntax) is the handling of the environment structure. Since you cannot use set-car!
and set-cdr!
in Clojure, these are implemented via an atom holding a map (copied from the code of Greg Sexton's chapter 4 notes on GitHub,我认为它与无法定义过程有同样的问题。
两个评估者的代码可以在这里找到:
不幸的是,定义过程无法正常工作。我期望发生的是:
;;; M-Eval input:
(defn (add1 x) (+ x 1))
;;; M-Eval value:
< Environment printed >
;;; M-Eval input:
(add1 10)
;;; M-Eval value:
11
注:除了define叫defn外,基本都是Scheme代码输入。
此处定义 add1
在环境结构中存储过程,当使用 (add1 10
) 调用时,符号 add1
在环境中查找,过程由求值器应用于 10,结果为 11。
然而我看到的是这样的:
;;; M-Eval input:
(defn (add1 x) (+ x 1))
;;; M-Eval value:
{add1 (procedure (x) (((+ x 1))) (#object[clojure.lang.Atom 0x7c197838 {:status :ready, :val {add1 (procedure (x) (((+ x 1))) (#object[clojure.lang.Atom 0x7c197838 {:status :ready, :val {add1 (procedure (x) (((+ x 1))) (#object[clojure.lang.Atom 0x7c197838 {:status :ready, :val {add1 (procedure (x) (((+ x 1))) (#object[clojure.lang.Atom 0x7c197838 {:status :ready, :val {add1 (procedure (x) (((+ x 1))) (... et cetera)
我得到一个很长的环境输出(看起来创建的过程有一个包含过程本身的环境),然后是 WhosebugError。
- Unhandled clojure.lang.Compiler$CompilerException
Error compiling:
scheme-evaluator.clj:316:1
(...)- Caused by java.lang.WhosebugError
(No message)
为清楚起见,我将 eval
放在下面。但我认为 the whole code 需要 运行 才能正确查看问题所在。
(defn eval [exp env]
(cond (self-evaluating? exp) exp
(variable? exp) (lookup-variable-value exp env)
(quoted? exp) (text-of-quotation exp)
(assignment? exp) (eval-assignment exp env)
(definition? exp) (eval-definition exp env)
(if? exp) (eval-if exp env)
(lambda? exp) (make-procedure (lambda-parameters exp)
(lambda-body exp)
env)
(begin? exp) (eval-sequence (begin-actions exp) env)
(cond? exp) (eval (cond->if exp) env)
(application? exp) (apply (eval (operator exp) env)
(list-of-values (operands exp) env))
:else (throw (Throwable. (str "Unknown expression type \"" exp "\" -- EVAL")))))
我希望有人能帮我解决这个问题,或许还能阐明这里出了什么问题。
问题是 lambda-body
程序。 lambda
列表包含 3 个元素;标记、参数及其主体。然而,通过 lambda-body
检索正文使用 cddr
而不是 caddr
,因此结果被额外的列表包裹。因此,如果您像这样更改 lambda-body
的定义:
(defn lambda-body [exp] (third exp))
然后就可以计算出结果了。
注意:如果你想避免堆栈溢出错误,那么你可以将 eval-definition
或 define-variable!
更改为 return 其他内容,例如给定的名称 exp
.