2012-09-13 1 views
5

tengo algo como lo siguiente:Garantizar que las familias de tipo derivarán ciertas clases

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

Esta falla debido a la línea deriving Show. No sé cómo forzar todas las instancias Configuration para garantizar que sus implementaciones data Pig y data Cow sean todas instancias de Show.

Sé que podría hacer que tenga showPig y showCow métodos y la escritura a cabo toda la instancia compleja show, pero en realidad las cosas son más complejas que esto y eso sería bastante dolor.

¿Existe alguna manera fácil y elegante de garantizar que las instancias familiares de tipo sean en sí mismas instancias de ciertas clases?

+1

¿No falla debido a la línea 'LANGAUGE'? –

+1

Ese no es todo el archivo; Lo reduje para propósitos de esta pregunta. Obviamente hay una declaración de módulo, una importación ParserCombinators.Parsec, y así sucesivamente. – So8res

+2

Creo que Matt entendió el hecho de que la línea dice 'LANGAUGE' mientras que debería ser' LANGUAGE'. –

Respuesta

8

Puede usar StandaloneDeriving para especificar las restricciones manualmente solo para la instancia Show.

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

Esto todavía le permiten tener Configuration instancias con Cow y Pig que no implementan Show, sin embargo, siempre y cuando no se trate de show ellos.

1

ya que dijo que quería fuerza todas las instancias de Configuration que tienen Pig c y Cow c implemento Show, de una manera aún más sencilla de hacer esto es simplemente limitar las familias de tipo en el contexto de la clase, así:

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

Como @hammar señaló en su comentario, el código anterior no se compilará. Una forma de solucionar esto es usar StandaloneDeriving, como sugirió. La otra forma es la siguiente:

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

Estos dos enfoques se obtienen resultados ligeramente diferentes, en el enfoque que @ de Hammar se requerir una restricción Configuration si llama show, mientras que mi enfoque poner a disposición dicho restricción.

+1

Esto no se compila (usando GHC 7.4.1, al menos). Sin embargo, al combinar esto con el enfoque 'StandaloneDeriving' usando 'derivando la instancia Configuration c => Show (Farm c)' se evita la necesidad de 'UndecidableInstances'. – hammar

Cuestiones relacionadas