简体   繁体   English

“除了”的复杂性在Haskell中的作用是什么?

[英]What purpose does the complexity of `Except` serve in Haskell?

I understand (I think) that there is a close relationship between Either and Except in Haskell, and that it is easy to convert from one to the other. 理解 (我认为)在Haskell中EitherExcept之间存在密切关系,并且很容易从一个转换为另一个。 But I'm a bit confused about best practices for handling errors in Haskell and under what circumstances and scenarios I would choose one over the other. 但是我对在Haskell中处理错误的最佳实践以及在什么情况和情况下我会选择其中一个而感到困惑。 For example, in the example provided in Control.Monad.Except , Either is used in the definition 例如,在Control.Monad.Except提供的示例中,在定义中使用了Either

type LengthMonad = Either LengthError

so that calculateLength "abc" is 所以calculateLength "abc"

Right 3

If instead one were to define 相反,如果要定义

type LengthMonad = Except LengthError

then calculateLength "abc" would be 然后calculateLength "abc"将是

ExceptT (Identity (Right 3))

I'm confused about what purpose this would serve and when one one want it. 我很困惑这会起什么作用,何时需要它。 Why does everything returned from calculateLength always have Identity ; 为什么从calculateLength返回的所有内容总是具有Identity ; why not just SomeExceptionType (Right 3) or even SomeSuccessType 3 ? 为什么不只是SomeExceptionType (Right 3)甚至SomeSuccessType 3

I'm a Haskell beginner when it comes to concepts like this, so a concrete example of when I'd want the latter over the former would be much appreciated, especially why it's so (apparently to me) complex. 当谈到像这样的概念时,我是一个Haskell的初学者,所以当我希望后者超过前者时,我会非常感激,特别是为什么它(显然对我来说)很复杂。 For example, what can a caller of a function that uses the Except version of calculateLength do, that they can't (or at least can't as easily) do with the Either version? 例如,使用Except calculateLength版本的函数的调用者可以做什么,他们不能(或至少不能那么容易)使用Either版本?

Abstract 抽象

Use Either for normal success/error APIs. Either用于正常成功/错误 API。 It's defined in the base library, so it doesn't push other dependencies on a consumer. 它在基础库中定义,因此不会将其他依赖项推送到使用者身上。 Also, this is one of the most basic Haskell types, so 'everyone' understands how it works. 此外,这是最基本的Haskell类型之一,因此'每个人'都了解它的工作原理。

Only use ExceptT if you specifically need to combine Either with another monad (such as, for example IO ). 如果您特别需要将Either与另一个monad(例如IO )组合,则仅使用ExceptT This type is defined in the transformers library, so pushes an extra dependency on consumers. 此类型在变换器库中定义,因此会对消费者产生额外的依赖性。 Additionally, monad transformers is a more advanced feature of Haskell, so you can't expect everyone to understand how to use it. 另外,monad变换器是Haskell的一个更高级的功能,所以你不能指望每个人都能理解如何使用它。

Speculation on reasons 对原因的猜测

I wasn't around when those decisions were made, but it seems that there are various historical reasons for the confusion . 做出这些决定时,我并不在身边,但似乎有各种历史原因引起混淆 Haskell is an old language (older than Java!), so even though efforts have been made to streamline it and rectify old mistakes, some still remain. Haskell是一种古老的语言(比Java早!),所以即使已经努力简化它并纠正旧的错误,一些仍然存在。 As far as I can tell, the Either / ExceptT confusion is one of those situations. 据我所知, Either / ExceptT混淆是其中一种情况。

I'm speculating that Either is older than the concept of monad transformers, so I imagine that the type Either was introduced to the base library early in the history of Haskell. 猜测 Either比monad变换器的概念要老,所以我想在早期的Haskell历史中将类型Either引入基础库。

The same thing seems to be the case with Maybe . Maybe似乎也是如此。

Other monads, likes eg Reader and State seem to have been introduced (or at least 'retconned') together with their monad transformers. 其他monad,例如ReaderState似乎已经与他们的monad变换器一起被引入(或至少'retconned')。 For example, Reader is just a special case of ReaderT , where the 'other' Monad is Identity : 例如, Reader只是ReaderT一个特例 ,其中'其他' MonadIdentity

type Reader r = ReaderT r Identity

The same goes for StateT : StateT

type State s = StateT s Identity

That's the general pattern for many of the monads defined in the transformers library. 这是变形金刚库中定义的许多monad的一般模式。 ExceptT just follows the pattern by defining Except as the special case of ExceptT . ExceptT只是遵循模式,将Except定义为ExceptT

There are exceptions to that pattern. 这种模式有例外。 For example, MaybeT doesn't define Maybe as a special case. 例如, MaybeT没有将Maybe定义为特例。 Again, I believe that this is for historical reasons; 我再次相信这是出于历史原因; Maybe was probably around long before anyone started work on the transformers library. Maybe很久很久才有人开始研究变形金刚图书馆。

The story about Either seems even more convoluted. 关于Either的故事似乎更令人费解。 As far as I can tell, there was , originally, an EitherT monad transformer, but apparently (I forget the details) there was something wrong with the way that it behaved (it probably broke some laws), so it was replaced with another transformer called ErrorT , which again turned out to be wrong. 据我所知, ,原来,一个EitherT单子转换,但显然(我忘了细节)有一些错误的方式,它的表现(它可能打破了一些法律),因此,它与另一变压器更换叫做ErrorT ,后来又证明是错的。 Third time's the charm, I suppose, so ExceptT was introduced. 我想,第三次是魅力,所以引入了ExceptT

The Control.Monad.Trans.Except module follows the pattern of most other monad transformers by defining the 'uneffectful' special case using a type alias: Control.Monad.Trans.Except模块遵循大多数其他monad变换器的模式,通过使用类型别名定义'无效'特殊情况:

type Except e = ExceptT e Identity

I suppose it does that because it can, but it may be unfortunate, because it's confusing. 我想这样做是因为它可以,但它可能是不幸的,因为它令人困惑。 There's definitely prior art that suggests that a monad transformer doesn't have to follow that pattern (eg MaybeT ), so I think it would have been better if the module hadn't done that, but it does, and that's where we are. 绝对现有技术表明monad变换器不必遵循该模式(例如MaybeT ),所以我认为如果模块没有这样做会更好,但确实如此,那就是我们所处的位置。

I would essentially ignore the Except type and use Either instead, but use ExceptT if a transformer is required. 我基本上会忽略Except类型并使用Either代替,但如果需要变换器则使用ExceptT

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM