Search code examples
clojureclojure-java-interopclojure-core.logic

How does clojure bind variable parameters?


I am a newbie in Clojure.The problem originated when I once checked the source code of 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)))))

The source code of conj shows that it uses recur to implement the function. This source code looks very simple. What I'm confused about is the condition it uses when determining whether recursion needs to continue. It looks like it checks if the variable parameters is nil , but if the variable parameters is nil, it will soon be equivalent to the third "arity" of conj? I then tried to evaluate the following expression:

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

It works normally and successfully adds nil to the vector. I understand that clojure actually wraps nil in a list and passes it to the function, but I don't understand why recur can pass a real nil in ? And why does clojure recognize and match the correct "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]

Solution

  • OK, my apologies for not realizing earlier that you have come across an aspect of Clojure behavior that I had never seen before. Today I learned something new about Clojure, and given 10 years with it, that surprised me.

    This is mentioned in a couple of sentences of the official Clojure documentation for recur, here: https://clojure.org/reference/special_forms#recur

    Here is a page of community-written examples and documentation (so not "official") that describes this behavior of recur with functions that have variadic arguments: https://clojuredocs.org/clojure.core/recur#example-55ff3cd4e4b08e404b6c1c7f