Quindi ci sono molti vantaggi nell'avere typeclass nel formato C a Bool
. Principalmente perché ti permettono di fare qualsiasi operazione logica tra due vincoli quando il normale C a
include solo implicitamente tutto.Conversione di un vincolo di classe arbitrario `C a` in` C a Bool`
Se consideriamo ~
un vincolo di classe, questo può essere fatto in questo modo
class Equal x y b | x y -> b
instance Equal x x True
instance False ~ b => Equal x y b
Ma ciò che rende questo caso particolare è il fatto che mettere x x
nella testa dell'istanza equivale a x ~ y =>
e poi x y
nella testa. Questo non è il caso per qualsiasi altro tipo. Quindi, se proviamo a fare qualcosa di simile per una classe C
otteniamo qualcosa come
class C' x b | x -> b
instance C x => C' x True
instance False ~ Bool => C' x b
Purtroppo questo non funziona in quanto solo uno di quei casi potrà mai essere ritirati perché non discriminare il tipo x
quindi qualsiasi tipo corrisponde a entrambe le teste.
Ho anche letto https://www.haskell.org/haskellwiki/GHC/AdvancedOverlap che di nuovo non si applica a nessuna classe C
perché richiede di riscrivere tutte le istanze della classe originale. Idealmente, mi piacerebbe che il mio codice funzionasse con GHC.Exts.Constraint
e KindSignatures
in modo che C
possa essere parametrico.
Così, per una classe come questa
class Match (c :: * -> Constraint) x b | c x -> b
Come faccio a scrivere le istanze in modo che Match c x True
se e solo se c x
, Match c x False
altrimenti?
Il 'C una forma Bool' è più forte di' C a'.Stai essenzialmente chiedendo come raccogliere l'insieme di istanze di una classe di caratteri, il che è impossibile. – user2407038
@ user2407038 Non che io stia dubitando di te, ma ho sentito "impossibile" riguardo al sistema di tipo prima e si è rivelato falso. –
Non so se posso fare una discussione convincente, ma ci proverò. Supponiamo che tu abbia scritto "Match". Nel modulo A definisco 'data X = X', e' classe A b x | b -> x; a :: Proxy b -> x; istanza A True Int; istanza A False Bool', 'test :: forall x b y. (Abbina Eq x b, A b y) => x -> y; test _ = a (Proxy :: Proxy b) '. Ho il modulo B (importa A), in cui il tipo di 'test X' deve essere' Int'. Nel modulo C (importazione A) ho 'istanza Eq X' quindi' test X :: Bool'. Il modulo D importa B e C. Il modulo D non può non forzare B e C a ricompilare, quindi 'test X' deve paradossalmente avere due tipi contemporaneamente. – user2407038