Common Lispはこの世に存在する言語の中でストレスなくプログラムできる唯一の言語であるというのは周知の事実です(ですよね?)。にも関わらず、実際に使われる機会はそれほど多くはありません。僕自身、仕事で使うのは難しいと考えています。
たとえばこんなことを言われたとします。
「やあ深町くん。実は大急ぎでTwitterみたいなサービスをつくってほしいんだ。できれば1週間でね」
そうすれば僕はこう言うでしょう。仕方ない。Perlだ。少しの間Common Lispと別れを告げ、ひたすらCPANを検索しつづける日々を迎えます。(もしくは転職先を探しているでしょう)
なぜCommon Lispではないのか。違いは決定的なライブラリの数と質の差です。CPANには考えうる限りのライブラリがあり、しかも多くにおいて複数の選択肢が存在します。
一方のCommon Lispはライブラリがあればラッキーです。そこから、パッチを当てることなく自分の処理系でビルドでき(はい、LOCAL-TIMEはアウト)、日本語まで扱えて(Drakmaがアウト)、よくメンテナンスされたドキュメントが揃っていて(Weblocksもアウト)、さらにわかりやすいAPIがあるなんて(CL-PPCREアウト)信じがたいことです。特にWebプログラミングで使えるものはひどいです。
周りを見渡してみると、Perlに限らず、ここ10年人気を得てきた言語はWebプログラミングを容易にする努力を惜しみません。Perl、Python、RubyはWeb業界を中心にコミュニティが動いているようにすら見えます。
僕は今、このLispを取り巻く環境を心底変えたいと思っています。古い慣習(シンボルを大文字で書くなんて!)を打ち捨てて、市民権を勝ち得てきた言語から多くを学ぶべきです。そして、現実的な問題として、たとえばCommon LispでWebアプリケーションを書けるように、といった努力をすべきでしょう。
この意見に同意してくれる人は、きっとこのエントリを気に入ってくれると思います。そして協力してほしい。僕が作った”Clack“はCommon LispにWeb時代をもたらすものです。
Clackとは
Clackを一言で説明するならば、「それぞれのWebサーバが持つ差異を吸収し、統一的なAPIを提供するためのWebアプリケーション環境」です。PythonのWSGI、RubyのRackからインスパイアされて実装しました。特に実装はPerlのPlackを参考にしています。
たとえばClackをロードしたあと、以下のようなコードを実行します。
1 2 3 |
(defun app (req) `(200 nil ("Hello, Clack!"))) (clackup #'app) |
ここでhttp://localhost:5000/にアクセスすると、「Hello, Clack!」と表示されるはずです。
Clackの利点
Webサーバを抽象化すること
Rackの素晴らしい点は、よくこう説明されます。「WebサーバとHTTPリクエスト、レスポンスを抽象化することでWebアプリケーションをポータブルにする」。
しかし、これだけであればClackを実装するメリットはほとんどありませんでした。Common LispにはHunchentootというLispで書かれた(しかも高速な)Webサーバが存在し、Webサーバ自身が高レベルなAPIを提供しているからです。
あまり声に出して語られることはありませんが、Rackには素晴らしい点がもう一点あります。それはMiddlewareです。
Middlewareこそが今Lispに必要なもの
Hunchentootが提供するAPIの上に何かをつくろうと思ったとき、アプリケーションを段階的に組み立てる仕組みがありません。Hunchentootのハンドラをマクロでラップして、ラップして、ラップして。出来上がるのはWeblocksのようなどこから手をつけていいのかわからないフレームワークになるでしょう。
Common Lispのプロダクトはこういった設計で作られていることが多いです。竹内先生はこれを「泥団子」と表現しました。これはLispの強すぎる力によるものでしょう。他の言語では肩に力を入れて書くようなものが、マクロにマクロを重ねて簡単に作れてしまうがゆえです。
しかし、これをどのレイヤーでも行うならば、再利用性がとても低いアプリケーションになってしまいます。部分的な利用、変更ができないカスタマイズ性の低いものになってしまいます。
Hunchentootは必要以上に大きすぎます。URLディスパッチャだけでなく、セッション管理やログ機構まで備えています。もはや泥団子というより”そびえ立つクソ”とでも表現したほうがよさそうです。
ClackではMiddlewareを使って、コアから切り離された処理を書くことができます。
Middlewareはアプリケーションに直接手を加えることなくアプリケーションを拡張するための機構です。これを使えばアプリケーションに渡る前にHTTPリクエストをいじったり、返ってきたHTTPレスポンスを変更することができます。
この設計のメリットはプロダクトを疎結合な小さな部品で構築することができる点です。
Clackが拓く未来
Clackが既存のCLプロダクトに対して新しい点を明確にするためには、Clack上でフレームワークを作ることを考えるとわかりやすいのでもう少しClackの紹介を続けますね。
Clackには標準でClack.App.Routeというアプリケーションをバンドルしました。これはTomohiro Matsuyamaが書いた、最小のフレームワークです。
1 2 3 4 5 6 7 8 9 10 11 |
(defpackage clack-sample (:use :cl :clack :clack.app.route)) (in-package :clack-sample) (defroute app (req) (GET "/" #'index) (GET "/login" #'login) (POST "/login" #'authorize) (GET "/member/:id" #'member)) (clackup #'app) |
URLベースのディスパッチをRubyのSinatraのように記述できます。
defroute
はマクロであり、単純なdefun
に展開されます。
また、それぞれのディスパッチ先の処理は関数として渡せるため、Clackアプリケーションを渡すことも可能です。
Middlewareはどうでしょう。Hunchentootではセッションを保持する機能もありますが、保存する先がメモリかDBに限定されています。一方ClackではセッションがMiddlewareとして実装されており、以下のように呼び出せば有効になります。
1 2 3 4 |
(clackup (builder (<clack-middleware-session> :store (make-instance '<clack-session-store>)) #'app)) |
もし出力先を変えたければ、Clack.Session.Storeを継承するクラスを書くだけでFileやMemcachedにも対応することができます(僕には余力がなかった。誰か作って欲しい)。
Clackの利点は疎結合による無限の拡張性です。本当はこの上にWebフレームワークでも書いて「ほらね?」とでも言ってあげれればいいのでしょうが、まだそこまでの余力はありません(誰か作って欲しい)。
「Lispはどこまでも抽象化の層を重ねることができる」と言う人もいます。それは正しいのです。ドメイン特化の部分まで抽象化できるのは明らかなLispの力です。しかし、それは乱用すると再利用性のない巨大な泥団子になります。再利用できる部分は共通化する仕組みをつくるべきです。
プログラムの世界は移り変わりが激しいです。技術を柔軟に組み合わせを変えられなければついていくのが難しくなるでしょう。5年後もHunchentootが使える世の中とは限りませんからね。
インストール
Clackはcl-annotというライブラリに依存しているため、これを先にインストールする必要があります。cl-annotはTomohiro Matsuyamaが開発した、とてもクールなライブラリなのでいずれにしても導入することをおすすめします(この紹介記事はいずれ彼が書くでしょう)。
残念なことにClackもcl-annotもまだQuicklispのリポジトリに入っていません(申請中)。使うにはそれぞれGitHubからダウンロードする必要があります。
まずASDFの設定をします。ここでは~/lisp/systems/にライブラリを放り込むように設定しています。
1 |
$ mkdir ~/lisp/systems |
そして~/.config/common-lisp/source-registry.conf.d/01-add-local-lisp.confに以下のように記述します。
1 |
(:tree (:home "lisp/systems/")) |
これで~/lisp/systems/以下に置いたライブラリはすべてql:quickloadできるようになります。
次にgit cloneします。
1 2 3 |
$ cd ~/lisp/systems $ git clone git://github.com/arielnetworks/cl-annot $ git clone git://github.com/fukamachi/clack |
あとはQuicklispでロードすれば依存パッケージもダウンロードされ、使える状態になるはずです。
1 |
(ql:quickload :clack) |
まとめ
Clackは何人かの友人のフィードバックを得ながら開発されました。Tomohiro Matsuyamaは実際にClackを使い、疎結合による開発のメリットを深く理解してくれました。
Emacs Lispで有名なKenji ImakadoはClackからCommon Lispに興味を持ち、その上にフレームワークを作り、実際に使いたいとすら言ってくれました。
現在考えうる限りで、Clackは間違いなくCommon LispでWeb開発するために最適な環境です。ぜひ使ってほしいです。
元記事 : Common LispがWeb業界を駆逐するとき – Revenge of Lisp in Web
最近のコメント