2014-04-14 32 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