2012-08-30 37 views
10

有沒有辦法讓默認類型實例相互定義?我試圖得到這樣的工作:相互引用的默認類型實例

{-# LANGUAGE DataKinds, KindSignatures #-} 
{-# LANGUAGE TypeFamilies #-} 
{-# LANGUAGE UndecidableInstances #-} 
data Tag = A | B | C 

class Foo (a :: *) where 
    type Bar a (b :: Tag) 

    type Bar a A =() 
    type Bar a B = Bar a A 
    type Bar a C = Bar a A 

instance Foo Int where 
    type Bar Int A = Bool 

test :: Bar Int B 
test = True 

但這不起作用:

Couldn't match type `Bar Int 'B' with `Bool' 
In the expression: True 
In an equation for `test': test = True 

注意,這並不工作之一:

test :: Bar Int B 
test =() 

回答

3

是,默認類型實例可以相互定義(如您可以從您自己的示例中看到的那樣):

instance Foo Int where 
-- So the default recursive definition will be used instead 
-- type Bar Int A = Bool 

test :: Bar Int B 
test =() 

然而,當您重新定義您的實例定義相關類型的代名詞Int更換的Bar整個默認的3線確定指標(而不僅僅是type Bar a A =())用一條線type Bar Int A = Bool這意味着Bar Int BBar Int C不再定義。

所以我想的使用遞歸的默認設置你想要的方式方法之一是重新定義特定的同義詞,而不是(雖然它是相當冗長):

class Foo (a :: *) where 
    type Bar a (b :: Tag) 
    type Bar a A = BarA a 
    type Bar a B = BarB a 

    type BarA a 
    type BarA a =() 

    type BarB a 
    type BarB a = Bar a A 

-- This now works 
instance Foo Int where 
    type BarA Int = Bool 

test :: Bar Int B 
test = True 

裏面可以回落到默認值:

-- As well as this one 
instance Foo Int where 
-- type BarA Int = Bool 

test :: Bar Int B 
test =()