Ответ 1
Да, экземпляры типа по умолчанию могут быть определены в терминах друг друга (как вы можете видеть из своего собственного примера):
instance Foo Int where
-- So the default recursive definition will be used instead
-- type Bar Int A = Bool
test :: Bar Int B
test = ()
Однако, когда вы переопределяете связанный синоним типа в определении вашего экземпляра для Int
, вы заменяете целую по умолчанию на 3 строки Bar
(а не только type Bar a A = ()
) одной строкой type Bar Int A = Bool
, что означает Bar Int B
и Bar 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 = ()