14

我已经知道F# Choice类型有一段时间了,但想不出我会在任何地方使用它,而不是用有意义的命名案例定义我自己的联合类型。

MSDN 文档没有提供太多建议(“具有两种选择的活动模式的帮助器类型。”)并且没有任何示例用法。

我一定遗漏了一些东西 - 这种类型与关税同盟相比的主要优势是什么?

4

4 回答 4

9

在我看来,该Choice类型的用例与元组类型的用例非常相似。在任何一种情况下,您通常都希望定义自己的更具体的类型,该类型与类型同构(用于选择的自定义 DU;用于元组的自定义记录类型)。尽管如此,在有限的范围内或在非常通用的情况下(良好的命名可能变得困难),拥有匿名变体是很好的。

于 2013-05-23T15:05:11.687 回答
4

当然,更具体的联合类型对于特定情况可能会很好,但是拥有通用的选择联合意味着您的代码可以在使用通用结构(例如工作流、函子等)时与其他代码很好地融合。

IIRC 标准 FSharp Core 库中没有 Either Monad(F# 术语中的工作流)的实现,但 FSharpx 库中有一个实现(虽然我找不到它的构造函数,所以我不得不自己动手感谢@MauricioScheffer 指点我choose)。

从我有限的(主要是 C# 互操作、F# 经验)来看,Choice 和 Option 并没有像 Haskell 的 Maybe 和 Either 代数数据类型被纳入其标准库一样多地融入 F# 的标准方法中,因此您不会获得那么多“这很有用”在 F# 中使用它们时就像在 Haskell 中一样,但它们非常有用。

举个例子:在我最近编写的一个应用程序中,当我有一个成功的结果时,我从方法中返回了 Choice1Of2,当出现问题时,Choice2Of2 带有错误消息——无论是捕获异常还是未满足先决条件——然后运行我的用于流程控制的工作流中的代码。这是这种联合类型的一种标准用法。

于 2013-05-23T16:20:25.240 回答
3

最好的例子是Async.Catch你要么返回结果要么返回异常,这两者都是有意义的。

话虽如此,Choice在 F# 代码中的使用相对有限,大多数时候人们使用 DU。但是,Choice当您懒得定义 DU 时,可能会使用 a。

Choice与 C# 交互时也可能有更好的行为

于 2013-05-23T10:51:13.887 回答
2

在尝试通过专用函数和 Active Patterns 强制创建可区分的联合值时,我观察到了它的价值。

这是发布的示例:

module File1 =

    type EmailAddress = 
        private
        | Valid   of string 
        | Invalid of string

    let createEmailAddress (address:System.String) =
        if address.Length > 0
        then Valid    address 
        else Invalid  address

    // Exposed patterns go here
    let (|Valid|Invalid|) (input : EmailAddress) : Choice<string, string>  = 
        match input with
        |Valid str -> Valid str
        |Invalid str -> Valid str

module File2 =

    open File1

    let validEmail = Valid "" // Compiler error

    let isValid = createEmailAddress "" // works

    let result = // also works
        match isValid with
        | Valid x -> true
        | _       -> false
于 2017-02-14T16:30:43.790 回答