haskell - RebindableSyntax 不能按预期工作
问题描述
当我定义>>
函数(带RebindableSyntax
扩展名)并直接使用它(mempty >> 1 >> 2 >> 3
)时,一切都按预期工作,但是当我使用 do block 时,出现以下错误:
Couldn't match expected type ‘Integer’
with actual type ‘Aggregator Integer’
In a stmt of a 'do' block: 1
In the expression:
do mempty
1
2
3
In an equation for ‘notWorking’:
notWorking
= do mempty
1
2
3
整个代码:
{-# LANGUAGE RebindableSyntax #-}
module RebindableSyntaxStuff where
import Prelude hiding ((>>), (>>=), return)
newtype Aggregator a = Aggregator [a]
deriving(Show)
instance Semigroup (Aggregator a) where
(Aggregator xs) <> (Aggregator ys) = Aggregator (xs++ys)
instance Monoid (Aggregator a) where
mempty = Aggregator []
pack :: a -> Aggregator a
pack x = Aggregator [x]
working :: Aggregator Integer
working = mempty >> 1 >> 2 >> 3 --Returns Aggregator [1,2,3]
notWorking :: Aggregator Integer
notWorking = do
mempty
1
2
3
(>>) :: Aggregator Integer -> Integer -> Aggregator Integer
(>>) a b = (<>) a (pack b)
据我了解,每行do
都会添加>>
,所以它应该可以工作。
我在哪里做错了?
解决方案
Haskell 对 do 符号进行去糖的方式是右结合的
我将(>>)
函数更改infixr
为参数的顺序。下面的代码:
working :: Aggregator Integer
working = 1 >> 2 >> 3 >> mempty
notWorking :: Aggregator Integer
notWorking = do -- Now works
1
2
3
mempty
infixr 0 >>
(>>) :: Integer -> Aggregator Integer -> Aggregator Integer
(>>) a = (<>) (pack a)
解决方案
您需要像这样定义运算符1:
(>>) :: Integer -> Aggregator Integer -> Aggregator Integer
(>>) a b = (<>) (pack a) b
然后你可以这样做:
finallyWorks :: Aggregator Integer
finallyWorks = do
1
2
3
mempty
原因是 Haskell 的do
语法被定义为>>
以右关联方式使用运算符。do { mempty; 1; 2; 3; }
最终被读取为运算符本身是左关联的,因此您的手动示例mempty >> (1 >> (2 >> 3))
被读取为; 不是一回事。>>
mempty >> 1 >> 2 >> 3
((mempty >> 1) >> 2) >> 3
我相信这是因为do
绑定变量(使用>>=
运算符而不是>>
)的脱糖规则必须与右侧相关联。这个:
do r1 <- action1
r2 <- action2 r1
f r2
对此进行脱糖:
action1 >>= (\r1 -> action2 r1 >>= (\r2 -> f r2))
从根本上说,do 块中的后续操作需要“嵌套在”绑定早期操作结果的 lambdas 中,以便这些结果在范围内。这就是导致do
块中行的右关联性质的原因。
实际的>>
运算符 fromMonad
原则上是关联的,因此a >> (b >> c)
具有与 相同的最终结果(a >> b) >> c
。因此do
,像您这样不绑定任何变量的块在理论上可以对>>
. 但是由于>>
是关联的,因此没有理由不以do
与绑定变量类似的方式对没有变量的行进行脱糖。
1或a >> (Aggregator b) = Aggregator (a : b)
。看起来它甚至应该是(>>) = coerce (:)
,但是如果没有在 上的类型注释它就不起作用:
,这使它看起来不再那么漂亮了。
推荐阅读
- javascript - 为什么 HTML 布局在 769 像素处中断?
- ionic-framework - 离子选择弹出界面不会在硬件后退按钮操作中隐藏
- jquery - 如何在浏览器窗口上按 F5(Refressing)时停止页面重新提交
- elasticsearch - 在elasticsearch中按日期之间的时差查询
- ionic-framework - 使用 Crosswalk Webview 打开外部链接时出现应用程序错误
- excel - 比较不同工作表中的多个列并删除
- swift - Swift FileHandle seek/readData 性能
- java - 返回当前日期后 num 天的日期值 JAVA
- r - 评估多项式函数
- php - 判断存储日志文件夹中是否存在日志文件