คลาสประเภท Haskell และตระกูลประเภท (ต่อ)

ฉันต้องการความช่วยเหลือในการหาข้อผิดพลาดของคอมไพเลอร์ซึ่งทำให้ฉันแทบบ้า...

ฉันมีคลาสประเภทต่อไปนี้:

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

ซึ่งฉันยกตัวอย่างสองครั้ง ครั้งแรกเป็นเหมือนเสน่ห์:

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'')))   

เนื่องจากตัวตรวจสอบประเภทอนุมาน

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

และลายเซ็นนี้ตรงกับลายเซ็นของคลาสสำหรับ (-->) ตั้งแต่นั้นมา

Res a s b = Reference s b

ตอนนี้ฉันเพิ่มอินสแตนซ์ที่สองและทุกอย่างพัง:

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

เมื่ออ่านอย่างละเอียดคอมไพเลอร์กำลังบอกฉันว่ามันได้อนุมานประเภทของ (-->) ดังนี้:

(-->) :: 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

แต่ทำไมมันไม่ตรงกับสองคำจำกัดความนี้ล่ะ?

ขออภัยที่ไม่ได้เสนอตัวอย่างที่กระชับและสแตนด์อโลนมากกว่านี้ แต่ในกรณีนี้ ฉันไม่สามารถทราบได้ว่าจะทำอย่างไร...


person Giuseppe Maggiore    schedule 08.04.2010    source แหล่งที่มา
comment
คุณช่วยยกตัวอย่างที่สามารถรันได้ทั้งหมดได้ไหม? เช่น Reference มาจากไหน? และรวมถึง {-# LANGUAGE TypeFamilies #-} ด้วย imho ที่สามารถช่วยผู้อื่นช่วยคุณได้   -  person yairchu    schedule 08.04.2010
comment
มันใหญ่มาก...นี่เป็นเพียงส่วนปลายของโปรเจ็กต์ที่ใหญ่กว่ามากซึ่งฉันไม่สามารถโพสต์ได้ทั้งหมด :(   -  person Giuseppe Maggiore    schedule 08.04.2010


คำตอบ (2)


เมื่อคุณเขียน

instance Selectable a s b where

คุณกำลังบอกว่า any การรวมกันของประเภทเป็นตัวอย่างของ Selectable สิ่งนี้ทำให้ไม่มีที่ว่างสำหรับกรณีอื่น

แน่นอนว่าส่วนขยายคอมไพเลอร์ที่ร่มรื่นบางส่วนจะช่วยให้คุณสามารถเขียนอินสแตนซ์ได้มากขึ้น (ขัดแย้งกันโดยไม่จำเป็น) แต่คุณจะพบปัญหาแน่นอน

คุณสามารถทำให้อินสแตนซ์แรกของคุณเจาะจงมากขึ้นเพื่อไม่ให้ขัดแย้งกับอินสแตนซ์อื่นที่คุณพยายามเขียนอีกต่อไปได้หรือไม่

การประสบปัญหาเช่นนี้มักเป็นสัญญาณว่าคลาสประเภทไม่ใช่คำตอบ หากคุณเขียนเพียงสองอินสแตนซ์ ทำไมไม่ละทิ้งการโอเวอร์โหลดและเขียนฟังก์ชันเฉพาะสองฟังก์ชัน—หนึ่งฟังก์ชันสำหรับแต่ละกรณีการใช้งาน

person Martijn    schedule 08.04.2010
comment
ตอนนี้ฉันมีสองฟังก์ชันแล้ว แต่เนื่องจากมันมีความหมายที่คล้ายกันมาก การโอเวอร์โหลดจึงให้ความรู้สึกเหมือนเป็นวิธีที่ถูกต้อง... ฉันต้องระบุบางอย่างเช่น หากไม่มีการจับคู่เฉพาะกับอินสแตนซ์ที่สองเกิดขึ้น ให้ไปกับฟังก์ชันแรก แต่ฉันเริ่มที่จะ กลัวว่าจะทำไม่ได้ :( - person Giuseppe Maggiore; 08.04.2010
comment
จูเซปเป้ แนวคิดที่อธิบายไว้ใน หน้านี้ใน wiki ใช้ได้กับคุณไหม ดูเหมือนว่าจะอธิบายสถานการณ์ของคุณได้ค่อนข้างดี! - person yatima2975; 08.04.2010
comment
เป็นไปได้ไหมสำหรับเขาที่จะใส่คำจำกัดความทั่วไปที่น้อยกว่าก่อน แล้วอีกอันจะทำหน้าที่เป็นกรณี 'ทางเลือก' - person jakebman; 08.04.2010
comment
ฉันต้องเห็นด้วยกับ Martijn ว่าฟังก์ชัน (-->) ทั้งสองดูไม่คล้ายกันเลยและไม่ควรมีชื่อเหมือนกัน ฉันเข้าใจว่าอันแรกคืออะไร แต่ไม่มีความคิดที่คลุมเครือที่สุดเกี่ยวกับอันที่สอง! - person Reid Barton; 09.04.2010

อย่างที่ฉันพูดไปในที่อื่น ฉันไม่รู้ว่าเกิดอะไรขึ้นในกรณีที่สองเนื่องจากมีบริบทน้อยมาก อย่างไรก็ตาม บางทีคุณอาจทำให้อินสแตนซ์ของคุณไม่ทับซ้อนกันได้โดยทำสิ่งนี้แทน:

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 ...

สิ่งนี้มีแนวโน้มที่จะทำให้คุณเกิดปัญหาที่ไซต์การโทรแทน และอาจจะดีกว่ามากถ้าใช้สองฟังก์ชันที่มีชื่อต่างกัน

person Reid Barton    schedule 09.04.2010