2013-06-13 10 views
8

Sto provando a scrivere un semplice algoritmo genetico in Haskell. Ho pensato che il primo passo dovrebbe essere quello di fare un typeclass per gli individui che sono 'genetica', in questo modo:Uso dei più comuni tipi di tipi di tipi di font

class Genetic a where 
    fitness :: (Ord b) => a -> b 

Questo mi sembra ragionevole - Non necessariamente voler limitare le funzioni di fitness a un tipo come Float o Double e concettualmente tutta la funzione di idoneità dovrebbe fare è fornire un ordine degli individui.

Tuttavia, quando a implementare questo typeclass per un String involucro:

data DNA = DNA String 
instance Genetic DNA where 
    fitness (DNA s) = length s 

vedo il seguente errore nel GHC:

Could not deduce (b ~ Int) 
from the context (Ord b) 
    bound by the type signature for fitness :: Ord b => DNA -> b 

Non è questo come dovrei definire le funzioni typeclass? Devo limitare la funzione a un tipo concreto specifico o fornire un'altra variabile di tipo al costruttore typeclass?

+7

Questo è un problema comune. La tua firma significa che * il chiamante * deve scegliere il tipo ordinabile, quindi 'fitness' deve essere in grado di fabbricare un valore di qualsiasi tipo ordinabile e restituirlo. Nota, 'Void' (il tipo senza valori) è ordinabile, quindi questo è impossibile. Probabilmente vuoi parametrizzare 'Genetic' nello spazio degli ordini:' class (Ord b) => Genetico b a dove fitness :: a -> b' – luqui

+0

@luqui Grazie, penso di averlo capito. A dimostrazione di ciò, sembra che a Haskell non piacciano i typeclass con parametri di tipo multi-tipo. Chi avrebbe mai pensato. –

+1

@DanielBuckmaster yes ma l'estensione 'MultiParamTypeclasses' è piuttosto comune per usare – jozefg

risposta

13

Luqui spiegato qual è il problema: fitness sarebbe bisogno di essere in grado di fornire qualsiasi Ord esempio il chiamante potrebbe richiedere, quando ciò che si vuole veramente è qualcuno specifica che si adatta al tipo migliore.

Questo è IMO una bella domanda di sinonimi associati Tipo:

{-# LANGUAGE TypeFamilies, FlexibleInstances, FlexibleContexts #-} 

class (Ord (Fitness a)) => Genetic a where 
    type Fitness a :: * 
    fitness :: a -> Fitness a 

data DNA = DNA String 
instance Genetic DNA where 
    type Fitness DNA = Int 
    fitness (DNA s) = length s 
+0

Oh wow, è bello. Penso che potrei andare da questa parte. Grazie! –

+0

Tranne che viene visualizzato un errore: 'Argomento non variabile di tipo nel vincolo: Ord (Fitness a)'. Dice '(Usa -XFlexibleContexts per permetterlo)' - sembra che sia richiesto un altro pragma? –

+3

@DanielBuckmaster, si, preparatevi a inserire qualsiasi estensione che il compilatore raccomanda a questo punto. A volte il codice classe tipo è così ... – luqui