Ich denke, diese Frage berührt den gleichen Bereich, aber ich kann nicht sehen, wie es auf meine Situation angewendet werden kann. Generic reply from agent/mailboxprocessor?Generische Abfragen und Befehle mit einem MailboxProcessor
Hier ist der Hintergrund. Ich habe einen Zustand, lass uns einfach sagen, dass es nur eine Liste von Spielern enthält. Es könnte mehr geben, z.B. Spiele usw. Ich habe auch einen initialState, der keine Spieler hat.
Ich habe zwei Arten von "Nachrichten", mit denen ich mich befassen muss. Abfragen, bei denen es sich um Funktionen handelt, die den Status einem Wert zuordnen, den Status jedoch nicht ändern. Z.B. Gebe einen Int zurück, der den höchsten Punktestand zeigt.
Und Befehle, die einen neuen Zustand erzeugen, aber einen Wert zurückgeben können. ZB Geben Sie einen neuen Spieler zur Sammlung und geben Sie eine ID oder was auch immer zurück.
type Message<'T> =
| Query of (State -> 'T)
| Command of (State -> 'T * State)
Und dann haben wir ein Modell, das auf Nachrichten reagieren kann. Aber die leider einen veränderlichen Zustand verwendet, würde ich lieber einen MailboxProcessor und eine Nachrichtenschleife verwenden.
type Model(state: State) =
let mutable currentState = state
let HandleMessage (m: Message<'outp>) =
match m with
| Query q -> q currentState
| Command c ->
let n, s = c currentState
currentState <- s
n
member this.Query<'T> (q: State -> 'T) =
HandleMessage (Query q)
member this.Command<'T> (c: State -> 'T * State) =
HandleMessage (Command c)
// Query Methods
let HowMany (s: State) = List.length s.Players
let HasAny (s: State) = (HowMany s) > 0
let ShowAll (s: State) = s
// Command Methods
let AddPlayer (p: Player) (s: State) = (p, {s with Players = p::s.Players})
let model = new Model(initialState)
model.Command (AddPlayer {Name="Sandra"; Points=1000})
model.Query HasAny
model.Query HowMany
model.Query ShowAll
Offensichtlich wäre es nett, wenn dieses State Argument selbst generisch wäre. Aber ein Schritt nach dem anderen.
Alles, was ich versucht habe, diesen veränderlichen currentState durch einen MailboxProcessor zu ersetzen, ist fehlgeschlagen. Das Problem ist mit den Generics und der statischen Natur von F #, aber ich kann keinen Weg finden.
Das Folgende funktioniert nicht, aber es zeigt, was ich tun möchte.
type Player = {Name: string; Points: int}
type State = {Players: Player list}
let initialState = {Players = []}
type Message<'T> =
| Query of (State -> 'T) * AsyncReplyChannel<'T>
| Command of (State -> 'T * State) * AsyncReplyChannel<'T>
type Model(state: State) =
let innerModel =
MailboxProcessor.Start(fun inbox ->
let rec messageLoop (state: State) =
async {
let! msg = inbox.Receive()
match (msg: Message<'outp>) with
| Query (q, replyChannel) ->
replyChannel.Reply(q state)
return! messageLoop state
| Command (c, replyChannel) ->
let result, newState = c state
replyChannel.Reply(result)
return! messageLoop(newState)
}
messageLoop initialState)
member this.Query<'T> (q: State -> 'T) =
innerModel.PostAndReply(fun chan -> Query(q , chan))
member this.Command<'T> (c: State -> 'T * State) =
innerModel.PostAndReply(fun chan -> Command(c, chan))
// Query Methods
let HowMany (s: State) = List.length s.Players
let HasAny (s: State) = (HowMany s) > 0
let ShowAll (s: State) = s
//// Command Methods
let AddPlayer (p: 'T) (s: State) = {s with Players = p::s.Players}
let model = new Model(initialState)
model.Command (AddPlayer {Name="Joe"; Points=1000})
model.Query HowMany
model.Query HasAny
model.Query ShowAll
Tomas, genau das habe ich versucht. Ich konnte sehen, dass der Agent die Funktionen übergeben wurde, so dass er nichts tun musste, außer das Ergebnis wieder zu bekommen. Deshalb habe ich so lange damit verbracht, es war wirklich nervig zu denken, dass ein generischer Ansatz vielleicht nicht möglich ist. –
Habe ich recht zu denken, dass es zu weit ist, den Staat selbst zu einem Generikum zu machen? z.B. Etwas wie. type Modell <'S> (state: 'S) = ... –
@RichardDalton Die generischen Zustand sollte vollständig funktionieren. Sie müssen nur die 'Message'- und' Model'-Typen generisch machen und auch 'initialState' als Konstruktor-Parameter an das' Model' übergeben, aber dann sollte es gut funktionieren! –