从 C# 中为 F# 中的约会从概念上创建一个有区别的联合

Conceptually creating a discriminated union for an appointment in F# from C#

客气点,我是 F# 的新手(来自 C#)。在查看我的约会簿的用户控件时,我发现它是建立在 class 概念之上的,即用于填充数据网格的“访问”概念。我想使用 F# 描述联合来替换 C# 访问 class,但无法正确使用。看多了,我的C#思路好像也断不了。

从概念上讲,“访问”将始终具有“约会时间”,而不管它是否具有名称或其他任何内容。现在从这一点来看,访问可以是几个不同的东西(使用区分联合的原因):

  1. 如果访问只有姓名和发布时间,那么它只是一个约会。
  2. 如果拜访只有预约时间、服务时间和姓名,那么这个人是没有预约的,是“走访”,
  3. 如果访问有姓名、约会时间、发布时间和服务时间,那么这是一个见过该人的约会 -- "a keep appointment",
  4. 如果访问只有预约时间而没有姓名或其他任何内容,则可以使用--“一个开放的时间段”。

在 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 的解决方案类似,但存在一些差异:

  1. 由于 appointmentTime 始终存在,我认为将它移到 DU 之外是有意义的。因此,Visit是由visitTypeappointmentTime组成的记录。
  2. 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