I'm not sure if I understand the question correctly - but you can certainly use a discriminated union as a type of your messages. Then you can have some cases (message types) that contain AsyncReplyChannel<T>
and some other messages that do not carry it (and do not require a reply).
For example, for a simple agent that adds numbers, you can have Add
(which does not need response) and Get
which does need a response. In addition, Get
carries a Boolean that specifies whether we should reset the state back to zero:
type Message =
| Add of int
| Get of bool * AsyncReplyChannel<int>
The agent then receives messages repeatedly and if the message is Get
then it sends a reply:
let counter = MailboxProcessor.Start(fun inbox ->
let rec loop count = async {
let! msg = inbox.Receive()
match msg with
| Add n -> return! loop (count + n) // Just update the number
| Get (reset, repl) ->
repl.Reply(count) // Reply to the caller
let count = if reset then 0 else count // get new state
return! loop count } // .. and continue in the new state
loop 0 )
You can then use Post
method to send message that does not require a reply and PostAndReply
to send a message that returns something via an async reply channel:
counter.Post(Add 10)
counter.PostAndReply(fun r -> Get(true, r))
counter.PostAndReply(fun r -> Get(false, r))