功能构成 - 什么时候?

时间:2014-01-02 16:09:45

标签: f# functional-programming

考虑到以下两种方法,在功能组合方面,两者的缺点和优点是什么?

方法1

let isNameTaken source name =
   source |> Query.Exists(fun z -> z.Name = name)

let usage : Customer = isNameTaken source "Test"

方法2

let isNameTaken f name = 
   f(fun z -> z.Name = name)

let usage : Customer = isNameTaken (source |> Query.Exists) "Test"

方法2 中通过(source |> Query.Exists)是否愚蠢 - 是否太极端?

2 个答案:

答案 0 :(得分:3)

这取决于更广泛的背景。我通常更喜欢第一种方法,除非你有一些非常好的理由使用第二种风格(例如,有许多类似于Query.Exists的函数需要以类似的方式应用)。

除此之外 - 我认为你的第二个例子有几个问题(例如source |> Query.Exists中的管道必须用(fun pred -> source |> Query.Exists pred)替换,这使得它更加丑陋。

即便如此,第二种方法并没有给你带来太多好处 - 你的isNameTaken只是一个测试客户名称是否等于给定名称的函数,然后它将其作为参数传递给某些{{1} - 你可以定义一个测试名称相等性的函数,并写下这样的东西:

f

更一般地说,我认为编写代码总是更可取的,这样调用者就可以编写可用的部分(如let nameEquals name (customer:Customer) = customer.Name = name let usage = source |> Query.Exists (nameEquals "Test") Query.Exists等),而不是以某种方式编写代码。要求调用者填充特定所需形状的某些孔(例如,实现具有指定签名的函数)。

答案 1 :(得分:0)

我认为你的问题的答案与两个主要标准有关。更重要的是,代码的可读性或查询与isNameTaken的分离。在这种特殊情况下,我不确定你是否通过解耦查询得到了很多,而且看起来你的解耦也是不完整的。

我不喜欢的是,在这两种情况下,你都z.NameisNameTaken紧密耦合,这意味着isNameTaken需要了解类型z。如果你没关系那么好。