这是我第一次玩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
。
答案 0 :(得分:5)
事实上,NewMonad Response
是hello
的正确类型;你只需要使用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有能力做到这一点,但无论如何它可能会非常脆弱,因为你不应该真的依赖订单请求被处理。 )