如何使用通过实例约束的函数依赖性确定的类型参数作为关联类型族方程的 RHS?

How can I use a type parameter determined via the functional dependency of an instance constraint as the RHS of an associated type family equation?

我有这样一个类型类:

class (Coercible a b) => Foo a b | a -> b

我想声明以下 Generic 实例:

data Thing a
  where
  Thing :: Foo a b => b -> Thing a

-- If the @b@ uniquely determined by @a@ is @Generic@, so is @Thing a@ ...
instance (Foo a b, Generic b) => Generic (Thing a)
  where
  type Rep (Thing a) = Rep b

不幸的是,这不能编译,错误信息是:

[typecheck] [E] • Type variable ‘r’ is mentioned in the RHS,
    but not bound on the LHS of the family instance
• In the type instance declaration for ‘Rep’
  In the instance declaration for ‘Generic (UnvalidatedData v)’

我知道我想要的在语义层面是可能的,因为如果我使用类型族而不是函数依赖如下:

class (Coercible a (B a)) => Foo' a
  where
  type B a :: Type

我可以声明:

data Thing a
  where
  Thing :: Foo' a => B a -> Thing a

-- If the @B a@ uniquely determined by @a@ is @Generic@, so is @Thing a@ ...
instance (Foo' a, Generic (B a)) => Generic (Thing a)
  where
  type Rep (Thing a) = Rep (B a)

不幸的是,关联类型族根本没有出现在类型类中,因此在传递类时不可能对关联类型族进行高阶推理。出于这个原因,我更愿意使用函数依赖而不是类型族。

使用多参数类型类的 FooThingThingGeneric 实例的最接近工作近似值是什么(如果有的话)?

我能想到的最好办法是同时使用函数依赖性和类型族,并尝试获得两全其美的情况:

class (Coercible a b, b ~ B a) => Foo a b | a -> b where
  type B a :: Type

data Thing a where
  Thing :: Foo a b => b -> Thing a

instance (Foo a b, Generic b) => Generic (Thing a) where
  type Rep (Thing a) = Rep (B a)

它不是非常优雅,但是在 Foo 的约束中使用 b ~ B a 意味着您不会意外地搞砸 Foo 的实例。例如,您可以这样写:

instance Foo (Sum a) a where
  type B (Sum a) = a

但是如果你尝试写 type B (Sum a) = Int,你会得到一个错误 arising from the superclasses of an instance declaration