2009-06-19 22 views
7

aşağıdaki typeclass Mapping tanımlamak isteyen soru:Haskell: tip sınıfları

{-# 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 

biri Mapping örneği 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 

Ve şimdi bir tür oluşturmak istiyorum Trie :: * -> * -> * -> * gibi

{-# 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) 

Şimdiye kadar çok iyi, şimdi de Trie 'insert ve empty tanımlamak istiyorum, ve ben sorunları içine burası.

daha basit olduğu için ben empty tartışacağız ve insert nasıl olsa buna ihtiyacı .. bu denerseniz:

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

ve bu beni aşağıdaki hatayı alıyorum yapar: Ben ettik

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} 

denedi ve çözmeye çalıştı ama başarısız oldu.

Bunu nasıl yapacağını bilen var mı? Bu mümkün mü? Daha önce var programı k1 değişken türü hakkında, belirli yerlerde dolayısıyla hataları için hangi anahtar türü hakkında belirsiz olduğu için idi

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

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

hataları:

+3

BTW, "v" yi tip sınıf tanımından kaldırmanızı öneririm (ancak yöntemlerin imzalarında bırakın). En azından şu ana kadar vermiş olduğunuz tüm yapılar için buna ihtiyacınız yok, çünkü bunların hepsi herhangi bir tür içerecek ve her şeyi daha basit hale getirecek. –

cevap

14

bir functional dependency ekleyin. Fonksiyonel bağımlılık, bu tür problemlerle ilgilenen anahtar tipinin harita türünden çıkarılmasına izin verir (sadece bir olası cevabın olduğunu bildirerek).

{-# 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:

+0

Teşekkürler! Bunu kodladım (aşağıya bakın) ve v tipi sınıf tanımından kaldırmayla ilgili öneriniz sayesinde oldukça düzgün bir şekilde çıktı. – yairchu

7

Kod Ganesh cevabını göstermek için fonksiyonel bağımlılıkları var olmasaydı, biz muhtemelen rahatsız edici bir arayüz üzerinde uzlaşma ve fonksiyon tabloları yerine türü sınıflarını kullanmak gerekir.

+0

@Titou: Düzenlemenizle ilgili olarak - @GaneshSittampalam ile yukarıdaki listeyi tip sınıfının tanımından kaldırmak için v ile ilgili tartışmaya bakın. 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

üzgünüm - düzeltildi . – Titou

+0

Hataya dikkat çekmek için zaman ayırdığınız için teşekkür ederim, çünkü bu sizin mesajınız olmadan sorgulamadığım yanlış bir inanıştı. – Titou