Let Over Lambda

先週から読み始めてようやく読了。先々月、半分くらいまで読んでいたのだが、中断して内容を忘れてしまっていたので最初から一気に読み直した。Let Over Lambdaは一言でいうと、Common Lispのアドバンスドなマクロのテクニックが解説されている非常にためになる本。特にマクロを定義するためのdefmacro自体を拡張するマクロや、aletやalambdaといった代表的なアナフォリックマクロ、パンドリックマクロでクロージャを開くといったLispマクロならではの技術が詰まっている。これらのマクロに共通して見られることだが、本書は一貫して構文を共通化することの重要性を説いていたのが印象的であった。lambdaフォームにはシャープクォート#'をつけないとか、スペシャル変数には耳当てをつけないとか。

筆者の主張としては最初から最後までLispを賛美するのだが、客観性に欠ける部分があったり、効率性に関しては他言語との正当な比較をしていない等、気になるところがないわけではないが、それ以上にマクロの面白さに引き込まれて読んでいて楽しかった。On Lispと並び、個人的にはかなりのヒット本。

行列積

行列積が必要になったので書いてみた。最初は配列に対する操作にしようと思ったけど、手っ取り早く使いたかったのでリストにした。loopマクロを使うとsumしてcollectするだけだから簡単に書けてよい。

1
2
3
4
5
6
7
8
9
(defun matrix-mul (a b)
(let ((n (length (nth 0 a)))
(m (length b)))
(if (= n m)
(loop for i below (length a)
collect (loop for j below (length (nth 0 b))
collect (loop for k below n
sum (* (nth k (nth i a)) (nth j (nth k b))))))
(error "Dimension error"))))

Migrate from Octopress to Hexo

年末年始にOctopressからHexoに移行したときのメモ。

まずOctopressで書いていたMarkdownの記事をHexo用のフォーマットに変換するスクリプトを書いた。

1
2
3
4
#!/bin/sh
for i in *.markdown; do
awk '!/^(layout|comments)/&&NR!=1{print $0}' $i | sed 's/^categories/tags/g' | sed 's/^title: *"\(.*\)"$/title: \1/g' > "$i".markdown.new
done

Hexoは1行目に---は書かないらしいので削除している。また、Octopressのlayout, comments等のタグもHexoでは不要なので削除し、OctopressのcategoriesはHexoではtagsとして扱うようなので変換している。最後に、Octopressでつけていたtitleのダブルクォーテーションを削除している。無論、*.markdown.newの内容が問題なさそうであれば*.markdownにリネームしておく。

また、各記事のPermalinkの設定もOctopressに合わせる必要があるが、これはHexoの_config.ymlに設定することで対応できる。

1
permalink: blog/:year/:month/:day/:title/

先頭のblog/がミソで、最初これを設定していなかったが故にOctopressとPermalinkの構造が変わってしまい、記事へのリンクが切れてしまった。(そしてしばらく気がつかなかった…)

テーマはCodelandというテーマをforkして、右のサイドペインにAboutウィジェットが表示されるようにしてみた。forkしたテーマはGithubに登録しておいた。

V8

V8をソースコードからビルドしてみるテスト。

V8のビルドにはdepot_toolsが必要なのであらかじめcloneしておく。

1
$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git

cloneしたディレクトリをPATHに追加しておく。下記のコマンドが動作すればOK。

1
$ gclient

続いてV8のソースコードをcloneする。

1
$ git clone https://chromium.googlesource.com/v8/v8.git

V8のディレクトリに移動し、

1
$ gclient sync

を実行する。あとはmakeするだけなのだが、コンパイラにclangを使うにはあらかじめ次のように設定しておく。

1
2
3
4
5
6
7
8
9
export CXX=`which clang++`
export CC=`which clang`
export CPP="`which clang` -E"
export LINK=`which clang++`
export CXX_host=`which clang++`
export CC_host=`which clang`
export CPP_host="`which clang` -E"
export LINK_host=`which clang++`
export GYP_DEFINES="clang=1"

