Use monad list inside monad transformer type classes?

My goal is to create a function that uses the list monad in the ReaderT WriterT stack or the RWS stack. More generally, how to use the monad list inside mtl typeclasses like MonadReader, MonadWriter?

Why am I trying to do this? This issue is an exercise in Haskell Start . He asks me to "use the functions of both MonadReader and MonadWriter, wrapping the monad of the base list. To verify that the function is shared, use two different monads to [verify] the requested functionality: ReaderT r (WriterT w []) a and RWST rwsma " Therefore, the book implies this is possible.

I can't figure out how to tell the compiler to use a list monad. If I use ask >>= lift or ask >>= lift . lift ask >>= lift . lift , I can get either a level 2 stack ( RWST [] ) or 3 stack levels ( ReaderT WriterT [] ), but not both.

At the center of my question:

 pathImplicitStack' start end | start == end = tell [end] pathImplicitStack' start end = do (s0, e0) <- ask >>= lift guard $ s0 == start tell [start] pathImplicitStack' e0 end 

In addition, I would like to know how to enter a function. My best attempt so far looks something like pathImplicitStack' :: (MonadReader [(Int, Int)] m, MonadWriter [Int] m, MonadPlus m) => Int -> Int -> m () I know this is wrong perhaps the list monad is missing. Also, I think MonadPlus might be useful in a type signature, but I'm not quite sure.

This line: do (s0, e0) <- ask >>= lift is something that is not pleasant to me. I tried 0, 1 and 2 elevators without success. I would like to ask for [(Int, Int)] , and then use the list monad to process just (Int, Int) (and let the list monad try all the possibilities for me).

As part of the exercise, I need to be able to call pathImplicitStack' with both of these functions (or very similar functions):

 pathImplicitRW :: [(Int, Int)] -> Int -> Int -> [[Int]] pathImplicitRW edges start end = execWriterT rdr where rdr = runReaderT (pathImplicitStack' start end) edges :: WriterT [Int] [] () pathImplicitRWS :: [(Int, Int)] -> Int -> Int -> [[Int]] pathImplicitRWS edges start end = map snd exec where exec = execRWST (pathImplicitStack' start end) edges () 

This is related to my previous question: How to use list monad inside ReaderT?

Entire file for easy testing:

 {-# LANGUAGE FlexibleContexts #-} module Foo where import Control.Monad.Reader import Control.Monad.Writer import Control.Monad.RWS graph1 :: [(Int, Int)] graph1 = [(2013,501),(2013,1004),(501,2558),(1004,2558)] pathImplicitRW :: [(Int, Int)] -> Int -> Int -> [[Int]] pathImplicitRW edges start end = execWriterT rdr where rdr = runReaderT (pathImplicitStack' start end) edges :: WriterT [Int] [] () pathImplicitRWS :: [(Int, Int)] -> Int -> Int -> [[Int]] pathImplicitRWS edges start end = map snd exec where exec = execRWST (pathImplicitStack' start end) edges () pathImplicitStack' :: (MonadReader [(Int, Int)] m, MonadWriter [Int] m, MonadPlus m) => Int -> Int -> [m ()] pathImplicitStack' start end | start == end = tell [end] pathImplicitStack' start end = do (s0, e0) <- ask >>= lift guard $ s0 == start tell [start] pathImplicitStack' e0 end 

change

Based on the image of John L, I tried

 pathImplicitStack' :: (MonadReader [(Int, Int)] (t []), MonadWriter [Int] (t []), MonadPlus (t []), MonadTrans t) => Int -> Int -> t [] () pathImplicitStack' start end | start == end = tell [end] pathImplicitStack' start end = do (s0, e0) <- ask >>= lift guard $ s0 == start tell [start] pathImplicitStack' e0 end 

but, as he noted, it can only be used with one monad transformer to wrap the list monad, i.e. RSWT, and cannot be used with ReaderT WriterT. So this is not the solution I'm looking for.

+6
source share
2 answers

So, the main problem with this in accordance with the requirements of the question is that there is no MTL library function for canceling a list from a monad, which can be an arbitrary level down. However, you can cheat a little: the MonadPlus instance for the combined Monad inherited from the main list monad, regardless of depth, and you can use it to generate the necessary action:

  do (s0, e0) <- ask >>= msum . map return 

Then an error occurs in the type signature, which must be changed to:

 pathImplicitStack' :: (MonadReader [(Int, Int)] m, MonadWriter [Int] m, MonadPlus m) => Int -> Int -> m () 

EDIT: Actually, I thought that this is actually not a hoax. It simply uses the MonadPlus API to bind alternative actions instead of directly using the main list monad.

+3
source

I think the difficulty here is that you are mixing the layers of the monad. Looking at

 pathImplicitStack' :: (MonadReader [(Int, Int)] m, MonadWriter [Int] m, MonadPlus m) => Int -> Int -> [m ()] 

This function returns a list of m () calculations, however ask >>= lift (and your previous question) suggests that List is the base monad on which you add additional transformers. If you want to use List as the base monad, you will need to change the type of pathImplicitStack'

 pathImplicitStack' :: (MonadReader [(Int, Int)] (t []), MonadWriter [Int] (t []), MonadPlus (t [])) => Int -> Int -> t [] () 

But even this is not enough for a general enough, because it allows you to add only one transformer on top of the list. You could use a library of operator types to combine two monad transformers into one transformer, but this is a bit complicated.

Here is one option: use Identity as the base monad and do list operations outside of this stack. (warning, all code is not verified, it may not even compile)

 pathImplicitStack' :: (MonadReader [(Int, Int)] m, MonadWriter [Int] m, MonadPlus m) => Int -> Int -> m () pathImplicitStack' start end | start == end = tell [end] pathImplicitStack' start end = do (s0, e0) <- ask >>= lift edges <- filter ((== start) . fst) <$> ask let m (s0,e0) = tell [s0] >> pathImplicitStack' e0 end mapM_ m edges 

There is one more option. You can use ListT or LogicT as an external transformer, allowing you to use this function (or something like this):

 pathImplicitStack'2 :: (MonadReader [(Int, Int)] m, MonadWriter [Int] m) => Int -> Int -> ListT m () pathImplicitStack'2 start end | start == end = tell [end] pathImplicitStack'2 start end = do (s0, e0) <- ask guard $ s0 == start tell [start] pathImplicitStack'2 e0 end -- if you have MonadReader/MonadWriter instances for ListT in scope, I think this will -- work. But if they aren't available, you will need to use `lift ask` and -- `lift (tell ...)` 

I would almost certainly choose the first approach.

+2
source

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


All Articles