3 ms·
That's not an extreme case at all, I'd even argue RWS(T) (or its 'manual' version) is a very common stack. As an example, I use RWST in Kontiki, my implementat
by nicolast 13y ago
That's not an extreme case at all, I'd even argue RWS(T) (or its 'manual' version) is a very common stack.
As an example, I use RWST in Kontiki, my implementation of the Raft consensus protocol, where the R part contains configuration (e.g. the set of nodes in the cluster), the W part is filled with 'commands' to be executed after an FSM transition as a reaction on some event (incoming message, timeout,...), where 'commands' are things like 'send this message to node N', 'broadcast this message to all nodes', 'append this entry to the replicated log' or 'log this message (for debugging)', and finally the S part provides access to the current state.
Every FSM transition returns the new state, and a list of commands to execute (& the updated state of the S part, but that's discarded).
All you need to provide is an 'interpreter' for the commands.
This approach makes testing very easy: I can start at any desired state and event (that's just pure data), run the FSM on that (which is also a pure operation, although that's slightly complicated due to the MonadLog implementation which should underlie RWST, but that's besides this discussion), and check whether the output state & commands are the ones I expect, without mocking any networking or intercepting other IO.
[update]
As an example of what this looks like from inside the FSM code, see https://github.com/NicolasT/kontiki/blob/master/src/Network/Kontiki/Raft/Candidate.hs#L34 https://github.com/NicolasT/kontiki/blob/master/src/Network/... This is a rather straight-forward implementation of the algorithm and looks imperative, but is 100% pure (with all its benefits).