Haskell 确保类型族将派生某些类

Haskell 确保类型族将派生某些类,haskell,type-families,Haskell,Type Families,我有如下几点: {-# 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] } der

我有如下几点:

{-# 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
由于
派生显示
行,此操作失败。我不知道如何强制所有
配置
实例以确保它们的
数据清管器
数据奶牛
实现都是
显示
的实例

我知道我可以让它有
showPig
showCow
方法,并写出整个复杂的
show
实例,但事实上事情比这更复杂,这将是一个相当痛苦的过程


是否有一种简单、优雅的方法来保证类型族实例本身就是某些类的实例?

您可以使用
独立派生
手动指定约束,仅用于
显示
实例

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

这仍然会让您拥有
配置
实例,其中
Cow
Pig
未实现
显示
,但是,只要您不尝试
显示

既然您说过要强制所有
配置
的实例使用
Pig c
Cow c
实现
显示
,那么更简单的方法就是在类的上下文中简单地约束类型族,如下所示:

{-# 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)
编辑:

正如@hammar在他的评论中指出的,前面的代码不会编译。解决这一问题的一种方法是按照他的建议,使用
独立派生。另一种方式是:

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

这两种方法得到的结果略有不同,因为如果调用
show
,@hammar的方法将需要
配置
约束,而我的方法将提供所述约束。

它不会因为
LANGAUGE
行而失败?这不是整个文件;为了这个问题,我把它删减了。显然有一个模块声明,一个ParserCombinators.Parsec import,等等。我认为Matt的意思是,行状态为
LANGAUGE
,而它应该是
LANGUAGE
。这不会编译(至少使用GHC 7.4.1)。但是,使用
派生实例配置c=>Show(farmc)
将其与
标准派生方法相结合,可以避免使用
不可判定实例。