Я пытаюсь проверить что-то для меня об операторе и функциональном приоритете в Haskell. Например, следующий код
list = map foo $ xs
может быть переписан как
list = (map foo) $ (xs)
и в конечном счете будет
list = map foo xs
Мой вопрос раньше был, почему первая формулировка не будет переписана как
list = (map foo $) xs
так как функциональный приоритет всегда выше, чем приоритет оператора, но я думаю, что нашел ответ: операторам просто не позволяют быть аргументами функций (кроме, конечно, при окружении их круглыми скобками). Действительно ли это правильно? Если так, я нахожу это нечетным, что нет никакого упоминания об этом механике/правиле в RWH, или Изучите Вас Haskell или любое из других мест, которые я искал. Таким образом, если Вы знаете место, где правило указано, свяжитесь с ним.
- редактирование: Спасибо за Ваши быстрые ответы. Я думаю, что мой беспорядок прибыл из размышления, что литерал оператора так или иначе оценит к чему-то, которое могло быть использовано функцией как аргумент. Это помогло мне помнить, что инфиксный оператор может быть механически переведен в функции префикса. Выполнение этого к первым урожаям формулировки
($) (map foo) (xs)
где нет сомнения, что ($) функция потребления, и так как эти две формулировки эквивалентны, затем литерал $ в первой формулировке не может быть использован картой.
Вы правы. Это правило является частью синтаксиса Haskell, определенного в Haskell Report . В частности, обратите внимание в Разделе 3, Выражения, что аргумент приложения функции ( fexp
) должен быть aexp
. Aexp позволяет использовать операторы как часть разделов, а также в выражении в скобках, но не только операторы.
В map foo $ xs
синтаксис Haskell означает, что он анализируется как два выражения, которые применяются к бинарному оператору $
. Как отмечает sepp2k, синтаксис (map foo $)
является левым разделом и имеет другое значение.
Должен признаться, я никогда особо не задумывался об этом, и мне пришлось поискать это в Отчете, чтобы понять, почему операторы ведут себя так, как они.
Во-первых, приложение (пробел) является «оператором» с наивысшим приоритетом.
Во-вторых, в Haskell нет различий между операторами и функциями, кроме того, что операторы по умолчанию являются инфиксными, а функции - нет. Вы можете преобразовывать функции в инфиксные с помощью обратных кавычек
2 `f` x
и преобразовывать операторы в префикс с скобками:
(+) 2 3
Итак, ваш вопрос немного сбивает с толку.
Теперь для определенных функций и операторов будет объявлен приоритет, который вы можете найти в GHCi с помощью ": info":
Prelude> :info ($)
($) :: (a -> b) -> a -> b -- Defined in GHC.Base
infixr 0 $
Prelude> :info (+)
class (Eq a, Show a) => Num a where
(+) :: a -> a -> a
infixl 6 +
Отображение приоритета и ассоциативности.
Операторы могут быть переданы как аргументы функции, если вы заключите их в круглые скобки (например, map foo ($) xs
, который действительно будет передан как (map foo ($)) xs
). Однако, если вы не заключите их в круглые скобки, вы правы, что они не могут быть переданы в качестве аргумента (или присвоены переменным).
Также обратите внимание, что синтаксис (someValue $)
(где $
может быть любым оператором) на самом деле означает нечто иное: он эквивалентен \ x -> someValue $ x
, т. е. он частично применяет оператор к своему левому операнду (что в случае $
, конечно, не работает). Аналогично ($ x)
частично применяет оператор к правому операнду. Итак, map ($ x) [f, g, h]
будет оценивать как [f x, g x, h x]
.
Разница в том, что инфиксные операторы помещаются между своими аргументами, поэтому этот
list = map foo $ xs
можно переписать в форме префикса как
list = ($) (map foo) xs
, что, по определению оператора $, просто
list = (map foo) xs