我是Haskell的新手,并且慢慢地认为Monad的存在失败了。真实世界Haskell warns against its use(“再一次,我们建议您几乎总是避免使用失败!”)。我今天才注意到,罗斯帕特森称之为“疣,而不是设计模式”back in 2008(似乎在那个帖子中得到了一些协议)。
在观看RalfLämmel博士talk on the essence of functional programming时,我开始明白可能导致Monad失败的紧张局势。在讲座中,Ralf讨论了向基础monadic解析器添加各种monadic效果(日志记录,状态等)。许多效果需要更改基本解析器,有时还需要更改使用的数据类型。我认为向所有monad添加'fail'可能是一种妥协,因为'fail'是如此常见,你想尽可能避免更改'base'解析器(或其他)。当然,某种“失败”对于解析器来说是有意义的,但并不总是,例如,put / get of State或者问/本地读者。
让我知道我是否可能走错了路。
我应该避免使用Monad失败吗? Monad失败的替代方案是什么? 是否有任何替代monad库不包括这个“设计疣”? 我在哪里可以阅读有关此设计决策历史的更多信息?
答案 0 :(得分:27)
一些单子具有合理的失效机制,例如:终端monad:
data Fail x = Fail
有些monad没有合理的失败机制(undefined
不合理),例如最初的monad:
data Return x = Return x
从这个意义上讲,要求所有monad都采用fail
方法显然是一个瑕疵。如果您正在编写通过monad (Monad m) =>
进行抽象的程序,那么使用该通用m
的{{1}}方法并不是很健康。这将导致您可以使用monad实例化的函数,其中fail
不应该存在。
我发现在使用fail
时(特别是间接地,通过匹配fail
)在使用明确指定良好Pat <- computation
行为的特定monad中时,反对意见较少。这些程序有望在返回旧规则后继续存在,在这种规则中,非平凡的模式匹配产生了对fail
的需求,而不仅仅是MonadZero
。
有人可能会说,更好的纪律总是明确地对待失败案件。我反对这个立场有两个方面:(1)monadic编程的目的是避免这种混乱,(2)对于monadic计算结果的案例分析的当前符号是如此糟糕。 SHE的下一个版本将支持该表示法(也可在其他变体中找到)
Monad
这可能会有所帮助。
但这整个情况令人遗憾。通过它们支持的操作来表征monad通常是有帮助的。您可以将case <- computation of
Pat_1 -> computation_1
...
Pat_n -> computation_n
,fail
等视为某些monad支持的操作,但不支持其他monad。 Haskell使得支持可用操作集中的小型本地化更改变得非常笨拙和昂贵,通过解释如何根据旧操作处理它们来引入新操作。如果我们真的想在这里做一个更整洁的工作,我们需要重新考虑throw
的工作原理,使其成为不同本地错误处理机制之间的翻译。我经常想要计算一个计算,该计算可能会失去信息(例如通过模式匹配失败)与处理程序,该处理程序在传递错误之前添加更多上下文信息。我不禁觉得这样做有时候比应该做的更难。
所以,这是一个可以做得更好的问题,但至少,只对提供合理实现的特定monad使用catch
,并正确处理'例外'。
答案 1 :(得分:25)
在Haskell 1.4(1997)中,没有fail
。相反,有一个MonadZero
类型类,其中包含zero
方法。现在,do
表示法使用zero
来表示模式匹配失败;这给人们带来了惊喜:他们的功能是否需要Monad
或MonadZero
取决于他们如何使用do
符号。
当Haskell 98稍后设计时,他们做了几处修改,使编程对新手来说更简单。例如,monad理解被转化为列表理解。同样,要删除do
类型类问题,已删除MonadZero
类;对于do
的使用,方法fail
已添加到Monad
;对于zero
的其他用途,mzero
添加了MonadPlus
方法。
我认为,有一个很好的论据,即fail
不应该明确地用于任何事情;它唯一的用途是翻译do
符号。尽管如此,我自己也经常调皮,并明确地使用fail
。
您可以访问原始的1.4和98报告here。我确信可以在某些电子邮件列表存档中找到导致更改的讨论,但我没有方便的链接。
答案 2 :(得分:6)
我试图尽可能避免Monad失败,并且根据您的情况,有多种方法可以捕获失败。 Edward Yang在题为8 ways to report errors in Haskell revisited的文章中对他的博客进行了很好的概述。
总之,报告错误的不同方式是:
其中,如果我知道如何处理错误,我会很想使用选项3和Either e b
,但需要更多的上下文。