Сохранение + чтение отсортированных карт в файл в Clojure

Я сохраняю вложенную карту данных на диск через spit, Я хочу, чтобы некоторые карты внутри моей карты сортировались и оставались отсортированными, когда я slurp карта обратно в мою программу. Сортированные карты не имеют уникального буквального представления, поэтому, когда я spit карта карт на диске, отсортированные карты и несортированные карты представлены одинаково, и #(read-string (slurp %))Использование данных делает каждую карту обычным несортированным типом. Вот игрушечный пример, иллюстрирующий проблему:

(def sorted-thing (sorted-map :c 3 :e 5 :a 1))
;= #'user/sorted-thing
(spit "disk" sorted-thing)
;= nil
(def read-thing (read-string (slurp "disk")))
;= #'user/read-thing

(assoc sorted-thing :b 2)
;= {:a 1, :b 2, :c 3, :e 5}
(assoc read-thing :b 2)
;= {:b 2, :a 1, :c 3, :e 5}

Есть ли какой-нибудь способ прочитать карты как отсортированные в первую очередь, вместо преобразования их в отсортированные карты после чтения? Или это признак того, что я должен использовать какую-то реальную базу данных?

2 ответа

Решение

*print-dup* динамически перебираемый Var предназначен для поддержки этого варианта использования:

(binding [*print-dup* true]
  (prn (sorted-map :foo 1)))
; #=(clojure.lang.PersistentTreeMap/create {:foo 1})

Закомментированная строка - это то, что печатается.

Так получилось, что это тоже влияет str применительно к структурам данных Clojure, и, следовательно, также spitтак что если вы делаете

 (binding [*print-dup* true]
   (spit "foo.txt" (sorted-map :foo 1)))

представление карты, записанное в foo.txt будет отображаться выше.

Правда, я не уверен на 100%, задокументировано ли это где-то; если вы чувствуете себя неловко по этому поводу, вы всегда можете spit результат использования pr-str с *print-dup* связан с true:

(binding [*print-dup* true]
  (pr-str (sorted-map :foo 1)))
;= "#=(clojure.lang.PersistentTreeMap/create {:foo 1})"

(На этот раз последняя строка - это возвращаемое значение, а не вывод на печать.)

Очевидно, вам придется иметь *read-eval* связан с true чтобы иметь возможность читать обратно эти литералы. Это хорошо, хотя, это именно то, для чего он предназначен (чтение кода из надежных источников).

Я не думаю, что это обязательно знак того, что вы должны использовать базу данных, но я думаю, что это признак того, что вы не должны использовать spit, Когда вы записываете отсортированные карты на диск, не используйте буквальный синтаксис карты. Если вы напишите его в следующем формате, будет работать read-string:

(def sorted-thing (eval (read-string "(sorted-map :c 3 :e 5 :a 1)")))
(assoc sorted-thing :b 2)
;= {:a 1, :b 2, :c 3, :e 5}
Другие вопросы по тегам