十分庆幸我偶然找到这本书,内容真是精彩,从来没有一本书这么吸引人,忽然感觉LISP的(((())))也没有那么讨厌了:)
目前看到了第三章,学习到了十诫中的第一条的list部分:列表递归时要问两个问题:列表是不是为空?还是其他?
五条法则都已经有了接触:
- The Law of Car
- The Law of Cdr
- The Law of Cons
- The Law of Null?
- The Law of Eq?
第四诫:
递归时始终要改变至少一个参数。而且这个改变必须是朝着终点越来越近。必须在终止条件中对改变的参数进行测试:当使用cdr时,用null?来检查是不是应该结束。
数字游戏
关于数字的操作,和atom是相似的,在处理时要明确终止条件-terminal condition,如zero? n,再者要寻找natural recursion。
第五诫
当用+来求值时,要用0作为终止行的值,因为加0不会影响加法的结果。
当用x来求值时,要用1作为终止行的值,因为乘以1不会影响乘法的结果。
当用cons求值时,要用()作为终止行的值。
再来看比较:
再来看幂运算:
第五章 全是小星星
这可以理解为多维递归,如从(abc def (abc def) (abc (abc de)))中去掉所有abc后为(def (def) ((de)))。
第四诫(最终版)
递归时要始终改变至少一个参数。当递归一个atom的列表lat时,用(cdr lat)。当递归一个数字n时,使用(sub1 n)。当递归一个S-表达式列表l时,如果(null? l)和(atom? (car l)) 都不为true,使用(car l)和(cdr l)。
参数必须是朝着递归终止的方向改变。需要在终止条件中对参数进行测试:
当使用cdr时,检查是否以null?结束;
当使用sub1时,检查是否以zero?结束。
第六诫
仅当功能正确之后再进行简化
第六章 影子
这一章主要讲算术。
本章算术的定义:算术表达式是一个atom(包括数字),或者用+,x或↑连接的两个算术表达式。
第七诫
在subparts上递归有着相同的特性:
第八诫
使用辅助函数对表现形式进行抽象
第九诫
把相同的模式抽象成函数
What does (multirember&co a lat f) do?
It looks at every atom of the lat to see whether it is eq? to a.
Those atoms that are not are collected in one list ls1;
the others for which the answer is true are collected in a second list Is2.
Finally, it determines the value of (f ls1 ls2).
第十诫
创建函数来一次收集多个值
下面实现multiinsetLR&co:
实现even-only*
第九章
以一个有趣的游戏开始:
假设 a = caviar,lat = (6 2 4 caviar 5 7 3),有(looking a lat) = #t;
假设 a = caviar,lat = (6 2 grits caviar 5 7 3),有(looking a lat) = #f;
(looking a lat),每个数字是下一个寻找的位置的下标。
关于Y-Combinator完全没看懂。。。。。
———————————–没看懂。。。。。的分割线———————————————
好吧,继续看,
重新从eternity看起。
eternity是一个不会停止的函数,因为它每次递归的仍然是原始集合(参数)本身。
那么我们定义一个will-stop?函数,这个函数判断传入的参数在执行后(应用函数调用()之后)会不会停止。
该函数应该返回#t或者#f。那么它完备了吗,是的因为它永远返回#t或者#f
既然这样,我们举一些例子:
如果f是length函数,那么(will-stop? length) 为#t。
那么,对于 (will-stop? eternity)呢?
因为eternity不返回,所以(will-stop? eternity)为#f。
让我们再试一个函数:
我们用()进行试验,last-try(quote())
假设 (will-stop? last-try)为#f,那么last-try的值为 (and #f (eternity (quote ())))。
那么(last-try (quote()))终止了,所以我们需要假设(will-stop? last-try)为#t。
如果(will-stop? last-try)为#t,那么last-try(quote())就是
(and #t (eternity (quote ())))
这永远无法终止。
这也就说,我们无法定义一个(will-stop? last-try)来返回#t或者#f。
那我们扔掉(define ),
上面的函数定义了空列表的长度,因为如果列表不为空,函数永远不返回。
我们暂且把它称为length0
那如何写一个函数计算元素个数不大于1的列表的长度呢?
因为length0实际上没有定义,所有我们用lambda替换掉:
你应该会知道如何计算元素个数不超过2的列表的长度了。
按照这样,我们就有可能计算长度是无穷大的列表的长度了。但这样的函数没办法写出来。。。
于是我们创建一个函数,看起来像length,但以(lambda (length))开始。
上面就是length0了。
重写length<=1:
重写length<=2:
重复的内容又出现了,即以length为参数的lambda,再提取出来,取名叫mk-length,从length0开始:
对于length<=1:
对于length<=2:
对于length<=3:
我们甚至可以把length0中的eternity 替换成mk-length:
甚至把length换成mk-length:
为啥? 看上去好看。但我们需要明白并不是所有的mk-length都是一样的。
所有的名字都是一样的,但有些名字比其他的更一样。
注意到mk-length传给了mk-length,我们可以利用这个创造一个额外的递归调用。从而得到length<=1:
那可以再多一层递归吗?
当然。
这不就是length函数么??
接着把(mk-length mk-length)提取出来,命名为length
好了,那我们算一下(apples)这个列表l的长度:
首先,我们需要知道l上面那个函数的值,因为这个值是个函数,作用在l上来求l长度的。如下:
然后, 经过若干……..就得到了Y算子。。。。
第十章 这一切都有啥用?(这些的值是什么?)
entry是一对列表,其中第一个是集合;并且这两个列表的长度要相同。如
(
(appetizer entree beverage)
(pate boeuf vin)
)
(
(appetizer entree beverage)
(beer beer beer)
)
(
(beverage dessert)
((food is) (number one with us))
)
table是entry的列表,比如
(
(
(appetizer entree beverae)
(pate boeuf vin)
)
(
(beverage dessert)
((food is) (number one with us))
)
)
有多少类型?
*const
*quote
*identifier
*lambda
*cond
*application
函数是action