Вам нужно выбрать методологию сортировки, прежде чем беспокоиться об используемой структуре данных. Если бы вы делали, скажем, сортировку вставкой, вы, вероятно, захотите начать с конца списка и вставлять элемент на каждом уровне рекурсии, следя за тем, как вы сами обрабатываете вставку.
Технически на любом конкретном уровне у вас есть доступ только к одному элементу данных, однако вы можете передать определенный элемент данных в качестве параметра для его сохранения. Например, здесь вставляемая часть алгоритма сортировки вставок, предполагается, что список отсортирован.
let rec insert i l =
match l with
| [] -> [i]
| h::t -> if h > i then
i::l
else
h::(insert i t)
Обратите внимание, что теперь у меня есть доступ к двум элементам: кешированному и оставшемуся. Другим вариантом может быть сортировка слиянием, когда у вас есть два отсортированных списка и, следовательно, два элемента для работы с любой конкретной итерацией.
Комментарий Даниэля с комментариями упоминает конкретную реализацию (быструю сортировку), если вам интересно.
Наконец, списки не являются оптимальными для алгоритмов сортировки из-за их жесткой структуры и необходимого количества выделений. Учитывая, что все известные алгоритмы сортировки имеют сложность> O (n), вы можете преобразовать свой список в массив и из него, чтобы повысить производительность без ущерба для асимптотической производительности.
EDIT:
Обратите внимание, что выше не в хвостовой рекурсивный формат, вам нужно сделать что-то вроде этого:
let insert i l =
let rec insert i l acc =
match l with
| [] -> List.foldBack (fun e a -> e :: a) acc [i]
| h::t -> if h > i then
List.foldBack (fun e a -> e :: a) acc i::l
else
insert i l (i::acc)
insert i l []
Я не помню наизусть лучший способ перевернуть список, поэтому пошел с примером из https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/lists