の続きです。
パターンマッチ
関数型言語では一般的なパターンマッチが、当然ながら Haskell にもあります。
パターンマッチは、パターン式を並べて記述します。パターンは上から最初にマッチしたものが利用されます。
リテラルパターン
Bool の否定演算となる not はパターンマッチを使い、以下のように定義できます。
not :: Bool -> Bool not False = True not True = False
つまり、引数が False にマッチしたら True を返却し、引数が True にマッチしたら False を返却します。実行すると以下のようになります。
Main> not True False Main> not False True
リストパターン
要素数が 3 で、まんなかの要素が H の場合にTrueを返却する関数 centerh を定義してみます。
centerh :: [Char] -> Bool centerh [_,'H',_] = True centerh _ = False
_ はワイルドカードとなります。
実行すると以下のようになります。
Main> centerh ['a','b','c'] False Main> centerh ['a','H','c'] True
先頭が 'H' のリストをテストする関数はコンス演算子 : を使って以下のように定義できます。
headh :: [Char] -> Bool headh ('H':_) = True headh _ = False
('H':_) にて、head が 'H' で、tail(先頭要素を除いたリスト)が何でも良い となります。
リストの長さを返却する関数は、パターンマッチを使って以下のように定義できます。
len :: [a] -> Int len [] = 0 len (_:xs) = 1 + len xs
再帰で定義しているので分かりにくいかもしれませんが、リストの要素が空要素にマッチした場合は 0 を返却し、要素があれば、ワイルドカードの _ を使って、リストの先頭の要素を除いた xs を再帰的に扱い、各再帰にて 1 を加算しています。
実行すると以下のようになります。
Main> len [2,3,4] 3 Main> len [] 0
タプルパターン
タプルについてもパターンマッチが適用できます。タプルの先頭要素を返却する first 関数を定義してみます。
first :: (a,b,c) -> a first (x, _, _) = x
実行すると以下のようになります。
Main> first (3,4,5) 3
マッチしない引数で呼び出すと以下のようなエラーとなります。
Main> first (3,4) ERROR - Type error in application *** Expression : first (3,4) *** Term : (3,4) *** Type : (d,e) *** Does not match : (a,b,c)
n+k パターン
n+k パターンでは、n は変数で、k は 0 以上の定数でパターンを定義します。
リストから指定数の要素を除いたリストを返却する drop は以下のように定義できます。
drop :: Int -> [a] -> [a] drop 0 xs = xs drop (n+1) [] = [] drop (n+1) (_:xs) = drop n xs
実行結果は以下のようになります。
Main> drop 3 [0,1,2,3,4,5,6] [3,4,5,6]
drop 3 [0,1,2,3,4,5,6]は、パターンマッチの最下部にある「drop (n+1) (_:xs) = drop n xs」にマッチして、
drop (2+1) [0,1,2,3,4,5,6] = drop 2 [1,2,3,4,5,6]
のように解釈され、再帰的に処理が行われます。
Haskell 2010 以降は n+k パターンは使用できなくなりましたけど、一応。
につづく