Проблема реализации F # Seq

Я недавно копался в исходном коде F #.

в Seq.fs:

// Binding. 
//
// We use a type defintion to apply a local dynamic optimization. 
// We automatically right-associate binding, i.e. push the continuations to the right.
// That is, bindG (bindG G1 cont1) cont2 --> bindG G1 (cont1 o cont2)
// This makes constructs such as the following linear rather than quadratic:
//
//  let rec rwalk n = { if n > 0 then 
//                         yield! rwalk (n-1)
//                         yield n }

Увидев приведенный выше код, я протестировал два кода:

let rec rwalk n = seq { if n > 0 then 
                         yield n
                         yield! rwalk (n-1)
                      }

и

let rec rwalk n = seq { if n > 0 then 
                         yield! rwalk (n-1)
                         yield n 
                      }

. Я обнаружил, что первый очень быстрый, а второй очень медленный. Если n = 10000, на моем компьютере для генерации этой последовательности требуется 3 секунды, то есть квадратичное время.

Квадратичное время является разумным, например,

seq {yield! {1; 2; ...; n-1}; yield n} переводится в

Seq.append {1; 2; ...; n-1} {n}

Я думаю, эта операция добавления должна занимать линейное время. В первом коде операция добавления выглядит так: seq {yield n; Уступать! {n-1; п-2; ...; 1}} , что требует постоянного времени.

Комментарии в коде говорят, что это линейное (возможно, это линейное время не является линейным). Возможно, это linear относится к использованию настроенной реализации для последовательности, а не выражения вычисления Moand / F # (как указано в спецификации F #, однако в спецификации не упоминается причина для этого ...).

Кто-нибудь может прояснить здесь нечеткость? Большое спасибо!

(ps, поскольку это проблема языкового дизайна и оптимизации, я также добавил тег Haskell, чтобы узнать, есть ли у людей идеи.)

11
задан Yin Zhu 20 November 2010 в 10:37
поделиться