我正在实施简单的http服务器 我希望我的回答取决于一些全球状态。例如,如果我收到请求' get_settings'我是第一次从同一个客户端发送大型设置json,第二次我将发送未经修改的' 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'
问题是如何实现它?我想尽可能简单,手动,没有任何Monad变形金刚等等。让代码变得丑陋,但很简单。 感谢
答案 0 :(得分:4)
由于更改旗帜明显有一些副作用,process
的结果将在IO
:
process :: B.ByteString -> Int -> IO B.ByteString
由于您不想使用任何类型的monad转换器,因此需要将Int
与一些可变引用进行交换。是的,您已正确阅读: 可变的几种类型,例如IORef
,MVar
,TVar
,MVector
,{ {1}} ......为了保持简单,请坚持IORef
。
STRef
请注意,您没有为该标志提供任何逻辑,因此我只是增加了该值,但您可能想要执行其他操作(或将标志更改为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
,因此您的代码段会变成类似
newIORef value