evens-only*&co

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

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください