ラベル Clojure の投稿を表示しています。 すべての投稿を表示
ラベル Clojure の投稿を表示しています。 すべての投稿を表示

2015年3月23日月曜日

Clojureでawtの画面を表示

ClojureからawtのWindowを表示するだけのサンプルプログラムです。
(ns myawt)

(import '(java.awt Frame)
        '(java.awt.event WindowListener))

(def window-width 600)
(def window-height 480)

(doto (Frame.)
    (.addWindowListener
        (proxy [WindowListener] []
            (windowActivated [e])
            (windowClosed [e] (System/exit 0))
            (windowClosing [e] (.dispose (.getWindow e)))
            (windowDeactivated [e])
            (windowDeiconified [e])
            (windowIconified [e])
            (windowOpened [e])))
     (.setSize window-width window-height)
     (.setVisible true))
windowClosedとwindowClosingのイベントハンドラを実装するのがポイントです。

参照
Frame
WindowListener

2012年9月23日日曜日

ClojureでDesign By Contract

Clojureでは、関数を定義する際に事前条件と事後条件を定義できます。
この機能を使えば、Design By Contract(契約による設計)を容易に実践できます。

事前条件を定義する
さっそく実験してみます。
「パラメータが文字列であること」という事前条件をもつ関数aを定義しました。

user=> (defn a [x] {:pre [(instance? String x)]} x)
#'user/a
user=> (a 1)
AssertionError Assert failed: (instance? String x) user/a (NO_SOURCE_FILE:1)
user=> (a "123")
"123"
view raw assert.clj hosted with ❤ by GitHub
パラメータとして1を渡したときにAssertionErrorが発生しました。

Assertionを無効にする
Assertionを無効にするには、*assert*へfalseをセットします。
この値はコンパイル時に参照されるため、REPLの場合はdefnを実行する前に設定しておく必要があります。
*assert*へfalseを設定してから、上と同じ関数を定義しました。

user=> (set! *assert* false)
false
user=> (defn a [x] {:pre [(instance? String x)]} x)
#'user/a
user=> (a 1)
1
user=> (a "123")
"123"
パラメータとして1を渡しても例外が発生しなくなりました。

例をもう少し
最後に、もう少し実践的な例として日付の比較をする関数を上げておきます。
この関数はCalendar.beforeを呼ぶため、パラメータはCalendarクラスのインスタンスでなければいけません。

user=> (import java.util.Calendar)
java.util.Calendar
;; 関数定義
user=> (defn before? [base comp]
#_=> {:pre [(instance? Calendar base)
#_=> (instance? Calendar comp)]
#_=> :post [(instance? Boolean %)]}
#_=> (.before base comp))
#'user/before?
;; 動作確認
user=> (def cal1 (Calendar/getInstance))
#'user/cal1
user=> (def cal2 (Calendar/getInstance))
#'user/cal2
user=> (before? cal1 cal2)
true
user=> (before? cal2 cal1)
false
;; Calendar以外を渡してみる
user=> (before? 1 2)
AssertionError Assert failed: (instance? Calendar base) user/before? (NO_SOURCE_FILE:1)
view raw before.clj hosted with ❤ by GitHub
事前条件と事後条件をシンプルに定義できるのが素敵だと思いました。

2012年6月26日火曜日

AngularJSとCompojureによる簡単なサンプル

Googleが開発しているAngularJS(以下angular)のバージョンが1.0になったらしいので、サンプルを作ってみました。最近はClojureに対する愛が高まっているので、サーバーサイドにはCompojureを選びました。angular-Compojure間をAjaxで通信することを目標に、一行掲示板のようなものを作りました。clj-anglr

苦労したこと
angularから送ったJSONをCompojure側で受け取るところ。

;; Good
(defroutes
(POST request (:param (read-json (slurp (:body request)))))
...)
;; Bad
(defroutes
(POST [param] param)
...)
view raw sample.clj hosted with ❤ by GitHub
Compojureのサンプルを検索してすぐに見つかるのはBadのほうだと思いますが、この書き方ではangularから送ったJSONを受信できません。JSONはリクエストパラメータとしてではなく、リクエストのBODYに格納されるため、Goodのように自分でBodyから取り出す必要がありました。

感じたこと
angularのマッピングは快適です。特に$scopeへ追加したオブジェクトを更新すると、何もしなくても画面に反映されるのがすごいと思いました。業務で作っているシステムは頻繁に画面がちらつく・・・。
もう一つ、サーバーサイドにCompojureというのはアリだと思いました。Clojureのデータ構造はシンプルなのでJavaに比べてなんとなく不安でしたが、JavaScriptと通信する時にJSONに変換するのであれば、大して問題にならない気がしました。むしろ、無駄な情報がないために見通しがいいとも感じました。

業務で使うことはまだないと思いますが、なかなか興味深いライブラリでした。

2012年2月23日木曜日

Codecademyの課題をClojureで解いてみよう - その3

今回はDice Game
rand-intを使えば、最初から整数として返してくれるので楽チン。
サイコロの出目と点数を返す関数とそれを表示する関数にわけてもいいかもしれない。


(defn dice-game []
(let [die1 (+ 1 (rand-int 6))
die2 (+ 1 (rand-int 6))]
(printf "you rolled a %d and a %d for a score of %d\n"
die1
die2
(cond (or (= 1 die1) (= 1 die2)) 0
(= die1 die2) (* 2 (+ die1 die2))
:else (+ die1 die2)))))
view raw dice-game.clj hosted with ❤ by GitHub

2012年2月12日日曜日

Codecademyの課題をClojureで解いてみよう - その2

今回はタクシーの運賃を計算する関数を実装します。
letを使って数値に名前をつけました。
そしてletの中で通常料金の計算は終わっているという。

(defn taxi-fare [milesTraveled, pickupTime]
(let [
baseFare 2.50
costPerMile 2.00
nightSurcharge 0.50
cost (+ baseFare (* costPerMile milesTraveled))]
(if (or (<= pickupTime 6)
(<= 20 pickupTime))
(+ nightSurcharge cost)
cost)))
view raw taxy-fare.clj hosted with ❤ by GitHub

2012年2月7日火曜日

Codecademyの課題をClojureで解いてみよう - その1

Clojureの練習にCodecademyの課題を使ってみようと思いました。

第一問はIntroductionよりFizzBuzz。
あまりきれいではないな。

(for [x (range 1 101)]
(if (and (= (mod x 3) 0) (= (mod x 5) 0)) "FizzBuzz"
(if (= (mod x 3) 0) "Fizz"
(if (= (mod x 5) 0) "Buzz" x))))
view raw FizzBuzz.clj hosted with ❤ by GitHub

2012年1月5日木曜日

メソッド名のリストを取得する

大したものではございませんが、REPLでJavaを呼び出すときに頻繁に入力しました。
(defn get-method-names [cls]
(map #(.getName %) (.getMethods cls)))

これをJavaでやろうとすると、キャストやら例外処理でぐちゃぐちゃになるんですよねえ。