在Clojure中,我发现这令人惊讶:
> (count nil)
0
我希望出现类型错误,例如:
> (count 77)
java.lang.UnsupportedOperationException: count not supported on this type: Long
因为nil
不是列表:
> (list? nil)
false
nil
是否具有空序列的特殊状态?
答案 0 :(得分:5)
来自官方documentation:
count
:
返回集合中的项目数。 (数nil)返回 0.也适用于字符串,数组和Java集合和映射
所以这是规范;)
我想这可以确保任何具有“可数”类型的变异值都可以在运行时处理
实际上,引用允许类型(字符串,数组和Java集合和映射)的任何引用都可能在某个时刻以nil
为目标。
答案 1 :(得分:5)
有一个旧的lisp传统来混淆nil和空列表。
现在Clojure并不遵守那个,而是在LISP差异页面
你可以阅读
Clojure的一大不同之处在于序列。序列不是特定的 收藏品,尤其是它们不一定是具体的清单。当你 向空集合询问其元素序列(通过调用 seq)它返回nil,说“我不能生产一个”。当你问一个 对于其余的最后一个元素的序列,它返回另一个逻辑 序列。您只能通过调用seq来判断该序列是否为空 反过来。这使得序列和序列协议成为可能 懒惰。
因此,为了能够与许多其他传统处理函数(首先,休息等)链接“seq”调用,你必须处理nil作为某种空列表(这只是我对整个事件的理解) 。
答案 2 :(得分:2)
Clojure有一个抽象优先设计(这些抽象可以是协议,接口或多方法)。也就是说,函数通常不应该以特定的数据类型为目标,而是应该在某种抽象类型上运行,并让任何数据类型实现该抽象,以便该函数使用。
Clojure中处理有序集合的函数应该以{{1}}为目标。这里的复杂性是我们还希望定位本地类型,例如clojure.lang.ISeq
或String
或Array
,其中我们无法追溯添加超类型。我们的解决方案是使用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模型,能够更好地利用延迟序列。