Posted at

すごいH本読んだからまとめ 3 「型」


はじめに


Haskellの型


型を確認してみる


  • ghciに:tと打ち込むと型を表示できる

*Main Lib> :t 'a' -- シングルクォーテーション、1文字

'a' :: Char
*Main Lib> :t 'ab' -- シングルクォーテーション、複数文字
<interactive>:1:1: error:
? Syntax error on 'ab'
Perhaps you intended to use TemplateHaskell or TemplateHaskellQuotes
? In the Template Haskell quotation 'ab'
*Main Lib> :t "aiueo" -- ダブルクォーテーション、複数文字
"aiueo" :: [Char]
*Main Lib> :t True -- 真偽値
True :: Bool


  • 値に対する型の表示は「値 :: 型」というフォーマットで出力される。


関数の型


  • Haskellは関数の型を明示的に宣言することができる。

isZero :: Int -> Bool -- 引数 -> 戻り値

isZero x = x == 0 -- Int型のxを受け取ってそれが0より大きいかどうかをBool型で返す。
*Main> isZero 9
False

-- 引数が複数ある場合は
-- 「引数 -> 引数 -> ...-> 戻り値」の順に型を定義する。
addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z


型の種類

|型|説明|

|--|--|

|Int|整数|

|Integer|巨大な整数|

|Float|浮動小数点数|

|Double|倍精度浮動小数点数(Floatの2倍のbit数で少数を表すので精度高まる)|

|Bool|TrueとFalseの2つを表す|

|Char|Unicode文字|

|タプル|()の中の要素数と要素の型に依存して型が決まる。空のタプルも()の型を持つ|


  • Haskellにおける文字列は文字のリストとして考えることができる

*Main Lib> ['a','i','u','e','o'] == "aiueo" -- 左右は同じもの

True


型変数


  • takeの型を確認するとリストの中身にaと入っている。

*Main> :t take

take :: Int -> [a] -> [a]
*Main> take 3 "aiueo" -- 文字列は文字のリスト
"aiu"


  • takeは指定された数の分だけ、リストの先頭を取り出す関数。

*Main> take 2 [1,2,3]

[1,2]


  • リストの中身はどんな型でも気にしない。そのため、aと表記することで、「どんな型でもいいですよ」を表す。


  • aのようなものを型変数と呼ぶ


  • 型変数を用いた関数は多相的関数と呼ぶ


型クラス


型クラスとは


  • あるに特定の関数を適用したときの振る舞いを定義するもの

  • 型と型クラスは多体多の関係

  • 文章ではなんだかよくわからないので具体例を確認する。


例(等値性)


  • (==)関数の型を確認してみる。(* (==)という書き方についてはこちら)

    haskell

    ghci> :t (==)

    (==) ::(Eq a) => a -> a -> Bool


  • いままで見たことない=>という書き方とその左側にある(Eq a)なるもの。ここが型クラス。


  • =>より右は同じ型の値を2つ突っ込んだら真偽値が入るという関数の型(私達は既に知っているはず。)


(Eq a) => a -> a -> Bool



  • (Eq a) は「Eqにおいて性質が保証された型a」というふうに読める。


  • A => Bは「AならばがB成立する。」と考えて大丈夫そうなので


  • (Eq a) => 左辺で「Eqという性質を満たす型aならば左辺が成立」と読める。


  • aが型変数ということはIntやリストなど、様々な型についてEqによる等値性の定義がされていると考えられる。

具体的に値を入れて関数を実行してみると

*Main> (==) [1,2,3] [1,2,3]

True
*Main> (==) [1,2,3] [1,2,2] -- 要素数が同じだけではFalse
False


  • 要素数が一緒なだけでなく、要素のパターンまで同じでないと(==)関数の結果がTrueにならないのは、Eqがリストの等値性をそういう定義にしているからなのである。

  • 型クラスはこういう風に「あるに特定の関数を適用したときの振る舞いを定義」する


他の型クラス


  • Show

文字列として表現できるもの

*Main> :t show --show関数の定義をみると

show :: Show a => a -> String -- Show型クラスを条件にした定義が書いてある。
-- 関数名と型クラス名が同じで分かり辛いが大文字から始まるShowは「文字列として表現できる」ということを表す型クラス。
-- showは「与えられた型を文字列にする」関数
*Main> show 1
"1"
*Main> show 3.0
"3.0"
*Main> show 'a'
"'a'"
*Main> show "aaa"
"\"aaa\""
*Main> show True
"True"
*Main> show False
"False"
*Main> show [1,2,3,4]
"[1,2,3,4]"


  • Num

数のように振る舞えるもの

*Main> :t (+) -- 足し算の型確認

(+) :: Num a => a -> a -> a -- 数のように振る舞えるならなんでも足し算していい
*Main> (+) 20 30 --整数でも
50
*Main> (+) 20.0 30.0 -- 浮動小数点数でもね
50.0

他にも


  • Ord(順番がある)

  • Enum(列挙可能)

  • Bounded(上限と下限をもつ)

  • Floating(浮動少数点数のみ)

  • Integral(実数のみ)

とかの型クラスで型の性質を定義できる。(基本的な型クラスの定義はHaskellがやっといてくれる)