2010-09-21 4 views
1

Операторы (..) и (.. ..)) в F # разворачиваются в какой-то момент, является ли операция времени компиляции или операция времени выполнения?- это диапазоны F #, оцененные во время компиляции или времени выполнения

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

+0

Напишите это, скомпилируйте его и проверьте с помощью Reflector. Если вы видите, что оно развернуто ... это время компиляции. Если нет, это время выполнения (я бы попробовал, но на данный момент у меня нет инструментов). –

+0

Если вы спрашиваете, возможно ли создать пользовательскую функцию для ускорения понимания быстрее, чем функция, встроенная в язык - ну, может быть. Как и большинство вещей в разработке программного обеспечения, ответ будет зависеть от контекста. –

ответ

3

Я думаю, что ответ от kvb отвечает на большинство проблем. Тем не менее, я думаю, что более точный ответ заключается в том, что диапазоны оцениваются лениво во время выполнения. Вот несколько подробностей о том, как работают диапазоны ...

Когда вы используете, например, 1 .. 10, где-то в вашем коде, он просто переводится на вызов метода. Вызов зависит от используемых контекстных и числовых типов.

  • Для [ 1 .. 10 ] или других выражений последовательности и for цикла, компилятор будет генерировать что-то вроде RangeInt32(1, 1, 10) (дополнительный параметр представляет собой этап).

  • Если у вас есть что-то вроде obj.[ 1 .. ] и obj некоторый объект, который поддерживает нарезки (например тип матрицы), то он будет переведен на obj.GetSlice(Some(1), None) (обратите внимание, что в этом случае верхняя/нижняя граница может отсутствовать).

Теперь на ваш вопрос довольно легко ответить - это вызов метода, который будет оцениваться во время выполнения. Однако важно отметить, что весь диапазон, возможно, не нужно оценивать! Например:

let nums = seq { 1 .. 10 } |> Seq.take 1 

Выражение последовательность будет переведен на вызов RangeInt32. Это просто вернет значение типа seq<int>, которое оценивается лениво. Вызов take 1 принимает только первый элемент, поэтому требуется только одно число из диапазона и его оценка.

Я не думаю, что ваша собственная реализация диапазонов может отличаться от стандартной, но вы можете обеспечить реализацию в качестве члена объекта. Тогда вы можете написать myObj.[1 .. 10] (и результат может быть любого типа, который вы хотите). Для этого вам понадобится метод экземпляра GetSlice, который более подробно discussed here.

3

Время работы. F # будет очень редко запускать ваш код как часть компиляции - единственный случай, который я могу представить, - это код в модулях NumericLiteralX. Кроме того, в коде вроде:

let f n = [1 .. n] 

верхняя граница даже не известна во время компиляции. Конечно, возможно, что в качестве детали реализации компилятор F # явно разворачивает определения, где обе границы являются статически известными значениями известного типа (например, int), но семантически он всегда должен быть таким же, как если бы он выполнялся во время выполнения.

Относительно вашего второго вопроса, быстрее чем?

Смежные вопросы