Насколько я могу судить, GHC может преобразовать любой числовой литерал с полиморфным типом по умолчанию Num a => a
в любой тип с экземпляром Num
. Я хотел бы знать, правда ли это, и немного о базовом механизме.
Чтобы исследовать это, я написал тип данных с именем MySum
, который копирует (часть) функциональность Sum
из Data.Monoid. Наиболее важной частью является то, что он содержит instance Num a => Num (MySum a)
.
Примечание. Так случилось, что мой вопрос начался. Моноид конкретно не актуален. Я включил часть этого кода в конец этого вопроса, на случай, если для ответа будет полезно обратиться к содержанию.
Похоже, что GHCi с радостью выполнит ввод в форме "v :: MySum t" при следующих условиях:
v - это полиморфное значение типа Num a => a
t (возможно, полиморфный) тип под Num
Насколько я могу судить, единственными числовыми литералами, совместимыми с типом Num a => a
, являются те, которые выглядят как целые числа. Это всегда так? Кажется, подразумевается, что значение может быть создано для любого типа в Num именно тогда, когда это значение является целым. Если это правильно, то я понимаю, как может работать что-то вроде 5 :: MySum Int
, учитывая функцию fromInteger
в Num
.
С учетом всего сказанного я не могу понять, как работает нечто подобное:
*Main Data.Monoid> 5 :: Fractional a => MySum a
MySum {getMySum = 5.0}
Если бы это можно было объяснить новичкам, я был бы признателен.
Экземпляр Num a => Num (MySum a)
, как и обещано:
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