"Data types à la carte" vs. nested FreeT transformers
haskell, monads
Solution
I'm not 100% confident in my own understanding of this, so if anyone notices anything (blatantly) wrong, please point it out.
Starting with Extensible Effects, the `Eff` type is basically isomorphic to:
data Eff :: [* -> *] -> * -> * where
Pure :: a -> Eff es a
Side :: Union es (Eff es a) -> Eff es a
where `Union es a` is a union/sum type of the list of types `es` parameterized by `a`. `Union` is isomorphic to repeated applications of `:+:` from Data Types a la Carte. To sum (!) it all up, `Eff` seems to be an optimized version of Data Types a la Carte.
We may conclude that the differences between monad transformers and extensible effects described in the paper apply here. In particular, free monad transformer stacks cannot interleave effects, while Data Types a la Carte/Extensible Effects can.
Problem
In the comments to this question, it has been mentioned that nesting several layers of FreeT transformers (each with a different functor) can serve a similar purpose to the "Data types à la carte" approach (that combines the functors themselves using coproducts) despite the two approaches not being isomorphic. My question is: where does the difference lie? Are there cases that one approach can handle, but not the other? Do they admit different interpreters? Update: Here's a simple example of nested `FreeT` transformers. Augmenting a computation with the ability to emit log messages and request delays: ``` import Data.Functor.Identity import Control.Monad import Control.Monad.Trans import Control.Monad.Trans.Free import Control.Concurrent type Delay = Int type DelayT = FreeT ((,) Delay) delay :: Monad m => Delay -> DelayT m () delay t = liftF (t,()) type Message = String type LogT = FreeT ((,) Message) emitLog :: Monad m => Message -> LogT m () emitLog msg = liftF (msg,()) type Effected = DelayT (LogT Identity) program :: Effected Char program = lift (emitLog "foo") >> delay 1000 >> return 'c' interpret :: Effected a -> IO a interpret = (iterT $ \(d,a)->threadDelay d >> a) . hoistFreeT (iterT $ \(m,a)->putStrLn m >> a) . hoistFreeT (hoistFreeT (return . runIdentity)) main :: IO () main = interpret program >>= putChar ``` (This particular example could have been made even simpler by using `Producer`s from the `pipes` package, which are a particular kind of free monad transformers.)