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

the little schemer 笔记(5)

第五章 “Oh My Gawd”:It's Full of Stars

(rember* a l)是什么,其中a是cup,l是((coffee) cup ((tea) cup) rember*发音为rember-star

((coffee ((tea) cup) (and (hick)) cup)



(rember* a l)是什么,其中a是suace,l是(((tomato sauce)) ((bean) sauce) (and ((flying)) sauce))

(((tomato)) ((bean)) (and ((flying))))




Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 China Mainland License.
现在写出函数rember*,下面是框架
(define rember*
  (lambda (a l)
    (cond
      (_____ _____)
      (_____ _____)
      (_____ _____))))

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

(define rember*
  (lambda (a l)
    (cond
      ((null? l) (quote ()))
      ((atom? (car l))
         (cond
           ((eq? a (car l)) (rember* a (cdr l)))
           (else (cons (car l) (rember* a (cdr l))))
      (else (cons (rember* a (car l)) (rember* a (cdrl)))))))))




(lat? l)是什么值,其中l是(((tomato sauce)) ((bean) sauce) (and ((flying)) sauce))

#f



(car l)是atom吗

不是



(insertR* new old l)是什么值,其中new是roast, old是chuck,l是((how much (wood)) could ((a (wood) chuck)) (((chuck))) (if (a) ((wood chuck))) could chuck wood)

((how much (wood)) could ((a (wood) roast)) (((roast))) (if (a) ((wood roast))) could roast wood)



现在写出函数 insertR*,下面是框架

(define insertR*
  (lambda (new old l)
    (cond
      (_____ _____)
      (_____ _____)
      (_____ _____))))


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

(define insertR*
  (lambda (new old l)
    (cond
      ((null? l) (quote()))
      ((atom? (car l)) (cond
                         ((eq? old (car l)) (cons old (cons new (insertR* new old (cdr l)))))
                         (else (cons (car l) (insertR* new old (cdr l))))))
      
      (else (cons (insertR* new old (car l)) (insertR* new old (cdr l)))))))
                                  



insertR*和 rember*有什么相似之处

当car是一个list时,他们都有car的递归。



所有的*-函数都有什么相似之处

都有三个分支查询,当car是一个list时,car和cdr一样也要递归。



为什么

因为所有的*-函数的list参数都是要么空要么里边有原子被cons到list中,要么有list被cons到list中。



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
第一戒 (最终版)

递归时至少要有一个参数变化,并且向终止条件方向变化。变化的参数必须有终止测试条件:当递归原子,lat时使用(cdr lat)。当递归数n时使用(sub1 n)。当递归一个 S-expression的列表l,当(null? l)或者(atom? (car l))使用(car l)和(cdr l)。

递归时参数要向终止条件方向变化:当使用cdr时,用null?测试终止;当使用sub1时,用zero?测试终止。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;




(occursomething a l),其中a是 banana,l是((banana) (split ((((banana ice))) (cream (banana)) sherbet)) (banana) (bread) (banana brandy))

5



那么 occursomething 的好点的名字是什么

occur*



写一个函数occur*
(define insertR*
  (lambda (a l)
    (cond
      (_____ _____)
      (_____ _____)
      (_____ _____))))

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

(define occur*
  (lambda (a l)
    (cond
      ((null? l) 0)
      ((atom? (car l))
       (cond
         ((eq? a (car l)) (add1 (occur* a (cdr l))))
         (else (occur* a (cdr l)))))
      (else (+ (occur* a (car l)) (occur* a (cdr l)))))))

'((banana) (split ((((banana ice))) (cream (banana)) sherbet)) (banana) (bread) (banana brandy))
(occur* 'banana '((banana) (split ((((banana ice))) (cream (banana)) sherbet)) (banana) (bread) (banana brandy))) 

DrRacket环境测试结果为
欢迎使用 DrRacket, 版本 5.1.3 [3m].
语言: 大; memory limit: 64 MB.
((banana)
 (split ((((banana ice))) (cream (banana)) sherbet))
 (banana)
 (bread)
 (banana brandy))
5



(subst* new old l), 其中new是orange,old是banana,l是((banana) (split ((((banana ice))) (cream (banana)) sherbet)) (banana) (bread) (banana brandy))

((orange) (split ((((orange ice))) (cream (orange)) sherbet)) (orange) (bread) (orange brandy))



写一个函数subst*

(define subst*
  (lambda (new old l)
    (cond
      (_____ _____)
      (_____ _____)
      (_____ _____))))

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

(define subst*
  (lambda (new old l)
    (cond
      ((null? l) (quote ()))
      ((atom? (car l))
       (cond
         ((eq? old (car l)) 
          (cons new (subst* new old (cdr l))))
         (else (cons (car l) 
                     (subst* new old (cdr l))))))
      (else (cons (subst* new old (car l)) 
                  (subst* new old (cdr l)))))))

'((banana) (split ((((banana ice))) (cream (banana)) sherbet)) (banana) (bread) (banana brandy))
(subst* 'orange 'banana '((banana) (split ((((banana ice))) (cream (banana)) sherbet)) (banana) (bread) (banana brandy))) 

DrRacket环境测试结果为
欢迎使用 DrRacket, 版本 5.1.3 [3m].
语言: 大; memory limit: 64 MB.
((banana) (split ((((banana ice))) (cream (banana)) sherbet)) (banana) (bread) (banana brandy))
((orange) (split ((((orange ice))) (cream (orange)) sherbet)) (orange) (bread) (orange brandy))



(insertL* new old l)是什么,其中new是pecker,old是chuck,l是
((how much (wood)) could ((a (wood) chuck)) (((chuck))) (if (a) ((wood chuck))) could chuck wood)

写一个函数 insertL*
(define insertL*
  (lambda (new old l)
    (cond
      (_____ _____)
      (_____ _____)
      (_____ _____))))

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

(define insertL*
  (lambda (new old l)
    (cond
      ((null? l) (quote ()))
      ((atom? (car l))
       (cond
         ((eq? old (car l)) 
          (cons new 
                (cons old 
                      (insertL* new old (cdr l)))))
         (else (cons (car l) 
                     (insertL* new old (cdr l))))))
      (else (cons (insertL* new old (car l)) 
                  (insertL* new old (cdr l)))))))

'((how much (wood)) could ((a (wood) chuck)) (((chuck))) (if (a) ((wood chuck))) could chuck wood)
(insertL* 'pecker 'chuck '((now much (wood)) could ((a (wood) chuck)) (((chuck))) (if (a) ((wood chuck))) could chuck wood))

DrRacket环境测试结果为
欢迎使用 DrRacket, 版本 5.1.3 [3m].
语言: 大; memory limit: 64 MB.
((how much (wood)) could ((a (wood) chuck)) (((chuck))) (if (a) ((wood chuck))) could chuck wood)
((now much (wood))
 could
 ((a (wood) pecker chuck))
 (((pecker chuck)))
 (if (a) ((wood pecker chuck)))
 could
 pecker
 chuck
 wood)




(nember* a l),气质那个a是 chips,l是 ((potato) (chips (( with) fish) (chips)))

#t,因为原子chips在列表l中。




写出函数member*
(define member*
  (lambda (a l)
    (cond
      (_____ _____)
      (_____ _____)
      (_____ _____))))

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

(define member*
  (lambda (a l)
    (cond
      ((null? l) #f)
      ((atom? (car l))
       (or (eq? a (car l))
           (member* a (cdr l))))
      (else (or (member* a (car l)) 
                (member* a (cdr l)))))))

'((potatoes) (chips (( with) fish) (chips)))
(member* 'chips '((potato) (chips (( with) fish) (chips)))) 

DrRacket环境测试结果为
语言: 大; memory limit: 64 MB.
((potato) (chips ((with) fish) (chips)))
#t




(leftmost l)是什么,其中l是((potatoe) (chips ((with) fish) (chips)))

potato




(leftmost l)是什么,其中l是(((hot) (tuna (and))) cheese)

hot




(leftmost l)是什么,其中l是(((() four)) 17 (seventeen))

没有答案



(leftmost (quote()))是什么

没有答案



你能描述leftmost是什么

这是我们的描述
“函数leftmost查找S-expression表达式中非空list中的的最左边的一个原子。




leftmost是一个*-函数吗

它的参数为 S-expression构成的表达式,但是仅在car上递归。



leftmost需要所有的三种分支查询吗

不,仅需要两个。我们已经确认 leftmost的参数是非空表并且没有空表成员。



现在看看你能不能写出 leftmost函数

(define leftmost
  (lambda (l)
    (cond
      (_____ _____)
      (_____ _____))))

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

(define leftmost
  (lambda (l)
    (cond
      ((atom? (car l)) (car l))
      (else (leftmost (cdr l))))))





还记得(or ...)是做什么的吗

(or ...) 一次查询一个直到出现真然后停下来,返回真。如果找不到真,那么(or ...)的值是假。




假设x是pizza,l是(mozzarella pizza),那么(and (atom? (car l)) (eq? (car l) x))的值是多少

#f



为什么是false假

因为(and ...)查询(atom? (car l)),是真,但是(eq? (car l) x)是假。于是为假。




假设x是pizza,l是((mozzarella) pizza)那么(and (atom? (car l)) (eq? (car l) x))的值是什么




为什么

因为(and ...)查询(atom? (car l)),但是(car l)不是一个atom。于是为#f




举个x和l的例子让(and (atom? (car l)) (eq? (car l) x))为真

下面是一个例子:x是pizza,l是(pizza (tastes good))




请用自己的话描述一下(and ...)的作用

下面是我们的描述
"(and ...)一次查询一个,直到出现否,然后返回假。如果总找不到假的表达式,(and ...)的值为真。



判断真假:(and ...)和(or ...)的有些参数没有查询

是的。(and ...)当找到#f时就停止了。(or ...)当找到t时就停止了。
注:(cond ...)也有不查询参数的时候。因为这个特性,(and ...) 和(or ...)也可以由(cond ...)定义:
(and alpha beta)=(cond (alpha beta) (else #f))
(or alpha beta)=(cond (alpha #t) else beta)





问当l是(strawberry ice cream),l2是(strawberry ice cream)问(eqlist? l1 l2)是什么

#t



问当l是(strawberry ice cream),l2是(strawberry cream ice)问(eqlist? l1 l2)是什么

#f



问当l1是(strawberry ice cream),l2是(strawberry cream ice)问(eqlist? l1 l2)是什么

#f



问当l1是(beef ((sausage)) (and (soda))),l2是(beef ((salami)) (and (soda)))是什么

#f,差一点就是#t真



问当l1是(beef ((sausage)) (and (soda))),l2是(beef ((sausage)) (and (soda)))是什么

#t



eqlist 是什么

查找两个list标是否小相同



eqlist?需要多少个查询

九个



为什么是九个查询

下面是我们的解释
”每个参数都可能
——是空表
——是原子cons出的list表
——是list表cos出的list表
例如,当第一个参数可能是空表,第二个参数可以有三种情况,那么3乘3共九种情况。



用eqan?写函数 eqlist?

(define eqan?
  (lambda (a1 a2)
    (cond
      ((and (number? a1) (number? a2)) (= a1 a2))
      ((or (number? a1) (number? a2)) #f)
      (else (eq? a1 a2)))))

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

(define eqlist?
  (lambda (l1 l2)
    (cond
      ((and (null? l1) (null? l2)) #t)                ;case1:l1 null,l2 null
      ((and (null? l1) (atom? (car l2))) #f)          ;case2:l1 null,car l2 atom
      ((null? l1) #f)                                 ;case3:l1 null,car l2 list
      ((and (atom? (car l1)) (null? l2)) #f)          ;case4:car l1 atom, l2 null
      ((and (atom? (car l1)) (atom? (car l2)))        ;case5:car l1 atom, car l2 atom
       (and (eqan? (car l1) (car l2))
            (eqlist? (cdr l1) (cdr l2))))
      ((atom? (car l1)) #f)                           ;case6:car l1 atom, car l2 list
      ((null? l2) #f)                                 ;case7:car l1 list, l2 null
      ((atom? (car l2)) #f)                           ;case8:car l1 list, car l2 atom
      (else                                           ;case9:car l1 list,car l2 list
       (and (eqlist? (car l1) (car l2)) 
            (eqlist? (cdr l1) (cdr l2)))))))

(eqlist? '(beef ((sausage)) (and (soda))) '(beef ((sausage)) (and (soda))))

DrRacket环境测试结果为
欢迎使用 DrRacket, 版本 5.1.3 [3m].
语言: 大; memory limit: 64 MB.
#t






第二个查询(atom? (car l2))OK吗

是的,第二个list不能为空,否则就是第一个查询条件了。



第三个查询为什么是(null? l1)

通过前两个查询知道,第一个参数是空表时,第二个参数既不是空表也不是第一个元素是原子的list表。如果(null? l1)是真,那么第二个参数必须是其中第一个元素是list表的一个list表。



判断真假:如果第一个参数是(),eqlist?得到#t对吗

对。因为(eqlist? (quote ()) l2)为真,l2必须为空表。



这就是说(and (null? l1) (null? l2))和(or (null? l1) (null? l2))满足前三种查询的情况

是的。如果第一个查询是真,那么eqlist?得到#t;否则为#f。



重写eqlist?

(define eqan?
  (lambda (a1 a2)
    (cond
      ((and (number? a1) (number? a2)) (= a1 a2))
      ((or (number? a1) (number? a2)) #f)
      (else (eq? a1 a2)))))

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

(define eqlist?
  (lambda (l1 l2)
    (cond
      ((and (null? l1) (null? l2)) #t) ;both are null
      ((or (null? l1) (null? l2) #f))  ;one is null
      ((and (atom? (car l1))           ;the following:none of l1,l2 is null
            (atom? (car l2)))
       (and (eqan? (car l1) (car l2)) (eqlist? (cdr l1) (cdr l2))))
      ((or (atom? (car l1))            ;one of cars is not atom
           (atom? (car l2)))
       #f)
      (else (and (eqlist? (car l1) (car l2)) (eqlist? (cdr l1) (cdr l2)))))));both car are list 

(eqlist? '(beef ((sausage)) (and (soda))) '(beef ((sausage)) (and (soda))))

DrRacket环境测试结果为

欢迎使用 DrRacket, 版本 5.1.3 [3m].
语言: 大; memory limit: 64 MB.
#t




什么是 S-expression表达式

原子或者由list构成的 S-expression表达式



为得到两个 S-expression表达式是否相同,equal?需要多少个查询

四个。第一个参数可能是空表或者list表构成的 S-expression表达式,第二个参数可能是空表或者list表构成的 S-expression表达式。



写出函数equal?

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

(define equal?
  (lambda (s1 s2)
    (cond
      ((and (atom? s1) (atom? s2)) (eqan? s1 s2));recurr terminating condtion,both are atom
      ((atom? s1) #f)
      ((atom? s2) #f)
      (else (eqlist? s1 s2)))));both are list(include null list)



第二个问题为什么是(atom? s1)

如果为真,我们知道第一个参数是atom原子,第二个参数是list表。



第二个问题为什么是(atom? s2)

到第三个查询时,我们知道第一个参数不是atom原子,所以我们唯一需要区分的时第二个参数数是否是atom原子。第一个参数必然是一个list。

我们可以把第二个和第三个查询写成这样吗
(or (atom? s1) (atom? s2))

当然



简化equal?
(define (atom? x)
  (and (not (null? x))
       (not (pair? x))))

(define equal?
  (lambda (s1 s2)
    (cond
      ((and (atom? s1) (atom? s2)) (eqan? s1 s2));recurr terminating condtion,both are atom
      ((or (atom? s1) (atom? s2)) #f);one is atom
      (else (eqlist? s1 s2)))));both are list(include null list)




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
第六戒
仅当函数正确后再简化
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



下面是把表lat替换为 S-expression表达式把a替换为任何 S-expression表达式后得到的新的rember

(define rember
  (lambda (s l)
    (cond
      ((null? l) (quote ()))
      ((atom? (car l))
       (cond
         ((equal? s (car l)) (cdr l))
         (else (cons (car l) (member s (cdr l))))))
      (else (cond
              ((equal? s (car l)) (cdr l))
              (else (cons (carl) (member s (cdr l)))))))))



可以简化吗

当然
(define rember
  (lambda (s l)
    (cond
      ((null? l) (quote()))
      (cond
        ((equal? s (car l)) (cdr l))
        (else (cons (car l) (rember s (cdr l))))))))

笔记:这个 S-expression表达式的rember有问题。如果(car l)本身不等于s但是l的成员或者l的成员的成员等等含有s的话那岂不是条过去了?



rember是一个"star"函数吗

不是



为什么

因为rember仅仅递归l的cdr



rember还能被简化吗

能,内层的(cond ...)可以提到外边的conde中。



做做看

(define rember
  (lambda (s l)
    (cond
      ((null? l) (quote()))
       ((equal? s (car l)) (cdr l))
       (else (cons (car l) (rember s (cdr l)))))))



这个能正常工作么

当然,所有的分支和递归和化简之前一样。



化简 insertL*

不能。在查询(eq? (car l) old)我们必须知道(car l)是否是atom原子。



当函数设计的正确,我们就能够更好的思考它们。

而这比起错误的函数节约时间。



所有用eq?和=的地方和广义eq?都可以用函数equal?吗

不能。eqan?的地方就不能,其它的都可以。实际上,不考虑eqan?例子的细节,就是我们的假设。

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