Почему Seq.iter и Seq.map настолько медленнее?

Рассмотрим этот код в F #:

let n = 10000000
let arr = Array.init n (fun _ -> 0)

let rec buildList n acc i = if i = n then acc else buildList n (0::acc) (i + 1)
let lst = buildList n [] 0

let doNothing _ = ()
let incr x = x + 1

#time

arr |> Array.iter doNothing         // this takes 14ms
arr |> Seq.iter doNothing           // this takes 74ms

lst |> List.iter doNothing          // this takes 19ms
lst |> Seq.iter doNothing           // this takes 88ms

arr |> Array.map incr               // this takes 33ms
arr |> Seq.map incr |> Seq.toArray  // this takes 231ms!

lst |> List.map incr                // this takes 753ms
lst |> Seq.map incr |> Seq.toList   // this takes 2111ms!!!!

Почему функции iter и map в модуле Seq настолько медленнее, чем эквиваленты модулей Array и List?

Ответ 1

Как только вы входите в Seq, вы теряете информацию о типе - переход к следующему элементу в списке требует вызова IEnumerator.MoveNext. Сравните с Array, вы просто увеличиваете индекс, а для List вы можете просто разыменовать указатель. По сути, вы получаете дополнительный вызов функции для каждого элемента в списке.

Преобразования обратно в List и Array также замедляют код по аналогичным причинам