我正在使用本身使用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
Run Code Online (Sandbox Code Playgroud)
现在,问题在于这只是一种形式.如果你在一个不是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
Run Code Online (Sandbox Code Playgroud)
到底是怎么回事?根据我在http://www.haskell.org/haskellwiki/Error_vs._Exception和其他地方所读到的内容,我应该捕获异常并将其转换为有用的东西. ie在我的代码可能是一个形实转换为BOOL,却怎么也运行seq在ie可能留下什么不计算?当我甚至无法弄清楚如何强制评估值时,我怎么可能捕获这样的异常?我没有时间进入zip-archive中进行正确的错误处理.
这里几乎没有问题.首先,要强制评估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)
Run Code Online (Sandbox Code Playgroud)
当然你知道isExcel只会回来True.您可以toExcel直接使用,并修改该either行以适应该行.
至于问题的根源,
a `seq` a
Run Code Online (Sandbox Code Playgroud)
是完全等同于a.这意味着,"在您评估时(第二次)a,评估(第一次)a".换句话说,它仍然太懒惰了.这就是你需要的原因evaluate.
| 归档时间: |
|
| 查看次数: |
128 次 |
| 最近记录: |