第4章 関数定義

条件式

if 論理式 then 式1 else 式2 の3つ組。ifもthenもelseも関数ではないようだが、3つ組で式となる。

abs' n = if n >= 0 then n else - n

話はそれるが、この場合の最後のやつは単項演算子に見えるけど、実は2項演算子なのかな。もしそうなら、(-n) = (0 - n) と自動的に置き換えられているのだろうか。

ガード

論理式で条件分岐。数学っぽいよね。

abs' n | n >= 0 = n
       | otherwise = - n

これ、改行には特に意味が無いのかな。(Hugsで試してみる)やはり改行には意味が無いようだな。

パターンマッチ

論理式ではなく、実引数で分岐。

not' False = True
not' True = False

今度のは改行に意味がある。

not' False = True not' True = False
-- Error!

と、改行を抜いたらエラーになった。 では、他の関数定義と混ぜたら?

not' False = True
abs' n = if n >= 0 then n else -n
not' True = False
-- Error!

やはりエラーになった。(「not'が多重定義されている」とのこと。)というわけで、関数定義は1箇所にまとめて書く必要がある。だからこそ、ワイルドカードがきちんと働くのだろう。

and' True True = True
and' _ _ = False

1行目によってand'の型がBool -> Bool -> Boolと分かっているので、2行目の定義があるからといってand' "True" "False"みたいな式を書くとエラーになる。 では、型の指定がなかったら?

true' _ = True

ってやると、ちゃんと多相型 a -> Boolになるから流石だ。

タプルパターン

fst (x, _) = x

リストパターン

head' [x : _] = x

n+kパターン

これはコードゴルフ以外には使わないほうがよさそうだ。

pred 0 = 0
pred (n + 1) = n

λ式

さすがにこれは、C#にもあるし、JavaScriptにもあるし、すんなり理解できる。

odds n = map (\x -> x * 2 + 1) [0..n-1]

逆に、下の書き方のほうがまだ馴染んでない。

odds n = map f [0..n-1]
         where f x = x * 2 + 1

セクション

演算子を中かっこでくくる(右引数または左引数をふくめてもよい)とセクションになるのはわかった。

inv = (1/)

とすると、

inv :: Double -> Double

という関数になる。

演習問題

問題1

halve :: [a] -> ([a],[a])
halve xs = splitAt (length xs `div` 2) xs

問題2-a

safetail :: [a] -> [a]
safetail xs = if null xs then [] else tail xs

問題2-b

safetail :: [a] -> [a]
safetail xs | null xs = []
            | otherwise = tail xs

問題2-c

safetail :: [a] -> [a]
safetail [] = []
safetail xs = tail xs

問題3-a

ワイルドカードを使わない場合

(||) :: Bool -> Bool -> Bool
True || True = True
True || False = True
False || True = True
False || False = False

問題3-b

ワイルドカードを使う場合

(||) :: Bool -> Bool -> Bool
False || False = False
_ || _ = True

問題3-c

ワイルドカードと引数を使う場合(ショートサーキット)

(||) :: Bool -> Bool -> Bool
True || _ = True
False || b = b

4通り……??教科書にも3通りしか載ってない気がするが。

問題4

(&&) :: Bool -> Bool -> Bool
a && b = if a then
           if b then True else False
         else False

問題5

(&&) :: Bool -> Bool -> Bool
a && b = if a then b else False

問題6

mult = \x -> (\y -> (\z -> x * y * z))