Friday, June 29, 2012

Wink Toolkit入門 ~エフェクト編~

こんにちは。
ニャンパス一味の土井(@exfreeter)です。

ちょっと間が空きましたが、僕は元気です。
前回の続きで、Wink ToolkitのウリであるエフェクトUIを紹介・解説していきます。

が、Wink Toolkitが提供しているUIは多岐にわたるため、その全てを1つのブログ記事で紹介することは到底出来ません。
今回は、特にスマホ的なUIである「Facebookライクな横スライドメニュー」と「引っ張って更新」の2つに絞って紹介することにします。

これらを実装することで一気にスマホらしいUIになりますよ。


Facebookライクな横スライドメニュー

FacebookのiOSネイティブアプリで導入されてから一気に広まった印象があります。
Facebook、Path、Google+、Yammerといった米国の有名スタートアップのアプリが採用していますし、日本のアプリでも増えてきているようです。

デモはこちら(Wink Toolkitのkitchensink。左上のボタンをタッチしてみて下さい。スマホのブラウザ推奨)



使い方等はKitchensinkのソースを見てもらうのが一番早いです。
左上のボタンを押した時に呼ばれるks.options.toggleメソッドが肝ですね。
Chromeの開発ツールか何かで見てもらうと、何をしてるかはすぐ分かると思います。

あの短いコードの中でアニメーションの仕方まで指定していて(ease-in-outの部分)、Winktoolkitの底力を感じられるのではないでしょうか。

引っ張って更新(Scroll To Refresh)

iOSのネイティブアプリでは非常にポピュラーなUIですよね。
iPhoneユーザーであれば一度は見たことがあるはずです。

Objective-Cを使ったネイティブアプリ開発では「Pull Refresh」とか「Pull To Refresh」とか呼ばれてますが、Wink Toolkitでは「Scroll To Refresh」というようです。

デモはこちら(Winkのデモページの一部です。スマホのブラウザ推奨)


使い方は、
http://www.winktoolkit.org/documentation/symbols/wink.plugins.ScrollToRefresh.html
を参照して下さい。

詳しいサンプルコードがあるので、分かりやすいかと。
文言やローディングの指定はお好みで。
サンプルでは引っ張った時と離した時の2つのコールバック関数はダミーになってます。

もしくは、デモの該当するページのソースを見るのも良いでしょう。


2つ紹介するだけでもそれなりの分量になってしまいましたが、まだまだイケてるエフェクトはたくさんあるので、自分で色々探してみてください。
個人的に「無駄にカッコイイ」と思うのは、SharingWheelというエフェクトかなぁ。

次回は、PhoneGapの導入を紹介したいと思います。

実践(?)Clojure「マルチメソッド」

こんにちはこんにちは!!

清水です。今回は入門Clojureじゃなくて、Clojureのちょっと実践的な機能を紹介します。飽きたわけじゃないんだからねっ!

ClojureはJVMで動いているので、Javaのクラスが使えます。実際、ClojureのデータはJavaのオブジェクトになっています。Javaではクラスを継承したりインタフェースを実装して、メソッドをオーバーライドすることにより、値によって異なる処理を実装します。

Clojureで値によって異なる処理を実装したい場合、同じようにクラスを作ることもできますが、その他にも「プロトコル」や「マルチメソッド」等いくつかの手段が用意されています。今回はその「マルチメソッド」を紹介します。

マルチメソッドとは

マルチメソッドは複数の関数をまとめたような特殊な関数で、引数の型などによって実行時に処理を変えることができます。また、後から簡単に処理を追加することもできます。

Javaのオーバーロードに似ていますが、Javaの場合はコンパイル時の型によって呼び出されるメソッドが決まるのに対して、マルチメソッドは実行時に実際の値によって呼び出されるメソッドが決まります。この特性はどちらかというと通常のメソッドに近いものですが、マルチメソッドは複数の引数を基にメソッドを切り替えることができ、さらにClojureのマルチメソッドは型以外の情報を使うことができます。(パターンマッチにも似ているかも)

Clojureの他に、Common Lispでもマルチメソッドが採用されています。Common Lispの場合は型(か値そのもの)でしかディスパッチできませんが、その分高速な気がします。あとだいぶ前にRubyで実装してみたりしました。Pythonにもライブラリがあるみたいです。

使ってみる

