2012-01-31 10 views
7

In un certo senso questo è un passo indietro rispetto alla mia domanda precedente, ma ... Qualcuno può ricordarmi perché questo non funziona?Tipi di elementi contenitore

 
class Container c e where 
    empty :: c 
    insert :: e -> c -> c 

instance Container [x] x where 
    empty = [] 
    insert = (:) 

instance Container ByteString Word8 where 
    empty = BIN.empty 
    insert = BIN.cons 

instance Ord x => Container (Set x) x where 
    empty = SET.empty 
    insert = SET.insert 

Ovviamente se fosse così facile, nessuno avrebbe preso la briga di inventare dipendenze funzionali né tipi associati. Quindi qual è il problema con quanto sopra?

+0

Provare ad usarlo. Presto ti lagnerai di un sovraccarico ambiguo. – augustss

risposta

10

Non c'è niente che ti impedisca di aggiungere instance Container [Int] Int e instance Container [Int] Char, e quando chiedi il empty :: [Int] il compilatore non ha modo di sapere da quale istanza deve provenire.

"Ah, ma ho solo instance Container [Int] Int", si dice. "E un instance Container [Int] Char sarebbe un bug comunque."

Ma il compilatore non può sapere che non si aggiungerà uno instance Container [Int] Char in futuro, e se lo si fa, non è consentito per esso di rompere il codice esistente.

Quindi abbiamo bisogno di un modo per dire al compilatore che

  • il primo parametro di Container determina in modo univoco il secondo parametro di Container
  • se vede istanze diverse che differiscono solo nel secondo tipo, che indica un bug

Inserire dipendenze funzionali.

+0

Sapevo che dovevo dimenticare qualcosa di ovvio ... – MathematicalOrchid

Problemi correlati