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
그래도 아무것도 잡지 못합니다. 간단한 테스트 케이스에서 :
safeMapM (\n -> return $ if n == 3 then error $ show n else n) [1,2,3,4,5]
다음과 같이 실패합니다.
*** Exception: 3
[1,2,"ghci>"
왜 잡히지 않습니까? 를 잡을 evaluate
만큼 충분히 평가하지 error
않습니까? 서명이 변경 될 필요없이이 주위에 방법이 있나요 safeMapM :: (NFData a, NFData b) => (a -> IO b) -> [a] -> IO [b]
및 사용은 deepseq
?
evaluate x
단지 평가 x
에 그걸 얻기 위해 충분히 WHNF , 그리고 Just x
심지어로 이미 WHNF에 x
완전히 평가되지 않은 썽크. 그래서 당신은 evaluate (Just x)
전혀 평가 x
를 포함하지 않는 을 가지고 있습니다 !
f x
함수 에 바인딩 하는 대신 다음과 같이로 래핑 하기 전에evaluate . Just
평가할 함수를 사용해야합니다 .x
Just
returnEval :: Monad m => a -> IO (m a)
returnEval x = evaluate x >>= return . return
이 함수를 사용하면 다음과 같이 평가 줄을 다시 작성할 수 있습니다.
appliedResult <- onException (f x >>= returnEval) (return Nothing)
그 변화로 인해 표현의 결과 [1,2,**exception**]
는 즉각적인 예외가됩니다. 다음 요점으로 넘어갑니다. onException
is not a "catch"block, it is more like finally like : "만약 문제가 발생하면이 코드를 실행하지만 두 경우 모두 첫 번째 표현식을 돌려주세요". catch
대신 사용하도록 변경 하면 마침내 시작하려는 동작으로 끝납니다 [1,2,4,5]
..
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
그러나 John L이 주석에서 말했듯이 이것은 여전히 최상위 수준의 예외 인 WHNF에 들어가는 데 필요한 예외 만 포착합니다. 중첩 된 전체 표현식에 대해 열심히 평가하려면 (아마도 그렇지 않을 수도 있음) deepseq와 같은 더 무딘 도구가 필요합니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다