I'm trying to make a safe version of mapM
that will exclude an element from the result if it throws an exception when executed.
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
It fails to catch anything though. In a simple test case:
safeMapM (\n -> return $ if n == 3 then error $ show n else n) [1,2,3,4,5]
it fails with:
*** Exception: 3
[1,2,"ghci>"
Why isn't it being caught? Does evaluate
not evaluate it fully enough for the error
to be caught? Is there a way around this without requiring that the signature be changed to safeMapM :: (NFData a, NFData b) => (a -> IO b) -> [a] -> IO [b]
, and using deepseq
?