第9回 データとしての関数(6月15日)

今日の課題

■ 再帰呼び出し

append を使わない reverse

再帰呼び出しのプログラミングでは,引数に与える情報の設計がキモである.

スタックを思い出して欲しい.要素をスタックに積むと,スタックには要素が逆順に並ぶ.

(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 ????????)))

練習1

上記の定義を完成させよう.

■ 高階関数

関数を引数に与える

リストの各要素について処理をしてその結果をリストで返す関数 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 のプログラムを印刷し,各行にコメントを手書きで書いて提出せよ.


(c) 2006.6.12 by tokuhisa