明示的な型宣言
GHCiで型を調べる
:t
を使う。
:t "a"
-- "a" :: [Char]
:t 1
-- 1 :: Num a => a
:t 2.0
-- 2.0 :: Fractional a => a
::
は〜の型を持つという意味。
関数の型宣言
引数と戻り値の方は->
で区切って、戻り値の型は最後。
removeNonUppercase :: [Char] -> [Char]
removeNonUppercase st = [c | c <- st, c `elem` ['A'..'Z']]
addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z
Haskellの一般的な型
- Int
- Float
- Double
- Bool
- Char
これらは他の言語とほぼ同じ。
違うのはこれ。
Integer
とても大きい整数。ただしInt
を使うほうが効率的。
factorial 50
-- 30414093201713378043612608166064768844377641568960512000000000000
()
空のタプルも型。ユニットと呼ばれる。
型変数
:t head
-- head :: [a] -> a
a
が型変数。どんな方も取り得る。
型変数を用いた関数は多相的関数と呼ばれる。
他のプログラミング言語にあるジェネリクスにちょっと似ている。
型変数の命名
a
、b
など1文字の場合が多い。
型クラス
型クラスとは?
何らかの振る舞いを定義するインターフェイス。
具体的には関数の集まり。
また、それらの関数をその型クラスのメソッドと呼ぶこともある。
オブジェクト指向型言語のクラスとは同じものではない。
型クラス制約
GHCi
で==
の型を確認。
:t (==)
-- (==) :: Eq a => a -> a -> Bool
=>
よりも前にあるものは型クラス制約と呼ばれる。
この結果の意味は「==
は同じ型の引数を2つ受け取り、Bool
を返す。引数の2つの型はEq
クラスのインスタンスでなければならない」
Eq
型クラス
Haskellのすべての標準型はEq
クラスのインスタンス(一部を除く)
2つの引数が同じ値かを確認。
Ord
型クラス
何らかの順序付けられる型のための型クラス。
:t (>)
-- (>) :: Ord a => a -> a -> Bool
:t (>=)
-- (>=) :: Ord a => a -> a -> Bool
Show
型クラス
ある値はその型がShow
型クラスのインスタンスになっていれば、文字列として表現できる。
Rubyのto_s
みたいなもの?
show 3
-- "3"
show "a"
-- "\"a\""
Read
型クラス
文字列を受け取りRead
のインスタンス型の値を返す。
read "True" || False
-- True
read "False" || False
-- False
read "1" + 2
-- 3
こういのはダメ。
read "5"
read
関数の型は以下のとおり。
GHCi
が何を返せばいいかわからない。GHCi
はread
関数から戻ってきた値の型を判定できない。
直後に+ 5
みたいなのがあると整数だと判定できる。
:t read
-- read :: Read a => String -> a
型注釈
コンパイラに型を伝える。
read "5" :: Int
-- 5
(read "5" :: Int) + 5
-- 10
Enum
型クラス
要素の値を列挙できる型クラス。
['a' .. 'z']
-- "abcdefghijklmnopqrstuvwxyz"
[LT .. GT]
-- [LT,EQ,GT]
サンプルとして[LT .. GT]
とあったけどLT
ってなんだろうか。
調べたあった。
HaskellのLT、GT、EQって - skalabeの日記
Ordering
という型らしい。
Bounded
型クラス
上限と下限を持つ。
minBound :: Int
--9223372036854775808
maxBound :: Int
-- 9223372036854775807
:t minBound
-- minBound :: Bounded a => a
:t maxBound
-- maxBound :: Bounded a => a
Num
型クラス
数値の型クラス。
:t 10
-- 10 :: Num a => a
:t 10.5
-- 10.5 :: Fractional a => a
:t 10 :: Double
-- 10 :: Double :: Double
あらゆる数値は多相定数として表現されている。
多相定数ってなんだ?
*
の型を調べる。
:t (*)
-- (*) :: Num a => a -> a -> a
2つの引数を受け取って1つの数を返し、これらはすべて同じ型でないといけない。
そのため、これはエラーになる。
(5 :: Integer) * (2 :: Int)
-- <interactive>:137:19:
-- Couldn't match expected type `Integer' with actual type `Int'
-- In the second argument of `(*)', namely `(2 :: Int)'
-- In the expression: (5 :: Integer) * (2 :: Int)
-- In an equation for `it': it = (5 :: Integer) * (2 :: Int)
--
けどこれはOK。
5 * (2 :: Integer)
-- 10
5はInt
、Integer
のどちらとしても振る舞える。
Floating
型クラス
Float
とDouble
が含まれる。浮動小数点の型クラス。
Integral
型クラス
Num
は実数の型クラス、Integral
は整数の型クラス。
fromIntegral
関数
浮動小数点と整数を一緒に扱う場合に使う。
fromIntegral :: (Integral a, Num b) => a -> b
何らかの整数を引数に取って一般的な数値を返す。
例えばlength
関数は整数を返すので、その値に実数をプラスするとエラー。
length [1,2,3] + 3.2
-- <interactive>:148:18:
-- No instance for (Fractional Int)
-- arising from the literal `3.2'
-- Possible fix: add an instance declaration for (Fractional Int)
-- In the second argument of `(+)', namely `3.2'
-- In the expression: length [1, 2, 3] + 3.2
-- In an equation for `it': it = length [1, 2, 3] + 3.2
+
は同じ型でなければいけない。
:t (+)
-- (+) :: Num a => a -> a -> a
fromIntegral(length [1,2,3]) + 3.2
-- 6.2
型クラスに関するいくつかの注意
- 1つの型クラスはいくつもの型クラスのインスタンスになることができる
- 1つの型クラスはいくつもの型をインスタンスとして持てる
- ある型のインスタンスにするために一旦、別のクラスのインスタンスにする必要がある場合がある
-
Ord
クラスのインスタンスになるにはEq
クラスにインスタンスになる必要がある