为什么不能通过部分上的方程定义中缀运算符?
Why is it not possible to define an infix operator via an equation on a section?
Hutton 的“Programming in Haskell”第一版指出,串联运算符 ++
可以定义为:
(++ ys) = foldr (:) ys
这符合逻辑。
我从来没有在其中的一个部分(在本例中 (++ ys)
)看到一个由方程定义的运算符,所以我自己试了一下:
(@@) :: [a] -> [a] -> [a]
(@@ ys) = foldr (:) ys
然而,这并没有编译,突出了 (@@ ys)
中的语法错误。
这从来都不是一个功能,还是在某个时候被删除了?如果是,为什么?
我知道我可以把上面的写成:
xs @@ ys = foldr (:) ys xs
但我觉得无点样式更优雅。
这会导致一些细微的不一致。尽管我们倾向于认为 curried 和 flipped 以及 uncurried 函数只是编写同一事物的不同方式,但当涉及到实际的评估策略时,这并不完全正确。考虑
(#>) :: Integer -> Integer -> Integer
(#>) n = let p = {- the `n`-th prime number -} `mod` 74
in (p+)
索引素数的成本很高。如果你写类似
map ((2^43) #>) [100 .. 150]
那么第243个质数只需要计算一次。相比之下,如果我定义
(<#) :: Integer -> Integer -> Integer
(<#) = flip foo
然后写 map (<# (2^43)) [100 .. 150]
会一遍又一遍地计算质数,因为 Haskell 不支持对第二个参数部分应用函数。
根据 flip foo
定义,这并不奇怪,但如果我可以直接将翻转形式定义为
(<#n) = let p = {- the `n`-th prime number -} `mod` 74
in (p+)
那么可以合理地预期 map (<# (2^43))
确实 共享素数计算,但要支持 Haskell 的部分评估语义需要跟踪比他们目前提供的信息更多,如果我们希望它可靠地工作,那么它可能会带来一些其他缺点。
我认为对于 =
绑定的 lhs 上允许的句法形式有多复杂,我认为有一个更简单的解释。
请始终 post 您收到的错误消息,不要只是说“突出显示语法错误”。该消息对您来说可能意义不大,但在这种情况下它给出了一个强烈的提示:
(@@ ys) = ...
===> error: Parse error in pattern: @@ys
(xs @@) = ...
===> error: Expression syntax in pattern: xs @@
“有规律”啊哈!也就是说,lhs 可能是一种句法模式。此外,无论您介绍什么,都可能没有签名声明;即使有,编译器也必须根据签名检查你的等式,所以它不能假设你所介绍的内容的真实性。考虑这些有效方程
z = 42 -- z counts as a pattern
Just z = {- long and complex expr returning a Maybe, binds z at module-wide scope -}
(Just z) = {- same same, binds z at module-wide scope -}
foo x = ... -- foo gets module-wide scope but not x
(foo x) = ... -- same
bar x y = ... -- bar gets module-wide scope but not x, y
(bar x) y = ... -- same
(x ## y) z = ... -- accepted, introduces triadic operator ##
x ## y z = -- rejected error: Parse error in pattern: y
(x ##) y = -- rejected error: Expression syntax in pattern: x ##
(## y) z = -- rejected error: Parse error in pattern: ##y
语言报告(第 4.4.3 节函数和模式绑定)有
decl -> (funlhs | pat) rhs
funlhs -> var apat { apat }
| pat varop pat
| ( funlhs ) apat { apat }
因此 lhs 不是可以出现表达式语法(包括运算符部分)的地方。另请参阅第 4.4.3.1 节末尾的丑陋细节,将 lhs 运算符语法与中缀数据构造函数结合使用呃!
The last sentence here 还确认您不能在 lhs 上使用运算符部分。
Hutton 的“Programming in Haskell”第一版指出,串联运算符 ++
可以定义为:
(++ ys) = foldr (:) ys
这符合逻辑。
我从来没有在其中的一个部分(在本例中 (++ ys)
)看到一个由方程定义的运算符,所以我自己试了一下:
(@@) :: [a] -> [a] -> [a]
(@@ ys) = foldr (:) ys
然而,这并没有编译,突出了 (@@ ys)
中的语法错误。
这从来都不是一个功能,还是在某个时候被删除了?如果是,为什么?
我知道我可以把上面的写成:
xs @@ ys = foldr (:) ys xs
但我觉得无点样式更优雅。
这会导致一些细微的不一致。尽管我们倾向于认为 curried 和 flipped 以及 uncurried 函数只是编写同一事物的不同方式,但当涉及到实际的评估策略时,这并不完全正确。考虑
(#>) :: Integer -> Integer -> Integer
(#>) n = let p = {- the `n`-th prime number -} `mod` 74
in (p+)
索引素数的成本很高。如果你写类似
map ((2^43) #>) [100 .. 150]
那么第243个质数只需要计算一次。相比之下,如果我定义
(<#) :: Integer -> Integer -> Integer
(<#) = flip foo
然后写 map (<# (2^43)) [100 .. 150]
会一遍又一遍地计算质数,因为 Haskell 不支持对第二个参数部分应用函数。
根据 flip foo
定义,这并不奇怪,但如果我可以直接将翻转形式定义为
(<#n) = let p = {- the `n`-th prime number -} `mod` 74
in (p+)
那么可以合理地预期 map (<# (2^43))
确实 共享素数计算,但要支持 Haskell 的部分评估语义需要跟踪比他们目前提供的信息更多,如果我们希望它可靠地工作,那么它可能会带来一些其他缺点。
我认为对于 =
绑定的 lhs 上允许的句法形式有多复杂,我认为有一个更简单的解释。
请始终 post 您收到的错误消息,不要只是说“突出显示语法错误”。该消息对您来说可能意义不大,但在这种情况下它给出了一个强烈的提示:
(@@ ys) = ...
===> error: Parse error in pattern: @@ys
(xs @@) = ...
===> error: Expression syntax in pattern: xs @@
“有规律”啊哈!也就是说,lhs 可能是一种句法模式。此外,无论您介绍什么,都可能没有签名声明;即使有,编译器也必须根据签名检查你的等式,所以它不能假设你所介绍的内容的真实性。考虑这些有效方程
z = 42 -- z counts as a pattern
Just z = {- long and complex expr returning a Maybe, binds z at module-wide scope -}
(Just z) = {- same same, binds z at module-wide scope -}
foo x = ... -- foo gets module-wide scope but not x
(foo x) = ... -- same
bar x y = ... -- bar gets module-wide scope but not x, y
(bar x) y = ... -- same
(x ## y) z = ... -- accepted, introduces triadic operator ##
x ## y z = -- rejected error: Parse error in pattern: y
(x ##) y = -- rejected error: Expression syntax in pattern: x ##
(## y) z = -- rejected error: Parse error in pattern: ##y
语言报告(第 4.4.3 节函数和模式绑定)有
decl -> (funlhs | pat) rhs
funlhs -> var apat { apat }
| pat varop pat
| ( funlhs ) apat { apat }
因此 lhs 不是可以出现表达式语法(包括运算符部分)的地方。另请参阅第 4.4.3.1 节末尾的丑陋细节,将 lhs 运算符语法与中缀数据构造函数结合使用呃!
The last sentence here 还确认您不能在 lhs 上使用运算符部分。