Exception 我的safeMapM赢了';我没有发现任何例外
我正在尝试创建一个安全版本的Exception 我的safeMapM赢了';我没有发现任何例外,exception,haskell,Exception,Haskell,我正在尝试创建一个安全版本的mapM,如果执行时抛出异常,它将从结果中排除元素 safeMapM :: (a -> IO b) -> [a] -> IO [b] safeMapM f [] = return [] safeMapM f (x : xs) = do restResult <- safeMapM f xs appliedResult <- onException (f x >>= evaluate . Just)
mapM
,如果执行时抛出异常,它将从结果中排除元素
safeMapM :: (a -> IO b) -> [a] -> IO [b]
safeMapM f [] = return []
safeMapM f (x : xs) = do
restResult <- safeMapM f xs
appliedResult <- onException (f x >>= evaluate . Just) (return Nothing)
case appliedResult of
Just x' -> return $ x' : restResult
Nothing -> return restResult
它失败于:
*** Exception: 3
[1,2,"ghci>"
为什么它没有被抓住?
评估
是否评估得不够充分,无法捕获错误
?有没有一种方法可以绕过这个问题,而不需要将签名更改为safeMapM::(NFData a,NFData b)=>(a->IO b)->[a]->IO[b]
,并使用deepseq
?评估x
只评估x
足够远的程度,以使其进入,而且x
已经在WHNF中,即使x
是一个完全未经评估的thunk。所以你有了evaluate(只是x)
,它根本不涉及x
的评估
而不是将fx
绑定到函数evaluate。Just
,您需要使用一个函数来计算x
,然后再将其包装为Just
,如下所示:
returnEval :: Monad m => a -> IO (m a)
returnEval x = evaluate x >>= return . return
使用该函数,您可以像这样重写求值行:
appliedResult <- onException (f x >>= returnEval) (return Nothing)
但正如John L在评论中所说,这仍然只捕获最高层的异常:进入WHNF所必需的异常。如果您真的想强制对整个嵌套表达式进行急切求值(您可能不想这样做),那么您需要一个更直截了当的工具,例如deepseq。
evaluate
仅计算WHNF。在本例中,这就是在调用evaluate
之前添加的包装器。删除只是
并相应地修改您的函数,它将捕获此错误。但是,如果不使用deepseq
,它仍然无法捕获所有内容。这就是我避免error
和其他异步异常的原因:它们更难捕获。
appliedResult <- onException (f x >>= returnEval) (return Nothing)
module SafeEval where
import Control.Exception
returnEval :: Monad m => a -> IO (m a)
returnEval x = evaluate x >>= return . return
safeMapM :: (a -> IO b) -> [a] -> IO [b]
safeMapM f [] = return []
safeMapM f (x : xs) = do
restResult <- safeMapM f xs
appliedResult <- catch (f x >>= returnEval) (\e -> (e :: SomeException) `seq` return Nothing)
case appliedResult of
Just x' -> return $ x' : restResult
Nothing -> return restResult