読者です 読者をやめる 読者になる 読者になる

2015年に作っていたもの

Lisp プログラミング

2015年に作ったものまとめ。1つ例外を除いて全部Common Lispでした。

全体的に飽き性っぷりが垣間見えるだけな気もしますが、来年どれかは発展させていきたいです。

オセロ

(旧版:sample-of-eshamster/othello-cl · GitHub

github.com

作るものに困ったらとりあえずオセロを作れば良いんじゃないか、と思って作りました。学習機構は作ってないですが、簡単な静的評価関数+αβ探索とUCT(Upper Confidence bounds applied to Trees)ぐらいは作りました。あとは簡単なCUIインタフェースつきです。

適当に作った結果、ゲーム開始地点から終局までのランダムシミュレーションが(初期局面へのリバース込みで)秒間30回というひどい値になっていたので、しばらく最適化して秒間200回ぐらいにしました。さらに、この年末にも最適化して遊んでいたところ、秒間1000回ぐらいになりました。相場が分かりませんが、実用にはまだ桁が足りない気がします*1

備忘録も兼ねて最適化周りの話はそのうち記事にしておきたいです。

ちなみに、旧版は右も左も分からない頃にClozure CL上で書いていたもので、新版はSBCLにも対応しつつパッケージ周りを少し整えて移植したものです。

cl-lazy

github.com

Land of Lispにはマクロによる遅延評価の実装が出てきます。面白そうだったので自分でも書いて色々遊んでみたのがこのライブラリです。

遅延評価と言えば無限長数列というイメージがあったので、とりあえずフィボナッチ数列を作ってみました。以外と手間取ったので、まずはマクロで苦労した部分を覆い隠してみました。それでも、数学的な記法による定義(漸化式)と比べると分かりにくいのでリードマクロで数列定義文法を作ってみました。

そんな感じで、思いの他Common Lispのマクロ方面を色々触ることができて楽しかったです。

結果ですが、#<fib[n] = 0, 1, (+ fib[n-2] fib[n-1])>で無限長フィボナッチ数列が定義できるようになりました。ワンライナーで数列を定義できる言語は数あれど、ここまで分かりやすいものはないんじゃないか、と密かに思ってます。

遅延評価部分よりも数列処理部分を取り出して発展させる道はありかもと思いつつ、自分で利用する場面がないので放置してます。

cl-prime-number

github.com

cl-lazyの遊びの一貫です。無限長素数列を作って遊んでいます。具体的には、素因数分解や、分解後の素数指数表現の中で最小公倍数や最大公約数を求める関数を作っています。

ちなみに、Gaucheの持つ素数ライブラリは恐ろしく速いですね。例に出ている素因数分解をcl-prime-numberに投げても、結果が返るよりもCtrl+Cを押す誘惑に負ける方が速いです。

MAL (Make a Lisp)

github.com

Lisp方言の一つであると同時に、Lispインタプリタを実装するためのチュートリアルでもあるMALに手を出してみました。この中では珍しく、Lispではなく前々から興味のあったF#で書いています(F#によるMAL実装は既にあったので、esh-fsharpというフォルダに入れています)。

ステップ4まではやりましたが、ステップ5の末尾再帰の実装がなんだか関数型っぽくなくなりそうで尻込みしている*2のと、同時期にLispが楽しくなってきたので頓挫しています。

cl-naive-bayes

github.com

単純ベイズ分類器(もしくはナイーブベイズ分類器)です。普段使っているInoReaderに若干不満があった*3ので、RSSリーダでも自作してみようかと思い、その部品として作りました。精度は問わないので、とにかく簡単に使えるものとして作っています。

単純ベイズ分類器としては一通りできあがっています*4。が、新しいおもちゃ下記のps-experiment関係の方が面白くなってきたのでRSSリーダ自体や、それに向けた分類器への機能追加は止まっています。そのうち再開する気でいますん。

kaggle-titanic

github.com

現実の統計的課題を世界中のデータサイエンティストが競って解くというKaggleなるものがあります。某氏にそそのかされて、そのチュートリアルとして有名(らしい)なタイタニックの生存者を推定する問題をCommon Lispで解いてみました。

まずは上記のベイズ分類器を試してみて、次はもっとマシな分類器で…というつもりでいました。が、CSVデータ処理マクロを書いたところで満足してしまったので、最初の段階で止まっています*5。テストデータの正解率は77%ぐらいで箸にも棒にもかからない感じです。

マクロの成長過程の一例としては見れそうなので、そのうちたぶん記事にします。

caveman-sample

github.com

深町さん作のWebフレームワークCaveman2を使ったサンプルです。HTML直書きやデフォルトのDjulaの代わりにcl-markupJavaScript直書きの代わりにParenscript、とCommon Lispづくしで書いて見ています。

今のところ、Angular.jsでアコーディオンパネルを作ってみたり(上記のRSSリーダに向けた実験)、WebGL(Three.js)を動かしてみたりして遊んでいます。

ps-experiment

github.com

上記のcaveman-sampleを作る中でParenscriptの不満なところに色々マクロを被せていたのですが、分量が増えてきたので独立させました。

ここ数ヶ月は大体これをいじっていた気がします。基本的にはJavaScriptでしかないところはよりJavaScriptらしく、逆にCommon Lispとして書ける部分はよりCommon Lispらしく、という方向で進めています。

cl-ps-ecs

github.com

ゲームプログラムのアーキテクチャの一つにEntity_component_system(ECS)というものがあります。「[GDC 2015]エンジンとツールがないなら自作しよう。「World of Tanks Blitz」ローンチまでの道のりを開発者が振り返る - 4Gamer.net]」で知って以来、自分で書いてみたら面白そうと思っていたものです。以前はXNAオブジェクト指向な簡単なライブラリを書いたりはしてましたが、今さらXNAはないよなあ…と移行先に迷って放置していました。

