2014-09-26 85 views
2

我想嵌入ReaderT到另一個monad變壓器。我該怎麼做呢?下面的例子使用Scotty,但我認爲它會與任何其他monad相同。如何讓ReaderT與另一個monad變壓器一起工作?

{-# LANGUAGE OverloadedStrings #-} 

import qualified Web.Scotty 
import Web.Scotty.Trans 

import Data.Text.Lazy 
import Control.Monad.IO.Class (liftIO) 

import Control.Monad.Trans.Reader 
import Control.Monad.Trans 

data Config = Config Text 

main :: IO() 
main = do 
    let config = Config "Hello World" 
    -- how to I make this line work? 
    scottyT 3000 id id routes 

routes :: ScottyT Text (ReaderT Config IO)() 
routes = do 
    get "/" info 

info :: ActionT Text (ReaderT Config IO)() 
info = do 
    -- this part seems like it works! 
    Config message <- lift ask 
    text $ "Info: " `append` message 

上線scottyT 3000 id id routes這樣的錯誤,因爲scottyT期望一個ScottyT Text IO()。我如何完成這項工作?以下是當前的錯誤:

Server.hs: line 24, column 24: 
    Couldn't match type `ReaderT Config IO' with `IO' 
    Expected type: ScottyT Text IO() 
     Actual type: ScottyT Text (ReaderT Config IO)() 
+0

嗯,這個工程,但我不知道它是正確的:'flip runReaderT config $ scottyT 3000 id(flip runReaderT config)routes'。我不認爲這是正確的考慮'runReaderT'需要兩次,但我不知道爲什麼scotty知道爲什麼'scottyT'函數需要這個參數 – bheklilr 2014-09-26 18:14:08

+0

你能否改變「Transformes stack」的順序,即' ReaderT配置(ScottyT文本IO)()'? – chaosmasttter 2014-09-26 18:16:30

+0

基於[this](http://stackoverflow.com/a/23190718/839246)的答案,你可以做'scottyT 3000(flip runReaderT)(flip runReaderT)路線,而這似乎是其他人的方式完成了。 – bheklilr 2014-09-26 18:19:49

回答

1

你必須改變你作爲id所提供的是那些有類型分別forall a. m a -> n am Response -> IO Response的參數。爲什麼?我不知道,但我發現here的範例顯示某人運行它類似於

main = do 
    let config = Config "Hello, world" 
     runner = flip runReaderT config 
    scottyT 3000 runner runner routes 

我測試過它,它至少起作用。我不知道這是否是最佳實踐。如果有人有更好的方法,隨時發佈。

+0

它如何看起來更容易理解monad?它看起來像斯科蒂添加了一些魔術來實現這一點,但如果他們沒有?它仍然有可能嗎? – 2014-09-26 18:38:45

+0

@SeanClarkHess我通常看到的是,你會有'scottyT ::(ScottyError e,MonadIO m)=> Port - > ScottyT em() - > m()',那麼你可以'翻轉runReaderT config $ scottyT 3000 routes'而不是隻運行'ScottyT'圖層。似乎scotty需要一些更高級的行爲來執行這些動作,我發現很難相信他們只需要糟糕的API設計就需要這些複雜的額外參數。就個人而言,我寧願能夠先運行'ReaderT' monad,留下一個'ScottyM' monad作爲我的基礎,以'scotty'運行,但這只是我 – bheklilr 2014-09-26 18:44:03

+1

對於Scotty≥0.10,'scottyT'不再需要「運行monad'm'爲monad'n',在'ScottyT'level參數中調用一次,所以最後一行應該是'scottyT 3000 runner routes'。 – beta 2015-07-10 08:17:51