Подтвердить что ты не робот

Выбор дизайна почтового ящика.

Глядя на:

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

Спасибо

4b9b3361

Ответ 1

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

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

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

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

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

'Msg * AsyncReplyChannel<'Reply>

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

'Msg * option<AsyncReplyChannel<'Reply>>

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