SICP学习笔记01 vvipi 发表于2018年11月3日,阅读:1530 #### 练习1.5 Ben Bitdiddle发明了一种检测方法,能够确定解释器采用应用序还是正则序求值,代码如下: ```scheme (define (p) (p)) (define (test x y) (if (= x 0) 0 y)) ``` 然后执行`(test 0 (p))`,应用序和正则序的解释器下运行各会发生什么情况? #### 参考答案 来自https://sicp.readthedocs.io/en/latest/chp1/5.html 解答这道题的关键在于了解到应用序和正则序之间的区别(书本的 1.1.5 小节有详细的说明)。 首先,可以确定的是,无论解释器使用的是什么求值方式,调用 `(p)` 总是进入一个无限循环(infinite loop),因为函数 p 会不断调用自身: `(define (p) (p))` 具体到解释器中,执行 (p) 调用会让解释器陷入停滞,最后只能强制将解释器进程杀掉: ```shell 1 ]=> (p) ^Z [1]+ 已停止 mit-scheme $ killall mit-scheme ``` 在应用序中,所有被传入的实际参数都会立即被求值,因此,在使用应用序的解释器里执行 (test 0 (p)) 时,实际参数 0 和 (p) 都会被求值,而对 (p) 的求值将使解释器进入无限循环,因此,如果一个解释器在运行 Ben 的测试时陷入停滞,那么这个解释器使用的是应用序求值模式。 另一方面,在正则序中,传入的实际参数只有在有需要时才会被求值,因此,在使用正则序的解释器里运行 `(test 0 (p))` 时, 0 和 (p) 都不会立即被求值,当解释进行到 if 语句时,形式参数 x 的实际参数(也即是 0)会被求值(求值结果也是为 0 ),然后和另一个 0 进行对比`((= x 0))`,因为对比的值为真(#t),所以 if 返回 0 作为值表达式的值,而这个值又作为 test 函数的值被返回。 因为在正则序求值中,调用 (p) 从始到终都没有被执行,所以也就不会产生无限循环,因此,如果一个解释器在运行 Ben 的测试时顺利返回 0 ,那么这个解释器使用的是正则序求值模式。 > **Note:** 另一个需要说明的地方是『形式参数』和『实际参数』两个名词。 对于一个函数来说,它接受的参数的局部名被称为形式参数。 而调用函数时传入的表达式,被称为实际参数。 比如说,对于函数 (define (square x) (* x x)) 来说, x 就是形式参数,当进行调用 (square 2) 时, 2 就是形式参数 x 的实际参数。 当人们只说『参数』而不说明它是『形式参数』还是『实际参数』时,他们一般指的是『形式参数』,但是具体还是要看上下文来决定。 #### 理解 `(define (p) (p))`这个语句很让人困惑,为了理解它,尝试执行: `(define p (p))`,结果是变量p未定义的错误。 `(define (p) p)`,没有出错。接着运行`p`或者`(p)`,返回的都是一个compound-procedure(组合式),相当于一个函数。 用python的语法再脑补一番之后,理解到 `(define p (p))`相当于python中的`p = p()`。 `(define (p) p)`相当于python中的 ```python def p(): return p # 返回函数本身的引用(未调用) ``` 而原文中的`(define (p) (p))`则相当于python中的 ```python def p(): return p() # 返回函数本身的调用 ``` 这是一个无限递归的死循环,不断调用函数本身。