条件式
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))