
Hi,
I'm interested in FRP, have read several of the papers and am wondering if it could be applied to writing multi-client server programs.
That's funny: in the last few months, I have developed a functional-reactive framework for large scale distributed system programming. You can find the source code and a technical report here: http://perso.eleves.bretagne.ens-cachan.fr/~dagand/opis/ This code is in OCaml but the concepts can be translated in Haskell: advised by Conal Elliott, I have already written the core of Opis in Haskell (i.e the Arrow instances and a small network simulator) to ensure the feasibility of a purely functional implementation. The implementation in Haskell is based on the Mealy automaton while my code in OCaml efficiently emulates this construct (based on suggestions of Zheng Li, Oleg Kiselyov and Jacques Garrigue).
What would be the input type events for such a system? What would be the output type events? How would the system handle the fact that it has to multiplex several IO streams (sockets)?
In my system, the input events are network events -- such as a received TCP message or a UDP packet as well as notifications (connection closed, listening on port X, ...) -- or timer events -- such as "a timer has just fired", "the timer is correctly set up" or "the timer has been removed" -- or user events -- whatever the user wants to signal. The outputs are commands to the "launcher" system: the launcher will collect these outputs and interpret them in term of (side-effecting) actions. For example, the reactive function might ask to "send the data D to peer x": thus, the launcher will connect to x, marshal the data and send it to x. Similarly, you can ask to listen on a network port, set up a timer, send an event to the user, ... The multiplexing is done out of the reactive function, in the launcher system. For networking, for instance, it opens one thread per open connection. Once a thread has retrieved a complete message, it sends it to reactive processing by a "Chan" (in Control.Concurrent). I hope the technical report is clearer than this rough description. I can send you a more "haskeller-friendly" paper if you are interested.
Should input events include new connection requests and shutdowns?
New connection requests are silent whereas a connection shutdown raises an input event.
Individual bytes? Streams of bytes? or higher level PDUs? What kind of output should be generated? Full PDUs? streams of bytes? Pairs of (connection identifier,data)?
I work at the message level. For instance, the reactive function outputs "Send( destination_ip , TCP, data )", then the launcher marshals "data" and sends it to "destination_ip". On the other side, the launcher marshals the received buffer of bytes to the same type and transmits "TCP_in( source_ip , data )" to the reactive function. Hence, for the reactive function, values are typed "end-to-end", hence reducing the risk of error in marshaling.
How would such a system effectively hide the multiplexed IO going on?
Personally, I chose to hide this multiplexing on the "launcher" side, ie. out of the reactive function. As the "launcher" side is developed once and for all (by me), a Opis' user will not have to deal with multiplexing: she just has to care with processing well-defined inputs by reacting with the correct outputs.
Is this sort of problem poorly suited for FRP?
According to my experience, developing peer-to-peer systems in Opis has been a great pleasure, because of its simplicity. On the other hand, my architecture is based on the Arrow type to build the reactive functions. Hence, I work hand-in-hand with the type-checker. When developing a protocol in Opis, it is sometimes like working with a theorem prover: if you forget that a given event could occur, the type-checker complains, for example. Hence, in the P2P field, my tool is a complete alien: people say that it looks great but don't want to invest time to learn it... :-( The "side-effects" of using purely functional structures are plentiful (and well-known here): ease of debugging of pure functions, modularity (given a reactive function, I can run it live on a network, simulate, debug, or model-check it without modification), ease of backtracking (useful for the debugger and the model-checker), reproducibility (see the complexity profiler), provability (see the use of Isabelle's certified code), and so on ... Currently, I'm developing a complete formalisation of the Mealy arrow instance in Coq and, hopefully, one day, I will be able to develop a complete P2P protocol in Coq ;-) Hope this inspires you, Regards, -- Pierre-Evariste DAGAND http://perso.eleves.bretagne.ens-cachan.fr/~dagand/