【问题标题】:How to handle invalid value exception in haskell and keep running如何处理haskell中的无效值异常并继续运行
【发布时间】:2020-09-10 12:10:56
【问题描述】:

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

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

  • 变换 (fn x => 15 div x) [1,3,0,5] -------------------- val it = [15,5, 0,3] : 整数列表

当谈到 haskell 中的异常处理时,我真的很困惑,我不明白。 我已经编写了这个基本代码,但它必须适应异常处理程序。

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]

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

我已经阅读了文档,上面写着:

如果您想在出现异常的情况下进行一些清理 引发,使用 finally、括号或 onException。恢复后 例外并做其他事情,最好的选择是使用其中之一 尝试家庭。 ...除非您正在从异步中恢复 异常,在这种情况下使用 catch 或 catchJust。

所以我猜我最好的选择可能是使用 try 或 catch 语句? 但我不太确定如何编写/组织它。

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

【问题讨论】:

  • 这个练习从何而来?它要求您做的事情并不是您在 Haskell 中真正应该做的事情。
  • 它的练习取自《编程语言基础》,第二版,第 5 章(专门针对函数式语言的那一章)。只是它是为标准 ML 设计的,我们被要求使用 haskell 来代替
  • 类型必须是(a -> a) -> [a] -> [a],还是至少可以是(a -> a) -> [a] -> IO [a]?
  • 顺便说一句,如果你被零除,Haskell 将抛出的错误不会是你的MyError 类型。
  • 我不知道标准 ML 是如何做到的,但是在 Haskell 中封装错误的一种常见方法是使用 Maybe 类型。您将创建您的函数transform :: (a -> Maybe a) -> [a] -> [a],它的第一个参数将通过返回Nothing 来指示“异常”。这样你就不必将它放在IO 中,因为大多数“异常”都可以在没有IO 的情况下使用Maybe 之类的东西被抛出和处理(编写函数safeDiv :: Int -> Int -> Maybe Int 可能是一个值得练习的练习)当div 出错时返回Nothing)。

标签: haskell exception io


【解决方案1】:

你被要求做的不是你应该做的。但是,如果我真的不得不写一个函数来处理异常而不是在 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 更细微的东西)。

【讨论】:

  • 我会马上研究这个替代方案!非常感谢。
猜你喜欢
  • 1970-01-01
  • 2011-12-09
  • 2019-09-05
  • 1970-01-01
  • 2015-01-03
  • 1970-01-01
  • 2013-11-03
  • 2015-07-26
  • 1970-01-01
相关资源
最近更新 更多