Haskellの基本データ型

(2008.8.18 新規作成。)

Preludeモジュールを中心に、基本的な型と, 主に使いそうな関数をまとめてみました。

基本型

Haskellの基本型には、次のようのものがあります。

区分 リテラル例 備考
真偽型 Bool True, False
整数 Int, Integer 3
実数 Float, Double 2.0
有理数 Rational
文字 Char 'a'
文字列 [Char], String "abc"
リスト [1,2,3] 値の型は同じでなければならない。
タプル ('a', 4)

真偽型

真または偽を表す真偽型は Bool です。

Bool型は FalseまたはTrueという値のみを持ちます。数値などからBool型への暗黙の変換はありません。True && 1 というコードはエラーになります。

Boolの例です。論理andと論理orはC言語スタイルです。

Prelude> True && True
True
Prelude> False || True
True
Prelude> not True
False
Prelude> True && 1

<interactive>:3:9:
    No instance for (Num Bool) arising from the literal `1'
    Possible fix: add an instance declaration for (Num Bool)
    In the second argument of `(&&)', namely `1'
    In the expression: True && 1
    In an equation for `it': it = True && 1

Bool型の定義をghciで見てみます。:infoコマンドです。

Prelude> :info Bool
data Bool = False | True 	-- Defined in `GHC.Types'
instance Bounded Bool -- Defined in `GHC.Enum'
instance Enum Bool -- Defined in `GHC.Enum'
instance Eq Bool -- Defined in `GHC.Classes'
instance Ord Bool -- Defined in `GHC.Classes'
instance Read Bool -- Defined in `GHC.Read'
instance Show Bool -- Defined in `GHC.Show'

Bool型は Enum, Eqなどのクラスのインスタンスになっています。

用語に注意:: ほかのプログラミング言語では,「型」=「クラス」となっているものが多いです。クラスをインスタンス化するとオブジェクトが生成されます。

いっぽうHaskell では, クラス (class) のインスタンスは「型」(data type) です。クラスでは型に共通の関数などを定義できます。

Haskell のクラスは, ほかのプログラミング言語でいうモジュールや抽象クラスみたいなものです。

整数

整数を表す型は Int と Integer です。Intは機械でプリミティブに表現できる大きさ (例えば31bit) までの整数, Integerはそれを超える大きさも扱えます (多倍長整数)。

Int型だと2の31乗でも値が壊れていますが, Integerにすると大丈夫です。

「リテラル::型名」とすると, リテラルを強制的に特定の型とできます。

Prelude> (2::Int) ^ 30
1073741824
Prelude> (2::Int) ^ 31
-2147483648
Prelude> (2::Int) ^ 32
0
Prelude> (2::Integer) ^ 32
4294967296

Int型は, 次のクラスのインスタンスになっています。

いっぽう Integer型は, 上のInt型のクラスのうち Boundedクラス以外のインスタンスになっています。

Bounded クラスは, 値の上限および下限を表す関数 maxBound, minBound を宣言しています。Integer型には上限および下限がありません。

Prelude> minBound::Int
-2147483648
Prelude> maxBound::Int
2147483647

Haskellでは暗黙の型変換はしてくれないので, Int型の値とInteger型の値で計算するときは, 型を合わせないといけません。

Prelude> (2::Int) + (3::Integer)

<interactive>:34:13:
    Couldn't match expected type `Int' with actual type `Integer'
    In the second argument of `(+)', namely `(3 :: Integer)'
    In the expression: (2 :: Int) + (3 :: Integer)
    In an equation for `it': it = (2 :: Int) + (3 :: Integer)

Int と Integer型の値は, toInteger関数か fromIntegral関数で揃えます。Intの範囲で十分か不明なときは, Int型のほうをInteger型に変換します。

次の例の前者は, Int型で表現できないのにInt型に変換しているため, 値が壊れています。エラーは出ません。

Prelude> (2::Int) + fromIntegral ((3::Integer) ^ 33)
-1504003195
Prelude> fromIntegral (2::Int) + ((3::Integer) ^ 33)
5559060566555525

fromIntegral関数は, Integralクラスのインスタンスである型 (= Int, Integer) の値を引数に取り, Numクラスのインスタンスの型へ変換します。

Numクラスについては後述。

fromIntegral :: (Integral a, Num b) => a -> b
  	-- Defined in `GHC.Real'

