从 C# 中为 F# 中的约会从概念上创建一个有区别的联合
Conceptually creating a discriminated union for an appointment in F# from C#
客气点,我是 F# 的新手(来自 C#)。在查看我的约会簿的用户控件时,我发现它是建立在 class 概念之上的,即用于填充数据网格的“访问”概念。我想使用 F# 描述联合来替换 C# 访问 class,但无法正确使用。看多了,我的C#思路好像也断不了。
从概念上讲,“访问”将始终具有“约会时间”,而不管它是否具有名称或其他任何内容。现在从这一点来看,访问可以是几个不同的东西(使用区分联合的原因):
- 如果访问只有姓名和发布时间,那么它只是一个约会。
- 如果拜访只有预约时间、服务时间和姓名,那么这个人是没有预约的,是“走访”,
- 如果访问有姓名、约会时间、发布时间和服务时间,那么这是一个见过该人的约会 -- "a keep appointment",
- 如果访问只有预约时间而没有姓名或其他任何内容,则可以使用--“一个开放的时间段”。
在 C# 中,这是一个简单的 class:
public class Visit
{
DateTime? tservice {get; set;}
DateTime? tappointment {get; set;}
DateTime? tposted {get; set; }
string lastname {get; set; }
string firstname {get; set; }
DateTime birthdate {get; set; }
}
如何在 F# 中将其概念性地写成可区分联合?我将如何使用 match...with 呢?
非常感谢任何帮助或指导。
Here's 如何在 F# 中将其建模为联合的示例。
基本思路是您描述了每个案例,而我刚刚翻译了您口述的每个案例。每个案例都只有允许的数据,因此没有可以填写或不填写的可空值。最重要的是,我定义了一个可以从任何形式的 DU 访问的助手成员,以便通常检索-使用过的数据(就像我想象的那个人的名字一样)。
希望对您有所帮助!
该解决方案与 ChesterHusk 的解决方案类似,但存在一些差异:
- 由于
appointmentTime
始终存在,我认为将它移到 DU 之外是有意义的。因此,Visit
是由visitType
和appointmentTime
组成的记录。
- 在
this.Name
中,我们使用名为 DU 的功能,它允许我们只捕获必需的字段。这种形式更好,因为它不随顺序或字段数变化。
open System
type VisitType =
| AppointmentOnly of name: string * postedTime: DateTime
| WalkIn of name: string * serviceTime: DateTime
| Kept of name: string * postedTime: DateTime * serviceTime: DateTime
| Open
type Visit =
{ appointmentTime: DateTime
visitType: VisitType }
with
member this.Name =
match this.visitType with
| AppointmentOnly(name=name) | WalkIn(name=name) | Kept(name=name) -> Some name
| Open -> None
let visit = { appointmentTime = DateTime.Now
visitType = WalkIn(name="cool_name", serviceTime=DateTime.Now) }
printfn "%A" visit.Name
printfn "%A" visit.appointmentTime
客气点,我是 F# 的新手(来自 C#)。在查看我的约会簿的用户控件时,我发现它是建立在 class 概念之上的,即用于填充数据网格的“访问”概念。我想使用 F# 描述联合来替换 C# 访问 class,但无法正确使用。看多了,我的C#思路好像也断不了。
从概念上讲,“访问”将始终具有“约会时间”,而不管它是否具有名称或其他任何内容。现在从这一点来看,访问可以是几个不同的东西(使用区分联合的原因):
- 如果访问只有姓名和发布时间,那么它只是一个约会。
- 如果拜访只有预约时间、服务时间和姓名,那么这个人是没有预约的,是“走访”,
- 如果访问有姓名、约会时间、发布时间和服务时间,那么这是一个见过该人的约会 -- "a keep appointment",
- 如果访问只有预约时间而没有姓名或其他任何内容,则可以使用--“一个开放的时间段”。
在 C# 中,这是一个简单的 class:
public class Visit
{
DateTime? tservice {get; set;}
DateTime? tappointment {get; set;}
DateTime? tposted {get; set; }
string lastname {get; set; }
string firstname {get; set; }
DateTime birthdate {get; set; }
}
如何在 F# 中将其概念性地写成可区分联合?我将如何使用 match...with 呢?
非常感谢任何帮助或指导。
Here's 如何在 F# 中将其建模为联合的示例。
基本思路是您描述了每个案例,而我刚刚翻译了您口述的每个案例。每个案例都只有允许的数据,因此没有可以填写或不填写的可空值。最重要的是,我定义了一个可以从任何形式的 DU 访问的助手成员,以便通常检索-使用过的数据(就像我想象的那个人的名字一样)。
希望对您有所帮助!
该解决方案与 ChesterHusk 的解决方案类似,但存在一些差异:
- 由于
appointmentTime
始终存在,我认为将它移到 DU 之外是有意义的。因此,Visit
是由visitType
和appointmentTime
组成的记录。 - 在
this.Name
中,我们使用名为 DU 的功能,它允许我们只捕获必需的字段。这种形式更好,因为它不随顺序或字段数变化。
open System
type VisitType =
| AppointmentOnly of name: string * postedTime: DateTime
| WalkIn of name: string * serviceTime: DateTime
| Kept of name: string * postedTime: DateTime * serviceTime: DateTime
| Open
type Visit =
{ appointmentTime: DateTime
visitType: VisitType }
with
member this.Name =
match this.visitType with
| AppointmentOnly(name=name) | WalkIn(name=name) | Kept(name=name) -> Some name
| Open -> None
let visit = { appointmentTime = DateTime.Now
visitType = WalkIn(name="cool_name", serviceTime=DateTime.Now) }
printfn "%A" visit.Name
printfn "%A" visit.appointmentTime