我通过SICP使用狡诈作为我的主要语言的练习当前工作。我发现了一个奇怪的现象,而在第3.5节执行演习。我已经使用转载狡诈1.4,狡诈1.8.6和1.8.7狡诈这种行为在各种平台和敢肯定它不是针对我的设置。

此代码工作正常(和计算e):

  (define y (integral (delay dy) 1 0.001))
  (define dy (stream-map (lambda (x) x) y))
  (stream-ref y 1000)

下面的代码得到相同的结果:

  (define (solve f y0 dt)
    (define y (integral (delay dy) y0 dt))
    (define dy (stream-map f y))
    y)
  (stream-ref (solve (lambda (x) x) 1 0.001) 1000)

但它产生的错误消息:

standard input:7:14: While evaluating arguments to stream-map in expression (stream-map f y):
standard input:7:14: Unbound variable:
y ABORT: (unbound-variable)

嵌入过程定义所以,当在(定义Y ...)不工作,而在REPL全球环境的过程外,它工作正常。

我在做什么错在这里?我可以张贴所述辅助代码(即,积分,流映射等等的定义)如果需要的话,也。随着利弊流系统相关的代码外,他们都在这本书。我自己的用于狡诈实施利弊流的如下:

(define-macro (cons-stream a b)
  `(cons ,a (delay ,b)))
有帮助吗?

解决方案

之间当你在REPL评估定义一一,当你将它们内部solve会发生什么的关键区别在于,在第一种情况下,它们被顺序地评估,从而表达y(stream-map <some-function> y)已经在范围,而用内部定义或letrec,它是尚未公布。

有趣的是,MIT方案,通过打算SICP时我使用的,就没有这样的问题当时仍然对待letrec和内部定义是不同的:

;; this is an error
(letrec ((xs '(1 2 3)) (ys (map (lambda (x) (+ x 1)) xs))) ys)

;; this is still an error (and is treated as such by Guile),
;; yet evaluates to (2 3 4) in MIT Scheme
(let () (define xs '(1 2 3)) (define ys (map (lambda (x) (+ x 1)) xs)) ys)

我不知道在内部定义了原“修订的报告在算法语言计划”或R2RS,但至少从R3RS被认为等同于letrec。显然,这个特点麻省理工学院的环境影响的书......或者也许是周围的其他方式。

其他提示

可以不具有取决于彼此内部限定;语言规范明确指出这个(R5RS 5.2.2):

  

...必须有可能来评估每个表达在每一个内部定义的而不设定或参照的任何可变限定。

可以认为这虽然解释之前收集所有的定义和评估他们的身体以随机的顺序。因为顺序是随机的,不能有,如果你期望它的工作是任何相互依赖性。

甚至还有附着于说,它不会就所有计划的求解定义(#71)一个注脚。

您必须编写的代码,使得一个定义是非常清楚地在其它的范围内,像嵌套让:

(define (solve f y0 dt)
  (let ((y (integral (delay dy) y0 dt)))
    (let ((dy (stream-map f y)))
      y)))

继的意见(从R5RS 4.2.2参考报价)的想法,我现在已经包装“y”和“dy”的定义为(lambda () ...)s:

  (define (solve f y0 dt)
    (define (y) (integral (delay (dy)) y0 dt))
    (define (dy) (stream-map f (y)))
    (y))

这确保了每个定义的<init>部分可以不参照所述圆形定义的变量,因为定义程序,而不是与像在原始的情况下其他变量的表达式来评价。

现在的代码肯定慢得多(因为功能将得到递归包裹)和被增加的堆栈大小的需求,但以下工作,并产生正确的结果:

  (debug-set! stack 2000000)
  (stream-ref (solve (lambda (x) x) 1 0.001) 1000)

通过类似的修改,Michal的示例代码工作只要一个定义程序而不是变量:

  (let ()
    (define (xs) '(1 2 3))
    (define (ys) (map (lambda (x) (+ x 1)) (xs)))
    (ys))

适用于狡诈1.8.6。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top