自己定义的 new-if
过程:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
(new-if (= 2 3) 0 5)
; 5
(new-if (= 1 1) 0 5)
; 0
当用 new-if
编写求平方根时:
(define (sqrt-iter guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve guess x) x)))
此时会发生什么呢......答案是会爆栈/递归深度过大
在 1-5 中明确说过, if 是一个特殊形式的 惰性
的过程, 与普通过程不同
而这里的 new-if, 是个自己定义的普通过程, 而非编译器提供的特殊过程
因此, 每次调用 sqrt-iter
, 其实都会求值第二分支中的 (sqrt-iter (improve guess x) x)
而该第二分支的求值又会再次求值其第二分支的表达式......
那么, 你可能又要问了:
(new-if (= 2 3) 0 5)
; 5
(new-if (= 1 1) 0 5)
; 0
先前的这部分代码, new-if 看起来不是只返回了一个值吗? 为什么你说是两个都求值?
如果两个都求值的话, 难道不会在 REPL 中打印 05
吗?
no, no, no, 虽然 new-if 在接收参数时对每个参数都求值了, 但是其内部定义是个 cond, 其只会返回某个单一的表达式
我们可以添加一点副作用(输入输出等)来进行验证:
(new-if #t (display 1) (display 2))
; 12
(if #t (display 1) (display 2))
; 1
new-if 在接收参数时便进行了求值, 因此打印输出了 12
而 if 是先判断条件再选取分支进行求值, 因此只打印输出了 1