読者です 読者をやめる 読者になる 読者になる

わどぅー

記事については、中間出力の場合も多いので間違ってたらごめんなさい。twitter は waddlaw です。どうぞよろしく。

プログラム工学VI 授業関連資料 第二回 基本型 演習課題

昨日に続いて第二回もやってみる。
http://web.archive.org/web/20050315160836/http://www.teu.ac.jp/kougi/koshida/Prog6/text02.html

とりあえず、演習課題に入る前に気になった点は次の箇所。

maxThree :: Int -> Int -> Int -> Int
maxThree x y z
  | (x >= y) && (x >= z)    = x
  | y >= z                  = y
  | otherwise               = z

この定義で maxThree 6 (4+3) 5 を簡約すると次のようになるらしい。

maxThree 6 (4+3) 5
  ?? 6 >= (4 +3) && 6 >= 5
  ??6 >= 7 && 6 >=5
  ?? ⇒  False && True
  ?? ⇒  False
  ?? 7 >= 5
  ?? ⇒  True
⇒  7

ここで気になるのは False && True の部分。たしか、(&&) や (||) って第一引数の値によっては第二引数を評価しなかった気がする。つまり

maxThree 6 (4+3) 5
  ?? 6 >= (4 +3) && 6 >= 5
  ??6 >= 7 && 6 >=5
  ?? ⇒  False && 6 >= 5
  ?? ⇒  False
  ?? 7 >= 5
  ?? ⇒  True
⇒  7

(&&) の場合は一度 False が現れちゃえば何があっても False だもんね。(||) の場合は True。

今回は練習問題があるみたいだから、これからやってしまおう

練習問題
2次方程式 a * x2 + b * x + c = 0 の解の個数を求める関数 numQuad を定義せよ.念のために書いておくと,numQuad の型は,numQuad :: Float -> Float -> Float -> Int であり,引数は,第1 引数から順に,2次方程式の係数 a, b, c である.

ガード式を使って求めれば素直に実装できる。

numQuad :: Float -> Float -> Float -> Int
numQuad a b c 
    | d > 0 = 2
    | d == 0 = 1
    | otherwise = 0
    where 
        d = b^2 - 4*a*c

testAll :: Bool
testAll = and [test1, test2, test3]

test1 :: Bool
test1 = numQuad 3 (-4) 2 == 0

test2 :: Bool
test2 = numQuad 25 20 4 == 1

test3 :: Bool
test3 = numQuad 1 7 1 == 2

テストに利用した入出力は高等学校数学I/方程式と不等式 - Wikibooksから引用。

                                                                        • -

課題1

 3個の整数が全て異なる時にTrueを,そうでないときにはFalseを返す関数

threeDifferent :: Int -> Int -> Int -> Bool
を定義せよ(君の定義した関数は,threeDifferent 3 4 3 とした時Falseを返すか?) さらに,作成した関数定義に基づき,次の式の「計算」を示せ.

threeDifferent (2+4) 5 (11 `div` 2)
なお,Haskellでは,&&や||は右結合と定義されている.

普通に実装したらこうかなぁ

threeDifferent :: Int -> Int -> Int -> Bool
threeDifferent a b c = (a /= b) && (b /= c) && (a /= c)

threeDifferent 3 4 3 の結果

*Main> threeDifferent 3 4 3
False

最後に、threeDifferent (2+4) 5 (11 `div` 2) の計算を示す。

threeDifferent (2+4) 5 (11 `div` 2)
=> threeDifferent = ((2+4) /= 5) && (5 /= (11 `div` 2)) && ((2+4) /= (11 `div` 2))
=> threeDifferent = (6 /= 5) && (5 /= (11 `div` 2)) && (6 /= (11 `div` 2))
=> threeDifferent = True && (5 /= (11 `div` 2)) && (6 /= (11 `div` 2))
=> threeDifferent = True && (5 /= 5) && (6 /= 5)
=> threeDifferent = True && False && (6 /= 5) -- この時点で式全体が False に確定する
=> False
                                                                        • -

課題2

 2個(及び3個)の整数の最小値を求める関数,

min :: Int -> Int -> Int
minThree :: Int -> Int -> Int -> Int
を定義せよ.minThreeを定義する際に,minを使っても良い.

注意するべき点?としては min は Prelude で定義されているので hiding しないとだめなとこかな

import Prelude hiding (min)

min :: Int -> Int -> Int
min a b
    | a <= b = a
    | otherwise = b

minThree :: Int -> Int -> Int -> Int
minThree a b c = min (min a b) (min a c)
                                                                        • -

課題3

 数字を,それが表す整数値に変換する関数

charToNum :: Char -> Int
を定義せよ.例えば,charToNum '6' の値は 6 となる.なお,数字以外の文字については,0を返すこと.これを定義する際には,Preludeで定義された関数isDigitを使ってよい.

問題の意図とは反するけど、僕の解答はこんな感じ

charToNum :: Char -> Int
charToNum c = read [c]

read の型は String -> a なので、[c] にしてます。String の型は [Char] です。

                                                                        • -

特に難しいのは無かったかな。これを一通り終わらせたらスタートHaskellの練習問題解こうっと