假设我有一个Pair类型:

data Pair a = Pair a a
为它编写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
这是正确的吗?如果是这样,那么在哪里指定b中的Pair b -type是一个半组?

最佳答案

实际上,Pair的唯一正确的monad实例如下。

instance Monad Pair where
    m >>= f = joinPair (f <$> m)

joinPair :: Pair (Pair a) -> Pair a
joinPair (Pair (Pair x _) (Pair _ y)) = Pair x y
之所以是正确的monad实例,是因为Pairrepresentable functor
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)
事实证明,对于每个可表示的仿函数(>>=)都等效于以下 bindRep 函数。
bindRep :: Representable f => f a -> (a -> f b) -> f b
bindRep m f = tabulate (\a -> index (f (index m a)) a)
如果我们将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)
以下Adelbert Chang的博客文章对此进行了更好的解释。 Reasoning with representable functors

这是证明独特性的另一种方法。考虑左右身份单子(monad)实例法则。
return a >>= k = k a -- left identity law

m >>= return = m     -- right identity law
现在,对于Pair数据类型return x = Pair x x。因此,我们可以专门研究这些法律。
Pair a a >>= k = k a     -- left identity law

m >>= \x -> Pair x x = m -- right identity law
那么,为了满足这两个定律,>>=的定义应该是什么?
Pair x y >>= f = Pair (oneOf [x1, x2, y1, y2]) (oneOf [x1, x2, y1, y2])
    where Pair x1 y1 = f x
          Pair x2 y2 = f y
oneOf函数不确定地返回列表的元素之一。
现在,如果我们的>>=函数满足左身份定律,那么当x = y时,则x1 = x2y1 = y2的结果必须是Pair (oneOf [x1, x2]) (oneOf [y1, y2])
同样,如果我们的>>=函数要满足正确的身份定律,则x1 = y1 = xx2 = y2 = y的结果必须是Pair (oneOf [x1, y1]) (oneOf [x2, y2])
因此,如果您想同时满足这两个定律,那么唯一有效的结果就是Pair x1 y2

关于haskell - 如何为两个参数都具有相同类型的对编写monad实例?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58753545/

10-13 06:14