我正在阅读 SICP 第 3.5.1 节,其中给出了 MIT/GNU 方案中提供的原始程序的实现。
我尝试加载这些实现而不考虑顺序,因为它们都是
(define ...)
,但实际上顺序很重要(对于以下简化的演示,我们需要在(define (cons-stream a b) ...)
之前运行(define (stream-enumerate-interval low high) ...)
)。
我跑步:
;; case 1
(define (stream-enumerate-interval low high)
(if (> low high)
the-empty-stream
(cons-stream
low
(stream-enumerate-interval (+ low 1) high))))
(stream-enumerate-interval 0 10)
(define (cons-stream a b)
(display "call cons-stream")
(cons a (delay b)))
(stream-enumerate-interval 0 10)
; not output "call cons-stream"
;; case 2
(define (cons-stream-1 a b)
(display "call cons-stream")
(cons a (delay b)))
(define (stream-enumerate-interval low high)
(if (> low high)
the-empty-stream
(cons-stream-1
low
(stream-enumerate-interval (+ low 1) high))))
(stream-enumerate-interval 0 10)
(define (cons-stream-1 a b)
(display "call cons-stream-1")
(cons a (delay b)))
(stream-enumerate-interval 0 10)
; will use the new "cons-stream-1" by outputing "call cons-stream-1".
;; case 3
(define (test-redefine-+ . args)
(display (apply + args)))
(test-redefine-+ 2 3 4)
(define (+ . args)
(apply * args))
(test-redefine-+ 2 3 4)
; redefinition works by outputing 24.
正如书所说:
我们假设有一个全局环境,由单个框架(没有封闭环境)组成,其中包括与原始过程相关的符号的值。
正如上面所说,我们只记录通过构造一个框架,将过程的形式参数绑定到调用的参数,然后在构造的新环境的上下文中评估过程的主体,将过程对象应用于一组参数。新框架将应用过程对象的环境部分作为其封闭环境。
通过计算相对于给定环境的 lambda 表达式来创建过程。生成的过程对象是由lambda 表达式的文本和指向创建过程的环境的指针组成的对。
define
时的“lambda表达式的text
”,而不像
cons-stream
那样记录里面使用的procedure的值。所以恕我直言,当我们调用第二个
(stream-enumerate-interval 0 10)
时,我们将尝试通过参数绑定在“新环境”中查找
cons-stream
的值。既然这会失败,那么我们看看“封闭环境”,即这里的全局环境。然后预计
cons-stream
已绑定到新值。但事实并非如此。 但是,对于用户自定义的
lambda
func
cons-stream-1
则不会出现上述问题。有人可以告诉我这两种情况对应的环境图之间的区别吗(不需要画图,可能很常规且乏味。清晰的文字对我来说就可以了)?
cons-stream
有关。 你的两个定义都是不正确的,因为
cons-stream
必须定义为
(cons-stream a b)
相当于
(cons a (delay b))
(从 3.5.1 开始)。这样的东西不能被定义为应用顺序语言中的过程,因为像
(a b c)
这样的形式被评估为:
a
、
b
和
c
;
a
的评估结果应用于评估两个参数的结果。
cons-stream
和
delay
都不能以这种方式实现,因为它们不得评估一个或多个论点。相反,它们要么是由语言定义的原语,要么是
宏,可以将其视为指定源的某些位如何转换为源的其他位的规则。
这意味着,例如,
(define upfrom
(lambda (v)
(cons-stream v (upfrom (+ v 1)))))
(define upfrom-0 (upfrom 0))
会起作用:很容易看出它不能这样做 - 它将无法终止 - 根据您对 cons-stream
的定义。然后发生的事情是,在您将
cons-stream
定义为普通过程之前,源代码到其他源代码的转换已经发生。