Rudi wrote a post which mentioned cohttp and abstracting over Lwt and async monads.
He notes that the standard approach (modules and functors) has some downsides (syntactically heavy; and unlike plain functions where type inference is automatic and works well, modules often require explicit type annotations and sharing constraints; moreover, even if we have first-order modules, in practice first-order modules seem to lack a few features that “normal” modules have, so code where the module implementation depends on runtime information is hard to write).
My question is: if I really want to write code that somehow is parametric over the monad involved, are there alternatives to modules and functors? Is there some clever encoding using plain functions? Or something else (typeclasses?)?
I played around with a “generic” monad ('a,'m)m = ('a -> 'm) -> 'm but didn’t get far.
I also tried the GADT approach via a generic/free/syntactic monad (type 'a m = Return: 'a -> 'a m | Bind: ('a m) -> ('a -> 'b m) -> 'b m), and then writing a map from this to the particular monad.
Are there any other options?