Demarcating monad transformers.

Hi Café, Below I describe what I call «demarcating monad transformer». It works great for my purposes, though the construction feels a bit awkward. Perhaps, this is just an instance of a general case. For details and example, see [1] (single module package). Recently I got a challenge of manipulating transformed monadic values. In my case the value was of type t (Free f) a (or MonadFree m => t m a). The challange itself was to provide a function: transform :: (Functor f, MonadTrans t) => (forall b. f b -> t (Free f) b) -> t (Free f) a -> t (Free f) a The type t (Free f) a for my purposes can be read as «a program with low-level API specified with functor f and extra features specified with monad transformer t». transform takes a “basic transformation” phi and an abstract program p and applies phi whenever p “executes” command of free functor f. It turns out that this function is impossible (try StateT). The point is that you can't “get inside” of transformed monadic value. So I came up with idea of «demarcating» monad transformer. By «demarcating» I mean separating pure monadic computations (lifted m a) from transformed ones (t m a). Such separation can be made explicit with the help of free monads: data DemarcateF t m next = forall b. DemarcateMonad (m b) (b -> next) -- "pure" monadic computation | forall b. DemarcateTrans (t m b) (b -> next) -- transformed monadic computation instance Functor (Demarcate t m) where ... -- getting monad for freenewtype Demarcate t m a = Demarcate { unDemarcate :: Free (DemarcateF t m) a } instance Monad (Demarcate t m) where ...instance MonadTrans (Demarcate t) where ... With that I can define transform functions: -- transform arbitrary monadic computationtransformDemarcateM :: (forall b. m b -> Demarcate t m b) -> Demarcate t m a -> Demarcate t m a -- transform free monadic actionstransformDemarcateFree :: (forall b. f b -> Demarcate t (Free f) b) -> Demarcate t (Free f) a -> Demarcate t (Free f) atransformDemarcateFree phi = transformDemarcateM (iterM phi) The complete code is available at [1]. Check out examples/simple.hs for a use case. Now the questions are: - has anyone else encountered such a challenge? - is this solution an instance of a more general pattern? - is it sensible to use Demarcate t m a when m is not a free monad? - how Demarcate may affect the performance? Thanks in advance, Nick [1] https://github.com/fizruk/demarcatehttps://github.com/fizruk/demarcate
participants (1)
-
Nickolay Kudasov