01 Toys
atom 与 list
atom 与 list 都是 S-expr
- ()被称为 null list,也是一个 list
- 'atom等价于- (quote atom),- 'list等价于- (quote list)
02 Do It, Do It Again, and Again, and Again…
列表
- (car l)表示取出 list 的第一个元素,结果可以是 atom 也可以是 list,如- (car '((a b c) x y z)) => '(a b c)
- (cdr l)表示取出 list 里除了第一个元素的剩下部分,如- (cdr '((a b c) x y z)) => '(x y z),当 list 只有一个元素时返回- ()
car 与 cdr 都不可对 atom 或者 null list 操作
- (cons x l)表示把一个元素加到另一个 list 的头部,返回一个 list,如- (cons 'a (car '((b) c d))) => '(a b),第一个参数随意,第二个参数必须是 list
可以用 (cons atom '()) 构建一个表 '(atom)
- (null? l)表示判断 list 是否为 null,如- (null? '(a)) => #f,参数必须是 list
(define atom?
  (lambda (x)
    (and (not (pair? x))
         (not (null? x)))))
- (eq? a b)表示判断两个 atom 是否相等,如- (eq? 'a 'a) => #,参数必须是非数字的 atom,不可以是 list
- (lat? lat)表示判断一个 list 全部都是由 atom 组成,如- (lat? '(a b (c))) => #f,对于 null list 也返回- #t
(define lat?
  (lambda (l)
    (cond
     ((null? l) #t)
     ((atom? (car l)) (lat? (cdr l)))
     (else #f))))
本章介绍了 scheme 的基本操作,其中最为重要的是 cond 的使用。模式匹配是 scheme 强大的武器,贯穿了这本书,
也是函数式编程的重要思考方式。
03 Cons the Magnificent
简单列表函数
- (member? a lat)表示判断一个 atom 是否为一个 lat 的一部分,如- (member? 'a '(a b c)) => #t
(define member?
  (lambda (a lat)
    (cond
     ((null? lat) #f)
     ((eq? a (car lat)) #t)
     (else (member? a (cdr lat))))))
- (rember a lat)表示从一个 lat 中移除一个 atom 第一次出现的地方,如- (rember 'mint '(mint lamb chops mint)) => '(lamb chops),若未出现则不改变
(define rember
  (lambda (a lat)
    (cond
     ((null? lat) '())
     ((eq? a (car lat)) (cdr lat))
     (else (cons (car lat)
                 (rember a (cdr lat)))))))
- (firsts l)表示取出 list 中每一个子列表的第一个元素,来组成新列表,如- (firsts '((a b) (c d) (e f))) => '(a c e)
(define firsts
  (lambda (l)
    (cond
     ((null? l) '())
     (else (cons (car (car l)) (firsts (cdr l)))))))
- (insertR a b lat)表示把 atom a 插入到 lat 里 atom b 第一次出现的位置后,如- (insertR 'a 'b '(c d b)) => '(c d b a)
(define insertR
  (lambda (a b lat)
    (cond
     ((null? lat) '())
     ((eq? b (car lat)) (cons b
                              (cons a (cdr lat))))
     (else (cons (car lat)
                 (insertR a b (cdr lat)))))))
(define insertL
  (lambda (a b lat)
    (cond
     ((null? lat) '())
     ((eq? b (car lat)) (cons a lat))
     (else (cons (car lat)
                 (insertL a b (cdr lat)))))))
- (subst a b lat)表示用 atom a 替换第一个 atom b,如- (subst 'a 'b '(c b)) => '(c a)
(define subst
  (lambda (a b lat)
    (cond
     ((null? lat) '())
     ((eq? b (car lat)) (cons a (cdr lat)))
     (else (cons (car lat)
                 (subst a b (cdr lat)))))))
- (subst2 a b c lat)表示用 atom a 替换 atom b 或第一个 atom c ,如- (subst2 'a 'b '(c b)) => '(c a)
(define subst2
  (lambda (a b c lat)
    (cond
     ((null? lat) '())
     ((or (eq? b (car lat))
          (eq? c (car lat))) (cons a (cdr lat)))
     (else (cons (car lat)
                 (subst2 a b c (cdr lat)))))))
多次操作的列表函数
- (multirember a lat)表示删除 lat 中所有的 atom a
(define multirember
  (lambda (a lat)
    (cond
     ((null? lat) '())
     ((eq? a (car lat)) (multirember a (cdr lat)))
     (else (cons (car lat)
                 (multirember a (cdr lat)))))))
- (multiinsertR a b lat)表示在所有的 atom b 后面插入 atom a
(define multiinsertR
  (lambda (a b lat)
    (cond
     ((null? lat) '())
     ((eq? b (car lat)) (cons b
                              (cons a (multiinsertR a b (cdr lat)))))
     (else (cons (car lat)
                 (multiinsertR a b (cdr lat)))))))
- (multiinsertR a b lat)表示在所有的 atom b 前面插入 atom a
(define multiinsertL
  (lambda (a b lat)
    (cond
     ((null? lat) '())
     ((eq? b (car lat)) (cons a (cons b (multiinsertL a b (cdr lat))))) ; 注意这个地方
     (else (cons (car lat)
                 (multiinsertL a b (cdr lat)))))))
- (multisubst a b lat)表示把所有的 atom b 替换成 atom a
(define multisubst
  (lambda (a b lat)
    (cond
     ((null? lat) '())
     ((eq? b (car lat)) (cons a (multisubst a b (cdr lat))))
     (else (cons (car lat)
                 (multisubst a b (cdr lat)))))))
04 Number Games
普通数字操作
下面只考虑非负整数。
- (add1 x)返回 x+1
- (sub1 x)返回 x-1
- (zero? x)判断 x 是否为 0
- (o+ m n)返回 m+n
- (o- m n)返回 m-n
(define o+
  (lambda (m n)
    (cond
     ((zero? m) n)
     (else (add1 (o+ n (sub1 m)))))))
(define o-
  (lambda (m n)
    (cond
     ((zero? m) n)
     (else (sub1 (o- n (sub1 m)))))))
可以发现数字操作可以与列表操作对应,zero? 对应 null?,add1 对应 cons
- tup 表示一个纯数字构成的 list,如 '(1 2 3),()称作 null tup
下面尝试将列表操作对应到数字操作
tup 的判空语句和 list 一样,都是 (null? tup)。同时,在数字运算中,((null? l) '()) 变为了 ((null? tup) 0)
- (addtup tup)求出 tup 中所有数字之和
(define addtup
  (lambda (tup)
    (cond
     ((null? tup) 0)
     (else (o+ (car tup)
               (addtup (cdr tup)))))))
- (o* a b)返回 a*b
(define o*
  (lambda (a b)
    (cond
     ((zero? b) 0)
     (else (o+ a (o* a (sub1 b)))))))
- (tup+ tup1 tup2)将 tup1 中元素与 tup2 中对应位置的元素相加,对于空元素视为 0,如- (tup+ '(1 2 3) '(3 4)) => '(4 6 3)
(define tup+
  (lambda (tup1 tup2)
    (cond
     ((and (null? tup1)
           (null? tup2)) '())
     ((null? tup1) tup2)
     ((null? tup2) tup1)
     (else (cons (o+ (car tup1) (car tup2))
                 (tup+ (cdr tup1) (cdr tup2)))))))
- (> a b)返回 a>b
(define >
  (lambda (a b)
    (cond
     (and (zero? a)
          (zero? b) #f)
     ((zero? a) #f)
     ((zero? b) #t)
     (else (> (sub1 a) (sub1 b))))))
- (a b)= 返回- a=b
(define =
  (lambda (a b)
    (cond
     ((> a b) #f)
     ((< a b) #f)
     (else #t))))
= 等价于 eq?
- (^ a b)计算- a^b
(define ^
  (lambda (a b)
    (cond
     ((zero? b) 1)
     (else (o* a (^ a (sub1 b)))))))
- (o/ a b)计算 a/b
(define o/
  (lambda (a b)
    (cond
     ((zero? a) 0)
     (else (add1 (o/ (o- a b) b))))))
列表中的数字运算
- (length lat)计算 lat 的长度
(define length
  (lambda (lat)
    (cond
     ((null? lat) 0)
     (else (add1 (length (cdr lat)))))))
- (pick n lat)返回计算 lat 中第 n 个元素
(define pick
  (lambda (n lat)
    (cond
     ((zero? (sub1 n)) (car lat))
     (else (pick (sub1 n) (cdr lat))))))
- (rempick n lat)返回去掉第 n 个元素后的 lat
(define rempick
  (lambda (n lat)
    (cond
     ((zero? (sub1 n)) (cdr lat)) ; 注意
     (else (cons (car lat)
                 (rempick (sub1 n) (cdr lat)))))))
- (number? n)判断 n 是否为数字,注意这个函数是基础函数,无法表达
- (non-nums lat)去除 lat 中所有的数字
(define non-nums
  (lambda (lat)
    (cond
     ((null? lat) '())
     ((number? (car lat)) (non-nums (cdr lat)))
     (else (cons (car lat)
                 (non-nums (cdr lat)))))))
- (all-nums lat)提取出 lat 中所有数字组成 tup
(define all-nums
  (lambda (lat)
    (cond
     ((null? lat) '())
     ((number? (car lat)) (cons (car lat)
                                (all-nums (cdr lat))))
     (else (all-nums (cdr lat))))))
- (eqan? a b)比较 a 和 b 是否相同(考虑数字和普通 atom)
(define eqan?
  (lambda (a b)
    (cond
     ((and (number? a)
           (number? b) (= a b)))
     ((or (number? a)
          (number? b)) #f)
     (else (eq? a b)))))
- (occur a lat)统计 a 在 lat 中出现的次数
(define occur
  (lambda (a lat)
    (cond
     ((null? lat) 0)
     ((eq? (car lat) a) (add1 (occur a (cdr lat))))
     (else (occur a (cdr lat))))))