Clojure вложенные карты. Доступ родительский ключ из значения - PullRequest
0 голосов
/ 20 марта 2020

Я новичок в Clojure. Этот вопрос относится к этому , но отличается. Скажем, у меня есть вложенная карта:

(def example
  {:a {:b 2 :data [1 2 3] :something-that-uses-data ?}})

И, предположим, я хочу получить доступ (-> example :a :b :data) в :something-that-uses-data. Должен ли я называть это точно так же, если есть какие-то макросы или ключевое слово (что-то вроде (-> this :data))? Ничего не могу найти пару часов.

Ответы [ 2 ]

0 голосов
/ 20 марта 2020

Я не уверен, что понимаю вопрос. Можете ли вы отредактировать, чтобы уточнить желаемое поведение?

Существует 3 способа доступа к глубоким структурам данных в библиотеке Tupelo.

  • Использование tupelo.forest для обработки дерева- как структуры данных. См. Документы и обязательно посмотрите видео.

  • Вы можете использовать tupelo.core/destruct, что является более привлекательной версией get-in с использованием шаблона. См. примеры здесь .

  • Вы можете выполнить первую глубину обхода вашей структуры данных, отслеживая родителей каждого узла, используя walk-with-parents. См. примеры и документы .


Доступ к родителям вложенного элемента данных

Вы можете сделать это, используя walk-with-parents и walk-with-parents-readonly. Рассмотрим следующую простую вложенную структуру данных:

(def data {:a 1 :b {:c 3}} )

Мы можем пройти структуру данных, запоминая путь от root к каждому элементу. Когда мы добираемся до элемента 3, у нас есть следующий путь родительских данных:

(walk-with-parents data <noop-intc>) =>

:parents => [ {:a 1, :b {:c 3}}   ; the orig map
              [:b {:c 3}]         ; the MapEntry for key :b
              {:c 3}              ; the map where value 3 
              [:c 3] ]            ; the MapEntry with value 3
:data => 3

Таким образом, перехватчик будет вызываться с двумя аргументами:

  • вектор пути родителей из 4 элементов
  • сам элемент данных

Для варианта -readonly функция перехватчика может выполнить проверку и выдать исключение в случае обнаружения проблемы. Для варианта без чтения возвращаемое значение заменяет элемент данных. Каждый перехватчик представляет собой двухэлементную карту, которая выглядит следующим образом:

{:enter (fn [parents data] ...)
 :leave (fn [parents data] ...) }
0 голосов
/ 20 марта 2020

Я думаю, что вы пытаетесь подражать объектам в Clojure. У объектов есть данные и функции, работающие с этими данными, упакованными вместе в классе, но в функциональных языках, таких как Clojure, данные и функции разделены.

Таким образом, идиоматический способ в Clojure - это функциональный подход, то есть просто функции, работающие с неизменяемыми данными. Единственная функция OO в Clojure - это протоколы, которые используются для полиморфизма.

Я думаю, что вы хотите в своем примере это:


(def example
  {:a {:b 2 :data [1 2 3]}})

(defn something-that-uses-data [{{:keys [data] :a}}]
  (do-work-with data))

Конечно, вы можете иметь карту, которая содержит данные и функции, но она будет полезна, только если функции разные и Вы хотите применить эти функции в последовательном контексте. Примерно так ... но я только догадываюсь, какой у тебя может быть контекст.

  (map (fn [[k v]
         (let [data (:data v)
               f (:somthing-that-uses-data v)]
           (f data)))
       collection-of-maps)
...