我定义了一个点
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
答案 0 :(得分:3)
对于第一种情况,编译器只是看到了警卫并且不够聪明,无法推断它们何时适用/不适用 - 你可以通过删除最后一个保护来解决这个问题。
对于第二个,我猜它是尾递归的,但在这些情况下最好的办法是用大输入列表进行测试,看看你是否崩溃
答案 1 :(得分:3)
一般来说,在最后一种模式中拥有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
之后没有额外的工作。