5

データベースへのアクセスが多い Happstack アプリケーションを作成したいと考えています。一番下にIOがあり、一番上にデータベース書き込みのようなモナド(真ん中にログライターがある)を持つモナドスタックは、各アクセスで明確な機能を持つように機能すると思います。例:

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

と:

getItemList :: MyDBMonad (Error [Item])
getItemList = do
  -- etc...

しかし、私は Monad と Monad Transformers についてほとんど知識がなく (この質問はそれについて学ぶための演習だと思います)、Database Monad の作成を開始する方法、IO を happstack から Database Stack に持ち上げる方法もわかりません。 ...等。

4

2 に答える 2

7

これは、私のような混乱した初心者のために、上記のスニペットからコンパイルされた最小限の動作コードです。

タイプに何かを入れて、レスポンスメーカーの内部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"]}
于 2012-06-21T13:44:14.143 に答える
6

「ReaderT」を使用する可能性があります。

type MyMonad a = ReaderT DbHandle ServerPart a

Readerモナドトランスフォーマーは、関数を使用して単一の値にアクセスできるようにします。askこの場合、すべての人に取得してもらいたい値はデータベース接続です。

ここに、DbHandleデータベースへの接続があります。

「ReaderT」はすでにすべての happstack-server 型クラスのインスタンスであるため、すべての通常の happstack-server 関数はこのモナドで機能します。

おそらく、データベース接続を開いたり閉じたりするための何らかのヘルパーも必要になるでしょう:

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

(ここで「ブラケット」のような関数を使用する方が良いかもしれませんが、ServerPartモナドにそのような操作があることを知りません)

ロギングをどのように行いたいかわかりません - ログファイルをどのように操作する予定ですか? 何かのようなもの:

type MyMonad a = ReaderT (DbHandle, LogHandle) ServerPart a

その後:

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

askLogger :: MyMonad LogHandle
askLogger = snd <$> ask

十分かもしれません。次に、これらのプリミティブを基に構築して、より高レベルの関数を作成できます。それが何であれ、でrunMyMonad渡されるように変更する必要もあります。LogHandle

アクセスしたいものを 2 つ以上取得したら、タプルの代わりに適切なレコード タイプを使用する必要があります。

于 2011-10-19T12:32:37.767 に答える