2026-03-07 #プログラミング
Emacsに帰った
以前情熱駆動開発という記事の中で、長年連れ添ったEmacsからvscodeに移った話を書いた。(実はそのあとneovimに行ったりもした)
あれから1年。結論から言うとEmacsに帰った。
vscodeもneovimも良いエディタだ。AIとの連携も素晴らしかった。けれど1年使ってみて僕にとって「よくできた他人の家」だった。便利だけど自分の家じゃない。どこに何があるかわかるけど配置を変えたいとは思えない。
Emacsは違う。あれは僕の手そのものだ。.emacsを書くだけで世界が変わる。設定ファイルがElispで書かれているということは、エディタの挙動そのものをプログラミングできるということ。
帰ってきて最初にinit.elを開いた時の安心感は異常だった。
やはりLisp
Emacsに帰って改めて気づいたことがある。僕はLispが好きだ。
S式の美しさ。括弧の海。あの独特の見た目を嫌う人は多いけど、僕にとっては「全てが同じ構造で表現される」という事実が心地良い。データもコードも同じ形をしている。
マクロで構文レベルから言語を改変できる。普通の言語だと「言語が用意した構文に従う」しかないけど、Lispは「自分で構文を作る」ができる。これは最強としか言いようがない。
仕事ではRubyを書いている。けどなんか足りない。Lispなんだよな。
既存Lispに思うこと
じゃあLispでなんか作ればいいじゃんという話になるのだが、実際にプロダクトを作ろうとすると既存のLisp系言語にはそれぞれ好きじゃないところがある
Clojure
Clojureは素晴らしい言語だと思う。設計思想には深く共感するし、何よりElixirもかなり影響を受けてる。immutableがデフォルト、永続データ構造、STM。思想が美しい。
けどJVMが重い。起動に数秒かかる。メモリも食う。そしてこれが決定的なのだがCloudflare Workersで動かない。
個人開発でサーバーレスにデプロイしたいのにJVMが足枷になる。GraalVMでネイティブコンパイルする手もあるけど、それはもうClojureの良さを半分捨てているような気がしてならない。
Common Lisp
Common Lispは速い。SBCLのコンパイラは本当に速い。ネイティブバイナリも吐ける。
けどエコシステムが厳しい。Quicklispにあるライブラリの数はnpmの何百分の一だし、HTTPクライアントひとつ取ってもClojureと比べると選択肢が限られる。そしてこれもやっぱりCloudflare Workersでは動かない。
Elixir
Elixirは最も完璧に近い存在だと思っている。マクロがある、パイプ演算子がある、パターンマッチがある、OTPという強力な並行処理フレームワークがある。
本当に美しい。けどBEAM VMはJVMと同じ課題を抱えている。Cloudflare Workersでは動かないし、バイナリにコンパイルできない。
惜しい。本当に惜しい。
結局何が欲しいのか
散々文句を言ったので、じゃあお前は何が欲しいんだよという話をする。
- Lispであること - S式、マクロ、これは譲れない
- バイナリにコンパイルできること - 高速で動作する。起動が一瞬
- WASMになること - Cloudflare Workersで動かしたい。ブラウザでも動かしたい
- エコシステムが揃っていること - なんでも作れる程度にはライブラリが欲しい
- 何らかの形で型を持っていること - 動的型付けだけだと大きくなった時に辛い
- パイプ演算子 -
|>がないと生きていけない体になってしまった
こんな言語、存在するわけがない。
存在するわけがないので、作るしかない。
Claude Codeなら作れるんじゃない?
以前の記事で情熱駆動開発について書いた。AIが僕の手足の延長になるという話だ。
Lispの処理系をゼロから書くのは大変だ。パーサー、評価器、マクロ展開、型チェック...。一人で全部やったら何ヶ月もかかる。
でも待ってくれ。僕の手足はもう伸びている。Claude Codeという最強の副操縦士がいる。
僕が「こういう言語が欲しい」と伝えて、設計の方向性を決めて、Claudeが実装する。僕が設計をレビューして、足りない部分を指摘して、Claudeが修正する。このループを回し続ければいけるんじゃないか?
いけた。
できたもの
数時間でできた。冗談みたいな話だけど本当に数時間で動くものができた。
lispectはLispコードをRustコードに変換するトランスパイラだ。S式で書いたコードがRustのコードになる。つまりRustのコンパイラでそのままコンパイルできる。
- 漸進的型付け - 型を書きたい時は書ける。書かなくても動く。strict modeにすれば厳格にもなる
- パイプ演算子対応 -
(|> data transform1 transform2)はもちろん、thread-lastの(->>)もある - パターンマッチ -
(match value (pattern result) ...)でenum分岐もできる - 文字列補間 - Rubyスタイルの文字列補間で式を埋め込める
- deftype/defenum - 構造体と列挙型を定義できる
- Rustのエコシステムにそのまま乗っかれる - crates.ioの全てが使える
- Lispのマクロ - quasiquote対応のdefmacroで構文レベルの拡張が可能
Rustのエコシステムに乗っかれるというのが重要で(Goではありません)、HTTPサーバーが欲しければaxum、JSONが欲しければserde、DBが欲しければsqlxが使える。エコシステム問題が一発で解決した。
そしてRustにコンパイルされるということは、当然バイナリになる。WASMターゲットもRustの仕組みでいけるはずなので、Cloudflare Workersで動かすのも時間の問題だと思っている。
欲しかったもの、全部手に入った説がある(足りなかったclaude codeさんにお願いして増やしてもらおう)
26年二度目のブログリプレイス
理想のLispが目の前にある。使わないてはない。
このブログはもともとAstroで構築されていた。しかし、
Lispectで書き直してみたらファイルサイズが減った。全82記事のソースコードの総量が目に見えて減った。S式は冗長に見えるけど、実際にはHTMLタグの開始と終了を書く必要がないし、テンプレートの抽象化がマクロで自然にできるので無駄が少ない。
ちゃんと測ってないけど、Claude Codeに記事を書いてもらう時の出力トークン量も減ってそうな気がする。S式はLLMにとっても効率的な表現なんじゃないかと。括弧が明確に構造を示してくれるからパースしやすいんだと思う。
何より全てがLispで書かれているのが気持ちいい。テンプレートもLisp、記事もLisp、ビルドスクリプトもLisp。HTMLもCSSの参照も全部S式で表現されている。raw HTMLは一行もない。
美しい。
この先
Lispectはまだ生まれたばかりだ。今はこのブログの静的サイト生成にしか使っていない。
このあとはDBに繋いでみたい。sqlxをlispectから叩いてCRUDができれば、Webアプリケーションが作れるようになる。Rustのエコシステムが使えるのでやろうと思えば何でもできるはずだ。
publicにしたらまた記事を書くかもしれない。その時はもうちょっと技術的な話も書けると思う。