是否有将一系列管道转换为功能组合的分步过程?

时间:2016-07-21 12:56:47

标签: f# functional-programming

是否有将多个管道转换为功能组合的分步过程?

旁注: 我是否甚至使用了术语"功能组合"在正确的背景下?

我有以下代码:

let purchase qty inventory =
    buyFrom inventory qty |> fromInventory
                          |> reduceBy qty

我想重构此代码以支持功能组合。

所以我认为我可以这样做:

let purchase qty inventory =
    buyFrom inventory >> fromInventory >> reduceBy qty

此代码编译。但是,当试图在调试器中调用购买函数时,我似乎错过了一个参数。

以下是我对该功能的测试:

[<Test>]
let ``buy last product``() =
    [SomeProduct] |> purchase 1
                  |> should equal []

注意:

我仍在努力解决FP基础问题,但仍然不了解将管道工作流程转换为功能组合的过程。

我想我明白功能组合依赖于部分应用程序,我认为我现在已经处理好了。因此,我有理由相信我的重构函数缺少一个参数。

有关工作流程的任何指导我可以用来更好地进行功能组合吗?

附录

type Product =
    | SomeProduct

type TransactionResult = { Price:decimal; Inventory:Product list }

(* Functions *)

let priceOf qty product =
    match product with
    | SomeProduct -> match qty with
                     | 3 -> decimal (qty - 1) * 1.99m
                     | _ -> decimal (qty) * 1.99m

let rec reduceBy count list =
    match list with
    | first::remaining when count = 1         -> remaining
    | first::second::remaining when count > 1 -> second::remaining |> reduceBy (count - 1)
    | remaining when count = 0                -> remaining
    | _ -> []

let buyFrom inventory qty =
    { Price=priceOf qty (List.head inventory); Inventory=inventory }

let fromInventory transactionResult =
    transactionResult.Inventory

2 个答案:

答案 0 :(得分:7)

直接翻译成合成形式可以是:

使用“前进”功能组合:

let purchase qty inventory = (buyFrom inventory >> fromInventory >> reduceBy qty) qty

使用“向后”功能组合(就我个人而言,我不确定我喜欢“向后”一词,因为这是传统数学意义上的功能组合,即f << g = f ∘ g):

let purchase' qty inventory = reduceBy qty << fromInventory << buyFrom inventory <| qty

正如您可以从上面的示例中看到的那样,当它让您完全跳过最后一个参数时,它确实是最有价值的。在这个例子中,你不能这样做,因为你依赖qty两次,所以我建议你坚持使用管道。

通常,如果您有一个函数f(x)和一个函数g(x),您可以通过以下方式编写一个函数h(x) = (f ∘ g)(x)

let h x = f (g (x))
let h x = x |> g |> f
let h x = f << g <| x
let h x = (g >> f) x

在后两种情况下,使用函数组合,您可以完全省略x

let h = f << g
let h = g >> f

答案 1 :(得分:6)

通常情况下,如果你可以按下你的管道表达式来获得表格

let f x y value = value |> f1 x |> f2 y |> f3

你可以将它重构为

let f x y = f1 x >> f2 y >> f3

这不是这里的情况,因为你的表达式以函数调用(buyFrom inventory qty)开头,然后将其值传送到fromInventory

在这种情况下,我认为你可以重构

let purchase' inventory qty =
    qty |> buyFrom inventory |> fromInventory |> reduceBy qty

但是你不能再进一步了,因为qty也需要reduceBy作为qty的参数。

认为你可以通过使用Reader或State monad来消除{{1}}的两次出现,但它几乎不值得努力。