Not really an answer, and much too informal for my linking, but nevertheless I have a few interesting observations that won't fit into a comment. First, let's consider this function you refer to:
f :: Monad m => [m a] -> m [a]
This signature is in fact stronger than it needs to be. The current generalization of this is the sequenceA
function from Data.Traversable
:
sequenceA :: (Traversable t, Applicative f) -> t (f a) -> f (t a)
...which doesn't need the full power of Monad
, and can work with any Traversable
and not just lists.
Second: the fact that Traversable
only requires Applicative
is I think really significant to this question, because applicative computations have a "list-like" structure. Every applicative computation can be rewritten to have the form f <$> a1 <*> ... <*> an
for some f
. Or, informally, every applicative computation can be seen as a list of actions a1, ... an
(heterogeneous on the result type, homogeneous in the functor type), plus an n-place function to combine their results.
If we look at sequenceA
through this lens, all it does is choose an f
built out of the appropriate nested number of list constructors:
sequenceA [a1, ..., an] == f <$> a1 <*> ... <*> an
where f v1 ... vn = v1 : ... : vn : []
Now, I haven't had the chance to try and prove this yet, but my conjectures would be the following:
- Mathematically speaking at least,
sequenceA
has a left inverse in free applicative functors. If you have a Functor f => [FreeA f a]
and you sequenceA
it, what you get is a list-like structure that contains those computations and a combining function that makes a list out of their results. I suspect however that it's not possible to write such a function in Haskell (unSequenceFreeA :: (Traversable t, Functor f) => FreeA f (t a) -> Maybe (t (Free f a))
), because you can't pattern match on the structure of the combining function in the FreeA
to tell that it's of the form f v1 ... vn = v1 : ... : vn : []
.
sequenceA
doesn't have a right inverse in a free applicative, however, because the combining function that produces a list out of the results from the a1, ... an
actions may do anything; for example, return a constant list of arbitrary length (unrelated to the computations that the free applicative value performs).
- Once you move to non-free applicative functors, there will no longer be a left inverse for
sequenceA
, because the non-free applicative functor's equations translate into cases where you can no longer tell apart which of two t (f a)
"action lists" was the source for a given f (t a)
"list-producing action."