Какие функции в ядре Clojure сохраняют meta?
Вопрос
Meta Clojure сохраняется только в том случае, если функция позаботится об этом, а основные функции Clojure не сохраняют meta глобально.Общее эмпирическое правило, которое я слышал, заключается в том, что функции сбора, такие как conj, assoc и т.д., Должны сохранять meta, но функции последовательности, такие как map, filter, take и т.д., Не сохраняют meta.
Есть ли где-нибудь список того, какие функции сохраняют meta?
Решение
Все дело в типажах.Функции последовательности действуют так, как будто они вызывают seq
зависит от их аргумента и, следовательно, не всегда возвращает объект одного и того же типа.Функции сбора данных и функции, зависящие от типа, не вызывают seq и не возвращают объект того же типа, что и тот, который был им предоставлен.Это как бы создает иллюзию возврата того же объекта (это может быть причиной такого поведения), даже если на самом деле это не так.Мы могли бы сказать, что эмпирическое правило заключается в том, что функция сохраняет meta, когда она сохраняет тип.
user> (meta (seq (with-meta (list 1) {:a 1})))
{:a 1}
user> (meta (seq (with-meta (vector 1) {:a 1})))
nil
Обязательно осознавайте , когда речь заходит о лени .:
user> (type (list 1))
clojure.lang.PersistentList
user> (type (map identity (list 1)))
clojure.lang.LazySeq
user> (meta (seq (with-meta (map identity (list 1)) {:a 1})))
nil
Список функций, которые сохраняют meta в коллекции, см. В разделе структуры данных Страница.Те, которые не сохраняют meta, находятся под последовательности страница, за исключением случаев, когда они возвращают объект того же типа.
Под капотом я не совсем уверен в деталях, поскольку были добавлены лень и фрагментированная последовательность, но вы можете посмотреть на cons
, seq
и seqFrom
методы из RT
класс.Функции, не сохраняющие метаданные, проходят через эти методы.В то время как функции сбора данных в конечном итоге используют методы, специфичные для их типов.