【发布时间】:2020-09-02 02:47:36
【问题描述】:
在 Haskell 中如下表达式:
a \b -> c $ d
要么是
• 无效
•(a (\b ->c)) d
•(a (\b -> (c d))
为什么?
【问题讨论】:
标签: haskell lambda syntax anonymous-function operator-precedence
在 Haskell 中如下表达式:
a \b -> c $ d
要么是
• 无效
•(a (\b ->c)) d
•(a (\b -> (c d))
为什么?
【问题讨论】:
标签: haskell lambda syntax anonymous-function operator-precedence
它在 vanilla 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 Report §3 中定义为尽可能向右延伸(添加了重点):
关于lambda 抽象、let 表达式和条件句的范围,语法是模棱两可的。通过这些结构中的每一个都尽可能向右延伸的元规则来解决歧义。
换句话说,可以认为 lambda 的主体具有比任何其他表达式更低的优先级。这个符号直接从 lambda 演算中借用,其中 a λb。 c d 等同于 (a (λb. (c d)))。
请注意,我没有在这里删除$:这两个表达式是不同的,即使它们的计算结果相同:
f x
f $ x
第一个是函数f对参数x的应用;第二个是将运算符($) 应用于参数f 和x。像所有中缀运算符一样,它是普通前缀函数调用的语法糖:
($) f x
($) 定义为具有最低运算符优先级的右关联运算符(即x $ y $ z = x $ (y $ z),not *(x $ y) $ z),其中声明infixr 0 Prelude。您可以在 GHCi 中使用:info(或:i)命令查看有关运算符的信息:
> :info $
($) :: (a -> b) -> a -> b -- Defined in ‘GHC.Base’
infixr 0 $
【讨论】: