我有以下内容:
{-# 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 Pig
和data Cow
实现都是Show
的实例。
我知道我可以使用showPig
和showCow
方法并写出整个复杂的show
实例,但实际上事情比这更复杂,而且相当痛苦。
是否有一种简单,优雅的方法来保证类型族实例本身就是某些类的实例?
答案 0 :(得分:8)
您可以使用StandaloneDeriving
手动为Show
实例手动指定约束。
{-# LANGUAGE StandaloneDeriving, FlexibleContexts, UndecidableInstances #-}
deriving instance (Show (Pig c), Show (Cow c)) => Show (Farm c)
这仍然会让Configuration
Cow
个实例与Pig
和Show
无法实现show
,但是,只要您不尝试{ {1}}他们。
答案 1 :(得分:1)
既然你说强制 Configuration
的所有实例都有Pig c
和Cow 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可用表示约束。