当我定义>>
函数(带RebindableSyntax
扩展名)并直接使用它(mempty >> 1 >> 2 >> 3
)时,一切都按预期工作,但是当我使用 do 块时,出现以下错误:
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
Run Code Online (Sandbox Code Playgroud)
全码:
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
Run Code Online (Sandbox Code Playgroud)
据我了解do
将添加>>
在每条新行上,所以它应该可以工作。
我在哪里做错了?
Haskell 对 do 符号进行脱糖的方式是右结合的
我改变了(>>)
函数infixr
和参数的顺序。代码如下:
{-# 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)
Run Code Online (Sandbox Code Playgroud)
您需要像这样定义您的运营商1:
(>>) :: Integer -> Aggregator Integer -> Aggregator Integer
(>>) a b = (<>) (pack a) b
Run Code Online (Sandbox Code Playgroud)
然后你可以这样做:
finallyWorks :: Aggregator Integer
finallyWorks = do
1
2
3
mempty
Run Code Online (Sandbox Code Playgroud)
原因是 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
Run Code Online (Sandbox Code Playgroud)
对此进行脱糖:
action1 >>= (\r1 -> action2 r1 >>= (\r2 -> f r2))
Run Code Online (Sandbox Code Playgroud)
从根本上说,do 块中的后面动作需要“嵌套在”绑定前面动作结果的 lambda 表达式中,以便这些结果在范围内。这就是导致do
块中行的右关联性质的原因。
实际的>>
操作符 fromMonad
原则上是关联的,因此与a >> (b >> c)
具有相同的最终结果(a >> b) >> c
。因此,do
像您这样不绑定任何变量的块理论上可以脱糖到>>
. 但由于>>
是关联的,没有理由不以do
与绑定变量的方式类似的方式对没有变量的行进行脱糖。
1或a >> (Aggregator b) = Aggregator (a : b)
。看起来它甚至应该是(>>) = coerce (:)
,但是如果没有在 上的类型注释,它就不起作用:
,这使它看起来不再那么漂亮了。
归档时间: |
|
查看次数: |
108 次 |
最近记录: |