2017-04-07 2 views
0

매개 변수화 된 타입 클래스를 사용하고 싶습니다. 컴파일에서하스켈 타입 클래스의 모호한 타입

class (CContext3D c k v) => CBuilder3D c a k v where 
    build3D :: c -> a -> String -> HSL HLangJS HLangJS 

나는 다음과 같은 오류가 나타날 수 있습니다 :

Could not deduce (CBuilder3D c a k0 v0) 
from the context: CBuilder3D c a k v 
bound by the type signature for: 
    build3D :: CBuilder3D c a k v => 
           c -> a -> String -> HSL HLangJS HLangJS 

다음 코드는 제대로 작동 :

class (CContext3D c KeyContext3D String) => CBuilder3D c a where 
    build3D :: c -> a -> String -> HSL HLangJS HLangJS 

이 가능 클래스의 인스턴스를 해제하는 방법을 아래에 내 소스 코드 k 및 v 유형에 따라 다릅니 까?

답변

2

build3D에 대한 호출이 있다고 가정합니다. 호출의 컨텍스트에서 컴파일러는 적절한 인스턴스를 찾아야합니다. 여기에는 변수 c a k v에 대한 값을 찾는 작업이 포함됩니다. 그러나 build3D 유형은 k v을 언급하지 않으므로 찾을 수 없습니다.

보다 구체적으로, 우리가 가진 경우

instance CBuilder3D c a K1 V1 where ... 
instance CBuilder3D c a K2 V2 where ... 

자신의 관련 build3D 기능은 정확히 같은 종류의 것, 그리고 컴파일러는 그 중 하나를 선택 할 수있는 방법이 없습니다.

가능한 해결책 :

가능하다면, 당신은 kv의 값이 다른 매개 변수에 의해 결정됩니다한다는 것은 함수 종속 또는 유형의 가족을 사용해야합니다. 이는 특정 클래스에 따라 다를 수도 있고 그렇지 않을 수도 있습니다.

그렇지 않으면 AllowAmbiguousTypesTypeApplications을 사용하고 모호한 유형을 유지하십시오. 그러나 모든 호출에서 build3D @t1 @t2 @t3 @t4 x1 x2 x3과 같이 명시 적으로 해당 유형을 지정해야합니다. 여기서 t1,...은 모든 변수 c a k v의 유형입니다. 그리 대단히 편리하지 않습니다.

또 다른 옵션은 프록시와 유형에 표시 k,v을하는 것입니다

import Data.Proxy 

class (CContext3D c k v) => CBuilder3D c a k v where 
    build3D :: proxy k -> proxy v -> c -> a -> String -> HSL HLangJS HLangJS 

이제 각각의 호출은 build3D (Proxy :: Proxy K1) (Proxy :: Proxy V1) x1 x2 x3과 같이해야한다.