开发者

Clojure: finding out if a collection is seq-able

开发者 https://www.devze.com 2023-01-22 10:32 出处:网络
So there\'s list?, seq?, vector?, map? and so on to determine what type of collection the argument is.

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)


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


Let's not forget about sequential?:

user=> (sequential? [])
true
user=> (sequential? '())
true
user=> (sequential? {:a 1})
false
user=> (sequential? "asdf")
false


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?


All seqables implement clojure.lang.Seqable marker:

(instance? clojure.lang.Seqable x)

Clojure 1.9 provides seqable?

0

精彩评论

暂无评论...
验证码 换一张
取 消