Давайте начнем с сигнатуры типа функции.Поскольку он получает n
и список в качестве аргументов и возвращает пару списков, у вас есть функция split
:
val split : int -> 'a list -> 'a list * 'a list
Вот один из подходов к реализации этой функции:
let split n xs =
let rec splitUtil n xs acc =
match xs with
| [] -> List.rev acc, []
| _ when n = 0 -> List.rev acc, xs
| x::xs' -> splitUtil (n-1) xs' (x::acc)
splitUtil n xs []
Идея состоит в том, чтобы использовать аккумулятор acc
для удержания пройденных вами элементов и уменьшения n
на протяжении долгого пути.Поскольку элементы добавляются к acc
, в конце вы должны обратить его, чтобы получить правильный порядок.
Функция имеет два базовых случая для завершения:
- Там нет элементаосталось пройти (
xs = []
в этой точке). - Вы прошли первые
n
элементов списка (n
уменьшается до 0
в это время).
Вот краткая иллюстрация того, как split
вычисляет результат:
split 2 [1; 2; 3] // call the auxiliary function splitUtil
~> splitUtil 2 [1; 2; 3] [] // match the 3rd case of x::xs'
~> splitUtil 1 [2; 3] [1] // match the 3rd case of x::xs'
~> splitUtil 0 [3] [2; 1] // match the 2nd case of n = 0 (base case)
~> List.rev [2; 1], [3] // call List.rev on acc
~> [1; 2], [3]