僕が Haskell を学び始めた頃、Haskell の文法はすんなりとは頭に入ってきませんでした。もともと僕はプログラミング言語の学習能力が低いので、僕だけかもしれませんが、「はじめからこう言ってもらえれば分かったのにぃ」ということを書きます。
はじめの一歩
分岐は case で書きます。以下に Maybe a に対する例を書きます。
case mx of Just x -> ... Nothing -> ...
念のため、Maybe a の定義も見てみましょう。
data Maybe a = Nothing | Just a
列挙されているデータ構成子を case に列挙できることが分かるでしょう。このように、case でマッチできるのは、データ構成子で表現されたパターンになります。
ワイルドカード
たとえば、以下のような型を定義したとします。
data Foo = A | B | C | D
これを case でマッチさせると以下のようになります。
case x of A -> ... B -> ... -- ここと C -> ... D -> ... -- ここが同じ!
たとえば、B と D が同じ処理であれば、ワイルドカードでまとめることができます。
case x of A -> ... C -> ... _ -> ... -- まとめた
絶対に起こりえないパターンは、ワイルドカードで書いて、error にするようにしておきましょう。
case x of A -> ... C -> ... _ -> error "絶対に起こらないからエラーを書いても大丈夫"
if は case
if は case を用いて定義されています。if x then y else z は、以下のように変換されます。
case x of True -> y False -> z
関数のトップレベル分岐も case
関数のトップレベル分岐も case の構文糖衣です。たとえば、
foo (Just x) = ... foo Nothing = ...
は、
foo x = case x of Just x -> ... Nothing -> ...
に変換されます。"=" が "->" に変換されることに注意して下さいね。
ガード
case の各パターンマッチには、ガードを書くことでさらに分岐させられます。ガードには真理値を書きます。
case mx of Just x | x > 100 -> ... | x < -100 -> ... | otherwise -> ... Nothing -> ...
ちなみに、otherwise は True の別名です。
再び関数
case にガードが書けるのですから、関数のトップレベル分岐にもガードが書けます。
foo (Just x) | x > 100 = ... | x < -100 = ... | otherwise = ... foo Nothing = ...
繰り返しますが、"->" が "=" になることに注意。
let と where
let と where のスコープを直感的に示します。
foo a b c = let x = f + g y = f - g in x + y where f = a + b g = b + c
- 関数の引数はどこからでも参照できる
- let の中から where を参照できる
- where の中から let は参照できない