とりあえずどういうものか使ってみましょう。

(defmulti format-item (fn [item] (:type item)))

(defmethod format-item :book [book]
  (str (:title book) "/" (:author book)))

(defmethod format-item :shoe [shoe]
  (str (:manufacturer shoe) "/" (:name shoe) "(" (:color shoe) ")"))

上記のコードはformat-itemというマルチメソッドを定義しています。商品の情報をひとつのマップとして受け取り、種別(:type)に合わせた文字列を構築して返すようになっています。マルチメソッドは通常の関数と同じように呼び出すことができます。

(format-item {:type :book :title "Land of LISP" :author "Conrad, M.D. Barski"})
; => "Land of LISP/Conrad, M.D.Barski"

(format-item {:type :shoe :manufacturer "Converse" :name "ALL STAR MULTI-PIPES OX" :color "Black"})
; => "Converse/ALL STAR MULTI_PIPES OX (Black)"

このような結果になります。

defmultiはマルチメソッドを定義するマクロです。以下のような形式になっています。

(defmulti 関数名 ディスパッチ関数)

「関数名」はdefnと同じで定義する関数の名前です。

「ディスパッチ関数」は上記では

(fn [item] (:type item))

です。

これは呼び出すメソッドを決める際に、引数のどの情報を使うかを決める関数です。format-itemはマップをひとつ受け取ることを想定しているので、その中の:typeのキーに対応する値によって呼び出されるメソッドが決まるということになります。

defmethodはdefmultiで定義したマルチメソッドに対してメソッドを追加するマクロです。

(defmethod マルチメソッド ディスパッチ値 [引数] 本体)

ひとつ目の引数として、処理を追加するマルチメソッドを指定します。

「ディスパッチ値」はdefmultiのディスパッチ関数の戻り値に対応する値を指定します。ディスパッチ関数の戻り値がこの値と一致している場合にこのメソッドが呼び出されます。

defmethodの引数はディスパッチ関数の引数と対応している必要があります。「本体」は通常の関数と同じように書きます。

先ほどのformat-itemのディスパッチ関数は受け取ったマップの:typeの値を返すので、

{:type :book ...}

というマップを渡した場合には

(defmethod format-item :book ...)

で定義したものが呼び出されます。

ちなみにキーワードは関数として呼び出すことができるので、先ほどのdefmultiは以下のように書くこともできます。

(defmulti format-item :type)


複数の引数によるディスパッチ

ディスパッチ関数は複数の引数を受け取ることができます。これによりいくつかの値の組み合わせによって柔軟に処理を切り替えることができたりするかもしれません。

(defmulti calc-attr (fn [attack-attr target-attr damage] [attack-attr target-attr]))

(defmethod calc-attr [:water :fire] [attack-attr target-attr damage]
  (* 2 damage))

(calc-attr :water :fire 100) ; => 200

RPGとかでよくある属性によるダメージ補正をするマルチメソッドです。みっつの引数attack-attr(攻撃属性)、target-attr(対象の属性)、damage(基本ダメージ)を受け取って、補正後のダメージを返します。

ディスパッチ関数はattack-attrとtarget-attrのふたつを要素に持つベクターを返します。defmethodのディスパッチ値も同じようなベクターにすることで、ふたつの値によってメソッドを変えることができます。

defmethodで定義したメソッドはディスパッチ値として

[:water :fire]

というベクターを持ちます。これにより、attack-attrが:water、target-attrが:fireで呼び出された場合にdamageが2倍になります。

こういう場合は属性テーブルとか作った方がわかりやすいかもしれません。複数の引数を使ったディスパッチ関数は個人的にあまり使わないため、良い例が浮かびませんでした。関数を返す関数を作ったり、関数を値に持つマップを作ったりした方が柔軟で分かりやすくなるような気がします。

デフォルトメソッド

先ほどのcalc-attrをどのメソッドにも該当しないように呼び出した場合

(calc-attr :normal :ice 60)
java.lang.IllegalArgumentException: No method in multimethod 'calc-attr' for dispatch value: [:normal :ice]

このようなエラーが発生します。ディスパッチ関数が[:normal :ice]を返したけど、それにマッチするメソッドがないというエラーです。

どれにもマッチしない場合に呼び出されるメソッドを作りたいことは頻繁にあります。そういう場合にはdefmethodのディスパッチ値に:defaultというキーワードを指定します。

