为什么用null函数代替== []检查Haskell中的空列表?

徐保钰*_*徐保钰 57 haskell list is-empty empty-list

我正在阅读“ 了解Haskell的伟大成就! ”的“入门”一章。它说:

null检查列表是否为空。如果是,则返回True,否则返回False。使用此函数代替xs == [](如果您有一个名为的列表xs

我在ghci中尝试过:

xs = []      -- and then,

xs == []
null xs
Run Code Online (Sandbox Code Playgroud)

他们俩都是True

我想知道有什么区别。

我应该使用该null函数代替,== []为什么?

Dan*_*ner 66

您应该使用null。在大多数情况下,这并不重要,但是无论如何这都是一个好习惯,因为有时候您可能想检查一系列不可比的事物是否为空。这是一个简短明了的示例,显示了这种差异:

> null [id]
False
> [id] == []
<interactive>:1:1: error:
    • No instance for (Eq (a0 -> a0)) arising from a use of ‘==’
        (maybe you haven't applied a function to enough arguments?)
    • In the expression: [id] == []
      In an equation for ‘it’: it = [id] == []
Run Code Online (Sandbox Code Playgroud)

  • “在大多数情况下都没有关系” –我不同意。编写多态列表函数是很常见的,它不需要“ Eq”约束(即使在大多数情况下,它们确实是带有“ Eq”类型的_instantiated_)。 (27认同)
  • 为了记录:`length xs == 0`是一个坏主意,因为它需要遍历整个链表(它是O(n)并且永远不会终止于无限表)。 (6认同)
  • 我同意此答案中的所有内容。为了子孙后代和完整性,也许值得一提的是为什么'length xs == 0'是一个坏主意。 (5认同)

Wil*_*sem 49

它们是有区别的。为了使用x == [],列表元素的类型应该是Eqtypeclass 的成员。实际上,检查两个列表是否相等是由实例声明定义的:

instance Eq a => Eq [a] where
    []     == []      =  True
    (x:xs) == (y:ys)  =  x == y  &&  xs == ys
    _      == _       =  False
Run Code Online (Sandbox Code Playgroud)

这意味着您不能使用x == []if x是例如IO Ints 的列表。

null :: [a] -> Bool另一方面,使用模式匹配。这实现为

null                    :: [a] -> Bool
null []                 =  True
null (_:_)              =  False
Run Code Online (Sandbox Code Playgroud)

因此,无论列表元素是什么类型,它都将始终进行类型检查。


col*_*ole 26

除了到目前为止给出的好答案之外,null实际上还有

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

我不知道您是否已经在LYAH中输入类型类,但是它的简短之处在于null不仅可以用于列表,还可以用于实现的任何数据结构null

也就是说,null在a Map或a上使用Set也是有效的。

> null Map.empty
True
> null (Map.singleton 1)
False
> null Set.empty
True
> null (Set.singleton 1)
False
> null []
True
> null [1]
False
Run Code Online (Sandbox Code Playgroud)

我认为编写需要具有这种通用功能的函数并不是特别常见,但是默认情况下编写更通用的代码也没有什么坏处。

旁注

在许多情况下,您最终想要使用一个函数,例如null对列表(或其他数据结构)执行条件行为。如果您已经知道您的输入是一个特定的数据结构,那么在空的情况下进行模式匹配会更加优雅。

比较

> null Map.empty
True
> null (Map.singleton 1)
False
> null Set.empty
True
> null (Set.singleton 1)
False
> null []
True
> null [1]
False
Run Code Online (Sandbox Code Playgroud)

myMap :: (a -> b) -> [a] -> [b]
myMap f xs
  | null xs = []
myMap f (x:xs) = f x : myMap f xs
Run Code Online (Sandbox Code Playgroud)

通常,如果可行,您应该尝试使用模式匹配。