I have a halogen application where all the components live inside my own AppMonad (which is just derived from ReaderT and has, for example, the baseUrl for external requests stored).
I’m wrapping a Javascript library that wants a function String -> Effect (Array a) (for some a, not important).
I have a function fetchStuff :: String -> AppMonad (Array a) and I’d like to pass that to the JS function.
How do I do that elegantly? I mean, I can just run the app monad, again passing the proper parameters. But that seems a bit clumsy.
In the general case this is a complex problem. Various solutions like monad-control (in haskell) and Concur’s shiftMap were invented for this but none of them seem completely satisfactory (and might actually conceal bugs), so I would recommend just writing your own simple helper functions that work for your use case until you need a more general thing.
In your simple reader case you can hide the clumsiness behind a function that reads the value, extracts the effect value and calls the js function.
runIO :: ReaderT Effect a -> (Effect a -> Effect r) -> ReaderT Effect r
runIO m f = do
r <- ask
liftEffect (f $ runReaderT m r)