Приложение оператора доллара Haskell

У меня проблемы с пониманием того, как приложение-функция работает с каррированием в haskell. Если у меня есть следующая функция:

($) :: (a -> b) -> a -> b

Я понимаю, что для частичного применения этой функции мне нужно предоставить функцию (a -> b) (первый аргумент $).

Почему тогда можно сначала применить значение (т.е. обратные аргументы)?

($ 0) :: Num a => (a -> b) -> b

Что мне здесь не хватает?


person Rumca    schedule 18.01.2013    source источник


Ответы (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
person Community    schedule 18.01.2013
comment
Спасибо, это объясняет, почему это работает именно так. Являются ли эти определения особенностями языка или их можно найти где-то в источниках? - person Rumca; 19.01.2013
comment
@Rumca Не совсем в исходнике, (x $) и ($ x) - это разделы, и их описание можно найти в отчет Haskell за 2010 год в разделах раздел. - person Davorak; 19.01.2013
comment
Язык описан в отчете Haskell 2010. - person Luis Casillas; 19.01.2013
comment
Синтаксис раздела (x $) = ... не является определением в смысле определения функции, он является частью синтаксиса языка и применяется ко всем функциям, а не только к $. (Конечно, имеет смысл только для функций, которые могут принимать ›=2 аргумента.) - person misterbee; 28.12.2013

($ 0)(\x -> x $ 0)(\x -> ($) x 0)

Если ($) :: (a -> b) -> a -> b) и мы применили второй аргумент, такой как (\x -> ($) x 0), мы имеем :: Num a => (a -> b) -> b

person ДМИТРИЙ МАЛИКОВ    schedule 18.01.2013

Вы путаете инфиксную запись оператора с функцией.

> :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

person Satvik    schedule 18.01.2013
comment
-1 Даже как человек, твердо понимающий, о чем этот вопрос и какова его аргументация, мне этот ответ кажется непонятным. Как может кто-то, кто не очень хорошо знает Haskell, понять это? Никакого объяснения, в чем разница между операторами и функциями. $ b => flip ($) b => \a -> ($) a b даже недопустимый синтаксис. (Редактировать: хорошо, было бы -1, если бы у меня было немного больше репутации.) - person John Tyree; 20.01.2013

Также обратите внимание, что в синтаксисе Haskell буквенно-цифровые имена отличаются от имен пунктуации.

Буквенно-цифровая функция foo1 a b является префиксом по умолчанию и становится инфиксом, если вы добавляете обратные кавычки: a `foo` b.

Функция с пунктуационным именем, например $ или <*>, по умолчанию является инфиксной и становится префиксной, если вы добавите круглые скобки ($) или (<*>). Это просто синтаксический сахар для программиста, знакомого с латиницей; это произвольное, но полезное различие между буквенно-цифровыми именами и именами знаков препинания.

Оба типа функций — это просто функции, они не имеют специальных семантических правил, которые мы имеем для «операторов» в C++ или Java. Это просто правила синтаксиса вокруг префикса/инфикса и обратных кавычек/круглых скобок, которые различаются между функциями с именами с пунктуационными именами и функциями с буквенно-цифровыми именами.

person misterbee    schedule 28.12.2013