如何在没有monad的纯haskell代码中捕获错误

nic*_*las 0 haskell

它可能被要求死亡,但任何人都会知道"抓住"的最少侵入性方式

catch
:: Exception e   
=> IO a 
-> (e -> IO a)  
-> IO a
Run Code Online (Sandbox Code Playgroud)

"纯" haskell计算中的错误?

(比方说,一些包含head []但不安全的代码,我不想让它变为真实的,也不会强制为monadic)

Rei*_*chs 6

没有办法catch在纯代码中使用.这是设计使然:异常由IO系统处理.这就是为什么类型catch的用途IO.如果要在纯代码中处理失败,则应使用类型来表示失败的可能性.在这种情况下,失败的是有时可能不存在该值.

我们在Haskell中使用的类型表示可以存在或不存在的值Maybe.Maybe是一个实例Monad,所以它是"monadic",但这不应该阻止你将它用于其预期目的.所以你想要的功能headMay来自安全包:headMay :: [a] -> Maybe a.

也就是说,如果你想避免使用monads,你可以使用一个解包列表的函数:

listElim :: b -> (a -> [a] -> b) -> [a] -> b
listElim nil _ [] = nil
listElim _ cons (x:xs) = cons x xs
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,这取代了[]使用nil:与一个呼叫cons.现在,您可以编写一个安全的头,可以指定默认值:

headDef :: a -> [a] -> a
headDef def = listElim def const
Run Code Online (Sandbox Code Playgroud)

不幸的是,函数是一个实例Monad,所以事实证明你毕竟是"强迫[d]成为monadic"!真的没有逃脱monad,所以也许更好地学习如何有效地使用它们.


dfe*_*uer 3

如果你想危险地生活,你可以使用unsafePerformIO

catch'Pure'
  :: Exception e   
  => a 
  -> (e -> a)
  -> a
catch'Pure' v h = unsafePerformIO $
  evaluate v `catch` (pure . h)
Run Code Online (Sandbox Code Playgroud)

问题是这根本不能保证行为良好。例如,如果您将值传递给它

(let a = a in a) `seq` error "hallo!"
Run Code Online (Sandbox Code Playgroud)

编译器有权有时产生无限循环,有时产生错误消息,这违反了纯度的基本期望。使用看起来像这样的代码是有原因的,但需要非常小心才能使其表现良好。