In haskell it’s very common pattern to use mtl-style typeclasses with monads, where in most of the code, you don’t write it for a concrete monad, but rather a list of the capabilities you want.
doSomething :: (MonadReader Cfg m, MonadError Err m) => Foo -> m Bar
which is very nice for both flexibility and the ability to show exactly what your code can do. However, it can sometimes have a large performance penalty [1] [2].
Now there are options like the {-# SPECIALIZE #-}
pragma, but that would force you to litter every single function with it. And conversely, there’s -fspecialize-agressively
, which solves the issue, but instead causes the compilation time and memory use of GHC to increase drastically [3].
What I’m suggesting is something in-between of these two options, where you make a global setting for your whole program to always specialize one list of typeclasses to another list of concrete types. One option would be that you can place these annotations either next to the declarations of the type classes or next to the concrete type. In other words, the same places where you can put an instance declaration.
The issue with the latter location is that it might be difficult for ghc to see that annotation in code that only imports the type class and not the concrete type, while an issue with the former option is that you can’t place the annotation on typeclasses which you don’t own.
Another option would be to not be explicit about the pair to specialize, but to say “always specialize this specific typeclass as much as possible” and/or “always specialize to this concrete type whenever you can”. This would for example allow us to place these on the generic monad type classes, since you’ll almost always want those specialized for performance. The risk here is that we don’t get much improvement over -fspecialize-agressively
.
What do people think about this idea? Can something like this be done already? Is there a better place than here to bring this up?