drama
drama copied to clipboard
Alternative `receive`?
Currently, receive
's type is (forall res. msg res -> Actor msg res) -> Actor msg ()
. As a result, when using it, a handler for all kinds of messages is passed in, used to process a single message (returning a result of a call
call if needed), and, well, return ()
.
As a result, it's not possible to 'return' values out of a handler into the actor code calling receive
. Hence, a "state" actor, as is provided as an example in the documentation, requires an IORef
(or similar) which gets updated from inside the message handler.
This is, however, quite unlike how this would be done in Erlang, and (IMHO) how it should be done in Haskell. Instead of using an IORef
and some forever $ receive _
, one could use explicit recursion, passing through the state as a pure value.
Hence, I was wondering, could there be a receive' :: (forall res. msg res -> Actor msg (res, a)) -> Actor msg a
, which would allow to implement a "state" actor somewhat like (writing this from memory, please forgive any type/syntax errors):
data StateMessage s a where
Get :: StateMessage s s
Set :: s -> StateMessage s ()
stateKeeper :: s -> Actor (StateMessage s) void
stateKeeper = loop
where
loop s0 = do
s' <- receive $ \case
Get -> (s0, s0)
Set s -> ((), s)
loop s'
You make a good point! 🙂 It would be more pure (and Erlang/Elixir-y) to recurse with the new state, rather than using a mutable cell. I think your pure receive'
would be a better default, and the current receive
could be renamed receive_
.