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

问题描述 投票:0回答:4

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

喜欢,

(when (seq lat) ...)

而不是

  (if (empty? lat)  
    '() ...)
clojure idioms
4个回答
25
投票

我可以想到几个原因:

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

  • 适合 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])
=> ()

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


8
投票

还要注意,集合类型和 nil 的并集形成了一个幺半群,将幺半群加和 nil 连接成幺半群零。因此 nil 在串联下保留空列表语义,同时也表示错误或“缺失”值。

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


5
投票

来自 Clojure 的乐趣

因为空集合在布尔上下文中的作用类似于

true
,所以您需要一个习惯用法来测试集合中是否有任何内容需要处理。值得庆幸的是,Clojure 提供了这样的技术:

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

(seq [])
;=> nil

在其他 Lisp 中,例如 Common Lisp,空列表用于表示

nil
。这被称为“nil 双关语”,并且仅当空列表为 false 时才可行。在这里返回 nil 是 clojure 重新引入 nil 双关语的方式。
    


1
投票

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

(如果错误 '() (执行(println 1) (打印2) (打印3)))

你可以写

(当为真时 (打印1) (打印2) (打印3))

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

附注

并不是说有称为

if-not

when-not
的函数,它们通常比
(if (not true) ...)
 更好
    

© www.soinside.com 2019 - 2024. All rights reserved.