2

For awhile now, whenever people mention the performance hit of free monad + interpreter pattern, I've had this vague idea in my head that: "Why not just use Template Haskell to evaluate your interpreter at compile time? Thus negating the performance hit of free monads entirely, essentially turning the free monad + interpreter pattern into a free monad + compiler pattern."

Making this a little more concrete, let's say I have something like the following:

data MyFreeF a = ...
type MyFreeM a = (Free MyFreeF) a

interpret :: MyFreeM a -> IO a
interpret = ...

compileFree :: MyFreeM a -> Q (TExp (IO a))
compileFree m = let x = interpret m in [|| x ||]

So, this seems on the surface like it should work. The issue I run into here is that this requires that Lift be derived for IO a. So my question is: Is such a thing possible? If not, does deriving Lift for IO a even make sense (i.e. we can't do this today, but if we had X, Y, and Z future GHC extension, we could!)?

So far I have tried using DeriveLift for IO and its constituent components (Like State#) as defined in GHC.IO, but was not able to get far.

Nathan BeDell
  • 2,263
  • 1
  • 14
  • 25
  • I don't think so -- such an instance would have to be able to inspect an `IO` action without running it, which sounds dubious. I think you could, however, have `interpret` return a `TExp` directly -- essentially just write `interpret` how you would have normally, except quasiquoted. – luqui Feb 28 '21 at 22:10
  • @luqui Unfortunately I don't think that is possible in non-trivial cases. That was an approach I tried previously -- GHC stage restrictions get in the way because of the recursive definition of the interpreter. – Nathan BeDell Feb 28 '21 at 22:12
  • that's a good point. Your compiler is not going to be able to compile an infinitely large program, which is what the recursive definition would get you -- you would have to encode the recursion in some way visible to your compiler. – luqui Feb 28 '21 at 22:13

0 Answers0