2010-11-17 6 views
5

Sto tentando di rappresentare i bordi ponderati. Alla fine voglio che OutE sia un'istanza di Eq e Ord, con il vincolo che etype sia un'istanza di Eq e Ord. Si supponga Ho seguente file come temp.hs:Aggiunta di vincoli di tipo al contesto delle dichiarazioni di istanza in Haskell

data (Ord etype)=> OutE vtype etype = OutE {destVertex:: vtype, edgeValue::etype} 

applyFunBy accessor ordfun = (\x y -> (ordfun (accessor x) (accessor y))) 

instance Eq (OutE vtype etype) where 
    --(==) :: Ord etype => (OutE vtype etype) -> (OutE vtype etype) -> Bool 
    --(/=) :: Ord etype => (OutE vtype etype) -> (OutE vtype etype) -> Bool 
    (==) = applyFunBy edgeValue (==) 
    (/=) = applyFunBy edgeValue (/=) 

quando carico in questo ghci, ottengo i seguenti errori:

temp.hs:10:19: 
    Could not deduce (Ord etype) 
     from the context (Eq (OutE vtype etype)) 
     arising from a use of `edgeValue' at temp.hs:10:19-27 
    Possible fix: 
     add (Ord etype) to the context of the instance declaration 
    In the first argument of `applyFunBy', namely `edgeValue' 
    In the expression: applyFunBy edgeValue (==) 
    In the definition of `==': == = applyFunBy edgeValue (==) 

temp.hs:11:19: 
    Could not deduce (Ord etype) 
     from the context (Eq (OutE vtype etype)) 
     arising from a use of `edgeValue' at temp.hs:11:19-27 
    Possible fix: 
     add (Ord etype) to the context of the instance declaration 
    In the first argument of `applyFunBy', namely `edgeValue' 
    In the expression: applyFunBy edgeValue (/=) 
    In the definition of `/=': /= = applyFunBy edgeValue (/=) 
Failed, modules loaded: none. 

Se includere le righe per le firme di tipo per (==) e (\ =), ottengo:

temp.hs:6:1: 
    Misplaced type signature: 
    == :: 
     (Ord etype) => (OutE vtype etype) -> (OutE vtype etype) -> Bool 

temp.hs:7:1: 
    Misplaced type signature: 
    /= :: 
     (Ord etype) => (OutE vtype etype) -> (OutE vtype etype) -> Bool 

risposta

5

È limitata etype di essere Ord in alla definizione di OutE:

data (Ord etype) => OutE vtype etype = ... 

Ma nel caso Eq, si sta effettivamente cercando di definire l'istanza per qualsiasietype senza limitazioni.

instance Eq (OutE vtype etype) where 

Naturalmente questo non funziona in quanto OutE sé è solo definito per Ord etype s, quindi si dovrà aggiungere il vincolo typeclass alla definizione dell'istanza pure.

instance (Ord etype) => Eq (OutE vtype etype) where 

nota che uno definizione di uno o ==/= è sufficiente per la typeclass al lavoro.


Si noti che è spesso più facile e quindi considerato lo stile meglio non avere typeclass vincoli data -Tipi, ma solo su istanze/metodi che in realtà richiedono la funzionalità del typeclass.

In molti casi, uno non ha bisogno del vincolo e termina semplicemente con firme di tipo inutilmente goffe.

Prendere per es. qualche tipo di mappa ordinato Ord key => Map key value.

E se vogliamo solo elencare tutte le chiavi? O ottieni il numero di elementi? Non abbiamo bisogno delle chiavi per essere Ord per questi, quindi perché non lasciamo la mappa senza restrizioni con semplice

getKeys :: Map key value -> [key] 
getLength :: Map key value -> Int 

e basta aggiungere il typeclass quando abbiamo veramente bisogno in una funzione come

insert :: Ord key => key -> value -> Map key value 
2
data (Ord etype)=> OutE vtype etype = OutE {destVertex:: vtype, edgeValue::etype} 

Prima edizione: Questo è consdered cattivo stile. Le dichiarazioni del tipo di dati non dovrebbero avere vincoli. Lascia i vincoli alle funzioni, proprio come fa il pacchetto contenitori.

instance Eq (OutE vtype etype) where 

Secondo "problema". È sufficiente aggiungere deriving (Eq) dopo la dichiarazione dei dati. Sto indovinando si sa che e sta scrivendo l'istanza in modo esplicito per il proprio apprendimento (buon per voi) ...

instance Eq (OutE vtype etype) where 
    (==) = applyFunBy edgeValue (==) 
    (/=) = applyFunBy edgeValue (/=) 

Terzo problema: non si può paragonare i valori di equità, se sono della classe Eq . Così si vuole dire etype è limitata dalla Eq:

instance (Eq etype) => Eq (OutE vtype etype) where 
    (==) = applyFunBy edgeValue (==) 
    (/=) = applyFunBy edgeValue (/=) 

In quarto luogo, in realtà non ha bisogno di scrivere un'istanza per entrambi (==) e (/ =). Le impostazioni predefinite funzioneranno una volta definito uno di questi.

+0

'derivando (Eq)' genererà operatori di uguaglianza basati su ** tutti i campi di record ** (e quindi genererà una complessa istanza di 'Eq' con un' Eq vtype') mentre l'istanza esplicita fornita nella domanda si confronta solo in base a 'edgeValue '. – Dario

+0

Giusto, non ho notato che lo stava facendo fino a dopo aver scritto quel pezzo. Grazie per la segnalazione. –