这一章还是在讲递归(实际上整本书都在讲递归),不过,上一章的例子中的函数只需要返回true/false,而这一章需要返回一个“修改”后的列表。这就引出了一个用于构建列表的cons关键字。
本章一共介绍了rember、firsts、insertR、insertL、subst、subst2、multirember、multiinsertR 8个函数,这里着重挑2个有代表性的讲讲吧。
rember是remove a member的意思,比如(rember 'b '(a b c d b)),返回的是'(a c d b)。注意这里的b一共出现了2次,而第二次出现的b不会被删除掉。如果需要删除的话,则需要用到multirember函数。当然面对更复杂的列表,这两个函数还是稍显乏力,比如'(a (((b)) c) b d),这种会在后续的章节里面提到。
rember的逻辑其实很简单:如果(car lat)和a相等,则返回(cdr lat),否则针对(cdr lat)执行rember,并通过cons把(car lat)和执行结果拼接成一个列表,直到列表为空。
(define rember
(lambda (a lat)
(cond
((null? lat) '()) ;; 直到列表为空
((eq? a (car lat)) (cdr lat)) ;; 如果相等,则...
(else (cons (car lat) (rember a (cdr lat))))))) ;; 否则...
比较有意思的是它和multirember之间,竟然只有一个地方有所不同:把则返回(cdr lat)改为(rember (cdr lat))就得到我们想要的效果了。
(define multi-rember
(lambda (a lat)
(cond
((null? lat) '())
((eq? a (car lat)) (multi-rember a (cdr lat))) ;; 这里和rember不同
(else (cons (car lat) (multi-rember a (cdr lat)))))))
natural recursion
最后提一句在注脚里面提到的“natural recursion”的概念,个人理解站在它对立面,不那么natural的应该是“迭代”。这让我想起在SICP里面有一小节讲到了程序执行时的形状。
我们以,Stack Overflow上的 What is the definition of "natural recursion"? 问题为例子。
迭代的“形状”是:
(plus 3 2)
(plus 4 1)
(plus 5 0)
递归的“形状”是:
(add1 (plus 2 2))
(add1 (add1 (plus 2 1)))
(add1 (add1 (add1 (plus 2 0))))
过多的就不展开了,挖个坑后面再填吧。
PS:不知道有没有人想一起研究研究Scheme的,加个微信聊一聊啊~