Clojure, агент, отсутствие побочных эффектов - PullRequest
2 голосов
/ 11 июля 2011

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

Все сообщения отправлены (я их распечатал и посчитал), но бывают случаи, когда у меня не хватает всех побочных эффектов. Как будто не все мои функции были применены к состоянию агента, или если последняя отправка была применена к предыдущему состоянию ..

Я экспериментировал с doall, dorun, но не нашел решения, благодарю за любую помощь.

;; aux function for adding an element to a hashmap 
(defn extend-regs [reg s o]
  (let [os (get reg s)]
    (if (nil? os)
      (assoc reg s [o])
      (assoc reg s (conj os o)))))

;; the agent's altering function - adding an element to the :regs field(a hashmap)
(defn add-reg! [d s o]
  (send d (fn [a] (assoc a :regs (extend-regs (:regs a) s o)))))



;; Creating the agents, dct/init returns an agent
;; pds: data for fields
(defn pdcts->init-dcts! [pds]
  (doall (map dct/init (map :nam pds) (repeat nil))))

;; Altering one agent's state,  dct/add-reg  sends an assoc message to the agent
;; d: agent,  pd: data for fields
(defn dct->add-regs! [d pd]
  (dorun (map (fn [s r] (dct/add-reg! d s r))
          (:syms pd)
          (:regs pd)))
  d)

;; Going through all agents
;; ds: agents,  pds: datas
(defn dcts->add-regs! [ds pds]
  (dorun (map (fn [d pd] (dct->add-regs! d pd))
          ds
          pds))
  ds)

РЕДАКТИРОВАТЬ: =================================================== ========

Хорошо, оказалось, что я просто не дождался, пока мои потоки завершат свои задачи. Теперь вопрос в том, как я могу контролировать своих агентов. Как я могу узнать, что в очереди есть незавершенные темы? Я нашел только swank.core / active-threads и подобные, но они не являются решением.

Ответы [ 2 ]

2 голосов
/ 12 июля 2011

У меня нет решения вашей проблемы, но я не могу удержаться, предлагая некоторое улучшение первых двух функций:

(defn extend-regs [reg s o]
  (let [os (get reg s)]
    (if (nil? os)
      (assoc reg s [o])
      (assoc reg s (conj os o)))))
;; => place the 'if inside the assoc:
(defn extend-regs [reg s o]
  (let [os (get reg s)]
    (assoc reg s (if (nil? os) [o] (conj os o)))))
;; => this (if (nil? x) ...) is the pattern of function fnil, so ...
(defn extend-regs [reg s o]
  (let [os (get reg s)]
    (assoc reg s ((fnil conj []) os o))))
;; with update-in, this will be even clearer, and we can remove the let altogether:
(defn extend-regs [reg s o]
  (update-in reg [s] (fnil conj []) o))

Что касается второго:

(defn add-reg! [d s o]
  (send d (fn [a] (assoc a :regs (extend-regs (:regs a) s o)))))
;; => We can, again, use update-in instead of assoc:
(defn add-reg! [d s o]
  (send d (fn [a] (update-in a [:regs] extend-regs s o))))
;; or, if you can get rid of extend-regs:
(defn add-reg! [d s o]
  (send d (fn [a] (update-in a [:regs s] (fnil conj []) o)))

Наконец, в качестве стиля я бы поместил add-reg в отдельную функцию и напрямую использовал идиому отправки агенту в клиентском коде (или использовал бы упрощенную функцию add-reg!):

(defn add-reg [v s o] (update-in v [:regs s] (fnil conj []) o))

(defn add-reg! [d s o] (send d add-reg))

Я знаю, что это не отвечает на ваш первоначальный вопрос, но было интересно написать этот шаг за шагом рефакторинг

1 голос
/ 14 июля 2011

Используйте await или await-for , чтобы дождаться, когда агент закончит свою текущую рабочую очередь:

(await agent1 agent2 agent3)

или

(apply await list-of-agents)

Незначительное улучшение адд-рег:

(defn extend-regs [reg s o]
  (update-in reg [s] conj o))

Это работает из-за

(conj nil :b)               ; => [:b] 

таким образом

(update-in {} [:a] conj :b) ; => {:a [:b]}

наконец-то имеем.

(defn add-reg! [d s o]
  (send d update-in s [:regs] conj o)
...