Haskell 运算符与函数优先级

发布于 2024-09-07 16:49:57 字数 690 浏览 1 评论 0原文

我正在尝试为自己验证一些关于 Haskell 中运算符和函数优先级的内容。例如,以下代码

list = map foo $ xs

可以重写为

list = (map foo) $ (xs)

并且最终将是

list = map foo xs

我过去的问题是,为什么第一个公式不会被重写为

list = (map foo $) xs

因为函数优先级始终高于运算符优先级,但我认为我已经找到了答案:运算符根本不允许作为函数的参数(当然,如果你用括号将它们括起来的话除外)。这是对的吗?如果是这样,我觉得很奇怪,在 RWH 或 Learn you a Haskell 或我搜索过的任何其他地方都没有提到这个机制/规则。因此,如果您知道某个地方规定了该规则,请链接到该地方。

- 编辑:感谢您的快速回答。我认为我的困惑来自于认为运算符文字会以某种方式评估为某些内容,该内容可能会被函数作为参数消耗。它帮助我记住,中缀运算符可以机械地转换为前缀函数。对第一个公式执行此操作,

($) (map foo) (xs)

毫无疑问 ($) 是消耗函数,并且由于两个公式是等效的,因此第一个公式中的 $ 文字不能被 map 消耗。

I am trying to verify something for myself about operator and function precedence in Haskell. For instance, the following code

list = map foo $ xs

can be rewritten as

list = (map foo) $ (xs)

and will eventually be

list = map foo xs

My question used to be, why the first formulation would not be rewritten as

list = (map foo $) xs

since function precedence is always higher than operator precedence, but I think that I have found the answer: operators are simply not allowed to be arguments of functions (except of course, if you surround them with parentheses). Is this right? If so, I find it odd, that there is no mention of this mechanic/rule in RWH or Learn you a Haskell, or any of the other places that I have searched. So if you know a place, where the rule is stated, please link to it.

-- edit: Thank you for your quick answers. I think my confusion came from thinking that an operator literal would somehow evaluate to something, that could get consumed by a function as an argument. It helped me to remember, that an infix operator can be mechanically translated to a prefix functions. Doing this to the first formulation yields

($) (map foo) (xs)

where there is no doubt that ($) is the consuming function, and since the two formulations are equivalent, then the $ literal in the first formulation cannot be consumed by map.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

情未る 2024-09-14 16:50:18

如果用括号括起来,运算符可以作为函数参数传递(即 map foo ($) xs,它确实会作为 (map foo ($)) xs 传递)。但是,如果您没有用括号将它们括起来,则它们不能作为参数传递(或分配给变量),这是正确的。

另请注意,语法 (someValue $) (其中 $ 可以是任何运算符)实际上意味着不同的东西:它相当于 \x ->; someValue $ x,即它将运算符部分应用于其左操作数(在 $ 的情况下当然是一个 noop)。同样,($ x) 部分地将运算符应用于右侧操作数。因此,map ($ x) [f, g, h] 将计算为 [fx, gx, hx]

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

怀念你的温柔 2024-09-14 16:50:15

不同之处在于中缀运算符放置在它们的参数之间,因此

list = map foo $ xs

可以以前缀形式重写

list = ($) (map foo) xs

,根据 $ 运算符的定义,这只是

list = (map foo) xs

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
萌梦深 2024-09-14 16:50:13

除了其他答案已经提供的信息之外,请注意,不同的运算符相对于其他运算符可以具有不同的优先级,以及左/右或非关联。
您可以在 Haskell 98 报告中找到 Prelude 运算符的这些属性固定部分

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

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

相守太难 2024-09-14 16:50:10

你是对的。此规则是 Haskell 报告 定义的 Haskell 语法的一部分。特别要注意的是,在第 3 节“表达式”中,函数应用程序的参数(fexp)必须是 aexp。 aexp 允许运算符作为节的一部分,也可以在括号表达式内,但不允许纯运算符。

map foo $ xs 中,Haskell 语法意味着它被解析为两个应用于二元运算符 $ 的表达式。正如 sepp2k 所指出的,语法 (map foo $) 是左侧部分,具有不同的含义。

我必须承认,我从来没有认真考虑过这个问题,实际上我必须在报告中查找一下,才能了解运营商为何会有这样的行为。

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.

千鲤 2024-09-14 16:50:07

首先,应用程序(空格)是优先级最高的“运算符”。

其次,在 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 +

显示优先级和关联性。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文