できたらいいなAndroidアプリ

Androidに限らずいろいろ書いていく。

プログラミング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’

今回はここまで。