它可能已经被要求处死,但是谁能知道最简单的“捕捉”方式
catch
:: Exception e
=> IO a
-> (e -> IO a)
-> IO a
“纯” haskell
计算中的错误?
(例如,某些包含head []
的代码不安全,我不想将其纯粹化为真实的,也不想强迫其成为单子)
答案 0 :(得分:6)
无法在纯代码中使用catch
。这是设计使然:异常由IO系统处理。这就是catch
类型使用IO
的原因。如果要用纯代码处理失败,则应使用一种类型来表示失败的可能性。在这种情况下,失败之处在于该值有时可能不存在。
我们在Haskell中用来表示可以存在或不存在的值的类型称为Maybe
。 Maybe
是Monad
的一个实例,因此它是“ monadic”的,但这不应阻止您将其用于预定目的。因此,您想要的功能是来自{em> safe 包中的headMay
:headMay :: [a] -> Maybe a
。
也就是说,如果要避免使用monad,可以改用解压缩列表的函数:
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
不幸的是,函数是Monad
的一个实例,因此事实证明您毕竟是“ force [d]要单子”!确实没有逃脱monad的麻烦,所以也许最好学习如何高效地使用它们。
答案 1 :(得分:2)
如果您想过危险的生活,可以使用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!"
有时,编译器有权产生一个无限循环,而在其他时候,会产生错误消息,这违反了对纯度的基本要求。有理由使用看起来像这样的代码,但是需要格外小心才能使其表现良好。
答案 2 :(得分:2)
Control.Spoon
中的spoon package提供了mostly安全的包装程序,用于为此所需的不安全操作。
λ> spoon (head [1,2,3])
Just 1
λ> spoon (head [])
Nothing