Почему `(a) читается как список, а `(a b) нет?

Изучая clojure, я был очень удивлен, обнаружив, что эти два объекта относятся к разным типам:

(list? `(inc))   ;; true
(list? `(inc 1)) ;; false

Теоретически я понимаю, почему вторая форма возвращает false, этот объект на самом деле является clojure.lang.Cons. Однако на практике я не понимаю, почему это происходит.

Почему читатель читает `(inc) иначе, чем `(inc 1)? Что происходит под капотом?


person Malabarba    schedule 18.03.2015    source источник
comment
К вкл это не относится, сравните (list? `(a)) с (list? `(a b)). Во всяком случае, (type ..) показывает, что первый — это PersistentList, а второй — Cons. Но почему.. без понятия.   -  person user2864740    schedule 18.03.2015
comment
@CharlesDuffy Ну, я знаю, что в других лиспах, когда второе значение минуса равно nil, это список из одного элемента (т.е. (inc)). Отличается ли это в clojure?   -  person Malabarba    schedule 18.03.2015
comment
@CharlesDuffy (type `(a b c)) также приводит к минусам. Отличается только форма `(singular), которая читается как PersistentList.   -  person user2864740    schedule 18.03.2015
comment
@ user2864740, действительно; Я только что узнал кое-что там.   -  person Charles Duffy    schedule 18.03.2015
comment
(list? '(a b)) возвращает true. Я предполагаю, что синтаксическая цитата не возвращает список, потому что проще реализовать соединение ~@ с общими последовательностями (с concat или чем-то еще). Вероятно, было бы разумнее проверить seq? вместо list?.   -  person DaoWen    schedule 18.03.2015
comment
@DaoWen Возможно. Мне нужен предикат для соответствия спискам или коду в кавычках, но не любой другой коллекции. Это seq?? Я знаю, что он проверяет ISeq, но я не знаю, реализуют ли какие-либо другие коллекции ISeq. (в любом случае, это побочная тема, мне все еще любопытен вопрос)   -  person Malabarba    schedule 19.03.2015
comment
Это интересно: clojuredocs.org/clojure.core/. В любом случае, вам, вероятно, следует просто развернуть свой собственный предикат; например: (defn code? [x] (or (list? x) (instance? clojure.lang.Cons x)))   -  person DaoWen    schedule 19.03.2015
comment
@DaoWen Да, это то, что я делаю, но вопрос не давал мне покоя :-). И эта ссылка действительно немного помогает.   -  person Malabarba    schedule 19.03.2015
comment
Согласно insideclojure.org/2015/01/02/sequences clojure.lang.PersistentList является единственным коллекция, которая реализует ISeq и будет истинной для seq?. (Внизу, начиная чуть выше предикатов и функций.)   -  person Shannon Severance    schedule 19.03.2015
comment
@ShannonSeverance Это странно. Я понимаю, что (seq? `(x y)) верно, а (list? `(x y)) ложно. Что, думаю, противоречит этому.   -  person Malabarba    schedule 19.03.2015
comment
Я не думаю, что clojure.lang.Cons считаются коллекциями, и он реализует ISeq.   -  person Shannon Severance    schedule 19.03.2015
comment
@ShannonSeverance Но он возвращает true coll? :-\   -  person Malabarba    schedule 19.03.2015
comment
Видимо я ошибался. Эффинг Clojure.   -  person Shannon Severance    schedule 19.03.2015
comment
из этой ссылки seq? - проверяет, реализует ли экземпляр ISeq   -  person noisesmith    schedule 19.03.2015


Ответы (2)


Когда читатель сталкивается с формой, заключенной в синтаксические кавычки, которая оказывается коллекцией, он будет .java#L862" rel="nofollow">перебирать каждый элемент и рекурсивно вызывать синтаксическую кавычку. Результат consed, начиная с nil.

Таким образом, возникает вопрос, почему выполняется следующее:

> (list? (cons 'inc nil))
true
> (list? (cons 'inc (cons 1 nil)))
false

Кажется, это вопрос определения.

person Jens    schedule 19.03.2015

list? на самом деле является функцией с очень ограниченной полезностью. На самом деле я еще не видел кода Clojure, в котором использовалось бы list?, но в лучшем случае это был бы плохой выбор, а чаще причина ошибки.

Если вы хотите знать, является ли что-то «списочным», seq? — отличный выбор.

в действии:

user=> (pprint/print-table (for [item [[] () `(a) `(a b) (seq [1])]]
                              {'item (pr-str item)
                               'seq? (seq? item)
                               'list? (list? item)
                               'type (type item)}))
|            item |  seq? | list? |                                           type |
|-----------------+-------+-------+------------------------------------------------|
|              [] | false | false |            class clojure.lang.PersistentVector |
|              () |  true |  true |    class clojure.lang.PersistentList$EmptyList |
|        (user/a) |  true |  true |              class clojure.lang.PersistentList |
| (user/a user/b) |  true | false |                        class clojure.lang.Cons |
|             (1) |  true | false | class clojure.lang.PersistentVector$ChunkedSeq |
person noisesmith    schedule 19.03.2015
comment
Проблема в том, что векторы шизофреничны: они говорят, что они ассоциативны, но они предоставляют последовательность значений, а не пар ключ-значение, под seq. - person Thumbnail; 19.03.2015
comment
Они также говорят, что они seqential?. - person noisesmith; 19.03.2015
comment
Я вижу, что clojure.lang.Sequential пусто, поэтому типы просто выбирают его реализацию. Тем не менее, sequential? лучше, чем seq?, как улучшение по сравнению с list?? - person Thumbnail; 19.03.2015
comment
Я думаю, что спрашивающий должен был бы ответить на это. Я предположил (возможно, ошибочно), что они хотели список вещей, например. вещи, которые будут печататься с помощью () и conj на передний план. - person noisesmith; 19.03.2015