(defmethod calc-attr :default [attack-attr target-attr damage]
  damage)

こうしておけば、該当するメソッドがない場合にこのメソッドが呼ばれるようになります。

(calc-attr :normal :ice 60) ; => 60

もし、ディスパッチ値として:defaultを使いたい場合は、defmultiのオプションでデフォルトメソッドのディスパッチ値を変えることができます。

(defmulti xyzzy (fn [x] (:type x))
  :default nil)

こうすると、ディスパッチ値としてnilを指定したメソッドがデフォルトメソッドになります。nilでもディスパッチしたいときには名前空間付きのキーワードを使ったり、一時的なオブジェクトを使ったりもできます。

継承みたいなもの

最初の例のformat-itemのようなマルチメソッドを作ったときに、comicのようなタイプをbookとして扱いたいことがあると思います。そういうときにはderiveという関数を使い、親子関係を構築します。

(defmulti format-item (fn [item] (:type item)))

(defmethod format-item ::book [book]
  (str (:title book) "/" (:author book)))

(derive ::comic ::book)

(format-item {:type ::comic :title "Kodoku no gurume" :author "Masayuki Qusumi and Jiro Taniguchi"})
; => "Kodoku no gurume/Masayuki Qusumi and Jiro Taniguchi"

deriveに子となるキーワードと親となるキーワードを指定すると、メソッドの決定時に自動的に子を親として扱ってくれます。deriveに渡すキーワードは名前空間を持つ必要があります。

子にはキーワードの他に、名前空間付きのシンボルと、Classオブジェクトを指定することができます。親には名前空間付きのキーワードとシンボルしか指定できません。

特定のマルチメソッドでのみの親子関係を使いたいときには、make-hierarchyという関数で階層オブジェクトを作り、そのRefをdefmultiに渡します。

(def hierarchy (ref (make-hierarchy)))

(defmulti xyzzy (fn [item] (:type item))
  :hierarchy hierarchy)

(dosync (alter hierarchy derive ::comic ::book))

階層に親子関係を追加するときにはderiveに引数として渡します。この場合のderiveは親子関係を追加した新しい階層オブジェクトを返します。それを再度Refの値にしなければマルチメソッドに反映されません。そのため上記のコードではdosyncとalterを使ってRefを更新しています。


マルチメソッドの説明は大体以上です。マルチメソッドだけでも便利ですが、メタデータと組み合わせたり、マクロの展開時にマルチメソッドを呼び出したりすると面白いことができそうな気がします。

Friday, June 22, 2012

Clojure入門「データ構造」

こんにちは。清水です。

今回はClojureのデータ型についていくつかだらだら解説します。

ClojureのデータにはJavaの標準なクラスのインスタンスになっているものがいくつかあります。なにがどんなクラスのインスタンスなのかは値をclass関数に渡したりするとわかります。

列挙系はダレますね。。。

文字列

Clojureの文字列はJavaのStringオブジェクトです。

"Hello, world."

ダブルクォーテーションで囲んだものが文字列になります。str関数を使うとオブジェクトを文字列に変換できます。

(str 428) ; => "428"

strは複数の引数を受け取り、全てを結合した文字列を返します。

(str "Hello" "World") ; => "HelloWorld"

clojure.stringという名前空間にいくつか文字列用の関数が用意されています。Stringのメソッドを使うこともできます。

文字

文字列とは別にひとつの文字を表すデータ型もあります。

\A

文字の前にバックスラッシュを付けると、その文字のリテラルになります。これはJavaのCharacterオブジェクトです。

\space ; 半角スペース\newline ; 改行\tab ; タブ

など、特殊な文字を表すリテラルもあります。

数値

数値には整数と浮動小数点数と分数があります。

4287.222/3

整数は値の大きさによってInteger、Long、BigIntegerオブジェクトのいずれかになります。浮動小数点数はDoubleオブジェクトで、分数はClojure独自のクラスのインスタンスです。また、分数のリテラルは/の前後にスペースを入れることはできません。

ブール

ブール値はJavaのBooleanオブジェクトで、trueとfalseの二つの値があります。ifの条件式や、コレクションをフィルタリングする時に渡す関数の戻り値などに使われます。ただし、その場合は厳密にtrueかfalseである必要はなく、falseと(後述する)nil以外は全てtrueとして扱われます。0や空の文字列や空のリストなどはfalseにはなりません。

