Ich kämpfe mit einem Designproblem in Haskell, das ich nicht elegant und befriedigend lösen kann. Ich habe ein System, das im Kern auf dem Konzept der Ereignisbeschaffung basiert: Der Zustand des Systems ergibt sich aus der Anwendung einer Sequenz von Ereignissen auf einen Anfangszustand. Es gibt verschiedene Arten von Ereignissen, wobei jeder Typ durch eine Typenfamilie mit einer bestimmten Komponente des Systems verbunden ist:
%Vor% Gegenwärtig ist das System zu 100% synchron und gekoppelt, wobei jedes Modell Zugriff auf alle Ereignisse des anderen Modells hat und dies wird schnell zu einem Durcheinander, so dass ich die Dinge durch die Einführung eines Ereignisbusses entkoppeln möchte Bus Events
so sollte ich etwas schreiben können wie
dispatch :: Bus Events -> Consumer (Event Foo) -> Bus Events
, um einen Konsumenten von Event Foo
an eine Bus Events
anzuhängen, vorausgesetzt, es gibt eine Form der Subtypisierung oder Subsumtion zwischen Event Foo
und Events
.
Dann kann ich Asynchronität hinzufügen, indem ich sicherstelle, dass die Benutzer in ihren eigenen Threads laufen.
Aus der Sicht des Systems würde ich dadurch sicherstellen, dass jede Komponente unabhängig verpackt werden kann, was die Abhängigkeiten auf eine Teilmenge aller Ereignisse einschränkt. Events
type würde auf der gesamten Anwendungsebene definiert werden.
Dieses Problem sieht täuschend ähnlich dem zeitdiskreten FRP aus, aber ich kann nicht in der Lage sein, meinen Kopf darum zu wickeln ...
Hat sich schon jemand mit etwas Ähnlichem beschäftigt und wenn ja, wie?
BEARBEITEN :
Ich habe den folgenden Code entwickelt, der Source
nicht verwendet, aber stark von @ Cirdecs Vorschlag inspiriert ist:
Eine Quelle von Ereignissen, die a
s trägt, die abonniert werden kann, hat den folgenden Typ:
Ein Consumer oder Handler von Ereignissen ist naiv etwas, das eine Ereignisquelle akzeptiert und abonniert.
%Vor%Dies ist ein wenig verschachtelt, wir können Dinge invertieren und eine schönere Darstellung für einen Event-Handler bekommen:
%Vor% Die ursprüngliche Ereignisquelle war ein wenig schwierig zu verwenden; Ein Abonnent möchte sich möglicherweise als Reaktion auf ein Ereignis abmelden. In diesem Fall müssen die Benutzer die resultierende Abmeldungsaktion rekursiv aufrufen, um festzulegen, was bei einem Ereignis zu tun ist. Beginnend mit der schöneren Definition von Handler
haben wir dieses Problem nicht. Eine Ereignisquelle akzeptiert jetzt einen Ereignishandler und veröffentlicht ihn.
Tags und Links haskell types event-sourcing