How to cleanly convert ListT monads between lists and transformers?

I am currently writing a project in which I heavily use the monata ListT transformer. When using simple lists, the implementation of non-determinism is very simple. However, as soon as I had to convert my code to ListT , it became much more complicated than 1 .

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

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

Although simple, I am surprised that it does not exist yet.

Questions:

  • Is there a better way to deal with non-determinism where a monad transformer is needed?
  • Are there any methods / libraries for easy and convenient conversion between lists and ListT ?

1 The exact reasons are pretty complicated, so I really don't want to talk too much about it.

+6
source share
2 answers

I do not think there are libraries for this; conv is an incredibly simple function, after all, and vice versa - it's just runListT .

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

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

I would recommend calling it something on the liftList lines. 1

Regarding the best monad transformer for non-determinism, I recommend taking a look at the logict package based on Oleg LogicT , which is the logical logic of the back trace logic with some useful operations . As a bonus, since [] is an instance of MonadLogic , these operations also work on lists.


1 Interestingly, we can define a function that generalizes the conv and liftMaybe :

 import Data.Foldable (Foldable) import qualified Data.Foldable as F choose :: (Foldable t, MonadPlus m) => ta -> ma choose = F.foldr (\ab -> return a `mplus` b) mzero 

This will probably make your code rather confusing, so I do not recommend using it :)

+6
source

I just came across this question a few months later because I was interested in something like this. So I came up with the following:

 {-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-} import Control.Monad.Trans.Class import Control.Monad.Trans.Maybe import Control.Monad.Trans.List -- | Minimal implementation: either joinLift or joinT class (MonadTrans t, Monad m) => MonadTransJoin tm | m -> t, t -> m where joinLift :: (Monad m', Monad (t m')) => m' (ma) -> tm' a joinLift = joinT . lift joinT :: (Monad m', Monad (t m')) => tm' (ma) -> tm' a joinT = (>>= (joinLift . return)) instance MonadTransJoin MaybeT Maybe where joinLift = MaybeT joinT = (>>= maybe mzero return) instance MonadTransJoin ListT [] where joinLift = ListT joinT = (>>= foldr mcons mzero) where mcons x xs = return x `mplus` xs 

So far, so good, and my joinT method for ListT / [] pair looks like it has something to do with ehird choose .

But the problem is that there really is no single interface between the monad transformer and the monad, whose behavior it endows with its base monad. We have MaybeT :: m (Maybe a) -> MaybeT ma and ListT :: m [a] -> ListT ma , but OTOH we have StateT :: (s -> m (a, s)) -> StateT sma . I don’t know if there is a way around this - it definitely requires

0
source

Source: https://habr.com/ru/post/908055/


All Articles