【发布时间】:2016-07-16 20:33:20
【问题描述】:
我注意到的一件事是Tuple 没有Monad 实例。
但元组确实有一个 Applicative 实例:
instance Monoid a => Applicative ((,) a)
这已经极大地限制了我们可以使 Monad 实例成为的内容。
让我们看看我们会为 join 得到的类型签名:
instance Monoid a => Monad ((,) a)
join :: Monad m => m (m a) -> m a
join :: Monoid a => (a, (a, b)) -> (a, b)
我们也可以看看单子定律:
join $ f <$> pure x == f x
join $ f <$> (mempty, x) == f x
join (mempty, f x) == f x
join (mempty, (a, b)) == (a, b)
join $ pure <$> x = x
join $ pure <$> (a, b) = (a, b)
join (a, (mempty, b)) = (a, b)
此时我们知道将mempty 和x 以任何一种方式组合都会产生x。我们拥有的关于x 的唯一类型信息是它是Monoid。所以基本上只有两个实现是:
join (a, (b, x)) = (a <> b, x)
和:
join (a, (b, x)) = (b <> a, x)
其中第二个使ap 和<*> 不一样。
所以现在我们知道((,) a) 的唯一有效Monad 实例是:
instance Monoid a => Monad ((,) a) where
(a, c) >>= f = let (b, c') = f c in (a <> b, c')
那为什么现在不是这样呢?
【问题讨论】:
-
我猜这是
ghc-8.1的新功能 -ghci说instance Monoid a => Monad ((,) a) -- Defined in ‘GHC.Base’ -
一个疯狂的猜测:因为它不够通用?这可能是
Set没有的原因…… -
Set没有单子实例,因为不存在满足单子定律的实例。((,) a)的提议实例是守法的,我认为是唯一可能的守法实例,因此创建它是有意义的。 -
我通常只使用the Writer Monad...
-
@ThreeFx 这是尽可能通用的。此外,根本没有实例将更具限制性。而且,正如 Michael 所提到的,这个实例已经存在于最新的稳定版 GHC 中。