Đây là ví dụ về chương trình Haskell FRP sử dụng thư viện phản ứng chuối. Tôi chỉ mới bắt đầu cảm thấy theo cách của tôi với Haskell, và đặc biệt là không có khá đầu của tôi xung quanh những gì FRP có nghĩa là. Tôi thực sự đánh giá cao một số phê bình của mã bên dướiTôi có sử dụng chuối phản ứng đúng không?
{-# 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
Có một ý chính tại đây: https://gist.github.com/1099712.
Tôi đặc biệt hoan nghênh bất kỳ nhận xét nào về việc sử dụng tiền tố "tốt" (Tôi không rõ chức năng này sẽ đi qua toàn bộ luồng sự kiện mỗi lần mặc dù tôi đoán là không).
Ngoài ra tôi muốn biết làm thế nào người ta sẽ đi về kéo tin nhắn từ nhiều ổ cắm - tại thời điểm này tôi có một vòng lặp sự kiện bên trong một mãi mãi. Như một ví dụ cụ thể về điều này làm thế nào tôi sẽ thêm ổ cắm thứ hai (một cặp REQ/REP trong ngôn ngữ zeromq) để truy vấn trạng thái hiện tại của IdMap bên trong bộ đếm?
Cảm ơn Heinrich, lý do thứ tại FRP trông giống như một phù hợp tốt ở đây là nếu bạn có nhiều ổ cắm zeromq, họ có thể rất dễ dàng bắt đầu giống như sự kiện điều khiển đầu vào từ một GUI ... Vì vậy, tôi mặc dù tôi muốn đá lốp xe của một số ý tưởng mới :-) Bạn có nghĩ rằng nó có ý nghĩa hơn để làm điều này với một tiểu bang monad và chủ đề haskell? –
@Ben Ford: Tôi đã thêm một nhận xét nhỏ vào câu trả lời. Tôi không biết những gì bạn muốn làm với các ổ cắm, vì vậy tôi không thể cho bạn biết liệu FRP là overkill cho mục đích của bạn. Về cơ bản, nếu mạng sự kiện của bạn sẽ không phát triển lớn hơn nhiều so với cái này với một 'E E' duy nhất và một số' filterE', thì nó hoàn toàn thanh lịch hơn mà không có FRP. –