2012-08-30 6 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(だけでなくtype Bar a A =())の全体デフォルトの3ライン定義のそれぞれで独立し置き換えるBar Int BBar Int Cはもはや定義されていることを意味しない1行type Bar Int A = Boolと。

だから私はあなたが意図した方法を再帰的なデフォルトを使用する方法の一つは、(それはかなり冗長ですが)の代わりに、特定のシノニムを再定義することであると思います。

バックデフォルトに落ちることができ
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 =() 
関連する問題