【问题标题】:Clojure Agent question - using send-offClojure 代理问题 - 使用发送
【发布时间】:2011-08-23 07:51:33
【问题描述】:

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

(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))
    

【问题讨论】:

    标签: clojure agents


    【解决方案1】:

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

    展示 Clojure 的动态特性。

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

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

    【讨论】:

    • 感谢您的解释。这里真的有必要使用#'animation Var吗?如果没有,为什么要打扰?如果是,为什么会这样?当一个函数不纯/有一些隐藏状态/有副作用时是否需要它?
    【解决方案2】:

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

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

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

    2. 这里要理解的一件重要的事情是代理模型。代理可以被认为是在单个可变单元上操作的工人。该代理有一个工作队列(功能队列)要做。发送和发送添加工作到该队列。由于发送只是将工作添加到队列中,因此它会立即返回。由于代理仅按顺序执行功能,因此第一个动画调用必须在执行下一个动画调用之前完成。因此,无论是先送行还是最后送行,您都能实现基本相同的目标。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-11
      • 2020-03-07
      相关资源
      最近更新 更多