您必须handlers
围绕以下事实进行设计:从数据库中获取是一种神奇的操作,可能无法满足您的期望。(例如,您的数据库可能会崩溃。)这就是为什么它的结果被用作IO
,这是monad的一种特殊情况。
monad 是一个颈部非常狭窄的罐子,甚至如此狭窄,一旦您将某些东西放入其中,就无法将其取出。(除非它碰巧也是 a comonad
,但那完全是另一回事了,而不是这样,IO
也不是这样ServerPart
。)所以,你永远不会将 an 转换IO String
为 a String
。不是你不能,而是你的程序会变得不正确。
你的情况有点棘手,因为你有两个单子在玩:IO
和ServerPart
. 幸运的是,ServerPart
基于IO
,它“更大”,并且在某种意义上可以吸收 IO
:我们可以将一些IO
放入 aServerPart
中,它会是ServerPart
静止的,因此我们可以将它交给simpleHTTP
。在happstack
中,这种转换可以通过require
函数来完成,但也有一个更通用的解决方案,涉及monad 转换器和lift
.
让我们先来看看解决方案require
。它的类型(简化为我们的例子)是:
IO (Maybe a) -> (a -> ServerPart r) -> ServerPart r
— 因此,它需要一个IO
带有一些参数的 jar,并使其适合存在于ServerPart
jar 中的函数。我们只需要稍微调整类型并创建一个lambda 抽象:
myFunc :: Integer -> IO (Maybe String)
myFunc _ = return . Just $ "A thing of beauty is a joy forever."
handlers :: ServerPart Response
handlers = require (myFunc 1) $ \x ->
do decodeBody (defaultBodyPolicy "/tmp/" 0 1000 1000)
msum [
dir "getData" $ ok $ toResponse x
]
mainFunc = simpleHTTP nullConf handlers
如您所见,我们必须进行 2 处修改:
require
是专门处理单子的方法happstack
。不过,一般来说,这只是将 monad 转换为更大的单子的情况,这是通过lift
. lift
(再次简化)的类型是:
IO String -> ServerPart String
所以,我们可以像往常一样只lift
为myFunc 1 :: IO String
正确的 monad 赋值,然后用 compose >>=
:
myFunc :: Integer -> IO String
myFunc _ = return $ "Its loveliness increases,.."
handlers :: ServerPart Response
handlers = lift (myFunc 1) >>= \x ->
do decodeBody (defaultBodyPolicy "/tmp/" 0 1000 1000)
msum [
dir "getData" $ ok $ toResponse x
]
mainFunc = simpleHTTP nullConf handlers
就如此容易。我再次使用了相同的 lambda 抽象技巧,但您也可以使用do-notation:
myFunc :: Integer -> IO String
myFunc _ = return $ "...it will never pass into nothingness."
handlers :: ServerPart Response
handlers = do
x <- lift (myFunc 1)
decodeBody (defaultBodyPolicy "/tmp/" 0 1000 1000)
msum [
dir "getData" $ ok $ toResponse x
]
mainFunc = simpleHTTP nullConf handlers
PS回到大罐子和小罐子的故事:你可以放入IO
正是ServerPart
因为ServerPart
它也是一个IO
monad——它是MonadIO
类的一个实例。这意味着您可以在IO
您中执行的任何操作ServerPart
,并且,除了通用之外lift
,还有一个专门的liftIO
功能,您可以在我使用的任何地方使用lift
。您可能会遇到许多其他 monad 的实例,MonadIO
因为它是在大型应用程序中构建代码的便捷方式。
在您的特定情况下,我仍然会坚持这种require
方式,因为我认为这是设计者的happstack
意图。虽然我不是特别了解happstack
,所以我可能是错的。
而已。快乐黑客!