以list作为操作单元
上一篇介绍如何构建list抽象,然后遍历list进行一些计算,如length等。那么有没有一个抽象,使得过程是以表或者表结构为操作对象,如(square_list ls)返回的是ls表的元素的平方构成的表?
(define (square_list ls)
(cond ((null? ls) null)
(else (cons (* (car ls) (car ls))
(square_list (cdr ls))))))
square_list是以ls为参数,计算每个元素的平方,然后再构成list并返回。如果需要对list作其他操作,比如开方、加一等呢?通过定义map过程能方便的进行类似的操作,如(map proc ls)。这里的proc可以是任意的包含一个元素参数的过程,这个map过程返回的是proc作用在ls元素中的结果所构成的list。
定义map抽象过程
(define (map proc ls)
(cond ((null? ls) null)
(else (cons (proc (car ls))
(map proc (cdr ls))))))
再一个例子,定义一个过程实现两个list合并。
(define (append ls1 ls2)
(cond ((null? ls1) ls2)
(else (cons (car ls1) (append (cdr ls1) ls2)))))
在append的基础上,定义reverse过程,使得输入的list翻转。如(reverse '(1 2 3 4))得到'(4 3 2 1)。
(define (revers ls)
(cond ((null? ls) null)
(else (append (revers (cdr ls)) (list (car ls))))))
尾递归实现reverse过程
还可以通过定义辅助过程,通过尾递归的方式将list中的元素加入到累加器中。这是尾递归的典型应用。
(define (revers2 ls)
(define (revers_aux ls acc)
(cond ((null? ls) acc)
(else (revers_aux (cdr ls) (cons (car ls) acc)))))
(revers_aux ls null))
再改进reverse过程,实现deep-reverse。
;
(define (deep_revers ls)
(define (revers_aux ls acc)
(cond ((null? ls) acc)
((not (pair? ls)) (cons ls acc))
(else (revers_aux (cdr ls) (revers_aux (car ls) acc)))))
(revers_aux ls null))
(deep_revers '(1 2 (3 4) ( 5 6 7)))
;-> '(7 6 5 4 3 2 1)
定义tree-map
与之前的map过程不同,tree-map能遍历整颗树,而不仅仅是list。然后将proc作用在每个元素上,并返回原来的树结构,只是新元素代替了旧元素。
(define (tree-map proc ls)
(cond ((null? ls) null)
((not (pair? ls)) (proc ls))
(else (cons (tree-map proc (car ls))
(tree-map proc (cdr ls))))))
> (tree-map inc '(1 2 (3 4)))
;->'(2 3 (4 5))
>(tree-map square '(1 2 (3 4))
;->'(1 4 (9 16))