Невозможно сохранить состояние с процессором почтового ящика (F #) - PullRequest
1 голос
/ 12 мая 2019

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

Я в значительной степени следовал коду из https://fsharpforfunandprofit.com/posts/concurrency-actor-model/, однако в моем случае он не работает должным образом.Код, который я имею, выглядит следующим образом:

type TransactionQueue ={

queue : string list

} with

static member UpdateState (msg : string) (tq : TransactionQueue) =
    {tq with queue = (msg :: tq.queue)}

static member Agent = MailboxProcessor.Start(fun inbox ->
                            let rec msgLoop (t : TransactionQueue) =
                                async{
                                   let! msg = inbox.Receive()
                                   let newT = TransactionQueue.UpdateState msg t
                                   printfn "%A" newT
                                   return! msgLoop newT
                                }
                            msgLoop {queue = []}
                        )

static member Add i = TransactionQueue.Agent.Post i



[<EntryPoint>]
let main argv =

// test in isolation
printfn "welcome to test"
let rec loop () =
    let str = Console.ReadLine()
    TransactionQueue.Add str
    loop ()

loop ()



0 

Результат, который я продолжаю получать, представляет собой список только самых последних входных данных, состояние не сохраняется.Поэтому, если я введу «a», затем «b», то «c» очередь будет иметь только значение «c» вместо «a»; «b»; «c»

Любая помощь или указатели будутсамое ценное!

1 Ответ

2 голосов
/ 12 мая 2019

Так же, как C # Properties , ваш Agent действительно является свойством и, следовательно, ведет себя как метод с параметром void. Вот почему вы будете получать нового агента каждый раз при обращении к свойству Agent.

В идиоматическом F # есть два стиля при реализации агентов. Если вам не нужно иметь много экземпляров агента, просто напишите модуль и заключите в него содержимое, связанное с агентом. В противном случае следует использовать стиль ООП.

Код для стиля # 1

module TransactionQueue =
    type private Queue = Queue of string list
    let private empty = Queue []
    let private update item (Queue items) = Queue (item :: items)
    let private agent = MailboxProcessor.Start <| fun inbox ->
        let rec msgLoop queue = async {
            let! msg = inbox.Receive ()
            return! queue |> update msg |> msgLoop
        }
        msgLoop empty
    let add item = agent.Post item

[<EntryPoint>]
let main argv =
    // test in isolation
    printfn "welcome to test"
    let rec loop () =
        let str = Console.ReadLine()
        TransactionQueue.add str
        loop ()
    loop ()

Код для стиля # 2

type Queue = Queue of string list with
    static member Empty = Queue []
    static member Update item (Queue items) =
        Queue (item :: items)

type Agent () =
    let agent = MailboxProcessor.Start <| fun inbox ->
        let rec msgLoop queue = async {
            let! msg = inbox.Receive ()
            return! queue |> Queue.Update msg |> msgLoop
        }
        msgLoop Queue.Empty
    member this.Add item = agent.Post item

[<EntryPoint>]
let main argv =
    // test in isolation
    printfn "welcome to test"
    let agent = new Agent ()
    let rec loop () =
        let str = Console.ReadLine()
        agent.Add str
        loop ()
    loop ()

Обратите внимание на использование Типов объединений в одном регистре для типа Queue.

...