Функция возвращает вторую половину заданного списка.
Интересной частью кода является только вложенная (рекурсивная) функция, поскольку единственная цель внешней функции - вызвать вложенную функцию и дважды передать ей указанный список. Вложенная функция cut
имеет два аргумента (в виде кортежа), поэтому ее тип:
cut : 'a list * 'a list -> 'a list
При рекурсивном вызове этой функции вызывается эта функция (которая объясняет, почему она вызывается с двумя аргументами). Вот код комментария:
// The 'function' syntax means that the arguments of the function are matched against
// several clauses. When the arguments (lists) match the clause, the clause is selected
// and its body will be executed.
let rec cut = function
// When the second list is empty or contains a single element,
// the function return all elements of the first list
| xs, ([] | [_]) -> xs
// When the first list is empty, return empty list
| [], _ -> []
// When first list is non-empty and second contains at least two elements,
// the function takes one element from the first list and two elements from
// the second list (x, y, y'), ignores them and calls itself with the
// remaining lists as arguments.
| x::xs, y::y'::ys -> cut (xs, ys)
cut ([ 1 .. 10 ], [ 1 .. 10 ])
Идея функции заключается в том, что она выполняет итерации по двум копиям одного и того же списка. На каждом рекурсивном шаге он пропускает два элемента из второго и один элемент из первого. К тому времени, когда он достигает конца второго списка, первый содержит вторую половину списка (поскольку функция пропускала свои элементы в 2 раза медленнее).
Чтобы получить первую половину списка , вам необходимо добавить дополнительный параметр к вашей внутренней рекурсивной функции cut
. Вы можете использовать его для накопления элементов из первого списка. Опять же, вам нужно пропустить элементы одного из списков в два раза быстрее. Вместо того, чтобы пропускать первые элементы другого списка, вам нужно взять их и добавить в свой аккумулятор.
Я не дам вам полного решения, но, чтобы дать вам некоторое представление, вот псевдокод:
| x::xs, _::_::ys ->
// Call 'cut' recursively to process 'xs' and 'ys'
// and add the element 'x' to the accumulator.
Другой способ написать функцию - использовать match
вместо function
и записать два аргумента как стандартные множественные аргументы (вместо использования кортежа). При игнорировании элементов в последнем предложении также можно использовать _
, поскольку их имена не нужны:
let rec cut l1 l2 =
match l1, l2 with
| xs, ([] | [_]) -> xs
| [], _ -> []
| _::xs, _::_::ys -> cut xs ys
cut [ 1 .. 10 ] [ 1 .. 10 ]