2012-09-13 9 views
5

ho qualcosa di simile alla seguente:garanzia che le famiglie di tipo deriveranno alcune classi

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

Questo non riesce a causa della linea deriving Show. Non so come forzare tutte le istanze Configuration per garantire che le relative implementazioni data Pig e data Cow siano tutte istanze di Show.

So che potrei farlo hanno showPig e showCow metodi e la scrittura l'intero complesso show esempio, ma in realtà le cose sono più complesse di questo e che sarebbe piuttosto un dolore.

Esiste un modo semplice ed elegante per garantire che le istanze della famiglia tipo siano esse stesse istanze di determinate classi?

+1

Non fallisce a causa della linea 'LANGAUGE'? –

+1

Questo non è l'intero file; L'ho ridotto per gli scopi di questa domanda. Ovviamente c'è una dichiarazione del modulo, un'importazione ParserCombinators.Parsec e così via. – So8res

+2

Penso che Matt abbia inteso il fatto che la riga indica 'LANGAUGE' mentre dovrebbe essere' LANGUAGE'. –

risposta

8

È possibile utilizzare StandaloneDeriving per specificare manualmente i vincoli solo per l'istanza Show.

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

Questo vi permetterà di avere ancora Configuration istanze con Cow e Pig che non implementano Show, tuttavia, fino a quando non si tenta di show loro.

1

Dal momento che hai detto che volevi forza tutte le istanze di Configuration di avere Pig c e Cow c attuare Show, un modo ancora più semplice per farlo è quello di limitare semplicemente le famiglie tipo nel contesto della classe, in questo modo:

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

Come @hammar ha sottolineato nel suo commento, il codice precedente non viene compilato. Un modo per risolvere questo problema è utilizzare StandaloneDeriving, come suggerito. L'altro modo è questo:

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

Questi due approcci si ottengono risultati leggermente diversi, in approccio che @ di Hammar sarà richiederà un vincolo Configuration se si chiama show, mentre il mio approccio sarà a disposizione detto vincolo.

+1

Questo non viene compilato (utilizzando almeno GHC 7.4.1). Tuttavia, combinando questo approccio con l'approccio 'StandaloneDeriving' usando' Ricava istanza Configuration c => Show (Farm c) 'evita la necessità di' UndecidableInstances'. – hammar

Problemi correlati