【问题标题】:Railway Oriented Programming and partial application面向铁路的编程和部分应用
【发布时间】:2019-03-20 00:50:16
【问题描述】:

当我必须处理 IO/解析字符串/...时,我喜欢使用 ROP...

但是,假设我有一个带有 2 个参数的函数。当您的 2 个参数已经是 Result (不需要相同的 '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

【问题讨论】:

    标签: f#


    【解决方案1】:

    我没有在您的示例中看到 部分应用程序,这是一个与柯里化和参数传递相关的概念 - 这就是为什么我假设您在单子 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

    现在您可以开始将lift 函数引入Result 世界:

    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
    

    【讨论】:

    • 谢谢!确实我很困惑,现在更清楚了
    猜你喜欢
    • 2019-10-08
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    • 2016-06-26
    • 2016-07-31
    • 2023-02-12
    • 2010-09-18
    • 2010-09-08
    相关资源
    最近更新 更多