Сортировка слиянием по своей природе не является хвостовой рекурсией. Сортировка требует двух рекурсивных вызовов, и при любом выполнении любой функции, самое большее один динамический вызов может быть в положении хвоста. (split
также вызывается из нехвостовой позиции, но так как он должен использовать постоянное пространство стека, которое должно быть в порядке).
Убедитесь, что вы используете последнюю версию OCaml. В версиях 3.08 и более старых, List.rev
может уничтожить стек. Эта проблема исправлена в версии 3.10. Используя версию 3.10.2, я могу отсортировать список из десяти миллионов элементов , используя ваш код. Это займет пару минут, но я не бью стопку. Поэтому я надеюсь, что ваша проблема просто в том, что у вас есть старая версия OCaml.
Если нет, то следующим шагом будет установка переменной окружения
OCAMLRUNPARAM=b=1
, который даст трассировку стека, когда вы ударите стек.
Я также хотел бы знать длину массивов, которые вы сортируете; хотя сортировка слиянием не может быть хвостовой рекурсией, ее не хвостовая природа должна стоить вам логарифмического пространства стека.
Если вам нужно отсортировать более 10 миллионов элементов, может быть, вам стоит взглянуть на другой алгоритм? Или, если хотите, вы можете CPS-конвертировать слияние вручную, что даст хвостовую рекурсивную версию за счет распределения переходов в куче. Но я думаю, что в этом нет необходимости.