问题
I have a number of events that are merged into one observable that executes some commands. If a command succeeded some result takes place. In addition, the command should be logged.
In terms of code, this looks like
let mevts = modifyingevents |> Observable.filter exec_action
|> Observable.add (fun action -> self.OutlineEdited <- true)
where the function exec_action
results in some side effect such as editing a treeview. If this succeeded then the property OutlineEdited
is set to true
.
I was hoping to follow this with something like
mevts |> Observable.scan (fun log action -> action::log) []
but it turns out that Observable.filter is executed once for each subscribed observer. Meaning that the side effect will be repeated.
Can you please suggest another way to achieve the same result without having the exec_action
executed twice? I am hoping to avoid having to use a mutable variable if possible.
回答1:
This example ilustrates nicely the difference between the IObservable<'T>
type (used in this example via the Observable
module) and the F# type IEvent<'T>
(and functions in Event
module).
When you use observables, every subscriber creates a new chain of operations (so side-effects are executed once for every subscriber). If you use events then the state is shared and side-effects are executed just once (regardless of the number of subscribers). On the other hand, the events do not get garbage collected when you remove all subscribers from an event.
So, if you do not need the events to be removed when all subscribers are removed, you should get the behaviour you want just by using Event
instead of Observable
:
modifyingevents
|> Event.filter exec_action
|> Event.scan (fun log action -> action::log) []
来源:https://stackoverflow.com/questions/12874689/f-observable-filter-with-side-effect