2009-06-19 8 views
7

desidero definire quanto segue typeclass Mapping:Haskell: classi tipo di domanda

{-# LANGUAGE MultiParamTypeClasses #-} 

class Mapping k v m where 
    empty :: m v 
    insert :: k -> v -> m v -> m v 
    search :: k -> m v -> Maybe v 
    delete :: k -> m v -> m v 

Un esempio di Mapping è Data.Map.Map

{-# LANGUAGE ..., FlexibleInstances #-} 

instance Ord k => Mapping k v (Map.Map k) where 
    empty = Map.empty 
    search = Map.lookup 
    insert = Map.insert 
    delete = Map.delete 

E ora voglio creare un tipo Trie :: * -> * -> * -> * come

{-# LANGUAGE ..., UndecidableInstances #-} 

data Trie m k v = Trie { 
    trValue :: Maybe v, 
    trChildren :: m (Trie m k v) 
} 

instance Mapping k (Trie m k v) m => Mapping [k] v (Trie m k) where 
    search [] tree = trValue tree 
    search (x:xs) tree = 
    search xs =<< search x (trChildren tree) 

Fin qui tutto bene, ora voglio anche definire insertTrie, ed è lì che ho problemi.

discuterò empty perché è più semplice e insert ne ha bisogno in ogni caso .. Se provo questo:

instance Mapping k (Trie m k v) m => Mapping [k] v (Trie m k) where 
    empty = Trie { trValue = Nothing, trChildren = empty } 
    ... 

e che mi fa ottenere il seguente errore:

Could not deduce (Mapping k (Trie m k1 v) (m k1)) 
    from the context (Mapping [k1] v (Trie m k1), 
        Mapping k1 (Trie m k1 v) (m k1)) 
    arising from a use of `empty' at test.hs:27:49-53 
Possible fix: 
    add (Mapping k (Trie m k1 v) (m k1)) to the context of 
    the instance declaration 
    or add an instance declaration for (Mapping k (Trie m k1 v) (m k1)) 
In the `trChildren' field of a record 
In the expression: Trie {trValue = Nothing, trChildren = empty} 
In the definition of `empty': 
    empty = Trie {trValue = Nothing, trChildren = empty} 

ho provato e provato a risolverlo ma fallito.

Qualcuno sa come farlo funzionare? È possibile?

+3

BTW, suggerisco di rimuovere 'v' dalla definizione della classe di tipi (ma lascialo nelle firme dei metodi). Non ne hai bisogno, almeno per tutte le strutture che hai dato finora, perché prenderanno qualsiasi tipo di contenuto e renderà tutto più semplice. –

risposta

14

Aggiungi un functional dependency:

{-# LANGUAGE ..., FunctionalDependencies #-} 

class Mapping k v m | m -> k where 
    ... 

Gli errori che avete ottenuto prima erano perché il programma era ambigua su quale tipo di chiave da utilizzare in alcuni punti, quindi gli errori circa il tipo di variabile k1. La dipendenza funzionale consente di dedurre il tipo di chiave dal tipo di mappa (dichiarando che esiste una sola possibile risposta), che tratta questo problema.

+0

Grazie! L'ho codificato (vedi sotto) ed è uscito abbastanza pulito grazie al tuo suggerimento sulla rimozione di v dalla definizione della classe del tipo. – yairchu

7

codice per dimostrare la risposta di Ganesh:

{-# LANGUAGE FlexibleInstances, FunctionalDependencies, MultiParamTypeClasses, StandaloneDeriving, UndecidableInstances #-} 

import qualified Data.Map as Map 
import Data.Maybe (fromMaybe) 

class Mapping k m | m -> k where    
    empty :: m v 
    insert :: k -> v -> m v -> m v 
    search :: k -> m v -> Maybe v 
    delete :: k -> m v -> m v 

instance Ord k => Mapping k (Map.Map k) where 
    empty = Map.empty 
    search = Map.lookup 
    insert = Map.insert 
    delete = Map.delete 

data Trie m v = Trie { 
    trValue :: Maybe v, 
    trChildren :: m (Trie m v) 
} 

deriving instance (Show v, Show (m (Trie m v))) => Show (Trie m v) 

trieMod :: Mapping k m => Maybe v -> [k] -> Trie m v -> Trie m v 
trieMod val [] trie = trie { trValue = val } 
trieMod val (x:xs) trie = 
    trie { trChildren = insert x newChild children } 
    where 
    children = trChildren trie 
    newChild = trieMod val xs prevChild 
    prevChild = fromMaybe empty . search x $ children 

instance Mapping k m => Mapping [k] (Trie m) where 
    empty = Trie { trValue = Nothing, trChildren = empty } 
    search [] trie = trValue trie 
    search (x:xs) trie = 
    search xs =<< search x (trChildren trie) 
    insert key val = trieMod (Just val) key 
    delete = trieMod Nothing 

type TernarySearchTree a = Trie (Map.Map a) 

Btw: Had dipendenze funzionali non esisteva, avremmo probabilmente bisogno di scendere a compromessi su un'interfaccia fastidioso e utilizzare le tabelle funzione invece di classi di tipo.

+0

@Titou: per quanto riguarda la modifica, vedere la discussione sopra con @GaneshSittampalam sulla rimozione di 'v' dalla definizione della classe di tipi. http://stackoverflow.com/questions/1019928/haskell-type-classes-question/1020264#comment829685_1019928 http://stackoverflow.com/questions/1019928/haskell-type-classes-question/1020264#comment829844_1020134 – yairchu

+0

sorry - correct . – Titou

+0

Grazie per aver dedicato del tempo per segnalare l'errore, perché era una falsa convinzione che non avrei interrogato senza il tuo messaggio. – Titou