如何处理 haskell 中的无效值异常并继续运行



我正在尝试实现这个练习,但在 Haskell 中

编写一个称为转换的高阶函数,该函数应用相同的函数 函数,以将其转换为新值的列表的所有元素。 但是,如果在转换 列表,则应使用给定列表中的原始值。为 实例

  • 变换 (fn x => 15div x( [1,3,0,5] -------------------- val it = [15,5,0,3] : int list

当涉及到哈斯克尔的异常处理时,我真的很困惑,我不明白。 我有我编写的这个基本代码,但它必须适应与异常处理程序一起使用。

import Control.Exception
import System.Environment  
import System.IO
data MyError = Error deriving Show
Instance Exception MyError
transform :: (a -> a) -> [a] -> [a] 
transform f [] = []
transform f (x:xs)  = [f x] ++ transform f [xs]

关于如何抛出和捕获此特定异常,我有几个问题,以便程序不会因此而停止其处理链。

我已经阅读了文档,其中说:

如果要在出现

异常时进行一些清理 提出,最后使用,括号或异常。在 例外并做其他事情,最好的选择是使用 尝试家庭。...除非您正在从异步恢复 例外,在这种情况下,使用 catch 或 catchJust。

所以我猜我最好的选择可能是使用尝试或捕获语句? 但我真的不确定如何编写/组织它。

我真的是函数式编程的新手,非常感谢所有有助于更好地理解这个问题。

你被要求做的事情不是你应该做的事情。但是,如果我真的必须编写一个由于某种原因处理异常而不在 IO 中的函数,我会安装spoon然后编写以下内容:

import Control.Spoon (teaspoon)
import Data.Maybe (fromMaybe)
transform :: (a -> a) -> [a] -> [a]
transform f = map $ x -> fromMaybe x . teaspoon $ f x

如果没有第三方库,您可以改为编写以下内容:

{-# LANGUAGE ScopedTypeVariables #-}
import Control.Exception (catch, evaluate, SomeException)
import System.IO.Unsafe (unsafePerformIO)
transform :: (a -> a) -> [a] -> [a]
transform f = map $ x -> unsafePerformIO $ evaluate (f x) `catch` (_ :: SomeException) -> pure x

为了强调:我不乐意看到其中任何一个在生产中完成,主要是由于unsafePerformIO(teaspoon内部使用(。但是,如果您被允许将结果放在IO中,那么第二种解决方案(但没有unsafePerformIO(是可以接受的(尽管捕获异步异常也很糟糕,因此您需要比SomeException更细微的东西(。