Although this question was asked some time ago, the current situation is somewhat different.
Many of the functions of a list module actually use an array inside.
For example, the current implementation is 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])
also FoldBack (although for lists longer than 4)
// this version doesn't causes Qaru - 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
Here, foldArraySubRight actually uses an iterative loop to process the array.
Other functions with similar optimizations include almost everything called *Back , as well as all sort* and permute .
source share