If you use :info showX you'll see the type you expect. If you use :type showX you are using :type with an "arbitrary expression" that turns out to be a single identifier. So GHC instantiates it with fresh type variables, generates constraints, simplifies them, and then re-generalises. The instantiation, constraint simplification, and regeneration is what expands the constraint synonym, and I don't see a robust way to stop that happening.

We could make :type behave like :info when given a bare identifier. Or, in those same circumstances, we would make :type refrain from the "instantiate, simplify, generalise" hoopla. But that would make :type on a bare identifier behave subtly differently to the way it does now.Is that special case worth it? Or would it be better to encourage users to use :info whenever possible?

I just assumed this can be similar to how ghc doesn't expand ordinary type synonyms unless necessary, but from what you're saying it sounds like it's different for constraints?

An even more important feature would be to preserve the synonym names in type errors. That'd allow to make such errors more domain-specific and informative, while an expanded version is very complex and essentially reveals a lot of internal details of the library.

Now if you instantiate and re-generalise it's really not possible to reconstruct the Foo a. I suppose you could have a magical special case when there is a type synonym for a single constraint. That might, just, be possible. But it'd be a bit of effort to push it through, so I propose to wait until more people yell.