如何在ReaderT中使用list monad?

时间:2014-06-12 07:30:21

标签: haskell monad-transformers

如何将Reader / ReaderT用于ask作为列表类型,例如[(Int, Int)]然后在列表monad(ask编辑的类型)中执行计算?

我的破解代码如下,为了清楚起见缩短了:

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来实现路径的更大问题的一部分。

1 个答案:

答案 0 :(得分:8)

这里的技巧是使用lift通过使用[a]将列表monad(即ReaderT env [])转换为lift

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

或专门用于你的monad堆栈:

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

ask返回包含在[(Int, Int)] monad中的状态(即ReaderT),例如:

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

我们希望将其转换为同一monad中的另一个值,但类型为:

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

因此,monad而不是输出中跟踪替代方案。考虑基本功能>>=

(>>=) :: Monad m => m a -> (a -> m b) -> m b

你应该能够看到我们拥有所需的所有部分。使用ask >>= lift

  1. 第一个参数是ReaderT [(Int, Int)] [] [(Int, Int)],意思是a[(Int, Int)]mReaderT [(Int, Int)] []
  2. 我们希望结果m bReaderT [(Int, Int)] [] (Int, Int),因此b(Int, Int)
  3. 因此该函数需要类型[(Int, Int)] -> ReaderT [(Int, Int)] [] (Int, Int)。如果您将a函数中的lift替换为(Int, Int),则表示完全匹配,这意味着表达式ask >>= lift可以满足您的需求。
  4. 你遇到的另一个错误是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变换器的类型是很好的。