Haskell は数値の型を合わせないと計算出来ません。それは他の言語も同じですが、 Haskell には型推論があるため、変換しようとする型を直接指定するのでなく、中間としてジェネリックな型を指定して、あとは Haskell におまかせするというようなイメージです。
(参考:Real World Haskell p153 表6-4 数値間の変換)
また、コンパイラが勝手にキャストとするということはありません。
整数(Int、Integer)の型が違う場合は fromIntegral を使って Num にして型を合わせてから計算する。
fromIntegral は Integral型からNum型に変換する関数です。
ghci> (fromIntegral (2::Int)) + 3::Integer --> 5 ghci> :t fromIntegral fromIntegral :: (Integral a, Num b) => a -> b
- Num 型は必要に応じてインスタンスが選択されます。
Num には Integer、Int、Float、Double のインスタンスがありますので、Integerのインスタンスを使って(+)の計算が行われます。
ghci> :i 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' ghci> :t (fromIntegral (2::Int))::Double --> (fromIntegral (2::Int))::Double :: Double ghci> :t (fromIntegral (2::Int))::Float --> (fromIntegral (2::Int))::Float :: Float ghci> :t (fromIntegral (2::Int))::Integer--> (fromIntegral (2::Int))::Integer :: Integer ghci> (fromIntegral (2::Int)) * (2::Integer) -- > 4 ghci> (fromIntegral (2::Int)) * (2::Float) -- > 4.0 ghci> (fromIntegral (2::Int)) * (2::Double) -- > 4.0
Integralクラスには IntegerとIntのインスタンスがある。
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 instance Integral Integer -- Defined in GHC.Real instance Integral Int -- Defined in GHC.Real
小数の型が違う場合は realToFrac を使って Real(Int、Integer、Float、Double) から Fractionalへ変換してから計算を行う。
> (realToFrac (2::Int)) / 3.2 --> 0.625 > (realToFrac (2::Int)) / (3.2::Double) --> 0.625 > (realToFrac (2::Int)) / (3.2::Float) --> 0.625 > :t realToFrac realToFrac :: (Real a, Fractional b) => a -> b -- Fractional型にはFloat、Double のインスタンスがありますので、必要に応じてFloat、Doubleの計算が行われます。 > :t (realToFrac (2.3::Double))::Float --> (realToFrac (2.3::Double))::Float :: Float > :t (realToFrac (2.3::Double))::Double --> (realToFrac (2.3::Double))::Double :: Double -- realToFrac は Real(Int、Integer、Float、Double)をFractional(Float、Double) -- に変換できる。 Prelude> :i Real class (Num a, Ord a) => Real a where toRational :: a -> Rational -- Defined in GHC.Real instance Real Integer -- Defined in GHC.Real instance Real Int -- Defined in GHC.Real instance Real Float -- Defined in GHC.Float instance Real Double -- Defined in GHC.Float > :t (realToFrac (2::Int))::Double -->(realToFrac (2::Int))::Double :: Double > (realToFrac (2::Int))::Double -->2.0 > (realToFrac (2::Integer))::Double -->2.0 > (realToFrac (2::Float))::Double -->2.0
- 整数とも浮動小数点とも解釈できるものは、 処理系が文脈に沿って解釈してくれます。
紫藤のページ / Haskell のお勉強 / 4. 型 / 1.3. 数値
ghci> 2 / 3 --> 0.6666666666666666 -- (/) は Fractional 型の引数を二つとりFractional 型を返す関数なので 2,3のリテラルは -- Fractional 型と 解釈されている。 -- (/) :: (Fractional a) => a -> a -> a ghci> :t 2 / 3 --> 2 / 3 :: (Fractional t) => t
- 整数(Int,Integer)には(/)instanceがないので割り算はエラーになる。
ghci> (2 :: Int) / (3 :: Int) <interactive>:1:0: No instance for (Fractional Int) arising from a use of `/' at <interactive>:1:0-22 Possible fix: add an instance declaration for (Fractional Int) In the expression: (2 :: Int) / (3 :: Int) In the definition of `it': it = (2 :: Int) / (3 :: Int) -- Num型にすれば OK ghci> (fromIntegral (2 :: Int)) / (fromIntegral (3 :: Int)) --> 0.6666666666666666
- Rational は有理数(分数で表せる数字)
ghci> toRational (1.2::Double) --> 5404319552844595 % 4503599627370496 ghci> toRational (0.25::Double) --> 1 % 4 ghci> toRational (0::Double) --> 0 % 1 ghci> toRational (1000::Double) --> 1000 % 1 -- Ratio モジュールをインポート ghci> :m + Ratio ghci> :i % (%) :: (Integral a) => a -> a -> Ratio a -- Defined in GHC.Real infixl 7 %
- 有理数を作ってみる。
> 1 % 2 -- > 1 % 2 > fromRational $ 1 % 2 -- > 0.5 > 1 / 3 ::Rational -- > 1 % 3 -- fromRational で出来るのは Fractional という型。 ghci> :t fromRational $ 1 % 2 --> fromRational $ 1 % 2 :: (Fractional a) => a ghci> 1 % 3 --> 1 % 3 ghci> fromRational $ 1 % 3 --> 0.3333333333333333 ghci> (fromRational $ 1 % 3)::Double --> 0.3333333333333333 ghci> (fromRational $ 1 % 3)::Float --> 0.33333334
- Double から Flot への変換。小数は必ず有理数になれる。Double も Flot も分数に変換し、Flot、Doubleに変換すればよい。
ghci> toRational (1.2::Double) --> 5404319552844595 % 4503599627370496 ghci> (fromRational $ toRational (1.2::Double))::Float -- > 1.2
- Fractional というのは Double、Float になれる数。
class (Num a) => Fractional a where (/) :: a -> a -> a recip :: a -> a fromRational :: Rational -> a -- Defined in GHC.Real instance Fractional Float -- Defined in GHC.Float instance Fractional Double -- Defined in GHC.Float ghci> :t (fromRational $ toRational (1.2::Double)) --> (fromRational $ toRational (1.2::Double)) :: (Fractional a) => a ghci> (fromRational $ toRational (1.2::Double)) + 1.2::Float --> 2.4 ghci> (fromRational $ toRational (1.2::Double)) + 1.2::Double --> 2.4
- Float から Double、Double から Float への変換。(Converting numbers)
> :m + GHC.Float > float2Double (1::Float) --> 1.0 > :t float2Double (1::Float) -- > float2Double (1::Float) :: Double > :t double2Float (1::Double) -- > double2Float (1::Double) :: Float > (1.234567890123456789::Double) -- > 1.2345678901234567 > double2Float (1.234567890123456789::Double) -- > 1.2345679
- Double、Float から Int, Integer へは小数点以下を切り捨てる。(Cookbook/Numbers)
ghci> :t (truncate (1.2::Double)) (truncate (1.2::Double)) :: (Integral b) => b ghci> :t (truncate (1.2::Double))::Int (truncate (1.2::Double))::Int :: Int