cae*_*eus 2 syntax lambda haskell anonymous-function operator-precedence
在 Haskell 中,以下表达式:
a \b -> c $ d
Run Code Online (Sandbox Code Playgroud)
或者是
• 无效的
• (a (\b ->c)) d
• (a (\b -> (c d))
为什么?
它在 vanilla Haskell 中是无效的,因为 lambda 不能直接用作函数的参数而没有中间运算符。正确的版本需要使用$或括号:
a \b -> c $ d
a $ \b -> c $ d
a ( \b -> c $ d )
Run Code Online (Sandbox Code Playgroud)
但是,没有根本原因不允许 lambda(或case、if、do、 或let表达式)出现在那里,因为它没有歧义。所述BlockArguments延伸部(在加入GHC 8.6.1)允许这些语法结构直接作为函数的参数。启用该功能后,它的解析与上述相同,如下所示:
(a (\b -> (c $ d))
Run Code Online (Sandbox Code Playgroud)
这样做的原因不是解析为*(a (\b -> c)) d是一个lambda的范围中定义的Haskell报告§3为尽量向右地(强调)延伸:
关于lambda 抽象、let 表达式和条件的范围,语法是不明确的。歧义由元规则解决,即这些结构中的每一个都尽可能向右延伸。
换句话说,可以认为 lambda 的主体比任何其他表达式具有更低的优先级。这个符号直接从 lambda 演算借用,其中a ? 乙。c d与 ( a (? b . ( c d ))) 相同。
请注意,我没有删除$此处:这两个表达式是不同的,即使它们的计算结果相同:
f x
f $ x
Run Code Online (Sandbox Code Playgroud)
第一个是函数f对参数的应用x;第二个是运算符($)对参数fand 的应用x。像所有中缀运算符一样,它是普通前缀函数调用的语法糖:
($) f x
Run Code Online (Sandbox Code Playgroud)
($)被定义为具有最低运算符优先级的右结合运算符(即x $ y $ z= x $ (y $ z),而不是* (x $ y) $ z),声明infixr 0在Prelude. 您可以在 GHCi 中使用:info(或:i) 命令查看有关运算符的信息:
> :info $
($) :: (a -> b) -> a -> b -- Defined in ‘GHC.Base’
infixr 0 $
Run Code Online (Sandbox Code Playgroud)