F#可选参数和重载替代

时间:2014-11-15 23:07:37

标签: f# functional-programming

在我的F#应用程序中,我经常需要对字符串中的字符串执行不区分大小写的搜索,因此我使用适当的比较创建了一个函数:

let indexOf (str:string) (value:string) startIndex =
    match str.IndexOf(value, startIndex, StringComparison.OrdinalIgnoreCase) with
    | index when index >= 0 -> Some index
    | _ -> None

我不喜欢这样一个事实:当我想从头开始搜索时,我必须将冗余0作为起始索引传递。

我对F#和函数式编程都比较陌生,所以我想知道从功能的角度来看什么是首选的(最干净的)解决方案?

  1. 创建两个版本:

    let indexOfFrom (str:string) (value:string) startIndex = (...)
    let indexOf str value = indexOfFrom str value 0
    
  2. 使用选项类型:

    let foundIndex = indexOf "bar foobar" "bar" (Some 4)
    
  3. 创建一个专门的歧视联盟:

    type Position =
        | Beginning
        | StartIndex of index : int
    let foundIndex = indexOf "bar foobar" "bar" (Index 4)
    
  4. 将'indexOf'函数放在一个类型中并使用'经典'重载。

  5. 将'indexOf'函数放在一个类型中并使用F#可选参数。

2 个答案:

答案 0 :(得分:7)

如果您将功能定义为F#函数,那么我认为使用两个单独的函数(具有合理描述性的名称)可能是您拥有的最佳选择。所以我选择了你的第一个选项(我绝对更喜欢这个选项而不仅仅是为了这个目的而定义一个有区别的联盟):

let indexOfFrom (str:string) (value:string) startIndex = (...)
let indexOf str value = indexOfFrom str value 0

另一种方法是将功能定义为类型的成员 - 然后您可以使用重载和F#可选参数,但是您必须使用全名String.IndexOf来访问它们。你可以这样写:

type String =
  static member IndexOf(str:string, value:string, startIndex) = (...)
  static member IndexOf(str, value) = String.IndexOf(str, value, 0)

或者,使用可选参数:

type String =
  static member IndexOf(str:string, value:string, ?startIndex) = (...)

哪个选项最好?

  • 如果您正在设计功能API(例如特定于域的语言),那么您选择使用两个单独的功能可能是最佳选择。

  • 如果您的目标是设计一个不错的F#API,那么我认为您的选项(多个函数)或可选参数是非常合理的。函数在Deedle中使用得相当多,而F# Charting依赖于可选参数。

  • 使用重载的好处是库也可以很好地从C#中使用。所以,如果您考虑从C#调用库,这几乎是唯一的选择。

答案 1 :(得分:6)

我认为选项1(带有curried函数)最简单。 Curried函数在函数式编程中非常常见。

在选项2或3中,您仍然需要从头开始将附加参数传递给搜索功能

选项4或5需要额外的开销来创建类型。它有点过分'这个简单的任务