MailboxProcessor.PostAndReply выбор дизайна - PullRequest
12 голосов
/ 29 февраля 2012

Глядя на:

member this.PostAndReply : (AsyncReplyChannel<'Reply> -> 'Msg) * ?int -> 'Reply

Я не могу понять, почему подпись выглядит так нелогично для меня. Мы хотим опубликовать сообщение для агента и дождаться ответа. Почему мы должны дать ему странную функцию «сообщения»?

Снова посмотрите этот фрагмент MSDN:

let rec loop() =
    printf "> "
    let input = Console.ReadLine()
    printThreadId("Console loop")
    let reply = agent.PostAndReply(fun replyChannel -> input, replyChannel)
    if (reply <> "Stopping.") then
        printfn "Reply: %s" reply
       loop()
    else
        ()
loop()

Я бы предпочел что-то вроде этого:

member this.PostAndReply : 'Msg * ?int -> 'Reply

Спасибо

1 Ответ

9 голосов
/ 29 февраля 2012

Эта подпись типа выглядит довольно запутанно, когда вы видите ее впервые, но она имеет смысл.

Дизайн библиотеки F #
Идея заключается в том, что когда вы вызываете PostAndReply, вам нужно дать ему функцию , которая:

  • создает сообщение типа 'Msg (для отправки агенту)
  • после того, как среда выполнения F # создает канал для отправки сообщений обратно вызывающей стороне (каналы представляются в виде значений типа AsyncReplyChannel<'Reply>).

Построенное вами сообщение должно содержать канал ответа, но библиотека F # не знает, как вы хотите представлять свои сообщения (и поэтому она не знает, как вы хотите сохранить канал ответа в сообщении). В результате библиотека просит вас написать функцию, которая создаст сообщение для агента после того, как система построит канал.

Ваше альтернативное предложение
Проблема с вашим предложением состоит в том, что если бы PostAndReply имел тип 'Msg -> 'Reply, сообщение, которое агент получает после того, как он вызвал Receive, было бы следующего типа:

'Msg * AsyncReplyChannel<'Reply>

... поэтому каждое сообщение, полученное агенту, также должно содержать канал для отправки ответов обратно. Однако вы, вероятно, не хотите отправлять ответ на каждое полученное сообщение, так что это не сработает. Может быть, вы могли бы использовать что-то вроде:

'Msg * option<AsyncReplyChannel<'Reply>>

... но это становится все сложнее (и это все еще не совсем правильно, потому что вы можете отвечать только на некоторые сообщения от 'Msg, но не на все).

...