2014-04-14 33 views
6

我正在嘗試使用Scotty來構建一個非常簡單的API。我想擴展Scotty monads,使我的路由處理器操作能夠訪問不變的環境。我相信這樣做的方法是將一個Reader monad添加到堆棧。現在我只想通過一些Text數據。我如何將讀者monad添加到Scotty的monad中?

type BrandyScottyM = ScottyT TL.Text (ReaderT T.Text IO) 
type BrandyActionM = ActionT TL.Text (ReaderT T.Text IO) 

https://github.com/stu-smith/Brandy/blob/0838a63537d7e396ac82d58d460c6529349303d3/src/Core.hs

所以我的第一個問題是,這是正確的做法:

我如下擴展斯科蒂單子?

我已經成功地更改了我的路由處理程序的類型,但我無法解決如何使用此堆棧來啓動Scotty。我已經嘗試以下操作:

runScotty :: Port -> Text -> BrandyScottyM() -> IO() 
runScotty port file = T.scottyT port ((\f -> runReader f file)) id 

https://github.com/stu-smith/Brandy/blob/0838a63537d7e396ac82d58d460c6529349303d3/src/Main.hs

但我得到的錯誤:

Couldn't match type `IO' with `Data.Functor.Identity.Identity' 
    Expected type: Reader Text (IO a) 
     Actual type: ReaderT Text IO a 
    In the first argument of `runReader', namely `f' 
    In the expression: runReader f file 
    In the second argument of `T.scottyT', namely 
     `((\ f -> runReader f file))' 
/home/stu/git/Brandy/src/Main.hs: line 36, column 65: 
    Couldn't match type `ReaderT Text IO Network.Wai.Internal.Response' 
        with `IO Network.Wai.Internal.Response' 
    Expected type: ReaderT Text IO Network.Wai.Internal.Response 
        -> IO Network.Wai.Internal.Response 
     Actual type: ReaderT Text IO Network.Wai.Internal.Response 
        -> ReaderT Text IO Network.Wai.Internal.Response 
    In the third argument of `T.scottyT', namely `id' 
    In the expression: T.scottyT port ((\ f -> runReader f file)) id 
    In an equation for `runScotty': 
     runScotty port file = T.scottyT port ((\ f -> runReader f file)) id 

所以我的第二個問題是,我該如何推出斯科蒂用不同的單子棧?這是我第一次嘗試使用monad變形金剛,並且我似乎無望地迷路了。

回答

9

您的方法看起來不錯。類型錯誤是因爲您應該使用runReaderT而不是runReaderrunReader僅適用於當您使用Reader時,它是ReaderT,而其下面是虛擬Identity monad)。

+1

啊哈太棒了,讓我在正確的路線。我還必須在應用程序和操作級別都創建'Reader',所以最終的調用是:''.scottyT port(\'runReaderT \'file)(\'runReaderT \'file)' – stusmith