gpt4 book ai didi

haskell - 我使用的是 react 香蕉吗?

转载 作者:行者123 更新时间:2023-12-03 14:03:28 25 4
gpt4 key购买 nike

这是一个使用 reactive-banana 库的 Haskell FRP 程序示例。我才刚刚开始对 Haskell 有所了解,尤其是还没有完全理解 FRP 的含义。我真的很感激对下面的代码的一些批评

{-# LANGUAGE DeriveDataTypeable #-}
module Main where

{-
Example FRP/zeromq app.

The idea is that messages come into a zeromq socket in the form "id state". The state is of each id is tracked until it's complete.
-}

import Control.Monad
import Data.ByteString.Char8 as C (unpack)
import Data.Map as M
import Data.Maybe
import Reactive.Banana
import System.Environment (getArgs)
import System.ZMQ

data Msg = Msg {mid :: String, state :: String}
deriving (Show, Typeable)

type IdMap = Map String String

-- | Deserialize a string to a Maybe Msg
fromString :: String -> Maybe Msg
fromString s =
case words s of
(x:y:[]) -> Just $ Msg x y
_ -> Nothing

-- | Map a message to a partial operation on a map
-- If the 'state' of the message is "complete" the operation is a delete
-- otherwise it's an insert
toMap :: Msg -> IdMap -> IdMap
toMap msg = case msg of
Msg id_ "complete" -> delete id_
_ -> insert (mid msg) (state msg)

main :: IO ()
main = do
(socketHandle,runSocket) <- newAddHandler

args <- getArgs
let sockAddr = case args of
[s] -> s
_ -> "tcp://127.0.0.1:9999"
putStrLn ("Socket: " ++ sockAddr)


network <- compile $ do
recvd <- fromAddHandler socketHandle

let
-- Filter out the Nothings
justs = filterE isJust recvd
-- Accumulate the partially applied toMap operations
counter = accumE M.empty $ (toMap . fromJust <$> justs)


-- Print the contents
reactimate $ fmap print counter

actuate network

-- Get a socket and kick off the eventloop
withContext 1 $ \ctx ->
withSocket ctx Sub $ \sub -> do
connect sub sockAddr
subscribe sub ""
linkSocketHandler sub runSocket


-- | Recieve a message, deserialize it to a 'Msg' and call the action with the message
linkSocketHandler :: Socket a -> (Maybe Msg -> IO ()) -> IO ()
linkSocketHandler s runner = forever $ do
receive s [] >>= runner . fromString . C.unpack

这里有一个要点: https://gist.github.com/1099712 .

我特别欢迎任何关于这是否是 accumE 的“好”使用的评论,(我不清楚这个函数每次都会遍历整个事件流,尽管我猜不是)。

此外,我想知道如何从多个套接字中提取消息 - 目前我在永远的内部有一个事件循环。作为一个具体的例子,我将如何添加第二个套接字(zeromq 用语中的 REQ/REP 对)来查询计数器内 IdMap 的当前状态?

最佳答案

(reactive-banana 的作者发言。)

总的来说,你的代码对我来说看起来不错。我实际上不明白你为什么首先使用 react 香蕉,但你会有你的理由。也就是说,如果您正在寻找类似 Node.js 的东西,请记住 Haskell 的轻量级线程 make it unnecessary使用基于事件的架构。

附录:基本上,当您有各种不同的输入、状态和输出必须在正确的时间(想想 GUI、动画、音频)下协同工作时,函数式响应式(Reactive)编程很有用。相比之下,当您处理许多本质上独立的事件时,它就显得过分了。这些最好用普通函数和偶尔的状态来处理。

关于个别问题:

"I'd particularly welcome any comments around whether this is a "good" use of accumE, (I'm unclear of this function will traverse the whole event stream each time although I'm guessing not)."



在我看来很好。如您所料, accumE功能确实是实时的;它只会存储当前的累积值。

从您的猜测来看,您似乎在想,每当有新事件出现时,它都会像 Firebug 一样在网络中传播。虽然这确实发生在内部,但这不是您应该如何考虑函数式响应式(Reactive)编程。相反,正确的图片是: fromAddHandler 的结果是输入事件的完整列表,因为它们将发生。换句话说,你应该认为 recvd包含 future 每个事件的有序列表。 (当然,为了您自己的理智,您不应该在他们的时间到来之前尝试查看它们。;-)) accumE函数只需遍历一次即可将一个列表转换为另一个列表。

我需要在文档中使这种思维方式更加清晰。

"Also I'd like to know how one would go about pulling in messages from multiple sockets - at the moment I have on event loop inside a forever. As a concrete example of this how would I add second socket (a REQ/REP pair in zeromq parlance) to query to the current state of the IdMap inside counter?"



如果 receive函数不会阻塞,你可以简单地在不同的套接字上调用它两次
linkSocketHandler s1 s2 runner1 runner2 = forever $ do 
receive s1 [] >>= runner1 . fromString . C.unpack
receive s2 [] >>= runner2 . fromString . C.unpack

如果它确实阻塞,您将需要使用线程,另请参阅 Handling Multiple TCP Streams 部分在Real World Haskell 一书中。 (请随意提出一个新问题,因为它超出了这个问题的范围。)

关于haskell - 我使用的是 react 香蕉吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6812533/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com