С одной стороны, числовые литералы, такие как 2
, на самом деле читаются как fromInteger 2 :: Num a => a
, поэтому могут обозначать любое значение типа Num a => a
, то есть любой тип, который в классе типов Num
то есть имеет среди прочего определенную специальную версию fromInteger
, которая возвращает фактическое значение фактического типа, преобразованное из целого числа 2
:
> :i Num
class Num a where
(+) :: a -> a -> a
(*) :: a -> a -> a
(-) :: a -> a -> a
negate :: a -> a
abs :: a -> a
signum :: a -> a
fromInteger :: Integer -> a
как Учебное пособие по Haskell ставит (в 10.3),
Целое число (без десятичной точки) фактически эквивалентно применению fromInteger
к значению числа как Integer
.
С другой стороны, ($)
имеет тип
> :t ($)
($) :: (a -> b) -> a -> b
Итак, у нас есть
fromInteger 2 :: Num a1 => a1
($) :: (a -> b) -> a -> b
--------------------------------------------
($) 2 :: Num (a -> b) => a -> b
Так что это функция, которая также должна быть в класс типов Num
.
Обычно это не так, но Haskell не знает, можно ли импортировать какой-либо модуль, который определяет такой экземпляр:
instance Num (a -> b) where
....
fromInteger n = ....
....
, поэтому он допускает такую возможность при проверке типа, и только тогда, видя, что такой фактический экземпляр не определен нигде, выдает ошибку , что .
Например,следуя подсказке от @ augustss в комментариях,
instance (Num b) => Num (a -> b) where
(+) f g x = f x + g x
(*) f g x = f x * g x
abs f x = abs (f x)
negate f x = negate (f x)
signum f x = signum (f x)
fromInteger n = const (fromInteger n)
позволяет нам написать (sin + 2 * cos^2) x
.