2012-02-15 4 views
5

질문. 명시 적 형식 서명없이이 코드를 작동시키는 방법이 있습니까?GHC 유형 추론 재발

코드. 첫째, 실제로 연습중인 훨씬 더 좋은 대체물 MonadTrans을 가지고 있는데, 이는 Data.Newtype에서 영감을 받았습니다. 그것은 내가 방법 foo와 클래스 A 있고, 일부 기본 모나드 MA 경우, 다음 어떤 변화 모나드 T M 또한 A이다, 그런 다음, 다음과 같이

{-# LANGUAGE FlexibleContexts, TypeFamilies #-} 

module Alt.Control.Monad.Trans where 

import Control.Monad 

class (Monad , Monad (BaseMonad)) => MonadTrans (:: * -> *) where 
    type BaseMonad :: * -> * 
    lift :: (BaseMonad) α -> α 

보인다. 지금 교체의 첫 번째 인수로 foo에 대한 바로 가기를 만들려면 코드에서

class A where 
    foo :: String -> () 

instance (A (BaseMonad), MonadTrans) => A where 
    foo n = lift $ foo n 

그러나, 나는이 명시 적 타입 서명, 또는 컴파일러의 컨텍스트 스택 오버 플로우가 필요합니다.

minimize_call :: A => () 
minimize_call = foo "minimize" 

가능한 정보는 추론를 도움이됩니다. 연결된 유형이 B :: * -> *이라고 가정 해 보겠습니다. 나는 컴파일러에게 BB t /= t, B (B t) /= B t 등을 만족 시키려고한다고 생각하고있다. 즉 B은 "단조롭다"- 연관된 유형을 추적하는 것은 newtype 래퍼를 제거하는 것과 동일하며, newtype 래퍼를 영원히 제거 할 수 없다는 것을 알아야한다. 따라서 서명에 컨텍스트 A을 추가해야합니다.

+0

죄송합니다. 나는 대체 MonadTrans로 전환했음을 기억해야합니다. 지금은 더 깨끗한 코드를 생성한다고 가정 해 봅시다. 그러나 더 중요한 이유가 있다고 생각합니다. – gatoatigrado

+0

흥미로운 질문입니다. 그래도 명백한 형식 서명을 원하십니까? 'minimize_call'은 다형성 상수가 아닌 고정 값이어야합니다 (아니면 다형성이 될 수 있습니다, 확실하지 않습니다)? 고정 된 단일 유형이있는 경우 그 사실을 문서로 작성하고, 그렇지 않은 경우에는 ** 그 문서 **를 작성합니다. 독자가 자신의 머리에서 전체 프로그램 분석을 수행하여'minimize_call '유형이 다소 비생산적인 것으로 파악되는지 확인하십시오. – Ben

+0

@Ben,이 경우에는'minimize_call'에 대한 타입 서명을하는 것이 좋은 습관입니다.그러나 형식 유추가 끊어진다는 것은 컴파일러에 대한 디자인, 컴파일러 또는 통신과 관련하여 문제가 발생했음을 나타내며, 알 수없는 오류 메시지는 말할 것도없고 문제를 일으킬 수 있습니다. – gatoatigrado

답변

3

예, 방법이 있습니다. A에 대해 접지 된 인스턴스를 제공하고 및 UndecidableInstances과 함께 을 언어 pragma에 추가하십시오.

그러나 A 클래스는 사용할 수 없습니다. 컴파일러가 인스턴스가 BaseMonad m = m과 함께 존재하지 않음을 알 수있는 방법이 없습니다. 따라서 여기 또는 다른 인스턴스를 사용할 것인지 여부를 알 수 없기 때문에 인스턴스를 선택할 수 없습니다.

{-# LANGUAGE FlexibleContexts, TypeFamilies, FlexibleInstances, UndecidableInstances, NoMonomorphismRestriction #-} 

module Trans (MonadTrans(..), A(..), minimize_call) where 

import Control.Monad 

class (Monad m, Monad (BaseMonad m)) => MonadTrans (m :: * -> *) where 
    type BaseMonad m :: * -> * 
    lift :: (BaseMonad m) α -> m α 

class A m where 
    foo :: String -> m() 


data Foo a = Bork 

instance Monad Foo where 
    return _ = Bork 
    _ >>= _ = Bork 

instance A Foo where 
    foo _ = Bork 


instance (A (BaseMonad m), MonadTrans m) => A m where 
    foo n = lift $ foo n 

-- minimize_call :: A m => m() 
minimize_call = foo "minimize" 

은 ghc 6.12, 7.0, 7.2 및 7.4로 컴파일됩니다. 서명이 없으면 minimize_call은 MR이 꺼져 있지 않으면 모노 형식 유형을 가져야합니다. A m 제약 조건이 기본값이 아니기 때문에 어쨌든 작동하지 않습니다. 따라서 MR을 꺼야합니다. 그러나 유형 검사기는 제약 조건이 만족 스러운지를 입증하기 위해 자체 꼬리를 추적합니다. 리프팅 인스턴스만으로는 불가능합니다. 앵커를 제공하면 할 수 있습니다.

그러나 형식 서명을 제공하는 것이 훨씬 더 좋습니다.

+0

고마워요.하지만 모듈에 접지 된 인스턴스는 필요 없습니다. 사실 컴파일러에 대한 백엔드의 수에 따라 여러 개의 접지 된 인스턴스가있을 수 있으며 특정 하나의 인스턴스를 사용하는 것이 바람직하지 않다고 가정합니다. 이미 FlexibleInstances, FlexibleContexts 및 NoMonomorphismRestriction이 켜져 있습니다. – gatoatigrado

+1

수출되지 않은 더미 모나드를 사용할 수 있습니다 (업데이트 참조). 'minimize_call'의 유추 된 타입은'A m => m()'입니다. 다른 곳에서 다른 접지 된 인스턴스를 사용하는 것을 배제하지 않습니다. 타입 검사기를 종료시키는 것만으로도 충분합니다. –

+0

실제로'minimize_call'이나'foo'를 전혀 사용할 수 없습니다. 형식 서명이 있거나 없거나. –