Clojure + Proce55ing(4)

cranebird2008-11-01


Follow1 - 2

クロージャーに全体をいれてしまうと少しは見やすいか?Python で self を明示的に渡すときのようなコードになってるけど。

  • Processing の場合は、全体が PApplet のサブクラスとして書かれる。グローバル変数に見えるものは実際はインスタンスフィールド、関数に見えるものは実際はインスタンスメソッド。Processing でクラス定義を書くと実際は内部クラス。
  • 下の clojure で書いた例は、setup, draw とも外部の関数 setup_fn, draw_fn を呼び出しているので厳密にはオリジナルと構成がことなる。Java 的には this をまるごと渡しているあまり行儀のよろしくないコード。
  • いまの自分の理解では、 clojure では static クラスメソッド(以下の例では cos, sin など)と、インスタンスメソッドの呼び出し方は使い分けないとエラーになる。これは嫌すぎる。
(let [angle1 (ref (float 0.0))
      x (ref (float 100))
      y (ref (float 100))
      segLength (float 50)]

  (defn segment [#^PApplet pa x y a]
    (doto pa
      (pushMatrix)
      (translate x y)
      (rotate a)
      (line 0 0 segLength 0)
      (popMatrix)))
 
  (defn fn_draw [#^PApplet pa]
    (. pa background 226)
    (dosync
     (let [mx (. pa mouseX)
	   my (. pa mouseY)
	   dx (- mx @x)
	   dy (- my @y)]
       (ref-set angle1 (. PApplet atan2 dy dx))
       (ref-set x (float (- mx (* (. PApplet cos @angle1) segLength))))
       (ref-set y (float (- my (* (. PApplet sin @angle1) segLength))))
       (segment pa @x @y @angle1)
       (. pa ellipse @x @y 20 20))))

  (defn fn_setup [#^PApplet pa]
    (doto pa
      (size 200 200)
      (smooth)
      (strokeWeight 20.0)
      (stroke 0 (float 100.0)))))

(defn make-follow1 []
  (proxy [PApplet] []
	 (setup [] (fn_setup this))
	 (draw [] (fn_draw this))))

資料

Follow1 - 1

とりあえず http://www.proce55ing.org/learning/topics/follow1.htmlClojure で書けるようになった。

  • Clojure では基本的になんでもイミュータブル。Var と Ref と Java クラスのフィールドだけが変更可能、らしい。
  • Ref は言語なのに「トランザクション」なんて概念が出てくる。ぜんぜん理解していないがなんともモダーンな香り。
  • gen-class というAPIでクラスを定義できるようだがこちらはまだ使い方が分からない。
  • 以下はメソッドを使っているけど ref も使っているというまだ中途半端な例。
  • clojure-mode.el を入手。インデントがちょっと不満。設定によるかも。
  • Lisp (Clojure) でプロトタイピングしてるうちに Magnetosphere が作れると素晴らしいが。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Follow 1 in Clojure.
;; This code is based on follow1 in http://www.proce55ing.org/learning/topics/follow1.html,
;; and follow1 is based on code from Keith Peters (www.bit-101.com).

(import '(processing.core PApplet))
(import '(javax.swing JFrame))

(def x (ref (float 100)))
(def y (ref (float 100)))
(def angle1 (ref (float 0.0)))
(def segLength (float 50))

(defn segment [#^PApplet p x y a]
  (doto p
    (pushMatrix)
    (translate x y)
    (rotate a)
    (line 0 0 segLength 0)
    (popMatrix)))

(defn make-follow1 []
  (proxy [PApplet] []
	 (setup []
		(doto this
		  (size 200 200)
		  (smooth)
		  (strokeWeight 20.0)
		  (stroke 0 (float 100.0))))
	 (draw []
	       (. this background 226)
	       (dosync	  
		(let [dx (- (. this mouseX) @x)
		      dy (- (. this mouseY) @y)]
		  (ref-set angle1 (. PApplet atan2 dy dx))
		  (ref-set x (float (- (. this mouseX)
				       (* (. PApplet cos @angle1) segLength))))
		  (ref-set y (float (- (. this mouseY)
				       (* (. PApplet sin @angle1) segLength))))
		  (segment this @x @y @angle1)
		  (. this ellipse @x @y 20 20))))))

(defn show-follow1 []
  (let [f (new JFrame)
        p (make-follow1)]
    (doto f
      (setSize 200 200)
      (add p)
      (setVisible true))
    (. p init)))