Help needed using ReaderT in Free monad interpreter

I’m a PureScript/Haskell beginner.
For learning purposes I ported my TypeScript util for validating translation files to PS. I’m experimenting with various architectures such as MTL, FT and Free.

I have a bunch of data types representing either valid or invalid translations which I want to render, starting by simply logging to console and maybe later extend to web UI.
While trying Free monad approach I wanted to hide ReaderT in interpreter to be able to track indent level and set filter. However the Reader context is not preserved in next instruction.

Here is a simplified gist where I have two instructions, one for setting the filter and second for reading the current value:

When calling local and then sending next data type to it, the reader context is lost. I still have only high-level understanding of monad transformers and Free monad. I guess it might be something the foldFree function is doing.

Is something like this possible or I am doing it totally wrong?

Thanks for help.

You can think of foldFree as being like foldMap. So like foldMap, which will map elements in a container to some Monoid and append them together, foldFree interprets each instruction into some Monad and then binds them together. Your intuition is that next is the next part of the program, but it’s not the full story in this case, since it’s universally quantified (forall). Remember, to actually execute your program, there needs to be a bind, but next is lifted via pure. To have the appropriate associativity that you want with local, you’d need something that lets you do:

example next =
  local do

instead of

example next =
  local do
    pure next

This is not possible with foldFree, since it’s semantically a monoidal operation.

To do what you wanted, you would need something that lets you do:

foldrFree :: forall f m a. (forall x. f (m x) -> m x) -> Free f a -> m a

With some set of constraints, I’m sure (maybe Functor f and Monad m).

An alternative is to not use Reader, and local, but use State with some sort of push and pop operations to track your own stack. This does not require nesting.


Oh, I get it.
I will try to experiment with both approaches you suggested.

Thanks very much for help