代码之家  ›  专栏  ›  技术社区  ›  nicolas

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

  •  0
  • nicolas  · 技术社区  · 5 年前

    它可能被要求处死,但有人知道最不具侵入性的“捕捉”方式吗

    catch
    :: Exception e   
    => IO a 
    -> (e -> IO a)  
    -> IO a
    

    “纯”中的错误 haskell 计算?

    (例如,某些代码包含 head []

    PS:当然,如果你能并且想从头开始设计, 一定要把它烤进去 (带有一个可能的类型)。这里的问题是,我是知情的 希望

    3 回复  |  直到 4 年前
        1
  •  7
  •   Rein Henrichs    5 年前

    没有办法使用 catch 在纯代码中。这是出于设计:异常由IO系统处理。这就是为什么 使用 IO

    Maybe . 是一个例子 Monad ,所以它是“一元的”,但这不应阻止您将其用于预期目的。所以你想要的功能是 headMay 安全 包裹: headMay :: [a] -> Maybe 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
    

    不幸的是,函数是

        2
  •  3
  •   dfeuer    5 年前

    如果你想生活在危险之中,你可以使用 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!"
    

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

        3
  •  2
  •   Anders Kaseorg    5 年前

    Control.Spoon spoon package 提供 mostly -安全包装,用于包装此操作所需的不安全操作。

    λ> spoon (head [1,2,3])
    Just 1
    λ> spoon (head [])
    Nothing