データ型を定義する
data
キーワードで定義する。
data MyBool = False | True
MyBool
というデータ型はTrue
またはFalse
の値コンストラクタを受け取る。型名及び、値コンストラクタは大文字から始まる必要がある。
値コンストラクタには引数を与えることができる。
data Shape = Circle Float Float Float | Rectangle Float Float Float Float
値コンストラクタは定義したデータ型を返す関数となる。
ghci> :t Circle Circle :: Float -> Float -> Float -> Float -> Shape ghci> :t Rectangle Rectangle :: Float -> Float -> Float -> Float -> Shape
定義したデータ型を使用する
Shape型
の面積を求める関数。
area :: Shape -> Float area (Circle _ _ r ) = pi * r ^ 2 area (Rectangle x1 y1 x2 y2) = ( abs $ x1 - x2 ) * ( abs $ y1 - y2 )
円を面積を求める場合、Circle型
を引数としたいところなんだけど、Cirecleはデータ型ではなく値コンストラクタなので、引数として用いることはできない。True -> Int
ではなくBool -> Int
と書かなければならない。ということ。
ghci> area $ Circle 1 1 1 3.1415927 ghci> area $ Rectangle 1 1 3 3 4.0
データ型に型クラスを定義する
Show型クラスを与える。(インデントに注意)
data Shape = Circle Float Float Float | Rectangle Float Float Float Float deriving (Show)
ghci> Circle 1.0 1.0 2.0 Circle 1.0 1.0 2.0
値コンストラクタは関数
値コンストラクタは関数なのでカリー化したり、高階関数として利用できたりする。とてもオシャレ。
ghci> let c = Circle 1.0 1.0 ghci> map c [1,2,3] [Circle 1.0 1.0 1.0,Circle 1.0 1.0 2.0,Circle 1.0 1.0 3.0]
値コンストラクタの引数にデータ型を与える
値コンストラクタの引数にデータ型を指定することも可能。Point
というデータ型を作成し、CircleとRectangleの座標点として活用。
data Point = Point Float Float deriving (Show) data Shape = Circle Point Float | Rectangle Point Point deriving (Show)
レコード構文
値コンストラクタの引数を名前付引数として表現する。
data Person = Person { firsrName :: String, lastName :: String, age :: Int } deriving (Show)
指定したフィールド名は自動的に関数として定義される。モジュール化しておき関数名の衝突を防げばよい。
ghci> :t firsrName firsrName :: Person -> String
初期化。以下のように扱うことができる。
ghci> let p = Person {firsrName="Mike", age=19, lastName="Gonz"} ghci> p Person {firsrName = "Mike", lastName = "Gonz", age = 19} ghci> firsrName p "Mike"
型引数
値コンストラクタに与える引数型の推論に用いる。例えば以下のように記述すると、異なる型を値コンストラクタに指定することができる。
data AnyType a = AnyVal a deriving(Show)
ghci> let i = AnyVal 1 ghci> let s = AnyVal "string" ghci> :t i i :: Num a => AnyType a ghci> :t s s :: AnyType [Char]
データインスタンスの比較
Eq型クラスを指定しておく。
data Person = Person { firsrName :: String, lastName :: String, age :: Int } deriving (Show, Eq)
比較はオブジェクト指向言語のようにインスタンスのハッシュ値を比較するのではなく、値コンストラクタと与えられた引数が一致するかで判断する。以下、p1とp2でTrueとなる。
ghci> let p1 = Person {firsrName="Mike",lastName="Gee",age=18} ghci> let p2 = Person {firsrName="Mike",lastName="Gee",age=18} ghci> let p3 = Person {firsrName="Mike",lastName="Gee",age=20} ghci> p1 == p2 True ghci> p1 == p3 False
列挙型
値コンストラクタに0引数、Enumを型クラスを与えることで列挙型が作成できる。OrdやBoundedも加えておくと便利。
data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday deriving (Eq, Ord, Show, Read, Bounded, Enum)
ghci> :t Monday Monday :: Day Traversable True ghci> Monday == Tuesday False ghci> minBound :: Day Monday
型シノニム
ある型に別名をつける。type
キーワードで定義する。
String型
は[Char]
の型シノニム。
type String = [Char]
型に別名をつけることによって、定義に対しての意味が明確になる。
type BookTitle = String type Books = [(BookTitle, String)] bookTitles :: Books -> [String] bookTitles books = map (\(s, _) -> s) books
型シノニムに型変数を与えることもできる。
type AssocList k v = [(k, v)]
Eitherタイプ
LeftとRightの値コンストラクタとそれに与える違った型変数をとる。主にLeftが異常系、Rightが正常型のデータを表す。
data Either a b = Left a | Right b deriving (Eq, Ord, Read, Show)