В Haskell, числовые литералы не полиморфный:
1 :: Int
1 :: Integer
1 :: Double
...
Технически это достигается с помощью общего типа
1 :: Num a => a
Таким образом, "1
может быть любого типа, при условии, что такой тип относится к классу Num
».
Когда вы делаете, например, C2 1
, 1
берется из типа функции a -> a
, и дополнительное ограничение создается для того, чтобы a -> a
является Num
:
C2 1 :: Num (a -> a) => T a
Конечно, функция является не число. Почему тогда нет ошибки типа? Потому что в Haskell не запрещено расширять класс Num
, чтобы включить функции. Вы можете сделать это с, , например:
instance Num b => Num (a -> b) where
fromInteger n = \_ -> n
x + y = \z -> x z + y z
...
превращая 1 :: a -> a
в функцию «константа один».
Это может дать такой код (надуманный пример следует)
case (some value of type T Int) of
C1 x -> x
C2 f -> (f + g) 50
-- assumning g :: Int -> Int
-- result is f 50 + g 50
Если вы не предоставите экземпляр, то код не является по своей сути неправильно, так как экземпляр может быть добавлен позже. В этом случае ограничение будет зависеть в вашем коде, поскольку оно не может быть освобождено. Если вы попытаетесь преобразовать T a
в любой тип, не включающий a
, для этого необходимо выполнить ограничение Num
, и в это время компилятор действительно будет жаловаться.
случаи, связанные с (+1)
можно объяснить, заметив, что это раздел оператор, так что это не просто унарный плюс в передней части 1.В частности,
(+1) means \x -> x + 1
так (+1)
на самом деле функция последования.
В ': t C1 (+1)' тип a is '(Num t => t -> t)' – Squidly