十四歳の夏まで、ぼくは一人で Haskell のコンパイラを作っていた。
正確に言うと、Haskell 全部ではない。let と where と代数的データ型と、遅延評価と、Hindley-Milner の型推論と、case 式と、map や foldr が気持ちよく動くくらいの、小さな方言だった。
でも、ぼくの中ではそれで十分だった。
世界には、父さんの古いノートPCと、学校の授業で配られた数学の問題集と、図書館で借りた『実践 Haskell』と、『型システム入門』のコピーと、ぼくの言葉にならない焦りがあった。コンパイラは、その焦りを一行ずつ別のものへ変える機械だった。
字句解析器は書けた。
パーサも、まあ書けた。
AST もできた。
でも、型推論器は時々、自分の尾を食べる蛇みたいに壊れた。遅延評価を素朴に実装すると、今度は空間効率がひどくなった。take 10 fibs を動かしただけで、ノートPC のファンが戦争みたいに鳴った。
それでもやめなかったのは、Haskell が好きだったからだと思う。
あの言語には、急いで結論へ行かなくてもいい感じがあった。値を必要になるまで待たせておける、という発想が、十四歳のぼくにはやさしかった。世の中のだいたいのことは、学校でも家でも、もっと早く答えろと言ってくる。Haskell だけは、まだ今じゃなくていい、と言ってくれた。
ぼくはその夏、コンパイラにまだ名前をつけていなかった。
名前をつけると、急にだめになる気がしたからだ。
1. 字句解析
彼女と会ったのは、市立大学の公開講座だった。
題目は「圏論とプログラミング入門」。中学生が行く場所ではなかったと思う。実際、教室の後ろにいるいちばん年下っぽい人間は、ぼくひとりだった。
講義をしていた若い准教授は、黒板に関手だの自然変換だのと書きながら、「分からなくても気にしなくていいです、今日は雰囲気だけ持って帰ってください」と言った。
その直後、前から二列目の右端に座っていた女の子が手を上げた。
「雰囲気だけだと、たぶん誤解します」
教室が少しだけ笑った。
でも彼女は笑わなかった。
小柄で、白いシャツの袖を二回折っていて、髪をひとつに結んでいた。見た感じでは、ぼくと同じか、一つ上くらいだった。
准教授が「じゃあ、どこが誤解されやすいと思いますか」と聞くと、彼女は立ち上がって黒板の前に行き、チョークを取った。
そして、さっきまでぼくがなんとなく煙みたいに見ていた図式を、きれいに書き直した。
「関手が何を保つかを最初に言わないと、ただの言い換えみたいに見えます」と彼女は言った。
「あと、プログラムとの対応を話すなら、圏の側に射しかないことと、計算の側に副作用があることの差も先に置いたほうがいいと思います」
教室が静かになった。
ぼくはその瞬間の感じを、今でもよく覚えている。
才能というのは、光るというより、周囲の輪郭を急にはっきりさせるものだ。
講義が終わったあと、ぼくは廊下で配られていたレジュメを鞄に入れながら、自分のノートを落とした。
ページが開いて、そこに書いてあった Γ ⊢ e : τ や、未完成の型推論規則や、雑な unification のメモが廊下の床にさらされた。
「Haskell?」
さっきの女の子の声だった。
ぼくはびっくりしてノートを拾い集めた。
「正確には、Haskell の小さい方言です」
「コンパイラ書いてるの?」
「はい」
「一人で?」
「はい」
彼女は、少しだけ黙ってから言った。
「いいね」
その一言が、ぼくには意外だった。
ふつうは、え、なんで、という顔をされる。十四歳で Haskell のコンパイラを自作していると話すと、だいたい二種類の反応が返ってくる。ひとつは薄い賞賛。もうひとつは、わざわざそんな遠回りをする理由が分からないという、本気の困惑だ。
彼女の「いいね」は、どちらでもなかった。
ただ、本当に、いいと思った時の声だった。
「どこまでできてるの」
「型推論が、まだ少し」
「少し、で済む?」
「済んでないです」
彼女はそこで初めて笑った。
「だよね」
それから、自分の名前を言った。
朝倉澄。
中学二年。数学オリンピックの国内合宿に出ていて、公開講座は大学の先生に誘われて来たのだという。
「ぼくも中二です」
「へえ」
「へえ、って」
「同い年に見えなかった」
「そっちもです」
澄はまた少し笑って、「ノート、見せてもらっていい?」と言った。
ぼくはためらったけれど、渡した。
彼女は立ったまま二ページめくって、すぐに言った。
「let の一般化、ここだと外に出しすぎるよ」
ぼくは一瞬、何を言われたのか分からなかった。
「え?」
「この場合、自由型変数の扱いがずれる。あと、occurs check も抜けてる」
ぼくはノートを取り返すみたいにして見た。
本当に、その通りだった。
その日、ぼくは彼女と最寄り駅まで一緒に歩いた。
電車が来るまでの七分くらいの間に、ぼくは自分のコンパイラのことを説明した。字句解析、レイアウトルールの簡略化、型環境、再帰、case 式、そして遅延評価のせいでヒープが膨らむ問題。
澄は途中で一度も退屈そうな顔をしなかった。
「今度、ノートPC 持ってきて」と彼女は言った。
「図書館で見たい」
ぼくは平静な顔で「いいよ」と答えたけれど、電車に乗ってから十分くらい、手のひらが熱かった。
2. 構文解析
それから、ぼくらは毎週土曜日に会うようになった。
駅前の図書館の自習室は、冷房が強すぎて、八月でも長袖がほしくなる場所だった。ぼくは父さんのお下がりのノートPCを持っていき、澄は大学ノートとシャープペンを持ってきた。
最初の二時間で、彼女はぼくの型推論器のいちばん悪いところを三つ見つけた。
一つ目、occurs check が抜けている。
二つ目、let の一般化を環境の自由型変数からちゃんと引いていない。
三つ目、エラーメッセージがひどい。
「三つ目がいちばんひどい」と澄は言った。
「だって、型エラー出た時に unification failed だけだよ」
「それはまだ途中だから」
「途中の人ほど、親切にしたほうがいい」
澄はそういう言い方をした。
正しさを言う時に、相手を殴らない。
ぼくはそこが好きだった。
ぼくがコードを書くあいだ、彼女は横で数式を書いた。
型環境をきれいに置き直し、推論規則を書き、let 多相がどこで効いてどこで効かないかを、小さな反例で示した。
ぼくは実装が得意だった。
バグの匂いを見つけるのも、ひどいコードを少しずつ動く形に寄せるのも、たぶん上手かった。
でも澄は、もっと高いところから全体を見た。
「たぶん、ぼくは木を見てるんだと思う」と言ったら、
「私は森じゃなくて、木のあいだの空気を見てるだけかも」
と彼女は言った。
その比喩はよく分からなかったけれど、たしかに彼女はそういう見方をした。
ある土曜日、ぼくは遅延評価の実装で完全に詰まっていた。
関数適用のたびにサンクを積んでいたら、共有がうまくいかず、同じ式が何度も評価される。メモ化を雑に入れると、今度は更新タイミングがずれて変なバグが出る。
澄はしばらく黙ってコードを見てから、ノートに小さな半順序を書いた。
「たぶん、⊥ から上がっていく感じで考えたほうがいい」
「どういうこと?」
「値がまだ決まってない状態も、値の一部として扱うの。完全に分かった時だけ本物、って考えると苦しくなる」
それはドメイン理論の初歩だった。
もちろん、十四歳のぼくらはそんな大きな名前を、毎回口にしていたわけじゃない。
でも彼女は、数学の言葉を、年齢とは無関係な自然さで使った。
「決まってないことを、ちゃんと決まってないまま扱えるのって、大事だよ」
と澄は言った。
その言い方は、コンパイラの話でもあり、たぶんそれ以外の話でもあった。
澄は考える時、シャープペンを回さなかった。
先端を紙に軽く置いたまま、数秒だけ止まる。
それから、一番短い線で本質まで行くみたいに書く。
その癖を、ぼくはいつのまにか好きになっていた。
3. 型推論
九月の終わり、ぼくらは初めて、ちゃんと動くものを見た。
画面の上で、take 10 fibs が一行ずつ値を返した。
ノートPC のファンはまだうるさかったけれど、少なくとも機械は暴走せず、型推論も通り、遅延リストはきれいに頭から十個だけ出てきた。
「出た」
とぼくが言うと、
「出たね」
と澄が言った。
それだけのことなのに、その日の図書館では声をひそめるのが大変だった。
ぼくらは自習室を出て、一階の自販機で冷たいミルクティーを買って、外のベンチに座った。九月の風はまだ少し暑かったけれど、八月よりはちゃんと夜に近づいていた。
「名前つけないの」と澄が言った。
「まだ早い気がして」
「じゃあ仮でいいよ」
「仮?」
「全部、最初は仮でしょう。定義だって、公理だって、あとから直すじゃん」
ぼくは少し考えた。
「じゃあ、Kite」
「どうして?」
「軽くしたいから」
「いい名前」
そうして、ぼくのコンパイラには、初めて名前がついた。
そのころには、ぼくらはコンパイラ以外の話も少しするようになっていた。
学校のこと。
クラスのこと。
家のこと。
澄の家には数学の本が多かった。彼女のお母さんは高校で数学を教えていて、お父さんはもういなかった。
「いない、って死んだとかじゃないよ」と澄はあっさり言った。
「単純にいないだけ」
ぼくはどう返していいか分からず、「そっか」とだけ言った。
彼女はそういう時、こちらに気を使わせないように話す人だった。
ぼくの家では、父さんが工場勤務で、母さんが夜勤のある看護師だった。悪い家ではなかった。ただ、ぼくの作っているものを、たぶん誰も本当には分からなかった。
「ゲームじゃないの?」と父さんは言ったことがある。
「ゲームではない」
「じゃあ、なんで作るんだ」
その問いに、ぼくはうまく答えられなかった。
澄は、その答えを半分くらい知っている人だった。
十月のはじめ、公開講座の准教授に途中経過をメールで送ったら、研究室の輪読会で十五分だけ話してみないかと返事が来た。
ぼくは Core への変換と遅延評価の実装を説明した。
澄は、主型がどう保たれるかと、簡単な strictness 推定をどこまで安全に入れられるかを黒板に書いた。
大学院生が何人か質問して、澄はその場で反例を一つ潰し、ぼくはノートPC を開いて実装側の差分を見せた。
終わったあと、准教授が「二人でやっていると、数学がそのまま道具になるんだね」と言った。
たぶん、その日が最初だった。
ぼくが一人で積み上げていたものが、澄と組んだことで急に外の空気に触れたのは。
ぼくらは十月、Kite に Core 言語を入れた。
表向きの糖衣をいったん剥がして、ラムダ、適用、let、case に落とす、小さな中間表現だ。
「人もこういうのあるのかな」と澄が言った。
「表面を剥がすと、もっと少ない要素にできる、みたいな」
「それ、あんまり剥がしすぎると嫌われると思う」
「たしかに」
澄はそう言って笑った。
その笑い方が好きだと思ったのは、たぶんその頃だった。
コンパイラが少しずつ賢くなるのと同じ速度で、彼女のことを好きになるのは、なんだか卑怯な感じもした。
でも、本当にそうだった。
ぼくが一人で持っていた、実装の喜びや詰まりや、型が通った時の妙な静けさを、彼女はほとんど同じ場所で分かった。
そういう人は、今まで一人もいなかった。
4. 最適化
十一月になると、Kite はもう小さな言語処理系として胸を張れるくらいには動いていた。
代数的データ型は動く。
パターンマッチも動く。
型推論はほとんどの例で素直に通る。
簡単な strictness の推定も入れて、あまりに明らかなサンクは作らないようにした。
ぼくはプログラムを書き、澄はテスト用の式と反例を持ってきた。
彼女は証明だけをする人ではなかった。
実装に降りてきた時の彼女は、すごく速かった。型規則の話をしていた十分後には、簡単な QuickCheck 風の性質テストを自分で書いて、「これ、壊れてるよ」と静かに言う。
「澄って、数学の人なのに、なんでそんなに実装も分かるの」
と聞いたら、
「分かりたいから」
と彼女は言った。
「定理だけだと、たまに寂しい」
その言葉は、ぼくの中に長く残った。
ぼくらは図書館が閉まるまで作業して、駅まで歩いた。
途中のコンビニで肉まんを買って、川沿いの道をゆっくり歩いた。
澄は、アメリカの大学のオンライン講義を夜中に見ていると言った。講義の速さは日本の高校の授業と全然違って、でもそのほうが気持ちいいのだと。
「向こうの先生、たまに証明を五行飛ばすんだよ」
「ひどい」
「ひどいけど、面白い」
ぼくはその時、少しだけ不安になった。
不安の形はまだはっきりしなかった。
でも、自分が一生かかっても辿り着けない速さで、彼女がどこかへ進んでいく感じは、前からうすくあった。
それでも、その冬がずっと続くような気もしていた。
若いというのは、未来を知らないことではなく、今の続きを根拠なく信じられることなのだと思う。
十二月の最初の土曜日、澄は図書館に来るなり、封筒を机の上に置いた。
「来た」
中には、英語の手紙が入っていた。
アメリカの大学の、早期進学プログラムからの招待だった。
数学の特別選抜で、年齢条件を外した審査に進んでほしい、という内容だった。渡航費の補助。寮。指導教員候補の名前。必要書類の締切。
ぼくは最初の三行を読んだだけで、頭が少し白くなった。
「すごいじゃん」と言った。
言葉はそれだけだった。
澄はうれしそうではなかった。
「行きたい?」
とぼくは聞いた。
「分からない」
「分からないんだ」
「分からないよ」
澄は封筒の角を指でなぞりながら言った。
「行きたい、はある。でも、十四歳だよ」
「うん」
「お母さん一人だし、英語もまだ完全じゃないし、そもそも、行ったらたぶん戻れない」
ぼくは何か言おうとして、やめた。
そこでたぶん、いちばん最初に浮かんだのは、自分のことだった。
Kite がある。
毎週の図書館がある。
土曜日の自販機がある。
それがなくなるのは嫌だ、と。
その考えは、あまりにも正直で、少し恥ずかしかった。
「まだ、このコンパイラ終わってないのに」
気がつくと、ぼくはそう言っていた。
澄は顔を上げた。
「うん」
と言ったきり、少し黙った。
ぼくは、その沈黙で、自分がひどく子どもだと知った。
5. コード生成
その日から二週間、ぼくらは少しぎこちなかった。
会えばコンパイラの話はする。
でも、アメリカの話になると、どちらかが少しだけ黙る。
Kite はそのあいだにも進んだ。型注釈つきのエラーメッセージが少しましになり、パターンマッチの網羅性チェックも簡易版ながら入った。小さな最適化もいくつか動いた。
進んだのに、前より楽しくない瞬間があった。
ぼくはそのことに、かなり戸惑った。
好きな人と一緒に作っていたものが、その人を失うかもしれないという前提に触れた瞬間、別のものに見える。そういうことが実際にあるのだと、ぼくはその時初めて知った。
クリスマスの少し前、澄はぼくの家に来た。
母さんが夜勤で、父さんは遅番だった。
こたつの上にノートPC を二台置いて、ぼくらはコードを見た。
外は寒かったけれど、部屋は乾燥していて、加湿器だけが小さく鳴っていた。
「この前はごめん」と、ぼくは先に言った。
「コンパイラを言い訳にした」
澄は少しだけ目を細めた。
「うん」
「ずるかった」
「うん」
「でも、終わってほしくなかったのも本当」
澄はそこでやっと、少しだけ笑った。
「私もだよ」
「え」
「Kite、まだ全然未完成だし」
「そこ?」
「そこも」
その「も」が、ぼくにはありがたかった。
「ねえ」と澄が言った。
「コンパイラって、なんのためにあると思う?」
「急にでかいこと聞くね」
「今、でかい話してるから」
ぼくは少し考えた。
「別の機械で動くようにするため」
「それだけ?」
「意味を保ったまま」
澄はうなずいた。
「そう。そこ、大事」
それから彼女は、ぼくのノートの空いているページに、小さく書いた。
source ≠ target
meaning survives
「私はさ」と彼女は言った。
「日本にいても、向こうに行っても、たぶん別の形になる。でも、別の形になるのって、悪いことじゃないのかもしれない」
その時、ぼくはやっと少し分かった。
コンパイラの仕事は、元のコードをそのままの姿で保存することじゃない。
別の環境で動ける形に翻訳して、それでも意味を失わせないことだ。
もし本当に澄のことが好きなら、ぼくが守りたいのは、毎週土曜に図書館で会える形式のほうじゃないはずだった。
ぼくはこたつの上のシャープペンを見たまま言った。
「行ったほうがいいと思う」
澄はすぐには返事をしなかった。
それから、とても静かに、
「うん」
と言った。
その「うん」は、前より少しだけ遠く聞こえたけれど、たぶん正しい距離だった。
6. 出力
出発の日、ぼくは成田空港へ行った。
大晦日の少し前で、空港は旅行客と見送りの人でざわざわしていた。スーツケースの車輪の音、アナウンスの声、ガラスの向こうの冬の光。世界にはこんなに簡単に遠くへ行く装置があるのに、見送りという行為だけが昔から変わらないのは、少し不思議だった。
澄は紺色のコートを着て、小さめのキャリーケースを引いていた。
彼女のお母さんは緊張した顔で、でも泣いてはいなかった。強い人だなと思った。
「これ」と澄が言って、ぼくに一冊のノートを渡した。
大学ノートだった。
表紙の右下に、小さな凧の落書きがしてあった。
開くと、Kite の型規則と、遅延評価のメモと、strictness 解析の改良案と、その合間に小さな証明がいくつも書いてあった。最後のページには、
Release 0.1 までにやること
とあり、その下に十七項目並んでいた。
「多い」
「暇な時にやって」
「暇じゃなくてもやると思う」
ぼくも鞄から USB メモリを出した。
「こっちは最新版」
「Git あるのに?」
「分かってるけど、物で渡したかった」
澄は少し笑って、「ありがとう」と言った。
出発のアナウンスが流れた。
そのあとに何を言ったか、実は細かくは覚えていない。
気をつけて、とか、向こうでもちゃんと食べて、とか、そういう普通のことを言った気がする。
でも、一つだけ、はっきり覚えている言葉がある。
「Kite、ちゃんと名前にしてよ」と澄が言った。
「仮じゃなくて?」
「もう仮じゃないでしょう」
ぼくはうなずいた。
「うん」
澄は搭乗口の前で一度だけ振り返った。
手を振った。
ぼくも振った。
それだけだった。
飛行機が見えなくなるまで空港に残る人もいるのだろうけれど、ぼくは途中で帰った。見えなくなるところまで見てしまうと、ほんとうに全部終わる気がしたからだ。
帰りの電車の窓に、夕方の空が流れていた。
ぼくは膝の上のノートを開いた。
澄の字で書かれた型規則は、ぼくの字よりずっときれいだった。
読みながら、少しだけ泣いた。
でも、不思議と絶望ではなかった。
寂しさはあった。
ひどくあった。
けれど、寂しさと正しさが同じ場所にあることを、あの日のぼくは初めて知った。
家に帰って、ノートPC を開き、リポジトリの README を編集した。
タイトル欄に、こう書いた。
Kite
A small lazy functional language with type inference
その下の謝辞に、最初の一行として、朝倉澄の名前を書いた。
コンパイラは翻訳機だ。
同じ形のまま引き止めるためではなく、別の機械で、別の場所で、それでも意味を失わずに動けるようにするためのものだ。
たぶん、人を好きになることも、少しだけそれに似ている。
十四歳の夏、ぼくは一人で Haskell のコンパイラを作り始めた。
十四歳の冬、そのコンパイラは、もう完全に一人のものではなくなっていた。