2.20
练习 2.20 过程+、*和list可以取任意个数的实际参数。定义这类过程的一种方式是采用一种带点尾部记法形式的define。在一个过程定义中,如果在形式参数表的最后一个参数之前有一个点号,那就表明,当这一过程被实际调用时,前面各个形式参数(如果有的话)将以前面的各个实际参数为值,与平常一样。但最后一个形式参数将以所有剩下的实际参数的表为值。例如,假若我们定义了:
(define (f x y . z) <body>)
过程 f 就可以用两个以上的参数调用。如果求值:
(f 1 2 3 4 5 6)
那么在 f 的体里,x将是1,y将是2,而z将是表(3 4 5 6)。给了定义:
(define (g . w) <body>)
过程g可以用0个或多个参数调用。如果求值:
(g 1 2 3 4 5 6)
那么在g的体里,w将是表(1 2 3 4 5 6)。
请采用这种记法形式写出过程same-parity,它将一个或者多个整数为参数,返回所有与其第一个参数有着同样奇偶性的参数形式的表。例如:
(same-parity 1 2 3 4 5 6 7)
(1 3 5 7)
(same-parity 2 3 4 5 6 7)
(2 4 6)
首先,很容易想到,函数的签名是这样的:
(define (same-parity x . w)
)
为了方便,想到使用递归。即假设求出了 (same-parity x . w1, ... wn-1),然后再求出 (same-parity x . w1, ..., wn-1, wn) 就只剩下一步之遥了。
但是这要求取 w 的前 n-1 项,以及最后一项。这和基本操作 car 以及 cdr 的操作正好相反,于是想到了利用前面练习中实现的 reverse,从而可以更简单地处理。
于是可以反过来思考,假设先求出了 w 的后 n-1 项,最后处理 w 的第一项。于是,使用 car 和 cdr 就能方便地操作:
(define (same-parity x . w)
(define (same-parity-list x lst)
(if (<= (length lst) 0)
'()
(if (= (mod x 2) (mod (car lst) 2))
(cons (car lst) (same-parity-list x (cdr lst)))
(same-parity-list x (cdr lst))
)
)
)
(cons x (same-parity-list x w))
)
(same-parity 1 2 3 4 5 6 7)
(same-parity 2 3 4 5 6 7)