再帰呼び出しのプログラミングでは,引数に与える情報の設計がキモである.
スタックを思い出して欲しい.要素をスタックに積むと,スタックには要素が逆順に並ぶ.
(1) リストの要素をスタックに積み,最後にスタックを結果として返すことで,reverse は実現できる.
(define rev (lambda (lst stack) (if (null? lst) stack (rev (cdr lst) (cons (car lst) stack))))) |
実行例:
(rev (list 1 2 3 4 5) ()) => (list 5 4 3 2 1)
rev の第1引数は reverse されるリスト,第2引数はスタックである.スタックは初期値は () として実行する.
(2) 引数を1つしかとらない関数 (reverse lst) は,内部で (rev lst ()) を呼び出す.
(define reverse (lambda (lst) (rev lst ()))) |
(3) scheme では,reverse の定義の中で,rev を定義することができる.
(define reverse (lambda (lst) ( ??? : ??? ) (rev ????????))) |
上記の定義を完成させよう.
リストの各要素について処理をしてその結果をリストで返す関数 collect
定義:
(define collect (lambda (lst func) (if (null? lst) () (cons (func (car lst)) (collect (cdr lst) func))))) |
書式:
(collect リスト 処理)
実行例:
(collect (list 1 2 3 4 5) (lambda (x) (* 2 x))) => (list 2 4 6 8 10)
面積を計算する関数を返す関数 menseki1
定義:
(define menseki1 (lambda (type) (cond ((string=? type "sankaku") (lambda (lower height) (/ (* lower height) 2))) ((string=? type "chouhoukei") (lambda (lower height) (* lower height))) ((string=? type "daikei") (lambda (upper lower height) (/ (* (+ upper lower) height) 2)))))) |
書式:
(menseki1 type)
実行例:
(menseki1 "sankaku") => #<procedure:12:11> ← 見た目に意味の不明な返り値 ((menseki1 "sankaku") 4 5) => 10
(1) 「底辺の長さや高さなどがリストで与えられるときに面積を計算する関数」を返す関数 menseki2 を定義せよ.
実行例:
((menseki2 "sankaku") (list 4 5))
(2) (1) の続きで,下記の実行例が再現できるように関数 keisan を関数 collect を使って定義せよ.
実行例:
(keisan menseki2 (list (list "sankaku" 4 5) (list "chouhoukei" 4 5) (list "daikei" 4 5 6))) => (list 10 20 27)
関数 collect, 関数 keisan,および関数 menseki2 のプログラムを印刷し,各行にコメントを手書きで書いて提出せよ.