Хотя этот вопрос был задан некоторое время назад, текущая ситуация несколько отличается.
Многие из функций модуля списка на самом деле используют массив для внутреннего использования.
Например, текущая реализацияof pairwise
[<CompiledName("Pairwise")>]
let pairwise (list: 'T list) =
let array = List.toArray list
if array.Length < 2 then [] else
List.init (array.Length-1) (fun i -> array.[i],array.[i+1])
также FoldBack
(хотя только для списков длиной более 4)
// this version doesn't causes stack overflow - it uses a private stack
[<CompiledName("FoldBack")>]
let foldBack<'T,'State> f (list:'T list) (acc:'State) =
let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
match list with
| [] -> acc
| [h] -> f.Invoke(h,acc)
| [h1;h2] -> f.Invoke(h1,f.Invoke(h2,acc))
| [h1;h2;h3] -> f.Invoke(h1,f.Invoke(h2,f.Invoke(h3,acc)))
| [h1;h2;h3;h4] -> f.Invoke(h1,f.Invoke(h2,f.Invoke(h3,f.Invoke(h4,acc))))
| _ ->
// It is faster to allocate and iterate an array than to create all those
// highly nested stacks. It also means we won't get stack overflows here.
let arr = toArray list
let arrn = arr.Length
foldArraySubRight f arr 0 (arrn - 1) acc
Здесь foldArraySubRight
фактически использует итерационный цикл для обработки массива.
Другие функции с похожей оптимизацией включают в себя практически все с именем, например *Back
, а также все функции sort*
и функцию permute
.