61

I have a multi-parameter typeclass with a functional dependency:

class Multi a b | a -> b

I also have a simple, non-injective type synonym family:

type family Fam a

I want to write an instance of Multi that uses Fam in the second parameter, like this:

instance Multi (Maybe a) (Fam a)

However, this instance is not accepted. GHC complains with the following error message:

error:
  • Illegal type synonym family application in instance: Fam a
  • In the instance declaration for ‘Multi (Maybe a) (Fam a)’

Fortunately, there is a workaround. I can perform a usual trick for moving a type out of the instance head and into an equality constraint:

instance (b ~ Fam a) => Multi (Maybe a) b

This instance is accepted! However, I got to thinking, and I started to wonder why this transformation could not be applied to all instances of Multi. After all, doesn’t the functional dependency imply that there can only be one b per a, anyway? In this situation, it seems like there is no reason that GHC should reject my first instance.

I found GHC Trac ticket #3485, which describes a similar situation, but that typeclass did not involve a functional dependency, so the ticket was (rightfully) closed as invalid. In my situation, however, I think the functional dependency avoids the problem described in the ticket. Is there anything I’m overlooking, or is this really an oversight/missing feature in GHC?

9
  • 2
    It'd be nice to have a self-contained example to be able to explore hypotheses when trying to answer your question.
    – gallais
    Commented Jul 27, 2017 at 21:14
  • 1
    @gallais Do you mean a self-contained practical example? The code in my question, short as it may be, should compile. Commented Jul 27, 2017 at 21:15
  • 1
    I think you've got it right. Ordinarily your second instance would be at risk of overlapping but here the fundep saves you, as you point out. I suspect the reason it hasn't been implemented in GHC is because one could argue that it's a counterintuitive/unexpected feature, which is only useful in specific situations, and which has a straightforward workaround. (To get a definitive answer you'd have to ask a GHC developer, though.) Commented Jul 27, 2017 at 21:34
  • 3
    I’ve opened GHC ticket #14046 to track this issue. I’ll probably delete this question if the answer is simply “because it isn’t implemented that way”. Commented Jul 27, 2017 at 21:59
  • 10
    Please don't delete the question for such a reason.
    – dfeuer
    Commented Jul 27, 2017 at 22:50

1 Answer 1

-2

Based on the comments I think that the problem why the first instance Multi (Maybe a) (Fam a) does not work and if the second one is due to the memory allocation why when you implement this solution it works

instance (b ~ Fam a) => Multi (Maybe a) b

because in this one you are moving (b ~ Fam a) to Multi (Maybe a) where b remains as a reserve

but that's my thinking

1
  • As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Commented Feb 20 at 12:52

Not the answer you're looking for? Browse other questions tagged or ask your own question.