为什么`(count nil)`返回0?

时间:2015-03-09 02:26:52

标签: clojure null

在Clojure中,我发现这令人惊讶:

> (count nil)
0

我希望出现类型错误,例如:

> (count 77)
java.lang.UnsupportedOperationException: count not supported on this type: Long

因为nil不是列表:

> (list? nil)
false

nil是否具有空序列的特殊状态?

4 个答案:

答案 0 :(得分:5)

来自官方documentation

count

  

返回集合中的项目数。 (数nil)返回   0.也适用于字符串,数组和Java集合和映射

所以这是规范;)

我想这可以确保任何具有“可数”类型的变异值都可以在运行时处理 实际上,引用允许类型(字符串,数组和Java集合和映射)的任何引用都可能在某个时刻以nil为目标。

答案 1 :(得分:5)

有一个旧的lisp传统来混淆nil和空列表。

现在Clojure并不遵守那个,而是在LISP差异页面

http://clojure.org/lisps

你可以阅读

  

Clojure的一大不同之处在于序列。序列不是特定的   收藏品,尤其是它们不一定是具体的清单。当你   向空集合询问其元素序列(通过调用   seq)它返回nil,说“我不能生产一个”。当你问一个   对于其余的最后一个元素的序列,它返回另一个逻辑   序列。您只能通过调用seq来判断该序列是否为空   反过来。这使得序列和序列协议成为可能   懒惰。

因此,为了能够与许多其他传统处理函数(首先,休息等)链接“seq”调用,你必须处理nil作为某种空列表(这只是我对整个事件的理解) 。

答案 2 :(得分:2)

Clojure有一个抽象优先设计(这些抽象可以是协议,接口或多方法)。也就是说,函数通常不应该以特定的数据类型为目标,而是应该在某种抽象类型上运行,并让任何数据类型实现该抽象,以便该函数使用。

Clojure中处理有序集合的函数应该以{{1​​}}为目标。这里的复杂性是我们还希望定位本地类型,例如clojure.lang.ISeqStringArray,其中我们无法追溯添加超类型。我们的解决方案是使用List来获取seq的实例。事实证明,将clojure.lang.ISeq视为空nil很方便,这简化了例如。各种链表表示,因为为列表的最后一个元素设置ISeq下一个元素是很自然的,因此将nil视为空列表。

答案 3 :(得分:2)

nil是否具有空序列的特殊状态?

是。这被称为 nil-punning - 一种Lisp传统,正如Freakhill所说。

在Clojure中,它只适用于一个方向:

  • 如果您提供序列所在的nil,它就会自行转换 进入空序列。这通常适用于count

例如,

(concat nil) ; => ()

(map inc nil) ; => ()
  • 但是如果你提供一个可能需要nil的空序列, 例如,作为逻辑假值,它转换为nil

例如

(if () 1 2) ; => 1

(if nil 1 2) ; => 2

This page解释了Clojure如何脱离传统的Lisp模型,能够更好地利用延迟序列。

相关问题