(not=(type`(1))(type`;;为什么?(单元素列表、语法引号、Cons、PersistentList)



我在Clojure 1.2.1:中看到了这种行为

user=> (type '(1 2))
clojure.lang.PersistentList
user=> (type `(1 2)) ;; notice syntax-quote
clojure.lang.Cons
user=> (type '(1))
clojure.lang.PersistentList
user=> (type `(1))
clojure.lang.PersistentList

我原以为‘(1)是个缺点,就像‘(12)是一样。

我也试过:

user=> (type (cons 1 nil)) 
clojure.lang.PersistentList
user=> (type (cons 1 `()))
clojure.lang.Cons
user=> (type (cons 1 '()))
clojure.lang.Cons
user=> (type (cons 1 []))
clojure.lang.Cons

那么,`(1)和(cons 1 nil)是PersistentList的原因是什么呢?

正如amalloy所说,您不应该针对那些确切的类型进行编程,而应该针对seq抽象进行编程。

然而,我想我可以猜测一下原因。生成PersistentList的Clojure表单最终调用RT.java,特别是cons(Object x, Object coll)方法。它以一个非常奇怪的检查开始:if(coll == null) return new PersistentList(x),之后如果检查不通过,它会创建一个Cons对象

static public IPersistentCollection cons(Object x, IPersistentCollection y) {
    if(y == null)
        return new PersistentList(x);
    return y.cons(x);
}

因此,在函数的早期版本中,调用被调度到第二个参数的cons方法,因此当第二个自变量为null(即Clojure中的nil)时,需要特殊处理。后来的版本不会进行调度(或者实际上是以不同的方式进行调度,可能是为了支持更多种类的集合类型),但检查被保留了下来,因为它不会破坏任何正确编写的代码。

如果您关心差异,那么您的程序是不正确的。它们都是seq,在(seq? x)返回true的意义上;剩下的是不应该依赖的实现细节。

最新更新