Приложение оператора Haskell dollar
У меня возникли проблемы с пониманием того, как приложение-приложение работает с currying в haskell.
Если у меня есть следующая функция:
($) :: (a -> b) -> a -> b
Я понимаю, что для частичного применения этой функции мне нужно предоставить функцию (a -> b)
($
первый аргумент).
Почему тогда можно сначала применить значение (т.е. обратные аргументы)?
($ 0) :: Num a => (a -> b) -> b
Что мне здесь не хватает?
Ответы
Ответ 1
($)
является оператором. В 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
Ответ 2
($ 0)
≡ (\x -> x $ 0)
≡ (\x -> ($) x 0)
Если ($) :: (a -> b) -> a -> b)
и мы применили второй аргумент, например (\x -> ($) x 0)
, имеем :: Num a => (a -> b) -> b
Ответ 3
Вы вводите в заблуждение инфиксную нотацию оператора с функцией.
> :t (($) (+1))
(($) (+1)) :: Num b => b -> b
Вот несколько форм выражений с $
, для лучшего понимания:
a $b = > ($) a b
($ b) = > flip ($) b = > (\ b a → ($) a b) b = > \a → ($) a b
(a $) = > ($) a = > \b → ($) a b
Ответ 4
Обратите внимание также, что в синтаксисе Haskell буквенно-цифровые имена отличаются от имен пунктуации.
Алфавитно-цифровая функция foo1 a b
по умолчанию является префиксом и становится инфиксной, если вы добавляете обратные ссылки: a `foo` b
.
Функция, обозначенная пунктуацией типа $
или <*>
, по умолчанию является инфиксной и становится префиксом, если вы добавляете круглые скобки ($)
или (<*>)
. Это просто синтаксический сахар для программиста, знакомого с латинским алфавитом; это произвольное, но полезное различие между буквенно-цифровыми именами и именами пунктуации.
Оба вида функций - это просто функции, у них нет специальных семантических правил, которые мы имеем для "операторов" на С++ или Java. Это просто правила синтаксиса вокруг префикса/инфикса и обратных циклов/круглых скобок, которые различаются между функциями с пунктуацией и функциями с буквенно-цифровым именем.