GHC solo sceglie uno, e questa è la scelta giusta Ogni due dizionari per lo stesso vincolo dovrebbero essere uguali
OverlappingInstances e IncoherentInstances sono sostanzialmente equivalenti al potere distruttivo. Entrambi perdono istanza coerenza per progetto (eventuali due vincoli uguali nel tuo programma sono soddisfatti dallo stesso dizionario). Sovrapposizione Le istanze ti danno un po 'più di capacità di capire quali istanze saranno utilizzate caso per caso, ma non è così utile quando arrivi al punto di passare a Dicts come valori di prima classe e così via. Prenderò in considerazione l'uso di OverlappingInstances solo se considero le istanze sovrapposte estensionalmente equivalenti (es., un'implementazione più efficiente ma altrimenti uguale per un tipo specifico come Int), ma anche in questo caso, se mi interessa abbastanza le prestazioni per scrivere quell'implementazione specializzata, non è un bug di prestazioni se non viene utilizzato quando potrebbe essere ?
In breve, se si utilizza OverlappingInstances, si ha il diritto di porre la domanda su quale dizionario verrà selezionato qui.
Ora è vero che è possibile rompere la coerenza dell'istanza senza Sovrapposizioni. In effetti puoi farlo senza orfani e senza estensioni diverse da FlexibleInstances (probabilmente il problema è che la definizione di "orfano" è sbagliata quando FlexibleInstances è abilitato). Questo è un bug di GHC di lunga data, che non è stato risolto in parte perché (a) in realtà non può causare arresti anomali direttamente come nessuno sembra sapere, e (b) potrebbero esserci molti programmi che in realtà si basa sull'avere più istanze per lo stesso vincolo in parti separate del programma e potrebbe essere difficile da evitare.
Tornando all'argomento principale, in linea di principio è importante che GHC possa selezionare qualsiasi dizionario che è disponibile per soddisfare un vincolo, perché anche se si suppone che siano uguali, GHC potrebbe avere più informazioni statiche su alcuni di essi di altri. Il tuo esempio è un po 'troppo semplice per essere illustrativo ma immagina di aver passato un argomento a bar
; in generale GHC non sa nulla del dizionario passato via Dict
quindi deve considerarlo come una chiamata a una funzione sconosciuta, ma hai chiamato foo
a un tipo specifico T
per il quale c'era un'istanza Bar T
in ambito, quindi GHC saprebbe che il bar
dal dizionario dei vincoli Bar a
è stato T
di bar
e potrebbe generare una chiamata a una funzione conosciuta e potenzialmente in linea T
di bar
ed eseguire di conseguenza più ottimizzazioni.
In pratica, GHC al momento non è così intelligente e utilizza solo il dizionario più interno disponibile. Probabilmente sarebbe già meglio usare sempre il dizionario più esterno. Ma casi come questo in cui ci sono più dizionari disponibili non sono molto comuni, quindi non abbiamo buoni benchmark su cui testare.
fonte
2015-04-08 16:27:34
Si potrebbe quindi chiedere perché abbiamo due estensioni (incoerente/sovrapposte) invece di solo uno. Si potrebbe avere l'impressione che la sovrapposizione da sola sia ancora "sicura", e solo in modo incoerente iniziano i veri problemi. – chi
"Ogni due dizionari per lo stesso vincolo dovrebbero essere uguali." - Supposto di essere, ma non lo sono. Vedere la mia risposta per un esempio di violazione di questa affermazione senza utilizzare istanze incoerenti o sovrapposte. –
Sì, questo è ciò che intendo per perdita di coerenza dell'istanza. –