Haskell operator vs function precedence

岁酱吖の 提交于 2019-11-27 12:35:54

You are correct. This rule is part of the Haskell syntax defined by the Haskell Report. In particular note in Section 3, Expressions, that the argument to function application (an fexp) must be an aexp. An aexp allows operators as part of sections, and also within a parenthesized expression, but not bare operators.

In map foo $ xs, the Haskell syntax means that this is parsed as two expressions which are applied to the binary operator $. As sepp2k notes, the syntax (map foo $) is a left section and has a different meaning.

I have to confess I've never thought much about this and actually had to look it up in the Report to see why operators have the behavior they do.

Don Stewart

Firstly, application (whitespace) is the highest precedence "operator".

Secondly, in Haskell, there's really no distinction between operators and functions, other than that operators are infix by default, while functions aren't. You can convert functions to infix with backticks

2 `f` x

and convert operators to prefix with parens:

(+) 2 3

So, your question is a bit confused.

Now, specific functions and operators will have declared precedence, which you can find in GHCi with ":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 +

Showing both precedence and associativity.

In addition to the information provided by other answers already, note that different operators can have different precedences over other operators, as well as being left-/right- or non-associative. You can find these properties for the Prelude operators in the Haskell 98 Report fixity section.

+--------+----------------------+-----------------------+-------------------+
| 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`      |
+--------+----------------------+-----------------------+-------------------+

Any operator lacking a fixity declaration is assumed to be left associative with precedence 9.

Remember, function application has highest precedence (think of precedence 10 compared to the other precedences in the table) [1].

The difference is that infix operators get placed between their arguments, so this

list = map foo $ xs

can be rewritten in prefix form as

list = ($) (map foo) xs

which, by the definition of the $ operator, is simply

list = (map foo) xs

Operators can be passed as function arguments if you surround them with parenthesis (i.e. map foo ($) xs, which would indeed be passed as (map foo ($)) xs). However if you do not surround them with parenthesis, you are correct that they cannot be passed as argument (or assigned to variables).

Also note that the syntax (someValue $) (where $ could be any operator) actually means something different: it is equivalent to \x -> someValue $ x, i.e. it partially applies the operator to its left operand (which in case of $ is a noop of course). Likewise ($ x) partially applies the operator to the right operand. So map ($ x) [f, g, h] would evaluate to [f x, g x, h x].

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!