The Littile Schemer 8章"Lambda the Ultimate"読了

最後の関数、evens-only*&coも難しいです。
何がムズいって、(car l)がリストだった時の書き方かなぁ...。


要素が数字のみのネストしたリストlを受け取って、奇数だけ除去して返す関数evens-only*を継続渡しスタイルに書きなおす問題です。
参考までに、継続渡しじゃないevens-only*関数はこんな関数です。

(define evens-only*
  (lambda (l)
    (cond
     ((null? l) '())
     ((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)))))))

評価してみると、こんな感じです。

gosh> (define nums* '((1) 2 3 ((4) 5 ((6) 7 8) 9 ) 10))
nums*
gosh> nums*
((1) 2 3 ((4) 5 ((6) 7 8) 9) 10)
gosh> (evens-only* nums*)
(() 2 ((4) ((6) 8)) 10)


これと同じ機能(奇数を除去する機能)を持ちつつ、同時に

  • 出現したすべての偶数の積
  • 出現したすべての奇数の和

を計算する機能を持つ関数evens-only*&coを継続渡しスタイルで書きなおすと...

(define evens-only*&co
  (lambda (l cont)
    (cond
     ((null? l) (cont '() 1 0))
     ((atom? (car l))
      (cond
       ((even? (car l))
	(evens-only*&co (cdr l)
			(lambda (evens* prod sum) (cont (cons (car l) evens*) (* (car l) prod) sum))))
       (else
	(evens-only*&co (cdr l)
			(lambda (evens* prod sum) (cont evens* prod (+ (car l) sum)))))))
     (else
      (evens-only*&co (car l)
		      (lambda (al ap as)
			(evens-only*&co (cdr l)
					(lambda (dl dp ds)
					  (cont (cons al dl) (* ap dp) (+ as ds))))))))))


(car l)にevens-only*&coを適用した結果、「偶数のみのリスト」「偶数の積」「奇数の和」が計算されるけど、
その結果に累積する形で(cdr l)に対するevens-only*&coの結果も持たなくてはいけないんですよね。
これをどう表現するか、僕にはとても難しいです。


でも、1回目読んだ時よりも、だいぶん理解できたんじゃないかと思う。