Thinking Functionally with Haskell勉強メモ: 第3章続続 integer/floatとInteger/Float
3.149 :: Fractional a => a
This type and the earlier type
Num a => a
for 42 explains why we can form a legitimate expression such as 42 + 3.149, adding an integer to a floating-point number. Both types are members of the Num class and all numbers can be added. (TFwH, p51)
これってどうなんだろう。42
は整数だし3.149
は小数だけど、それぞれがHaskell expressionとしてはTypeはInteger/IntやFloatではないし、だからこそ足せる、ように見えるのだけど・・・
例えば実際42 + 3.149
を評価してみると:
Prelude> 42 + 3.149 45.149 Prelude> :t 42 + 3.149 42 + 3.149 :: Fractional a => a
これは確かに整数と小数を足しているし、だからIntとFloatを足しているように見える。けれども
Prelude> :t 42 42 :: Num t => t Prelude> :t 3.149 3.149 :: Fractional t => t
42
はexpressionとしては型はNum t => t
、つまり「何の型かはまだわからないけどNum型のどれか」、3.149
は「何の型かはまだわからないけどFractional型のどれか」。42
がFractional型としても扱えるから足せた、というのが正しいのでは。
実際IntとFloatは足せない:
Prelude> :{ Prelude| x :: Int Prelude| x = 42 Prelude| y :: Float Prelude| y = 3.149 Prelude| :} Prelude> x + y <interactive>:7:5: error: • Couldn't match expected type ‘Int’ with actual type ‘Float’ • In the second argument of ‘(+)’, namely ‘y’ In the expression: x + y In an equation for ‘it’: it = x + y Prelude> :t x + y <interactive>:1:5: error: • Couldn't match expected type ‘Int’ with actual type ‘Float’ • In the second argument of ‘(+)’, namely ‘y’ In the expression: x + y
Int型のx、Float型のyに42と3.149という値が入っている場合はこのように足し合わせることができない。+
が(Num a) => a -> a -> a
だからだろう。もし(Num a, Num b) => a -> b -> b
などだったら足し合わせることができるだろうけど、a -> b -> b
なのかa -> b -> a
なのかなどが一意で決まらない。
42
といったexpressionを特定の型ではなく、許容度の高い「型クラスNumに属する型のどれか」とだけ推論しているから、他の「型クラスNumに属する型のどれか」のexpressionと足すと42
もその型のexpressionだと推論可能、だからwell-definedなまま、ということだと思う。
なので42 + 3.149
というexpressionはIntとFloatの和ではなく、「Fractional型クラスに属する何らかの型」二つの和だ。異なる型同士の演算が行われているのでも、型変換が行われているのでもなく、型推論で選択可能な最も許容度の高い型クラスに演算子の右辺・左辺ともに収束している。
目に見えるintegerやfloatは必ずしもInt型やFloat型とは限らない。というか型は定まっていない。