<2017年12月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

the little schemer 笔记(6)

第六章 Shadows

1 是算术表达式吗





3 是算术表达式吗

是的



1+3 是算术表达式吗

是的



1+3×4 是算术表达式吗

当然是



cookie 是算术表达式吗

是啊,你需要来一块吗




e那么 3 ^ y + 5

是的




你来说说什么是算术表达式

我们这样描述
“对于这一章,算术表达式可以是atom原子(包括数),或者由+,×,或者^连接的两个算术表达式。”



(quote a) 是什么

a



(quote +) 是什么

原子+,而不是操作+



(quote ×) 代表什么

代表原子×,而不是操作×



(eq? (quote a) y) 是真还是假,其中y是a





(eq? x y) 是真还是假,其中x是a,y是a

者痛前边的那个问题一样。真。




(n + 3) 是算术表达式吗

不是啊,括号括着 n + 3。我们的算术定义没有提到括号。



我们可以认为(n + 3) 是算术表达式吗吗

可以,只要注意括号问题。(原文没看明白:Yes, if we keep in mind that the parentheses are not really there.)



那(n + 3)怎么称呼

称作(n + 3)的表达(representation)



为什么(n + 3) 是一个好的表达

因为
1.  (n + 3) 是一个 S-expression表达式,它可以作为函数参数
2.  它就像 n + 3


(numbered? x)是真还是假,其中x是 1





3 + 4 × 5 的表示是什么

(3 + (4 × 5))



(numbered? y) 是真还是假,其中y是(3 + (4 ^ 5))






(numbered? z) 是真还是假,其中z是(2 × sausage)

假,因为sausage不是一个数。



numbered?是什么

一个函数,查询一个算术表示是否只包含有在+,×,和^,及其后边的数。



写个 numbered?函数的框架试试

(define numbered?
  (lambda (aexp)
    (cond
      (_____ _____)
      (_____ _____)
      (_____ _____)
      (_____ _____))))



第一个查询是什么

(atom? aexp)




(eq? (car (cdr aexp)) (quote +))是什么

这是第二个查询




你能猜出来第三个查询吗

(eq? (car (cdr aexp)) (quote ×)),完全正确



那第四个查询呢

(eq? (car (cdr aexp)) (quote ^)),完全正确




我们还需要查询aexp吗

不需要了,我们可以用else把前一个查询替换掉



为什么我们查询算术表达式是四个,而不是两个。毕竟像(1 + 3)这样的算术表达式是lats(即原子构成的list表)

因为我们把(1 + 3)表达看作是lsit表组成的算术表达式,而不是它本身的那样。而且算术表达式可以是数,或者有算术表达式和+,×,或者^连接组成。



现在你能写出函数 numbered?吗

(define (atom? x)
  (and (not (null? x))
       (not (pair? x))))

(define numbered?
  (lambda (aexp)
    (cond
      ((atom? aexp) (number? aexp))
      ((eq? (car (cdr aexp)) (quote +)) ...)
      ((eq? (car (cdr aexp)) (quote ×)) ...)
      ((eq? (car (cdr aexp)) (quote ^)) ...))))



为什么当aexp是atom原子时查询(number? aexp)

因为我们想知道算术表达式中的原子是否是数



为什么我们需要知道是否aexp中+连接的东西是否是两个算术表达式

我们需要查找出来两个子表达式是否是numbered



第一个 subsexpression在哪儿

就是aexp的car



第二个 subsexpression在哪儿

就是aexp的cdr的cdr的car(即aexp的第三个成员)



所以我们需要查询什么

(numbered? (car aexp))和(numbered? (car (cdr (cdr aexp))))必须都是真。




第二个回答是什么

(and (numbered? (car aexp)) (numbered? (car (cdr (cdr aexp)))))



再试试写出函数 numbered?

(define (atom? x)
  (and (not (null? x))
       (not (pair? x))))

