プログラミングHaskell 第4章 関数定義
関数型プログラミング言語と言うだけあって、関数を定義する方法がいろいろある。
基本
-- 基本はこの形 関数名 引数 = 定義式 -- 例 isDigit :: Char -> Bool isDigit c = c >= '0' && c <= '9'
条件式
ifを使った式。
myAbs :: Int -> Int myAbs n = if n >= 0 then n else -n
- 入れ子に出来る。
then
の式とelse
の式は、同じ型でなければならない。else
は必須。
ガード
switch文に近い。上から順番に条件式を評価して、True
になった式の結果が適用される。
mySignum :: Int -> Int mySignum n | n < 0 = -1 | n == 0 = 0 | otherwise = 1
otherwise
は標準ライブラリ内でotherwise = True
と定義されている。switch文のdefaultとして使う。
(-1)?
mySignum -1
を試したら怒られた。
*Main> mySignum -1 <interactive>:353:10: No instance for (Num (Int -> Int)) (maybe you haven't applied enough arguments to a function?) arising from a use of ‘-’ In the expression: mySignum - 1 In an equation for ‘it’: it = mySignum - 1 *Main> mySignum (-1) -1
mySignum - 1
と解釈された?mySignum (-1)
で正しく動いた。
パターンマッチ
ガードに似ている。パターンと呼ばれる式とそれに対応する結果を列挙する。パターンを上から順に見ていって、合致するパターンの結果が採用される。
myAnd :: Bool -> Bool -> Bool True `myAnd` True = True True `myAnd` False = False False `myAnd` True = False False `myAnd` False = False -- パターンは上から順番に評価するから、ワイルドカード"_"を使うとこうも書ける。 True `myAnd` True = True _ `myAnd` _ = False -- 標準ライブラリではこの様に定義されているらしい。 -- 第1引数がFalseの場合、第2引数を評価する必要が無い。 True `myAnd` a = a False `myAnd` _ = False
タプル・パターン
要素がパターンであるタプルはパターンである。
myFst :: (a, b) -> a myFst (x, _) = x mySnd :: (a, b) -> b mySnd (_, x) = x
リスト・パターン
要素がパターンのリストはパターンである。
myTest :: [Char] -> Bool myTest ['a', _, _] = True myTest _ = False
String型は[Char]?
上のmyTestを実行してみた
*Main> myTest ['a', 'b', 'c'] True *Main> myTest ['a', 'b', 'c', 'd'] False *Main> myTest ['A', 'b', 'c'] False -- これでも同じ *Main> myTest "abc" True *Main> myTest "abcd" False *Main> myTest "Abc" False
文字列は[Char]型なの?
-- :tコマンドの結果 *Main> :t "hoge" "hoge" :: [Char] -- myTestの型宣言を変更してみたが、結果は同じ。 myTest :: String -> Bool myTest ['a', _, _] = True myTest _ = False *Main> myTest ['a', 'b', 'c'] True *Main> myTest ['a', 'b', 'c', 'd'] False *Main> myTest ['A', 'b', 'c'] False *Main> myTest "abc" True *Main> myTest "abcd" False *Main> myTest "Abc" False
同じだった。
*Main> :i String type String = [Char] -- Defined in ‘GHC.Base’
今回はここまで。