在monad变换器类型类中使用list monad?

Dan*_*l K 6 haskell monad-transformers

我的目标是创建一个在ReaderT WriterT堆栈或RWS堆栈中使用列表monad的函数.更一般地说,如何在mtl类型类中使用列表monad,例如MonadReader,MonadWriter?

我为什么要这样做?这个问题是在Beginning Haskell中的一个练习.它要求我"来自MonadReader和MonadWriter包装用底名单单子使用功能要检查功能一般情况下,使用两种不同的单子到[测试]所请求的功能:ReaderT r (WriterT w []) aRWST r w s m a"所以这本书暗示这是可能的.

我无法弄清楚如何"告诉"编译器使用列表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
Run Code Online (Sandbox Code Playgroud)

另外,我想知道如何键入该功能.到目前为止,我最好的尝试看起来像pathImplicitStack' :: (MonadReader [(Int, Int)] m, MonadWriter [Int] m, MonadPlus m) => Int -> Int -> m () 我知道这是不对的,列表monad可能会丢失.另外,我认为MonadPlus在类型签名中可能很有用,但我不太确定.

这一行:do (s0, e0) <- ask >>= lift给我带来麻烦的那一行.我尝试了0,1和2升降机没有成功.我想要ask一个[(Int, Int)]然后使用list monad来处理一个(Int, Int)(并让列表monad为我尝试所有可能性).

作为练习的一部分,我需要能够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 ()
Run Code Online (Sandbox Code Playgroud)

这与我之前的问题有关:如何在ReaderT中使用list monad?

整个文件易于测试:

{-# 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
Run Code Online (Sandbox Code Playgroud)

编辑

根据John的反馈,我试过了

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
Run Code Online (Sandbox Code Playgroud)

但正如他所指出的,它只能与一个monad变换器一起使用来包装列表monad,即RSWT,并且不能与ReaderT WriterT一起使用.所以这不是我要找的解决方案.

Ørj*_*sen 5

因此,在问题的要求内执行此操作的基本问题是,没有 MTL 库函数可以从可能是任意级别的列表 monad 中提升。但是,您可以“作弊”一点:无论深度如何,MonadPlus组合的实例Monad 都是从底层列表 monad 继承的,您可以使用它来生成所需的操作:

  do  (s0, e0) <- ask >>= msum . map return
Run Code Online (Sandbox Code Playgroud)

然后类型签名也有错误,需要改成:

pathImplicitStack' :: (MonadReader [(Int, Int)] m, MonadWriter [Int] m, MonadPlus m) => Int -> Int -> m ()
Run Code Online (Sandbox Code Playgroud)

编辑:实际上在第二个想法这实际上并不是作弊。它只是使用MonadPlusAPI 来链接替代操作,而不是直接使用底层列表 monad。