(n >= 3 ) && (n <= 99)
ИЛИ
n `elem` [3..99]
Какой быстрее и почему?
Первый один быстрее
(n >= 3) && (n <= 99)
он выполняет 3 операции
n >= 3
n <= 99
and
Где, поскольку elem ищет элемент в массиве, он выполняет до (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
компилятор не может получить его, программисты компилятора и библиотеки должны будут вручную кодировать его и гарантировать, что он сохранится во всех случаях.