9月28日、Paul TM氏が「What makes Lisp difficult to read?」と題した記事を公開した。Lispの括弧構文がなぜ読みにくいのかを、視覚認知と作業記憶の観点から分析した内容だ。
Lispは1958年に登場した最古の部類に入るプログラミング言語で、ClojureやRacket、Emacs Lispなどの形で今も現役だ。しかし「括弧だらけで読めない」という声は初心者だけでなく経験豊富な開発者からも絶えず上がり続けている。これに対してLisperは「慣れの問題」と反論することが多い。Paul TM氏はその反論を一概に否定するわけではないが、「慣れだけでは説明できない構造的な問題がある」と主張する。その根拠が、人間の視覚認知と作業記憶の特性だ。
知覚には「ハードウェアアクセラレーション」がある
議論の出発点として、著者はストループ効果を引き合いに出す。「赤」という文字が青色で書かれているとき、人は色を答えるのに時間がかかる。これは知覚が入力を均等に処理せず、文字の「意味」を自動的に読み取ってしまうことを示している。著者はこれを「知覚のハードウェアアクセラレーション」と呼び、コードの読みやすさにも同じ原理が働くと述べる。つまり、構文の読みにくさは「訓練で克服できる問題」である以前に、人間の知覚特性に根ざした問題だという立場だ。
ぼかしてみると差が歴然とする:近接の法則
ゲシュタルト心理学の近接の法則によれば、近くにある要素は関連して知覚される。C言語スタイルのoperation(arg1, arg2)とLispの(operation arg1 arg2)を比較すると、この差が浮き彫りになる。
C言語スタイルでは関数名と引数が括弧とカンマで視覚的にグループ化され、スペースの使われ方に変化がある。一方Lispでは、関数名も引数もすべて均一なスペースで区切られ、視覚的なグループの手がかりがない。
著者はこれをぼかし(ブラー)処理で可視化している。C言語の式をぼかすと「関数名の塊」「引数の塊」という複数のブロブが見えるのに対し、Lispの式では識別子がそれぞれ別々のブロブになり、周辺視野でも構造が読み取れない。目を細めて画面を見るだけで構造がわかるC言語と、そうならないLispの差が視覚的に実証されている形だ。
開き括弧と閉じ括弧が遠すぎる:閉合の法則
ゲシュタルトの閉合の法則と対称性の法則も関係する。対応する括弧のペアは、視野内に同時に収まることで初めて「ひとつのまとまり」として知覚できる。ところがLispでは、開き括弧の直後に関数名が来るため、対応する閉じ括弧が遠くなる。make-string-output-streamやcall-with-current-continuationのような長い識別子はこの距離をさらに広げる。
著者は目の解像度低下を再現した放射状ブラーで比較画像を示している。C言語では閉じ括弧が開き括弧から一目で見える。Lispでは開き括弧を「記憶」したまま、閉じ括弧が視野に入るまで待たなければならない。
この「閉じ括弧を近づけたい」という傾向は、他の言語設計にも現れている。Kotlinなどでラムダ式を括弧の外に書けるトレイリングラムダ構文が好まれることを、著者はその証拠として挙げる。
作業記憶の限界:メンタルスタック問題
視覚の問題に加えて、人間の作業記憶(ワーキングメモリ)は同時に保持できる項目数に限りがあるという制約も読みやすさに影響する。著者はこれを「メンタルスタック」と呼ぶ。
ネストが深くなるほど、まだ閉じていない括弧の数を頭の中で追い続ける必要があり、認知負荷が増す。さらに深刻なのが評価順の問題だ。(h (g (f a)))のような式では、最初に評価される(f a)が最後に読まれる。式の構造を把握する1パス目と、評価順に読み直す2パス目が必要になり、認知負荷が二重にかかる。
C言語スタイルのメソッドチェーン(file.split(",").map(toInt).filter(positive).sum())は読む順序と評価順序が一致している。Clojureが持つスレッディングマクロ(->>)は「データを左から右へ流す」記法を実現したもので、まさにこの問題への対処として設計されたものだ。著者はこれを「プログラマ自身が評価順と一致した記法を好む証拠」と見ている。
「慣れ」は本当に解決策か
著者の分析をまとめると、Lispの読みにくさには以下の構造的な要因がある。
- 近接の法則:均一なスペースのみで区切るため、引数のグループを視覚的に識別しにくい
- 閉合・対称の法則:開き括弧と閉じ括弧の距離が遠く、一目で対応を取れない
- メンタルスタックの消費:深いネストや評価順と読み順のズレが作業記憶を圧迫する
もちろん慣れによって一部の問題は軽減できる。しかしこれらの要因は人間の知覚と記憶の特性に根ざしており、訓練だけで完全には消えない。Lispのエコシステム自身がスレッディングマクロのような回避策を生み出してきたこと自体が、その証左とも言える。
詳細はWhat makes Lisp difficult to read?を参照していただきたい。