Prenderò un approccio simile ma leggermente diverso alla risposta di J. Abrahamson.
Proprio quello che chiedi non può essere fatto, perché le classi di tipo devono essere risolti staticamente, ma l'esistenza di Show (a b)
potrebbe essere dinamica a seconda della instantation di b
. Questa istanziazione è nascosta all'interno del valore X
e pertanto non è visibile per il controllo di tipo quando non si ha nient'altro che uno X b
di origine sconosciuta.
Sarebbe bello scrivere una condizione sulla a
come Show (a b)
esiste ogni volta Show b
fa, perché allora l'esistenza di Show (a b)
non è in realtà dipende da b
come già sappiamo che Show b
è sempre vero.
Non possiamo scrivere che condizioni direttamente, ma siamo in grado di esprimere qualcosa di simile utilizzando GADTs:
{-# LANGUAGE GADTs #-}
data ShowDict a where
ShowDict :: Show a => ShowDict a
Il tipo ShowDict a
fornisce una sorta di reificazione della classe Show a
- è qualcosa che possiamo passare intorno e definire le funzioni sopra.
In particolare possiamo ora definire una classe Show1
che esprime la condizione Show (a b)
ogni volta che abbiamo un Show b
:
class Show1 a where
show1Dict :: ShowDict b -> ShowDict (a b)
e ora possiamo definire Show (X a)
in termini di Show1
, costruendo ShowDict (a b)
e quindi pattern-matching su di esso per rivelare l'istanza Show
:
{-# LANGUAGE ScopedTypeVariables #-}
instance Show1 a => Show (X a) where
show (X (v :: a b)) =
case show1Dict ShowDict :: ShowDict (a b) of
ShowDict -> "X (" ++ show v ++ ")"
Un'implementazione più completa sarebbe anche inc lude gli altri membri di Show
(showsPrec
e showList
).
La cosa bella di questa soluzione è che possiamo tranquillamente definire Show1
per []
, riutilizzando automaticamente il sottostante Show
esempio:
instance Show1 [] where
show1Dict ShowDict = ShowDict
anche io preferisco evitare il molto generico Show (a b)
esempio dalla risposta di J. Abrahamson, ma il lato negativo di dover mettere la logica nell'istanza Show
per X
è che finiamo per doverlo implementare manualmente piuttosto che ottenere il comportamento derivato automaticamente per il costruttore.
Peccato. Tutto quello che il manuale GHC dice su OverlappingInstances è spaventoso. – Will
Sì, non è assolutamente consigliato. Show1 può anche clobare altre istanze abbastanza facilmente. –