假设我有一个对类型:
data Pair a = Pair a a
Run Code Online (Sandbox Code Playgroud)
为它编写monad实例的正确方法是什么?我的想法大致是这样的:
instance Semigroup a => Semigroup (Pair a) where
Pair a1 a2 <> Pair b1 b2 = Pair (a1 <> b1)(a2 <> b2)
instance Monad Pair where
return = pure
(Pair a b) >>= f = f a <> f b
Run Code Online (Sandbox Code Playgroud)
这是对的吗?如果是这样,那么在对中指定b型中的b类型是一个半群?
实际上,的唯一正确的monad实例Pair如下。
instance Monad Pair where
m >>= f = joinPair (f <$> m)
joinPair :: Pair (Pair a) -> Pair a
joinPair (Pair (Pair x _) (Pair _ y)) = Pair x y
Run Code Online (Sandbox Code Playgroud)
这是正确的monad实例的原因是因为它Pair是一个可表示的函子。
instance Representable Pair where
type Rep Pair = Bool
index (Pair x _) False = x
index (Pair _ y) True = y
tabulate f = Pair (f False) (f True)
Run Code Online (Sandbox Code Playgroud)
事实证明,对于每个可表示的函子,(>>=)都等效于以下bindRep函数。
bindRep :: Representable f => f a -> (a -> f b) -> f b
bindRep m f = tabulate (\a -> index (f (index m a)) a)
Run Code Online (Sandbox Code Playgroud)
如果我们将bindRep功能专门化,Pair则会得到以下结果。
bindRep :: Pair a -> (a -> Pair b) -> Pair b
bindRep (Pair x y) f = tabulate (\a -> index (f (index (Pair x y) a)) a)
= Pair (index (f x) False) (index (f y) True)
-- |_________________| |________________|
-- | |
-- (1st elem of f x) (2nd elem of f y)
Run Code Online (Sandbox Code Playgroud)
以下Adelbert Chang的博客文章对此进行了更好的解释。用可表示的函子进行推理。