了解ErrorT monad转换器

时间:2016-04-10 17:19:44

标签: haskell

newtype ErrorT e m a = ErrorT { runErrorT :: m (Either e a) }

instance (Monad m, Error e) => Monad (ErrorT e m) where

    return a = ErrorT $ return (Right a)

    m >>= k = ErrorT $ do
        a <- runErrorT m
        case a of
            Left l -> return (Left l)
            Right r -> runErrorT (k r)

    fail msg = ErrorT $ return (Left (strMsg msg))

让我们考虑上面的代码。理解它让我很麻烦。它如何在Monads / Transormer Monads的背景下工作?特别是,问题在于理解为什么return a = ErrorT $ return (Right a)返回return (Right a)。我不明白为什么会这样。

第二个问题。 m >>= k基本上是我理解的(我希望如此;))但为什么Right r -> runErrorT (k r)出现了runError?

1 个答案:

答案 0 :(得分:3)

ErrorT只是一个包装器。也就是说,类型ErrorT e m am (Either e a)类型同构:后者可以由构造函数ErrorT转换为前者,而其关联的析构函数runErrorT在其他方向。

return>>=的定义必须包装/解包值以尊重类型。这个包装/解包在运行时没有具体的影响,它只是在那里,所以程序类型检查,编译器可以选择正确的monad实例(mErrorT e m,具体取决于它是否是一个值裹)。

下面

return a = ErrorT $ return (Right a)

部分return (Right a)的类型为m (Either e a),但我们需要ErrorT e m a。应用ErrorT修复了该问题。

同样,在此代码中:

m >>= k = ErrorT $ do
    a <- runErrorT m
    case a of
        Left l -> return (Left l)
        Right r -> runErrorT (k r)

我们需要返回ErrorT m e b。这是通过将ErrorT应用于某些m (Either e b)类型值来完成的。部分Left l的类型为Either e b,因此return会将最后的m添加到顶部。相反,部分k r的类型为ErrorT e m b,因此我们需要使用runErrorT打开它(以便可以再次重新整理do。)