在评估者的环境中存储过程导致无限循环

时间:2016-04-09 17:48:15

标签: clojure scheme evaluation sicp

我将元循环评估程序的Structure and Interpretation of Computer Programs (SICP)版本转换为Clojure。主要区别(除了语法)是环境结构的处理。由于您无法在Clojure中使用set-car!set-cdr!,因此这些是通过持有地图的原子(从Greg Sexton's chapter 4 notes on GitHub的代码复制而来实现的,我相信它具有相同的问题而无法使用定义程序)。

这两个评估者的代码可以在这里找到:

不幸的是,定义一个过程无法正常工作。我期望发生的是:

  

;;; M-Eval输入:
  (defn(add1 x)(+ x 1))

  ;;; M-Eval值:
  <环境印刷>

  ;;; M-Eval输入:
  (add1 10)

  ;;; M-Eval值:
  11

注意:它基本上是输入的代码,除了定义名为defn。

这里定义add1在环境结构中存储一个过程,当用(add1 10调用它时)在环境中查找符号add1,并且评估者创建的过程是适用于10,结果为11。

但我看到的是:

  

;;; M-Eval输入:
  (defn(add1 x)(+ x 1))

  ;;; M-Eval值:
  {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)) ))(...等等)

我得到一个很长的环境输出(看起来创建的过程有一个包含过程本身的环境),然后是一个StackOverflowError。

  
      
  1. 未处理的clojure.lang.Compiler $ CompilerException
      编译错误:
      方案-evaluator.clj:316:1
      (...)

  2.   
  3. 由java.lang.StackOverflowError引起的   (没有消息)
  4.   

为清楚起见,我将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")))))

我希望有人能帮助我解决这个问题,或许可以对这里出了什么问题有所了解。

1 个答案:

答案 0 :(得分:1)

问题是lambda-body程序。 lambda列表包含3个元素;标签,参数和它的主体。但是,按lambda-body检索正文会使用cddr而不是caddr,因此结果会被额外列表包裹。因此,如果您更改lambda-body的定义,请执行以下操作:

(defn lambda-body [exp] (third exp))

然后你可以得到计算结果。

注意:如果您想避免堆栈溢出错误,那么您可以更改eval-definitiondefine-variable!以返回其他内容,例如给定exp的名称。