'(you lisp me)

Lispって何だ

繋がるAndroid端末とPC

先日,ECL Androidなるものがリリースされていました.

ECL自体はCommon Lispの処理系の1つで,Cのソースコードへ変換してコンパイルするのが特徴です.ECL AndroidはそれをAndroidアプリとして動作するようにしたもののようで,ちょうど手元にAndroidタブレットがあったので早速インストールしてみました.apkファイルはこちらからダウンロードしました.

起動画面

f:id:iriscode:20151114175808j:plain

起動するとコンソールのような画面でeclが走ります.

初回起動時にはswankがインストール・コンパイルされます.

一見するとコンソールのような見た目ですが,キャレットもなく標準出力をそのまま表示しているだけのようです(?).実際に式を評価するにはいちいち右上のメニューからEvalを選択して式を入力しなければならないようで.しかしEvalの上にSwank serverという項目があり,これを選択するとSwankサーバーが立ち上がります.

ということは,他の端末から接続することが出来るじゃないか!

接続方法

まず(Swankサーバーを立ち上げた)接続先の端末のIPアドレスを知る必要がありますね.

Androidの「設定」→「端末情報」→「端末の状態」→「IPアドレス」からIPアドレスを確認してどこかにメモっておきましょう.次に,接続先の端末と同じネットワーク環境内にある端末(PC)からCommon Lisp処理系を立ち上げます(ここはECLじゃなくても大丈夫です).Swankサーバーに接続するために(ql:quickload :swank-client)したら,