nil

nilは何もないことを表す値です。内部的にはJavaのnullです。nilはfalseとして扱われる他、空のコレクションにもなります。

ちなみに、空のリストはnilではありません。

キーワード

キーワードは名前空間と名前を持つオブジェクトです。文字列にも似ていますが、同じ名前空間と名前を持つキーワードは同じインスタンスになるため、文字列よりも比較が速い等の利点があります。

:foo

上記のようにコロンの後に名前をつけると、その名前のキーワードになります。この形式のキーワードは名前空間を持ちません。そのため、どの名前空間内で記述しても同じインスタンスを表すことになります。

::foo

このようにコロンを二つ付けると、現在の名前空間のキーワードになります。

:xyzzy/foo

また、上記のように名前空間と名前をスラッシュで区切ると、任意の名前空間のキーワードを使うことができます。

キーワードはマップのキーに使われることが多いです。ほとんどの場合、名前空間を持たないキーワードが使われ、名前空間毎に固有のキーを用意したい場合などに名前空間付きのキーワードを使ったりします。

(Rubyのシンボルに近いのかも。)

シンボル

シンボルはキーワードと同じように名前空間と名前を持ち、コード上でなにかの名前を表すのに使われます。変数や関数の名前、strやprintlnなどの名前もシンボルです。シンボルはそのまま評価すると結びつけられた値を返します。そのため、

str

と書けばstrの関数自体が返されます。定義されていないシンボルを評価しようとすると

java.lang.Exception: Unable to resolve symbol: foo in this context

などといったエラーが発生します。シンボルを直接値として扱うには、名前の前にシングルクォーテーションを付けます。

'foo

このシンボルは名前空間を持ちません。シングルクォーテーションの代わりにバッククォーテーションを付けると、現在の名前空間内のシンボルになり、キーワードと同じように名前の前に名前空間を付けると任意の名前空間のシンボルになります。

ちなみにこのシングルクォーテーションはquoteというマクロの糖衣構文で、下のコードと同じになります。

(quote foo)

quoteは引数を評価せずに式としてそのまま返します。

シンボルはマクロを書くときに使います、それ以外では使う機会は少ないです。

ちなみに、キーワードはシンボルではなく、シンボルはキーワードではありません。

リスト

Clojureのリストは連結リストとして実装されたオブジェクトです。JavaのListインタフェースを実装しているため、Javaのメソッドに渡すこともできます。リストは丸括弧に値を並べた形で表されます。

'(15 9 48)

リストを作るときには先ほどのquoteを使います。quoteしないと上記の場合は15という関数を呼び出すという意味になってしまいます。上記のように書いた場合は括弧の中のものもquoteされてしまうので、変数の値をリストに含めようとするとシンボルになってしまいます。変数の値を含めたい場合はlist関数を使います。

(list foo bar xyzzy)

この場合は変数foo、bar、xyzzyの値を含んだリストになります。空のリストの場合のみ、quoteもlistもなく、()と書くだけで作れます。

リストの先頭の要素はfirst関数、先頭を除いたリストはrest関数で取得できます。

(first '(15 9 48)) ; => 15(rest '(15 9 48)) ; => (9 48)

ベクター

ベクターは整数のインデックスでアクセスできるコレクションです。JavaのVectorとは違うものですが、Listインタフェースを実装しています。ベクターは[]の中に要素を並べて書きます。

[15 9 48][foo bar xyzzy]

ベクターを作るときにはquoteする必要はなく、変数もそのまま書けます。

要素を取得するにはget関数を使います。

(get [15 9 48] 1) ; => 9

該当する要素が無い場合はnil、またはgetの3番目の引数を返します。また、ベクターそのものを関数として呼び出しても要素を取得することができます。

([15 9 48] 1) ; => 9

この形式の場合、該当する要素が無い場合はエラーになります。

マップ

マップは順序を持たない連想配列です。{}の中にキーと値を並べて書きます。

{:name => "Hamachi" :price => 130}

上記の場合はnameとpriceという名前のキーワード二つをキーに持つマップになります。

マップの要素を取得するのにもget関数が使えます。

(get {:name => "Hamachi" :price => 130} :price) ; => 130

ベクター同様に、マップそのものを関数として呼び出して要素を取得することもできます。また、キーワードかシンボルを関数としてマップを渡しても同様のことができます。

