Как сопоставить шаблон по типу сообщения, полученного в F# akka.net?

Пожалуйста, смотрите последнее редактирование.

Извиняюсь за вопрос новичка. Я пытаюсь реализовать что-то в F# с помощью Akka.net. Я очень новичок в F#, и я использовал только Акку из Scala. По сути, я пытаюсь реализовать что-то довольно простое в Scala, а именно заставить актера делать разные вещи в зависимости от типа получаемого им сообщения.

Мой код приведен ниже, и это небольшая модификация примера "Привет, мир", взята с сайта akka.net. Я считаю, что первая проблема с моим кодом заключается в том, что он выполняет сопоставление с образцом записи вместо сопоставления с образцом типа, однако я не смог написать сопоставление с типом без ошибок компиляции... Любая помощь будет принята с благодарностью. Спасибо.

open Akka.FSharp
open Actors
open Akka
open Akka.Actor

type Entries = { Entries: List<string>}

let system = ActorSystem.Create "MySystem"

let feedBrowser = spawn system "feedBrowser" <| fun mailbox -> 
    let rec loop() = actor {
        let! msg = mailbox.Receive()
        match msg with 
        | { Entries = entries} -> printf "%A" entries
        | _ -> printf "unmatched message %A" msg 
        return! loop()}
    loop()

[<EntryPoint>]
let main argv = 

    feedBrowser <! "abc"        // this should not blow up but it does

    system.AwaitTermination()

    0

Редактировать: ошибка является ошибкой во время выполнения, System.InvalidCastException, не может привести объект типа String к записям.

Позднее редактирование: я получил это для работы с этим изменением, понижая до объекта:

let feedBrowser = spawn system "feedBrowser" <| fun mailbox -> 
    let rec loop() = actor {
        let! msg = mailbox.Receive()
        let msgObj = msg :> Object
        match msgObj with 
        | :? Entries as e  -> printfn "matched message %A" e
        | _ -> printf "unmatched message %A" msg 
        return! loop()}
    loop()

Теперь эти две строки работают правильно

feedBrowser <! "abc"
feedBrowser <! { Entries = ["a"; "b"] }

первый выводит "непревзойденное сообщение abc", а второй выводит записи.

Есть ли лучший способ обойти это без актерского состава? Есть ли у akka.net что-то конкретно для этого случая? Спасибо.

1 ответ

Решение

Вы должны использовать Дискриминационный Союз (тип Команды в этом примере). Тогда вы можете сопоставить шаблон с его параметрами.

type Entries = { Entries: List<string>}

type Command = 
    | ListEntries of Entries
    | OtherCommand of string

let stack() = 

    let system = ActorSystem.Create "MySystem"

    let feedBrowser = spawn system "feedBrowser" <| fun mailbox -> 
        let rec loop() = actor {
            let! msg = mailbox.Receive()
            match msg with 
            | ListEntries { Entries = entries} -> printf "%A" entries
            | OtherCommand s -> printf "%s" s
            return! loop() }
        loop()

И чтобы отправить сообщение, вы должны использовать:

feedBrowser <! OtherCommand "abc"
feedBrowser <! ListEntries { Entries = ["a"; "b"] }

Важно сказать, что оператор отправки имеет следующую подпись:

#ICanTell -> obj -> unit

Поэтому, если вы передадите сообщение другого типа, например строку, оно вызовет исключение.

Другие вопросы по тегам