如何在没有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!"