了解工会案例

Understanding union cases

我有一些这样的类型:

type Workshop = { Start: DateTime; End: DateTime }
type Mounting = { Start: DateTime; End: DateTime }
type FixedWorkTime = { Start: DateTime; End: DateTime }

type WorkTime =
    | Workshop of Workshop
    | Mounting of Mounting

type ApprovedWorkTime =
    | ExistingWorkTime of WorkTime
    | FixedWorkTime of FixedWorkTime

现在我想用这个签名创建一个函数WorkTime -> ApprovedWorkTime

let FixWorkTime (workTime: WorkTime) : ApprovedWorkTime =
    match workTime with
    | WorkTime.Workshop workshop -> ApprovedWorkTime.ExistingWorkTime { Start = workshop.Start, End = workshop.End }
    | WorkTime.Mounting mounting -> ApprovedWorkTime.FixedWorkTime { Start = mounting.Start, End = mounting.End }

match 编译失败并出现此错误:

This expression was expected to have type 'WorkTime' but here has type 'FixedWorkTime'

我该如何解决这个问题?

在记录的字段之间使用分号,而不是逗号。每当您看到逗号时,就假设它表示一个元组。

其次,ExistingWorkTime是WorkTime的,WorkTime也是一个DU,所以你有层次。

let fixWorkTime (workTime: WorkTime) : ApprovedWorkTime =
    match workTime with
    | Workshop workshop -> ExistingWorkTime (Workshop { Start = workshop.Start; End = workshop.End })
    | Mounting mounting -> FixedWorkTime { Start = mounting.Start; End = mounting.End }

这里:

ApprovedWorkTime.ExistingWorkTime { Start = workshop.Start, End = workshop.End }

您正在尝试使用 ExistingWorkTime 构造函数构造 ApprovedWorkTime 的值,并且将记录作为参数传递给它。

但根据其定义:

| ExistingWorkTime of WorkTime

它不需要记录,或者需要 WorkTime 类型的值。

所以修复它的最短方法是将它 workTime 作为参数:

ApprovedWorkTime.ExistingWorkTime workTime

虽然我严重怀疑这是你的意思。


另外,我想指出您的类型不必要地复杂。看:每个值都有相同的字段,它们只是构造函数不同,每次在值之间转换时都必须来回铲这些字段。

一个更高效的模型应该在顶层有 StartEnd 字段,以及作为第三个字段的工作类型:

type WorkTime<'kind>= { Start: DateTime; End: DateTime; Kind: 'kind }

type WorkTimeKind = Workshop | Mounting

type ApprovedWorkTimeKind = ExistingWorkTime of WorkTime | FixedWorkTime

简单的解决方法是使类型匹配,正如其他答案已经解释的那样:

let FixWorkTime (workTime: WorkTime) : ApprovedWorkTime =
    match workTime with
    | WorkTime.Workshop _ -> ExistingWorkTime workTime
    | WorkTime.Mounting mounting -> FixedWorkTime { Start = mounting.Start; End = mounting.End }

不过,我可能会稍微更改一下您的类型,使它们更具可组合性:

type Interval = { Start: DateTime; End: DateTime }

type WorkTime =
    | Workshop of Interval
    | Mounting of Interval

type ApprovedWorkTime =
    | ExistingWorkTime of WorkTime
    | FixedWorkTime of Interval

let FixWorkTime (workTime: WorkTime) : ApprovedWorkTime =
    match workTime with
    | Workshop _ -> ExistingWorkTime workTime
    | Mounting interval -> FixedWorkTime interval