7月17日、scotto.meが「A Road to Lisp: Which Lisp」と題した記事を公開した。関数型プログラミングへの関心が再び高まる中、Lispファミリーの主要方言であるCommon Lisp・Clojure・Racketを実務目線で比較し、どれから学び始めるべきかを整理した内容だ。
Lispに興味を持ったエンジニアが最初にぶつかる壁は「どのLispを選ぶか」だ。PythonやJavaは実装が複数あっても同一の言語として扱われる。しかしLispは違う。Lispは単一の言語ではなく、言語の「ファミリー」であり、Wikipediaには20以上の方言(ダイアレクト)が列挙されている。S式((operator arg1 arg2)という括弧ベースの構文)という根幹は共有しつつ、セマンティクス・標準ライブラリ・言語機能の点では大きく異なる。別の主要言語で言えば、PythonとRubyとPerlを「どれもスクリプト言語」と一括りにするようなものだ。著者は「方言の選択は重要だが、初心者が思うほど決定的ではない」とも述べており、どれから始めてもLispが持つ「問題を考えるための新しい思考様式」は身につくという。
Common Lisp:30年以上現役の「本流」
1994年にANSI規格として標準化されたCommon Lisp(CL)は、全Lisp方言の中で最も包括的かつ成熟した存在だ。代表的な実装はSBCL(Steel Bank Common Lisp)で、ネイティブコードに直接コンパイルされる。最適化されたCommon LispコードはCやRustに匹敵する実行速度を達成できるとされる。
CLの際立った特徴がコンディション&リスタートシステムだ。一般的な例外処理とは異なり、プログラム実行中に異常が発生した際、プロセスを停止させずにその時点の変数やスタック状態をインタラクティブに検査できる。「リトライ」「無視して継続」「別の値で再開」といった選択肢を実行中に提示できるため、リモートサーバーで障害が起きた場合もプロセスのREPLに接続してライブ調査が可能だ。これは他の主要言語ではほぼ見られない設計だ。
1994年の仕様が今も現役という安定性も強みで、1991年出版のPeter Norvig著『PAIP』のコードが現代の実装でそのまま動くケースも多い。RubyやPythonのような後方互換性の破壊とは無縁に近い。実際の採用例として挙げられているのは、Rigetti Computing(量子コンピューティング)、Grammarly(文法チェックのコア)、Google Flight Search(ITA Softwareの実装)、そしてHacker News(現在はSBCLで動くClarc実装で1日約1,000万ページを配信)だ。
弱点も率直に書かれている。コミュニティは小さく分散しており、企業スポンサーも不在。パターンマッチングやイミュータブルコレクション、遅延シーケンスといった近代的な機能は標準では持たない。
Clojure:JVMに乗ったモダンなLisp
ClojureはRich Hickeyが2007年ごろ、「JVMしか使えない現場でもLispを書きたい」という動機から設計した方言だ。JVMをターゲットにすることで、Javaエコシステムの膨大なライブラリ・ガベージコレクション・OS移植性を丸ごと活用できる。
言語の核心は純粋関数とイミュータブルデータ構造だ。可変状態を扱う際は atoms・refs・agents という明示的な仕組みを使う設計で、並行処理のバグを構造的に防ぐ。永続データ構造(構造共有による効率的なイミュータブル更新)、遅延シーケンス、EDN(JSONに代わるLispらしいデータ記述形式)といった現代的な設計も備える。さらにClojureScriptとしてJavaScriptへのコンパイルも可能で、サーバーとブラウザで同一ロジックを共有するフルスタック開発にも対応する。
採用企業は、ClojureのメインスポンサーであるCognitectを買収した中南米最大級のフィンテック企業Nubankをはじめ、Walmart・Netflix・Apple・Salesforce・Amazon・Cisco・Grammarlyなど幅広い。「おそらくプロダクション環境で最も多く使われているLisp」とも表現されており、実務投入のしやすさという点では方言の中で頭一つ抜けている。トレードオフはJVMのスタックトレースにJavaの実装詳細が混入する点で、デバッグ時のエラーメッセージが読みにくくなることがある。
Racket:「言語を作るための言語」
RacketはScheme(LispのもうひとつのメジャーなブランチでR7RS規格として標準化されている)から派生した方言で、教育・研究用途を中心に設計されている。独自の型システムや言語拡張機能を持ち、「プログラミング言語を作るための言語」とも呼ばれる。MIT・Stanford・Brown大学などの計算機科学教育で長年使われてきた背景があり、Racketの前身であるMzSchemeは名著『SICP』(計算機プログラムの構造と解釈)の演習環境として使われた。コミュニティ規模はCommon LispやClojureより小さく、プロダクション採用事例も限られるが、言語設計の実験や学術研究の文脈では学習リソースが最も豊富な選択肢だ。
結局どれを選ぶべきか
著者がまとめる選択の指針は明快だ。Lispの思想を純粋に学びたい・歴史的な資産を活かしたいならCommon Lisp(SBCLから始めるのが無難)、実務投入しやすくモダンな関数型設計を試したいならClojure(Javaチームへの導入パスもある)、言語設計や教育・研究が目的ならRacketが向いている。
どれを選んでも、Lispが与える「コードとデータが同じ構造を持つ」というホモイコニシティ(homoiconicity:プログラムコードそのものがデータ構造として操作できる性質)の感覚と、マクロによるメタプログラミングの体験は共通して得られる。
Common Lispの入口として記事で紹介されている主なリソースは以下だ。
- A Road to Common Lisp(Steve Losh)— 本記事の「シリーズ前作」に相当する定番ガイド
- Practical Common Lisp(Peter Seibel、無料公開)
- On Lisp(Paul Graham、マクロに特化)
- The Common Lisp Cookbook(実践的なチュートリアル集)
- IDE:Emacs + Sly または SLIME が最良の選択肢とされている
Clojureについては、Clojure公式サイトのGetting Startedが整備されているほか、コミュニティSlackのClojurians(参加リンク)が初心者にも質問しやすい場として知られている。
詳細はA Road to Lisp: Which Lispを参照していただきたい。