以上の準備が整ったところで、あとは

1
$ make native

でビルドが始まる。makeのターゲットにnativeを指定すると、ホストマシンのアーキテクチャをターゲットとしたリリースビルドが指定される。手もとのMacBook Proで大体25分くらいで完了した。結果はoutディレクトリに出力されており、例えばout/native/shellを実行するとV8を組み込んだサンプルシェルが起動する。

1
2
3
$ out/native/shell
V8 version 3.32.0 (candidate) [sample shell]
>

以上の手順含め詳細は下記サイトに説明がある。

BuildingWithGYP

Hexo

今までブログはOctopressという静的サイトジェネレータを使っていたが、毎回サイトの生成に時間がかかるためなんとかしたいと思っていた。探した中で良さそうだったのがHexoというNode.jsベースのジェネレータ。サイト構築までの手順も少なく、処理速度もそれなりに速くて快適だ。準備に必要なコマンドは、

1
2
3
4
5
$ npm install -g hexo
$ hexo init blog
$ cd blog
$ npm install
$ hexo s

だけでよい。これだけで、http://localhost:4000 にアクセスしてプレビューが見れるようになる。記事を新規追加するには hexo n で引数に記事のタイトルを指定すればよく、コマンドもOctopressのrake new_post["title"]よりはだいぶ簡潔になっている。

構成もシンプルなのでテーマのカスタマイズもやりやすい。_config.ymlの設定がグローバルなJavaScriptオブジェクトとして扱われ、EJSテンプレートから参照できるというコンセプトもシンプルでいいと思う。

まあ、deployするまでまだ作業することが残っているので、実際は上記の作業だけで終わりというわけにはいかないが、GitHub Pagesを使っている場合、設定ファイルにリポジトリを設定しておけばhexo dですぐにdeployできる。

というわけでしばらくはHexoを使ってみます。

ningler - Blog application sample using ningle

ningle という Common Lisp 用の Web アプリケーションフレームワークを使ってみたところ、非常にシンプルなインタフェースでわかりやすかったので、これを使ったサンプルとして ningler というブログアプリを作ってみました。Python の近いものとして Flask というマイクロフレームを調べていたのですが、そのチュートリアルに Flaskr というサンプルがあったので、ningler はこれを ningle 用に移植したものになります。
テンプレートエンジンには CL-EMB、データベースは SQLite を使いました。データベース用の Common Lisp ライブラリは CL-DBI を使ってます。

こういった Web アプリケーションフレームワークは慣れていないので実装の一つ一つが手探り状態でした。特に ningle を使ってみて困った点は、ある URL から別の URL にリダイレクトするときにデータも一緒に引き継ぐ方法がなかった点と、セッション管理の正当な方法がわからなかった点です。前者は Flask の flash に相当する機能で、リダイレクト後にリプライするデータをバッファに積んでおき、実際にリダイレクト先にリクエストがきたときにバッファから取り出してリプライする、という使い方を想定したもので、Flask ではフレームワークとテンプレートで連携して実現できるようになってます。
一方、ningle にはそのような連携機能はないため、今回作った ningler ではフレームワーク側に文字列をバッファしておき、リダイレクト先にリクエストがきたらバッファから取り出して CL-EMB のテンプレートに env 経由で渡してあげるという方法をとりました。後者に関しては、clack:clackup するときに Clack<clack-middleware-session> を指定した上で、(ningle:context :session) で取得できるデータにログイン状態を記録することで実現しました。これは正しい方法なのかいまいちわかってません。

また、CL-EMB が他のテンプレートを埋め込む機能がなかった点に関しては、埋め込む部分を <% @var body %> としておき、他のテンプレートを execute-emb した結果を env から body に渡して埋め込みました。

