ivanperez-keera/dunai

Use a better ListT

turion opened this issue · 10 comments

The ListT implementation we're using (from transformers) is wrong (it's just m [a]) and we should eventually settle for a different, correct version.

What would the behaviour of other versions be?

Following https://wiki.haskell.org/ListT_done_right, it would be like so:

-- The monadic list type
data MList' m a = MNil | a `MCons` MList m a
type MList m a  = m (MList' m a)
 
-- This can be directly used as a monad transformer
newtype ListT m a = ListT { runListT :: MList m a }

By the way, this is isomorphic to our MStream. It interleaves one effect of m with one element of the list.

Also, is this the reason that Control.Monad.Trans.MSF.List is not listed in dunai.cabal? (Because it's deemed incorrect?)

I don't see any reason not to list it. If there ever was one, I can't recall.

So, the difference is how the effects in the monad m get unfolded (one by one vs all at once).

Yes. Although I don't see anything wrong with ListT only working for commutative monads in principle.

So, essentially, it is possible to obtain the current behaviour with a helper function:

listT2List :: ListT m a -> m [a]
listT2List = mlistT2List . runListT

mlistT2List :: MList m a -> m [a]
mlistT2List MNil            = return []
mlistT2List (MCons a listT) = do
  as <- mlistT2List listT
  return (a : as)

And, probably:

mlistT2List = reverse . foldM (\xs a -> return (a:xs)) []

I also see no reason not to support the so-called broken ListT. So this ticket could be "provide combinators/lifting/running functions for another list transformer".

This currently is not bugging me at all. I can either close it and you can re-open when it becomes the one issue you (@turion ) are actively working on, or assign it to you and forget about it.

This issue has been stagnated for over 3 years. I'm closing it.