1

私は単純な http サーバーを実装していますが、応答をグローバルな状態に依存させたいと考えています。たとえば、同じクライアントからリクエスト「get_settings」を初めて取得した場合、大きな設定 json を送信し、2 回目は「変更されていない」http 応答を送信します。

そんな感じ

import Network.Simple.TCP

main = withSocketsDo $ do 
    let settings_state = 0 -- flag for settings response
    serve (Host "127.0.0.1") "23980" $ \(conn_sock, remote_addr) -> do
        putStrLn $ "TCP connection established from " ++ show remote_addr
        (Just inp) <- recv conn_sock 1024
        send conn_sock (process inp settings_state)

process :: B.ByteString -> Int -> B.ByteString
process inp flag
    | flag == 0 = ... -- return full response and change global flag
    | otherwise = ... -- return 'Not-modified'

問題は、どうすればそれを実装できるかということです。そして、モナドトランスフォーマーなどを使わずに、手動でできるだけ簡単にしたいと思います。コードは醜くシンプルにしましょう。ありがとう

4

1 に答える 1

4

フラグの変更には明らかな副作用があるため、 の結果は次のprocessようになりますIO

process :: B.ByteString -> Int -> IO B.ByteString

いかなる種類のモナド変換子も使用したくないので、 をInt変更可能な参照と交換する必要があります。はい、正しく読みました: 、、、…など、変更可能な型いくつかあります。シンプルにするために、 に固執しましょう。IORefMVarTVarMVectorSTRefIORef

process :: B.ByteString -> IORef Int -> IO B.ByteString
process inp flag = do
    oldFlag <- readIORef flag
    if oldFlag == 0 
       then do modifyIORef' flag (+1)
               return bigJSONObject
       else return notModified

フラグのロジックを提供していないため、値を増やしただけですが、おそらく何か他のことをしたい (またはフラグを に変更したいIORef Bool) ことに注意してください。マルチスレッドプログラムで安全にatomicModifyIORef'使用したい場合にも使用したいことに注意してください。IORef

    oldFlag <- atomicModifyIORef' flag (\o -> (o+1,o))

IORefいずれにせよ、 withを作成する必要があるnewIORef valueため、コード スニペットは次のようになります。

main = withSocketsDo $ do 
    settings_state <- newIORef 0
    serve (Host "127.0.0.1") "23980" $ \(conn_sock, remote_addr) -> do
        -- ...
于 2014-07-19T21:08:50.283 に答える