在Haskell中,下面的表达式:
a \b -> c $ d
以下内容可能是:
• 无效的
• (a (\b ->c)) d
• (a (\b -> (c d))
为什么呢?
a \b -> c $ d
以下内容可能是:
• 无效的
• (a (\b ->c)) d
• (a (\b -> (c d))
为什么呢?
在原始的 Haskell 中这是无效的,因为一个 lambda 函数不能直接作为参数传递给另一个函数。正确的版本需要使用 $
或圆括号:
a \b -> c $ d
a $ \b -> c $ d
a ( \b -> c $ d )
然而,并没有根本性的理由禁止在那里使用lambda(或case
,if
,do
或let
表达式),因为它不会产生歧义。 BlockArguments
扩展(在GHC 8.6.1中添加)允许这些语法结构直接作为参数传递给函数。启用此扩展后,它的解析结果与上述相同,即:
(a (\b -> (c $ d))
(a (\b -> c)) d
的原因是,lambda的作用域在 Haskell 报告 §3中被定义并扩展到尽可能右侧(强调部分已添加):
换句话说,lambda体可以被认为具有低于任何其他表达式的优先级。该符号直接借鉴自λ演算,其中 a λb. c d与 (a (λb. (c d))) 相同。关于 lambda 抽象、let 表达式和条件语句的范围,语法存在歧义。通过元规则予以解决,每个构造都尽可能向右侧扩展。
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 $