Generische Abfragen und Befehle, die einen MailboxProcessor verwenden

8

Ich denke, diese Frage berührt den gleichen Bereich, aber ich kann nicht sehen, wie es auf meine Situation angewendet werden kann. Generische Antwort vom Agenten / Mailboxprozessor?

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.

%Vor%

Ich habe zwei Arten von "Nachrichten", mit denen ich mich befassen muss. Abfragen, bei denen es sich um Funktionen handelt, die den Status einem bestimmten Wert zuordnen, den Status jedoch nicht ändern. Z.B. Gebe ein int zurück, das den höchsten Punktestand zeigt.

Und Befehle, die einen neuen Zustand erzeugen, aber einen Wert zurückgeben können. ZB Fügen Sie der Sammlung einen neuen Spieler hinzu und geben Sie eine ID oder was auch immer zurück.

%Vor%

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.

%Vor%

Natürlich wäre es schön, wenn dieses Staatsargument 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.

%Vor%     
Richard Dalton 30.11.2015, 23:39
quelle

2 Antworten

5

Wie Scott erwähnt, ist das Problem, dass Ihr Message<'T> -Typ generisch ist, aber die Art, wie er verwendet wird, beschränkt 'T auf nur einen einzigen Typ innerhalb des Körpers des Agenten.

Allerdings muss der Agent nichts mit dem Wert 'T tun. Es übergibt einfach das Ergebnis der Funktion (in der Nachricht enthalten) an den asynchronen Antwortkanal (der ebenfalls in der Nachricht enthalten ist). Also können wir dies lösen, indem wir den Wert vom Typ 'T vollständig vor dem Agenten verbergen und der Nachricht einen Wert geben, der nur eine Funktion enthält:

%Vor%

Sie könnten sogar nur eine Funktion State -> State verwenden (wobei die Abfrage eine Funktion ist, die immer denselben Zustand zurückgibt), aber ich wollte die ursprüngliche Struktur behalten.

Im Agenten können Sie nun einfach die Funktion aufrufen und für Befehle in den neuen Zustand wechseln:

%Vor%

Das Interessante sind die Mitglieder. Sie sind generisch und verwenden weiterhin PostAndAsyncReply , um einen Wert vom Typ AsyncReplyChannel<'T> zu erstellen. Der Geltungsbereich von 'T kann jedoch auf den Hauptteil der Funktionen beschränkt werden, da sie jetzt Query oder Command -Werte erstellen, die die Antwort direkt an den gerade erstellten Kanal senden:

%Vor%

Tatsächlich ist dies Ihrer ursprünglichen Lösung sehr ähnlich. Wir mussten einfach den gesamten Code, der sich mit 'T -Werten beschäftigt, aus dem Hauptteil des Agenten in die generischen Methoden extrahieren.

BEARBEITEN: Hinzufügen einer Version, die auch für den Status generisch ist:

%Vor%     
Tomas Petricek 01.12.2015, 00:42
quelle
4

Das Problem ist, dass das generische Message<'T> an einen bestimmten Typ ( Player ) gebunden ist, wenn der Typ infinefiziert wird passiert am AddPlayer . Die nachfolgenden Aufrufe erfordern 'T als int , bool etc.

Das heißt, es ist nur generisch, wenn es definiert ist. Ein bestimmtes Modell muss einen bestimmten -Typ haben.

Es gibt ein paar Lösungen, aber keine sehr elegante, denke ich.

Mein bevorzugter Ansatz wäre eine Vereinigung aller möglichen Abfrage- und Befehlsergebnisse, wie unten gezeigt.

%Vor%     
Grundoon 01.12.2015 00:24
quelle

Tags und Links