(n >= 3 ) && (n <= 99)
ИЛИ
n `elem` [3..99]
Какой из них быстрее и почему?
(n >= 3 ) && (n <= 99)
ИЛИ
n `elem` [3..99]
Какой из них быстрее и почему?
Первый быстрее
(n >= 3) && (n <= 99)
он выполняет 3 операции
n >= 3
n <= 99
and
Где в качестве elem просматривается элемент в массиве, поэтому выполняется операция upto (99 - 3) * 2.
index = 0
isFound = false
array[] = { 3, 4, 5, 6, ... 98, 99 }
while isFound == false
isFound = (n == array[index++])
(n >= 3) && (n <= 99) происходит быстрее, поскольку он включает только два тривиальных сравнения. Если компилятор/интерпретатор не выполняет никакой реальной оптимизации черной магии, он должен построить список ([3.99]), потому что ленивая оценка не может быть использована (обычно "тянет" следующее значение, пока вы не закончите, что будет иметь сложность O (n/2) в этом случае).
Эти два выражения не означают одно и то же. Тонкая разница в том, что на Ord
и на Enum
:
> :t \n -> (n >= 3) && (n <= 99)
\n -> (n >= 3) && (n <= 99) :: (Num a, Ord a) => a -> Bool
> :t \n -> n `elem` [3..99]
\n -> n `elem` [3..99] :: (Num a, Enum a) => a -> Bool
Итак, например, если n равно 3.14159, то первый тест пройдет, а второй не будет:
> (pi >= 3) && (pi <= 99)
True
> pi `elem` [3..99]
False
Кроме того, в то время как четыре экземпляра Prelude Num
(Int
, Integer
, Float
и Double
) являются экземплярами как Ord
, так и Enum
, можно представить себе числовой тип, который является экземпляром Ord
, но не Enum
. В таком случае второй тест не будет даже законным.
Следовательно, в общем случае компилятор не может оплотировать второй так быстро, как первый, если только он не знает для данного типа, что он Ord
и что все упорядоченные значения в диапазоне также находятся в списке перечисление, созданное enumFromTo
. Для Float
и Double
это неверно, и для Int
и Integer
для компилятора нет способа получить его, программисты компилятора и библиотеки должны будут передать его код и обеспечить его хранение в все случаи.
Зависит от машины и компилятора (или интерпретатора).