F# 可选参数和重载替代方案

10

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

在我的 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. 使用 Option 类型:

    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”函数置于类型中,并使用“classic”重载技术。

  5. 将“indexOf”函数置于类型中,并使用F#可选参数。

2个回答

13
如果您将功能定义为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#调用库,这几乎是唯一的选项。


6

我认为选项1(使用柯里化函数)最简单。柯里化函数在函数式编程中非常常见。

在选项2或3中,您仍需要向函数传递附加参数以进行从头开始的搜索

选项4或5需要额外的开销来创建类型。对于这个简单的任务来说有点“杀鸡焉用牛刀”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接