2013-05-08 7 views
7

Sto utilizzando la seguente typeclass:Come dire ad Haskell di non importare la stessa istanza da due moduli?

module T where 
class T a where 
    v :: a 

Un'istanza di T Int che ho implementato:

import T 
import A (av) 

instance T Int where 
    v = 0 

main = putStrLn (av ++ show v) 

E un modulo che voglio usare un valore, che ha anche un esempio di T Int.

module A where 
import T 
instance T Int where 
    v = 0 
av = "value from A" 

Il problema è questo non funziona:

$ runghc Main.hs 

Main.hs:4:9: 
    Duplicate instance declarations: 
     instance T Int -- Defined at Main.hs:4:9-13 
     instance T Int -- Defined at A.hs:3:9-13 

Haskell si lamenta che ci sono 2 le dichiarazioni per la stessa istanza. Come posso dirgli di non importare l'istanza da B o di unificare entrambe le istanze o di utilizzare l'istanza solo da Main?

+1

Non farlo. La soluzione corretta è solo dichiarare l'istanza in un posto. – hammar

+0

@hammar: Non ho scritto 'T' o' B', ma voglio usare un valore da 'B', e voglio creare un'istanza di' T'. – Dog

+1

Ah, questo rende più complicato. In tal caso, puoi creare un 'newtype' che avvolga il tipo esistente e scrivi invece la tua istanza per' newtype'. – hammar

risposta

8

Sfortunatamente, non è possibile controllare il modo in cui le istanze vengono importate ed esportate; vedi Do Haskell imports have side effects?.

Ciò significa che sarà necessario rifattorizzare il codice per garantire che l'istanza sia definita in un solo file. In generale, è meglio definire un'istanza nel file che definisce la classe o il tipo di dati - infatti, c'è persino un avviso sulle istanze "orfane" che non seguono questa regola. (Guarda Orphaned instances in Haskell per una lunga discussione sul motivo per cui dovresti evitare le istanze orfane.)

Tuttavia, se questo è impossibile per qualche motivo, puoi comunque scegliere arbitrariamente uno dei file per mantenerlo o persino creare un nuovo modulo da importare da tutti i file che richiedono quella particolare istanza.

Più in generale, come si dovrebbe affrontare la possibilità che le due istanze fatto diverse cose, come:

instance T Int where v = 0 
{- And in a different file: -} 
instance T Int where v = 1 

Non c'è davvero immediatamente evidente modo per disambiguare questi due senza significativamente cambiare il modo in Haskell sistema di tipografia funziona.

Dal momento che hai scritto tu stesso una delle istanze, rimuovi semplicemente quella. Poiché è lo stesso di quello predefinito, importa quel modulo ovunque ti serva per utilizzarlo.

+0

"Ciò significa che dovrai rifattorizzare il tuo codice per assicurarti che l'istanza sia definita solo in un file." Come posso fare questo? Non ho scritto 'T' o' B'. – Dog

+0

Oh. Allora sì, è cattivo. Questo è il motivo per cui non dovresti scrivere istanze orfane. Presenterei un bug su questo con il modulo che ha l'istanza orfana - cioè, quella che ha l'istanza senza definire né la classe né il tipo. –

+2

@Dog: In realtà, forse ho frainteso il tuo problema. Dal momento che hai scritto una delle istanze, cancella semplicemente quella. Scrivilo per un 'newtype' se devi. –

Problemi correlati