Haskell 中的运算符与匿名函数优先级

Operator vs Anonymous function precedence in Haskell

在Haskell下面的表达式中:

 a \b -> c $ d

• 无效

(a (\b ->c)) d

(a (\b -> (c d))

为什么?

它在 vanilla Haskell 中是无效的,因为 lambda 不能直接用作函数的参数而没有中间运算符。正确的版本需要使用$或者括号:

a   \b -> c $ d
a $ \b -> c $ d
a ( \b -> c $ d )

但是,没有根本原因不允许 lambda(或 caseifdolet 表达式),因为这不是模棱两可的。 BlockArguments 扩展(在 GHC 8.6.1 中添加)允许这些语法结构直接作为函数的参数。启用后,它解析与上面相同,如:

(a (\b -> (c $ d))

解析为*(a (\b -> c)) d的原因是lambda的范围在Haskell Report §3中定义为向右延伸至可能(强调):

The grammar is ambiguous regarding the extent of lambda abstractions, let expressions, and conditionals. The ambiguity is resolved by the meta-rule that each of these constructs extends as far to the right as possible.

换句话说,可以认为 lambda 的主体比任何其他表达式具有 较低 的优先级。这个符号是直接从 lambda 演算中借用的,其中 a λbc d 等同于 (ab. (c d))).

请注意,我没有在此处删除 $:这两个表达式是不同的,即使它们的计算结果相同:

f x
f $ x

第一个是函数f对参数x的应用;第二个是运算符 ($) 对参数 fx 的应用。与所有中缀运算符一样,它是普通前缀函数调用的语法糖:

($) f x

($) 定义为 right-associative 运算符(即 x $ y $ z = x $ (y $ z)not *(x $ y) $ z) 具有最低的运算符优先级,在 Prelude 中声明 infixr 0。您可以在 GHCi 中使用 :info(或 :i)命令查看有关操作员的信息:

> :info $
($) :: (a -> b) -> a -> b   -- Defined in ‘GHC.Base’
infixr 0 $