Clojure Agent вопрос - используя рассылку
У меня есть пара вопросов по поводу следующего кода:
(import
'(java.awt Color Graphics Dimension)
'(java.awt.image BufferedImage)
'(javax.swing JPanel JFrame))
(def width 900)
(def height 600)
(defn render
[g]
(let [img (new BufferedImage width height
(. BufferedImage TYPE_INT_ARGB))
bg (. img (getGraphics))]
(doto bg
(.setColor (. Color white))
(.fillRect 0 0 (. img (getWidth)) (. img (getHeight)))
(.setColor (. Color red))
(.drawOval 200 200 (rand-int 100) (rand-int 50)))
(. g (drawImage img 0 0 nil))
(. bg (dispose))
))
(def panel (doto (proxy [JPanel] []
(paint [g] (render g)))
(.setPreferredSize (new Dimension
width
height))))
(def frame (doto (new JFrame) (.add panel) .pack .show))
(def animator (agent nil))
(defn animation
[x]
(send-off *agent* #'animation)
(. panel (repaint))
(. Thread (sleep 100)))
(send-off animator animation)
- В функции анимации - почему
#'
Использовали до анимации при отправке? - Почему
send-off
в начале анимации работают функции? Разве он не должен просто снова запускать функцию анимации и никогда не выполнять методы repaint и sleep? Есть ли какой-либо недостаток по сравнению с оригиналом при написании функции анимации:
(defn animation [x] (. panel (repaint)) (. Thread (sleep 100)) (send-off *agent* animation))
2 ответа
В функции анимации - почему # используется перед анимацией при отправке?
Чтобы продемонстрировать динамический характер Clojure.
Форма #'animation
это Var, один из изменяемых ссылочных типов Clojure. defn
макрос создает переменную Для удобства вызов Var, который ссылается на функцию, аналогичен вызову самой функции. Но Var, в отличие от функции, может измениться! Мы могли бы переопределить #'animation
на Clojure REPL и сразу увидеть эффекты.
С помощью (send-off *agent* #'animation)
заставляет Clojure посмотреть текущее значение #'animation
Вар каждый раз. Если код использовал (send-off *agent* animation)
вместо этого Clojure будет искать значение только один раз, и будет невозможно изменить функцию анимации без остановки цикла.
1.
Это также немного неясно для меня, но кажется, что это дизайнерское решение Рича. Если вы заметили:
user=> (defn x [y] (+ y 2))
#'user/x
user=> ((var x) 3)
5
Если переменная находится в местоположении функции / макроса, она в конечном итоге преобразуется в функцию или макрос.
2.
Здесь важно понять одну модель агента. Агенты могут рассматриваться как работники, работающие с одной изменяемой ячейкой. Для этого агента есть очередь работы (очередь функций). отослать и отправить добавить работу в эту очередь. Поскольку отправка только добавляет работу в очередь, она немедленно возвращается. Поскольку агент выполняет только функции последовательно, первый вызов анимации должен завершиться перед выполнением следующего. Таким образом, вы достигаете в основном одного и того же, независимо от того, отправляете ли вы отправку первым или последним.
3.
Не должно быть заметной разницы между ними.