铁路定向编程及部分应用

时间:2019-03-19 10:25:09

标签: f#

当我需要处理IO /解析字符串/ ...时,我喜欢使用ROP。

但是,我们有一个带有2个参数的函数。当您的2个参数已经是Result <'a,'b>(不一定是相同的'a,'b)时,如何清理/读取局部应用程序?

现在,我要做的是使用元组传递参数,并使用下面的函数获取元组的结果,以便随后将函数与该“元组参数”绑定。

/// Transform a tuple of Result in a Result of tuple
let tupleAllResult x =
    match (fst x, snd x) with
    | Result.Ok a, Result.Ok b    -> (a,b) |> Result.Ok
    | Result.Ok a, Result.Error b -> b |> Result.Error
    | Result.Error a, _           -> a |> Result.Error

let f (a: 'T, b: 'U) = // something

(A, B) |> tupleAllResult
       |> (Result.bind f)

有什么好主意吗?

这是我写的,虽然可以,但可能不是最优雅的

let resultFunc (f: Result<('a -> Result<'b, 'c>), 'd>) a =
    match f with
    | Result.Ok g    -> (g a) |> Result.Ok |> Result.flatten
    | Result.Error e -> e |> Result.Error  |> Result.flatten

1 个答案:

答案 0 :(得分:7)

在您的示例中,我没有看到部分应用,这是与currying和参数传递有关的概念-这就是为什么我假设您追随Monadic apply的原因,因为您想要将包装为Result值的函数转换为采用Result并返回另一个Result的函数。

let (.>>.) aR bR = // This is "tupleAllResult" under a different name
    match aR, bR with
    | Ok a, Ok b -> Ok(a, b)
    | Error e, _ | _, Error e -> Error e
// val ( .>>. ) : aR:Result<'a,'b> -> bR:Result<'c,'b> -> Result<('a * 'c),'b>

let (<*>) fR xR = // This is another name for "apply"
    (fR .>>. xR) |> Result.map (fun (f, x) -> f x)
// val ( <*> ) : fR:Result<('a -> 'b),'c> -> xR:Result<'a,'c> -> Result<'b,'c>

与您所遇到的问题的区别是map,而不是最后一行的bind

现在,您可以开始在Result世界中使用lift函数了:

let lift2 f xR yR =
    Ok f <*> xR <*> yR
// val lift2 :
//   f:('a -> 'b -> 'c) -> xR:Result<'a,'d> -> yR:Result<'b,'d> -> Result<'c,'d>

let res : Result<_,unit> = lift2 (+) (Ok 1) (Ok 2) 
// val res : Result<int,unit> = Ok 3