Для построения списка с использованием свертывания, вероятно, проще использовать fold_right
, поскольку вы можете эффективно добавлять элементы в список только в начале, и, следовательно, вы должны начать строить список справа, что и делает fold_right
.(Вы также можете использовать fold_left
, но затем вам нужно перевернуть список на дополнительном шаге или использовать дорогую конкатенацию списков.)
Более простым примером для построения списка с fold_right
будет созданиесписок сумм элементов списка, начинающихся в конце списка, например, sums [a; b; c]
дает [a+b+c; b+c; c]
.Код выглядит следующим образом.
let sums = List.fold_right
(fun x ys ->
match ys with
| [] -> [x]
| hd :: tl -> (x + hd) :: ys)
[1; 2; 3; 4; 5]
[]
Что делает внутренняя функция, так это берет первый элемент из уже построенного списка и добавляет его к текущему элементу.(Помните, что элементы посещаются справа налево.) Затем сумма добавляется в начало уже существующего списка.
Определение функции non_decresing
работает аналогичным образом.Однако нам приходится работать с вложенными списками, что несколько усложняет ситуацию.Код выглядит следующим образом.
let non_decreasing xs =
List.fold_right
(fun x outer ->
match outer with
| [] -> [[x]]
| outer_hd :: outer_tl ->
if x <= List.hd outer_hd then
(x :: outer_hd) :: outer_tl
else
[x] :: outer)
xs
[]
Опять же, мы строим список справа налево, но на этот раз мы должны решить, к какому из двух списков мы добавим новый элемент.Либо мы добавляем его в начало внешнего списка, либо добавляем новый список, содержащий только текущий элемент, в начало внешнего списка.