evens-only*
関数 evens-only* は入れ子になった数のリストからすべての奇数を削除する。「簡単な練習でしょう」なんて書いてあるので、今度も答を見ないで書いてみる。ちなみに、偶数であることを判定する even? の定義は質問の中で提示されている。
(use mymodule)
(define even?
(lambda (n)
(o= (o* (o/ n 2) 2) n)))
(define evens-only*
(lambda (l)
(cond
((null? l) (quote ()))
((atom? (car l))
(cond
((even? (car l)) (cons (car l) (evens-only* (cdr l))))
(else (evens-only* (cdr l)))))
(else
(cons (evens-only* (car l)) (evens-only* (cdr l)))))))
(print (evens-only* '((9 1 2 8) 3 10 ((9 9) 7 6) 2)))
^o^ > gosh -I. evens-only_star.scm ((2 8) 10 (() 6) 2)
うん、簡単。
evens-only*&co
こっちが本題。関数 evens-only*&co は、引数から奇数を削除して偶数だけの入れ子のリストを作る一方、同時に引数中の偶数の積と奇数の和を計算する関数。概要が示されているので、それをもとに書いてみよう・・・・・・と思ったけど、最後の else の再帰をどうすればわからなくて、結局答を見て写経した。
(use mymodule)
(define even?
(lambda (n)
(o= (o* (o/ n 2) 2) n)))
(define evens-only*&co
(lambda (l col)
(cond
((null? l) (col (quote ()) 1 0))
((atom? (car l))
(cond
((even? (car l)) (evens-only*&co (cdr l)
(lambda (newl p s) (col (cons (car l) newl) (o* (car l) p) s))))
(else (evens-only*&co (cdr l)
(lambda (newl p s) (col newl p (o+ (car l) s)))))))
(else
(evens-only*&co (car l)
(lambda (al ap as)
(evens-only*&co (cdr l)
(lambda (dl dp ds)
(col (cons al dl) (o* ap dp) (o+ as ds))))))))))
(define the-last-friend
(lambda (newl product sum)
(cons sum (cons product newl))))
(print (evens-only*&co '((9 1 2 8) 3 10 ((9 9) 7 6) 2) the-last-friend))
最後の else の再帰は、まず (car l) について evens-only*&co を再帰してその収集子の中でさらに (cdr l) について再帰している。(car l) についての収集子の引数 al、ap、ps は (car l) のなかの偶数のリスト、偶数の積、奇数の和。それから (cdr l) についての収集子の引数 dl、dp、ds は (cdr l) のなかの偶数のリスト、偶数の積、奇数の和だ。そして最後にリストは cons、積は o*、和は o+ をそれぞれ適用しているわけだ。ああ、なんてややこしいんだ。
実行結果:
^o^ > gosh -I. evens-only_star_and_co.scm (38 1920 (2 8) 10 (() 6) 2)
はあ、なんとかできた。
これで8章も終わり。