({:name => "Hamachi" :price => 130} :price) ; => 130(:price {:name => "Hamachi" :price => 130}) ; => 130

この形式の場合でも該当する要素が無い場合はnilを返しますが、関数として呼び出せないものを左側に置いてしまうとエラーになるので注意が必要です。

マップはJavaのMapインタフェースを実装しているので、メソッドの引数に渡したりできます。Javaで書くよりも簡単。


セット

セットは順序を持たず重複の無い要素の集合です。JavaのSetインタフェースを実装しています。セットは#{}の中に要素を並べて書きます。

#{10 20 30}

セットにもget関数が使えます。引数として要素を渡すと、その要素がセットの中に含まれる場合には同じものを返し、無い場合はnil(または3番の引数)を返します。

(get #{10 20 30} 20) ; => 20

セット自体を関数として呼び出しても同じことができます。

(#{10 20 30} 20) ; => 20

要素がある場合には要素そのものを、無い場合はnilを返すので、セットがfalseやnilを含むことが無ければ条件式として使うことができます。

上記のリストやベクターなどのコレクションは全て変更不能なオブジェクトです。ベクターの要素を変えたい場合は要素を変えた新しいベクターを作成します。Clojureにはその為の関数が用意されています。次回はコレクションについてもうちょっと解説する予定です。

なにやら新しいシリーズが始まったようなので合わせてどうぞ

Thursday, June 21, 2012

Wink Toolkit入門 ~導入編~

こんにちは&はじめまして。
ニャンパス一味の土井(@exfreeter)です。
まだまだ駆け出しのプログラマですが、iOS向けアプリやClojureによるWebアプリをメインに開発しています。

このたび、清水君(@yuushimizu)のClojureの連載と並行してNyampass tech blogで記事を執筆することになりました。
慣れてくると言葉使いが崩れて関西弁になると思いますが、生暖かい目で見守って頂けると幸いです。

僕はObjective-CでiOS向けアプリを作ることが多いんですが、Javascriptで作りたいという方は多いと思います。
そこで、まずは「スマホ向けネイティブアプリをJavaScriptで作る」というテーマで書いていく予定です。(数回程度の予定)
これらの一連の記事を読めば、初歩的なネイティブアプリをHTML/CSS/JSだけで作れるようになるかも。

今回は、スマホWebサイト用のJavascriptフレームワークであるWink Toolkitの紹介および導入を解説したいと思います。
次回以降、Winkの豊富なエフェクトの紹介やPhoneGapによるWebサイトのネイティブ化などに進んでいく予定です。

では、早速はじめましょう。


Wink Toolkitとは?

一言でいうと、スマホ向けのサイトを作るためのJSフレームワークです。
似たようなものとしてjQuery MobilejQTouchなどがありますが、そのようなものだと思っていただければOKです。

恐らく、2012/06現在で一番勢いがあるのはjQuery Mobileだと思います。
ネット上の情報や関連書籍なども充実してます。

が、現状だと重いんですよね.....。
ニャンパスでも幾つかのフレームワークを試しましたが、結局はパフォーマンスを重視してWink Toolkitに落ち着きました。

Wink Toolkitの特徴は、軽さと豊富なエフェクト系UIです。
デモサンプルも豊富なので、これらを組み合わせるだけでスマホぽいUIのサイトが作れちゃいます。
具体的にどういうことが出来るかは、以下のURLから見ることが出来ます。(PCから見ても良いですが、スマホのブラウザで見るのをオススメします)


FacebookやPathのiOSネイティブアプリで見られる横スライド式のメニューや、スマホでは定番の「引っ張って更新」なんかもありますよね。
正直、「無駄にカッコいい」というレベルです。

Wink Toolkitの導入

では、早速Wink Toolkitを導入していきましょう。

まず、本家サイトからWink本体をダウンロードして下さい。(画面上部のdownloadsからダウンロードページに行けます)
とりあえず、ダウンロードページの一番上のリンクから最新版のZipを落としておいてください。(2012/06/21現在での最新版は1.4.2。以下、1.4.2を前提に進めます)

そのZipが上記デモページのソースになっているので、自信のある方はそれを見てゴニョゴニョやってるうちに使いこなせるようになるかと。

今回は初回ということで、デモの一番上にあるアコーディオンのページのソースを見るところまでにしましょう。

Zipを解凍したら、ui/layout/accordion/test/test_accordion_1.htmlをブラウザで開いてみてください。
3つのセクションを持つアコーディオンがありますね。
では、test_accordion_1.htmlのソースを見ていきましょう。

8行目と11行目でCSS、14行目でテーマ用のJS、19行目から36行目まででWinkのcoreのJS、39行目でアコーディオン用のJSをそれぞれ読み込み、41行目以降がこのページで使うアコーディオン等を具体的に作っているJSのコードになっています。
これが、Wink Toolkitの基本的な使い方になります。
また、core部分はwink.min.jsで代替可能です。(今回だとwink_1.4.2.min.jsですね)

CSSとJSがペアになっている点に注目して下さい。(8/14行目、11/39行目)
Wink Toolkitを使う場合、基本的に、hogehoge.jsを使う時にはhogehoge.cssも読み込む必要があります。
例えば、アコーディオンを使いたい時はaccordion.jsとaccordion.cssが必要だし、カルーセルを使いたい時はcarousel.jsとcarousel.cssが必要になります。
CSSを忘れることが多いので、注意して下さい。

以上、駆け足になりましたが、Wink Toolkitの導入でした。
詳しくは、本家のドキュメントを参照して下さい。
かなり分かりやすいと思います。

次回は、Wink Toolkitの豊富なエフェクトUIの中でも一際光る(と個人的には思っている)Facebookライクな横スライド式のメニューを紹介しようと思います。

Friday, June 15, 2012

Clojure入門「関数と変数」

こんにちは。ニャンパス一味の清水です。

今回はClojureの関数と変数について少しだけ解説します。

関数

関数の定義

前回も書きましたが、関数は"defn"というマクロを使って定義します。

(defn -main []
  (println "Hello, world!"))

defnの形式は以下のようになっています。

(defn 関数名 [引数 ...] 本体)

先の例の場合は関数名が-main、引数は無し、本体は(println "Hello, world!")です。

引数を取る場合には[]の中に引数の名前を並べます。

(defn add-forty-two [x]
  (+ 42 x))

(defn triangle [base height]
  (/ (* base height) 2))

それぞれ、引数をひとつ受け取って42を足した数を返す関数と、引数をふたつ受け取って三角形の面積を返す関数です。

関数の呼び出し

関数は以下のような形式で呼び出します。

(関数 引数 ...)

コードの中では括弧の中の一番左が関数かマクロになり、その右側に引数が並びます。上記で定義したadd-forty-twoを呼び出すには以下のようにします。

(add-forty-two 30)

この場合、add-forty-twoの定義内のxには30が束縛され、結果として72を返します。同様に、triangleを呼び出すには以下のようにします。

(triangle 31 6)

引数baseには31、heightには6が束縛され、93を返します。

ちなみに、Clojureのコードでは区切り文字としてスペースやタブや改行が使用されます。カンマを付けて見やすくすることもできますが、動作には影響がありません。

また、add-forty-twoやtriangleの本体でも関数を呼び出しています。

(+ x 42)

上記は + という関数を、xと42を引数として呼び出しています。

(/ (* base height) 2)

triangleではふたつの関数 / と * を呼び出しています。この場合、先に

(* base height)

が評価され、その結果と2が / の引数になります。

Javaメソッドの呼び出し

ClojureからJavaのメソッドを呼び出すことができます。Clojureの文字列はJavaのStringオブジェクトなので、Stringクラスのメソッドを使えます。

(.toLowerCase "HELLO")

上記は"HELLO"というStringオブジェクトのtoLowerCaseメソッドを呼び出しています。結果として"hello"が返ります。このように、メソッド名の前に . を付けたものを関数として呼び出すと、ひとつ目の引数のメソッドが呼び出されます。

無名関数

"fn"というマクロを使うと無名関数を作ることができます。

(fn [x] (+ 42 x))

これは先ほどのadd-forty-twoと同じ結果を返す関数です。無名関数はそのまま呼び出せるので

((fn [x] (+ 42 x)) 30)

このように、関数を置く場所に無名関数を置くことができます。(この場合意味はありませんが)

無名関数は、関数を受け取る関数を呼び出す場合などに使います。

変数 

グローバル変数

変数は"def"という特殊な形式を使用して定義できます。

(def 名前 値)

defは名前空間内でグローバルな変数を作ります。

(def x 42)

(defn add-forty-two [y]
  (+ x y))

上記の場合、add-forty-two内のxは42になります。

ローカル変数

defはグローバルな変数を作るため、関数内のローカルな変数を作る時には使用できません。ローカル変数を作るには"let"というマクロを使います。

(let [変数名 値 ...] 処理)

letで作った変数はletの中でのみ参照できます。

(let [x 42]
  (+ x 30))

上の例では + に42と30が渡されます。これを実行すると(let ...)という式自体が72を返します。(関数を作ったりはせずに)

ひとつのletで複数の変数を作ることもできます。

(let [x 42
      y 30]
  (+ x y))

これは先の例と同じ動作をします。

letで作った変数には別の値を代入できません。Clojureでは変数の再代入をしなくても大体の処理を書くことができます。再代入可能な変数が必要な場合は別の仕組みを使いますが、今回はスルーします。

関数と変数

defnは無名関数を値としてグローバル変数を定義しているだけなので、defを使って書き直すことができます。

(defn add-forty-two [x]
  (+ 42 x))

(def add-forty-two (fn [x] (+ 42 x)))

上記のdefnとdefは同じ結果になります。

つまり、Clojureでは関数も数値も同じようにデータとして扱えるということです
(JavaScriptと同じ感じです)

letを使ってローカルな関数を作ることもできますし、そのために"letfn"というマクロも用意されています。関数に関数を渡すことも多く、標準で用意されている関数には、リストやベクターを処理するために関数を受け取るものが多く存在します。

次回はその辺りも踏まえて、データ構造についてちょっぴり解説していこうと思います。

Friday, June 8, 2012

Clojure入門「プロジェクトを作る」

こんにちは。ニャンパスの清水です。

前回の続きで、Leiningenを使ってプロジェクトの作り方を解説します。

プロジェクトを作る

プロジェクトを作るには

lein new プロジェクト名

というコマンドを使います。試しにHello worldを作ってみましょう。

lein new hello-world

すると、hello-worldというディレクトリが作成され、その中にプロジェクトのテンプレートとなる以下のファイルが用意されます。

README ... リードミーです。プロジェクトの説明等を書きます。
project.clj ... プロジェクトの構成を定義するファイルです。
src/hello_world/core.clj ... 標準で用意されるソースファイルです。
test/hello_world/test/core.clj ... core.cljのテストの為のソースファイルです。

まずはproject.cljを編集します。このファイルにはプロジェクトのバージョンや依存するライブラリ等を記述します。作成されたばかりのproject.cljは以下のようになっているハズです。

(defproject hello-world "1.0.0-SNAPSHOT"
  :description "FIXME: write description"
  :dependencies [[org.clojure/clojure "1.3.0"]])

とりあえず以下のように編集します。

(defproject hello-world "1.0.0"
  :description "Hello world."
  :dependencies [[org.clojure/clojure "1.3.0"]]
  :main hello-world.core)

"1.0.0"と書いたところはプロジェクトのバージョンです。ライブラリを作る場合等に重要になりますが、今回は適当に決めます。

descriptionはプロジェクトの説明です。

最後に追加した

:main hello-world.core

というのは、プロジェクトを実行した際にエントリーポイントとなる名前空間を指定しています。"hello-world.core"という名前空間はlein newで作成されたcore.cljの名前空間です。ここで指定した名前空間の中の"-main"という名前の関数が実行されます。(名前は変更することもできます。)

実装する

core.cljを編集してHello worldを実装します。

(ns hello-world.core)

作成されたばかりのcore.cljは上の一行しか書かれていません。これはこのファイル(実際にはnsより下に書いたもの)の名前空間がhello-world.coreだという宣言です。ここにエントリーポイントとなる-main関数を定義します。

(ns hello-world.core)

(defn -main []
  (println "Hello, world!"))

関数を定義するには"defn"というマクロを使います。Clojure(やその他のLisp)のマクロはCのマクロよりも強力で、構文のようなものまで作れてしまいます。

defnは以下のような形式で使用します。

(defn 関数名 [引数] 本体)

関数名には-mainを指定します。Clojureでは変数や関数の名前に"-"や"+"や"?"など色んな文字を使うことができます。前回、数値を足し合わせるのに使った"+"も実は"+"という名前の関数なのです。

引数の部分は空にしておきます。本体には"Hello, world!"を出力する処理を記述します。

(println "Hello, world!")

文字列を出力するには"println"関数を使用します。これはJavaのprintlnメソッドとだいたい一緒で、引数として渡した値を出力します。

以上がHello worldの実装です。

実行する

実行する前に、使用するライブラリ(今回はClojureの標準ライブラリだけ)をプロジェクトに追加します。

lein deps

というコマンドを実行するとproject.cljの内容に応じてライブラリが取得され、プロジェクトのlibディレクトリの中にコピーされます。

これでようやく実行できます。実行するには

lein run

というコマンドを使います。起動に時間がかかりますが、何も問題がなければ

Hello, world!

と出力されます。めでたしめでたし。

問題がある場合には少し不親切なエラーが表示されるので、project.cljとcore.cljを確認してみてください。

次回はClojureの関数とかマクロについて少し詳しく解説できたらいいなと思ってます。

Friday, June 1, 2012

Clojure入門「とりあえず使ってみる」

こんにちは。ニャンパスでプログラムを書いている清水(@yuushimizu)です。

このブログでは、主にニャンパスが普段使っている技術(ClojureやMongoDBなど)についての解説やチュートリアルをゆるふわに書いていく予定です。よろしくおねがいしますー。@tnoborioに昨日突然ブログを書けと言われました><

今回はClojureを実行してみるまでについて軽く書きます。

Clojureって?

「Clojure」はLisp系のプログラミング言語のひとつです。

Lisp系の言語には「Common Lisp」や「Scheme」などがありますが、それらの言語と比べたときのClojureの大きな特徴として「JVMで動作する」ということが上げられます。JVMで動作するので、Javaの標準ライブラリやJava向けに書かれたライブラリ(Apache Commonsとか)を使うことができます。実際、Clojureの文字列はJavaのStringになっていて、リストやベクターもJavaのListインタフェースを実装していたりします。また、Clojureで書いたクラスをJavaから使うことも可能です。

その他には、不変なデータ構造を多用することや、標準で遅延シーケンスが組み込まれていることもClojureの特徴と言えます。

Javaと比べると、コードを短く書くことができ、さらにマクロにより冗長さを減らせることや、クラスや関数を実行時に作ったり変更したりできることが違いとして上げられます。関数を値として扱えるため、Javaではクラスが必要だった処理を、Clojureではすごく簡潔に書くことができます。

例えばリストをソートするときにJavaでは以下のように書いたりしますが

Collections.sort(list, new Comparator<integer>() {
  public int compare(final Integer n, final Integer m) {return n - m;}
});

Clojureでは以下のようにすごく短く書けます。

(sort < list)

かっこいいですね!

他にJVMで動作する言語では「Scala」が最近流行っている気がします。Clojureは動的な言語ですが、Scalaは静的な言語です。どっちもJVMで動作するというだけで、言語としては離れたところにあるので比べられない感じです。ちなみに僕はClojureよりCommon Lispが好きです。

Clojureを動かしてみる

Clojureのインストールは簡単です。この記事ではMac OS X (Lion)上で動かす想定で書いていますが、だいたいのLinuxでも動くハズ。

Leiningen

Clojureのプロジェクト管理ツールに「Leiningen」というものがあります。これを使うとClojureを使うのが超簡単になります。「Leiningen」は「らいにんげん」と読むそうです。

Leiningenは http://leiningen.org/ からダウンロードできます。インストール方法は「Install」のところに書いてあります。

  1. Download the lein script というリンクからスクリプトファイル(lein)をダウンロード
  2. それをパスの通ったところに置く
  3. 実行権限を付ける
これでインスートル完了です。

REPLの実行

とりあえずClojureを使ってみるには

lein repl

というコマンドを実行します。ちょっと時間がかかりますが起動すると

user=> 

上記のようなプロンプトが表示されます。試しに

user=> (+ 7 6 5)

と打ち込んでみると

18

と表示されるハズです。REPL(Read-Eval-Print Loop)を使うとちょっとしたコードを対話的に実行することができます。

REPLはデバッグや落書きに便利ですが、コレだけでは開発できません。普段はLeiningenを使ってプロジェクトを作って開発しています。とりあえず今回はここまでにして、次回はその辺りを解説する予定です。