我是编程的新手,开始学习Language Scheme。 (我研究《计算机程序的结构和解释》这本书)发现了一个任务,下面将对此进行介绍。我编写了两个代码,将if
替换为cond
,但是由于某些原因,运行第一个代码时会无休止地递归,但是运行第二个代码时会无休止地递归,并且通常会计算 sqrt ...尽管代码相同,为什么会这样?
Alyssa P. Hacker看不到为什么需要以特殊形式提供
if
。她问:“为什么我不能仅仅根据cond
将其定义为一个普通过程?”阿丽莎的朋友伊娃·卢·阿托(Eva Lu Ator)声称确实可以做到这一点,并且她定义了if
的新版本:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
Eva演示了Alyssa的程序:
(new-if (= 2 3) 0 5)
5
(new-if (= 1 1) 0 5)
0
高兴的是,Alyssa使用
new-if
重写了square-root
程序:
(define (sqrt-iter guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
当Alyssa尝试使用它来计算平方根时会发生什么?解释。
第一个代码:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
(define (square x)
(* x x))
(define (average x y)
(/ (+ x y) 2))
(define (improve guess x)
(average guess (/ x guess)))
(define (better-good-enough? prev-guess guess)
(< (abs (- guess prev-guess))
0.00001))
(define (better-sqrt-iter prev-guess guess x)
(new-if (better-good-enough? prev-guess guess)
guess
(better-sqrt-iter guess
(improve guess x)
x)))
(define (better-sqrt x)
(better-sqrt-iter 0 1.0 x))
第二个代码:
(define (square x)
(* x x))
(define (average x y)
(/ (+ x y) 2))
(define (improve guess x)
(average guess (/ x guess)))
(define (better-good-enough? prev-guess guess)
(< (abs (- guess prev-guess))
0.00001))
(define (better-sqrt-iter prev-guess guess x)
(cond ((better-good-enough? prev-guess guess)
guess)
(else (better-sqrt-iter guess
(improve guess x)
x))))
(define (better-sqrt x)
(better-sqrt-iter 0 1.0 x))
答案 0 :(得分:1)
这闻起来像是一个作业问题,但是,假设您使用的是Scheme,请考虑一下一般形式(因此,不是任何一种特殊形式)的情况会发生什么
(f a b c)
被评估:
f
,a
,b
和c
以未定义的顺序进行评估(甚至可能一次都评估); f
的值(换句话说,对其求值的结果)应用于对a
,b
和{{1 }}; 当您使用此评估策略来评估c
的第一版时会发生什么?您可以只用纸和笔进行一些评估,看看会发生什么。
为什么评估规则在这里是个问题?
答案 1 :(得分:0)
我们可以使用替代模型。
(better-sqrt 1)
(better-sqrt-iter 0 1.0 1)
(cond
((better-good-enough? 0 1.0) 1.0)
(else
(better-sqrt-iter 1.0
(improve 1.0 1)
1))))
(cond
(#f 1.0)
(else
(better-sqrt-iter 1.0
(improve 1.0 1)
1))))
(better-sqrt-iter 1.0
(improve 1.0 1)
1)
(better-sqrt-iter 1.0
1.0
1)
(cond
((better-good-enough? 1.0 1.0) 1.0)
(else
(better-sqrt-iter 1.0
(improve 1.0 1.0)
1))))
(cond
(#t 1.0)
(else
(better-sqrt-iter 1.0
(improve 1.0 1.0)
1))))
1.0
现在让我们用new-if
尝试一下:
(better-sqrt 1)
(better-sqrt-iter 0 1.0 1)
方案说,您可以按任何顺序评估程序。我选择从右到左!
(new-if (better-good-enough? 0 1.0)
1.0
(better-sqrt-iter 1.0
(improve 1.0 1)
1))
(new-if (better-good-enough? 0 1.0)
1.0
(new-if (better-good-enough? 1.0 1.0)
1.0
(better-sqrt-iter 1.0
(improve 1.0 1)
1)))
(new-if (better-good-enough? 0 1.0)
1.0
(new-if (better-good-enough? 1.0 1.0)
1.0
(new-if (better-good-enough? 1.0 1.0)
1.0
(better-sqrt-iter 1.0
(improve 1.0 1)
1))))
(new-if (better-good-enough? 0 1.0)
1.0
(new-if (better-good-enough? 1.0 1.0)
1.0
(new-if (better-good-enough? 1.0 1.0)
1.0
(new-if (better-good-enough? 1.0 1.0)
1.0
(better-sqrt-iter 1.0
(improve 1.0 1)
1)))))
;; goes on like this forever!
请注意,我从来没有做过任何good-enough
调用,因为在评估new-if
的主体之前,所有3个表达式都需要完成,而内置 if
首先评估测试表达式,然后根据评估测试表达式的结果,仅评估结果表达式或替代表达式中的一个,因此递归停止。