为什么Clojure成语更喜欢返回nil而不是像Scheme这样的空列表?

时间:2011-05-18 13:22:38

标签: clojure idioms

来自a comment on another question,有人说Clojure成语更喜欢返回nil而不是像Scheme中的空列表。那是为什么?

像,

(when (seq lat) ...)

而不是

  (if (empty? lat)  
    '() ...)

4 个答案:

答案 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)

来自The Joy of Clojure

  

因为空集合在布尔上下文中的行为类似于true,所以您需要一个成语来测试集合中是否有任何要处理的内容。值得庆幸的是,Clojure提供了这样一种技术:

(seq [1 2 3])
;=> (1 2 3)

(seq [])
;=> nil

在其他Lisp中,如Common Lisp,空列表用于表示nil。这被称为 nil punning ,仅在空列表为假时才可行。在这里返回nil是clojure重新引入nil punning的方式。

答案 3 :(得分:1)

自从我写评论后,我会写一个答案。 (skuro的答案提供了所有信息,但可能过多)

  1. 首先,我认为应该首先考虑更多的重要事项。
  2. seq正是每个人大部分时间都在使用的内容,但empty?只适用于(not (seq lat))
  3. 在Clojure'()中是正确的,所以如果序列完成,你想要返回错误的东西。
  4. 如果你只有一个importend分支,如果其他的返回false /'()或类似的东西你为什么要记下那个分支。 when只有一个分支,如果你想产生副作用,那么这个分支是非常好的。您不必使用do
  5. 见这个例子:

    (如果是假的话 “() (做(println 1)       (println 2)       (println 3)))

    你可以写

    (当时为真    (println 1)    (println 2)    (println 3))

    不是那么不同,但我认为最好阅读。


    P.S。

    并非有if-notwhen-not这些功能通常比(if (not true) ...)更好