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



从对另一个问题的评论中,有人说 Clojure 习语更喜欢返回 nil 而不是像 Scheme 中那样返回空列表。为什么?

喜欢

(when (seq lat) ...)

而不是

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

我能想到几个原因:

  • 逻辑上的区别。在Clojure中,nil意味着什么都没有/没有价值。而'()"空列表是一个值 - 它恰好是一个空列表的值。区分这两者通常在概念上和逻辑上都是有用的。

  • 适合 JVM - JVM 对象模型支持空引用。相当多的Java API返回null表示"无"或"未找到值"。因此,为了确保JVM的互操作性,Clojure以类似的方式使用nil是有意义的。

  • 懒惰 - 这里的逻辑相当复杂,但我的理解是,使用 nil 表示"无列表"更适合 Clojure 的懒惰序列。由于Clojure默认是一种惰性的函数式编程语言,因此将这种用法作为标准用法是有意义的。有关一些额外的说明,请参阅 http://clojure.org/lazy。

  • "虚假" - 在编写检查集合的条件代码时,使用 nil 表示"无"和表示"false"很方便 - 因此您可以编写类似 (if (some-map :some-key) ....) 的代码来测试哈希映射是否包含给定键的值。

  • 性能 - 测试 nil 比检查列表以查看它是否为空更有效...因此,采用这个成语作为标准可以带来更高性能的惯用语代码

请注意,Clojure 中仍然有一些函数会返回一个空列表。一个例子是休息:

(rest [1])
=> ()

这个关于休息与下一个的问题详细介绍了为什么会这样......

另请注意,集合类型和 nil 的并集形成一个幺半群,幺半群加上 nil 幺半群零。因此,nil 将空列表语义保持在串联下,同时还表示一个假值或"缺失"值。

Python 是另一种语言,其中常见的幺半群恒等式表示假值:0、空列表、空元组。

摘自《The Joy of Clojure》

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

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

在其他 Lisp 中,如 Common Lisp,空列表用于表示 nil 。这称为 nil 双关语,只有在空列表为假时才可行。回到这里nil是clojure重新引入零双关语的方式。

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

  1. 首先,我认为更多的进口应该放在第一位。
  2. seq只是每个人大部分时间都在使用的东西,但empty?只是(not (seq lat))
  3. 在 Clojure 中,'() 是真的,所以如果序列完成,你想返回一些假的东西。
  4. 如果你只有一个importend分支,如果另一个返回false/'()或类似的东西,为什么要写下那个分支。 when只有一个分支,如果你想有副作用,这是特别好的。您不必使用 do .

请参阅此示例:

(如果为假'()(do (println 1) (打印ln 2) (println 3)))

你可以写

(当为真时 (打印ln 1) (打印ln 2) (印刷品3))

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


附言

并不是说有称为if-not的函数,when-not它们通常比(if (not true) ...)更好

最新更新