簡體   English   中英

如何累積可觀察物

[英]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始終使用原始傳遞給accumulatet調用。 原始的t應該是初始值,應該作為第二個參數的一部分傳遞給scan

f:'t -> 'a -> 't * 'u option產生的元組的第一部分是累加值。 因此,該部分需要返回以進行scan ,以使其再次傳遞給f並不斷積累。

在你的問題的要求是積累並傳遞一個事件時,元組的第二部分是Some 'u 因此,問題是如何同時做這兩項:累加't和過濾'u

答案是通過將累積值與f所做Some 'u相結合。 所以,你需要保持元組的scan狀態,然后后來只保留使用第二部分choosesnd

這是您要尋找的:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM