Оператор Haskell против приоритета функции
Я пытаюсь проверить что-то для себя о приоритете оператора и функции в Haskell. Например, следующий код
list = map foo $ xs
можно переписать как
list = (map foo) $ (xs)
и в конечном итоге будет
list = map foo xs
Мой вопрос был, почему первая формулировка не была переписана как
list = (map foo $) xs
поскольку приоритет функции всегда выше приоритета оператора, но я думаю, что нашел ответ: операторы просто не могут быть аргументами функций (за исключением, конечно, если вы окружите их круглыми скобками). Это правильно? Если это так, мне показалось странным, что в RWH не упоминается об этом механизме/правилах или не узнаете вас в Haskell или в любом другом месте, которое я искал. Поэтому, если вы знаете место, где указано правило, просим связаться с ним.
- отредактируйте: Спасибо за ваши быстрые ответы. Я думаю, что моя путаница возникла из-за того, что оператор-литерал каким-то образом оценит что-то, что может быть использовано функцией в качестве аргумента. Это помогло мне вспомнить, что оператор инфикса можно механически перевести на префиксные функции. Выполнение этой первой формулы дает
($) (map foo) (xs)
где нет сомнений в том, что ($) является потребляющей функцией, и поскольку эти две формулы эквивалентны, то литерал $в первой формулировке не может быть использован картой.
Ответы
Ответ 1
Вы правы. Это правило является частью синтаксиса Haskell, определяемого Haskell Report. В частности, обратите внимание в разделе 3 "Выражения", что аргумент функции приложения (a fexp
) должен быть aexp
. Aexp позволяет операторам как часть разделов, так и внутри выражения в скобках, но не голые операторы.
В map foo $ xs
синтаксис Haskell означает, что это анализируется как два выражения, которые применяются к двоичному оператору $
. Как отмечает sepp2k, синтаксис (map foo $)
является левым разделом и имеет другое значение.
Я должен признаться, что я никогда не думал об этом и на самом деле должен был найти его в отчете, чтобы понять, почему у операторов есть поведение, которое они выполняют.
Ответ 2
Во-первых, приложение (пробел) является оператором наивысшего приоритета.
Во-вторых, в Haskell нет никакого различия между операторами и функциями, кроме того, что по умолчанию операторы infix, а функции - нет. Вы можете преобразовывать функции в инфикс с обратными окнами
2 `f` x
и преобразовать операторы в префикс с помощью parens:
(+) 2 3
Итак, ваш вопрос немного смущен.
Теперь конкретные функции и операторы объявят приоритет, который вы можете найти в GHCi с помощью ": info":
Prelude> :info ($)
($) :: (a -> b) -> a -> b -- Defined in GHC.Base
infixr 0 $
class (Eq a, Show a) => Num a where
(+) :: a -> a -> a
infixl 6 +
Показывает как приоритет, так и ассоциативность.
Ответ 3
Различие заключается в том, что операторы infix устанавливаются между их аргументами, поэтому этот
list = map foo $ xs
можно переписать в префиксной форме как
list = ($) (map foo) xs
который по определению оператора $просто
list = (map foo) xs
Ответ 4
Операторы могут передаваться как аргументы функции, если вы окружите их скобкой (т.е. map foo ($) xs
, которая действительно будет передана как (map foo ($)) xs
). Однако, если вы не окружите их скобкой, вы правы, что их нельзя передать в качестве аргумента (или назначить переменным).
Также обратите внимание, что синтаксис (someValue $)
(где $
может быть любым оператором) на самом деле означает что-то другое: он эквивалентен \x -> someValue $ x
, то есть он частично применяет оператор к его левому операнду (который в случае $
- конечно, конечно). Аналогично ($ x)
частично применяет оператор к правому операнду. Итак, map ($ x) [f, g, h]
будет оценивать значение [f x, g x, h x]
.
Ответ 5
В дополнение к информации, предоставленной другими ответами, обратите внимание, что разные операторы могут иметь разные приоритеты над другими операторами, а также быть левыми/правомерными или неассоциативными.
Эти свойства для операторов Prelude
можно найти в разделе Haskell 98.
+--------+----------------------+-----------------------+-------------------+
| Prec- | Left associative | Non-associative | Right associative |
| edence | operators | operators | operators |
+--------+----------------------+-----------------------+-------------------+
| 9 | !! | | . |
| 8 | | | ^, ^^, ** |
| 7 | *, /, `div`, | | |
| | `mod`, `rem`, `quot` | | |
| 6 | +, - | | |
| 5 | | | :, ++ |
| 4 | | ==, /=, <, <=, >, >=, | |
| | | `elem`, `notElem` | |
| 3 | | | && |
| 2 | | | || |
| 1 | >>, >>= | | |
| 0 | | | $, $!, `seq` |
+--------+----------------------+-----------------------+-------------------+
Предполагается, что любой оператор, у которого отсутствует объявление фиксации, остается ассоциативным с приоритетом 9.
Помните, что приложение-приложение имеет самый высокий приоритет (подумайте о приоритете 10
по сравнению с другими приоритетами в таблице) [1].