计算机程序的结构和解释3.5.2引入无限流:
(define ones
(cons-stream 1 ones))此代码在DrRacket中不起作用,错误如下:
1:未定义;不能在定义之前引用标识符。
其他代码如下:
(define (integers-starting-from n)
(cons-stream n
(integers-starting-from (+ n 1))))
(define integers (integers-starting-from 1))产生错误:
交互禁用
(陷入无限循环?)
据我所读(SICP),实现无限流的关键是延迟评估:
(define (delay exp)
(lambda () exp))
(define (cons-stream a b)
(cons a
(delay b)))在cons-stream中使用这种方法,无限流仍然是非法的。
这种数据结构让我想起了递归函数,在它的定义中,自调用是合法的(在编译中),无论是在实际的退出中还是在不存在的情况下。
为什么引用自己的值是非法的?连推荐信都被推迟了?
无限流能被其他编程语言所支持吗?
如果不是,这是处理器处理汇编语言的方式吗?数据堆栈之类的?
发布于 2015-08-08 16:47:47
这是因为define中的表达式是在名称绑定到值之前计算的。它试图在定义(cons-stream 1 ones)之前计算ones,从而导致错误。
这对于函数来说工作得很好的原因是,当函数被计算时,不对函数的主体进行计算。也就是说,要计算(lambda (x) (f x)),语言返回一个函数,而不查看它的主体。因为
(define (f x) (f x))是用于定义lambda的语法糖,应用相同的逻辑。
您是否将cons-stream定义为上面所示?如果您使cons-stream成为一个正常的函数,它将不能正常工作。由于Scheme在默认情况下是严格的,因此在调用函数之前对参数进行计算。如果cons-stream是一个正常函数,那么在传递给delay之前,b将被完全计算,这就使您遇到了一个无限循环。
SICP中的cons-stream是一种“特殊形式”,而不是一个函数,这意味着它可以控制参数的计算方式。
如果您使用stream-cons和其他内置在Racket中的stream-操作,您将得到您想要的行为。
最后,其他一些语言确实允许引用自己的值。Haskell就是一个很好的例子,因为在默认情况下,一切都是懒惰的。下面是一个Haskell片段,它将ones定义为无限列表。(由于一切都很懒惰,Haskell列表的行为就像Scheme流一样):
ones = 1 : ones发布于 2015-08-08 16:50:06
这一定义适用于球拍:
(define ones
(cons-stream 1 ones))…只要您将cons-stream的延迟实现作为一种特殊形式提供,这就是SICP第3.5节的全部要点:
(define-syntax cons-stream
(syntax-rules ()
((_ head tail)
(cons head (delay tail)))))发布于 2015-08-09 16:31:45
添加到上面的答案中,为了确保代码运行,您还应该像下面这样定义delay:
(define-syntax delay
(syntax-rules ()
((_ exp)
(lambda () exp))))必须将delay和cons-stream定义为宏。
在另一个选项中,您可以只调用在Racket中预定义的delay,而不是构建一个新的。
但别这么做:
(define (delay exp)
(lambda () exp))编译器将接受您的定义,因此程序在计算中崩溃:
交互禁用
https://stackoverflow.com/questions/31896117
复制相似问题