今やCommon Lispという新天地を手に入れたので、せっかくだからWeb GL(→JavaScript→Parenscript→ps-experiment)でも組み合わせて作ってみようか、と動き出したところです*6

進捗としては、ようやくcaveman-sampleの方でお試し第一段を書けるようになったところです。が、まだ使える代物には全然なっていません。

特徴として、(今の所)Common LispとParenscript(+ ps-experiment)の共用コードとなっています*7。これについては、実用的な価値を求めたというより、ps-experimentの皮を被せることでどこまでCommon Lispっぽく書けるかを試している感じです。

ちなみにps-experimentの安定化にもかなり貢献しています。なにしろ数歩ごとにps-experimentのバグを2つ3つ踏み抜いていたので…*8

その他

ひっそりとSchemeGauche)やClojureを触ったりもしてましたが、githubにはまだ痕跡がないです。

また、年始にUnityを少し触っていました。簡単なモデルを作って動かしたりユニティちゃんを動かしたりしてみましたが、特に形になったものはないです。プロジェクトがすぐアセットだらけになりますが、こういうMByte級のファイルがGitの履歴に溜っていくのは気持ち悪いですし、かといってバージョン管理なしでは怖くて何も作れない体質になってしまったので、そこで挫折しています。RubyのGemfileのようなものってないんでしたっけ。アセット編集した場合どうするんだとかもあるので、簡単でないのは分かるのですが。一応自作or編集したスクリプトだけ取り出した残骸はありますが、これだけでどうなるものでもないです…。


来年に向けて

Lispという新天地を手に入れたおかげでプログラミングのモチベーションがかなり回復したので、引き続きこの方面を掘っていきたいと思います。Lispは何もかも全てLispで書きたくなる魔力に満ちていますが、他の言語にもまた足を伸ばしてみるつもりです。候補は色々浮かびますが、まあ気の向いたところに進むつもりです。

他にGithub, CircleCI, (ぼっち)Slackと環境の近代化も進めてきたので、引き続き色々なツールを漁っていけたらと思います。


*1:手生成が明らかなボトルネックになっているので、ビットボードに手を出す必要がありそうです

*2:解説を読んだ限りは、ステップ4から差分それだけでいけるのかー、と感心はしたのですが

*3:とはいえ、今は亡きGoogle Readerからの乗り換え先として検討した中では圧倒的に良いものでした

*4:はじめての怪しげな英語ドキュメントを書いてみたりもしました

*5:一応、雑なアンサンブル単純ベイズは書いてみましたが、特に精度は上がらなかった…という所で飽きました

*6:ちなみに、Parenscriptにこだわっているのは、Web GLヘビーに作るとただのJavaScriptになってしまって悔しいので、Common Lispで書ける範囲を確保したいといった辺りが理由です

*7:ps-experimentで"xxx.ps+"系のマクロをいくつか提供しています。例えば"defun.ps+"ではCommon Lispの関数とJavaScriptの関数(を生成するCommon Lisp関数)が生成されます。現状これを利用して全て書いています。肝心のパッケージ周りは作り込めていないので、use(use-package)でお茶を濁していますが…。

*8:テストはきちんと書いているんですけどね…。パッケージや評価順序周りのやっかいなバグが中々つかまらないです