As far as I can tell, GHC can convert any numeric literal with default polymorphic type Num a => a
into any type with an instance of Num
. I'd like to know whether this is true and a little about the underlying mechanism.
To explore this, I have written a datatype called MySum
which replicates (part of) the functionality of Sum
from Data.Monoid. The most important part is that it contains instance Num a => Num (MySum a)
.
Note - This just so happens to be where my question go its start. The Monoid is not specifically relevant. I've included a portion of that code at the bottom of this question, just in case it is useful for an answer to refer to the contents.
It seems that GHCi will happily comply with an input of the form "v :: MySum t", under the following conditions:
v is a polymorphic value of type
Num a => a
t is a (possibly polymorphic) type under
Num
As far as I can tell, the only numeric literals compatible with the type Num a => a
are ones that look like integers. Is this always the case? It seems to imply that a value can instantiated to any type under Num exactly when that value is integral. If this is correct, then I understand how something like 5 :: MySum Int
might work, given the function fromInteger
in Num
.
With all of that said, I can't figure out how something like this works:
*Main Data.Monoid> 5 :: Fractional a => MySum a
MySum {getMySum = 5.0}
If it's possible to explain this in a novice-friendly way, I would appreciate it.
The instance Num a => Num (MySum a)
, as promised:
import Control.Applicative
newtype MySum a = MySum {getMySum :: a}
deriving Show
instance Functor MySum where
fmap f (MySum a) = MySum (f a)
instance Applicative MySum where
pure = MySum
(MySum f) <*> (MySum a) = MySum (f a)
instance Num a => Num (MySum a) where
(+) = liftA2 (+)
(-) = liftA2 (-)
(*) = liftA2 (*)
negate = fmap negate
abs = fmap abs
signum = fmap signum
fromInteger = pure . fromInteger