检查Haskell中的空列表:是(长度列表== 0)还是(列表== [])效率更高?

时间:2016-04-07 05:00:19

标签: haskell optimization

假设我想检查Haskell中一个守卫中的列表是否为空,有两个选项:

  1. length list == 0
  2. list == []
  3. 这两个逻辑测试中的哪一个更有效?我倾向于说空列表测试因为依赖于更基本的构造而不是前奏函数length但是我不确定。

3 个答案:

答案 0 :(得分:14)

length list == 0需要遍历整个列表以获取其长度,这意味着它是 O(n)list == []对元素类型产生Eq约束。 null list以恒定时间运行,没有类型类约束。

然而,有一个巧妙的做法是做length list == 0这样的事情,它的优势在于它可以很好地概括为length list1 == length list2而无需通过更长的列表:你可以使用genericLength自然数字的充分惰性表示,以便比较只会强制遍历较短的列表。

一个例子是使用the Natural type

import Data.Number.Natural
import Data.List (genericLength)

nats :: [Int]
nats = iterate succ 0

areThereTenNats :: Bool
areThereTenNats = genericLength nats >= (10 :: Natural)

答案 1 :(得分:7)

正如其他人所指出的那样,检查列表是否为空(而不是更多)的最佳方法是使用

null :: Foldable f => f a -> Bool

可以在

类型中使用
null :: [a] -> Bool

如果你想检查一个列表是否为空,因为你想要查看它的元素,你通常应该使用模式匹配:

f [] = something
f (x : xs) = something using x and/or xs

如果你想比较两个列表的长度(而不是更多),最好的方法通常是

compareLength :: [a] -> [b] -> Ordering
compareLength [] [] = EQ
compareLength [] (_ : _) = LT
compareLength (_ : _) [] = GT
compareLength (_ : xs) (_ : ys) =
  compareLength xs ys

检查列表长度与特定数字的比较的最佳方法是

compareToLength :: Foldable f
                => f a -> Int -> Ordering
compareToLength = foldr go (compare 0) where
  go _ r n | n <= 0 = GT
           | otherwise = r $! n - 1

答案 2 :(得分:4)

您可以使用null list检查列表是否为空,并返回布尔值。

Prelude> null []
True
Prelude> null [1]
False
Prelude> null ""
True
Prelude> null "Test"
False