Is there a way to have default type instances defined in terms of each other? I'm trying to get something like this working:
{-# 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
but this doesn't work:
Couldn't match type `Bar Int 'B' with `Bool'
In the expression: True
In an equation for `test': test = True
Note that this doesn't work either:
test :: Bar Int B
test = ()
Yes, default type instances can be defined in terms of each other (as you can see from your own example):
instance Foo Int where
-- So the default recursive definition will be used instead
-- type Bar Int A = Bool
test :: Bar Int B
test = ()
However when you redefine associated type synonym in your instance definition for Int
you replace entire default 3-line defintion of Bar
(and not just the type Bar a A = ()
) with one line type Bar Int A = Bool
which means Bar Int B
and Bar Int C
are no longer defined.
So I guess one of the ways to use recursive defaults the way you intended is to redefine specific synonyms instead (though it is rather verbose):
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
Which can fall back to defaults:
-- As well as this one
instance Foo Int where
-- type BarA Int = Bool
test :: Bar Int B
test = ()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With