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