【问题标题】:Incomplete pattern matching a tuple in F#在 F# 中匹配元组的不完整模式
【发布时间】:2012-07-06 10:30:03
【问题描述】:

我定义一个点

type TimeSeriesPoint<'T> = 
    { Time : DateTimeOffset
      Value : 'T }

还有一个系列

type TimeSeries<'T> = TimeSeriesPoint<'T> list

我假设这个列表中的点是按时间排序的。

我正在尝试压缩两个时间序列,一般来说,它们会同时具有点,但其中任何一个都可能缺少一些点。

知道为什么我会在下面的代码中收到不完整模式匹配的警告吗?

let zip (series1 : TimeSeries<float>) (series2 : TimeSeries<float>) =
    let rec loop revAcc ser1 ser2 =
       match ser1, ser2 with
       | [], _ | _, [] -> List.rev revAcc
       | hd1::tl1, hd2::tl2 when hd1.Time = hd2.Time ->
           loop ({ Time = hd1.Time; Value = (hd1.Value, hd2.Value) }::revAcc) tl1 tl2
       | hd1::tl1, hd2::tl2 when hd1.Time < hd2.Time ->
           loop revAcc tl1 ser2
       | hd1::tl1, hd2::tl2 when hd1.Time > hd2.Time ->
           loop revAcc ser1 tl2
    loop [] series1 series2

如果我这样写,我不会收到警告,但它是尾递归的吗?

let zip' (series1 : TimeSeries<float>) (series2 : TimeSeries<float>) =
    let rec loop revAcc ser1 ser2 =
       match ser1, ser2 with
       | [], _ | _, [] -> List.rev revAcc
       | hd1::tl1, hd2::tl2 ->
           if hd1.Time = hd2.Time then
               loop ({ Time = hd1.Time; Value = (hd1.Value, hd2.Value) }::revAcc) tl1 tl2
           elif hd1.Time < hd2.Time then
               loop revAcc tl1 ser2
           else 
               loop revAcc ser1 tl2
    loop [] series1 series2

【问题讨论】:

  • 我会在最后移动第一个匹配并将其写为“catch-all” | _ -> List.rev revAcc

标签: f# pattern-matching tail-recursion guard-clause


【解决方案1】:

一般来说,在最后一个模式中有一个when 保护是一种反模式。

zip中,你可以通过去掉多余的保护来达到和zip'一样的效果:

let zip (series1: TimeSeries<float>) (series2: TimeSeries<float>) =
    let rec loop revAcc ser1 ser2 =
       match ser1, ser2 with
       | [], _ | _, [] -> List.rev revAcc
       | hd1::tl1, hd2::tl2 when hd1.Time = hd2.Time ->
           loop ({ Time = hd1.Time; Value = (hd1.Value, hd2.Value) }::revAcc) tl1 tl2
       | hd1::tl1, hd2::tl2 when hd1.Time < hd2.Time ->
           loop revAcc tl1 ser2
       | hd1::tl1, hd2::tl2 ->
           loop revAcc ser1 tl2
    loop [] series1 series2

这两个函数都是尾递归的,因为在递归调用 loop 之后没有额外的工作。

【讨论】:

    【解决方案2】:

    对于第一种情况,编译器只看到了守卫并且不够聪明,无法推断它们何时应用/不应用 - 您可以通过删除最后一个 where 保护来解决此问题。

    第二个我猜它是尾递归的,但在这些情况下最好的办法是用一个大的输入列表进行测试,看看你是否不会崩溃

    【讨论】:

    • 使用自定义运算符,您可以创建一个类,以便比较返回 false,例如 NULL 在 SQL 中的工作方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-12
    • 1970-01-01
    相关资源
    最近更新 更多