Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cleanly convert between lists and ListT monad transformers?

I am currently writing a project where I make a heavy use of ListT monad transformer. When using plain lists, implementing nondeterminism is very easy. However once I had to convert my code to ListT, it got much more complicated 1.

As a simple example: converting from [a] to ListT a actually requires composing two functions:

conv :: (Monad m) => [a] -> ListT m a
conv = ListT . return

Though it's simple, I am surprised it's not already there.

Questions:

  • Is there some better way to handle nondeterminism where a monad transformer is needed?
  • Are there any techniques / libraries for converting cleanly back and forth between lists and ListT?

1 The exact reasons are quite complicated, so I don't really want to elaborate too much on that.

like image 312
julx Avatar asked Feb 09 '12 16:02

julx


1 Answers

I don't think there are any libraries for this; conv is an incredibly simple function, after all, and the other way around is just runListT.

conv is similar to the liftMaybe often desired when using MaybeT:

liftMaybe :: (Monad m) => Maybe a -> MaybeT m a
liftMaybe = MaybeT . return

I would recommend naming it something along the lines of liftList.1

As far as a better monad transformer for nondeterminism goes, I recommend taking a look at the logict package, based on Oleg's LogicT transformer, which is a continuation-based backtracking logic monad with some helpful operations. As a bonus, since [] is an instance of MonadLogic, those operations also work on lists.


1 Interestingly, we can define a function that generalises the pattern of conv and liftMaybe:

import Data.Foldable (Foldable)
import qualified Data.Foldable as F

choose :: (Foldable t, MonadPlus m) => t a -> m a
choose = F.foldr (\a b -> return a `mplus` b) mzero

This will probably make your code quite confusing, so I don't recommend using it :)

like image 116
ehird Avatar answered Nov 04 '22 13:11

ehird