2010-02-16 1 views
6

당신이 catches의 예를 보면 : catches은 패턴 (두 개의 예외 유형)에 맞게 사용자 정의 메커니즘을 정의 것처럼Haskell에서 사용자 지정 가드 메커니즘을 정의 할 수 있습니까?

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

것 같습니다. 나는 틀린가 아니면 특정 패턴에 일치하는 람다 함수를 취할 수있는 함수를 정의 할 수 있도록 일반화 할 수 있는가?

편집 : 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 

답변

5

이것은 직장에서 GHC 확장자 인 Scoped Type Variables입니다. 자세한 내용은 링크를 클릭하십시오.

기본적으로 일치시킬 수 있기 전에 패턴에 의해 충족되어야하는 유형에 대한 어설 션을 정의합니다. 그래서, 예, 그것은 경비원과 비슷하지만 완전히 그렇지는 않습니다.

이 예제가 어떻게 작동합니까?

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 

우리는 IOExceptionArithException가 typeclass Exception을 구현하는 여러 종류의 것을 참조하십시오 것을 알아 sources of "base" library으로 다이빙.

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

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

handleIO :: IOException -> IO() 
handleIO ex = .... 
: 우리는 또한 toException/fromException 하나는 유형 IOException, ArithException의 값에서 /로 유형 Exception의 값을 변환 할 수있는 포장/풀기 메커니즘 등, 우리가 작성한 수 있도록

는 것을 알

IOException이 발생한다고 가정 해보십시오. catchesHandler이 핸들러 목록의 첫 번째 요소를 처리 할 때 을 호출하는 tryHandler을 호출합니다. tryHandler의 정의에서 fromException의 리턴 유형은 handleArith의 인수와 같아야합니다. 반면에 e은 Exception 유형, 즉 - (IOException ...)입니다. 그래서, 유형 (이 유효한 하스켈하지 않습니다,하지만 난 당신이 내 포인트를 얻을 수 있기를 바랍니다)이 방법을 재생 :

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

를 즉시 결과가 Nothing 것을 다음에 instance Exception IOException ...에서, 그래서이 핸들러를 건너 뜁니다 . 동일한 이유에 의해 fromException(Just (IOException ...))을 돌려주기 때문에 다음 핸들러가 호출됩니다.

handleArithhandleIO의 형식 시그니처를 사용하여 각각이 호출 될시기를 지정하고 은 이러한 방식으로 문제가 발생했음을 확인했습니다.

원하는 경우 범위 형식 변수를 사용하여 f의 정의 안에 handleIOhandleArith의 제약 유형을 지정할 수도 있습니다. 아마, 이것은 당신에게 더 나은 가독성을 줄 수 있습니다.

마무리, 범위 형 변수는 여기에서 주요한 선수가 아닙니다. 그들은 단지 편의를 위해 사용됩니다. 이런 종류의 속임수를 사용하는 주요 기계는 fromException/toException과 친구들입니다. 범위 형 변수를 사용하면 가드 패턴과 더욱 유사한 구문을 사용할 수 있습니다.

+0

범위가 지정된 유형 변수는 어떤 방식으로 관련되어 있습니까? 나는이 메커니즘을 잡아 먹는 근원의 직장에서 보지 못한다. – me2

+0

toException/toException 트릭으로부터 설명하기 위해 업데이트 됨 – ADEpt

1
case() of 
()| foo expr1 -> handleFooCase 
    | bar expr2 -> handleBarCase 
    | otherwise -> blah