第3章 型とクラス竹辺靖昭 (@beketa)
基本概念型とは?互いに関連する値の集合例: Bool型はFalseとTrueという値を持つv :: T  「vは型Tの値である」例: False :: Bool       not :: Bool -> Bool    -- Bool型をBool型に変換する関数の型       not True :: Bool型推論関数適用の型付け規則:f :: A -> B かつ e :: A ならば f e :: Bすべての式は型を持たなければいけない推論できない式(例: not 3)は型エラーとなるHaskellは事前に型検査をおこなうので型安全である(型安全だからといってエラーがないわけではない: 1 `div` 0)
基本概念(続き)GHCのコマンド:type (Hugsと同じ):t とも書けるGHCでのセッション例:*Main> :type notnot :: Bool -> Bool*Main> :t not Falsenot False :: Bool*Main> :t not 3<interactive>:1:5:No instance for (Num Bool)(以下略)
基本型Bool : TrueとFalseChar : 文字 'a', 'A', '3', '_', '\n' などString : 文字列 "abc" (Charのリスト [Char])Int: 固定精度整数Integer : 多倍長整数Float : 単精度浮動小数点数数値は複数の型を持ちうる3:: Int, 3 :: Integer, 3 :: Float のどれも有効
リスト型リスト同じ型の要素の並びT型の要素を持つリストの型を[T]と書く例: [False, True, False] :: [Bool]       ['a', 'b', 'c', 'd'] :: [Char]  ("abcd"と同じ)       ["One", "Two", "Three"] :: [String]リスト型の特徴リストの型には長さの情報は含まれていない要素の型に特に制約はない(何のリストでも作ることができる)リストの長さには制限はない(無限リストも可)
タプル型タプル有限個の要素の組(各要素の型は違っていてもよい)i番目の要素が型Tiを持つときタプルの型を(T1, T2, ..., Tn)と書く(i = 1 ... n)例: (False, True) :: (Bool, Bool)       (False, 'a', True) :: (Bool, Char, Bool)       ("Yes", True, 'a') :: (String, Bool, Char)() : ユニット組(double) : 要素数2のタプル三つ組(triple) : 要素数3のタプルタプルの特徴タプルの型には長さの情報が含まれている要素の型に特に制約はない(何のタプルでも作ることができる)タプルの要素数は有限
関数型T1の引数をT2に変換する関数の型をT1 -> T2と書く例: not :: Bool -> BoolisDigit :: Char -> Bool特徴引数と結果の型には制約はないリストやタプルを使えば複数の引数を取る関数などを定義できる例: add :: (Int, Int) -> Int       add (x, y) = x + yzeroto :: Int -> [Int]zeroto n = [0 .. n]全域関数である必要はない(例: headは[]には定義されていない)
関数型(続き)余談: GHCでのisDigitの使い方Hugsの例で載っていた:loadコマンドではPrelude> :load Data.Char<no location info>: module `Data.Char‘ is a package moduleFailed, modules loaded: none.となってしまいロードできないようであったPrelude> import Data.CharPrelude Data.Char> :t isDigitisDigit :: Char -> Bool
カリー化された関数カリー(Curry)化: 「カレー」と同じスペルしかし「カレー化」とは表記しないようである
カリー化された関数タプルを使わずに複数の引数を処理するやり方add' :: Int -> (Int -> Int)add' x y = x + yadd' xは関数を返すその関数にyを与えるとx + yを返す先ほどのタプルを使った足し算add :: (Int, Int) -> Intadd (x, y) = x + yaddのような関数をadd'のようにすることをカリー化という3引数以上でもできる
カリー化された関数(続き)カリー化された関数の方が柔軟である部分適用(引数を部分的に与える)だけで関数を作ることができる例: add' 1はInt -> Intの関数として使える->は右結合Int -> Int -> Int -> IntはInt -> (Int -> (Int -> Int)) の意味である関数適用は左結合mult x y z は((mult x) y) z の意味である
多相型リストの長さを求める関数lengthどんな型のリストの長さも求められる> length [1, 3, 5, 7]4> length ["Yes", "No"]2型変数: 「どんな型にも」を表す(小文字 a, b, c)例: length :: [a] -> Intfst :: (a, b) -> a       head :: [a] -> a  等
多重定義型加算演算子 +IntやFloatなどの数値型の足し算ができる> 1 + 23> 1.1 + 2.23.3クラス制約: 「どんな数値型にも」というような制約を表す書き方 C aC: クラス名、a: 型変数 「クラスCのインスタンスであるどんな型aについても」(+) :: Num a => a -> a -> aNumクラスのインスタンスであるどんな型aについても加算演算子(+)の型はa -> a -> aである
多重定義型 (続き)例: (-) :: Num a => a -> a -> a       negate :: Num a => a -> a       abs :: Num a => a -> a数値自体も多重定義されている3 :: Num a => a
基本クラスクラス共通のメソッド(多重定義された関数)を提供する型の集合クラスのインスタンス: クラスの要素Eq: 等しいかどうか判定できる以下のメソッドが定義されている(==) :: a -> a -> Bool(/=) :: a -> a -> BoolBool, Char, String, Int, IntegerなどはEqのインスタンスEqのインスタンスのリスト、タプルもEqのインスタンス関数型はEqクラスのインスタンスではない
基本クラス (続き)Ord: 順序がつけられるEqクラスのインスタンスであり、以下のメソッドが定義されている(<) :: a -> a -> Bool(<=) :: a -> a -> Bool(>) :: a -> a -> Bool(>=) :: a -> a -> Boolmin :: a -> a -> amax :: a -> a -> aBool, Char等はOrdのインスタンスOrdのインスタンスのリスト、タプルもOrdのインスタンス(辞書式順序)
基本クラス (続き)Show: 表示できる(文字列に変換できる)show :: a -> StringRead: 文字列から変換できるread :: String -> areadの結果の型は文脈から決まる場合にはその型になるnot (read "False")のread "False"の型はBool決まらない場合には結果の型を指定すればよい> read "123"<interactive>:1:1:    Ambiguous type variable `a0‘ in the constraint:(中略)> read "123" :: Int123目的の型に変換できないような文字列が入力されるとエラーになるnot (read "Hello")はエラーになる
基本クラス (続き)Num: 数値EqとShowのインスタンスであり、以下のメソッドが定義されている(+) :: a -> a -> a(-) :: a -> a -> a(*) :: a -> a -> anegate :: a -> aabs :: a -> asignum :: a -> aIntegral: 整数Numのインスタンスであり、以下のメソッドが定義されているdiv :: a -> a -> amod :: a -> a -> aFractional: 分数Numのインスタンスであり、以下のメソッドが定義されている(/) :: a -> a -> arecip :: a -> a    -- 逆数
参考文献George BooleBool代数を作った人Haskell Curryカリー化はHaskell Curryにちなんで名づけられている(Haskellのカレーではない)Haskell Report型システムの詳細が書いてあるhttp://www.haskell.org/definition

第3章 型とクラス