Arantium Maestum

プログラミング、囲碁、読書の話題

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型とは限らない。というか型は定まっていない。