前回の続き
Haskell を使ってみる 6 (パターンマッチ) - kntmr-blog
ガード
ガードは引数の値が満たす性質で処理を分岐させるときに使う。パイプ文字 (|
) と条件式と関数本体を組み合わせて記述する。(パターンは引数の構造で条件を分岐させるもの)
-- 階乗を求める関数 fact :: Integer -> Integer fact n | n < 0 = error "error!!" | n == 0 = 1 | otherwise = n * fact(n - 1) *Main> fact 3 6
where
where
キーワードは計算結果を変数に束縛するときに使う。where
で定義した変数のスコープはその関数内のみ。
-- where キーワードを使わない場合 totalCheck :: Integer -> Integer -> String totalCheck x y | x + y < 10 = "less than 10" | x + y < 100 = "less than 100" | otherwise = "a large number" -- where キーワードを使う場合 totalCheck' :: Integer -> Integer -> String totalCheck' x y | total < 10 = "less than 10" | total < 100 = "less than 100" | otherwise = "a large number" where total = x + y
where
キーワードの中でパターンマッチを使うことができる。
initials :: String -> String -> String initials firstname lastname = [f] ++ ". " ++ [l] ++ "." where (f:_) = firstname (l:_) = lastname
let
let
式では関数のどこでも変数を束縛することができる。let
式自身が式であり、変数の束縛は局所的でガード間で共有されない。(where
キーワードは関数の終わりで変数を束縛する)
let
で変数に束縛し、続く in
に式を記述する。
-- ローカルスコープに関数を作ることができる Prelude> [let square x = x * x in (square 2, square 3, square 4)] [(4,9,16)] -- セミコロン区切りで複数の変数に束縛できる Prelude> (let a = 10; b = 20; c = 30 in a * b * c, let foo = "Hello"; bar = "Haskell" in foo ++ " " ++ bar) (6000,"Hello Haskell") -- let 式とパターンマッチでタプルを要素に分解して変数に束縛できる Prelude> (let (a, b, c) = (1, 2, 3) in a + b + c) * 100 600
リスト内包表記と let
式の組み合わせ。述語のように使っているが、フィルタしているのではなく計算結果を変数に束縛している。
-- リストから値を受け取り、計算結果を area に束縛する calcCircleArea :: [Double] -> [Double] calcCircleArea xs = [area | r <- xs, let area = r * r * 3.14]
case
case
式ではコード中のどこでもパターンマッチを使うことができる。変数で指定した値に基づいてコードブロックを評価する。case
式は関数の引数に対するパターンマッチと似ている。(実際、case
式の糖衣構文になっている)
case
式に合致するパターンが見つからない場合はランタイムエラーが発生する。
-- 関数の引数に対するパターンマッチ head' :: [a] -> a head' [] = error "empty list" head' (x:_) = x -- case 式 head'' :: [a] -> a head'' xs = case xs of [] -> error "empty list" (x:_) -> x
引数によるパターンマッチは関数定義のときしか使えない。case
式では、式の途中でパターンマッチを使うことができる。
checkList :: [a] -> String checkList list = "This list is " ++ case list of [] -> "empty." [x] -> "a singleton list." xs -> "a longer list." -- case 式の代わりに where を使う場合 checkList' :: [a] -> String checkList' list = "This list is " ++ what list where what [] = "empty." what [x] = "a singleton list." what xs = "a longer list."
今回はガードのあれこれについて。