Clojure + Proce55ing(4)
Follow1 - 2
クロージャーに全体をいれてしまうと少しは見やすいか?Python で self を明示的に渡すときのようなコードになってるけど。
- Processing の場合は、全体が PApplet のサブクラスとして書かれる。グローバル変数に見えるものは実際はインスタンスフィールド、関数に見えるものは実際はインスタンスメソッド。Processing でクラス定義を書くと実際は内部クラス。
- 下の clojure で書いた例は、setup, draw とも外部の関数 setup_fn, draw_fn を呼び出しているので厳密にはオリジナルと構成がことなる。Java 的には this をまるごと渡しているあまり行儀のよろしくないコード。
- いまの自分の理解では、 clojure では static クラスメソッド(以下の例では cos, sin など)と、インスタンスメソッドの呼び出し方は使い分けないとエラーになる。これは嫌すぎる。
- PApplet の JavaDoc. 巨大なクラスで山ほどメソッドがある。 http://dev.processing.org/reference/core/javadoc/processing/core/PApplet.html
- cos は実際は Math.cos を呼んでいるだけ。
(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))))
資料
- http://blog.thinkrelevance.com/2008/9/16/pcl-clojure Practical Common Lisp を Clojure で。これは役に立ちそう。
- http://www.atmarkit.co.jp/fwcr/design/tool/processing01/03.html AtmarkIT の Processing 記事。
Follow1 - 1
とりあえず http://www.proce55ing.org/learning/topics/follow1.html が Clojure で書けるようになった。
- Clojure では基本的になんでもイミュータブル。Var と Ref と Java クラスのフィールドだけが変更可能、らしい。
- Ref は言語なのに「トランザクション」なんて概念が出てくる。ぜんぜん理解していないがなんともモダーンな香り。
- gen-class というAPIでクラスを定義できるようだがこちらはまだ使い方が分からない。
- 以下はメソッドを使っているけど ref も使っているというまだ中途半端な例。
- clojure-mode.el を入手。インデントがちょっと不満。設定によるかも。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 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)))