Оператор Haskell против приоритета функции - PullRequest
38 голосов
/ 27 июня 2010

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

list = map foo $ xs

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

list = (map foo) $ (xs)

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

list = map foo xs

Раньше у меня был вопрос, почему первая формулировка не будет переписана как

list = (map foo $) xs

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

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

($) (map foo) (xs)

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

Ответы [ 5 ]

36 голосов
/ 27 июня 2010

Во-первых, приложение (пробел) является «оператором» наивысшего приоритета.

Во-вторых, в 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 +

Отображение как приоритета, так и ассоциативности.

27 голосов
/ 27 июня 2010

Вы правы.Это правило является частью синтаксиса Haskell, определенного в отчете Haskell .В частности, обратите внимание, что в Разделе 3, Выражения, аргумент приложения функции (fexp) должен быть aexp.Aexp позволяет использовать операторы как часть разделов, а также в выражении в скобках, но не как пустые операторы.

В map foo $ xs синтаксис Haskell означает, что он анализируется как два выражения, которые применяются к бинарному оператору.$.Как отмечает sepp2k, синтаксис (map foo $) является левым разделом и имеет другое значение.

Я должен признаться, я никогда не задумывался об этом, и на самом деле мне пришлось искать его в отчете, чтобы понять, почемуоператоры имеют поведение, которое они делают.

17 голосов
/ 17 мая 2015

В дополнение к информации, уже предоставленной другими ответами, обратите внимание, что разные операторы могут иметь разные приоритеты по сравнению с другими операторами, а также быть левыми / правыми или неассоциативными. Вы можете найти эти свойства для операторов Prelude в разделе исправления Haskell 98 Report .

+--------+----------------------+-----------------------+-------------------+
| 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] .

11 голосов
/ 27 июня 2010

Разница в том, что инфиксные операторы размещаются между своими аргументами, поэтому это

list = map foo $ xs

может быть переписано в виде префикса как

list = ($) (map foo) xs

который, по определению оператора $, просто

list = (map foo) xs
10 голосов
/ 27 июня 2010

Операторы могут быть переданы в качестве аргументов функции, если вы заключите их в круглые скобки (то есть map foo ($) xs, что в действительности будет передано как (map foo ($)) xs). Однако, если вы не заключаете их в круглые скобки, вы правы, что они не могут быть переданы в качестве аргумента (или назначены переменным).

Также обратите внимание, что синтаксис (someValue $) (где $ может быть любым оператором) на самом деле означает что-то другое: оно эквивалентно \x -> someValue $ x, т.е. оно частично применяет оператор к своему левому операнду (который в случае $ это просто шумиха). Аналогично ($ x) частично применяет оператор к правому операнду. Так что map ($ x) [f, g, h] будет оцениваться как [f x, g x, h x].

...