我对 Haskell 相当陌生,并且慢慢地意识到 Monad failure 的存在有问题。现实世界哈斯克尔警告不要使用它 http://book.realworldhaskell.org/read/monad-transformers.html#x_Et(“我们再次建议您几乎总是避免使用失败!”)。我今天才注意到罗斯帕特森称其为“疣,而不是设计模式”早在2008年 http://haskell.1045720.n5.nabble.com/Proposal-Add-Text-Read-maybeRead-Read-a-gt-String-gt-Maybe-a-td3174167.html(并且似乎在那条线索中达成了相当多的一致)。
在观看 Ralf Lämmel 博士的表演时谈谈函数式编程的本质 http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Dr-Ralf-Lmmel-AFP-The-Quick-Essence-of-Functional-Programming,我开始理解可能导致 Monad 失败的紧张局势。在讲座中,Ralf 谈到了向基本单子解析器添加各种单子效果(日志记录、状态等)。许多效果需要更改基本解析器,有时还需要更改所使用的数据类型。我认为向所有单子添加“失败”可能是一种妥协,因为“失败”非常常见,并且您希望尽可能避免对“基本”解析器(或其他)进行更改。当然,某种“失败”对于解析器来说是有意义的,但并不总是如此,例如 State 的 put/get 或 Reader 的 Ask/local。
让我知道我是否走错了路。
我应该避免使用 Monad 失败吗?
Monad 失败的替代方案是什么?
是否有任何不包含此“设计疣”的替代 monad 库?
我在哪里可以了解有关此设计决策的历史的更多信息?
一些 monad 具有合理的故障机制,例如终端单子:
data Fail x = Fail
有些 monad 没有合理的故障机制(undefined
是不明智的),例如初始单子:
data Return x = Return x
从这个意义上说,要求所有单子都具有一个明显的缺陷fail
方法。如果您正在编写对 monad 进行抽象的程序(Monad m) =>
,使用这个泛型并不是很健康m
's fail
方法。这将产生一个可以用 monad 实例化的函数,其中fail
不应该真正存在。
我发现反对使用的人较少fail
(特别是间接地,通过匹配Pat <- computation
)当在一个特定的单子中工作时,一个好的fail
行为已被明确规定。这样的程序有望在回归旧规则的情况下继续存在,在旧规则中,非平凡的模式匹配创造了对MonadZero
而不是仅仅Monad
.
有人可能会说,更好的纪律总是明确地处理失败案例。我反对这个立场有两个原因:(1)一元编程的目的是避免这种混乱,(2)当前对一元计算结果进行案例分析的表示法非常糟糕。 SHE 的下一个版本将支持该表示法(也见于其他变体)
case <- computation of
Pat_1 -> computation_1
...
Pat_n -> computation_n
这可能会有所帮助。
但这整个情况真是一团糟。通过单子支持的操作来表征单子通常很有帮助。你可以看到fail
, throw
等作为一些单子支持的操作,但其他单子不支持。 Haskell 使得支持可用操作集中的小型局部更改变得非常笨拙和昂贵,通过解释如何根据旧操作来处理新操作来引入新操作。如果我们真的想在这里做得更整洁,我们需要重新考虑如何catch
作品,使其成为之间的翻译不同的本地错误处理机制。我经常想将可能在无信息的情况下失败的计算(例如,通过模式匹配失败)与一个处理程序括起来,该处理程序在传递错误之前添加更多上下文信息。我不禁感到有时这样做比应有的更困难。
所以,这是一个可以做得更好的问题,但至少,使用fail
仅适用于提供合理实现并正确处理“异常”的特定单子。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)