ソフトウエア技法

現実の問題を扱うプログラム




現実の問題は複雑
問題が数式で簡潔に書かれていることは少ない
冗長な情報が含まれていたり,プログラムを作る
上で必要な情報が含まれていないことがある
問題分野の知識が必要とされる
例題:簡単な「現実」の問題
東海道新幹線で東京を発車して新大阪に到
着する列車の一番列車は東京を6時に出て,
新大阪に8時25分に到着するのぞみ1号であ
る.次の列車は東京を6時16分に出て,新大
阪に8時43分に到着するのぞみ3号である.
のぞみ3号は,東京から552.6キロメートル離
れた新大阪にいく最高速のぞみに比べると新
大阪に到着するのに2分よけいにかかる.東
京から新大阪へ行く最も高速な列車の時速を
計算するプログラムを作成せよ.
(注: 故意にわかりにくくしている)
問題の分析

問題文はあいまいで、わかりにくい


東京から新大阪へ行く最高速の新幹線列車の
時速を計算すること


何を求めるのかはっきりさせる
これには、東京と新大阪の間の距離と最高速列車の
所要時間がわかればよい
不要な情報

列車番号
問題領域の知識


東海道新幹線ではのぞみが最高速の列車であ
る
時速=距離/所要時間

専門家の間では常識となっていることもプログラムを
書く人は知らないことが多い
目的を書く
;; velocity : distance hour -> velo
;; distance : number
;; hour : number
;; velo : number
;; velocity はdistance/hour で定義される
;; example: (velocity 1000 5) = 200
(define (velocity distance hour)
(/ distance hour))
プログラム作成法
1.
2.
3.




4.
5.
6.
7.
問題を理解する
プログラムで行うべきことを書き下す
型の宣言をする
;; velocity : distance hour -> velo
;; distance : number
;; hour : number
;; velo : number
目的を書く
理解を助ける入出力の例を示す
プログラムの本体を書く
テストをする
続き
;; 一時間は60分であることを定義している
(define min-in-hour 60)
;; 手続き(関数) h:m-to-hは時間と分を与えて,時間を計算する
;; 例: (h:m-to-h 1 30) => 1.5,
;; なぜならば,1時間30分は1.5時間である.
(define (h:m-to-h hour min)
(+ hour (/ min min-in-hour)))
続き
;; 以下のプログラムは最高速の列車の時速を
計算する
;; 東京と新大阪の距離は552.6である
(- (h:m-to-h 8 43) (h:m-to-h 6 16) (h:m-to-h 0 2))
(velocity 552.6 (- (h:m-to-h 8 43)(h:m-to-h 6
16) (h:m-to-h 0 2)))
条件式

条件に基づいて,計算の道筋を変更する
条件式の基となる概念

真理値(trueとfalse)


真は#t,偽は#f
述語






述語は真理値を値とする関数
(= 4 5)
(< 5 4)
(and (= x y) (< y z))
(or (= x y) (> y z))
(not (= x y))
(define (between-5-6? n)(and (< 5 n) (< n 6)))
関数 cinterval-3-9?

(define (cinterval-3-9? n)
(and (<= 3 n) (< n 9)))
条件式の一般形
(cond
[question answer]
...
[question answer]
)
あるいは
(cond
[question answer]
...
[else answer]
)
条件式の例
(cond
[(<= n 1000) 0.040]
[(<= n 5000) 0.045]
[(<= n 10000) 0.055]
[(> n 10000) 0.060])
上から条件を見ていくことに注意
条件式の例
(cond
[(<= n 1000) 0.040]
[(<= n 5000) 0.045]
[(<= n 10000) 0.055]
[else 0.060])
条件式を用いるプログラム例


実数を係数とする二次方程式
a x**2 + b x + c=0
の実根の数を求める
(how-many a b c) ==> 二次方程式の実根の数
how-many
; how-many : number number number-> number
;; how-many は二次方程式の実数根の数を返す
;;二次方程式a x**2 + b x + c= 0は係数a, b, cで与え
る
続き
;; 二次方程式 a x**2 + b x + c = 0 が与えられたとする
;; ここで, aは0でないとする
;; 実根の数は 2 if b**2 > 4 a c
;;
1 if b**2 = 4 a c
;;
0 if b**2 < 4 a c
;; 例: (how-many 1 0 -1) = 2
;;
(how-many 2 4 2) = 1
;; a = 0の時はプログラムは 文字列“error” を返す
(define (how-many a b c) ..)
(define (how-many a b c)
(cond
[(= a 0) "error"]
[else (cond [(= (determinant a b c) 0) 1]
[(> (determinant a b c) 0) 2]
[(< (determinant a b c ) 0) 0])]))
続き
;; determinant: number number number -> number
;; 判別式 b**2 - 4 a c を計算する
(define (determinant a b c) (- (* b b) (* 4 a c)))
記号 (シンボル)

記号は引用符が先頭についた文字の列

人工知能の研究のために導入された


例 'the, 'dog, 'How-are-you?
文字列とは異なる

"the", "dog", "How are you?"
記号 ー 続き

もっとも基本的なデータ構造でこれ以上分割できない

基本的な操作は、比較のみ


(eq? 'Morning 'Morning)
(eq? 'Morning 'Evening)
記号を用いたプログラム例

次のような挨拶に答えるプログラムを作成する




'GoodMorning ==> 'Hi
'HowAreYou? ==> 'Fine
'GoodAfternoon ==> 'INeedANap
'GoodEvening ==> 'BoyAmITired
プログラムの骨子
;; reply : symbol -> symbol
;; 挨拶 s の返答を返す
(define (reply s) ...)
対話をするプログラム
(define (reply s)
(cond
[(eq? s 'GoodMorning) 'Hi]
[(eq? s 'HowAreYou?) 'Fine]
[(eq? s 'GoodAfternoon) 'INeedANap]
[(eq? s 'GoodEvening) 'BoyAmITired]))
簡単な通訳プログラム






(define (interpret s)
(cond
[(eq? s 'GoodMorning) 'おはよう]
[(eq? s 'HowAreYou?) '元気?]
[(eq? s 'GoodAfternoon) '今日は]
[(eq? s 'GoodEvening) '今晩は]))