【发布时间】:2014-08-03 10:34:15
【问题描述】:
我的目标是创建一个在 ReaderT WriterT 堆栈或 RWS 堆栈中使用 list monad 的函数。更一般地,如何在 MonadReader、MonadWriter 等 mtl 类型类中使用 list monad?
我为什么要这样做?这个问题是Beginning Haskell 中的一个练习。它要求我“使用 MonadReader 和 MonadWriter 包装基本列表 monad 的功能。要检查该功能是否通用,请使用两个不同的 monad 来 [测试] 请求的功能:ReaderT r (WriterT w []) a 和 RWST r w s m a”所以这本书暗示这是可能的。
我不知道如何“告诉”编译器使用 list monad。如果我使用 ask >>= lift 或 ask >>= lift . lift 我可以让 2 级堆栈 (RWST []) 或 3 级堆栈 (ReaderT WriterT []) 工作,但不能同时工作。
我问题的重点:
pathImplicitStack' start end | start == end = tell [end]
pathImplicitStack' start end =
do (s0, e0) <- ask >>= lift
guard $ s0 == start
tell [start]
pathImplicitStack' e0 end
另外,我想知道如何键入函数。到目前为止,我最好的尝试看起来像 pathImplicitStack' :: (MonadReader [(Int, Int)] m, MonadWriter [Int] m, MonadPlus m) => Int -> Int -> m () 我知道这是不对的,可能缺少列表单子。另外,我认为 MonadPlus 在类型签名中可能有用,但我不太确定。
这一行:do (s0, e0) <- ask >>= lift 给我带来了麻烦。我尝试了 0、1 和 2 次升降机,但均未成功。我想ask 获取[(Int, Int)],然后使用列表单子来处理(Int, Int)(并让列表单子为我尝试所有可能性)。
作为练习的一部分,我需要能够使用这两个函数(或非常相似的函数)调用pathImplicitStack':
pathImplicitRW :: [(Int, Int)] -> Int -> Int -> [[Int]]
pathImplicitRW edges start end = execWriterT rdr
where rdr = runReaderT (pathImplicitStack' start end) edges :: WriterT [Int] [] ()
pathImplicitRWS :: [(Int, Int)] -> Int -> Int -> [[Int]]
pathImplicitRWS edges start end = map snd exec
where exec = execRWST (pathImplicitStack' start end) edges ()
这和我之前的问题有关:How do I use list monad inside of ReaderT?
整个文件方便测试:
{-# LANGUAGE FlexibleContexts #-}
module Foo where
import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.RWS
graph1 :: [(Int, Int)]
graph1 = [(2013,501),(2013,1004),(501,2558),(1004,2558)]
pathImplicitRW :: [(Int, Int)] -> Int -> Int -> [[Int]]
pathImplicitRW edges start end = execWriterT rdr
where rdr = runReaderT (pathImplicitStack' start end) edges :: WriterT [Int] [] ()
pathImplicitRWS :: [(Int, Int)] -> Int -> Int -> [[Int]]
pathImplicitRWS edges start end = map snd exec
where exec = execRWST (pathImplicitStack' start end) edges ()
pathImplicitStack' :: (MonadReader [(Int, Int)] m, MonadWriter [Int] m, MonadPlus m) => Int -> Int -> [m ()]
pathImplicitStack' start end | start == end = tell [end]
pathImplicitStack' start end =
do (s0, e0) <- ask >>= lift
guard $ s0 == start
tell [start]
pathImplicitStack' e0 end
编辑
根据我尝试过的 John L 的反馈
pathImplicitStack' :: (MonadReader [(Int, Int)] (t []), MonadWriter [Int] (t []), MonadPlus (t []), MonadTrans t) => Int -> Int -> t [] ()
pathImplicitStack' start end | start == end = tell [end]
pathImplicitStack' start end =
do (s0, e0) <- ask >>= lift
guard $ s0 == start
tell [start]
pathImplicitStack' e0 end
但正如他所指出的,它只能与一个 monad 转换器一起使用来包装列表 monad,即 RSWT,并且不能与 ReaderT WriterT 一起使用。所以这不是我正在寻找的解决方案。
【问题讨论】:
-
MonadPlus基本上是“list monad”类型的类。例如:cons a as = return a `mplus` as和nil = mzero。
标签: haskell monad-transformers monadplus