来自a comment on another question,有人说Clojure成语更喜欢返回nil而不是像Scheme中的空列表。那是为什么?
像,
(when (seq lat) ...)
而不是
(if (empty? lat)
'() ...)
答案 0 :(得分:23)
我可以想到几个原因:
逻辑区别。在Clojure中,没有任何意义/缺乏价值。而'()'空列表是一个值 - 它恰好是一个空列表的值。在概念上和逻辑上有用的区分两者。
< / LI>适合JVM - JVM对象模型支持空引用。而且很多Java API都返回null表示“没有”或“找不到值”。因此,为了确保简单的JVM互操作性,Clojure以类似的方式使用nil是有意义的。
懒惰 - 这里的逻辑非常复杂,但我的理解是使用nil作为“no list”可以更好地使用Clojure的lazy sequences。由于Clojure默认是一种惰性函数式编程语言,因此这种用法是标准的。有关其他说明,请参阅http://clojure.org/lazy。
“Falsiness” - 在编写用于检查集合的条件代码时,使用nil表示“无”并且表示“false”也很方便 - 因此您可以编写类似{{的代码1}}测试一个hashmap是否包含给定键的值。
性能 - 测试nil比检查列表以查看它是否为空更有效...因此采用此习惯用作标准可以带来更高性能的惯用代码
请注意,Clojure中仍然存在一些返回空列表的函数。一个例子是休息:
(if (some-map :some-key) ....)
这question on rest vs. next详细说明了为什么......
答案 1 :(得分:7)
还要注意,集合类型和nil的并集形成一个monoid,连接monoid加上nil和monoid零。因此,nil将空列表语义保持在连接状态,同时还表示错误或“缺失”值。
Python是另一种语言,其中常见的monoid身份表示错误值:0,空列表,空元组。
答案 2 :(得分:5)
因为空集合在布尔上下文中的行为类似于
true
,所以您需要一个成语来测试集合中是否有任何要处理的内容。值得庆幸的是,Clojure提供了这样一种技术:(seq [1 2 3]) ;=> (1 2 3) (seq []) ;=> nil
在其他Lisp中,如Common Lisp,空列表用于表示nil
。这被称为 nil punning ,仅在空列表为假时才可行。在这里返回nil
是clojure重新引入nil punning的方式。
答案 3 :(得分:1)
自从我写评论后,我会写一个答案。 (skuro的答案提供了所有信息,但可能过多)
seq
正是每个人大部分时间都在使用的内容,但empty?
只适用于(not (seq lat))
when
只有一个分支,如果你想产生副作用,那么这个分支是非常好的。您不必使用do
。见这个例子:
(如果是假的话 “() (做(println 1) (println 2) (println 3)))
你可以写
(当时为真 (println 1) (println 2) (println 3))
不是那么不同,但我认为最好阅读。
P.S。
并非有if-not
和when-not
这些功能通常比(if (not true) ...)
更好