Clojure: выяснение того, является ли сбор некогда

Итак, список?, seq?, vector?, map? и т.д., чтобы определить, какой тип коллекции имеет аргумент.

Какой хороший способ сказать разницу между

  • карта (т.е. что-то, что содержит пары ключ-значение)
  • набор (т.е. что-то, что содержит значения)
  • значение не коллекции, как строка.

Есть ли лучший способ, чем

#(or (seq? %) (list? %) etc)

Ответы

Ответ 1

с использованием seq? примерно так же кратким и чистым, как и он.

clojure.contrib.core определяет:

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

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

он делает то, что вы предложили, с одним большим выражением or

  • уже seq
  • экземпляр clojure.lang.Seqable
  • ноль
  • экземпляр Iterable
  • массив
  • строка
  • экземпляр java.util.Map

Ответ 2

Функция seq прямо сейчас делает следующее:

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

В RT.java в последней версии Clojure вы найдете:

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 или LazySeq уже является seq. A Seqable - это то, что знает, как вернуть себя.

Это оставляет такие вещи, как базовые классы Java, которые должны быть доступны, но которые Clojure не могут изменить, чтобы добавить метод seq. В настоящее время они жестко закодированы в этом списке. Я не удивлюсь, если реализация изменится когда-нибудь, возможно, используя протоколы для расширения классов ядра Java?

Ответ 3

Не забывайте о sequential?:

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

Ответ 4

Все sequables реализуют маркер clojure.lang.Seqable:

(instance? clojure.lang.Seqable x)

Clojure 1.9 обеспечивает seqable?