Help with multiple arity arg lists

I’m trying to write several functions which each follow a similar kind of argument parsing.
In all cases the functions are unary functions.
However, there are three cases to consider. 1) the argument is not a list, 2) the argument is a singleton list, 3) the argument is a list with a head and non-empty tail.

I tried the following, but the compiler complains. Can't have 2 overloads with same arity

What’s the correct way to do this?

(defn f
   ;; case 1
  ([[token & args]]
   (if (nil? args)
     ;; case 2
     ;; case 3

If I try to write my own code to test the types, it immediately gets tricky, as the type seems to depend on the call site.

clojure-rte.core> (defn a [[b & args]]
                    (type args))
clojure-rte.core> (a (list 1 2 3))
clojure-rte.core> (a [1 2 3])

The following does not work because (seq? [1 2 3]) returns false.

(defn f [expr]
  (cond (seq? expr)
        (let [[token & args] expr]
          (if (nil? args)
            ;; case 2
            ;; case 3
        ;; case 1

Try (sequential? expr), or (coll? expr) if you want to handle other collections like maps and sets.

(seq? [1 2 3]) is tricky, because vectors are not seqs but they are sequential and sequable:

(seq? [1 2 3]) => false
(seqable? [1 2 3]) => true
(sequential? [1 2 3]) => true

The idiom you might be looking for is simply the non-predicate seq:

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

See docs for Collections and Sequences and this whole Q&A but particular the Venn diagram therein. Also the ISeq interface docs.

Incidentally, if you haven’t watched Clojure for Lisp Programmers (and part 2) I highly recommend it. Even without CL experience I consider it one of my favorite talks to explain the reasoning behind Clojure’s design decisions and idioms. In it, Rich gives one of the best explanations anywhere of the seq idiom.

Yes, I’ve seen the videos. Great videos. bravo

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.