为什么 Clojure 习惯用法更喜欢返回 nil 而不是像Scheme 那样返回空列表?
来自对另一个问题的评论,有人是说 Clojure 习惯用法更喜欢返回 nil 而不是像Scheme 中那样返回空列表。这是为什么?
喜欢,
(when (seq lat) ...)
而不是
(if (empty? lat)
'() ...)
From a comment on another question, someone is saying that Clojure idiom prefers to return nil rather than an empty list like in Scheme. Why is that?
Like,
(when (seq lat) ...)
instead of
(if (empty? lat)
'() ...)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我可以想到几个原因:
逻辑区别。在 Clojure 中,nil 意味着什么都没有/没有价值。而 '() “空列表是一个值 - 它恰好是一个空列表值。在概念上和逻辑上区分这两者通常很有用。
适合 JVM - JVM 对象模型支持空引用。并且相当多的 Java API 返回 null 表示“无”或“未找到值”。因此,为了确保轻松的 JVM 互操作性,Clojure 以类似的方式使用 nil 是有意义的。
懒惰 - 这里的逻辑相当复杂,但我的理解是,使用 nil 表示“无列表”与 Clojure 的 惰性序列。由于 Clojure 默认是一种惰性函数式编程语言,因此这种用法成为标准是有意义的。请参阅 http://clojure.org/lazy 了解一些额外的说明。
“虚假” - 在编写检查集合的条件代码时,使用 nil 表示“无”也表示“假”,这很方便 - 因此您可以编写类似
(if (some-map :some-key) ....)
测试 hashmap 是否包含给定键的值。性能 - 测试 nil 比检查列表是否为空更有效......因此采用这个习惯用法作为标准可以带来更高性能的惯用代码
请注意,Clojure 中仍然有一些函数确实返回一个空列表。休息就是一个例子:
这个关于休息与下一个的问题详细说明了为什么会这样……
I can think of a few reasons:
Logical distinction. In Clojure nil means nothing / absence of value. Whereas '() "the empty list is a value - it just happens to be a value that is an empty list. It's quite often conceptually and logically useful to distinguish between the two.
Fit with JVM - the JVM object model supports null references. And quite a lot of Java APIs return null to mean "nothing" or "value not found". So to ensure easy JVM interoperability, it makes sense for Clojure to use nil in a similar way.
Laziness - the logic here is quite complicated, but my understanding is that using nil for "no list" works better with Clojure's lazy sequences. As Clojure is a lazy functional programming language by default, it makes sense for this usage to be standard. See http://clojure.org/lazy for some extra explanation.
"Falsiness" - It's convenient to use nil to mean "nothing" and also to mean "false" when writing conditional code that examines collections - so you can write code like
(if (some-map :some-key) ....)
to test if a hashmap contains a value for a given key.Performance - It's more efficient to test for nil than to examine a list to see if it empty... hence adopting this idiom as standard can lead to higher performance idiomatic code
Note that there are still some functions in Clojure that do return an empty list. An example is rest:
This question on rest vs. next goes into some detail of why this is.....
另请注意,集合类型和 nil 的并集形成了一个幺半群,串联了幺半群加和 nil 为幺半群零。因此 nil 在串联下保留空列表语义,同时也表示错误或“缺失”值。
Python 是另一种语言,其中常见的幺半群恒等式表示错误值:0、空列表、空元组。
Also note that the union of collection types and nil form a monoid, with concatenation the monoid plus and nil the monoid zero. So nil keeps the empty list semantics under concatenation while also representing a false or "missing" value.
Python is another language where common monoid identities represent false values: 0, empty list, empty tuple.
来自Clojure 的乐趣
在其他 Lisp 中,例如 Common Lisp,空列表用于表示
nil
。这称为nil 双关,并且仅当空列表为 false 时才可行。这里返回 nil 是 clojure 重新引入 nil 双关语的方式。From The Joy of Clojure
In other Lisps, like Common Lisp, the empty list is used to mean
nil
. This is known as nil punning and is only viable when the empty list is falsey. Returningnil
here is clojure's way of reintroducing nil punning.既然我写了评论,我就写一个答案。 (skuro的答案提供了所有信息,但可能太多了)
seq
是每个人大多数时候都使用的,但是empty?
就可以了(not (seq lat))
当
只有一个分支时,如果您想产生副作用,这是特别好的。您不必使用do
。请参阅此示例:(
如果为 false
'()
(执行(println 1)
(打印2)
(println 3)))
你可以写
(当 true 时
(打印1)
(打印2)
(println 3))
没什么不同,但我认为阅读起来更好。
PS
并不是有称为
if-not
和when-not
的函数,它们通常比(if (not true) ...)
Since I wrote the comment I will write a answer. (The answer of skuro provides all information but maybe a too much)
seq
is just what everybody uses most of the time butempty?
is fine to its just(not (seq lat))
when
has only one branch this is spezially good if you want to have sideeffects. You don't have to usedo
.See this example:
(if false
'()
(do (println 1)
(println 2)
(println 3)))
you can write
(when true
(println 1)
(println 2)
(println 3))
Not that diffrent but i think its better to read.
P.S.
Not that there are functions called
if-not
andwhen-not
they are often better then(if (not true) ...)