Best way to create a typeclass dependency graph?

I was doing some refactors for a project I’m working on, and I found myself in a situation where it would be really handy if I could get a graph of the project’s typeclass dependencies. Including cross-module dependencies.

I did a bit of hacking, and managed to get something working using a GHC plugin and Prolog. The GHC plugin outputs the constraint information for each module into a single Prolog file, and then my Prolog script queries that file to make a Graphviz file for the part of the graph I care about.

This works, but it’s pretty janky and won’t be good enough if we decide to add the tool to our CI. My gut instinct is that I should redo it using our HIE files, so that I can keep everything in Haskell and so that it can be run independently of GHC.

My question is, has anyone done something like this before? If there’s a tool I can reuse, or some thoughts on the best process, I’d appreciate a comment!

There is Calligraphy which works exactly as you describe: it processes HIE files and passes it to Graphviz to produce a graph. I can’t remember if it can specifically process typeclass dependencies, but there are some filtering options available, worth checking out.

What exactly is a type class dependency for you?
Very likely anything in the type class definition, like
class Eq a => Ord a would count as such a dependency.
But what about instances? If your project defines classes A and B and concrete type T :: * -> * and there is an instance

instance A x => B (T x)

would you count that as a dependency?

Anyways, the constraints package might be helpful.

Thanks for the responses!

To give a bit more detail, my project has a tree of typeclasses that we use to form a tagless embedding of a generic programming language. We have an ADT called TypeData, and I need to know which typeclasses reference it in their method signatures, and a graph of the transitive closure of typeclasses that have those as constraints.

Because the typeclasses that I care about are so specific, I’m not sure if I’ll find an off-the-shelf solution. But if something gets part of the way, it could save me some work.