(swank-client:with-slime-connection (conn "接続先のIPアドレス" Swankサーバーのポート番号)
(swank-client:slime-eval '(format t "Hello, Android!") conn))

を実行します.

するとAndroid端末の方にHello, Android!が出力されます.やったぜ.

(get-quicklisp)を評価するとquicklispも入るそうなので,もしかしたらAndroid端末上でCommon Lispプログラミングが出来るのかもしれません.とてもワクワクしますね!

Swankサーバーへの接続についてはこちらの記事を参考にさせて頂きました.

2-gramのマルコフ連鎖

マルコフ連鎖という文生成アルゴリズムがありますね.原理としてはすごく簡単なので人工知能入門には最適です.なので実装してみました.以下にコードを示します.

これをコンパイルして実行した結果が以下になります.
入力テキストは青空文庫から「走れメロス」を使わせていただきました.

# ./malkov-chain melos.txt メ 10 > output.txt
# cat output.txt
メロスは赤面して、あ、ちに、決しは夜だ。
メロスは、自分の心臓を全里程のと颯ったらいかって来ぬ、われて、待ったいるこいだ。
メロスは出かっていでも、私は夢だ大きずべらな事だ! メロスのまち伏せぬ、醜い。
メロスは、も言うに私のだぞ。
メロスは、途で精神々としくれると信実と頭は無いうになメロス。
メロスはた様子です。
メロス様の旅人を振ったらめてくり挙げて来た。
メロスは幾度を聞え、水がわぬ、市に上りといたがいる。
メロスは、信実はじ、メロスは短剣が空虚なんでに涙を拍ってきくなって哀れる希望みじくこへ行くりのけれかりで逢われしも永く走った小降りしたちとし、わし、こと、喉が、人た。
メロス、「うち、待しまえに到達セリヌンティウスも照覧あある事は出しに最も言って答えた。
メロス、三里程の一人のだ陽気に答えたち彼はなくれかなっときな衣裳やつもとメロスは、降りに裏切りし寄せぬる。
メロストラクスは、お目撃ちをすの一切のだ、は、そのだつめだ。
メロスは在る。
メロスは、ちだ十里行けてく、永くらして、つで、王城になるがつも、わし瞬間、そのは、や、不貞腐れた頃である。
メロスは、犬を持ったて来た。

参考本のコードをそのまま移植したようなものなので,解説は省かせていただきます.
やたら型指定をしていますが,実際どの程度するべきなのでしょうか?必要な箇所のみで良いという記述を見たことがある気がするので,この場合はやり過ぎなのかな.ちなみに実行時間は0.05sぐらいでした.

実装にあたって参考にした本がこちらです.

簡単な文章生成に始まり,音声処理,会話応答システム,遺伝的アルゴリズムを利用した学習など人工知能技術の入門書に相応しい内容となっています.中身のプログラムは簡単なC言語で書かれているので非常に分かりやすかったです.形態素解析の方法も載っているのでMeCabのようなことを自力でやる場合にも良いかもしれません.まだ読み終わっていないので,今度はもっとまともな文を生成出来るプログラムを書きます.

フィボナッチでのベンチマーク'(C CCL SBCL)

正直ベンチマーク記事は(世に溢れてるから)あまり書きたくなかったのですが,少しびっくりしたことがあったので書きます.

ベンチを取るに至った経緯

先日,某SNSで知り合った方とSkypeでお話する機会がありました.内容の殆どがプログラミングの話題で,互いのやりたいことについて語りました.非常に楽しかったですし,自分とは違う所を目指している人との話は新鮮でした.その中で出た話題の一つに,一番パフォーマンスの良い言語は何かということがありました.彼は,一番速いのは結局のところ最適化をかけたCだろうと言っていました.確かにその考えは現実的であり,もっともであると思いました.しかし僕はLispに夢を抱いてしまったがため,多少劣ろうがLispも負けてはいないというところを証明したかったのです.

結果

さて,それでは実際に結果をお見せしましょうか.以下がベンチマークの結果になります(測定はtimeコマンド).
僕が今回驚いたのは,Clozure CLがSBCLの速度を上回っていることです!

追記(2015/10/18 15:20):
redditの方でご指摘があったので,CLの方の戻り値の型指定と最適化オプションを追加してみました.
また,10回計測して最も速いタイムを記載するようにしました.
依然としてClozure CLの方が速いようですが,SBCLもCの1/2倍を切りました!

gcc -O2(5.2.0) time
real 0m0.201s
user 0m0.200s
sys 0m0.000s
ccl(1.11) time
real 0m0.340s
user 0m0.333s
sys 0m0.007s
sbcl(1.2.12) time
real 0m0.362s
user 0m0.360s
sys 0m0.000s

ベンチマークコードが以下になります.

CLのコードはsbclでもcclでも同じコードから実行ファイルが生成出来るように,実行ファイル生成部分をまとめてみました.今回の結果を比較してみると,型指定などの最適化を施すとCommon LispでもCの1/2倍程度の速度が出ることが分かります.他の言語とも比較してみないと詳しいことは分かりませんが,上出来でしょう.

結果的にはCLの負けですが,例えば以下のようなコードだとどうでしょうか.

これの測定結果が以下になります(cclもほとんど同じ結果).

sbcl time
real 0m0.006s
user 0m0.003s
sys 0m0.000s

このコードでは150番目のフィボナッチ数を求めています.先ほどの'よくあるフィボナッチ数を求めるコードで150番目の数を求めようとすると,非常に長い時間がかかります(なので僕は求まる前にC-cしてしまいました).このように同じ結果を求める場合でも,書き方によっては非常に速くなる場合があります.
追記(2015/10/23 11:44):
そもそもこれなら末尾最適化した方が速いですね(笑)

同じことをCでやればより速いタイムで上回って来るとは思いますが,僕が思うにこれがLispでCに(速度で)勝つ方法なのではないでしょうか.

ProjectEulerを少しだけ

アウトプットの場は出来た.さあ何を書こうか.
とりあえず今まで書き溜めたLispコードを小出しにしていきましょうか.

Project Eulerの問題に挑戦

肩慣らしに簡単な数学の問題をいくつかLispで解いてみました.他の言語と違って書き方が色々あって面白かったです.以下は僕の足りない頭を捻りにひねって導き出したコードです.もっと効率の良い書き方がありましたらご教示ください.

解答は(solve-n)の形式でまとめてみました.

今更ですが4番目のコードの回文数かどうか判定する部分は,reverse関数でリストを逆にしてequalで比較しても良かった気がします.

それにしてもインデントのルールがイマイチ掴めませんね…….

僕とLisp

僕について

今年から大学生になりました.
情報系の学部に所属しております.

プログラミングを学び始めたのは小学4年生の時で,当時はゲームプログラマーを目指していました.
しかし,吉里吉里ライクなノベルゲームエンジンの開発などを経て,ゲーム作りを支援する方向に転換しました.
現在は人工知能のゲーム等への応用を目指して勉強しています.

僕とLisp

初めてLispに触れたのは中学生の頃でした.
CやPerlを学んで,さあ次は何をやろうか,という時にCommon Lispに出会いました.
当時はこの言語で一体何が出来るんだろうと思っていました.
ネットを頼りに情報を集めても,わくわくするようなインスピレーションは得られませんでした.
僕の使う言語選びの基準は'ワクワクでした.
よって,その時はすぐに切り捨ててしまいました(今思えばなんと愚かなことか).

Lispとの再会を果たしたのが今年のことでした.
偶然にも僕が配属された研究室ではCommonLispを研究に使っていたのです.
それを知って再び興味を持ち,'Lispをキーワードに検索をかけて辿り着いたのが深町さんのブログでした.
彼(と呼んでいいのか躊躇いがありますが)はおそらく日本で最も活発に活動しているLisperです.
そんな彼がLispを始めたのが(推測ではありますが)およそ6年前で,僕が初めてLispに触れたのとほぼ同時期です.
(今でこそ彼は日本を代表するLisperなのですから,きっとその時が彼の人生の分岐点だったのでしょう).

技術力の差はあれど,僕も今からでも彼のようにLispを操れるようになりたいと思いました.
彼のプロダクトはワクワクするものが多い.
というのも,僕のキャリアで最も大きな比率を占めているのがWebプログラミングだからです.
Perlは先述した通りですが,とくにJavaScriptを長くやっていました(ノベルゲームエンジンJavaScript).
やはり,Lispといえば人工知能,というイメージが強かったのですが,彼の製作物がその考えを改めさせてくれました.
僕の中で何か革新が起こり,再びLispと向き合ってみようという気さえ起こしたのです.
それがじっくり時間をかけてLispを学んでみたいと思ったキッカケでした.  

さて,2015年現在,人工知能界隈ではpythonが注目を集めているようですが,僕はあえてLispでの実装を試みます.
そもそも人工知能のために考えられた言語なのですから,当然といえば当然ではありますね.
また,興味のある分野にはどんどん挑戦して行きたいです.
もちろんLispで.

このブログには僕がLispを理解するために行っていることを書きたいと思います.
(Lispへの熱い想いもありますが,それを語るにはまだまだ知識も語彙力も足りませんので)

多くの人がLispを好きになってくれることを信じて.

(exit)

#| まとまりの無い文章失礼しましたorz |#