Подтвердить что ты не робот

Оператор Haskell против приоритета функции

Я пытаюсь проверить что-то для себя о приоритете оператора и функции в Haskell. Например, следующий код

list = map foo $ xs

можно переписать как

list = (map foo) $ (xs)

и в конечном итоге будет

list = map foo xs

Мой вопрос был, почему первая формулировка не была переписана как

list = (map foo $) xs

поскольку приоритет функции всегда выше приоритета оператора, но я думаю, что нашел ответ: операторы просто не могут быть аргументами функций (за исключением, конечно, если вы окружите их круглыми скобками). Это правильно? Если это так, мне показалось странным, что в RWH не упоминается об этом механизме/правилах или не узнаете вас в Haskell или в любом другом месте, которое я искал. Поэтому, если вы знаете место, где указано правило, просим связаться с ним.

- отредактируйте: Спасибо за ваши быстрые ответы. Я думаю, что моя путаница возникла из-за того, что оператор-литерал каким-то образом оценит что-то, что может быть использовано функцией в качестве аргумента. Это помогло мне вспомнить, что оператор инфикса можно механически перевести на префиксные функции. Выполнение этой первой формулы дает

($) (map foo) (xs)

где нет сомнений в том, что ($) является потребляющей функцией, и поскольку эти две формулы эквивалентны, то литерал $в первой формулировке не может быть использован картой.

4b9b3361

Ответ 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].