F#可选参数和重载替代

Mac*_*iak 5 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
Run Code Online (Sandbox Code Playgroud)

我不喜欢这样的事实,当我想从头开始搜索时,我必须将冗余0作为起始索引.

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

  1. 创建两个版本:

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

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

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

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

Tom*_*cek 8

如果将功能定义为F#函数,那么我认为使用两个单独的函数(具有合理的描述性名称)可能是最好的选择。因此,我会选择您的第一个选项(我绝对更喜欢此选项,而不是仅出于此单个目的而定义歧视联盟):

let indexOfFrom (str:string) (value:string) startIndex = (...)
let indexOf str value = indexOfFrom str value 0
Run Code Online (Sandbox Code Playgroud)

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

type String =
  static member IndexOf(str:string, value:string, startIndex) = (...)
  static member IndexOf(str, value) = String.IndexOf(str, value, 0)
Run Code Online (Sandbox Code Playgroud)

或者,使用可选参数:

type String =
  static member IndexOf(str:string, value:string, ?startIndex) = (...)
Run Code Online (Sandbox Code Playgroud)

哪个选项是最好的?

  • 如果您正在设计功能性API(例如,特定领域的语言),那么带有两个独立功能的选项可能是最佳选择。

  • 如果您打算设计一个不错的F#API,那么我认为您的选项(多个函数)或可选参数是相当合理的。函数在Deedle使用率很高F#图表依赖于可选参数。

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


Pet*_*etr 6

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

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

选项4或5需要额外的开销来创建类型.对于这个简单的任务来说,这有点过分了