asp*_*asp 1 haskell happstack hdbc
我正在使用HDBC从数据库中检索数据,然后尝试使用Happstack将此数据发送到Web客户端.
myFunc :: Integer -> IO String
myFunc = ... fetch from db here ...
handlers :: ServerPart Response
handlers =
do decodeBody (defaultBodyPolicy "/tmp/" 0 1000 1000)
msum [
dir "getData" $ ok $ toResponse $ myFunc $ toInteger 1
]
mainFunc = simpleHTTP nullConf handlers
Run Code Online (Sandbox Code Playgroud)
当我构建上面的代码时,我收到此错误:
使用"toResponse"时没有(ToMessage(IO String))的实例
我尝试了什么?
IO String为String(liftIO例如使用).提前致谢.
您必须设计handlers一个事实,即从数据库中获取是一个神奇的动作,可能无法满足您的期望.(例如,您的数据库可能会崩溃.)这就是为什么它的结果是作为IO一个monad的特殊情况.
monad是一个颈部非常狭窄的罐子,即便如此,一旦你把东西放在那里,你就无法输出它.(除非它也是一个comonad,但是这是一个整体的另一个故事,而不是与本案IO也没有用ServerPart.)所以,你永远不会转换的IO String一个String.不是你不能,但你的程序会变得不正确.
你的情况有点棘手,因为你在那里玩两个单子:IO和ServerPart.幸运的是,ServerPart建立在IO,它是" 大 ",并可以在一定意义上,吸收 IO:我们可以把一些IO成ServerPart,这将是一个ServerPart还在,于是我们可以给它simpleHTTP.在happstack,这种转换可以通过require函数完成,但也有一个更通用的解决方案,涉及monad变换器和lift.
我们先来看看解决方案require.它的类型(简化为我们的例子)是:
IO (Maybe a) -> (a -> ServerPart r) -> ServerPart r
Run Code Online (Sandbox Code Playgroud)
- 所以,它需要一个IO带有一些参数的jar,并使它适合生活在ServerPartjar中的函数.我们只需要稍微调整类型并创建一个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
Run Code Online (Sandbox Code Playgroud)
如您所见,我们必须进行2次修改:
根据需要调整myFunc以使其返回.这是一个更好的设计,因为现在可能有两种方式失败:MayberequiremyFunc
Maybe,它可以返回Nothing,这意味着404等.这种情况相当普遍.IO,它可能会出错,这意味着数据库崩溃了.现在是时候提醒DevOps团队了.调整handlers,使其myFunc在外部.可以更具体地说:抽象myFunc来自handlers.这就是为什么这种语法被称为lambda 抽象.
require是happstack具体处理monad的方法.一般来说,这只是将 monad转换为更大的monad的情况,这是通过lift.lift(再次,简化)的类型是:
IO String -> ServerPart String
Run Code Online (Sandbox Code Playgroud)
所以,我们可以将正确的monad lift的myFunc 1 :: IO String价值,然后>>=像往常一样组成:
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
Run Code Online (Sandbox Code Playgroud)
就如此容易.我再次使用相同的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
Run Code Online (Sandbox Code Playgroud)
PS回到大型和小型罐子的故事:你可以投入IO到ServerPart正是因为ServerPart它也是一个IO单子 - 它是一个MonadIO类的实例.这意味着,任何你能做到IO,你也可以做ServerPart,而且,除了一般的lift,有一个专门的liftIO,你可以用我到处使用的功能lift.您很可能会遇到许多其他monad,MonadIO因为它是在大型应用程序中构造代码的便捷方式.
在你的特殊情况下,我会坚持不懈的require方式,因为我认为这是设计师的happstack意思.我不是特别了解happstack,所以我可能错了.
而已.快乐的黑客!
| 归档时间: |
|
| 查看次数: |
176 次 |
| 最近记录: |