drama icon indicating copy to clipboard operation
drama copied to clipboard

Alternative `receive`?

Open NicolasT opened this issue 2 years ago • 1 comments

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'

NicolasT avatar Feb 11 '23 21:02 NicolasT

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_.

evanrelf avatar Feb 16 '23 00:02 evanrelf