WindowsでClojure

鉄分豊富な人が遊びにやって来た。一泊して酒を酌み交わし親交を深めた訳であるが、翌日はどうすべ? って、話になったよ。そこはそれ、磁石に吸い寄せられるように、大宮にある 鉄道博物館 へ、行ってみようとあっさり決まった。実はおいらも行った事無いんだよね。(昔々、秋葉原と言うか神田の それには行ったけど)

ちょいっと早めに着いたけど、長蛇の列になってましたよ。列の大半は小さい子供さんを伴った家族連れ。 おいらみたいな、中年おじさん連は浮いていた。自動発券機で1000円のスイカもどきのカードを買って 改札を通りました。本物のスイカも勿論使えます。

家族連れのお目当ては、各種シュミレーターの予約券Getで、列を成してました。TDLみたいな雰囲気 ですな。おいら達は、まずは2階へ、一番乗りでした。壁に沿って、鉄道の歴史が展示されてて、思わず 昔にトリップしてしまいましたよ。そして、一角には、日本一大きいと言うジオラマ(鉄道模型)室が ありました。鉄道の一日を約10分に渡って解説してました。始発電車、始発新幹線が動き出し、夕刻には 夜行寝台の北斗星とかが動き、ああ、あれに乗って北海道まで行ったなあなんて思いだしました。 また、資料室は地味だけど、ヘッドプレート等がたくさん展示されてて面白かった。国鉄が終了する時 の、さおようなら国鉄(1987.3.31)、よろしくJR(1987.4.1)のプレートが感慨深いでした。

一階には、お召し列車の展示とかSLとかいろいろあって、全部乗ってみるとどのくらい時間がかかる のだろう? 連れは何度も来たいと申しておりました。12時から始まる、SL機関車の転回台運用は 必見です。途中で鳴らす汽笛が何とも言えないいい味を出してましたね。

昼は中で売っている駅弁を買って食べるべし。いろいろあって迷っちゃうぞ。いろいろ買ってお土産に するのもいいかも。おいらは、お土産に、石炭あられ(竹炭入りで石炭とそっくり、土産で一番人気とか)と、銚子 電鉄のぬれせんべいを買いました。連れは、2Fのショップでしか手に入らないというグッズ類を 大量に買ってましたよ。

WindowsでClojure

今までずっと歴史物をやっていたけど、そろそろ飽きてきたので現代に戻ります。暫く前にClojureが 1,1から1.2になりました。Wnidowsに入れている Clojure-Box でも、1.2にしようと思って、*.jarだけ1.2に入れ替えたのはいいんだけど、構成が変わって微妙な 警告が出てくるようになりました。このまま使っていてもいいんだろうけど、ちと気分が悪いので 新たに入れなおしました。 あの人 も始めたようですし、本も読み直しています。

で、どうせ整備するなら、少し使いやすいようにしようと、環境整備編に(性懲りもなく)走って しまうのでした。何するか? WindowsだってLein使いたいよね。Leinって、Clojure界のデブロイ 環境です。(あっ、正確には開発環境だけど、おいらは、出来上がったjarファイルをひとまとまりに して、Clojureも入っていないPCに持って行ける事に価値を見出しています)

github に行って、lein-win32.zipとleiningen-1.3.1-standalone.jarを落としてきて、適当なdirに両者を 入れ、Pathを通せば出来上がり。使い方と言うかサブコマンドは、Lein help すれば出てきます。

余勢を駆ってFreeBSDでも

やってみよう。Linuxでの解説はいろいろあるもんで。。。

問題は、Windows上にあるClojure-boxもどきをどう作るかです。emacsには便利な ELPA と言うのが提供されているので、今回はこれを利用する事にします。

まず上記の指示に従って、パッケージリストを取り寄せます。emacsを再起動してから M-x package-list-package すると、インストール可能なパッケージが出てくるので、swank-clojureと pareditの所で I を押します。(インストールするパッケージの選択)続いて X を押すと、実行 (インストール)されます。途中でエラーが発生するかも知れませんが無視しても大丈夫です。 これで、関連する便利パッケージも自動的に入ります。emacsでファイルを閲覧する時にキー操作が 面倒だと思ったら、ついでに less も入れておくといいです。M-x less-minner-mode すれば、emacsがless に変身してくれます。Windowsみたいな貧弱な環境だと超便利!

