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.