2010-04-07 95 views
9

此代碼編譯罰款:問題混合型類和類型的家庭時

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, 
    UndecidableInstances, FlexibleContexts, EmptyDataDecls, ScopedTypeVariables, 
    TypeOperators, TypeSynonymInstances, TypeFamilies #-} 
class Sel a s b where 
    type Res a s b :: * 

instance Sel a s b where 
    type Res a s b = (s -> (b,s)) 

instance Sel a s (b->(c,a)) where 
    type Res a s (b->(c,a)) = (b -> s -> (c,s)) 

,但只要我添加將R謂詞GHC失敗:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, 
    UndecidableInstances, FlexibleContexts, EmptyDataDecls, ScopedTypeVariables, 
    TypeOperators, TypeSynonymInstances, TypeFamilies #-} 
class Sel a s b where 
    type Res a s b :: * 

instance Sel a s b where 
    type Res a s b = (s -> (b,s)) 

class R a where 
    type Rec a :: * 
    cons :: a -> Rec a 
    elim :: Rec a -> a 
instance Sel a s (b->(c,Rec a)) where 
    type Res a s (b->(c,Rec a)) = (b -> s -> (c,s)) 

抱怨說:

Illegal type synonym family application in instance: 
     b -> (c, Rec a) 
    In the instance declaration for `Sel a s (b -> (c, Rec a))' 

這是什麼意思和(最重要的是)我該如何解決它?

由於

+2

沒有第一段代碼不適合我編譯。 GHC(6.12.1)抱怨'衝突的家庭實例聲明'。 – kennytm 2010-04-07 06:49:10

回答

12

類型系列是單向的:您可以將Rec a擴展爲其計算類型,但不能(唯一地)從擴展回到Rec a。這使得類型函數的應用程序不適合實例簽名,因爲它們永遠不會觸發實例應用。

你可以嘗試,而不是:

instance Rec a ~ reca => Sel a s (b->(c,reca)) 

這意味着別的東西:它說,任何功能b -> (c, reca)是一個實例,然後當它已經無可挽回地匹配,編譯器會檢查Rec a ~ reca。但是這可能足以滿足你的需求。

1

Rec不是類型構造函數;這是一個類型函數。也許你只能在類型定義的類型中使用它,而不能在類聲明中使用它?我在這裏瘋狂猜測;我不明白類型家族的所有規則。

我不知道如何解決它,但是有些事情嘗試包括:

  • 擺脫階級SEL的,只是定義type family Res a s b :: *。使用type instance而不是類機制。

  • 使用data製作類型Rec內射幾乎是不可能的,但我不這麼認爲。

  • 減少到可以工作的最小數量的語言擴展—它可以使其他人更容易幫助您,它也可以幫助編譯器。

+1

切換到使用'data'將會起作用 - 實例頭部允許數據族,而類型同義詞族不允許。 – 2010-04-07 06:56:41

1

這意味着在聲明類型實例時不允許使用類型synomym族。請參閱GHC手冊的"Type families and instance declarations"部分。

你可以修復它的唯一方法是重構,以便不需要它。