Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 何时在F中使用区分并集与记录类型#_F#_Record_Discriminated Union - Fatal编程技术网

F# 何时在F中使用区分并集与记录类型#

F# 何时在F中使用区分并集与记录类型#,f#,record,discriminated-union,F#,Record,Discriminated Union,在开始复杂的例子之前,我试图弄清楚F#的基本知识。我正在学习的材料介绍了区分工会和记录类型。我已经审查了这两种材料,但我仍然不清楚为什么我们会使用其中一种 我创建的大多数玩具示例似乎都可以在这两个方面实现。记录似乎与我认为的C#中的对象非常接近,但我试图避免依赖映射到C#来理解F# 所以 是否有明确的理由使用其中一个而不是另一个 是否存在某些适用的规范案例 是否有某些功能在一个系统中可用,但在另一个系统中不可用 其他的 将其视为记录为“和”,而受歧视的工会则是“或”。 这是一个字符串和一个in

在开始复杂的例子之前,我试图弄清楚F#的基本知识。我正在学习的材料介绍了区分工会和记录类型。我已经审查了这两种材料,但我仍然不清楚为什么我们会使用其中一种

我创建的大多数玩具示例似乎都可以在这两个方面实现。记录似乎与我认为的C#中的对象非常接近,但我试图避免依赖映射到C#来理解F#

所以

  • 是否有明确的理由使用其中一个而不是另一个

  • 是否存在某些适用的规范案例

  • 是否有某些功能在一个系统中可用,但在另一个系统中不可用 其他的


将其视为记录为“和”,而受歧视的工会则是“或”。 这是一个字符串和一个int:

type MyRecord = { myString: string
                  myInt: int }
虽然这是一个字符串或int值,但不是两者都是:

type MyUnion = | Int of int
               | Str of string
这个虚构的游戏可以在标题屏幕、游戏中或显示最终分数,但只能显示其中一个选项

type Game =
  | Title
  | Ingame of Player * Score * Turn
  | Endgame of Score
如果您来自C#,您可以将记录理解为具有附加值的密封类:

  • 默认情况下是不可变的
  • 默认结构平等
  • 易于模式匹配
  • 等等
受歧视的工会对备选方案进行编码,例如

上面的DU如下所示:表达式可以是整数,也可以是变量,或者是两个表达式的加法,或者是两个表达式之间的减法。这些案件不可能同时发生

您需要所有字段来构造记录。您还可以在记录中使用DU,反之亦然

type Name =
    { FirstName : string;
      MiddleName : string option;
      LastName : string }
上面的示例显示中间名是可选的

在F#中,您通常开始使用元组或记录对数据进行建模。当需要高级功能时,可以将它们移动到类中

另一方面,有区别的并集用于为备选方案和案例之间的互斥关系建模。

使用记录(在函数编程理论中称为产品类型)处理由多个属性描述的复杂数据,如数据库记录或某个模型实体:

type User = { Username : string; IsActive : bool }

type Body = { 
    Position : Vector2<double<m>>
    Mass : double<kg>
    Velocity : Vector2<double<m/s>> 
}
但在操作失败的情况下,
ResultValue
没有意义。因此,这种类型的受歧视联合版本上的模式匹配如下所示:

type OperationResult<'T> = { 
    HasSucceeded : bool
    ResultValue : 'T
    ErrorMessage : string
}
match result with
| Success resultValue -> ...
| Failure errorMessage -> ...
如果您的模式与我们的操作类型的记录类型版本相匹配,那么就没有什么意义了:

match result with
| { HasSucceeded = true; ResultValue = resultValue; ErrorMessage = _ } -> ...
| { HasSucceeded = false; ErrorMessage = errorMessage; ResultValue = _ } -> ...
它看起来冗长而笨拙,效率也可能更低。我认为当你有这样的感觉时,这可能暗示你在使用错误的工具来完成任务。

理解DU的一种(有点缺陷)方法是将其视为一个花哨的C#“并集”,而记录更像是一个普通的对象(有多个独立的字段)


看待DU的另一种方式是将DU看作两级类层次结构,其中顶层DU类型是抽象基类,DU的实例是子类。这个视图实际上接近实际的.NET实现,尽管编译器隐藏了这个细节。

这个页面的末尾有一个简短的段落。那么,在DU中有没有办法创建一个扩展游戏的组合类型?例如| InGameTitle of Title*Ingame。i、 e.包含标题*玩家*分数*的元组Turn@Chris:这只会引出一个问题:你为什么要这样做?@ildjarn你说得很对。当我第一次写这篇评论时,我并没有完全理解DUs的目的。塔珀先生的回答帮助我理解了为什么你会像罗伯特那样使用它,而不是像我概述的那样。谢谢。这个答案和另一个答案都指向DU是一种OR关系的事实。但正如我们所理解的,一个DU可以包含多个值。i、 e.
类型名称
可以有
FirstName、MiddleName和LastName的值
。这仍然让我有点不确定,所有字段都有值的记录和所有字段都有值的DU之间有什么区别。是DU可以进行某种形式的推理或操作,而记录则不能?或者不可变属性就是这里的区别?谢谢你的回答。现在我明白了DU的特殊意义。OO继承层次结构的一个重要区别是DU的不同情况只是标记,而不是不同的(子)类型。这有时会让新来者感到困惑。
match result with
| Success resultValue -> ...
| Failure errorMessage -> ...
match result with
| { HasSucceeded = true; ResultValue = resultValue; ErrorMessage = _ } -> ...
| { HasSucceeded = false; ErrorMessage = errorMessage; ResultValue = _ } -> ...