两个monad之间的差异:ErrorT e Identity v和E e v

时间:2016-04-21 21:46:09

标签: haskell monads

有人可以解释

之间的区别
ErrorT String Identity Integer

Either String Integer

2 个答案:

答案 0 :(得分:3)

(为了简化这一点,我将根据ExceptT类型而不是the deprecated ErrorT来回答。我对ErrorT的回答并不严格,但是&# 39; s真实模数导致ErrorT弃用的一些令人讨厌的事实。)

这里要理解的关键概念是isomorphism。非正式地说非常,两种类型是同构的,尽管表面上有所不同,但它们基本上是相同的。"

我们可以通过添加这个概念来更多地关注这个概念:两个Haskell类型是同构的,如果两者都可以转换为另一个"无损"时尚由一对反函数。在这种情况下,Either e aEitherT e Identity a是同构的,因为以下两个函数是反转的:

toEither :: ExceptT e Identity a -> Either e a
toEither ma = runIdentity (runExceptT ma)

toExceptT :: Either e a -> ExceptT e Identity a
toExceptT (Left e) = throwError e
toExceptT (Right a) = return a

通过上面的非正式评论,这告诉你的是这两种类型基本相同。"反函数增加的肉是他们证明:

  1. 如果您有任何使用任何一种类型的代码,您可以重构它以使用另一种代码,代码将产生完全相同的结果和行为;
  2. 如果你有两个独立的库,其中一个使用第一个类型而另一个使用第二个类型,你可以使用同构函数在它们之间桥接,一切都会没问题。
  3. 所以归结为在编程中通常有很多不同的方法来完成 相同的事情。在这种情况下,ExceptTEither的更一般版本,但是当您插入Identity作为基本monad时,您会获得与Either完全相同的内容。在这种情况下,我们通常更喜欢使用Either因为我们没有那么多的样板,但有时我们发现自己处于ExceptT e Identity a的情况,然后知道同构有助于您了解它与Either e a没有本质区别。

    这是另一种分析方法。 ExceptT类型的定义如下:

    newtype ExceptT e m a = ExceptT { runExceptT :: m (Either e a) }
    

    在Haskell中,newtype定义是同构(ExceptT构造函数而runExceptT函数是反转的),在这种情况下意味着以下两种类型是同构的:

    ExceptT e m a ~ m (Either e a)
    

    这意味着这两个同构也是同构的:

    ExceptT e Identity a ~ Identity (Either e a)
    

    Identity也被定义为newtype

    newtype Identity a = Identity { runIdentity :: a }
    

    这意味着这种同构也存在:

    Identity a ~ a
    

    因此这些也是如此:

    Identity (Either e a) ~ Either e a
    ExceptT e Identity a ~ Either e a
    

    因此,当一个库透明地将某种类型定义为newtype时,注意到这一事实是值得的。 (这就是为什么Haskell中的库文档告诉您导出构造函数的数据类型是data还是newtype定义 - 知道它是newtype的原因很重要。)

    从同构的角度来看这个问题的另一个好处是,它可以帮助您更好地理解许多标准的Haskell库。如上所述,根据newtype的{​​{1}}定义,以下同构成立

    ExceptT

    使用ExceptT e m a ~ m (Either e a) 形式的monadic类型时,我们通常会将m a称为" monad"和m"结果类型"。通过这个镜头观察它,然后:

    1. a中,m (Either e a)是monad,m是结果类型;
    2. Either e a中,ExceptT e m a是monad,ExceptT e m是结果类型。
    3. 所以a monad变换器是一个同构,它允许我们翻转视角"对ExceptT类型的计算,以便我们将m (Either e a)视为结果类型而不是a。它通过改变含义"来实现这一点。 monad操作从他们在Either e a中的含义到解释"视角翻转"问题。

答案 1 :(得分:1)

By convention, Either is used to emulate an exception system, but it is not designed for that.

That's why we use ErrorT for bigger implementations, since it comes with the Error type, which allows the user to define more general exceptions.

However, once you run with runErrorT the monadic action of type ErrorT e Identity a, you get a value of type Either e a. So, those types are somewhat equivalent, just that ErrorT allows you to use functions like throwError and catchError instead of either, which is less clear (especially when repeatedly used).

PS: As the documentation states, Control.Monad.Error is deprecated, Control.Monad.Except instead.