2014-12-06 4 views
6

가끔 나는이 문제를 겪고 마침내 일반적인 해결책이나 패턴이 있는지 묻고 싶다. 중첩 된 컨텍스트 참조에서 유형 변수를 외부 컨텍스트의 유형으로 만들 수 있습니까? 예를 들어,Haskell 타입 변수 참조하기

foo :: a -> ... -> .. 
foo = ... 
    where bar :: a -> ... 

지금 bara는 foo는의 a 다릅니다. 일반적으로 이것이 내가 원하는 것이지만 때로는 삶을 어렵게 만들고, 그것들을 동일하게 만들어야합니다. 나는 더러운 트릭을 사용하여 유형 검사기가 과거에 두 검사기를 통합하도록했지만 가끔씩 방해를받습니다. 마침내이 질문에 대한 나의 최근 사례 (Parsec 함수)가 있습니다.

data Project = ... deriving Enum 
data Stuff = ... 

pProject :: Monad m => P m Stuff 
pProject = do 
    stuff <- pStuff 
    ... 
    convert stuff <$> pEnum :: P m Project 

pEnum :: (Monad m, Enum a) => String -> P m a 
pEnum = ... 

convert 기능은 그러므로 내가 주석 :: P m Project를 지정했다, 유형을 필요로했다. 그러나 그 뜻은 m을 소개해야한다는 뜻입니다. 불행히도 함수 시그니처와 같은 m이 아닙니다. 유형 검사 보고서 이와 :

상황 Monad m

에서 pEnum의 사용으로 인해 발생하는 Monad m1을 추론 할 수 없습니다 함수 서명의 m 못생긴 해킹없이 참조 할 수있는 방법이 있나요? (못생긴 해킹은 실행되지 않는 더미 코드를 삽입하는 것이지만 두 가지 유형을 통합하기 위해 존재합니다.)

답변

13

ScopedTypeVariables 확장자를 포함하면 범위를 포함하는 유형 변수를 참조 할 수 있습니다.

하위 호환성을 위해 forall 명시 적 형식 서명에만 적용됩니다. 그래서 당신이 작성해야 : 그 후

pProject :: forall m. Monad m => P m Stuff 

을, 당신은 pProject의 범위 내에서 변수가 올바른 유형 m를 참조 할 수있을 것입니다.

+5

'ScopedTypeVariables'는 명시 적으로'forall'을 가진 서명에만 적용된다는 것을 지적 해 주셔서 감사합니다. 전혀 작동하지 않는 것 같아서 이상한 일은 없을 것입니다 ... – Cirdec

+3

그건 완전히 사실입니다 -'ScopedTypeVariables'는 타입 변수가'forall'이 없어도 클래스 선언에서 범위를 만듭니다. 그래서 그것은 고의적 인 Haskell 2010 프로그램의 의미를 바꿀 수 있습니다. – shachaf