Lisp 一直在变化, scheme 作为 Lisp 的一门方言是从 Lisp 演化而来。
在 linux 下安装 scheme 解释器。
Note
guile-2.0 - GNU extension language and Scheme interpreter
可以使用 guile
$ sudo apt-get install guile-2.0
通常情况下他们得到的结果是一样的,有写特殊情况下,会得出不同的结果,见习题1.5
lisp 采用的是应用序求值,部分原因是这样可以避免对部分表达式重复求值从而提高效率。
10,12,8,3,10 6,a,b,19,#f,4,16,6,16
(/ (+ 5 4 (- 2 (- 3 (+ 6 (/ 4 5)))))
(* 3 (- 6 2) (- 2 7)))
(define (max x y) (if (< x y) y x))
(define (min x y) (if (< x y) x y))
(define (func x y z)
(+ (max x y) (max (min x y) z)))
a 加 (b的绝对值)
(define (p) (p))
(define (test x y)
(if (= x 0)
0
y))
而后求值下列表达式:
(test 0 (p))
首先 (define (p) (p)) 定义了一个永远返回自己的递归死循环。直接调用 (p) 命令行就死掉了。
如果是正则序:
首先替换 (test 0 (p)) 中的 test 然后再计算整个列表的值。因此替换后相当于是
(if (= 0 0) 0 (p))
而 if 的条件为 true 因此返回的是0 掠过了(p)这个死循环
如果是应用序求值:
首先需要计算 (test 0 (p)) 中每个参数的值。然后再带入 test 中求值。因此,在计算参数的过程中,
程序会陷入死循环。
在 guile 中测试的结果是。 程序进入了死循环。
(define (average x y)
(/ (+ x y) 2))
(define (improve guess x)
(average guess (/ x guess)))
(define (square x)
(* x x))
(define (good-enough? guess x)
(< (abs (- (square guess) x)) 0.001))
(define (sqrt-iter guess x)
(if (good-enough? guess x)
guess
(sqrt-iter (improve guess x) x)))
(define (sqrt x)
(sqrt-iter 1.0 x))
scheme@(guile-user)> (sqrt 1)
$3 = 1.0
scheme@(guile-user)> (sqrt 2)
$4 = 1.41421568627451
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
它看起来工作的很不错:
scheme@(guile-user)> (new-if (= 2 3) 0 5)
$1 = 5
scheme@(guile-user)> (new-if (= 1 1) 0 5)
$2 = 0
使用 new-if 的后果
(define (sqrt-iter-new guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter-new (improve guess x) x)))
(define (sqrt-new x)
(sqrt-iter-new 1.0 x))
scheme@(guile-user)> (sqrt-new 2)
<unnamed port>:21:11: In procedure good-enough?:
<unnamed port>:21:11: Throw to key `vm-error' with args `(vm-run "VM: Stack overflow" ())'.
Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.
得到了上面的错误信息。backtrace后发现貌似陷入了无限递归。因为在new-if中, 接下来的参数都会作为new-if调用的参数被求值,从而陷入了无限递归;而使用 if的话,处理接下来的“参数”(之所以打引号是因为Lisp默认的if应该不算是 函数调用,算是个语句),会先对第一个参数求值而后决定进入哪个过程分支。