2011-12-16 4 views
11

유형 - 클래스와 장난이 작동하지 않습니다Typeclass 인스턴스 내가이 잘, 예를 작동하는 것 같다 겉으로는 결백</p> <pre><code>class Pair p a | p -> a where one :: p -> a two :: p -> a </code></pre> <p>함께했다

instance Pair [a] a where 
    one [x,_] = x 
    two [_,y] = y 

그러나 튜플에 문제가 있습니다. 다음과 같은 정의가 컴파일 비록 내가 예상대로 ...

instance Pair (a,a) a where 
    one p = fst p 
    two p = snd p 

... 나는 그것을 사용할 수 없습니다 제대로 인스턴스를 정의하는 방법은

main = print $ two (3, 4) 

No instance for (Pair (t, t1) a) 
    arising from a use of `two' at src\Main.hs:593:15-23 
Possible fix: add an instance declaration for (Pair (t, t1) a) 
In the second argument of `($)', namely `two (3, 4)' 
In the expression: print $ two (3, 4) 
In the definition of `main': main = print $ two (3, 4) 

있습니까? 아니면 newtype 래퍼에 의존해야합니까?

답변

18

인스턴스가 실제로 잘 작동합니다. 관찰 :

main = print $ two (3 :: Int, 4 :: Int) 

이것은 예상대로 작동합니다. 그렇다면 형식 주석이 없으면 왜 작동하지 않습니까? 음, 튜플의 타입을 고려해보십시오 : (3, 4) :: (Num t, Num t1) => (t, t1). 숫자 리터럴은 다형성이므로 은 동일한 유형 인이 필요하지 않습니다. 인스턴스가 (a, a)에 대해 정의되었지만 해당 인스턴스의 존재로 인해 다양한 유형의 합리적인 이유로 GHC에 유형을 통일하도록 지시하지 않습니다. GHC가 두 가지 유형이 동일하다는 것을 다른 방법으로 추론 할 수없는 한, 일 수 있더라도 원하는 인스턴스를 선택하지 않습니다.

위와 마찬가지로 문제를 해결하기 위해 유형 주석을 추가 할 수 있습니다. 인수가 다른 곳에서 오는 경우에는 대개 동일한 유형으로 알려져 있기 때문에 일반적으로 불필요하지만 숫자 리터럴을 사용하려는 경우 신속하게 서툴러집니다.

대체 솔루션으로 인해 인스턴스 선택 (a, a)에 대한 인스턴스를 가지고, 어떻게 작동하는지, 점에 유의하는 것입니다 당신은뿐만 아니라 당신이 원하더라도 (a, b) 같은 인스턴스를 쓸 수 있다는 것을 의미한다. 그래서 우리는이 같은 종류의 클래스를 사용하여 통일을 강제로, 조금 속이 수 있습니다 다음 ~ 컨텍스트에 대한 TypeFamilies 확장을 필요로

instance (a ~ b) => Pair (a,b) a where 

을, 나는 생각한다. 인스턴스 선택은 컨텍스트를 무시하기 때문에 처음에는 인스턴스를 모든 튜플에서 일치시킬 수 있습니다. 그러나 인스턴스를 선택한 후에는 a ~ b 컨텍스트가 유형 평등을 선언합니다.이 같음은 서로 다르지만 더 중요한 것은 여기에서 가능한 경우 형식 변수를 통합합니다. 이것을 사용하면 주석이없는 main의 정의가있는 그대로 작동합니다.

+0

감사합니다. – Landei

6

문제는 숫자가 다형성 유형이라는 점입니다. 두 개의 리터럴 모두 동일한 유형 (Int)을 가져야하는 것은 유형 검사기에 분명하지 않습니다. 튜플에 다형성이 아닌 무언가를 사용한다면 코드가 작동해야합니다. 다음 예를 고려해보십시오.

*Main> two (3,4) 

<interactive>:1:1: 
    No instance for (Pair (t0, t1) a0) 
     arising from a use of `two' 
    Possible fix: add an instance declaration for (Pair (t0, t1) a0) 
    In the expression: two (3, 4) 
    In an equation for `it': it = two (3, 4) 
*Main> let f = id :: Int -> Int -- Force a monomorphic type 
*Main> two (f 3,f 4) 
4 
*Main> two ('a','b') 
'b' 
*Main> two ("foo","bar") 
"bar" 
*Main> two (('a':),('b':)) "cde" 
"bcde" 
*Main>