[英]How to Accumulate Observables
我應該定義一個函數,該函數將返回IObservable <'u>
accumulate : ('t -> 'a -> 't * 'u option) -> 't -> IObservable<'a> -> IObservable<'u>
因此,我的函數ft obs'將obs的可觀察事件累積到類型為't的累加器中,並在'snd(f acc a)'對觀察到的事件'a'求值為'Some u'時發出可觀察的事件u。
到目前為止,我已經實現了以下功能:
let accumulate (f:'t -> 'a -> 't * 'u option) t obs =
Observable.scan (fun _ x -> snd (f t x)) None obs
我真的不明白這種可觀察的掃描方式是如何工作的,在這種情況下,我的函數返回IObservable <'u選項>。 我該如何解決? 我在正確的軌道上嗎?
功能fun _ x -> snd (ftx)
不完整。 提示是第一個參數_
被忽略,結果元組的第一部分被snd
的調用丟棄。
沒有累積,因為ftx
始終使用原始傳遞給accumulate
值t
調用。 原始的t
應該是初始值,應該作為第二個參數的一部分傳遞給scan
。
由f:'t -> 'a -> 't * 'u option
產生的元組的第一部分是累加值。 因此,該部分需要返回以進行scan
,以使其再次傳遞給f
並不斷積累。
在你的問題的要求是積累並傳遞一個事件時,元組的第二部分是Some 'u
因此,問題是如何同時做這兩項:累加't
和過濾'u
?
答案是通過將累積值與f
所做Some 'u
相結合。 所以,你需要保持元組的scan
狀態,然后后來只保留使用第二部分choose
和snd
。
這是您要尋找的:
let accumulate (f:'t -> 'a -> 't * 'u option) t obs =
obs
|> Observable.scan (fun (acc, _) x -> f acc x) (t, None)
|> Observable.choose snd
scan
scan
是通過將變化的狀態與一系列值一起傳遞給函數來承載變化的狀態的函數。 特別是,它可以用於累加值,例如int
運行總計:
let keepTotal obs =
obs
|> Observable.scan (fun total v -> total + v) 0
這等效於命令式代碼中的total
可變:
let mutable total = 0
let keepTotal2 obs =
obs
|> Observable.map (fun v ->
total <- total + v
total
)
請注意,這兩個版本具有相同的元素:
0
total + v
當然,即使使用map
,第二個版本也是不好的功能代碼,因為它使用了一個外部可變變量,這是一個很大的NO NO。
您原來的問題可以用相同的方法解決:
let accumulate2 (f:'t -> 'a -> 't * 'u option) t obs =
let mutable acc = t
obs
|> Observable.choose (fun x ->
let acc2, uOp = f acc x
acc <- acc2
uOp
)
即使此變量使用的可變變量在函數式編程中也是很丑陋的(並且是不必要的),但在功能上還可以,因為變量acc
是內部變量,而accumulate2
之外的代碼都看不到它。 雖然仍然丑陋。
你可以鏈中的Observable.choose
后您的Observable.scan
以獲得正確的類型簽名
let accumulate (f:'t -> 'a -> 't * 'u option) t obs =
obs
|> Observable.scan (fun _ x -> snd (f t x)) None
|> Observable.choose id
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.