Clojure: выяснить, является ли коллекция последовательной - PullRequest
13 голосов
/ 26 октября 2010

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

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

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

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

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

Ответы [ 4 ]

9 голосов
/ 26 октября 2010

с использованием 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 утверждением

  • уже следующий
  • экземпляр clojure.lang.Seqable
  • ноль
  • экземпляр Iterable
  • массив
  • строка
  • экземпляр java.util.Map
4 голосов
/ 06 августа 2016

Давайте не будем забывать о sequential?:

user=> (sequential? [])
true
user=> (sequential? '())
true
user=> (sequential? {:a 1})
false
user=> (sequential? "asdf")
false
4 голосов
/ 26 октября 2010

Функция 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 уже является следствием.Seqable - это то, что знает, как вернуть последовательность из себя.

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

0 голосов
/ 25 июня 2017

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

(instance? clojure.lang.Seqable x)

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

...