Lawful list and set monad transformers based on free monads.
This package provides a lawful ListT implementation based on free monads. It also provides an _Applicative_ list transformer, which is a lawful Applicative, and isomorphic to the old ListT.
Free ListT
This package provides a lawful ListT implementation based on free monads. It also provides an Applicative list transformer, which is a lawful Applicative, and isomorphic to the old ListT.
Background
The old ListT transformer from transformers < 0.6 was unlawful: For a noncommutative monad, ListT m was not a monad. It was implemented simply as the composition of list and m:
newtype ListT m a = ListT (m [a])
As such, it is automatically a lawful Functor and Applicative in a canonical way. But famously, a composition of two monads is not always a monad, and in this case, it in fact isn't.
Previous approaches
Streaming
There is one popular approach to ListT, representing the transformer as a stream:
newtype ListT m a = ListT (m (Maybe (a, ListT m a)))
This approach is implemented in https://hackage.haskell.org/package/list-t and https://hackage.haskell.org/package/list-transformer, and it is a great choice in many cases.
Basically, to go through the list, one has to perform one effect in m at each step, and one discovers whether the list now ends or produces a further element. But this also means that the list structure enforces all earlier m effects before a later element can be accessed.
Church-encoding
Another possibility is Church-encoding the list, which is implemented in logict.
Free approach
A simple algebraic approach that does not enforce the linear structure of streaming ListT is a free monad:
newtype ListT m a = ListT (FreeT [] m a)
This gives a branching rose tree of computations, where at every step in m, arbitrarily many branches can arise.
Unfolding the definition of FreeT as an algebraic datatype would result in something like:
data ListT m a = OneLayer (m a) | TwoLayers (m [m a]) | ThreeLayers (m [m [m a]]) | ...
Applicative transformer
As mentioned already, the old ListT is a valid Applicative transformer, which means that ListT m is a lawful Applicative as long as m is. This is useful and sufficient in many situations, which is why it is reinstated here.
Also, values of type m [a] occur very often in the wild (for example when using mapM), so it makes sense to give them a proper type that captures their properties.
To give some more examples, all lawful ListT implementations have some kind of "running" function that maps it to m [a]. The free ListT is no exception here. In a sense, one can "flatten" or "concatenate" all free list layers into a single one. While this is a natural transformation, this is of course not a monad morphism.