Is it possible to create type family instances from a fundep class? For example, let's say that I have the class
class A a b | a -> b
with some instances (imported an external library) and want to create all corresponding instances for the type family
type family A' a :: *
such that A' a ~ b
iff A a b
, without having to manually copy and modify the instances from the external source.
How would I do that (if it is possible)?
My most promising attempt so far,
class A' a where
type A'_b a :: *
instance forall a b. A a b => A' a where
type A'_b a = b
gives the error message
The RHS of an associated type declaration mentions ‘b’
All such variables must be bound on the LHS
So, my guess is that the answer is no? :/
Don't overthink it.
class C a b | a -> b
instance C T U
roughly translates into
class C' a where
type B a
instance C' T where
type B T = U
They're semantically somewhat different, even though they behave in a similar way. C
is a two-parameter class, but its second parameter is uniquely determined by its first. C'
is a one-parameter class with an associated type. Associated types are interpreted as top-level axioms for FC's coercion system whereas fundeps basically just affect unification.
It is possible to convert between the two styles, but you have to use a newtype
to bind the variables in the type
equation.
newtype WrappedB a = WrappedB { unwrapB :: B a }
instance C' a => C a (WrappedB a) -- you can't use a type synonym family in an instance
newtype Wrap a b = Wrap { unWrap :: a }
instance C a b => C' (Wrap a b) where
type B (Wrap a b) = b -- b needs to be bound on the LHS of this equation
In general I don't advise writing the sort of generic instance you've attempted in your question, because such instances have a tendency to be overlapping.
Functional dependencies are less, um, weird than type families, though. All other things being equal I tend to prefer a fundep.