函数签名'a -> 'b -> ('a -> 'b -> 'c) -> 'c是否为标准函数式概念?
关于F#管道中传递两个参数的函数优化
首先,你的apply2函数完全满足需求,逻辑上一点问题都没有——它本质是把两个参数先部分应用好,再接收一个二元函数并执行调用,完美适配你在管道链里的场景:把myFun柯里化后得到的TypeA -> TypeB -> ResultType函数,通过管道传给apply2 valueA valueB,最终完成参数传递并算出结果。
不过如果你觉得自己单独定义函数有点冗余,其实有几种更简洁的替代方式:
1. 直接用匿名函数替代
不需要额外定义apply2,直接在管道里写匿名函数,语义同样清晰:
let useCase someValue (valueA: TypeA) (valueB: TypeB) = someValue |> ... |> toMyType |> myFun |> fun f -> f valueA valueB
这种写法和你的apply2完全等价,省去了单独定义函数的步骤,临时用的话很省心。
2. 定义贴合管道的自定义操作符
如果这种场景在代码里出现得比较频繁,可以定义一个自定义操作符,让管道链看起来更连贯自然:
// 定义操作符:接收函数和两个参数,执行调用 let ( <||> ) f x y = f x y // 使用时的写法 let useCase someValue (valueA: TypeA) (valueB: TypeB) = someValue |> ... |> toMyType |> myFun <||> valueA <||> valueB
或者调整操作符的参数顺序,让它更适配管道左到右的流畅性:
// 操作符先接收两个参数,再接收函数并执行 let ( <**> ) (x, y) f = f x y // 使用时的写法 let useCase someValue (valueA: TypeA) (valueB: TypeB) = someValue |> ... |> toMyType |> myFun |> (valueA, valueB) <**>
3. 利用F#的部分应用特性调整管道顺序
你也可以换一种思路,直接把valueA和valueB部分应用到myFun上,不过需要用到反向管道操作符(<|):
let useCase someValue (valueA: TypeA) (valueB: TypeB) = myFun <| (someValue |> ... |> toMyType) <| valueA <| valueB
不过这种写法会打破原有的左到右管道流,可读性不如前两种,适合场景比较特殊的时候用。
总的来说,你的apply2是完全合理的实现,如果只是偶尔用到,匿名函数是最省事的替代;如果频繁出现,自定义操作符能让代码更易读。
内容的提问来源于stack exchange,提问作者cmeeren
相关产品推荐
相关产品推荐

