2012-09-13 78 views
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實例,但在現實中的事情比這更復雜,這將是一個相當痛苦。

是否有一種簡單而優雅的方式來保證類型族實例本身就是某些類的實例?

+1

它不會因爲'LANGAUGE'行而失敗嗎? –

+1

這不是整個文件;爲了這個問題,我削減了它。顯然有一個模塊聲明,一個ParserCombinators.Parsec導入,等等。 – So8res

+2

我認爲馬特的意思是這條線表示「LANGAUGE」,而它應該是'LANGUAGE'。 –

回答

8

您可以使用StandaloneDeriving手動指定約束條件爲Show實例。

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

這仍然會讓你有CowPigConfiguration情況下不執行Show,但是,只要你不要試圖show他們。

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。另一種方法是這樣的:

​​

這兩種方法讓你略微不同的結果,在@哈馬爾的方法將需要一個Configuration約束,如果你打電話show,而我的方法將使可用表示約束。

+1

這不會編譯(至少使用GHC 7.4.1)。然而,使用'派生實例Configuration c => Show(Farm c)''將'StandaloneDeriving'方法結合起來可以避免使用'UndecidableInstances'。 – hammar