如何使用ReaderT转换Happstack的ServerPart响应?

时间:2012-01-26 04:40:24

标签: haskell

这是我第一次玩Monad变形金刚。这是一个简单的快乐堆栈应用程序。

{-# LANGUAGE OverloadedStrings #-}

import Happstack.Lite 
import qualified Data.ByteString.Lazy.Char8 as L

main :: IO ()
main = do
    serve Nothing hello 

hello :: ServerPart Response
hello = do
    ok $ toResponse ("Hello" :: L.ByteString)

我希望能够更改hello,以便它可以使用ReaderT读取一些全局配置数据。我们只说配置是一个字符串,以保持简单

type NewMonad = ReaderT L.ByteString (ServerPartT IO) 
runNewMonad :: NewMonad a -> L.ByteString -> ServerPart a
runNewMonad k c = runReaderT k c

如何更改问候语才能使用ask?我不确定那种类型。 NewMonad Response不太正确,因为ok会返回ServerPart Response

如何更改main以使serve有效?它需要ServerPart Response

1 个答案:

答案 0 :(得分:5)

事实上,NewMonad Responsehello的正确类型;你只需要使用lift将底层monad中的动作转换为变换器中的一个动作。例如:

hello :: NewMonad Response
hello = do
    foo <- ask
    lift . ok $ toResponse foo

一般来说,

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

即,如果你有一个monadic动作,那么你将它转换为该monad上任何monad变换器中的动作。这是monad变换器的定义:它可以转换任何monad,并嵌入该monad的动作。

似乎将所有monadic动作限制为一个特定的monad - 而不是使用类型类在任何适当的monad中工作 - 是完全Haststack与this type for ok完全相比的一个简化:happstack-lite使用:

ok :: (FilterMonad Response m) => a -> m a

使用此类型,假设为标准变换器声明了适当的实例,您可以直接在ok中使用MyMonad

对于main,您需要删除ReaderT图层,引导一个ServerPart Response,您可以传递给serve

main :: IO ()
main = do
    serve Nothing $ runNewMonad hello ("Hello" :: L.ByteString)

(如果您使用的monad承载状态要在许多请求的过程中进行更改,这会导致问题,因为serve的类型限制太大而无法支持此类状态线程(无需手动编码)与IORef或类似的);可能无限制的Happstack有能力做到这一点,但无论如何它可能会非常脆弱,因为你不应该真的依赖订单请求被处理。 )