Моя цель - создать функцию, которая использует монаду списка внутри стека ReaderT WriterT или стека RWS. В более общем плане, как мне использовать монаду списка внутри классов типов mtl, таких как MonadReader, MonadWriter?
Почему я пытаюсь это сделать? Эта проблема является упражнением в Beginning Haskell. Он просит меня «использовать функциональность как MonadReader, так и MonadWriter, обертывающую монаду базового списка. Чтобы проверить, является ли функция общей, используйте две разные монады для [проверки] запрошенной функциональности: ReaderT r (WriterT w []) a
и RWST r w s m a
» Итак, книга подразумевает, что это возможно.
Я не могу понять, как «сказать» компилятору использовать монаду списка. Если я использую ask >>= lift
или ask >>= lift . lift
, я могу заставить работать либо двухуровневый стек (RWST []
), либо трехуровневый стек (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 ()
Это связано с моим предыдущим вопросом: Как использовать монаду списка внутри 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
изменить
Основываясь на отзывах Джона Л., я попробовал
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
но, как он указал, его можно использовать только с одним преобразователем монад для обертывания монады списка, то есть RSWT, и его нельзя использовать с ReaderT WriterT. Так что это не то решение, которое я ищу.
MonadPlus
- это в основном класс типа монады списка. Например:cons a as = return a `mplus` as
иnil = mzero
. - person Gabriel Gonzalez   schedule 13.06.2014