保证类型系列将派生某些类

时间:2012-09-13 18:35:00

标签: 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]
    } deriving Show

由于deriving Show行而失败。我不知道如何强制所有Configuration个实例,以确保他们的data Pigdata Cow实现都是Show的实例。

我知道我可以使用showPigshowCow方法并写出整个复杂的show实例,但实际上事情比这更复杂,而且相当痛苦。

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

2 个答案:

答案 0 :(得分:8)

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

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

这仍然会让Configuration Cow个实例与PigShow无法实现show,但是,只要您不尝试{ {1}}他们。

答案 1 :(得分: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)

这两种方法会给你略有不同的结果,因为如果你调用Configuration,@ hammar的方法将要求 show约束,而我的方法将 make可用表示约束。