Какой из них быстрее и почему?

(n >= 3 ) && (n <= 99)

ИЛИ

 n `elem` [3..99]

Какой из них быстрее и почему?

Ответ 1

Первый быстрее

 (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++])

Ответ 2

(n >= 3) && (n <= 99) происходит быстрее, поскольку он включает только два тривиальных сравнения. Если компилятор/интерпретатор не выполняет никакой реальной оптимизации черной магии, он должен построить список ([3.99]), потому что ленивая оценка не может быть использована (обычно "тянет" следующее значение, пока вы не закончите, что будет иметь сложность O (n/2) в этом случае).

Ответ 3

Эти два выражения не означают одно и то же. Тонкая разница в том, что на 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 для компилятора нет способа получить его, программисты компилятора и библиотеки должны будут передать его код и обеспечить его хранение в все случаи.

Ответ 4

Зависит от машины и компилятора (или интерпретатора).