The Little Schemer 知识点整理(六):如影随形
2018 年 12 月 29 日
准备知识
-
算术表达式
它要么是一个原子(包括数字),要么是用 +×↑ 连接起来的两个算术表达式。
-
算术表达式的表示方式
- 中缀:
(3 + 4)
- 后缀:
(3 4 +)
- 前缀:
(+ 3 4)
- 前缀:
(+ (× 3 6) (↑ 8 2))
- 中缀:
-
表示法
数字也是某种表示法,比如阿拉伯表示法 4。我们也可以用
(() () () ())
来表示。
Scheme 十诫之第七诫
对具有相同性质的 subparts 进行递归调用:
- 列表的子列表
- 算术表达式的子表达式
Scheme 十诫之第八诫
八戒,为师。。。
使用辅助函数来抽象表达方式。
自定义函数
(numbered? aexp)
定义:用于判断一个算术表达式的表示方式中,是否除了 +×↑ 之外,只包含数字。
实现:
(define numbered?
(lambda (aexp)
(cond
((atom? aexp) (number? aexp))
(else
(and (numbered? (car aexp))
(numbered? (car (cdr (cdr aexp)))))))))
(value nexp)
定义:返回可计数算术表达式(中缀)的一般性值。
实现:
(define value
(lambda (nexp)
(cond
((atom? nexp) nexp)
((eq? (car (car nexp)) (quote +))
(plus (value (car nexp))
(value (car (cdr (cdr nexp))))))
((eq? (car (car nexp)) (quote ×))
(× (value (car nexp))
(value (car (cdr (cdr nexp))))))
(else
(↑ (value (car nexp))
(value (car (cdr (cdr nexp)))))))))
如果是前缀表达式的话:
(define value
(lambda (nexp)
(cond
((atom? nexp) nexp)
((eq? (car nexp) (quote +))
(plus (value (car (cdr nexp)))
(value (car (cdr (cdr nexp))))))
((eq? (car nexp) (quote ×))
(× (value (car (cdr nexp)))
(value (car (cdr (cdr nexp))))))
(else
(↑ (value (car (cdr nexp)))
(value (car (cdr (cdr nexp)))))))))
(1st-sub-exp aexp)
定义:一个算术表达式(前缀)的表示方式中的第一个子表达式。
实现:(可省略 cond
和 else
,因为只有一个问题)
(define 1st-sub-exp
(lambda (aexp)
(car (cdr aexp))))
(2nd-sub-exp aexp)
定义:一个算术表达式(前缀)的表示方式中的第二个子表达式。
实现:
(define 2nd-sub-exp
(lambda (aexp)
(car (cdr (cdr aexp)))))
抽象 value 函数
我们把 (car nexp)
替换成 (operator nexp)
:
(define operator
(lambda (aexp)
(car aexp)))
那么 value 函数可以重写为:
(define value
(lambda (nexp)
(cond
((atom? nexp) nexp)
((eq? (operator nexp) (quote +))
(plus (value (1st-sub-exp nexp))
(value (2nd-sub-exp nexp))))
((eq? (operator nexp) (quote ×))
(× (value (1st-sub-exp nexp))
(value (2nd-sub-exp nexp))))
(else
(↑ (value (1st-sub-exp nexp))
(value (2nd-sub-exp nexp)))))))
调整 1st-sub-exp 和 operator 就可以表示中缀算术表达式:
(define 1st-sub-exp
(lambda (aexp)
(car aexp)))
(define operator
(lambda (aexp)
(car (cdr aexp))))
这里,1st-sub-exp,2nd-sub-exp 和 operator 都是辅助函数。
回顾 lat? 函数
(define lat?
(lambda (l)
(cond
((null? l) #t)
((atom? (car l)) (lat? (cdr l)))
(else #f))))
如果 0 表示为 (),1 是 (()),2 是 (() ()),以此类推。
当 l 是 (1 2 3),lat? l
显然是 #t。但是如果把数字用上述表示法表示,那 lat? l
的值显然是 #f,与实际不符。所以使用辅助函数来抽象的时候需要注意这类问题。
EOF