(define numbered?
  (lambda (aexp)
    (cond
      ((atom? aexp) (number? aexp))
      ((eq? (car (cdr aexp)) (quote +)) (and (numbered? (car aexp)) (numbered? (car (cdr (cdr aexp))))))
      ((eq? (car (cdr aexp)) (quote ×)) (and (numbered? (car aexp)) (numbered? (car (cdr (cdr aexp))))))
      ((eq? (car (cdr aexp)) (quote ^)) (and (numbered? (car aexp)) (numbered? (car (cdr (cdr aexp)))))))))




既然aexp已经被认为是算术表达式,我们可以把 numbered?写得更简单些

(define (atom? x)
  (and (not (null? x))
       (not (pair? x))))

(define numbered?
  (lambda (aexp)
    (cond
      ((atom? aexp) (number? aexp))
      (else (and (numbered? (car aexp)) (numbered? (car (cdr (cdr aexp)))))))))



为什么可以简化

因为我们知道函数是正确的



(value u) 的值是多少,其中u是13

13



(value x) 的值是多少,其中x是(1 + 3)

4



(value y) 的值是多少,其中x是(1 + (3 ^ 4))



(value z) 的值是多少,其中z是cookie

没有答案



(value nexp) 返回我们认为的那样的数学算术表达式的值

期待如此



value 对nexp要几个查询

4个



现在,让我们试着写出函数 value

(define value
  (lambda (nexp)
    (cond
      ((atom? nexp) ...)
      ((eq? (car (cdr nexp)) (quote +)) ...)
      ((eq? (car (cdr nexp)) (quote ×)) ...)
      (else ...))))



由+把两个算术表达式相连而构成的算术表达式的值是多少

如果我们知道两个子表达式的值,我们把它们求和就可以了。



