2011-07-25 22 views
17

以下は、反応性バナナライブラリーを使用するHaskell FRPプログラムの例です。私はちょうどハスケルと一緒に自分のやり方を感じ始めているだけで、特にFRPの意味を頭に入れていない。 https://gist.github.com/1099712は:私は本当に要旨はここにあります私は反応性バナナを使用していますか?

{-# 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 

以下のコードのいくつかの批判をいただければと思います。

私は、これがaccumEの「良い」使用であるかどうかについてのコメントを特に歓迎します(私は推測していませんが、毎回この関数の全体がイベントストリーム全体をトラバースします)。

また、私は、複数のソケットからメッセージを引き出す方法について知りたいと思います。今のところ、永遠に1つのイベントループがあります。これの具体的な例として、カウンタ内のIdMapの現在の状態を照会するために、2番目のソケット(zeromq構文でREQ/REPペア)を追加する方法はありますか?

答えて

21

reactive-bananaの著者話す。)

全体的に、あなたのコードは、私には正常に見えます。なぜ私は最初に反応性バナナを使用しているのか理解していませんが、理由はあります。つまり、Node.jsのようなものを探しているのであれば、Haskellのleightweightスレッドmake it unnecessaryはイベントベースのアーキテクチャを使用することを忘れないでください。

補足:基本的に機能的なリアクティブプログラミングは、さまざまな入力、状態、および出力が適切なタイミング(GUI、アニメーション、オーディオなど)で一緒に機能する必要がある場合に便利です。これとは対照的に、あなたが本質的に独立した多くのイベントを処理しているのは残念です。これらは通常の機能と時折の状態で最もよく処理されます。


に関する個別の質問:

がaccumEの良い 『利用「私は特にこれがあるかどうかの周りに任意のコメントを歓迎するだろうが』、(私は、全体を横断するこの機能の不明確です私は推測しているが、毎回イベントストリーム)。

私にはうまく見えます。あなたが推測したように、accumE関数は実際にはリアルタイムです。現在の累積値のみが格納されます。

あなたの推測から判断すると、新しいイベントが到着するたびにホタルのようなネットワークを通過すると考えているようです。これは内部的には発生しますが、ではなくあなたはどうすればよいですかは機能的な反応的プログラミングについてと思っています。むしろ、右の図はこれです。fromAddHandlerの結果は、入力イベントの完全なリストです。となります。言い換えれば、recvdには、将来の各イベントの順序付きリストが含まれていると考えるべきです。 (もちろん、あなた自身の正気のために、時間が来る前にそれらを見てみるべきではありません.-))accumE関数は、一度それをトラバースすることによって1つのリストを別のものに単純に変換します。

ドキュメントでは、このような考え方をより明確にする必要があります。

"また、私は、複数のソケットからメッセージを引き出す方法について知りたいと思います。本の具体的な例として、どのように私はカウンターの内側IDMAPの現在の状態に照会する第2のソケット(zeromq用語でREQ/REPのペア)を追加しますか?」

receive機能がブロックされない場合は、あなたをそれは、あなたがブロック、スレッドを使用する必要があるブック実世界HaskellでもセクションHandling Multiple TCP Streamsが表示されない場合は、単に異なるソケット

linkSocketHandler s1 s2 runner1 runner2 = forever $ do 
    receive s1 [] >>= runner1 . fromString . C.unpack 
    receive s2 [] >>= runner2 . fromString . C.unpack 

に二回、それを呼び出すことができます。(この上で新しい質問をお気軽にこれは本書の範囲外です)

+0

ありがとうございました。 FRPでは、ここではうまくフィットするように見えますが、多くのzeromqソケットがあれば、GUIからのイベント駆動型の入力に非常に簡単に似せるようになるでしょう...だから私はいくつかの新しいアイデアのタイヤをキックします:-) State Monadとhaskellスレッドでこれを行う方が理に適っていると思いますか? –

+0

@Ben Ford:答えに小さな言葉を追加しました。私はあなたがソケットで何をしたいのか分からないので、あなたの目的のためにFRPが過労であるかどうかは分かりません。基本的に、イベントネットワークが単一の 'accumE'といくつかの' filterE'を持つこれよりもはるかに大きくならないなら、それはFRPなしでもっと優雅に行われます。 –

関連する問題