Как поделиться атомом в макросе в Clojurescript?

У меня есть следующий код в пространстве имен clj (clojure).

(ns project.clojure.clojurescript-макросы)

(def trace-history (atom []))

; hmm, you could run out of memory on recursive functions here?
; Fortunately functions aren't actually recursive in clojure. :]
(defmacro push-args [name args]
  `(swap! trace-history
     (fn [stack#]
       (conj stack# [~name (zipmap ~(vec (map str args)) ~args)]))))

(push-args :hello [:a :b :c])

в другом пространстве имен cljs (clojurescript) у меня есть следующие

(ns project.clojurescript.user   
  (:require-macros [project.clojure.clojurescript-macros :as c]))

(c/push-args :hello [:a :b :c])

Я компилирую свой код clojurescript и открываю его в своем браузере. К сожалению, я получаю следующую ошибку.

Uncaught TypeError: Cannot read property 'trace_history' of undefined main.js:22348
(anonymous function)                                                  main.js:22348

Глядя на строку 22348 в моем скомпилированном коде clojurescipt, я вижу следующее.

cljs.core.swap_BANG_.call(null, project.clojure.trace_history, function(stack__6402__auto__) {
  return cljs.core.conj.call(null, stack__6402__auto__, 
    cljs.core.PersistentVector.fromArray(["\ufdd0'hello", 
      cljs.core.zipmap.call(null, 
        cljs.core.PersistentVector.fromArray([":a", ":b", ":c"], true),          
        cljs.core.PersistentVector.fromArray(["\ufdd0'a", "\ufdd0'b", "\ufdd0'c"], 
      true))], 
    true))
  });

Проблема в том, что project.clojure.trace_history нигде не определено в main.js. Я понимаю, что не так, но не знаю, как это исправить. Я пробовал другие решения, такие как размещение истории трассировки в общем файле clojure и запись истории трассировки в сам файл cljs. Кажется, ничего не работает. Учитывая, что я хочу иметь общий глобальный атом между всеми компиляциями этого макроса, как я могу сделать это в Clojurescript?


person Stephen Cagle    schedule 02.10.2012    source источник
comment
Просто любопытно, почему push-args - это макрос? Я не вижу, чтобы он делал что-то такое, что функция не могла бы делать так же хорошо с тем же синтаксисом, а макросы гораздо труднее рассуждать, особенно в ClojureScript.   -  person levand    schedule 02.10.2012
comment
В моем коде args на самом деле является списком аргументов, переданным моему настраиваемому макросу defn (который в основном просто вызывает defn). Я пытаюсь объединить [fx-name {map of fx-names arguments / values}] в переменную trace-history каждый раз, когда вызывается одна из моих настраиваемых функций defn (и убирать значение при успешном запуске функции) . Затем, когда утверждение не выполняется, я могу распечатать историю трассировки и, надеюсь, легче диагностировать, почему утверждение не удалось. Подобен отладчику, но доступен, когда включены утверждения.   -  person Stephen Cagle    schedule 02.10.2012


Ответы (1)


Атом - это данные времени выполнения, макрос - конструкция времени компиляции. На самом деле для макроса не имеет смысла иметь «общий глобальный атом» - ваш макрос там компилируется в код, который просто ожидает наличия символа с именем trace-history в текущем NS.

Если вы просто хотите написать общий код, который может использовать атом, вы должны написать его так, чтобы он мог принимать атом в качестве аргумента, а не предполагать его существование через жестко заданное имя символа.

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

person levand    schedule 02.10.2012
comment
Да, было бы неплохо иметь возможность разделить атом между клиентом и сервером, но это не то, что мне нужно. Думаю, я мог бы разделить атом между макросами, но теперь это потребует передачи атома повсюду, не так ли? Я думаю, что нет никакого способа разделить атом во время выполнения, поскольку макрос раскрывается (и, как таковой, потребуется атом) во время компиляции, я думаю? - person Stephen Cagle; 02.10.2012
comment
Да, ты прав. Если бы мы говорили о функциях, было бы лучше использовать партиал. На самом деле нет эквивалента для макросов, потому что они просто преобразования источника в источник и не имеют понятия данных, прикрепленных к ним. Самое близкое, что вы можете получить, - это то, что у вас уже есть; Предположим, что в текущем пространстве имен будет определенный символ. - person levand; 02.10.2012