Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何在Happstack中创建数据库Monad堆栈?_Haskell_Monads_Monad Transformers_Happstack - Fatal编程技术网

Haskell 如何在Happstack中创建数据库Monad堆栈?

Haskell 如何在Happstack中创建数据库Monad堆栈?,haskell,monads,monad-transformers,happstack,Haskell,Monads,Monad Transformers,Happstack,我想创建一个Happstack应用程序,它可以访问大量数据库。我认为底部带有IO的Monad堆栈和顶部类似Monad的数据库写入(中间带有log writer)可以在每次访问中都有一个清晰的函数,例如: itemsRequest :: ServerConfig -> ServerPart Response itemsRequest cf = dir "items" $ do methodM [GET,HEAD] liftIO $ noticeM (scLogger cf) "sen

我想创建一个Happstack应用程序,它可以访问大量数据库。我认为底部带有IO的Monad堆栈和顶部类似Monad的数据库写入(中间带有log writer)可以在每次访问中都有一个清晰的函数,例如:

itemsRequest :: ServerConfig -> ServerPart Response
itemsRequest cf = dir "items" $ do
  methodM [GET,HEAD]
  liftIO $ noticeM (scLogger cf) "sended job list"

  items <- runDBMonad (scDBConnString cf) $ getItemLists

  case items of
    (Right xs) -> ok $ toResponse $ show xs
    (Left err) -> internalServerError $ toResponse $ show err

但是我对Monad和Monad Transformers知之甚少(我把这个问题看作是学习Monad的练习),我不知道如何开始创建数据库Monad,如何将IO从happstack提升到数据库堆栈等等。

您可能想使用“ReaderT”:

type MyMonad a = ReaderT DbHandle ServerPart a
Reader
monad transformer使用
ask
函数访问单个值-在这种情况下,我们希望每个人都能获得的值是数据库连接

这里,
DbHandle
是与数据库的某种连接

因为“ReaderT”已经是所有hapstack服务器类型类的实例,所以所有正常的hapstack服务器函数都将在此monad中工作

您可能还需要某种帮助程序来打开和关闭数据库连接:

runMyMonad :: String -> MyMonad a -> ServerPart a
runMyMonad connectionString m = do
   db <- liftIO $ connect_to_your_db connectionString
   result <- runReaderT m db
   liftIO $ close_your_db_connection db
然后:

askDb :: MyMonad DbHandle
askDb = fst <$> ask

askLogger :: MyMonad LogHandle
askLogger = snd <$> ask
askDb::MyMonad DbHandle
askDb=fst ask
Askloger::MyMonad日志句柄
askLogger=snd ask
也许足够了。然后,您可以在这些原语的基础上构建更高级别的函数。您还需要将
runMyMonad
更改为在
LogHandle
中传递,不管是什么


一旦你有两个以上的东西想要访问它,你就需要有一个合适的记录类型而不是元组。

这里有一些从上面的代码片段编译出来的最简单的工作代码,供像我这样的新手使用

您将内容放入
AppConfig
中,然后在响应生成器中使用
ask
将其抓取

{-# LANGUAGE OverloadedStrings #-}
module Main where

import Happstack.Server
import Control.Monad.Reader
import qualified Data.ByteString.Char8 as C

myApp :: AppMonad Response
myApp = do
    -- access app config. look mom, no lift!
    test <- ask

    -- try some happstack funs. no lift either.
    rq <- askRq
    bs <- lookBS "lol"

    -- test IO please ignore
    liftIO . print $ test
    liftIO . print $ rq
    liftIO . print $ bs

    -- bye
    ok $ toResponse ("Oh, hi!" :: C.ByteString)

-- Put your stuff here.
data AppConfig = AppConfig { appSpam :: C.ByteString
                           , appEggs :: [C.ByteString] } deriving (Eq, Show)
config = AppConfig "THIS. IS. SPAAAAAM!!1" []

type AppMonad = ReaderT AppConfig (ServerPartT IO)

main = simpleHTTP (nullConf {port=8001}) $ runReaderT myApp config {appEggs=["red", "gold", "green"]}
{-#语言重载字符串}
模块主要在哪里
导入hapstack.Server
导入控制.Monad.Reader
将限定的Data.ByteString.Char8作为C导入
myApp::AppMonad响应
myApp=do
--访问应用程序配置。看,妈妈,别搭便车!

测试我尝试使用“unsafePerformIO”在其中执行IO。由于Happstack使用纯粹的组合,可能这是您执行IO的唯一方法。@Wu Xingbo,可以使用liftIO在Happstack上执行IO,但我不知道应该将谁传递到另一个monad堆栈。旁白:对于连接池,有和。不过,这可能超出了你的需要。
askDb :: MyMonad DbHandle
askDb = fst <$> ask

askLogger :: MyMonad LogHandle
askLogger = snd <$> ask
{-# LANGUAGE OverloadedStrings #-}
module Main where

import Happstack.Server
import Control.Monad.Reader
import qualified Data.ByteString.Char8 as C

myApp :: AppMonad Response
myApp = do
    -- access app config. look mom, no lift!
    test <- ask

    -- try some happstack funs. no lift either.
    rq <- askRq
    bs <- lookBS "lol"

    -- test IO please ignore
    liftIO . print $ test
    liftIO . print $ rq
    liftIO . print $ bs

    -- bye
    ok $ toResponse ("Oh, hi!" :: C.ByteString)

-- Put your stuff here.
data AppConfig = AppConfig { appSpam :: C.ByteString
                           , appEggs :: [C.ByteString] } deriving (Eq, Show)
config = AppConfig "THIS. IS. SPAAAAAM!!1" []

type AppMonad = ReaderT AppConfig (ServerPartT IO)

main = simpleHTTP (nullConf {port=8001}) $ runReaderT myApp config {appEggs=["red", "gold", "green"]}