14

So there's list?, seq?, vector?, map? and so on to determine what type of collection the argument is.

What's a good way of telling the difference between

  • a map (i.e. something that contains key-value pairs)
  • a collection (i.e. something that contains values)
  • a non collection value like a string.

Is there a better way than

#(or (seq? %) (list? %) etc)
Kurt Schelfthout
  • 8,880
  • 1
  • 30
  • 48

4 Answers4

9

using seq? is about as concise and clean as it gets.

clojure.contrib.core defines:

seqable?
    function
    Usage: (seqable? x)
    Returns true if (seq x) will succeed, false otherwise.

http://clojure.github.com/clojure-contrib/core-api.html

it does what you proposed with one big or statement of

  • already a seq
  • an instance of clojure.lang.Seqable
  • nil
  • instance of Iterable
  • an array
  • a string
  • instance of java.util.Map
kotarak
  • 17,099
  • 2
  • 49
  • 39
Arthur Ulfeldt
  • 90,827
  • 27
  • 201
  • 284
  • In the current version of Clojure (1.5) seqable? is currently living in clojure.core.incubator (repo @ https://github.com/clojure/core.incubator) – Daniel Neal Aug 11 '13 at 16:10
6

Let's not forget about sequential?:

user=> (sequential? [])
true
user=> (sequential? '())
true
user=> (sequential? {:a 1})
false
user=> (sequential? "asdf")
false
staafl
  • 3,147
  • 1
  • 28
  • 23
4

The function seq right now does only this:

(. clojure.lang.RT (seq coll))

In RT.java in the latest version of Clojure, you'll find:

static public ISeq seq(Object coll){
    if(coll instanceof ASeq)
        return (ASeq) coll;
    else if(coll instanceof LazySeq)
        return ((LazySeq) coll).seq();
    else
        return seqFrom(coll);
}

static ISeq seqFrom(Object coll){
    if(coll instanceof Seqable)
        return ((Seqable) coll).seq();
    else if(coll == null)
        return null;
    else if(coll instanceof Iterable)
        return IteratorSeq.create(((Iterable) coll).iterator());
    else if(coll.getClass().isArray())
        return ArraySeq.createFromObject(coll);
    else if(coll instanceof CharSequence)
        return StringSeq.create((CharSequence) coll);
    else if(coll instanceof Map)
        return seq(((Map) coll).entrySet());
    else {
        Class c = coll.getClass();
        Class sc = c.getSuperclass();
        throw new IllegalArgumentException("Don't know how to create ISeq from: " + c.getName());
    }
}

An ASeq or a LazySeq is already a seq. A Seqable is something that knows how to return a seq of itself.

That leaves things like Java core classes, which should be seqable but which Clojure can't alter to add a seq method. Those are currently hard-coded into this list. I wouldn't be surprised if the implementation changed someday, maybe using protocols to extend the Java core classes instead?

Brian Carper
  • 71,150
  • 28
  • 166
  • 168
0

All seqables implement clojure.lang.Seqable marker:

(instance? clojure.lang.Seqable x)

Clojure 1.9 provides seqable?

VitoshKa
  • 8,387
  • 3
  • 35
  • 59