2013-07-01 5 views
11

È possibile avere un tipo come parte di un typeclass? Qualcosa di simile:Haskell: Le classificazioni tipiche possono definire tipi (tratti del tipo ala)

class KeyTraits v where 
    keyType :: * 
    key :: v -> keyType 

data TableRow = { date :: Date, metaData :: String, value :: Int } 

instance KeyTraits TableRow where 
    keyType = Date 
    key = date 

E queste funzioni di "tipo livello" possono essere utilizzate altrove? Per esempio:

-- automatically deduce the type for the key, from the value type, using 
-- the typeclass 
data MyMap v = { getMap :: (KeyTraits v) => Map (keyType) v } 

io possa fare qualcosa di completamente sbagliato, ma io fondamentalmente voglio la possibilità di definire le relazioni di tipo come quello di cui sopra (per esempio Alcuni valori già possono avere dati che possono essere utilizzati come una chiave). Se ciò non è possibile, o è difficile, potresti suggerire un design migliore che sia più idiomatico?

Grazie!

risposta

26

Date un'occhiata a type families.

{-# LANGUAGE TypeFamilies #-} 
{-# LANGUAGE RankNTypes #-} 

class KeyTraits k where 
    type KeyType k :: * 
    key :: v -> KeyType k 

data TableRow = TableRow { date :: Date, metaData :: String, value :: Int } 

instance KeyTraits TableRow where 
    type KeyType TableRow = Date 
    key = date 

data MyMap v = MyMap { getMap :: (KeyTraits v) => Map (KeyType v) v } 
11

famiglie tipo sono esattamente quello che stai cercando, ma c'è anche un altro modo per raggiungere la loro funzionalità, vale a dire con multi-parameter type classesfunctional dependencies. Con queste estensioni si codice potrebbe assomigliare a questo:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-} 

class KeyTraits v k | v -> k where 
    key :: v -> k 

data TableRow = { date :: Date, metaData :: String, value :: Int } 

instance KeyTraits TableRow Date where 
    key = date 

Qui il tipo associato migra tipo di parametro di classe, e il rapporto tra v e k, precedentemente implicita, ora diventa esplicito con dipendenza funzionale.

Questo è completamente equivalente ai tipi associati, ma IMO offre una sintassi molto più pulita, specialmente nelle funzioni che utilizzano la classe del tipo. Confronto:

getMap :: (KeyTraits v) => Map (KeyType v) v 

e

getMap :: (KeyTraits k v) => Map k v 

Questo diventa più evidente quando più tipi e più classi di tipo appaiono in dichiarazione di tipo singolo.

Tuttavia, le famiglie di tipi sembrano essere preferite dalla comunità di haskell, e infatti l'intera estensione è più potente di MPTC + FD, poiché le famiglie di tipi possono essere dichiarate senza classi di tipi e ci sono anche famiglie di dati.

+0

Grazie mille per l'alternativa! Anche se l'altra risposta è più direttamente legata al titolo della domanda, la tua soluzione è altrettanto rilevante. –

+0

Ho avuto l'impressione che MPTC + FD fosse più espressivo della TF in alcuni casi estremi con dipendenze complicate ... –

Problemi correlati