haskell - `Except` 的复杂性在 Haskell 中的作用是什么?
问题描述
我理解(我认为)Haskell 之间有密切的关系,Either
并且Except
很容易从一个转换到另一个。但是我对在 Haskell 中处理错误的最佳实践以及在什么情况和场景下我会选择其中一个感到有点困惑。例如,在 中提供的示例中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 初学者,所以我希望后者而不是前者的具体例子将不胜感激,特别是为什么它如此(显然对我而言)复杂。例如,使用doExcept
版本的函数的调用者可以calculateLength
做什么,而他们不能(或至少不能那么容易)用该Either
版本做什么?
解决方案
抽象的
用于Either
正常的成功/错误API。它是在基础库中定义的,因此它不会将其他依赖项推向消费者。此外,这是最基本的 Haskell 类型之一,因此“每个人”都了解它的工作原理。
仅ExceptT
在您特别需要Either
与另一个 monad 组合时使用(例如,例如IO
)。这种类型是在转换器库中定义的,因此对消费者产生了额外的依赖。此外,monad 转换器是 Haskell 的一个更高级的功能,所以你不能指望每个人都了解如何使用它。
推测原因
做出这些决定时我不在,但似乎有各种历史原因造成了这种混乱。Haskell 是一门古老的语言(比 Java 还要古老!),因此尽管已经努力简化它并纠正旧的错误,但仍然存在一些错误。据我所知,Either
/ExceptT
混乱就是其中一种情况。
我推测这Either
比 monad 转换器的概念更早,所以我想这种类型是在 Haskell 历史早期Either
被引入基础库的。
同样的事情似乎也是如此Maybe
。
其他单子,例如Reader和State似乎已经与它们的单子转换器一起被引入(或至少“重新连接”)。例如,Reader
只是 的一个特例,ReaderT
其中“其他”Monad
是Identity
:
type Reader r = ReaderT r Identity
这同样适用于StateT
:
type State s = StateT s Identity
这是在转换器库中定义的许多 monad 的一般模式。只是通过定义为 的特例ExceptT
来遵循模式。Except
ExceptT
这种模式也有例外。例如,MaybeT
不定义Maybe
为特例。同样,我认为这是出于历史原因;Maybe
可能早在有人开始研究变形金刚库之前就已经存在了。
关于的故事Either
似乎更加扑朔迷离。据我所知,最初有一个monadEitherT
变压器,但显然(我忘记了细节)它的行为方式有问题(它可能违反了一些法律),所以它被另一个名为ErrorT
,这再次证明是错误的。我想第三次是魅力,所以ExceptT
被介绍了。
该Control.Monad.Trans.Except
模块通过使用类型别名定义“无效”特殊情况,遵循大多数其他 monad 转换器的模式:
type Except e = ExceptT e Identity
我想它这样做是因为它可以,但它可能是不幸的,因为它令人困惑。肯定有现有技术表明 monad 转换器不必遵循这种模式(例如MaybeT
),所以我认为如果模块没有这样做会更好,但它确实如此,这就是我们所处的位置。
我基本上会忽略Except
类型并Either
改为使用,但ExceptT
如果需要变压器则使用。
推荐阅读
- php - 预期数量的 EC2 实例未在给定时间内初始化
- javascript - 在 selectize.js 中禁用焦点下拉菜单
- ruby-on-rails - 模型验证是否应该反映数据库列约束
- bash - 在 Makefile 中回显退出代码
- python - 如何在 Tensorflow 中附加不同长度的平面张量?
- html - FontAwesome 图标溢出其容器
- css - 为什么css溢出隐藏在这种情况下不起作用
- react-native - 在这种情况下如何正确调用 this.setState() ?
- python-3.x - 是否有支持标识符和多行值中的冒号的配置文件格式?
- neural-network - 考虑到步幅和输入大小,这些卷积是如何实现的?