こんな感じで色々ケアする部分はあるようですが、複雑なフレームワークを覚えるよりは ningle のようなシンプルなフレームワーク上に色々組み合わせて構築していく方が小回りがきくため、プロトタイピングに向いていると感じました。それにしても nitro_idiot さんはこのような便利な Common Lisp ライブラリをいくつも精力的に開発されていてすごいっす。

参考

Common Lisp の効率的なファイル読み込み

Common Lisp でファイルを読み込む方法は Slurping a file in Common Lisp が参考になる。指定したファイルを読み込み、バッファ (配列) を返す関数はこんな感じ。実測はしていないが Perl スクリプト以上の速度が出るらしい。

1
2
3
4
5
(defun read-file (path)
(with-open-file (in path)
(let ((seq (make-array (file-length in) :element-type 'character :fill-pointer t)))
(setf (fill-pointer seq) (read-sequence seq in))
seq)))

Wordbank

Wordbank に検索回数順に表示するコマンド :t を追加した。何回も検索している単語はおそらく覚えにくい単語だと思うので、これで自分の苦手単語をチェックしてみよう。

DB から検索回数の多い順に N 個の要素を取り出す処理 (nthmost) は、DB のすべての要素をソートした上で上位 N 個を取り出すという非常にナイーブな実装にしている。これは On Lisp にあるように、N が DB の要素数によらず小さい定数である場合は、上位 N 個の要素を記憶しながら DB のすべての要素を調べあげ、記憶していた上位 N 個をソートして返す、というアルゴリズムの方が効率がよい。DB のサイズが大きくなってパフォーマンスが悪くなってきたら対応してみるかな。

Android Studio 0.8.6

Android Studio がいつの間にか 0.8.1 から 0.8.6 にアップデートされていた。以前、Android Studio 0.8.1 で作成したプログラムを実機で動かそうとしたときに build.gradle の設定をこのように設定していた。

0.8.6 にアップデートしたついでに設定方法を見直してみた。まずプロジェクトを作成するときに Minimum SDK の項目に API 19: Android 4.4 (KitKat) を指定する (最新は Android L であるがこれを選択するとうまくいかなかった)。API 15 の実機で動作させるため、build.gradle の設定は以下のようにした。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apply plugin: 'com.android.application'
android {
compileSdkVersion 19
buildToolsVersion "20.0.0"
defaultConfig {
applicationId "com.example.tanaka.myapplication"
minSdkVersion 15 // Changed this value from 19 to 15
targetSdkVersion 19
versionCode 1
versionName "1.0"
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}

Wordbank

Wordbank の検索機能を強化してみた。デ辞蔵の API では検索ワードから始まる単語が複数返されるので、検索ワードが検索結果の第一候補と一致した場合、もしくは検索結果が 1 件のみの場合はそのまま意味を表示し、その他の場合は複数の検索結果からユーザが選択するようにした。また、検索ワードの語尾に * を指定することで、第一候補と一致した場合でも複数の検索結果を表示するようなインタフェースにした。

さらに、一度調べた検索結果はローカルの DB にキャッシュするようにして、次回以降は高速に検索できるようにした。無駄に検索クエリを投げないので Web サービスにも優しい。

コマンドは vi ライクにしている。:q! とか :wq とかも欲しいけど現状は未対応。

  • :q プログラムを終了
  • :w ローカル DB を保存

あとは単語ごとに検索回数を記録してソートして表示できるようにすれば、とりあえず欲しかった機能は満たされるかな。

ちょっと困っているのがコマンド入力インタフェースの実装。検索ワードを入力する状態と、検索結果から選択する状態があるため、状態を持ったクロージャがあれば何とかなるかと思っていたが、第一候補に一致した場合の検索結果の一発表示やコマンドの追加が重なって次第にカオスな感じになってきており、なんか違うなーという感じ。あるべき姿はこうではなく、インタフェースの改良やコマンドの追加に対して柔軟に対応できる拡張性のある何か。