Le lezioni sono un po 'strane. L'idea originale (che funziona ancora abbastanza) è una sorta di zucchero sintattico attorno a ciò che altrimenti sarebbero le dichiarazioni data
. Ad esempio, puoi immaginare:
data Num a = Num {plus :: a -> a -> a, ... , fromInt :: Integer -> a}
numInteger :: Num Integer
numInteger = Num (+) ... id
quindi puoi scrivere funzioni che hanno ad es. tipo:
test :: Num x -> x -> x -> x -> x
test lib a b c = a + b * (abs (c + b))
where (+) = plus lib
(*) = times lib
abs = absoluteValue lib
Quindi l'idea è "stiamo per derivare automaticamente tutto questo codice di libreria." La domanda è: come troviamo la biblioteca che vogliamo? E 'facile se abbiamo una biblioteca di tipo Num Int
, ma come facciamo a estenderlo a "istanze vincolati" sulla base di funzioni di tipo:
fooLib :: Foo x -> Bar x
xyyLib :: Xyy x -> Bar x
La presente soluzione in Haskell è quello di fare un tipo reticolo corrispondere ai tipi di output di tali funzioni e propagare gli input alla dichiarazione risultante. Ma quando ci sono due uscite dello stesso tipo, avremmo bisogno di un combinatore che si fonde questi in:
eitherLib :: Either (Foo x) (Xyy x) -> Bar x
e fondamentalmente il problema è che non c'è un buon vincolo-combinatore di questo tipo al momento. Questa è la tua obiezione.
Bene, questo è vero, ma ci sono modi per ottenere qualcosa di moralmente simile nella pratica. Supponiamo di definire alcune funzioni con i tipi:
data F
data X
foobar'lib :: Foo x -> Bar' x F
xyybar'lib :: Xyy x -> Bar' x X
bar'barlib :: Bar' x y -> Bar x
Chiaramente il y
è una sorta di "tipo fantasma" threaded attraverso tutto questo, ma rimane potente perché, dato che vogliamo un Bar x
saremo propagare la necessità di un Bar' x y
e data la necessità per il Bar' x y
genereremo uno Bar' x X
o un Bar' x y
. Quindi con i tipi di fantasmi e le classi di tipi a più parametri, otteniamo il risultato che vogliamo.
Maggiori informazioni: https://www.haskell.org/haskellwiki/GHC/AdvancedOverlap
Quale istanza deve GHC scegliere se 'a' è un' foo' e un 'Xyy'? – mb14
@ mb14: un arbitrario. ('IncoherentInstances' già fa qualcosa di simile, e posso conviverci). – ron
In effetti, l'unica differenza sembra essere che "IncoherentInstances" consente a GHC di eseguire il commit su entrambe le istanze, eventualmente scartando una con un contesto soddisfacente e impegnandosi in quella non soddisfacente (che attiverà un errore). Questa domanda invece chiede perché GHC non abbia il flag 'BacktrackOnContextFailures', se ho capito bene, in modo che alla fine venga tentata l'istanza corretta. Sicuramente porterà all'intrattabilità nei casi peggiori, ma abbiamo già "UndecidableInstances" che può avere un impatto significativo sulle prestazioni. – chi