`Except` 的复杂性在 Haskell 中有什么用?
What purpose does the complexity of `Except` serve in Haskell?
我在 (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. 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. For example, in the example中提供了Control.Monad.Except
,Either
定义中使用了
type LengthMonad = Either LengthError
所以calculateLength "abc"
是
Right 3
如果改为定义
type LengthMonad = Except LengthError
那么 calculateLength "abc"
就是
ExceptT (Identity (Right 3))
我对这将用于什么目的以及何时需要它感到困惑。为什么从 calculateLength
返回的所有内容总是 Identity
;为什么不只是 SomeExceptionType (Right 3)
甚至 SomeSuccessType 3
?
我是一个 Haskell 初学者,当涉及到像这样的概念时,所以一个具体的例子,当我想要后者而不是前者时,将非常感激,特别是为什么它是如此(显然我)复杂。例如,使用 calculateLength
的 Except
版本的函数的调用者可以做什么,而他们不能(或至少不能那么容易地)使用 Either
做什么版本?
摘要
对正常的 success/error API 使用 Either
。它在 base 库中定义,因此它不会将其他依赖项推给消费者。此外,这是最基本的 Haskell 类型之一,因此 'everyone' 了解它的工作原理。
如果您特别需要将 Either
与另一个单子组合(例如 IO
),则仅使用 ExceptT
。这种类型在 transformers 库中定义,因此对消费者产生了额外的依赖。此外,monad transformers 是 Haskell 的一个更高级的特性,所以你不能指望每个人都能理解如何使用它。
原因推测
做出这些决定时我不在,但是 it seems that there are various historical reasons for the confusion。 Haskell 是一种 旧的 语言(比 Java 更早!),因此尽管已努力简化它并纠正旧错误,但仍有一些错误。据我所知,Either
/ExceptT
混乱就是其中一种情况。
我 推测 Either
比 monad 转换器的概念更早,所以我想 Either
类型被引入 base 库的历史早于 Haskell.
Maybe
似乎也是如此。
其他单子,例如Reader 和 State 似乎与它们的 monad 转换器一起被引入(或至少 'retconned')。例如,Reader
只是 ReaderT
的 特例 ,其中 'other' Monad
是 Identity
:
type Reader r = ReaderT r Identity
StateT
也一样:
type State s = StateT s Identity
这是 transformers 库中定义的许多单子的通用模式。 ExceptT
只是通过将 Except
定义为 ExceptT
.
的特例来遵循模式
这种模式也有例外。例如,MaybeT
没有将 Maybe
定义为特例。同样,我认为这是出于历史原因; Maybe
可能早在有人开始研究 transformers 库之前就存在了。
关于 Either
的故事似乎更加复杂。据我所知, 是 ,最初是一个 EitherT
monad 转换器,但显然(我忘记了细节)它的行为方式有问题(它可能违反了一些法律),因此它被另一个名为 ErrorT
的转换器所取代,这又被证明是错误的。第三次是魅力,我想,所以 ExceptT
被介绍了。
Control.Monad.Trans.Except
模块通过使用类型别名定义 'uneffectful' 特殊情况来遵循大多数其他 monad 转换器的模式:
type Except e = ExceptT e Identity
我想它这样做是因为它可以,但它可能很不幸,因为它令人困惑。肯定有现有技术表明 monad 转换器不必遵循该模式(例如 MaybeT
),所以我认为如果模块没有这样做会更好,但它确实如此,那就是我们在哪里。
我基本上会忽略 Except
类型并使用 Either
代替,但如果需要转换器,请使用 ExceptT
。
我在Either
and Except
in Haskell, and that it is easy to convert from one to the other. 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. For example, in the example中提供了Control.Monad.Except
,Either
定义中使用了
type LengthMonad = Either LengthError
所以calculateLength "abc"
是
Right 3
如果改为定义
type LengthMonad = Except LengthError
那么 calculateLength "abc"
就是
ExceptT (Identity (Right 3))
我对这将用于什么目的以及何时需要它感到困惑。为什么从 calculateLength
返回的所有内容总是 Identity
;为什么不只是 SomeExceptionType (Right 3)
甚至 SomeSuccessType 3
?
我是一个 Haskell 初学者,当涉及到像这样的概念时,所以一个具体的例子,当我想要后者而不是前者时,将非常感激,特别是为什么它是如此(显然我)复杂。例如,使用 calculateLength
的 Except
版本的函数的调用者可以做什么,而他们不能(或至少不能那么容易地)使用 Either
做什么版本?
摘要
对正常的 success/error API 使用 Either
。它在 base 库中定义,因此它不会将其他依赖项推给消费者。此外,这是最基本的 Haskell 类型之一,因此 'everyone' 了解它的工作原理。
如果您特别需要将 Either
与另一个单子组合(例如 IO
),则仅使用 ExceptT
。这种类型在 transformers 库中定义,因此对消费者产生了额外的依赖。此外,monad transformers 是 Haskell 的一个更高级的特性,所以你不能指望每个人都能理解如何使用它。
原因推测
做出这些决定时我不在,但是 it seems that there are various historical reasons for the confusion。 Haskell 是一种 旧的 语言(比 Java 更早!),因此尽管已努力简化它并纠正旧错误,但仍有一些错误。据我所知,Either
/ExceptT
混乱就是其中一种情况。
我 推测 Either
比 monad 转换器的概念更早,所以我想 Either
类型被引入 base 库的历史早于 Haskell.
Maybe
似乎也是如此。
其他单子,例如Reader 和 State 似乎与它们的 monad 转换器一起被引入(或至少 'retconned')。例如,Reader
只是 ReaderT
的 特例 ,其中 'other' Monad
是 Identity
:
type Reader r = ReaderT r Identity
StateT
也一样:
type State s = StateT s Identity
这是 transformers 库中定义的许多单子的通用模式。 ExceptT
只是通过将 Except
定义为 ExceptT
.
这种模式也有例外。例如,MaybeT
没有将 Maybe
定义为特例。同样,我认为这是出于历史原因; Maybe
可能早在有人开始研究 transformers 库之前就存在了。
关于 Either
的故事似乎更加复杂。据我所知, 是 ,最初是一个 EitherT
monad 转换器,但显然(我忘记了细节)它的行为方式有问题(它可能违反了一些法律),因此它被另一个名为 ErrorT
的转换器所取代,这又被证明是错误的。第三次是魅力,我想,所以 ExceptT
被介绍了。
Control.Monad.Trans.Except
模块通过使用类型别名定义 'uneffectful' 特殊情况来遵循大多数其他 monad 转换器的模式:
type Except e = ExceptT e Identity
我想它这样做是因为它可以,但它可能很不幸,因为它令人困惑。肯定有现有技术表明 monad 转换器不必遵循该模式(例如 MaybeT
),所以我认为如果模块没有这样做会更好,但它确实如此,那就是我们在哪里。
我基本上会忽略 Except
类型并使用 Either
代替,但如果需要转换器,请使用 ExceptT
。