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章も終わり。