如何在没有monad的纯haskell代码中捕获错误
它可能被要求处死,但有人知道最不具侵入性的“捕捉”方式吗 “纯”如何在没有monad的纯haskell代码中捕获错误,haskell,Haskell,它可能被要求处死,但有人知道最不具侵入性的“捕捉”方式吗 “纯”haskell计算出错 (比如说,一些代码包含head[],不安全,我不想让它们成为纯粹的真实代码,也不想强迫它们成为一元代码) PS:当然,如果你能并且想从头开始设计,一定要在中烘焙(用一种可能的类型)。这里的问题是,我确实有意想要保持它的不安全性(保持不安全语言的简单翻译),并且想知道这样做的最佳/最不丑陋的方式是什么。没有办法在纯代码中使用catch。这是出于设计:异常由IO系统处理。这就是catch类型使用IO的原因。如果您
haskell
计算出错
(比如说,一些代码包含head[]
,不安全,我不想让它们成为纯粹的真实代码,也不想强迫它们成为一元代码)
PS:当然,如果你能并且想从头开始设计,一定要在中烘焙(用一种可能的类型)。这里的问题是,我确实有意想要保持它的不安全性(保持不安全语言的简单翻译),并且想知道这样做的最佳/最不丑陋的方式是什么。没有办法在纯代码中使用
catch
。这是出于设计:异常由IO系统处理。这就是catch
类型使用IO
的原因。如果您想在纯代码中处理失败,那么应该使用类型来表示失败的可能性。在这种情况下,失败的原因是该值有时可能不存在
我们在Haskell中用来表示一个可以存在或不存在的值的类型称为Maybe
可能
是单子的一个实例,因此它是“单子的”,但这不应阻止您将其用于预期目的。因此,您需要的功能是来自安全软件包的headMay
:headMay::[a]->可能是a
也就是说,如果你想避免单子,你可以使用一个函数来解压列表:
listElim :: b -> (a -> [a] -> b) -> [a] -> b
listElim nil _ [] = nil
listElim _ cons (x:xs) = cons x xs
如您所见,这将[]
替换为nil
,:
替换为调用cons
。现在,您可以编写一个安全头,用于指定默认值:
headDef :: a -> [a] -> a
headDef def = listElim def const
不幸的是,函数是
单子的一个实例,所以事实证明你毕竟是“强迫[d]成为单子的!”!真的无法逃避单子,因此也许最好学习如何有效地使用它们。如果你想生活在危险之中,你可以使用unsafePerformIO
:
catch'Pure'
:: Exception e
=> a
-> (e -> a)
-> a
catch'Pure' v h = unsafePerformIO $
evaluate v `catch` (pure . h)
问题是,这根本不能保证表现良好。例如,如果将值传递给它
(let a = a in a) `seq` error "hallo!"
编译器有权有时生成无限循环,有时生成错误消息,这违反了对纯度的基本期望。使用类似这样的代码是有原因的,但要使其表现良好,需要非常小心。中的提供了一个安全的包装,包装了这方面所需的不安全操作
λ>勺子(头[1,2,3])
只有一个
λ> 勺子(头[])
没有什么
使用可能
。捕捉错误是一元的——你不能“强迫它成为一元的。”它是一元的,通过它的属性。写你自己的数据Ok a=No |是的a
,不要为它写Monad
实例,写safeHead::[a]->Ok a
。然后意识到您实际上希望它是一个Monad
,因为成为Monad
非常有用。然后改用也许
。不一定能清楚地理解你的问题。你能更准确地举例说明你想要避免什么吗?如果它只用于头
,您可以使用数据。Maybe.listToMaybe
。这将专门用于Maybe,将需要我重写代码(在可能的情况下,它来自SML),并且仍然可以引发任何其他异常。我想通过处理异常来确保类型a的值确实没有影响。与其使用自定义的listElim
,不如建议使用foldr
:headDef=foldr const
。我的意思是我可以用模式匹配来编写它,但这更有趣。问题是:异常在IO
中处理,但在纯代码中生成。单子的用法可能不够清楚:我不想以特定的方式对代码排序。并非所有使用maybe的代码都是通过包装/展开来传播可选值的一系列步骤构成的,正如CPS/monad所做的那样spoon
使用了unsafePerformIO
和deepseq
的组合,我绝对不建议严重使用。如果你想要一个返回一个的头
,你可以使用“安全”包中的那一个。@Reinhenrich我也不推荐它,但OP确实说了“我不想把它变成纯粹的真实,也不想强迫它成为一元的”,至少勺子
(或茶匙
,如果你不想使用深序
)比直接写不安全的行为
更安全。然后,我再次承认,我常常不知道人们说“一元”(或者,就此而言,“纯”)是什么意思@ReinHenrichs我在想象OP有一种巨大复杂的计算,它的头深深地埋在层和函数层中,这些层都是基于头永远不会收到空列表的假设而构建的,而这种假设由于某种原因现在已经改变了。解决这个问题的困难部分是正确的方法不是从头部获取Maybe
-这很容易-困难的部分是乏味地修复所有的函数层,让Maybe
一路回到外部调用方。因此,我想,OP正在寻找一个快速而肮脏的快捷方式。显然,这是一个糟糕的软件e但有些一次性的项目并不需要好的软件工程。或者至少当我试图不去怀疑整个计算机科学领域时,我告诉自己这一点……没关系,我的(进口的)代码从一开始是不安全的,我对此没有意见。希望我处理错误不会让它变得更不安全,但会让它变得更不安全:))
(let a = a in a) `seq` error "hallo!"