我正在使用一个将结果作为双轨值(成功和失败)的库。在 Observable.map
中函数体 我经常从函数的成功跟踪中得到可观察的结果,但我不知道如何处理它们(在 Observable.map
body 处)。
换句话说,我经常陷入结果如下所示的情况(当然这是最简单的):
Rop.Result<IObservable<Rop.Result<IObservable,Messages>,Messages>
一方面,将消息转换回异常并引发它们似乎对我来说很重要,另一方面,错误处理程序是不纯的函数,我宁愿不传递它们。
我想知道什么是标准且干净的解决方案来处理 Observable.map
处双轨结果的失败 body 。
更新:示例
这是有史以来最简单的问题示例:
module problem
open FSharp.Control.Reactive
type Person = {FirstName:string;LastName:string}
let getPersonByLastName lastName =
let persons = Observable.toObservable<|seq{
yield {FirstName="Jhone";LastName="Smith"}
yield {FirstName="Joe";LastName="Smith"}
yield {FirstName="Jack";LastName="Smith"}
}
Rop.succeed persons
let main =
let final =
Observable.single("Smith")
|>Observable.map(fun lastName ->
let personResults = getPersonByLastName lastName
personResults
)
0
在此示例中 final
表达式结果的类型为IObservable<Result<IObservable<Person>,ErrorMessage list>>
但我希望它是 IObservable<Person>
,因为进一步Observable
转换最终会得到非常肮脏和复杂的表达式。
最佳答案
在最简单的层面上,您需要的是一种提取并显示 IObservable
的方法。包裹在 RopResult
中。解决方案的一部分已经在评论中提到( Observable.bind
),另一部分是函数 RopResult<IObservable<'a>, 'b> -> IObservable<RopResult<'a,'b>>
。
为此,您需要解构 RopResult
并处理这两种情况。因此,将其放在您所说的问题的背景下:
Observable.single("Smith")
|>Observable.bind(fun lastName ->
match getPersonByLastName lastName with
| Rop.RopResult.Success (next, msgs) ->
next |> Observable.map (fun x -> Rop.RopResult.Success (x, msgs))
| Rop.RopResult.Failure msgs ->
Observable.result <| Rop.RopResult.Failure msgs)
这是好的代码吗?我不这么认为。您可以通过使用其他 ROP api 函数,或者通过在此处使用绑定(bind)主体的计算表达式来使其稍微好一些,但这不是重点。
使用 Observables 的响应式(Reactive)编程和“面向铁路的编程”都是有用的工具,只要它们能够捕获和抽象出您正在建模的任何计算中涉及的一些复杂元素。这是可行的,因为它们是建立在可以很好地组合在一起的基元之上的。当您尝试像这样“交织”两者时,您会失去一些,因为您必须自己管理该构图。
我会说you're better off using exceptions这里 - 特别是因为 Observables 对它们有内置的支持。
关于f# - 将面向铁路的故障跟踪转换为 Rx 友好错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49956854/