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

J-S*_*J-S 13 optimization haskell

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

  1. length list == 0
  2. list == []

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

Cac*_*tus 14

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

然而,有一个巧妙的做法,就是做一些length list == 0优点,它可以很好地概括,length list1 == length list2而无需通过更长的列表:你可以使用genericLength自然数字的足够懒惰的表示,以便比较只会强制遍历较短的列表.

一个例子是使用的Natural类型:

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

nats :: [Int]
nats = iterate succ 0

areThereTenNats :: Bool
areThereTenNats = genericLength nats >= (10 :: Natural)
Run Code Online (Sandbox Code Playgroud)

  • @DerekElkins,在第一个参数上通过模式匹配添加并在第二个参数中是"参数"的传统实现将正常工作.但是,您必须阅读`genericLength`源代码和`+`实现源代码,以验证这一点.使用参数化来查看"forall a"显然是正确的.[a]`作为一个自然数. (2认同)
  • @dfeuer我想我应该更清楚的是,对于"== 0"情况,虽然它不会比"null"快,但它不会过于低效.对于任何其他情况,它是一个搅拌垃圾和浪费计算的方法,应该是两个并行的指针,不需要分配.它确实具有与指针行走相同的渐近效率.我只是想表明,如果你担心效率,转换为"懒惰的自然"类型与你应该做的完全相反.(我不是说仙人掌说它是.) (2认同)
  • @仙人掌,我的意思是“存在一个。[a]`或使用`forall`的各种方法。 (2认同)

dfe*_*uer 9

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

null :: Foldable f => f a -> Bool
Run Code Online (Sandbox Code Playgroud)

可以在类型上使用

null :: [a] -> Bool
Run Code Online (Sandbox Code Playgroud)

如果要检查列表是否为空是因为要查看其元素否则,通常应该使用模式匹配:

f [] = something
f (x : xs) = something using x and/or xs
Run Code Online (Sandbox Code Playgroud)

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

compareLength :: [a] -> [b] -> Ordering
compareLength [] [] = EQ
compareLength [] (_ : _) = LT
compareLength (_ : _) [] = GT
compareLength (_ : xs) (_ : ys) =
  compareLength xs ys
Run Code Online (Sandbox Code Playgroud)

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

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


man*_*mat 5

您可以使用来检查您的列表是否在固定时间内为空null list,这将返回一个布尔值。

Prelude> null []
True
Prelude> null [1]
False
Prelude> null ""
True
Prelude> null "Test"
False
Run Code Online (Sandbox Code Playgroud)