Clojure Agent问题 - 使用发送

时间:2011-05-11 13:24:49

标签: clojure agents

我对以下代码有几个问题:

(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)
  1. 在动画功能中 - 为什么在发送动画之前使用#'
  2. 为什么动画功能开始时send-off有效?它不应该再次开始动画功能,永远不会执行重绘和睡眠方法吗?
  3. 与原作相比,将动画功能写成:

    是否有任何不利之处
    (defn animation 
      [x]
      (. panel (repaint))
      (. Thread (sleep 100))
      (send-off *agent* animation))
    

2 个答案:

答案 0 :(得分:8)

在动画功能中 - 为什么在发送动画之前使用#'?

展示Clojure的动态性。

表单#'animation是一个Var,是Clojure的可变引用类型之一。 defn宏创建一个Var。为方便起见,调用引用函数的Var与调用函数本身相同。但是,与功能不同,Var可以改变!我们可以在Clojure REPL重新定义#'animation并立即看到效果。

使用(send-off *agent* #'animation)强制Clojure每次都查找#'animation Var的当前值。如果代码使用(send-off *agent* animation)代替,那么Clojure只会查找一次值,并且不能在不停止循环的情况下更改动画功能。

答案 1 :(得分:3)

1.这对我来说有点不清楚,但似乎是Rich的设计决定。如果您注意到:

user=> (defn x [y] (+ y 2))
#'user/x
user=> ((var x) 3)
5

如果var位于函数/宏位置,它最终将解析为函数或宏。

2.这里要理解的一件重要事情是代理模型。可以将代理视为在单个可变细胞上操作的工作者。该代理程序有一个工作队列(函数队列)。发送和发送添加工作到该队列。由于send-off仅向队列添加工作,因此会立即返回。由于代理仅以串行方式执行功能,因此第一个动画调用必须在执行下一个动作之前完成。因此,无论是先发送还是最后发送都能达到基本相同的目的。

3.两者之间应该没有明显的区别。