Приложение с частичной функцией Haskell с $
Я новичок в Haskell и смотрю на простой пример использования приложения функции с $
,
Это кажется простым - он берет функцию и применяет ее к значению.
Так что это имеет смысл:
> (+3) $ 2
5
Это также имеет смысл:
> ($) (+3) 2
5
Это имеет смысл, потому что первый аргумент является функцией, а второй аргумент является значением.
Теперь об использовании $
создать частичную функцию.
Глядя на типы, это имеет смысл - просто нужно Num
введите значение для b
:
> :t ($) (+3)
($) (+3) :: Num b => b -> b
Но вот где я заблудился - что здесь происходит?
> :t ($) (2)
($) (2) :: Num (a -> b) => a -> b
Я ожидал, что первый аргумент должен быть функцией, а не простым значением Num.
Итак, вот мои вопросы:
- Что тут происходит?
- Что значит ограничение
Num (a -> b)
синтаксис значит? - Какой пример использования
($)
таким образом, это начинается с чего-то вроде($) (2)
?
Спасибо!
1 ответ
С одной стороны, числовые литералы, такие как 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
,