2014-10-15 3 views
0

mapM의 안전한 버전을 만들어 실행시 예외를 throw하는 경우 결과에서 요소를 제외하려고합니다.내 safeMapM은 예외를 catch하지 않습니다.

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 (\n -> return $ if n == 3 then error $ show n else n) [1,2,3,4,5] 

가 실패 : 간단한 테스트 케이스에? evaluateerror이 잡힐만큼 충분히 평가되지 않습니까? 서명을 safeMapM :: (NFData a, NFData b) => (a -> IO b) -> [a] -> IO [b]으로 변경하고 deepseq을 사용하지 않고이 문제를 해결할 방법이 있습니까?

+0

'evaluate'은 WHNF 만 평가합니다. 이 경우,'evaluate'을 호출하기 바로 전에 추가 한'Just' 래퍼입니다. 'Just'를 제거하고 그에 따라 함수를 수정하면이 오류를 잡아야합니다. 그래도 'deepseq'를 사용하지 않으면 모든 것을 포착하지 못합니다. –

+0

이것이 내가'error'와 다른 비동기 예외를 피하는 이유입니다. 그들은 잡기가 훨씬 더 어렵습니다. –

답변

1

evaluate xWHNF로를 얻을 충분히 x을 평가하고, Just xx 완전히 평가되지 않은 썽크에 WHNF 이미 사용 중입니다. 그래서 evaluate (Just x)이 있는데, x을 전혀 포함하지 않습니다!

대신 기능 evaluate . Justf x 바인딩, 당신은 전에 xJust에 포장 평가하는 함수,이 같은 것을 사용할 필요가 :이 기능을 사용

returnEval :: Monad m => a -> IO (m a) 
returnEval x = evaluate x >>= return . return 

을, 당신은 다시 작성할 수 있습니다 당신의 평가 라인은 이렇게 :

appliedResult <- onException (f x >>= returnEval) (return Nothing) 

그 변화와 함께, 당신의 표현의 결과는 [1,2,**exception**] 즉시 예외가 발생합니다. 다음 지점으로 우리를 데려다줍니다 : onException은 "catch"블록이 아니며 마침내 더 좋아집니다 : "문제가 발생하면이 코드를 실행하십시오. 그러나 두 경우 모두 첫 번째 표현식을 돌려주십시오". 이 값을 catch 대신 사용하도록 변경하면 결국 [1,2,4,5]과 같은 동작으로 끝납니다. WHNF에 도착하는 데 필요한 것들 :

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 

그러나 존 L이 코멘트에 말한대로,이 여전히 최상위 수준의 예외를 잡는다

. 중첩 된 표현식 전체를 열심히 평가하고 싶다면 deepseq와 같은 무딘 도구가 필요합니다.

관련 문제