How to use list monad inside ReaderT?

How to use Reader / ReaderT to ask for a list type, for example. [(Int, Int)] and then do the calculations inside the list monad (the type that ed ed was for)?

My broken code follows, shortened for clarity:

 attempt :: Int -> Int -> ReaderT [(Int,Int)] [] [[Int]] attempt start end = do (s0, e0) <- ask return [0] 

To give you an idea of ​​what I'm trying to do, here is the same function using the list monad, but not Reader:

 paths :: [(Int, Int)] -> Int -> Int -> [[Int]] paths edges start end = if start == end then return [end] else do (s0, e0) <- edges guard $ s0 == start subpath <- paths edges e0 end return $ s0 : subpath 

I use ReaderT because I study monad transformers. This is part of a larger problem using both Reader and Writer and a list monad to implement paths.

+4
source share
1 answer

The trick here is to use the elevator to convert the list monad (ie [a] ) to ReaderT env [] using lift :

 lift :: (Monad m, MonadTrans t) => ma -> tma 

or specializing in your monad stack:

 lift :: [a] -> ReaderT [(Int,Int)] [] a 

ask returns a state (ie [(Int, Int)] ) enclosed in the ReaderT monad, for example:

 ask :: ReaderT [(Int, Int)] [] [(Int, Int)] 

We want to convert this to a different value in the same monad, but with a type:

 ??? :: ReaderT [(Int, Int)] [] (Int, Int) 

Thus, alternatives are monitored, not output. Consider the main function >>= :

 (>>=) :: Monad m => ma -> (a -> mb) -> mb 

You should be able to see that we have all the necessary items. Using ask >>= lift :

  • The first argument is ReaderT [(Int, Int)] [] [(Int, Int)] , which means a is [(Int, Int)] , and m is ReaderT [(Int, Int)] []
  • We want the result of mb be ReaderT [(Int, Int)] [] (Int, Int) , so b is (Int, Int)
  • Therefore, functions need the type [(Int, Int)] -> ReaderT [(Int, Int)] [] (Int, Int) . If you replace a with the lift function with (Int, Int) , this is a perfect match, which means the ask >>= lift expression does what you want.

Another error you encountered is the output type of the ReaderT monad, since it contains a list monad, which you did not need to wrap the result in another pair of brackets. A ReaderT state [] already contains the concept of multiple results, in which case the only result is [Int] , showing the path of the graph.

Here is the working code:

 {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} module Main where import Control.Monad.Reader import Control.Applicative paths :: Int -> Int -> ReaderT [(Int,Int)] [] [Int] paths start end = do if start == end then return [end] else do (s0, e0) <- ask >>= lift guard $ s0 == start (s0 :) <$> paths e0 end input :: [(Int, Int)] input = [(1,2), (2,7), (3,4), (7, 3), (7, 5), (5, 3)] test :: [[Int]] test = runReaderT (paths 2 4) input > test [[2,7,3,4],[2,7,5,3,4]] 

Hope this explains it clearly. In this situation, I probably just stick to the original solution (using Reader alone is usually not very useful), but it's good to know how to understand and manipulate the types of monads and monad transformers.

+8
source

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


All Articles