绝对强制在Haskell中捕获错误

 nlyyan_613 发布于 2023-02-03 09:38

我正在使用本身使用zip-archive的hs-excelx库.zip-archive正在达到它调用的条件fail,在该特定上下文中,它会计算为对其的调用error.这是对error纯代码的调用.

我正在尝试检测特定文件是否实际上是Excel文件.实际上我必须在不崩溃的情况下检测到这一点,所以我编写了一个名为isExcel的函数来进行检测:

import qualified Data.Excelx as E

isExcel :: BS.ByteString -> Bool
isExcel = maybe False (\_ -> True) . E.toExcelx

现在,问题在于这只是一种形式.如果你在一个不是zip存档的字节串上调用E.toExcelx,那么zip-archive就会error出来.

但是,我知道我正在调用isExcelIO代码,所以我编写了一个IO函数来尝试捕获这样的错误:

import qualified Data.ByteString.Lazy as BS
import Control.Exception

sd :: BS.ByteString -> IO Bool
sd bs = handle handler $ do
        ie <- return $ Excel.isExcel bs
        return (ie `seq` ie)
    where
    handler :: SomeException -> IO Bool
    handler e = return False

> sd BS.empty
*** Exception: too few bytes. Failed reading at byte position 4

到底是怎么回事?根据我在http://www.haskell.org/haskellwiki/Error_vs._Exception和其他地方所读到的内容,我应该捕获异常并将其转换为有用的东西. ie在我的代码可能是一个形实转换为BOOL,却怎么也运行seqie可能留下什么不计算?当我甚至无法弄清楚如何强制评估值时,我怎么可能捕获这样的异常?我没有时间进入zip-archive中进行正确的错误处理.

1 个回答
  • 这里几乎没有问题.首先,要强制评估IO中的值,请使用Control.Exception.evaluate.这个函数有类型evaluate :: a -> IO a,它基本上是一个钩子,告诉编译器强制进行评估.它存在的唯一原因是启用异常处理.

    接下来,您需要一些机制来实际捕获异常.您目前正在使用handle,但是Control.Exception.try,具有该类型try :: Exception e => IO a -> IO (Either e a),可能在这里使用起来有点简单.这种类型有点奇怪,但这意味着,对于您指定的某些异常类型,它将try返回值或异常.如果评估引发的异常不是您指定的类型(并且无法强制转换),try则会重新抛出异常.

    调用error产生类型的异常ErrorCall,以便处理您可以使用的异常

    sd :: BS.ByteString -> IO Bool
    sd bs = do
            ie <- try $ evaluate $ Excel.isExcel bs
            either (const False) (id) (ie :: Either ErrorCall Bool)
    

    当然你知道isExcel只会回来True.您可以toExcel直接使用,并修改该either行以适应该行.

    至于问题的根源,

    a `seq` a
    

    完全等同a.这意味着,"在您评估时(第二次)a,评估(第一次)a".换句话说,它仍然太懒惰了.这就是你需要的原因evaluate.

    2023-02-03 09:44 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有