1.1,我用的是kawa,这是用java实现的一个scheme的解释器,kawa(在window下直接双击打开就可以运行)
#|kawa:1|# 10 10 #|kawa:2|# (+ 5 3 4) 12 #|kawa:3|# (- 9 1) 8 #|kawa:4|# (/ 6 2) 3 #|kawa:5|# (+ (* 2 4) (- 4 6)) 6 #|kawa:6|# (define a 3) #|kawa:7|# (define b (+ a 1)) #|kawa:8|# (+ a b (* a b)) 19 #|kawa:9|# (= a b) #f #|kawa:10|# ((if (and (> b a) (< b (* a b))) #|(---:11|# b a) #|(---:12|# #|(---:13|# ((if (and (> b a) (< b (* a b))) #|(---:14|# b a) #|(---:15|# (if (and (> b a) (< b (* a b))) #|(---:16|# #|(---:18|# (if (and (> b a) (< b (* a b))) b a) #|(---:19|# (if (and (> b a) (< b (* a b))) b a) #|(---:20|# a #|(---:21|# b #|(---:22|# a #|(---:23|# ) #|(---:24|# )) /dev/stdin:24:3: An unexpected close paren was read. #|kawa:25|# a 3 #|kawa:26|# b 4 #|kawa:27|# (if (and (> b a) (< b (* a b))) b a) 4 #|kawa:28|# (cond ((= a 4) 6) #|(---:29|# ((= b 4) (+ 6 7 a)) #|(---:30|# (else 25)) 16 #|kawa:39|# (+ 2 (if (> b a) b a)) 6 #|kawa:40|# (* (cond ((> a b) a) #|(---:41|# ((< a b) b) #|(---:42|# (else -1)) #|(---:43|# (+ a 1)) 16
1.2 最简单的可以看到分号看做一个中点,把这个表达式变换成
(/ (5+4+(2-(3-(6+4/5)))) 3(6-2)(2-7))
接下来就每次把这个表达式分成两份
(/ (+ (5+4) (2-(3-(6+4/5))))
(* 3 (6-2) (2-7)))
next:
(/ (+ (+ 5 4) (- 2 (3-(6+4/5))))
(* 3 (- 6 2) (- 2 7)))
next:
(/ (+ (+ 5 4) (- 2 (- 3 (+ 6 (/ 4 5)))))
(* 3 (- 6 2) (- 2 7)))
执行后的值是:
#|kawa:44|# (/ (+ (+ 5 4) (- 2 (- 3 (+ 6 (/ 4 5)))))
#|(---:45|# (* 3 (- 6 2) (- 2 7)))
-37/150
#|kawa:46|#
1.3 这个过程的逻辑就是:在三个数中,随便拿出来一个数x。那么,这个数只有两种结果:是最小的那一个或者是最大的两个数里面的一个。如果他是最小的那一个,那么就把其他的两个数求和;如果不是,那么就取出剩下的两个数里面的大者求和。
(define (max-of-two x y) (if (< x y) y x))
(define (sum-of-bigger-two x y z)
(if (< x y) (+ y (max-of-two x z)) (+ x (max-of-two y z))))
结果
#|kawa:49|# (define (max-of-two x y) (if (< x y) y x))
#|kawa:50|#(max-of-two 10 10)
10
#|kawa:51|#(max-of-two 10 1)
10
#|kawa:52|# (max-of-two 1 10)
10
#|kawa:53|# (define (sum-of-bigger-two x y z)
#|(---:54|# (if (< x y) (+ y (max-of-two x z)) (+ x (sum-of-bigger-two y z))))
/dev/stdin:54:42: call to 'sum-of-bigger-two' has too few arguments (2; must be 3)
#|kawa:55|# (define (sum-of-bigger-two x y z)
#|(---:56|# (if (< x y) (+ y (max-of-two x z)) (+ x (sum-of-two y z))))
/dev/stdin:56:42: warning - no declaration seen for sum-of-two
#|kawa:57|# (define (sum-of-bigger-two x y z)
#|(---:58|# (if (< x y) (+ y (max-of-two x z)) (+ x (max-of-two y z))))
#|kawa:59|# (sum-of-bigger-two 10 12 1)
22
#|kawa:61|# (sum-of-bigger-two 10 10 1)
20
1.5
(define (p) (p))
(define (test x y)
(if (= x 0)
0
y))
使用表达式(test 0 (p))
如果使用的是应用序求值,那么就是说一个值会在过程被调用之前计算。如果是这样,那么在调用的时候要先计算过程p的值,但是p是一个未定的值,因此会出现异常。
看下面,在kawa中果然如此:
#|kawa:73|# (define (p) (p))
#|kawa:74|# (define (test x y)
#|(---:75|# (if (= x 0)
#|(---:76|# 0
#|(---:77|# y))
#|kawa:78|#(test 0 10)
0
#|kawa:79|# (test 1 10)
10
#|kawa:80|# (test 0 (p))
....(嘿嘿,直接卡死)
另一方面,如果使用的是正则序求值,那么直到过程真正被使用的时候才会出现异常。但是在这个测试过程中,根据if的执行的规则:如果x=0,那么会直接返回0;根本不会用到y,也就不会出现异常。
另外要提一下,我接触的所有的编程语言中,貌似用的都是应用序求值。