Приложение оператора Haskell доллар
У меня возникли проблемы с пониманием того, как приложение функции работает с карри в haskell. Если у меня есть следующая функция:
($) :: (a -> b) -> a -> b
Я понимаю, что для частичного применения этой функции мне нужно предоставить (a -> b)
функция ($
Первый аргумент).
Почему тогда можно сначала применить значение (т. Е. Обратные аргументы)?
($ 0) :: Num a => (a -> b) -> b
Что мне здесь не хватает?
4 ответа
($)
это оператор. В Haskell любой оператор может быть записан в левой части (например, (x $)
) или правый раздел (например, ($ x)
):
(x $) = (\y -> x $ y) = ($) x
($ x) = (\y -> y $ x) = flip ($) x
Обратите внимание, что единственным исключением из этого правила является (-)
, чтобы удобно писать отрицательные числа:
\x -> (x-) :: Num a => a -> a -> a -- equivalent to \x -> (-) x
\x -> (-x) :: Num a => a -> a -- equivalent to \x -> negate x
Если вы хотите кратко написать (\y -> y - x)
, ты можешь использовать subtract
:
\x -> subtract x :: Num a => a -> a -> a -- equivalent to \x -> flip (-) x
($ 0)
≡ (\x -> x $ 0)
≡ (\x -> ($) x 0)
Если ($) :: (a -> b) -> a -> b)
и мы применили второй аргумент, как (\x -> ($) x 0)
у нас есть :: Num a => (a -> b) -> b
Вы путаете запись инфиксного оператора с функцией.
> :t (($) (+1))
(($) (+1)) :: Num b => b -> b
Вот некоторые формы выражений с $
для лучшего понимания:
a $ b => ($) ab
($ b) => flip ($) b => (\ ba -> ($) ab) b => \ a -> ($) ab
(a $) => ($) a => \ b -> ($) ab
Также обратите внимание, что в синтаксисе Haskell буквенно-цифровые имена отличаются от знаков препинания.
Буквенно-цифровая функция foo1 a b
по умолчанию является префиксом и становится инфиксным, если вы добавляете обратные ссылки: a `foo` b
,
Функция с пунктуацией $
или же <*>
по умолчанию является инфиксным и становится префиксным, если вы добавляете скобки ($)
или же (<*>)
, Это просто синтаксический сахар для программиста, знакомого с латинским алфавитом; это произвольное, но полезное различие между буквенно-цифровыми именами и знаками препинания.
Оба вида функций являются просто функциями, у них нет специальных семантических правил, которые мы имеем для "операторов" в C++ или Java. Это просто правила синтаксиса вокруг префикса / инфикса и обратных кавычек / скобок, которые различаются между функциями с пунктуацией и функциями с буквенно-цифровыми именами.