Kelas tipe Haskell dan keluarga tipe (lanjutan)

Saya butuh bantuan dalam mencari kesalahan kompiler yang benar-benar membuat saya gila...

Saya memiliki kelas tipe berikut:

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

yang saya contohkan dua kali. Pertama kali berjalan seperti pesona:

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

sejak pemeriksa tipe menyimpulkan

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

dan tanda tangan ini cocok dengan tanda tangan kelas untuk (-->) sejak itu

Res a s b = Reference s b

Sekarang saya menambahkan contoh kedua dan semuanya rusak:

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

kompiler mengeluhkan hal itu

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

membaca dengan cermat kompiler memberi tahu saya bahwa ia telah menyimpulkan tipe (-->) sebagai berikut:

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

yang benar sejak itu

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

tapi kenapa tidak bisa cocok dengan kedua definisi tersebut?

Maaf karena tidak menawarkan contoh yang lebih ringkas dan mandiri, tetapi dalam kasus ini saya tidak tahu bagaimana melakukannya...


person Giuseppe Maggiore    schedule 08.04.2010    source sumber
comment
bisakah Anda memberikan contoh lengkap yang bisa dijalankan? yaitu dari mana Reference berasal? dan bahkan menyertakan {-# LANGUAGE TypeFamilies #-}. imho itu bisa membantu orang lain membantu Anda.   -  person yairchu    schedule 08.04.2010
comment
Agak besar...Ini hanya tip dari proyek yang jauh lebih besar yang tidak mungkin saya posting secara keseluruhan :(   -  person Giuseppe Maggiore    schedule 08.04.2010


Jawaban (2)


Saat Anda menulis

instance Selectable a s b where

Anda mengatakan bahwa kombinasi tipe apa pun adalah turunan dari Selectable. Hal ini tidak memberikan ruang untuk kejadian lain.

Tentu saja, ekstensi kompiler tertentu yang teduh akan memungkinkan Anda menulis lebih banyak instance (tentu saja bertentangan), tetapi Anda pasti akan mengalami masalah.

Bisakah Anda membuat contoh pertama Anda lebih spesifik sehingga tidak lagi bertentangan dengan contoh lain yang Anda coba tulis?

Mengalami masalah seperti ini biasanya merupakan tanda bahwa kelas tipe bukanlah jawabannya. Jika Anda hanya menulis dua instance, mengapa tidak berhenti melakukan kelebihan beban dan cukup menulis dua fungsi spesifik—satu untuk setiap use case?

person Martijn    schedule 08.04.2010
comment
Ya, saya memang memiliki dua fungsi sekarang tetapi karena keduanya memiliki semantik yang sangat mirip, kelebihan muatan terasa seperti cara yang benar... Saya perlu menentukan sesuatu seperti jika tidak ada kecocokan spesifik dengan contoh kedua yang terjadi maka lanjutkan dengan yang pertama, tetapi saya mulai takut ini tidak bisa dilakukan :( - person Giuseppe Maggiore; 08.04.2010
comment
Giuseppe, apakah ide yang dijelaskan di halaman di wiki ini cocok untuk Anda? Tampaknya menggambarkan situasi Anda dengan cukup baik! - person yatima2975; 08.04.2010
comment
apakah mungkin baginya untuk mengutamakan definisi yang kurang umum, dan kemudian yang lain bertindak sebagai kasus 'penggantian'? - person jakebman; 08.04.2010
comment
Saya harus setuju dengan Martijn bahwa kedua fungsi (-->) tidak tampak serupa sama sekali dan tidak boleh memiliki nama yang sama--Saya mengerti apa yang pertama, tetapi tidak tahu sama sekali tentang yang kedua! - person Reid Barton; 09.04.2010

Seperti yang saya katakan di tempat lain, saya tidak tahu apa yang terjadi pada contoh kedua karena konteksnya sangat sedikit. Namun, mungkin Anda dapat membuat instance Anda tidak tumpang tindih dengan melakukan ini:

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

Hal ini mungkin akan menyebabkan masalah pada situs panggilan, dan mungkin lebih baik menggunakan dua fungsi dengan nama berbeda.

person Reid Barton    schedule 09.04.2010