Create a gist now

Instantly share code, notes, and snippets.

はじけるCommonの香り!キュアClojure!

プリキュア Advent Calendar 2014 - Adventar の 23 日目の記事です.

Clocure

Clojure + Precureという意味で命名された,PycureおよびRubicureリスペクトです.

つまり世界初のLispによるプリキュア実装です.更にJVMのためのプリキュア実装でもあります.

ソースコードは kaosf/clocure にあります.ここから Clojars (Clojureのライブラリ登録サービス) へのリンクなども確認出来ます.

名前についての余談

実は最初は Clocure ではなくて Prejure という名前にしようと考えていました.「プリ」の方を残したかったですし,何よりたったの1文字しか違わないというのが面白い.

するとなんとLeiningenから警告を受けました."xxxjure" って名前のライブラリは作れないそうなのです.

lein new default prejure
#=>
# Sorry, names such as clojure or *jure are not allowed.
# If you intend to use this name ironically, please set the
# LEIN_IRONIC_JURE environment variable and try again.

そんなわけで名前は Clocure になったのです.

Clocure の使い方

まずLeiningenを用意します.

Clojureが初めての方も,この機会に入門してしまいましょう.

Leiningenのインストールは公式サイトの Install を参考にするのが一番確実です.Windowsユーザはどうすればいいのかも教えてくれます.

Linuxの方は以下を実行すればOKです.

# Debian/Ubuntu
sudo apt-get install openjdk-7-jdk
# Fedora/CentOS
sudo yum install -y java-1.7.0-openjdk java-1.7.0-openjdk-devel

if [ ! -d $HOME/local/bin ]; then mkdir -p $HOME/local/bin; fi
cd $HOME/local/bin
wget https://raw.github.com/technomancy/leiningen/stable/bin/lein
chmod +x lein
./lein
export PATH=$HOME/local/bin:$PATH
echo 'export PATH=$HOME/local/bin:$PATH' >> .bashrc # 必要に応じて .zshrc など

これで ~/local/bin/lein が用意されてパスも通るので lein コマンドが使えるようになります.

そうしたらClocureを利用するサンプルアプリ環境を作りましょう.

lein new app myappname # 好きな名前でいい
cd myappname

プロジェクト直下に project.clj というファイルがあります.これが設定ファイルになります.ここの :dependencies [] の中に [clocure "1.0.0"] を追加します.多分以下のような形になるはずです.

(defproject myappname "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.6.0"],
                 [clocure "1.0.0"]]
  :main ^:skip-aot myappname.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

そうしたら lein repl でREPLを起動して,以下を試します.

