は は ハ は haskell

blog1.mammb.com

の続きです。

パターンマッチ

関数型言語では一般的なパターンマッチが、当然ながら 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 パターンは使用できなくなりましたけど、一応。




blog1.mammb.com

につづく