(1 + (3 × 4)中的里那哥哥子表达式的值是什么

当然是用value计算1,再用value计算(3 × 4)就可以了



总的来说呢

在子表达式上递归value



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
第七戒
在相同本性的东西上递归子组成部分:
*list表
*算术表达式
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



再试试函数value

(define value
  (lambda (nexp)
    (cond
      ((atom? nexp) nexp)
      ((eq? (car (cdr nexp)) (quote +)) (+ (value (car nexp)) (car (cdr (cdr nexp)))))
      ((eq? (car (cdr nexp)) (quote ×)) ('× (value (car nexp)) (car (cdr (cdr nexp)))))
      (else ('^ (value (car nexp)) (car (cdr (cdr nexp))))))))



你能想出算术表达式的不同表示吗

有好几种呢



(3 4 +)可以表示 3 + 4吗

可以啊



(+ 3 4) 可以吗

可以吗



或者(plus 3 4)

可以



(+ ( 3 6) (^ 8 2))是一个算术表达式的表达吗

是的。




试着谢谢函数value来处理一种新的算术表达式,可以是:
——是数
——是 + 后边跟着两个算术表达式
——是 × 后边跟着两个算术表达式
——是 ^ 后边跟着两个算术表达式



这个怎么样

(define value
  (lambda (nexp)
    (cond
      ((atom? nexp) nexp)
      ((eq? (car nexp) (quote +)) (+ (value (cdr nexp)) (car (cdr (cdr nexp)))))
      ((eq? (car nexp) (quote ×)) (× (value (cdr nexp)) (car (cdr (cdr nexp)))))
      (else (^ (value (cdr nexp)) (car (cdr (cdr nexp))))))))




你猜的没错

这个是错的




让我们试一试
(+ 1 3)


(atom ? nexp),其中 nexp 是(+ 1 3)





(eq? (car nexp) (quote +)) 其中 nexp 是 (+ 1 3)





现在递归

是的。



(cdr nexp) 是什么 其中 nexp 是 (+ 1 3)

(1 3)



(1 3) 现在i是我们算术表达式的表达了

不,我们违反了第七戒。(1 3)子部分不是一个算术表达式的表达。我们对一个list表做递归。但是不是所有的list都是算术表达式的表达。我们必须是对子表达式做递归。




怎样得到算术表达式的第一个子表达式

取cdr再去car。就是第二个list成员。



(cdr (cdr nexp)) 是一个算术表达式吗

不是,取cdr再取cdr就是(3)了,(3)不是算术表达式



再一次,我们之前把(+ 1 3)考虑的是表而不是算术表达式的表达。

取cdr取cdr再去car就得到了第二个子表达式,就是第三个list成员。



nexp取cdr再取nexp是什么

算术表达式的表达的第一个子表达式



我们来为算术表达式写一个函数1st-sub-exp

(define 1st-sub-exp
  (lambda (aexp)
    (cond
      (else (car (cdr aexp))))))



为什么else

因为第一个查询也是最后一个查询



我们可以把(cond ...)去掉吗,既然不需要分支查询

当然,第四章的rember一行版本的就是这样子的

(define 1st-sub-exp
  (lambda (aexp)
    (car (cdr aexp))))



为算术表达式写函数 2nd-sub-exp

(define 2nd-sub-exp
  (lambda (aexp)
    (car (cdr (cdr aexp)))))



最后我们把(car nexp)替换为(operator nexp)
(define  operator
  (lambda (aexp)
    (car aexp)))



现在再一次重写函数value

(define (atom? x)
  (and (not (null? x))
       (not (pair? x))))

(define operator
  (lambda (aexp)
    (car aexp)))

(define 1st-sub-exp
  (lambda (aexp)
    (car (cdr aexp))))

(define 2nd-sub-exp
  (lambda (aexp)
    (car (cdr (cdr aexp)))))

(define value
  (lambda (nexp)
    (cond
      ((atom? nexp) nexp)
      ((eq? (operator nexp) (quote +)) (+ (1st-sub-exp nexp) (2nd-sub-exp nexp)))
      ((eq? (operator nexp) (quote ×)) ('× (1st-sub-exp nexp) (2nd-sub-exp nexp)))
      (else ('^ (1st-sub-exp nexp) (2nd-sub-exp nexp))))))



我们可以对这一章的算术表达式的表达使用value函数吗

可以,通用改为使用 1st-sub-exp和 operator



试试看
(define 1st-sub-exp
  (lambda (aexp)
    (car (cdr aexp))))

(define operator
  (lambda (aexp)
    (car aexp)))




很简单不是吗

是的,因为我们用辅助函数来隐藏表达。



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
第八戒

使用辅助函数来抽象表达
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



我们之前见到过表达没

是的,只不过我们没告诉你



我们用过哪写表达

真值!数!



数是表达?

是的。比如说4是概念“4”。我们使用符号因为我们习惯阿拉伯数字表达。



我们还可以用什么表示呢

(() () () ())也可以表示。(((())))如何?(I V)怎么样?



还记得我们有多少个对数使用的元函数吗

四个:numbers? zero? add1和sub1



让我们再试试数的其它表示,零怎么表示

我们选择()



1 怎么表示
(())




2 怎么表示

(() ())



知道了?那3呢

(() () ())



写一个函数来测试是否是zero零

(define sero?
  (lambda (n)
    (null? n)))



写一个像add1函数的函数

(define edd1
  (lambda (n)
    (cons (quote ()) n)))



那sub1呢

(define zub1
  (lambda (n)
    (cdr n)))



这样对吗

让我们瞧瞧看



当n是()时(zub1 n)是多少

没有答案,但是没有关系。——回忆cdr的规则。



使用表达重写+




(define +
  (lambda (n m)
    (cond
      ((sero? m) n)
      (else (edd1 (+ n (zub1 m)))))))



+变了吗

Yes and no.它变化了,但是只是一点点。



回忆lat?

很简单:
(define lat?
  (lambda (l)
    (cond
      ((null?) #t)
      ((atom? (car l)) (lat? (cdr l)))
      (else #f))))
问这个干吗



还记得当ls是(1 2 3)时,(lat? ls)是什么吗

真,当然了。



对于我们的新数,(1 2 3)是什么

((()) (() ()) (() () ()))



那当ls是((()) (() ()) (() () ()))时,(lat? ls)是什么





这样有什么坏的地方吗

你必须得提防shadows了。

 

 

 

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 China Mainland License.

posted @ 2019-01-21 10:21  史D芬周  阅读(283)  评论(0编辑  收藏  举报