考虑到以下两种方法,在功能组合方面,两者的缺点和优点是什么?
方法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)
是否愚蠢 - 是否太极端?
答案 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.Name
与isNameTaken
紧密耦合,这意味着isNameTaken
需要了解类型z
。如果你没关系那么好。