如何使用Reader / ReaderT来ask列表类型,例如[(Int, Int)] ,然后在列表monad( ask输入的类型[(Int, Int)]执行计算?
我的破解代码如下,为了清楚起见缩短了:
attempt :: Int -> Int -> ReaderT [(Int,Int)] [] [[Int]] attempt start end = do (s0, e0) <- ask return [0]为了让您了解我正在尝试做什么,这里是相同的功能,使用列表monad而不是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我正在使用ReaderT,因为我正在学习monad变换器。 这是使用Reader和Writer以及list monad来实现路径的更大问题的一部分。
How do I use Reader/ReaderT to ask for a list type, e.g. [(Int, Int)] and then perform calculations inside the list monad (of the type that was asked 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 : subpathI'm using ReaderT because I'm learning monad transformers. It's part of a larger problem using both Reader and Writer and list monad to implement paths.
最满意答案
这里的技巧是使用lift通过使用lift将列表monad(即[a] )转换为ReaderT env [] :
lift :: (Monad m, MonadTrans t) => m a -> t m a或专门用于你的monad堆栈:
lift :: [a] -> ReaderT [(Int,Int)] [] aask返回包含在ReaderT monad中的状态(即[(Int, Int)] ),例如:
ask :: ReaderT [(Int, Int)] [] [(Int, Int)]我们想将它转换为同一monad中的另一个值,但具有以下类型:
??? :: ReaderT [(Int, Int)] [] (Int, Int)所以替代方案由monad而不是输出中跟踪。 考虑基本功能>>= :
(>>=) :: Monad m => m a -> (a -> m b) -> m b您应该能够看到我们拥有所需的所有部分。 使用ask >>= lift :
第一个参数是ReaderT [(Int, Int)] [] [(Int, Int)] ,意思是a是[(Int, Int)] , m是ReaderT [(Int, Int)] [] 我们希望结果mb是ReaderT [(Int, Int)] [] (Int, Int) ,所以b是(Int, Int) 所以函数需要类型[(Int, Int)] -> ReaderT [(Int, Int)] [] (Int, Int) 。 如果用(Int, Int)替换lift函数中的a ,它是一个完美的匹配,意味着表达式ask >>= lift做你想要的。你遇到的另一个错误是ReaderT monad的输出类型 - 因为它包含一个列表monad,你不需要将结果包装在另一对括号中。 ReaderT state []已经包含多个结果的概念,在这种情况下,单个结果是显示图形路径的[Int] 。
这是工作代码:
{-# 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]]我希望能够清楚地解释清楚。 在这种情况下,我可能会坚持使用原始解决方案(使用Reader本身通常不是很有用),但知道如何理解和操作monad和monad变换器的类型是很好的。
The trick here is to use lift to convert a list monad (ie an [a]) into a ReaderT env [] by using lift:
lift :: (Monad m, MonadTrans t) => m a -> t m aor specialized to your monad stack:
lift :: [a] -> ReaderT [(Int,Int)] [] aask returns the state (ie [(Int, Int)]) wrapped in the ReaderT monad eg:
ask :: ReaderT [(Int, Int)] [] [(Int, Int)]We want to convert that into another value in the same monad but with the type:
??? :: ReaderT [(Int, Int)] [] (Int, Int)So the alternatives are tracked by the monad instead of in the output. Consider the basic function >>=:
(>>=) :: Monad m => m a -> (a -> m b) -> m bYou should be able to see we have all the pieces required. Using ask >>= lift:
The first argument is ReaderT [(Int, Int)] [] [(Int, Int)], meaning a is [(Int, Int)], and m is ReaderT [(Int, Int)] [] We want the result m b to be ReaderT [(Int, Int)] [] (Int, Int), so b is (Int, Int) So the function needs the type [(Int, Int)] -> ReaderT [(Int, Int)] [] (Int, Int). If you replace the a in the lift function with (Int, Int), it is a perfect match, meaning the expression ask >>= lift does what you want.The other mistake you had was the output type of the ReaderT monad - as it contained a list monad you didn't need to wrap the result in another pair of brackets. A ReaderT state [] already contains the concept of multiple results, and a single result in this case is a [Int] showing the graph path.
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]]I hope that explains it clearly. In this situation, I would probably just stick with the original solution (using Reader by itself is normally not very useful), but it is good to know how to understand and manipulate the types of monads and monad transformers.
如何在ReaderT中使用list monad?(How do I use list monad inside of ReaderT?)如何使用Reader / ReaderT来ask列表类型,例如[(Int, Int)] ,然后在列表monad( ask输入的类型[(Int, Int)]执行计算?
我的破解代码如下,为了清楚起见缩短了:
attempt :: Int -> Int -> ReaderT [(Int,Int)] [] [[Int]] attempt start end = do (s0, e0) <- ask return [0]为了让您了解我正在尝试做什么,这里是相同的功能,使用列表monad而不是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我正在使用ReaderT,因为我正在学习monad变换器。 这是使用Reader和Writer以及list monad来实现路径的更大问题的一部分。
How do I use Reader/ReaderT to ask for a list type, e.g. [(Int, Int)] and then perform calculations inside the list monad (of the type that was asked 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 : subpathI'm using ReaderT because I'm learning monad transformers. It's part of a larger problem using both Reader and Writer and list monad to implement paths.
最满意答案
这里的技巧是使用lift通过使用lift将列表monad(即[a] )转换为ReaderT env [] :
lift :: (Monad m, MonadTrans t) => m a -> t m a或专门用于你的monad堆栈:
lift :: [a] -> ReaderT [(Int,Int)] [] aask返回包含在ReaderT monad中的状态(即[(Int, Int)] ),例如:
ask :: ReaderT [(Int, Int)] [] [(Int, Int)]我们想将它转换为同一monad中的另一个值,但具有以下类型:
??? :: ReaderT [(Int, Int)] [] (Int, Int)所以替代方案由monad而不是输出中跟踪。 考虑基本功能>>= :
(>>=) :: Monad m => m a -> (a -> m b) -> m b您应该能够看到我们拥有所需的所有部分。 使用ask >>= lift :
第一个参数是ReaderT [(Int, Int)] [] [(Int, Int)] ,意思是a是[(Int, Int)] , m是ReaderT [(Int, Int)] [] 我们希望结果mb是ReaderT [(Int, Int)] [] (Int, Int) ,所以b是(Int, Int) 所以函数需要类型[(Int, Int)] -> ReaderT [(Int, Int)] [] (Int, Int) 。 如果用(Int, Int)替换lift函数中的a ,它是一个完美的匹配,意味着表达式ask >>= lift做你想要的。你遇到的另一个错误是ReaderT monad的输出类型 - 因为它包含一个列表monad,你不需要将结果包装在另一对括号中。 ReaderT state []已经包含多个结果的概念,在这种情况下,单个结果是显示图形路径的[Int] 。
这是工作代码:
{-# 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]]我希望能够清楚地解释清楚。 在这种情况下,我可能会坚持使用原始解决方案(使用Reader本身通常不是很有用),但知道如何理解和操作monad和monad变换器的类型是很好的。
The trick here is to use lift to convert a list monad (ie an [a]) into a ReaderT env [] by using lift:
lift :: (Monad m, MonadTrans t) => m a -> t m aor specialized to your monad stack:
lift :: [a] -> ReaderT [(Int,Int)] [] aask returns the state (ie [(Int, Int)]) wrapped in the ReaderT monad eg:
ask :: ReaderT [(Int, Int)] [] [(Int, Int)]We want to convert that into another value in the same monad but with the type:
??? :: ReaderT [(Int, Int)] [] (Int, Int)So the alternatives are tracked by the monad instead of in the output. Consider the basic function >>=:
(>>=) :: Monad m => m a -> (a -> m b) -> m bYou should be able to see we have all the pieces required. Using ask >>= lift:
The first argument is ReaderT [(Int, Int)] [] [(Int, Int)], meaning a is [(Int, Int)], and m is ReaderT [(Int, Int)] [] We want the result m b to be ReaderT [(Int, Int)] [] (Int, Int), so b is (Int, Int) So the function needs the type [(Int, Int)] -> ReaderT [(Int, Int)] [] (Int, Int). If you replace the a in the lift function with (Int, Int), it is a perfect match, meaning the expression ask >>= lift does what you want.The other mistake you had was the output type of the ReaderT monad - as it contained a list monad you didn't need to wrap the result in another pair of brackets. A ReaderT state [] already contains the concept of multiple results, and a single result in this case is a [Int] showing the graph path.
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]]I hope that explains it clearly. In this situation, I would probably just stick with the original solution (using Reader by itself is normally not very useful), but it is good to know how to understand and manipulate the types of monads and monad transformers.
发布评论