主な演算子

四則演算も普通にできます。比較演算子もC言語スタイルです。演算子は優先順位があります。+, -より *, /が先。

比較では, 実数と整数を比較しても大丈夫。不等号は「!=」ではなく「/=」.

整数同士の除算は, 割り切れないときは実数になります。

Prelude> 2 + 1000 * 3
3002
Prelude> 1 == 1
True                                                                            
Prelude> 4 >= 3.99
True                                                                            
Prelude> 2 /= 3
True                                                                            
Prelude> 2 / 3
0.6666666666666666                                                              

(==), (/=) は Eqクラスで, (<), (<=), (>), (>=) は Ordクラスで宣言されています。

また, 「(演算子)」と書くと, 関数呼び出しスタイルで呼び出せます。

Prelude> (*) 2 50
100

Integralクラス

Int, Integer型の共通のクラスである, Integralクラスについても見ておきましょう。

quotなど, 共通の関数が宣言されています。

class (Real a, Enum a) => Integral a where
  quot :: a -> a -> a
  rem :: a -> a -> a
  div :: a -> a -> a
  mod :: a -> a -> a
  quotRem :: a -> a -> (a, a)
  divMod :: a -> a -> (a, a)
  toInteger :: a -> Integer
  	-- Defined in `GHC.Real'

実数

Float型とDouble型があります。

両方とも, 次のクラスのインスタンスです。

有理数

有理数を表す Rational型もあります。まず, Data.Ratioモジュールを導入します。

Prelude> :module + Data.Ratio
Prelude Data.Ratio> :info Rational
type Rational = Ratio Integer 	-- Defined in `GHC.Real'

Rational型はRatio Integerの別名です。Ratioについて見てみましょう。

Haskell
[POPUP]
  1. data Ratio a = !a GHC.Real.:% !a -- Defined in `GHC.Real'
  2. instance Integral a => Enum (Ratio a) -- Defined in `GHC.Real'
  3. instance Eq a => Eq (Ratio a) -- Defined in `GHC.Real'
  4. instance Integral a => Fractional (Ratio a)
  5. -- Defined in `GHC.Real'
  6. instance Integral a => Num (Ratio a) -- Defined in `GHC.Real'
  7. instance Integral a => Ord (Ratio a) -- Defined in `GHC.Real'
  8. instance (Integral a, Read a) => Read (Ratio a)
  9. -- Defined in `GHC.Read'
  10. instance Integral a => Real (Ratio a) -- Defined in `GHC.Real'
  11. instance Integral a => RealFrac (Ratio a) -- Defined in `GHC.Real'
  12. instance (Integral a, Show a) => Show (Ratio a)
  13. -- Defined in `GHC.Real'

Numクラス

基本になる Num.

class Num a where
  (+) :: a -> a -> a
  (*) :: a -> a -> a
  (-) :: a -> a -> a
  negate :: a -> a
  abs :: a -> a
  signum :: a -> a
  fromInteger :: Integer -> a
  	-- Defined in `GHC.Num'
instance Num Integer -- Defined in `GHC.Num'
instance Num Int -- Defined in `GHC.Num'
instance Num Float -- Defined in `GHC.Float'
instance Num Double -- Defined in `GHC.Float'

共通の演算子

いろいろな型で使える演算子は、EqクラスやOrdクラスで定義されています。

class Ord

class Eq a => Ord a
compare :: a -> a -> Ordering
compare x y は、x, y の大小関係をEQ, LT, GT で返す。x < y のときLT.
(<) :: a -> a -> Bool
(<=) :: a -> a -> Bool
(>) :: a -> a -> Bool
(>=) :: a -> a -> Bool
max :: a -> a -> a
min :: a -> a -> a
max, min は、二つの値を比較して、大きいほう/小さいほうを返す。
data Rational = Ratio Integer class (Eq a, Show a) => Num a class (Num a, Ord a) => Real Fractional Floating

タプル

fst :: (a, b) -> a
タプルの最初の要素を得る。
snd :: (a, b) -> b
タプルの2番目の要素を得る。

3つ以上のタプルのときはどうやって取り出すの?