第7回 制御構造(1)(5月30日)

今日の課題

■ Language の選択

DrScheme は習熟度に合せたプログラミングができるような配慮がされて いる.これからの演習では,「Standard」のレベルで演習を進めるので,以下 の操作をしておくこと.

  1. メニューの中の「Language」をクリック
  2. 「Choose Language」をクリック
  3. Choose Language ウインドウの上から2行目の「Standard (R5RS)」をク リック
  4. 「OK」をクリック
  5. 「Run」ボタンを押す.

■ lambda と順接

前回に示した lambda を用いた関数定義の書式では,以下のようになって いた.
(define <名前> (lambda (<引数名>  <引数名> …) 式))

正確には,以下のようになる.
(define <名前> (lambda (<引数名>  <引数名> …) 式の並び))

この意味は,「式の並び」が,プログラミングの考え方でいうところの順接に相当する.式の並びのうち,最後に評価した式の返り値が,この lambda の全体の返り値になる.

例題1

Definitions で以下を定義しよう.
(define say
  (lambda (x)
    (write "Hello ")
    (write x)
    (write "World")))

Interactions で以下を実行しよう.
> (say 'scheme)

■ 条件式

条件式は次の2つの書式がある.2つめで,偽の場合,この式全体の返り値は不明である(処理はエラー終了とならずに進む).
(if <真偽を返す式> <真の際に評価する式> <偽の際に評価する式>)
(if <真偽を返す式> <真の際に評価する式>)

if により同一の処理が可能ではあるが,Lispにおける伝統的な条件式として,cond がある.
(cond (<真偽を返す式1> <真偽を返す式1真の際に評価する式の並び1>)
      (<真偽を返す式2> <真偽を返す式2真の際に評価する式の並び2>)
                  - - - 
      (<真偽を返す式n> <真偽を返す式n真の際に評価する式の並びn>))

例題2

以下にサンプルを示す.Interactions で実行してみよう.
> (if (< 1 2) 'ok 'ng))
> (if (> 1 2) 'ok 'ng))
> (if (< 1 2) 'ok))
> (if (> 1 2) 'ok))

練習1

成績を入力して,ABCラベルを出力する関数 label を作成しよう.もし,成績 s が 90以上ならば "A",80以上90未満ならば "B",70以上80未満ならば "C",60以上70未満ならば"D",60未満ならば"E"を返せ.ここで,if 関数を使う場合(label1)と cond 関数を使う場合(label2)のそれぞれを作成してみよう.

■ 再帰

ある名前で定義した関数の中で,その名前の関数を評価すること.再帰型の関数では,再帰を終了する条件が必要である.

例題2

階乗を計算する関数 factorial を定義しよう.factorial では再帰を終了する条件は,0 の階乗を求めるときであり,その返り値は,1 である.
(define factorial
  (lambda (x)
    (if (= x 0)
        1
        (* x (factorial (- x 1))))))

練習2

以下の問について,再帰を使って回答せよ.

(問1) 1, 3, 5, ... というように,1以上の奇数 n 個をを昇順にとりこぼしなくならべたとき,それらの数の和を求める関数 sum_odd(n) を定義せよ.

(問2)an+1 = 2an + 2 と定義される式の第n項を計算する関数 prac0703(n) を定義せよ.n は 1 以上の整数,a1 = 2 とする.

(問3)an+1 - 5an + 6 = 0 を満たす数列の第n項を計算する関数 prac0704(n) を定義せよ.n は 1 以上の整数,a1 = 7 とする.

(問4)an+2 - 3an+1 + 4an + 5 = 6 を満たす数列の第n項を計算する関数 prac0705(n) を定義せよ.n は 1 以上の整数,a2 = 7,a1 = 8 とする.

□第3回小レポート

以下の3つの関数を計算するために必要な scheme プログラムリストを印刷し,各行に手書きで説明を書いて,提出せよ.

以下の問題で,お金の計算をするが,小数点数が計算結果に表れて良いことにする.また,再帰を使う回答を想定しているので,一般式の回答をする人は,別解として追加して回答すること.

(1) a の n 乗を計算する関数 power(a,n) を定義せよ.n は正の整数とする.ちなみに,an = exp(n * log(a))である.(配点:1点)

(2) 年複利 r のところに a 円を預けたとき,n 年後の年末の元利を計算する関数 yokin(a,r,n) を定義せよ.ちなみに,複利の計算では,元金 a を一定期間預けたあとの利息 ar を,元金に加えて次の期間の新しい元金とみなす.(配点:3点)

ヒント:
1年 元金=a 利息=元金*r = ar
2年 新元金=a+ar 利息=新元金*r=(a+ar)r
3年 新元金=a+ar+(a+ar)r 利息=新元金*r=(a+ar+(a+ar)r)r
: : :

検算:年利1割のところに3,000円を3年預けると,3,993円になる.

(3) 年複利 r のところに毎年 a 円ずつ預ける積立預金の n 年後の年末の元利を計算する関数 tsumitate(a,r,n) を定義せよ.(配点:3点)

ヒント:
1年目末 yokin(a,r,n)
2年目末 yokin(a,r,n) + yokin(a,r,n-1)
3年目末 yokin(a,r,n) + yokin(a,r,n-1) + yokin(a,r,n-2)
: : :

検算:年利1割のところに1,000円の積み立てを3年行うと,3,641円になる.

(4) 年複利 r のところから b 円を借りてローンを組み,年末に一定額 a 円を払うことにする.支払いが完了する年数を計算する関数 nenpunen(a,b,r) を定義せよ.(配点:3点)

ヒント:
b <= 0のとき完了(0年)
a <= br のとき破産('bankruptcy)
上記以外のとき,「元金 + 利息 - 返済額」円の返済に掛かる年数 + 1年

検算:年利1%のところから100万円借りて,年に12万円ずつ払うことにすると完済に9年かかる.ご利用は計画的に.


(c) 2006.5.28 by tokuhisa