(require '[clocure.core :refer :all])

(transform nagisa)
;=>
;デュアル・オーロラ・ウェイブ!!
;光の使者、キュアブラック!
;ふたりはプリキュア!
;闇の力のしもべ達よ!
;とっととお家に帰りなさい!
;#clocure.core.Precure{:id black, :name "キュアブラック", :short-name "ブラック", :name-en "Cure Black", :short-name-en "Black", :before nagisa}

ちゃんとなぎさがキュアブラックに変身しましたね?そして transform 関数を経て別の値が帰ってきました.これが black と同じになります.

(def x (transform nagisa))

(= x black) ;=> true
(= x nagisa) ;=> false

コーディングする上で毎度毎度 cureblackshinyluminous とタイプするのは,プリキュアの名前を打ち込めて幸せハピネスかもしれませんが疲れも溜まってしまいます. なので全て nagisa black luminous などの短い名前で登録してあります.

あと上記サンプルだとグローバル名前空間に nagisa だの black だのが登録されてるように見えますが,実際すべて clocure.core/ 配下に定義されています.それを打たなくても使えているのは require の部分の :refer のおかげです.

グローバル名前空間に見えないですか?最初からちゃんと clocure.core/ が見えてました?JVM界隈の感覚がよく分からないので不安です…

「ふたりは」プリキュア

なぎさとほのかはふたり一緒じゃないと変身出来ないのが設定上正確です.しかしClocureではあえて自由度を持たせるために単体での変身を制限していません.

しかし,ふたりで変身することももちろん可能です.そのためには transform 関数に :with を使ってもう一人を渡します.

(transform nagisa :with honoka)
;=>
;なぎさ・ほのか「デュアル・オーロラ・ウェイブ!!」
;ブラック「光の使者、キュアブラック!」
;ホワイト「光の使者、キュアホワイト!」
;ブラック・ホワイト「ふたりはプリキュア!」
;ホワイト「闇の力のしもべ達よ!」
;ブラック「とっととお家に帰りなさい!」
;[#clocure.core.Precure{:id black, :name "キュアブラック", :short-name "ブラック", :name-en "Cure Black", :short-name-en "Black", :before nagisa} #clocure.core.Precure{:id white, :name "キュアホワイト", :short-name "ホワイト", :name-en "Cure White", :short-name-en "White", :before honoka}]

こうすると,今まで (transform nagisa) の評価結果は black と等価だったのが,二人で変身したことにより二人のプリキュアが返ってきます.

(def futari (transform nagisa :with honoka))

(= futari [black white]) ;=> true

複数同時変身はこの他に咲と舞,スイートチームと,あともう一組で実装されています.

天空に満ちる月!大地に薫る風!

ふたりはプリキュアSplash☆Starにおいて,キュアブルームとキュアイーグレット,キュアブライトとキュアウィンディは必ずどちらか片方の組み合わせでしか出現しません.(※ブルームとウィンディ,ブライトとイーグレットはありえないということ)

単体で変身した場合にはその限りではありませんが,複数同時変身の場合には必ず揃いのペアで登場します.

(def futari (transform saki :with mai))

(or
  (= futari [bloom egret])
  (= futari [bright windy])) ;=> true

珍しい人たち

他のプリキュア実装には居ないキャラを追加するブランチが実はあります.満と薫,キュアフラワー,キュアエンプレスなど,まだおひろめが出来ていません.しかし,ハピネスチャージプリキュアに登場した,間違いなくプリキュアである,とあるふたりが居ます.

オハナとオリナです.

(transform ohana :with orina)
;=>
;(かわルンルン♪)
;オハナ・オリナ「プリキュア!くるりんミラーチェンジ!」
;サンセット「紅い夕日は明日への誓い!キュアサンセット!」
;ウェーブ「寄せては返す悠久の調べ!キュアウェーブ!」
;サンセット・ウェーブ「南国に輝く二つの光!アローハプリキュア!」
;[#clocure.core.Precure{:id sunset, :name "キュアサンセット", :short-name "サンセット", :name-en "Cure Sunset", :short-name-en "Sunset", :before ohana} #clocure.core.Precure{:id wave, :name "キュアウェーブ", :short-name "ウェーブ", :name-en "Cure Wave", :short-name-en "Wave", :before orina}]

さっき複数変身のところで言った「もう一組」とは彼女たちのことです.

そして,イースも居ます.実は setsuna に限り transform 関数ではなく switch-over 関数に適用することが出来ます.すると評価結果が eas になります.

(def x (switch-over setsuna))

(= x eas) ;=> true

あ!あと当然なんですが,キュアエコーちゃんと居ます!キュアエコーはプリキュアです!

そもそも何に使えるライブラリなのか

単なるお遊び(というのが半分以上ですが)で作ったわけではなく,「プリキュア全員の名前を特定の形式で取得したい」などの要望を満たすために作りました.

なので以下のようなものがあります.

(:name nagisa) ;=> "美墨なぎさ"
(:first-name nagisa) ;=> "なぎさ"
(:family-name nagisa) ;=> "美墨"

(:name black) ;=> "キュアブラック"
(:short-name black) ;=> "ブラック"
(:name-en black) ;=> "Cure Black"
(:short-name-en black) ;=> "Black"

苗字が無い人なんかはその辺りが nil になります.

(:family-name eas) ;=> nil
(:family-name orina) ;=> nil

この辺りの七面倒臭い設定を一括で行ってくれるのが,これこそがClocureの特徴(であってくれたらいいなぁ…)である defhuman マクロと defprecure マクロです.

以下のような設定をS式として並べていけば,変身前と変身後の対応も取って HumanPrecure が定義出来ます.

(defhuman nagisa misumi    なぎさ 美墨 なぎさ みすみ   black)
(defhuman honoka yukishiro ほのか 雪城 ほのか ゆきしろ white)


(defprecure black ブラック nagisa)
(defprecure white ホワイト honoka)

いちいち "black""ブラック" と文字列指定しなくても大丈夫です.

変身メッセージは設定にするには長いのとまだ実装の仕様が出来ていないのとで transform-messages に辞書形式で追加していく形になります.

このような感じでキャラの追加が行い易く,記述の見通しも高まります.

YAMLにするのも考えたのですが(JSONは考えなかった),いちいち name: black のように書くのが面倒だったので,見た目スプレッドシートのように書ける,ただしS式である,という現状に落ち着かせています.

今後の展望

まずは満と薫,そしてキュアフラワー,キュアエンプレスを実装する.

まずは可能であれば,揚げたてフレッシュなキュアカオルちゃん,キュアファイヤー,キュアゴリラ,キュアセバスチャンも実装したいです.異質な変身するを人たちを集めたいです.

それと妖精.妖精が居ないと変身出来ないプリキュアがシリーズによっては居ます.それを再現したいです.

後は strict モードを導入したいです.これを設定しておけば (transform nagisa) が何らかの例外(ほのか無しの一人では変身出来ません or メップルが居ないと変身出来ません)を吐くようになる感じ.

後何よりもGo!プリンセスプリキュアの三人の名前が判明しましたので,ブランチ用意して待っておくべきですね.

他には,せっかくのClojureなので並列処理に対応するとか無意味にしたいですね.あっちでキュアブルームに変身したなら,こっちは絶対にキュアイーグレットにしか変身しない,とか.現状単なるランダムなので.

更に他には,変身時のセリフも何らかのマクロ,あるいは独自の仕様とそのパーサを作って,今全パターン書いているのを統一出来るようにしたいです.これもまだ実験状態のブランチが眠ってます…

まとめ

  • Lispはプリキュアになれる!
  • マクロ難しいけど出来たら楽しい
  • もっとやりたいこといっぱいあるねん
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment