Chr*_*arn 22 f# record discriminated-union
在尝试复杂的例子之前,我试图弄清楚F#的基础知识.我正在学习的材料引入了Discriminate Unions和Record类型.我已经审查了两者的材料,但我仍然不清楚为什么我们会使用一个而不是另一个.
我创建的大多数玩具示例似乎都可以在两者中实现.记录似乎与我认为的C#中的对象非常接近,但我试图避免依赖映射到c#作为理解F#的方法
所以...
是否有明确的理由使用一个而不是另一个?
是否存在适用的某些规范案例?
是否有某些功能可用于一个,而不是另一个?
Rob*_*sen 27
把它想象成一个记录是'和',而一个受歧视的联盟是'或'.这是一个字符串和一个int:
type MyRecord = { myString: string
myInt: int }
Run Code Online (Sandbox Code Playgroud)
虽然这是一个字符串或int的值,但不是两个:
type MyUnion = | Int of int
| Str of string
Run Code Online (Sandbox Code Playgroud)
这个虚构的游戏可以在标题屏幕,游戏中,或显示最终得分,但只有其中一个选项.
type Game =
| Title
| Ingame of Player * Score * Turn
| Endgame of Score
Run Code Online (Sandbox Code Playgroud)
Mis*_*hor 11
使用记录(在函数式编程理论中称为产品类型)来处理由多个属性描述的复杂数据,例如数据库记录或某个模型实体:
type User = { Username : string; IsActive : bool }
type Body = {
Position : Vector2<double<m>>
Mass : double<kg>
Velocity : Vector2<double<m/s>>
}
Run Code Online (Sandbox Code Playgroud)
使用有区别的联合(称为和类型)来表示可以枚举的数据可能值.例如:
type NatNumber =
| One
| Two
| Three
...
type UserStatus =
| Inactive
| Active
| Disabled
type OperationResult<'T> =
| Success of 'T
| Failure of string
Run Code Online (Sandbox Code Playgroud)
请注意,区分联合值的可能值也是互斥的 - 操作的结果可以是Successa或a Failure,但不能同时为两者.
您可以使用记录类型对操作结果进行编码,如下所示:
type OperationResult<'T> = {
HasSucceeded : bool
ResultValue : 'T
ErrorMessage : string
}
Run Code Online (Sandbox Code Playgroud)
但是如果操作失败,那就ResultValue没有意义了.因此,此类型的区分联合版本上的模式匹配将如下所示:
match result with
| Success resultValue -> ...
| Failure errorMessage -> ...
Run Code Online (Sandbox Code Playgroud)
如果你模式匹配我们的操作类型的记录类型版本,它将没有多大意义:
match result with
| { HasSucceeded = true; ResultValue = resultValue; ErrorMessage = _ } -> ...
| { HasSucceeded = false; ErrorMessage = errorMessage; ResultValue = _ } -> ...
Run Code Online (Sandbox Code Playgroud)
它看起来冗长而笨拙,也可能效率低下.我想当你有这种感觉时,这可能暗示你正在使用错误的工具完成任务.
如果您来自C#,您可以将记录理解为具有附加值的密封类:
受歧视的联盟编码替代方案,例如
type Expr =
| Num of int
| Var of int
| Add of Expr * Expr
| Sub of Expr * Expr
Run Code Online (Sandbox Code Playgroud)
杜上述被读出如下:表达式是任一的整数,或者一个变量,或加成两个表达式或两个表达式之间减法.这些情况不可能同时发生.
您需要所有字段来构建记录.您也可以在记录中使用DU,反之亦然
type Name =
{ FirstName : string;
MiddleName : string option;
LastName : string }
Run Code Online (Sandbox Code Playgroud)
上面的示例显示中间名是可选的.
在F#中,您经常使用元组或记录开始建模数据.当需要高级功能时,您可以将它们移动到类.
另一方面,受歧视的工会被用来模拟案件之间的替代和相互排斥关系.