paredit-modeは、開き括弧に対する閉じ括弧(いわゆるコッカ)を自動で挿入してくれる 機能があります。また文字列を囲むダブルクォートも2つ自動で挿入してカーソルがその間に位置 してくれるので、カッコやダブルクォートの閉じ忘れを防止出来ます。設定は、.emacsに

(autoload 'paredit-mode "paredit"
      "Minor mode for pseudo-structurally editing Clojure code." t)
    (add-hook 'clojure-mode-hook     (lambda () (paredit-mode +1)))
    (add-hook 'slime-repl-mode-hook  (lambda () (paredit-mode +1)))

と書いておきます。

ついでに、leinも入れておくと吉。lein new project-nameした後、project-name-dir内に自動 生成される project.cljに

   :dev-dependencies [[swank-clojure "1.3.0-SNAPSHOT"]]

を追加し、lein depsすると、便利機能が追加されます。

こうしておいて、lein swankした後で、emacsを起動し、slime-connect すると、便利です。

例題

clojure本もいいけど、もっと他にないかと探してみると

八発白中

に、L5という面白いものが掲載されてた。試してみよっと。

試してみた。FreeBSDで作った L5.jar をWindowsへ持ってきて、サンプルを動かしてみたらちゃんと 動いた。これぞClojure(Java)の威力。(jarファイルのダブルクリックで、起動するなんて、ちょっと びっくりです。これって、leinが気を利かせてくれてるから?)

秋だから絵を描こう

(ns simple-plotter
  (:import (javax.swing JFrame JPanel )
           (java.awt Color Graphics Graphics2D Image))
  (:use (clojure.contrib def)))

;; This is an attempt to make graphics in clojure as simple as it was on a ZX
;; Spectrum. Let us count the whole maven/leiningen/cake-clojure-emacs-(require
;; 'simple-plotter) thing as being a one-time effort equivalent to persuading
;; one's father to buy a ZX Spectrum in the first place.

;; Define some colours to use:
;; java.awt.Color/GREEN -> simple-plotter/green

(defmacro- defcolours [& colours]
  (list* 'do (map #(list 'def  (symbol (. (str %) toLowerCase)) (symbol (str "Color/" (str %)))) colours)))

(defcolours black blue cyan darkGray gray green lightGray magenta orange pink red white yellow)

;; Private machinery

(defn- draw-lines [lines #^Graphics2D g2d xs ys]
  (doseq [[x1 y1 x2 y2 color] @lines]
    (. g2d setColor color)
    (. g2d drawLine (* xs x1) (* ys y1) (* xs x2) (* ys y2))))

(defn- render-lines-to-graphics [lines paper-color height width
                                 #^Graphics2D g w h ]
  (doto g
    (.setColor @paper-color)
    (.fillRect 0 0 w h))
    (draw-lines lines g (/ w @width) (/ h @height)))

(defn- primitive-repaint [plotter]
  (. (plotter :panel) repaint))

(defn create-plotter [title width height ink paper]
  (let [lines       (atom [])
        height      (atom height)
        width       (atom width)
        paper-color (atom paper)
        panel       (proxy [JPanel] []
                      (paintComponent [g]
                                      (proxy-super paintComponent g)
                                      (render-lines-to-graphics
                                       lines paper-color height width
                                       #^Graphics2D g
                                       (. this getWidth)
                                       (. this getHeight))))
        frame (JFrame. title)]
    (doto frame
      (.add panel)
      ;; The extra space 2,32 is taken up by the window decorations
      ;; in GNOME. How to get that from the OS? 
      (.setSize (+ @width 2) (+ @height 32))
      (.setVisible true))
    {:height height
     :width  width
     :ink-color (atom ink)
     :paper-color paper-color
     :current-position (atom [0,0])
     :lines lines
     :panel panel}))


(defn- primitive-line [plotter x1 y1 x2 y2]
  (let [ink @(:ink-color plotter)]
    (swap! (:lines plotter) conj [x1 y1 x2 y2 ink]))
  (primitive-repaint plotter))

(defn- set-paper-color [plotter color]
  (swap! (plotter :paper-color) (constantly color))
  (primitive-repaint plotter))

(defn- set-ink-color [plotter color]
  (swap! (plotter :ink-color) (constantly color)))

(defn- set-current-position [plotter [x y]]
  (swap! (plotter :current-position) (constantly [x y])))

(defn- remove-lines [plotter] (swap! (plotter :lines) (constantly [])))

(defn- make-scalars [points xleft xright ytop ybottom]
  (let [xmax (reduce max (map first points))
        xmin (reduce min (map first points))
        ymax (reduce max (map second points))
        ymin (reduce min (map second points))]
    [(fn[x] (+ xleft (* (/ (- x xmin) (- xmax xmin))    (- xright xleft))))
     (fn[y] (+ ybottom  (* (/ (- y ymin) (- ymax ymin)) (- ytop ybottom))))]))


(defvar- current-plotter (atom nil))

;; ;; Public Interface

(defn create-window
  ([] (create-window "Simple Plotter"))
  ([title] (create-window title 1024 768))
  ([title width height] (create-window title width height white black ))
  ([title width height ink paper]
     (let [plotter (create-plotter title width height ink paper)]
       (swap! current-plotter (constantly plotter))
       plotter)))

;;Makes a version of a function with an implicit first argument of plotter, and
;;a default version with no first argument is not supplied, and which uses
;;current-plotter instead.
(defmacro ddefn [fnname args & body]
  `(defn ~fnname
     (~args (~fnname @~'current-plotter ~@args))
     ([~'plotter ~@args] ~@body)))

(ddefn plot [x1 y1]
       (primitive-line plotter x1 y1 x1 y1)
       (set-current-position plotter [x1 y1]))

(ddefn cls [] 
       (remove-lines plotter)
       (primitive-repaint plotter))

(ddefn plot [x1 y1]
     (primitive-line plotter x1 y1 x1 y1)
     (set-current-position plotter [x1 y1]))

(ddefn draw [dx dy]
  (let [[x1 y1] @(plotter :current-position)
        [x2 y2] [(+ x1 dx) (+ y1 dy)]]
    (primitive-line plotter x1 y1 x2 y2)
    (set-current-position plotter [x2 y2])))

(ddefn line [x1 y1 x2 y2]
   (plot plotter x1 y1)
   (draw plotter (- x2 x1) (- y2 y1)))

(ddefn ink   [color] (set-ink-color plotter color))

(ddefn paper [color] (set-paper-color plotter color))

(ddefn scaled-scatter-plot [points xleft xright ytop ybottom scalepoints]
  (let [[xsc ysc] (make-scalars (take scalepoints points) xleft xright ytop ybottom)]
      (doseq [[x y] points]
        (plot (* (xsc x))
              (* (ysc y))))))

(defn window [plotter]
  (swap! current-plotter (fn[x] plotter)))

(ddefn get-height [] @(plotter :height))

(ddefn get-width  [] @(plotter :width))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Examples

(defn sine-example[]

  (create-window "sine")

  (cls)
  
  ;; sine graph
  (doseq [x (range 1024)]
    (plot x (+ 384 (* 376 (Math/sin (* Math/PI (/ x 512)))))))

  ;; axes
  (ink yellow)
  (plot 0 384) (draw 1024 0)
  (line 512 0 512 1024))

(sine-example)

上記をREPL画面に貼り付けると、お試しの正弦波が別画面に表示されます。

;; (use 'simple-plotter)

(defn transform [[xx xy yx yy dx dy]]
  (fn [[x y]] [(+ (* xx x) (* xy y) dx)
               (+ (* yx x) (* yy y) dy)]))

(def barnsleys-fern '((2  [  0    0     0     0.16 0 0    ])
                      (6  [  0.2 -0.26  0.23  0.22 0 0    ])
                      (7  [ -0.15 0.28  0.26  0.24 0 0.44 ])
                      (85 [  0.85 0.04 -0.004 0.85 0 1.6  ])))

(defn choose [lst] (let [n (count lst)] (nth lst (rand n))))

(defn iteration [transforms]
  (let [transform-list (mapcat (fn [[n t]] (repeat n (transform t))) transforms)]
    (fn [x] ((choose transform-list) x))))

(def barnsley-points (iterate (iteration barnsleys-fern) [0 1]))

(create-window "Barnsley's Fern" 350 450)

(ink green)
(scaled-scatter-plot (take 10000 barnsley-points) 50 300 50 400 100)

続いて、上記を貼り付けると。。。 色は秋色の方が良かったかしら?

初心(これでウブと読むんだってさ)でも clojure してみよう

ウブンツでもやってみんべぇ。

sudo apt-get install maven2
vi pom.xml
mvn clojure:repl

たったこれだけで、Clojureを始められます。劣化したS式であるxmlを事前に準備するのが 面倒ですが。(下記をpom.xmlとして用意) 初回は、あれこれ御取り寄せするので、プロンプトが出てくるまで、ちと時間がかかります。なお、REPL は、ヒストリー機能付きになってるので、矢印キー等で過去に入力したS式を簡単に呼び出せます。

それから、事前にJDKを入れておくのをお忘れなく。Sunのやつでもopenなやつでも、お好きにどうぞ。 嗚呼、もうSunのJDKじゃ無いんですね。Javaの生みの親 James Gosling はオラクルを辞めちゃったし いろいろとごたごた してるみたいだし。ごたごたついでに、Lambada は λ にしてね。Clojureは、Lambdaの代わりを fn が 務めているよ。変わらない事がStatusというCLは、結局独自追加が祟って非互換性が生まれるんでしょうな。 だったら、最初から互換性なんて期待しなければいいのに。

話が逸れちゃったわい。FreeBSDで使ってるJavaは

[sakae@cdr ~]$ java -version
java version "1.6.0_07"
Diablo Java(TM) SE Runtime Environment (build 1.6.0_07-b02)
Diablo Java HotSpot(TM) Client VM (build 10.0-b23, mixed mode, sharing)
[sakae@cdr ~]$ javac -version
javac 1.6.0_07

こんなのでした、って、普通の人には参考にならないよね。後、

mvn clojure:swank

お好みで、emacsから、M-x slime-connectするのもいいでしょう。

<project>

  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>hello-maven-clojure-swank</artifactId>

  <version>1.0-SNAPSHOT</version>
  <name>hello-maven</name>
  <description>maven, clojure, emacs: together at last</description>

  <repositories>
    <repository>
      <id>clojars</id>
      <url>http://clojars.org/repo/</url>
    </repository>
    <repository>
      <id>clojure</id>
      <url>http://build.clojure.org/releases</url>
    </repository>
    <repository>
      <id>central</id>
      <url>http://repo1.maven.org/maven2</url>
    </repository>
  </repositories>

  <dependencies>
    <dependency>
      <groupId>org.clojure</groupId>
      <artifactId>clojure</artifactId>
      <version>1.2.0</version>
    </dependency>
    <dependency>
      <groupId>org.clojure</groupId>
      <artifactId>clojure-contrib</artifactId>
      <version>1.2.0</version>
    </dependency>
    <dependency>
      <groupId>jline</groupId>
      <artifactId>jline</artifactId>
      <version>0.9.94</version>
    </dependency>
    <dependency>
      <groupId>swank-clojure</groupId>
      <artifactId>swank-clojure</artifactId>
      <version>1.2.1</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
         <groupId>com.theoryinpractise</groupId>
            <artifactId>clojure-maven-plugin</artifactId>
         <version>1.3.3</version>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
          <artifactId>versions-maven-plugin</artifactId>
        <version>1.2</version>
      </plugin>
    </plugins>

  </build>

</project>

MyMEMO: Swap CapLock and Control Key

REGEDIT4

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,03,00,00,00,1d,00,3a,00,3a,00,1d,00,00,00,00,00

キーボード配列をWindows上で変更するWindows キーボードレイアウトの変更。 これ、自分へのメモ。だったら、ここに書くなちゅうに!