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?