madd a b = do aa <- a
bb <- b
return (aa + bb)
data Counter a = Counter a Int
deriving (Show,Eq)
instance Functor Counter where
fmap f (Counter a i) = Counter (f a) i
instance Applicative Counter where
pure x = Counter x 0
Counter f i <*> Counter x j = Counter (f x) (i + j)
instance Monad Counter where
return x = Counter x 0
Counter a i >>= f =
let Counter b j = f a
in Counter b (i + j + 1)
所以假设此代码运行:
madd (Counter 10 43) (Counter 32 1)
一个人获得Counter 42 46
。
我不知道这是如何产生此结果的。因此, madd
"调用" monad Counter
,然后将 +
函数传递到单一实例的>>=
。但是后来我找到了单元实例如何调用/传递功能/结果非常困惑。
任何人都可以详细解释中间计算的工作方式吗?
tl; dr &#8202;:拥抱do
,避开 bind &#8202;!无论如何,这是一个实施细节。do
确实可以视为公理的主要符号,如" monads" 是首先说" program" 的一种方式(插入a对冲预选赛(。
do
符号被列为 bind &#8202;基代码,
do { v <- m ; f v } === m >>= f
相反,沿反向方向
Counter a i >>= f === do { v <- Counter a i ; f v }
因此,您的Monad实例的 bind 定义,
Counter a i >>= f = Counter b (i + j + 1) where
Counter b j = f a
可以非正式地重写为
instance Monad Counter where
return x = Counter x 0
do { v <- Counter x i
; f v } = Counter y (i + j + 1) where -- the bind transformation
Counter y j = f v
v = x
Now we can manipulate your do
code directly, to see what's going on:
madd (Counter 10 43) (Counter 32 1)
= do { aa <- Counter 10 43
; bb <- Counter 32 1
; return (aa + bb)
}
= do { aa <- Counter 10 43
; do { bb <- Counter 32 1 -- by Monad Laws
; return (aa + bb)
}}
= do { aa <- Counter 10 43
; f aa } where f aa = do { bb <- Counter 32 1 -- abstraction
; return (aa + bb)
}
= Counter y (43 + j + 1) -- the bind transformation
where Counter y j = f 10
= do { bb <- Counter 32 1
; return (10 + bb)
}
= do { bb <- Counter 32 1
; (return . (10 +)) bb
}
= Counter y (1 + j + 1) -- the bind transformation
where Counter y j = (return . (10 +)) 32
= return 42
= Counter 42 0
= Counter 42 (1 + 0 + 1)
= Counter 42 2
= Counter 42 (43 + 2 + 1)
= Counter 42 46
that is, madd (Counter a i) (Counter b j)
produces Counter (a+b) (i+j+2)
, 2 being the number of bind transformation applications.
When desugared your do
expression in madd
becomes
a >>= aa -> b >>= bb -> return (a + b)
因此,您可以从第一和第二计数器加两个,每个都有43加1,每个计数器都在madd中绑定
学习单子时,避免执行表示法是一个好主意,并始终记住单核的绑定(>> =(的特定定义,我们正在分析