2010-04-08 14 views
2

나는 하스켈 타입 클래스와 형 가족 (계속)

나는 다음과 같은 종류의 클래스가 ... 정말 날 미치게하는 컴파일러 오류를 계산에 약간의 도움이 필요합니다 :

infixl 7 --> 
class Selectable a s b where 
    type Res a s b :: * 
    (-->) :: (CNum n) => (Reference s a) -> (n,(a->b),(a->b->a)) -> Res a s b 

을 두 번 인스턴스. 처음 마법처럼 간다 : 유형 검사는

(-->) :: Reference s a -> (n,a->b,a->b->a) -> Reference s b 

을 유추이 서명의 클래스 서명이 일치하기 때문에

instance Selectable a s b where 
    type Res a s b = Reference s b 
    (-->) (Reference get set) (_,read,write) = 
     (Reference (\s -> 
         let (v,s') = get s 
         in (read v,s')) 
        (\s -> \x -> 
         let (v,s') = get s 
          v' = write v x 
          (_,s'') = set s' v' 
         in (x,s''))) 

- 이제

Res a s b = Reference s b 

이후 (>) I 두 번째 인스턴스를 추가하면 모든 것이 손상됩니다.

instance (Recursive a, Rec a ~ reca) => Selectable a s (Method reca b c) where 
    type Res a s (Method reca b c) = b -> Reference s c 
    (-->) (Reference get set) (_,read,write) = 
    \(x :: b) -> 
     from_constant(Constant(\(s :: s)-> 
          let (v,s') = get s :: (a,s) 
           m = read v 
           ry = m x :: Reference (reca) c 
           (y,v') = getter ry (cons v) :: (c,reca) 
           v'' = elim v' 
           (_,s'') = set s' v'' 
           in (y,s''))) :: Reference s c 
Couldn't match expected type `Res a s (Method reca b c)' 
     against inferred type `b -> Reference s c' 
The lambda expression `\ (x :: b) -> ...' has one argument, 
which does not match its type 
In the expression: 
    \ (x :: b) 
     -> from_constant (Constant (\ (s :: s) -> let ... in ...)) :: 
      Reference s c 
In the definition of `-->': 
    --> (Reference get set) (_, read, write) 
      = \ (x :: b) 
       -> from_constant (Constant (\ (s :: s) -> ...)) :: Reference s c 

신중하게 컴파일러가이 유형 추론 것을 나에게 말하고 읽는 것을

컴파일러는 불평 (->)를 thusly 히 : 올바른

(-->) :: Reference s a -> (n,a->(Method reca b c),a->(Method reca b c)->a) -> (b -> Reference s c) 

Res a s (Method reca b c) = b -> Reference s c 
이후

하지만 두 정의와 일치하지 않는 이유는 무엇입니까?

더 간결하고 독립 예제를 제공하지 않는,하지만이 경우에 당신이 당신이 말하는

instance Selectable a s b where 

을 쓸 때 ... 그 방법

+2

완전한 실행 가능한 예제를 제공 할 수 있습니까? 즉 '참조'는? 심지어'{- # LANGUAGE TypeFamilies # -}'를 포함합니다.다른 사람들이 당신을 도울 수 있도록 도와주는 이모. – yairchu

+0

그것은 엄청 거대합니다. 이것은 단지 전체적으로 게시 할 수없는 훨씬 더 큰 프로젝트의 일각입니다. ( –

답변

4

을 알아낼 수 없습니다 죄송합니다 어떤 그 유형의 조합은 선택 가능의 인스턴스입니다. 이로 인해 다른 인스턴스를위한 공간이 남지 않습니다.

확실한 특정 컴파일러 확장을 사용하면 더 많은 (필연적으로 상충되는) 인스턴스를 작성할 수 있지만 문제가 발생할 수 있습니다.

첫 번째 인스턴스를 더 구체적으로 만들면 더 이상 작성하려고하는 다른 인스턴스와 충돌하지 않을 수 있습니까?

이러한 문제는 일반적으로 형식 클래스가 대답이 아니라는 신호입니다. 두 개의 인스턴스 만 작성하는 경우 오버로드를 포기하고 두 개의 특정 기능 (각 유스 케이스에 하나씩)을 작성하십시오.

+0

글쎄, 지금은 두 가지 기능이 있지만 아주 유사한 의미가 있기 때문에 오버로드가 올바른 방식으로 느껴집니다. ... "두 번째 인스턴스와 일치하는 특정 항목이없는 경우 첫 번째 항목과 일치하는 항목이 없으면이 항목을 수행 할 수 없다는 우려가 있습니다."( –

+0

주세페, [wiki의이 페이지] (http://www.haskell.org/haskellwiki/GHC/AdvancedOverlap)이 당신의 상황을 아주 잘 묘사 한 것 같습니다! – yatima2975

+0

그는 덜 일반적인 것을 넣을 수 있습니다. 정의를 먼저하고 다른 하나는 'fallback'케이스로 사용합니까? – jakebman

0

내가 다른 곳에서 말했듯이, 두 번째 경우에는 어떤 상황이 일어나고 있는지 전혀 알지 못합니다. 이 대신에, 비록 당신에게 전화 사이트에서 문제를 일으킬 가능성이

class Selectable a s b r where 
    (-->) :: (CNum n) => (Reference s a) -> (n,(a->b),(a->b->a)) -> r 

instance Selectable a s b (Reference s b) where ... 
instance (Recursive a, Rec a ~ reca) => Selectable a s (Method reca b c) (b -> Reference s c) where ... 

, 그것은 아마 훨씬 더 다른 이름으로 두 가지 기능을 사용하는 방법이다 : 그러나, 어쩌면 당신이 대신 수행하여 인스턴스가 겹치지 할 수 있습니다.