Haskell パターンマッチを学習する

個人開発したアプリの宣伝
目的地が設定できる手帳のような使い心地のTODOアプリを公開しています。
Todo with Location

Todo with Location

  • Yoshiko Ichikawa
  • Productivity
  • Free

スポンサードリンク

パターンマッチ

引数の値による条件分岐が行える。オシャレ。上から条件に合った式が見つかれば、以降の式は評価されない。

lucky :: Int -> String
lucky 7 = "lucky number seven!"
lucky x = "out of lucky"
ghci> lucky 2
"out of lucky"
ghci> lucky 7
"lucky number seven!"

複数の引数のパターンマッチ

list2split :: Int -> Int -> Int -> Int -> Int
list2split x y 2 3 = x + y
ghci> list2split 2 7 2 3
9


パターンマッチによる再帰

再帰の終了条件となる式をパターンマッチを使用して記述できる。大変オシャレ。この辺りからHaskell楽しいと感じはじめた(^_^)

factorial :: Int -> Int
factorial 0 = 1
factorial n = n * factorial(n -1)
ghci> factorial 5
120


タプルのパターンマッチ

マッチしたタプルの要素を束縛できる。

addVectors :: (Double, Double) -> (Double, Double) -> (Double, Double) 
addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
ghci> :t addVectors 
addVectors :: (Double, Double) -> (Double, Double) -> (Double, Double)
ghci> addVectors (4.0, 7.0) (2.0, 8.0)
(6.0,15.0)

束縛する必要がない場合、_で使用しないことを明言できる。

funcname :: (a, b, c) -> c
funcname (_, _, z) = z


リスト内包表記のパターンマッチ

リスト内包表記もパターンマッチしたものを束縛できる。オシャレ。

ghci> [x | (x, 4) <- [ (1,4), (5,5), (7,4) ]]
[1,7]


リストのパターンマッチ

リスト[1,2]1:[2]の糖衣構文の為、コンスでパターンマッチでき、先頭と以降のリストを束縛できる。とてもオシャレ。コンスでパターンマッチする場合は()でくくらないとsyntax errorになる。

list2split :: [a] -> (a,[a])
list2split [] = error "empty list"
list2split (x:xs) = (x, xs)
ghci> list2split [1,2,3]
(1,[2,3])
ghci> list2split [3]
(3,[])

error関数はランタイムエラーを発生させる。


asパターン

束縛した変数とマッチ対象としたソースも同様に束縛する。

firstCharacterBy :: String -> String
firstCharacterBy all@(x:_) = all ++ " first character is " ++ [x]
ghci> firstCharacterBy "Hello"
"Hello first character is H"


パターンマッチに式を用いる
guardCase :: Int -> Int
guardCase n
 | n == 0 = 1
 | n < 10 = 10
 | n < 100 = 100
 | otherwise = 50
ghci> guardCase 0
1
ghci> guardCase 9
10
ghci> guardCase 99
100
ghci> guardCase 101
50


where パターンマッチの比較に用いる式を束縛する

パターンマッチの対象を式から計算する時、whereを用いて束縛することができる。

whereCase :: Int -> Int -> Int
whereCase n m
  | ans == 0 = 0
  | ans < 10 = 10
  | otherwise = 11
  where ans = n + m
ghci> whereCase 0 0
0
ghci> whereCase 0 1
10
ghci> whereCase 5 12
11

whereの中でもパターンマッチで束縛できる。

whereCase :: Int -> Int -> Int
whereCase n m
  | x == ans = 0
  | ans < 10 = 10
  | otherwise = x
  where
    ans = n + m
    (x:_) = [1,2]

whereは関数を返すこともできるので、where内で、関数パターンマッチを記述することもできる。

whereCase :: [Int] -> Int
whereCase xs
  | funcName xs == 0 = 1
  | otherwise = funcName xs
  where
    funcName [] = 0
    funcName (x:_) = x
ghci> whereCase []
1
ghci> whereCase [3,2,1]
3


任意のタイミングで値を束縛する let式

letで束縛し、inに式を記述する。また値に限らず関数などもletに束縛できる。

letExp :: Int -> Int -> Int
letExp n m = 
  let ans = n * m
  in ans

関数の束縛

ghci> [let sample x = x * x in (sample 2, sample 4, sample 5)]
[(4,16,25)]

またセミコロンで区切ることで複数の変数に対して束縛できる。

let a = 1; b = 2 in a * 2


リスト内包表記でのlet

inで式を書かず、述語として束縛のみ行える。

ghci> [ans| x <- [1,2,3], let ans= x * 2]
[2,4,6]
case式

関数パターンマッチの糖衣構文。

caseFunc :: [Int] -> Int
caseFunc xs = 
  case xs of
    [] -> 1
    (x:_) ->  x
ghci> caseFunc []
1
ghci> caseFunc [3]
3