2013-04-04 13 views
8

Supponiamo che io ho la seguente classe:Haskell classi di tipo ereditare

class P a where 
    nameOf :: a -> String 

vorrei dichiarare che tutte le istanze di questa classe sono automaticamente istanze di Show. Il mio primo tentativo sarebbe il seguente:

instance P a => Show a where 
    show = nameOf 

Il mio primo tentativo di andare in questo modo ieri ha provocato un labirinto di coniglio di estensioni del linguaggio: casi che io è stato detto di accendere le istanze flessibili, le istanze quindi indecidibili, poi sovrapposti, e infine ottenere un errore sulla sovrapposizione delle dichiarazioni di istanza. Ho rinunciato e sono tornato a ripetere il codice. Tuttavia, questo sembra fondamentalmente una domanda molto semplice, che dovrebbe essere facilmente soddisfatta.

Così, due domande:

  1. C'è un modo banalmente facile per fare questo che ho appena perso?
  2. Perché si verifica un problema di istanze sovrapposte? Posso capire perché potrei aver bisogno di UndecidableInstances, poiché sembra che stia violando la condizione di Paterson, ma non ci sono istanze sovrapposte qui intorno: non ci sono istanze di P, pari. Perché il tipografo ritiene che ci siano più istanze per (come sembra essere il caso in questo esempio di giocattolo)?
+3

La sovrapposizione (e la risoluzione di sovraccarico) è determinata solo dalla testa dell'istanza 'Mostra a', quindi effettivamente si sovrappone a ogni altra istanza' Mostra'. – augustss

+1

Supponiamo che tu dichiari l'istanza di 'P Int' e che tu abbia già un'istanza per' Show Int', quindi questo si tradurrà in istanze sovrapposte per Show. – Satvik

+0

@Satvik Sure, tranne per il fatto che non ho un'istanza di 'P Int' intorno. Mi aspetterei un errore se provassi a creare un 'P Int', ma non semplicemente dichiarando che potrebbe esistere. – Impredicative

risposta

5

È l'errore casi di sovrapposizione, perché alcune delle vostre istanze di P può avere altri casi di Show e poi il compilatore non sarà in grado di decidere quali utilizzare. Se hai un'istanza di P per Double, allora ci sei, ottieni due istanze di Show per Double: la tua generale e quella già dichiarata nella libreria di base di Haskell. Come viene attivato questo errore è correttamente dichiarato da @augustss nei commenti alla tua domanda. Per maggiori informazioni vedi the specs.

Come già sai, non c'è modo di ottenere ciò che stai cercando senza lo UndecidableInstances. Quando abiliti quel flag devi capire che stai assumendo la responsabilità del compilatore per assicurarti che non ci siano istanze in conflitto. Ciò significa che, naturalmente, non ci devono essere altre istanze di Show prodotte nella libreria. Ciò significa anche che la libreria non esporterà la classe P, che cancellerà la possibilità per gli utenti della libreria di dichiarare le istanze in conflitto.

Se il tuo caso è in qualche modo in conflitto con quanto detto sopra, è un segno affidabile che deve esserci qualcosa di sbagliato in esso. E infatti c'è ...


Quello che stai cercando di ottenere è sbagliato soprattutto. Vi manca diversi punti importanti sulla Show typeclass, distinguendolo da costrutti come metodo toString di linguaggi OO popolari:

  1. Da Show's haddock:

    Il risultato di spettacolo è un sintatticamente corretta espressione Haskell contenente solo costanti, date le dichiarazioni di fissità in vigore nel punto in cui il tipo è dichiarato. Contiene solo i nomi dei costruttori definiti nel tipo di dati, parentesi e spazi.Quando vengono utilizzati campi del costruttore etichettati, vengono utilizzate anche parentesi graffe, virgole, nomi di campi e segni di uguale.

    In altre parole, dichiarare un'istanza di Show, che non produce un'espressione Haskell valida, non è corretta.

  2. Dato quanto sopra, non ha senso dichiarare un'istanza personalizzata di Show quando il tipo consente di derivarla semplicemente.

  3. Quando un tipo non consente di derivarlo (ad esempio, GADT), in genere è necessario attenersi alle istanze specifiche del tipo per ottenere risultati corretti.

Quindi, se avete bisogno di una funzione di rappresentanza personalizzato, non si dovrebbe usare Show per questo. Basta dichiarare una classe personalizzata, ad esempio

class Repr a where 
    repr :: a -> String 

e avvicinarsi responsabilmente alla dichiarazione di istanze.

+0

Sono cauto nell'accettare questa risposta perché ritengo che sia tecnicamente sbagliato in parte. Il problema non è che alcune istanze di 'P' hanno altre istanze di' Show': come notato, non ci sono * istanze di 'P'. 'augusts' ha spiegato il vero problema, avendo a che fare con la valutazione della sovrapposizione. Se lo aggiusti, sarei felice di accettare; Prendo il tuo punto sull'uso di "spettacolo". – Impredicative

+0

@Impredicative Probabilmente non mi sono chiarito, ho aggiornato il primo paragrafo. –