Exception 绝对强制捕获Haskell中的错误

Exception 绝对强制捕获Haskell中的错误,exception,haskell,Exception,Haskell,我使用的是hs excelx库,它本身使用zip存档。zip存档正在达到调用fail的条件,在该特定上下文中,其计算结果为调用error。这是对纯代码中的error的调用 我试图检测某个特定文件是否实际上是Excel文件。实际上,我有必要在不崩溃的情况下检测到这一点,因此我编写了一个名为isExcel的函数来进行检测: import qualified Data.Excelx as E isExcel :: BS.ByteString -> Bool isExcel = maybe Fa

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

我试图检测某个特定文件是否实际上是Excel文件。实际上,我有必要在不崩溃的情况下检测到这一点,因此我编写了一个名为isExcel的函数来进行检测:

import qualified Data.Excelx as E

isExcel :: BS.ByteString -> Bool
isExcel = maybe False (\_ -> True) . E.toExcelx
现在,问题是这只是一种形式。如果您在不是zip存档的bytestring上调用E.toExcelx,zip存档将简单地
error
out

但是,我知道我正在IO代码中调用
isExcel
,所以我编写了一个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
将限定数据.ByteString.Lazy导入为BS
导入控制。异常
sd::BS.ByteString->IO Bool
sd bs=句柄处理程序$do
伊奥布尔
handler e=返回False
>sd-BS.empty
***例外:字节太少。在字节位置4读取失败

发生了什么事?根据我在和其他地方读到的内容,我应该捕获异常并将其转换为有用的内容<在我的代码中,code>ie可能是对Bool的猛击,但是在
ie
上运行
seq
怎么可能会留下任何未评估的内容呢?当我甚至不知道如何强制计算一个值时,我怎么可能捕获这样的异常?我没有时间进入zip存档并对错误进行适当的处理。

这里几乎没有什么问题。首先,要强制计算IO中的值,请使用
Control.Exception.evaluate
。此函数的类型为
evaluate::a->ioa
,它基本上是一个钩子,用于告诉编译器强制执行求值。它存在的唯一原因是启用异常处理

接下来,您需要一些机器来实际捕获异常。您当前使用的是
handle
,但是
Control.Exception.try
,其类型为
try::Exception e=>ioa->IO(ea)
,在这里使用起来可能要简单一些。这种类型有点奇怪,但它意味着,对于您指定的某个异常类型,它
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)

完全等同于
a
。它的意思是,“在计算(第二个)
a
时,也要计算(第一个)
a
”。换句话说,它还是太懒了。这就是为什么您需要
评估

您是否尝试过使用bang模式绑定
ie
或严格的
$?我相信有一些情况下,
seq
没有正确地将值完全计算到NF,但我对它的了解不够,无法在这些情况下正确地进行评论。我在一些地方尝试了bang模式,但还没有发现它改变了我代码中任何内容的情况。我搜索文档已有几个月了。我甚至读过严格的io库。我以前从未发现或看到过对它的引用。在IO评估中需要非常严格,这一点很常见,为什么在文档中没有得到更高的重视?我不知道为什么没有更突出地提到它,尽管我认为这是因为现在的最佳实践建议避免纯代码中的异常。此外,从技术上讲,可以通过
seq
获得您想要的严格性,但不是您使用它的方式。
a `seq` a