5

我有以下内容:

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

deriving Show由于这条线,这失败了。我不知道如何强制所有Configuration实例确保它们data Pigdata Cow实现都是Show.

我知道我可以让它拥有showPigshowCow方法并写出整个复杂的show实例,但实际上事情比这更复杂,那将是相当痛苦的。

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

4

2 回答 2

8

您可以使用仅为实例StandaloneDeriving手动指定约束。Show

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

但是,只要您不尝试使用它们,这仍然可以让您拥有未实现的Configuration实例。CowPigShowshow

于 2012-09-13T18:59:50.333 回答
1

既然您说您想强制的所有实例Configuration具有Pig cCow c实现Show,那么更简单的方法是简单地在类的上下文中约束类型族,如下所示:

{-# 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 在他的评论中指出的那样,前面的代码不会编译。StandaloneDeriving正如他所建议的那样,解决此问题的一种方法是使用。另一种方式是这样的:

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

这两种方法得到的结果略有不同,如果你调用@hammar 的方法将需要一个约束,而我的方法将提供所述约束。Configurationshow

于 2012-09-14T20:00:54.313 回答