1. Haskell の数値の種類
Prelude の Numbers には、Haskell 数値型が挙げられてる。
これを Python の「3.2 標準型の階層」における Numbers と比較すると、
- Int --- plain integer, int()
- Integer --- long integer, long()
- Float
- Double --- floating point number, float()
- Rational
Float について、Python では、
Python は単精度の浮動小数点数をサポートしません; 単精度の数を使う理由は、通常プロセッサやメモリ使用量の節約ですが、こうした節約は Python でオブジェクトを扱う際のオーバヘッドに比べれば微々たるものにすぎません。
(3.2 標準型の階層 より)
ついでに、Ruby では、
Float の実装は C 言語の double で、その精度は環境に依存します。
組み込みクラス/モジュール/例外クラス - Rubyリファレンスマニュアル via kwout
2. Int と Integer の違い
Prelude の data Int によると、Int は、
A fixed-precision integer type with at least the range [-2^29 .. 2^29-1].
Int に対して data Integer は、
Arbitrary-precision integers.
つまり、Int型 は表現できる範囲が決っているのに対して、Integer 型 は制限がない。
maxBound, minBound 関数で、表現できる範囲を調べる
Int 型は 2^29 の範囲を表現できることが保証されている。 実際に使える範囲を知るには、
「using minBound and maxBound from the Bounded class. 」
(data Int より) 。
maxBound は Bounded クラスのメソッドで、次のように定義されている。
maxBound :: a
ん? (@_@;) 何だろう、このメソッドは。「引数が一つ?」かと一瞬思いきや、
引数はなく、返ってくるのは型変数 a ?
型クラスとインスタンスの関係を整理する
Bounded クラスを見ると、以下のように定義されている。
class Bounded a where minBound, maxBound :: a
型クラスの宣言で使われている型変数 a は、Bounded クラスのインスタンス。
例えば、Bool 型は、Bounded クラスのインスタンスとして定義されている。Bool 型の値は、True と False しかないので、最大・最小を考えやすい。以下のように定義されている。
instance Bounded Bool where minBound = False maxBound = True
この型クラスとインスタンスの表現は、慣れないと混乱する。(+_+) 基本的な事項を整理する。
上記の `instance’ は、
Bool 型が Bounded クラスのインスタンスである
ことを宣言している。
Bounded クラスでは、実装すべき関数は 2 つある。
- minBound
- maxBound
この関数の返す値は、Bounded クラスの定義を見ると、型変数 a とある。
class Bounded a where
この型変数 a は、任意の型ではなく、 Bounded クラスのインスタンス。
Bool 型を、Bounded クラスのインスタンスであると、定義したのを見直す。
instance Bounded Bool where minBound = False maxBound = True
minBound は False を返し、maxBound は True を返している。
このように書ける理由は、「Bool 型 は、Bounded クラスのインスタンスである」と、最初の行で宣言している。
よって、Bool 型の値は、Bounded クラスのインスタンスだから、
「 minBound, maxBound 関数を定義し、その関数は Bounded クラスのインスタンスである型ノ値でなくてはならない」
ということを満たすことになる。つまり、 Bool 型に対して maxBound を適用すると、Bounded クラスのインスタンスである Bool 型の値 True を返すということ。
(cf. Haskell の代数的データ型と型クラス、instance 宣言の関係)
maxBound を適用するときは、型を指定する
ghci で maxBound を呼出すと、
Prelude> maxBound:1:0: Ambiguous type variable `a' in the constraint: `Bounded a' arising from a use of `maxBound' at :1:0-7 Probable fix: add a type signature that fixes these type variable(s)
「型変数 a が曖昧だから型を付けろ!」ということかな。
Haskell : maxBound によると、以下のように型を指定する必要がある。
Prelude> maxBound :: Bool True
なぜなら、maxBound 関数は、いろいろな型のインスタンス宣言で多重定義されているから、どの型に適用したいのか示さなければならない。
表現できる数値の確認
maxBound, minBound を使って限界を確認してみる。
print $ 2 ^ 29 - 1 -- 536870911 print (maxBound :: Int) -- 2147483647 print $ 2 ^ 31 - 1 -- 2147483647 print $ 0x7fffffff -- 2147483647 print $ - 2 ^ 29 -- -536870912 print (minBound :: Int) -- -2147483648 print $ - 2 ^ 31 -- -2147483648 print $ -0x80000000 -- -2147483648
(cf. 32ビット – Wikipedia)
Int 型は、境界となる値に気をつける
Int 型の範囲を調べるために、境界となる値を調べる関数 hoge を定義する。
hoge :: Int -> Int hoge x = 2 ^ 31 + x main = do print $ hoge (-1) -- 2147483647 print $ hoge 0 -- -2147483648
hoge 関数は、Int で表現できる範囲を超えると負の数になってしまう。
これを修正するには、toInteger を使う。
hoge :: Int -> Integer hoge x = 2 ^ 31 + (toInteger x)
Int と Integer は型が異なるので、
print $ hoge (0 :: Integer)
と書くと、
Couldn't match expected type `Int' against inferred type `Integer'
「Integer 型に適用しているけれど、そこは Int 型!」と、しっかり怒られる。
3. Float もあるけれど、Double を使えば良い
Float, Double については、各々以下を参照。
-
単精度 – Wikipedia --- Float
- 倍精度 – Wikipedia --- Double
先ほど述べたように、Python は Float に相当するものがない。Haskell も基本は Double 。
Float
s (probably 32-bits) are almost always a bad idea, unless you Really Know What You Are Doing. UseDouble
s. There's rarely a speed disadvantage—modern machines will use the same floating-point unit for both.
Float と Double では、パフォーマンスに滅多に差が出ないとのこと。
Float 、Double の型の定義を比較すると、同じ型クラスのインスタンスであることがわかる。
4. Rational は有理数
Rational は、有理数を表わす。
有理数(ゆうりすう、rational number)とは、二つの整数 a, b (ただし b は 0 でない)をもちいて a/b という分数で表せる数のことをいう。b = 1 とすることにより、任意の整数は有理数として扱うことができる。
(有理数 – Wikipedia より)
Python で有理数を使うには、こちらを参照。
Haskell では、以下のように type で別名が与えられている。
Data.Ratio によると、% によって Ratio a 型の値を作ることができる。
Rational を少数に変換するには、Fractional クラスの fromRational を使う。
fromRational :: Rational –> a
試してみる。
import Data.Ratio main = do print $ 1 % 3 -- 1%3 print $ 2 % 6 -- 1%3 print $ fromRational (1 % 3) -- 0.3333333333333333
5. Num は型クラス
数値に関するエラーで、よく見かける Num 。
これは型ではなくて、型クラス。
この型クラスにより、型に適用できる関数が定義されている。適用できる関数により、数値の型を分類していると言える。数値の型が、どの型クラスのインスタンスで、どのような関数を適用できるのか、確認しておくと良い。
数値の階層関係
階層関係を示すと、
その他、RealFrac, RealFloat がある。
上記の階層関係における --- の右側のクラスは、Num の系統以外に、各々のクラスに制約として付いているクラス。
Num クラスでは、値が等しいかどうか分かればよく、順序関係を表す Ord クラスは、Real クラスで付けられている。
例えば、 「10 より大きいか検査する関数」を定義して、Num クラスの制約を付けたとする。
comp10 :: Num a => a -> Bool comp10 x = x > 10 main = do print $ comp10 8
実行すると、
Could not deduce (Ord a) from the context (Num a) arising from a use of `>' at numtest.hs:28:11-16
`>’ を適用することができないとエラーがでる。
少なくとも、comp10 関数の引数の制約は Real でなくてはだめということ。
6. まとめ
- Haskell における数値の表現には、色々な型がある。
- 数値の型は、型クラスの観点から分類されている。
- 型クラスは、数値に対する可能な操作を定義することによって、数の概念を表現している。
0コメント:
コメントを投稿