如何在ReaderT内部使用列表单子? [英] How do I use list monad inside of ReaderT?

查看:46
本文介绍了如何在ReaderT内部使用列表单子?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用 Reader / ReaderT 询问以获取列表类型,例如 [((Int,Int)] ,然后在列表monad(类型为 ask 的类型)中执行计算?

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]

为了让您了解我要执行的操作,以下是相同的功能,但使用列表monad而不使用Reader:

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

我使用ReaderT是因为我正在学习monad变压器.这是同时使用Reader和Writer以及list monad来实现路径的一个较大问题的一部分.

I'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将列表monad(即 [a] )转换为 ReaderT env[] 通过使用 lift :

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 a

或专门用于您的monad堆栈:

or specialized to your monad stack:

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

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

ask returns the state (ie [(Int, Int)]) wrapped in the ReaderT monad eg:

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

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

We want to convert that into another value in the same monad but with the type:

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

因此,替代选项由monad而不是输出跟踪.考虑基本功能>> = :

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 b

您应该能够看到我们具备了所有必要的条件.使用 ask>> =提升:

You should be able to see we have all the pieces required. Using ask >>= lift:

  1. 第一个参数是 ReaderT [(Int,Int)] [] [(Int,Int)] ,表示 a [(Int,Int)] ,而 m ReaderT [(Int,Int)] []
  2. 我们希望结果 mb ReaderT [(Int,Int)] [](Int,Int),所以 b (Int,Int)
  3. 因此该函数需要类型 [(Int,Int)]->ReaderT [(Int,Int)] [](Int,Int).如果将 lift 函数中的 a 替换为(Int,Int),则这是一个完美的匹配,表示表达式 ask>> =电梯可以满足您的需求.
  1. The first argument is ReaderT [(Int, Int)] [] [(Int, Int)], meaning a is [(Int, Int)], and m is ReaderT [(Int, Int)] []
  2. We want the result m b to be ReaderT [(Int, Int)] [] (Int, Int), so b is (Int, Int)
  3. 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.

您遇到的另一个错误是 ReaderT monad的输出类型-因为它包含一个列表monad,所以您不需要将结果包装在另一对括号中. ReaderT状态[] 已经包含多个结果的概念,在这种情况下,单个结果是显示图形路径的 [Int] .

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.

这是工作代码:

{-# 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转换器的类型.

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内部使用列表单子?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