Да. Понимание списка обычно медленнее, чем непосредственное использование списка или массива F #. (На моей машине я также нахожу похожее время с вами.)
Давайте посмотрим, как они реализованы. Версия для понимания списка на самом деле довольно сложна:
последовательность / IEnumerable<int>
создается с использованием синтаксиса понимания. Это просто ленивая последовательность, здесь мало времени.
, затем эта последовательность преобразуется в F # List с помощью чего-то вроде Seq.toList
. Фактическое время проводится здесь. Здесь выполняется много кода типа HasNext
MoveNext
и switch (state)
. С таким большим количеством вызовов функций вы не можете ожидать этого быстро.
В то время как функциональная версия doublesearcher
должным образом оптимизирована в хвостовую рекурсию. Это более прямая версия, чем понимание списка, и в ней используется мало вызовов функций.
Обычно нам не важны эти небольшие различия в производительности для последовательности, списков или массивов, если операция не очень критична. Я думаю, что в вашем примере поколение в любом случае одноразовое. Два времени не являются большой проблемой. Для других случаев, например скалярное произведение двух векторов с использованием массивов может сэкономить много времени, поскольку эта операция выполняется много раз.