문제

예제를 보면 catches:

 f = expr `catches` [Handler (\ (ex :: ArithException) -> handleArith ex),
                     Handler (\ (ex :: IOException)    -> handleIO    ex)]

보입니다 catches 패턴 (두 가지 예외 유형)과 일치하는 사용자 정의 메커니즘을 정의했습니다. 내가 착각 했습니까, 아니면 특정 패턴과 일치하는 람다 함수를 취할 수있는 함수를 정의 할 수 있도록 일반화 될 수 있습니까?

편집 : FYI 아래는 캐치의 GHC 소스입니다. 누군가가 이것이 어떻게 작동하는지에 대해 약간의 빛을 발할 수 있다면 그것은 좋을 것입니다.

catches :: IO a -> [Handler a] -> IO a
catches io handlers = io `catch` catchesHandler handlers

catchesHandler :: [Handler a] -> SomeException -> IO a
catchesHandler handlers e = foldr tryHandler (throw e) handlers
    where tryHandler (Handler handler) res
              = case fromException e of
                Just e' -> handler e'
                Nothing -> res
도움이 되었습니까?

해결책

이것이 스코프 형 유형 변수 직장에서의 GHC 확장. 자세한 내용은 링크를 따르십시오.

기본적으로, 당신은 패턴이 일치하기 전에 충족 해야하는 유형에 대한 어설 션을 정의합니다. 그렇습니다. 경비원과 유사하지만 완전히 그렇지는 않습니다.

이 특정 예는 어떻게 작동합니까? 로 뛰어 들어라 "기본"라이브러리의 출처 그것을 알아 보려면 :

class (Show e) => Exception e where
    toException   :: e -> SomeException
    fromException :: SomeException -> Maybe e

data SomeException = forall e . Exception e => SomeException e

instance Exception IOException where
    toException = IOException
    fromException (IOException e) = Just e
    fromException _ = Nothing

instance Exception ArithException where
    toException = ArithException
    fromException (ArithException e) = Just e
    fromException _ = Nothing

우리는 그것을 봅니다 IOException 그리고 ArithException 타입 클래스를 구현하는 다른 유형입니다 Exception. 우리는 또한 그것을 봅니다 toException/fromException 유형 값을 변환 할 수있는 포장/포장 메커니즘입니다. Exception 유형 값으로/ IOException, ArithException, 등.

그래서 우리는 다음을 쓸 수있었습니다.

f = expr `catches` [Handler handleArith,
                    Handler handleIO]

handleArith :: ArithException -> IO ()
handleArith ex = ....

handleIO :: IOException -> IO ()
handleIO ex = ....

한다고 가정 IOException 발생합니다. 언제 catchesHandler 핸들러 목록의 첫 번째 요소를 처리하고 호출합니다. tryHandler, 전화 fromException. 정의에서 tryHandler 그것은 그 반환 유형의 다음을 따릅니다 fromException 논쟁과 동일해야합니다 handleArith. 반면에, e 유형 예외, 즉 - (ioException ...)입니다. 따라서 유형이 이런 식으로 재생됩니다 (이것은 유효한 Haskell은 아니지만 내 요점을 얻기를 바랍니다).

fromException :: (IOException ...) -> Maybe ArithException

로부터 instance Exception IOException ... 결과가 즉시 뒤 따릅니다 Nothing, 이 처리기가 건너 뜁니다. 같은 추론으로 다음 핸들러가 호출 될 것입니다. fromException 돌아올 것입니다 (Just (IOException ...)).

따라서 유형의 서명을 사용했습니다 handleArith 그리고 handleIO 각각이 호출 될 때를 지정하고 fromException/toException 이런 식으로 일어 났는지 확인했습니다.

원한다면 제약 유형의 handleIO 그리고 handleArith 정의 내부 f, 스코프 유형 변수 사용. 아마도 이것은 더 나은 가독성을 줄 수 있습니다.

마무리, 범위의 유형 변수는 여기서 주요 플레이어가 아닙니다. 그들은 편의를 위해 사용됩니다. 이런 종류의 트릭을 연주하는 주요 기계는입니다 fromException/toException 그리고 친구들. 스코핑 된 유형 변수는 가드 패턴과 더 유사한 구문을 가질 수 있습니다.

다른 팁

case () of 
  ()| foo expr1 -> handleFooCase
    | bar expr2 -> handleBarCase
    | otherwise -> blah
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top