2014-06-12 33 views
4

如何使用Reader/ReaderTask以獲取列表類型,例如: [(Int, Int)]然後在列表monad中執行計算(類型爲ask ed)?如何在ReaderT中使用list monad?

我斷碼如下,縮短了清晰:

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

爲了給你什麼,我試圖做一個想法,這裏是相同的功能,使用列表單子而不是讀者:

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並列出monad來實現路徑的更大問題的一部分。

+1

你可以用'Reader [(Int,Int)] [[Int]]'來代替嗎? –

回答

8

這裏的技巧是使用升降轉換列表單子(即[a])爲ReaderT env []使用lift

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

或專門到你的單子堆棧:

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

ask返回包含在ReaderT monad中的狀態(即[(Int, Int)])例如:

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

我們希望將其轉換成另一種價值相同的單子,但與類型:

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

所以,替代由單子,而不是在輸出跟蹤。考慮基本功能>>=

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

您應該可以看到我們有所有需要的零件。使用ask >>= 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)] -> ReaderT [(Int, Int)] [] (Int, Int) 。如果用(Int, Int)替換lift函數中的a,這是一個完美匹配,這意味着表達式ask >>= lift可以實現您想要的功能。

您遇到的另一個錯誤是ReaderT monad的輸出類型 - 因爲它包含一個monad列表,所以您不需要將結果包裝在另一對括號中。 A 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本身通常不是很有用),但瞭解如何理解和操縱monads和monad變換器的類型是很好的。