为什么 Clojure 习惯用法更喜欢返回 nil 而不是像Scheme 那样返回空列表?

发布于 2024-11-08 20:14:48 字数 334 浏览 3 评论 0原文

来自对另一个问题的评论,有人是说 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

相思碎 2024-11-15 20:14:48

我可以想到几个原因:

  • 逻辑区别。在 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 中仍然有一些函数确实返回一个空列表。休息就是一个例子:

(rest [1])
=> ()

这个关于休息与下一个的问题详细说明了为什么会这样……

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:

(rest [1])
=> ()

This question on rest vs. next goes into some detail of why this is.....

风筝有风,海豚有海 2024-11-15 20:14:48

另请注意,集合类型和 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.

快乐很简单 2024-11-15 20:14:48

来自Clojure 的乐趣

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

<前><代码>(seq [1 2 3])
;=> (1 2 3)

(序列[])
;=>零

在其他 Lisp 中,例如 Common Lisp,空列表用于表示 nil。这称为nil 双关,并且仅当空列表为 false 时才可行。这里返回 nil 是 clojure 重新引入 nil 双关语的方式。

From The Joy of Clojure

Because empty collections act like true in Boolean contexts, you need an idiom for testing whether there's anything in a collection to process. Thankfully, Clojure provides such a technique:

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

(seq [])
;=> nil

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. Returning nil here is clojure's way of reintroducing nil punning.

み零 2024-11-15 20:14:48

既然我写了评论,我就写一个答案。 (skuro的答案提供了所有信息,但可能太多了)

  1. 首先,我认为更重要的东西应该放在第一位。
  2. seq 是每个人大多数时候都使用的,但是 empty? 就可以了 (not (seq lat))
  3. 在 Clojure '( ) 为 true,因此通常情况下,如果序列完成,您希望返回 false 的值。
  4. 如果你的分支中只有一个 importend 分支,如果另一个分支返回 false/'() 或类似的东西,为什么你应该写下该分支。 只有一个分支时,如果您想产生副作用,这是特别好的。您不必使用do

请参阅此示例:(

如果为 false
'()
(执行(println 1)
(打印2)
(println 3)))

你可以写

(当 true 时
(打印1)
(打印2)
(println 3))

没什么不同,但我认为阅读起来更好。


PS

并不是有称为 if-notwhen-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)

  1. First of all I think that more importend things should be in first.
  2. seq is just what everybody uses most of the time but empty? is fine to its just (not (seq lat))
  3. In Clojure '() is true, so normaly you want to return something thats false if the sequence is finished.
  4. if you have only one importend branch in your if an the other returnes false/'() or something like that why should you write down that branch. when has only one branch this is spezially good if you want to have sideeffects. You don't have to use do.

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 and when-not they are often better then (if (not true) ...)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文