Haskell中运算符和匿名函数的优先级对比

3
在Haskell中,下面的表达式:
 a \b -> c $ d

以下内容可能是:

• 无效的

(a (\b ->c)) d

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

为什么呢?

1个回答

7

在原始的 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 报告 §3中被定义并扩展到尽可能右侧(强调部分已添加):

关于 lambda 抽象、let 表达式和条件语句的范围,语法存在歧义。通过元规则予以解决,每个构造都尽可能向右侧扩展。

换句话说,lambda体可以被认为具有低于任何其他表达式的优先级。该符号直接借鉴自λ演算,其中 a λb. c d与 (ab. (c d))) 相同。
请注意,这里没有删除$:尽管它们求值结果相同,但这两个表达式是不同的。
f x
f $ x

第一个是将函数f应用于参数x; 第二个是将运算符($ )应用于参数f和x。和所有中缀运算符一样,它是正常前缀函数调用的语法糖:
($) f x

($)被定义为一个右结合运算符(即x $ y $ z等价于x $ (y $ z),而不是(x $ y) $ z),并且它的优先级最低,其在Prelude中有声明infixr 0。你可以通过GHCi中的:info:i命令查看有关运算符的信息:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接