在F#中对记录进行模式匹配

4
有没有更加惯用的方式来对记录进行模式匹配?我的代码似乎不太对劲。
type Period = AM | PM

type TimeOfDay = {hours : int; minutes : int; p : Period}

let before (tod1 : TimeOfDay, tod2 : TimeOfDay) =
   match tod1, tod2 with
   | {hours = h1; minutes = m1; p = AM}, {hours = h2; minutes = m2; p = AM} -> (h1, m1) < (h2, m2)
   | {hours = h1; minutes = m1; p = PM}, {hours = h2; minutes = m2; p = PM} -> (h1, m1) < (h2, m2)
   | {hours = _; minutes = _; p = AM}, {hours = _; minutes = _; p = PM} -> true
   | {hours = _; minutes = _; p = PM}, {hours = _; minutes = _; p = AM} -> false

5
如果把Period放到TimeOfDay的首个字段,那么TimeOfDay的值将按你期望的顺序自然排序,这样你就可以只使用tod1 < tod2。这是因为在你对Period的定义中,AM位于PM之前。虽然这对你的问题没有帮助。 - Leaf Garland
3
如果由于某些原因您无法重新排序记录字段(例如,如果它们来自外部库),则仍然可以使用 (tod1.p, tod1.hours, tod1.minutes) < (tod2.p, tod2.hours, tod2.minutes) 进行比较。 - Tarmil
1
或者,您可以切换到24小时制:let adjust = function | {hours=h; minutes=m; p=PM} -> {hours=h+12; minutes=m; p=AM} | x -> x,然后比较应用此函数到两个记录的结果:let before (tod1, tod2) = adjust tod1 < adjust tod2 - Be Brave Be Like Ukraine
2个回答

7
您可以进行小幅改进,因为您不需要显示不必要的模式来生成以下内容。
let before (tod1 : TimeOfDay, tod2 : TimeOfDay) =
   match tod1, tod2 with
   | {hours = h1; minutes = m1; p = AM}, {hours = h2; minutes = m2; p = AM} -> (h1, m1) < (h2, m2)
   | {hours = h1; minutes = m1; p = PM}, {hours = h2; minutes = m2; p = PM} -> (h1, m1) < (h2, m2)
   | { p = AM}, {p = PM} -> true
   | { p = PM}, {p = AM} -> false

接下来,您可以定义一个Active Pattern将类型分解为元组,如下所示。
let (|TIME|) (t:TimeOfDay) = t.hours,t.minutes,t.p

let before (tod1 : TimeOfDay, tod2 : TimeOfDay) =
   match tod1, tod2 with
   | TIME(h1,m1,AM), TIME(h2,m2,PM) -> (h1, m1) < (h2, m2)
   | TIME(h1,m1,PM), TIME(h2,m2,PM) -> (h1, m1) < (h2, m2)
   | { p = AM}, {p = PM} -> true
   | { p = PM}, {p = AM} -> false

2
你可以在匹配中删除不需要的属性,使用“guards”(when子句)来检查两个

属性是否相等,并创建一个本地函数来简化元组比较。

let before (tod1: TimeOfDay, tod2: TimeOfDay) =
   let getTime tod = (tod.hours, tod.minutes)
   match tod1, tod2 with
   | { p = x }, { p = y } when x = y -> getTime tod1 < getTime tod2
   | { p = AM }, _ -> true
   | _ -> false

或者只需执行以下操作即可删除最后一个模式
let before (tod1: TimeOfDay, tod2: TimeOfDay) =
   let getTime tod = (tod.hours, tod.minutes)
   match tod1, tod2 with
   | { p = x }, { p = y } when x = y -> getTime tod1 < getTime tod2
   | { p = x }, _ -> x = AM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接