(n >= 3 ) && (n <= 99)
OR
n `elem` [3..99]
哪一个更快,为什么?
答案 0 :(得分:18)
第一个更快
(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++])
答案 1 :(得分:11)
(n> = 3)&amp;&amp; (n <= 99)更快,因为它仅涉及两个平凡的比较。如果编译器/解释器没有做任何真正的黑魔法优化,它必须构造列表([3..99]),因为懒惰的评估不能使用(通常“拉”下一个值,直到你完成,在这种情况下会有O(n / 2)的复杂度。
答案 2 :(得分:8)
这两个表达并不是一回事。一个微妙的区别是,一个依赖于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
)都是{{1}的实例}和Ord
,可以想象一个数字类型,它是Enum
但不是Ord
的实例。在这种情况下,第二次测试甚至不合法。
因此,一般情况下,编译器不能将第二个显示为与第一个一样快,除非它知道给定类型,它是Enum
并且该范围内的所有有序值也在由Ord
创建的列表枚举。对于enumFromTo
和Float
,这不是真的,对于Double
和Int
,编译器无法派生它,编译器和库程序员必须手工编码并确保在所有情况下都能保留。
答案 3 :(得分:-2)
取决于机器和编译器(或解释器)。