【问题标题】:Pattern matching on records in F#F# 中记录的模式匹配
【发布时间】:2013-10-19 07:35:59
【问题描述】:

有没有更惯用的方法来对记录进行模式匹配?我的代码似乎不正确。

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

【问题讨论】:

  • 如果您将Period 移动到TimeOfDay 中的第一个字段,那么TimeOfDay 值自然会按照您期望的顺序排序,因此您可以使用tod1 &lt; tod2。这是因为AMPeriod 的定义中出现在PM 之前。不过对你的问题没有帮助。
  • 如果由于某种原因您无法重新排序记录字段(例如,如果它们来自外部库),您仍然可以使用(tod1.p, tod1.hours, tod1.minutes) &lt; (tod2.p, tod2.hours, tod2.minutes)
  • 或者,您可以切换到 24 小时制:let adjust = function | {hours=h; minutes=m; p=PM} -&gt; {hours=h+12; minutes=m; p=AM} | x -&gt; x,然后将应用此功能的结果与两条记录进行比较:let before (tod1, tod2) = adjust tod1 &lt; adjust tod2

标签: f# idioms


【解决方案1】:

您可以做些小改进,因为您不需要显示不需要的模式来生成以下内容

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

接下来,您可以定义一个活动模式来将类型解构为一个元组,如下所示

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】:

    您可以删除匹配中不需要的属性,使用“守卫”(when 子句)检查两个pproperties 是否相等,并创建一个局部函数来简化元组比较。

    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
    

    【讨论】:

      猜你喜欢
      • 2020-10-21
      • 1970-01-01
      • 2015-03-21
      • 2016-10-29
      • 2019-01-10
      • 2018-01-08
      • 2011-10-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多