2012-09-13 15 views
5

Mam coś jak następuje:gwarancji, że rodziny typu będą czerpać pewne klasy

{-# LANGUAGE TypeFamilies #-} 

class Configuration c where 
    data Pig c 
    data Cow c 

    parsePig :: GenParser Char st (Pig c) 
    parseCow :: GenParser Char st (Cow c) 

data Farm c = 
    { pigs :: [Pig c] 
    , cows :: [Cow c] 
    } deriving Show 

to się nie powiedzie z powodu linii deriving Show. Nie wiem, jak wymusić wszystkie instancje Configuration, aby zapewnić, że ich implementacje data Pig i data Cow są instancjami Show.

Wiem, że mógłbym zrobić to mieć showPig i showCow metod i napisać cały kompleks show przykład, ale w rzeczywistości sprawy są bardziej skomplikowane niż to i to byłoby dość uciążliwe.

Czy istnieje prosty, elegancki sposób na zagwarantowanie, że instancje rodzinne typu będą same instancjami niektórych klas?

+1

Nie zawiedzie z powodu linii 'LANGAUGE'? –

+1

To nie jest cały plik; Zmniejszyłem to dla celów tego pytania. Oczywiście istnieje deklaracja modułu, importowanie ParserCombinators.Parsec i tak dalej. – So8res

+2

Myślę, że Matt miał na myśli fakt, że linia określa 'LANGAUGE', podczas gdy powinno być' LANGUAGE'. –

Odpowiedz

8

Można użyć StandaloneDeriving, aby ręcznie określić ograniczenia tylko dla instancji Show.

{-# LANGUAGE StandaloneDeriving, FlexibleContexts, UndecidableInstances #-} 
deriving instance (Show (Pig c), Show (Cow c)) => Show (Farm c) 

ten będzie nadal pozwalają mieć Configuration instancji z Cow i Pig które nie implementują Show jednak, dopóki nie próbują show im.

1

Ponieważ powiedział pan chciał życie wszystkie instancje Configuration mieć Pig c i Cow c wdrożyć Show, jeszcze prostszy sposób to zrobić jest po prostu ograniczyć rodzinom typu w kontekście klasy, na przykład tak:

{-# LANGUAGE TypeFamilies, FlexibleContexts #-} 

class (Show (Pig c), Show (Cow c)) => Configuration c where 
    data Pig c 
    data Cow c 

data Farm c = Farm { pigs :: [Pig c], 
        cows :: [Cow c] } deriving (Show) 

EDIT:

Jak @hammar wskazał w swoim komentarzu, poprzedni kod nie zostanie skompilowany. Jednym ze sposobów rozwiązania tego problemu jest użycie StandaloneDeriving, zgodnie z sugestią. Innym sposobem jest taka:

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

class (Show (Pig c), Show (Cow c)) => Configuration c where 
    data Pig c 
    data Cow c 

data Farm c where 
    Farm :: Configuration c => { pigs :: [Pig c], 
           cows :: [Cow c] } -> Farm c deriving (Show) 

Te dwa podejścia Ci nieco inne wyniki, w podejście @ hammar będzie wymagają się Configuration ograniczenia jeśli zadzwonisz show, natomiast moje podejście udostępniają powiedział ograniczenie.

+1

To nie jest kompilowane (przynajmniej przy użyciu GHC 7.4.1). Jednak połączenie tego z podejściem 'StandaloneDeriving' przy użyciu' wyprowadzania konfiguracji instancji c => Show (Farm c) 'pozwala uniknąć konieczności stosowania" UndecidableInstances ". – hammar

Powiązane problemy