相互引用的默认类型实例

Cac*_*tus 10 haskell typeclass type-families

有没有办法让默认类型实例相互定义?我想尝试这样的工作:

{-# 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
Run Code Online (Sandbox Code Playgroud)

但这不起作用:

Couldn't match type `Bar Int 'B' with `Bool'
In the expression: True
In an equation for `test': test = True
Run Code Online (Sandbox Code Playgroud)

请注意,这也不起作用:

test :: Bar Int B
test = ()
Run Code Online (Sandbox Code Playgroud)

Ed'*_*'ka 3

是的,默认类型实例可以相互定义(正如您从自己的示例中看到的那样):

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

test :: Bar Int B
test = ()
Run Code Online (Sandbox Code Playgroud)

但是,当您在实例定义中重新定义关联类型同义词时,Int您将(而不仅仅是) 的整个默认 3 行定义替换为一行,这意味着和不再定义。Bartype Bar a A = ()type Bar Int A = BoolBar 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
Run Code Online (Sandbox Code Playgroud)

可以回退到默认值:

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

test :: Bar Int B
test = ()
Run Code Online (Sandbox Code Playgroud)