网络书屋(Web Reading Room)

A blogging framework for hackers.

The Fifth Interpreter With the Implementation of letrec(Important)

letrec的作用是可以定义内部函数。它的实现类似于let,只不过let实现的主要是局部变量,而他是局部的过程(持保留意见)

错误1.

1
2
3
4
5
6
7
8
9
10
11
  (define-datatype environment environment?
    (empty-env)
    (extend-env
     (bvar symbol?)  ;;;这边是一个 所以是symbol?
     (bval expval?)
     (saved-env environment?))
    (extend-env-rec
     (id symbol?)
     (bvar (list-of symbol?)) ;;这边和proc-val的定义发生了冲突  一个是symbol? 另外一个则是(list-of symbol?)
     (body expression?)
     (saved-env environment?)))

而在实际的extend-env-rec的实现中,则是调用了proc-val,所以并且传入到proc-val,为了保证一致性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
;;;;;;;;;;;;;;;; environment constructors and observers ;;;;;;;;;;;;;;;;
(define apply-env
  (lambda (env search-sym)
    (cases environment env
           (empty-env ()
                      (error 'apply-env "No binding for ~s" search-sym))
           (extend-env (var val saved-env)
                       (if (eqv? search-sym var)
                           val
                           (apply-env saved-env search-sym)))
           (extend-env-rec (p-name b-var p-body saved-env)
                           (if (eqv? search-sym p-name)
                             ;; (proc-val (procedure b-var p-body env))  ;;;注意这里的变化!
                              (proc-val (procedure b-var p-body env #t)) ;;修改了一个bug 目的是可以追踪的作用
                               (apply-env saved-env search-sym))))))

所以需要对应的修改proc-val

1
2
3
4
5
6
7
8
9
  ;; proc? : SchemeVal -> Bool
  ;; procedure : Var * Exp * Env -> Proc
  (define-datatype proc proc? ;;;注意这边的变化 影响到apply-procedure
    (procedure
     ;(var symbol?)  ;;;为了保证和environment的define-datatype一直改为(list-of symbol?)
     (var (list-of symbol?))
     (body expression?)
     (env environment?)
     (trace boolean?))) ;;;需要考虑#t #f

错误2.

1
2
3
4
5
> (run "letrec double(x)=+(x,6) in (double 10)")
enter: (x) = #(struct:num-val 10)
. . cdr: contract violation
  expected: pair?
  given: (num-val 10)

原因在于原先的call-exp并没有遍历的过程,而新改进的apply-procedure则是需要遍历,

1
2
3
4
    (call-exp (rator rand)
             (let ((proc (expval->proc (value-of rator env)))
                   (arg (value-of rand env))) 
               (apply-procedure proc arg)))

改进的call-exp

1
2
3
4
    (call-exp (rator rands)
             (let ((proc (expval->proc (value-of rator env)))
                   (args (map (lambda (x) (value-of x env)) rands)))
               (apply-procedure proc args)))

额外错误

1
 data-structures.scm:7:11: all-defined: not a provide sub-form in: (all-defined)

这个错误是因为现在都是在使用(all-defined-out)

为什么还是会出现如下的错误

1
2
3
4
5
6
> (run "letrec double(x)
            = if zero?(x) then 0 else -((double -(x,1)), 2)
       in (double 6)")
. . extend-env-rec: bad value for bvar field: '(x)
> (run "if zero?(3) then 0 else -(3,2)")
(num-val 1)