为自制的 monad 转换器定义绑定

Defining bind for home-made monad transformer

我已经定义了我自己的 WriterT 版本以及一个对其进行解包的函数:

newtype WT w m a = WT (m a, w)

unWT :: (Monoid w, Monad m) => WT w m a -> (m a, w)
unWT (WT cmaw) = cmaw

现在我试图定义 monad (WT w m),但没有成功:

instance (Monoid w, Monad m) => Monad (WT w m) where
  return x = WT (return x, mempty)
  wtwma >>= fawtwmb = WT $ let (ma, w1) = unWT wtwma
                               (mb, w2) = unWT $ do a <- ma
                                                    fawtwmb a
                           in (mb, mappend w1 w2)

错误位于 do 表达式中,在我尝试从 ma 中提取 a 的位置:

Expected type: WT w m a, Actual type: m a

我尝试了一些变体,结果总是相似的。我无法为这个 monad 定义 bind

我的主要问题是:如果 monad 在一对内部,我如何提取它的值?

设想以下计算:

tellLine :: WT String IO ()
tellLine = do
    input <- WT (getLine, "")
    WT (return (), input)

impossible :: String
impossible = snd (unWT tellLine)

如果这相当于"expected",我们应该得到impossible是用户输入的字符串。但是,我们不能在 IO 之外这样做;这样的 impossible 不可能像这里那样是纯粹的 String。因此,不可能产生作为 monad 计算结果收到的 w

另一种可能性是简单地 return 第一次绑定之前发生的 w,因此我们不必依赖任何单子操作。 las,身份法则之一阻碍了我们。

return x >>= f = f x

这里可以看出"before the first bind"不是一个有意义的概念,因为左边有bind,右边没有。所以 return 在第一次绑定之前发生的 w 肯定会违反这个 monad 法则。

唯一剩下的可能性是 w 永远是 mempty。但这也行不通,因为另一个恒等式。

m >>= return = m

因此,如果 m 具有 w 的非 mempty 值,绑定将消灭它并违反此法则。

这个 WT 不能是一个 monad 转换器。有一个 WriterT 变压器,但它被定义为 m (a,w) 避免了这些问题。