首页 > 解决方案 > clojure 如何绑定可变参数?

问题描述

我是 Clojure 的新手。我曾经检查过以下源代码时出现了问题conj

    (def conj 
      (fn ^:static conj
        ([] [])
        ([coll] coll)
        ([coll x] (clojure.lang.RT/conj coll x));4
        ([coll x & xs] ;1
         (if xs ;2
           (recur (clojure.lang.RT/conj coll x) (first xs) (next xs)) ;3
           (clojure.lang.RT/conj coll x)))))

的源代码conj显示它使用recur来实现该功能。这个源代码看起来很简单。我感到困惑的是它在确定递归是否需要继续时使用的条件。看起来它检查变量参数是否是nil,但如果变量参数是nil,它很快就会等同于conj?的第三个“arity” 然后我尝试评估以下表达式:

user=> (conj [] 1 (next []))
[1 nil]
user=>

它正常工作并成功添加nil到向量中。我知道clojure实际上包装nil在一个列表中并将其传递给函数,但我不明白为什么recur可以传递一个实数nil?为什么clojure会识别并匹配正确的“arity”?


user=> (def my_conj
   (fn [coll x & xs]
     (println "xs is" xs)
     (if xs
       (recur (clojure.lang.RT/conj coll x) (first xs) (next xs))
       (clojure.lang.RT/conj coll x))))
#'user/my_conj
user=> (my_conj [] 1 (next []))
xs is (nil)
xs is nil
[1 nil]

标签: clojureclojure-java-interopclojure-core.logic

解决方案


好的,我很抱歉没有更早地意识到您遇到了我以前从未见过的 Clojure 行为的一个方面。今天我学到了一些关于 Clojure 的新东西,并且用了 10 年,这让我感到惊讶。

这是在官方 Clojure 文档的几句话中提到的 recur,这里:https ://clojure.org/reference/special_forms#recur

这是一个社区编写的示例和文档页面(因此不是“官方”),描述了具有可变参数的函数的这种递归行为:https ://clojuredocs.org/clojure.core/recur#example-55ff3cd4e4b08e404b6c1c7f


推荐阅读