【问题标题】:How do I use list monad inside of ReaderT?如何在 ReaderT 中使用 list monad?
【发布时间】:2014-06-12 07:30:20
【问题描述】:

我如何使用Reader/ReaderTask 作为列表类型,例如[(Int, Int)] 然后在列表 monad 中执行计算(asked 的类型)?

以下是我损坏的代码,为清楚起见已缩短:

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

为了让您了解我想要做什么,这里是相同的函数,使用 list 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,因为我正在学习单子转换器。这是使用 Reader 和 Writer 以及 list monad 来实现路径的更大问题的一部分。

【问题讨论】:

  • 你能用Reader [(Int,Int)] [[Int]]代替吗?

标签: haskell monad-transformers


【解决方案1】:

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

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

或专门用于您的 monad 堆栈:

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

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

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

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

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

因此替代方案由 monad 跟踪,而不是在输出中。考虑基本函数&gt;&gt;=

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

您应该能够看到我们拥有所需的所有部件。使用ask &gt;&gt;= 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)] -&gt; ReaderT [(Int, Int)] [] (Int, Int)类型。如果将lift 函数中的a 替换为(Int, Int),则完全匹配,这意味着表达式ask &gt;&gt;= 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 转换器的类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-05
    • 2021-08-19
    相关资源
    最近更新 更多