【问题标题】:Function composition - when?功能组合 - 什么时候?
【发布时间】:2014-01-02 16:09:44
【问题描述】:

鉴于以下两种方法,在功能组合方面,两者的优缺点是什么?

方法 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) 是不是很傻 - 是不是太极端了?

【问题讨论】:

    标签: f# functional-programming


    【解决方案1】:

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

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

    即便如此,第二种方法并没有真正给您带来太多好处 - 您的 isNameTaken 只是一个测试客户名称是否等于给定名称的函数,然后将其作为参数传递给某些 f - 您可以只定义一个测试名称相等性的函数并编写如下内容:

    let nameEquals name (customer:Customer) = 
      customer.Name = name
    
    let usage = source |> Query.Exists (nameEquals "Test")
    

    更一般地说,我认为编写代码总是更可取,以便调用者可以编写可供他们使用的部分(如Query.ExistsnameEquals 等),而不是以要求调用者的方式填充一些特定形状的孔(例如,实现具有指定签名的函数)。

    【讨论】:

    • 如果有很多地方要检查姓名是否被占用怎么办? - 你会每次都写let usage = source |> Query.Exists (nameEquals "Test")吗?
    • @ebb 如果有很多地方需要检查姓名是否被占用,那么我会采用您的第一种方法。如果您需要检查与名称相等性相关的不同属性,那么我会使用我的示例。
    • 所以简而言之,您宁愿使用 Query.Exists (nameEquals "Test") 而不是 Query.Exists(fun z -> z = "Test") ? - 为什么?因为它更短,还是我误解了“属性”?
    【解决方案2】:

    我认为您的问题的答案与两个主要标准有关。哪个更重要,代码的可读性或查询与isNameTaken的解耦。在这种特殊情况下,我不确定您是否从解耦查询中得到了很多,而且您的解耦似乎也是部分的。

    对此我不喜欢的是,在这两种情况下,z.Name 都与isNameTaken 紧密耦合,这意味着isNameTaken 需要知道z 的类型。如果你没问题,那很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-06
      • 2010-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多