Неполный шаблон, соответствующий кортежу в F#
Я определяю точку
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
2 ответа
Вообще, это анти-паттерн иметь 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
,
В первом случае компилятор просто видит охранников и не достаточно умен, чтобы рассуждать о том, когда они применяются / не применяются - это можно исправить, удалив последний элемент защиты where.
Во-вторых, я бы предположил, что это хвостовая рекурсия, но лучшее, что нужно сделать в этих случаях, - это протестировать с большим списком ввода и посмотреть, не произойдет ли сбой.