Sto cercando di scrivere del codice Haskell in cui ci sono più tipi di dati, ognuno dei quali può avere più implementazioni. Per fare questo, definisco ogni tipo di dati come un class
i cui metodi sono i costruttori ei selettori rilevanti e quindi implementano tutte le operazioni sui membri di quella classe in termini di costruttori e selettori specifici.Divertimento con i tipi! Risoluzione esempio più dichiarazioni
Per esempio, forse A
è una classe polinomio (con metodi getCoefficients
e makePolynomial
) che possono avere una rappresentazione come SparsePoly
o un DensePoly
e B
è una classe numero complesso (con metodi getReal
, getImag
e makeComplex
) che può essere rappresentato come ComplexCartesian
o ComplexPolar
.
ho riprodotto un esempio minimo al di sotto. Ho due classi A
e B
ognuna delle quali ha un'implementazione. Voglio fare tutte le istanze di entrambe le classi in istanze di Num
automaticamente (questo richiede le estensioni di FlexibleInstances
e UndecidableInstances
). Questo funziona bene quando ho solo una delle A
o B
, ma quando provo a compilare con entrambi, ottengo il seguente errore:
Duplicate instance declarations:
instance [overlap ok] (A a, Num x, Show (a x), Eq (a x)) =>
Num (a x)
-- Defined at test.hs:13:10-56
instance [overlap ok] (B b, Num x, Show (b x), Eq (b x)) =>
Num (b x)
-- Defined at test.hs:27:10-56
suppongo che il messaggio 'dichiarazioni di istanza duplicati' è perché un tipo di dati potrebbe essere creata un'istanza di entrambi A
e B
. Voglio essere in grado di fare una promessa al compilatore che non lo farò, o forse specificare una classe predefinita da utilizzare nel caso in cui un tipo sia un'istanza di entrambe le classi.
C'è un modo per fare questo (forse un altro tipo di estensione?) O si tratta di qualcosa che mi sono bloccato con?
Ecco il mio codice:
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
class A a where
fa :: a x -> x
ga :: x -> a x
data AImpl x = AImpl x deriving (Eq,Show)
instance A AImpl where
fa (AImpl x) = x
ga x = AImpl x
instance (A a, Num x, Show (a x), Eq (a x)) => Num (a x) where
a1 + a2 = ga (fa a1 + fa a2)
-- other implementations go here
class B b where
fb :: b x -> x
gb :: x -> b x
data BImpl x = BImpl x deriving (Eq,Show)
instance B BImpl where
fb (BImpl x) = x
gb x = BImpl x
instance (B b, Num x, Show (b x), Eq (b x)) => Num (b x) where
-- implementations go here
Edit: per intenderci, non sto cercando di scrivere alcun codice pratico utilizzando questa tecnica. Lo faccio come un esercizio per aiutarmi a capire meglio il tipo di sistema e le estensioni.
Correlato: [Come scrivere, "se il tipo a, allora a è anche un'istanza di b in base a questa definizione."] (Http://stackoverflow.com/a/3216937/98117). – hammar