
2026/01/17 4:34
「Pythonで90行に凝縮するAPL/K のゴルフ」
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
## Summary この記事では、MITでIPLを拒否した後にジョン・マッカーシーが開発したリープ(Lisp)と、ハーバード大学の* A Programming Language *(1962年)で公開されたケネス・アイヴァーソンのAPLという二つの初期ミニマリストプログラミング言語が、どのように現代の数値ライブラリに影響を与えてきたかを追跡します。1979年にアラン・ペルリスが議長を務めたパネルでは、LispとAPLを統合するべきかどうかが議論されましたが、結論には至りませんでした。一方でアイヴァーソンは同年トゥリング賞を受賞し、「Notation as a Tool of Thought」という講演を行いました。 APLの字形アルファベット(各記号が完全な概念を表す)とその配列中心のミニマリズムという核となるアイデアは、NumPy、PyTorch、TensorFlow、JAXなどのライブラリにおいて、ブロードキャスティング、ベクトル化、および軸に沿った削減を通じて実装されています。 アーサー・ウィットニーはアイヴァーソンの弟子であり、11歳の時にAPLに初めて触れ、後に1988年に取引システム向けのA+方言を構築しました。1992年に彼はこれらの影響を統合し、K言語を作成しました。多次元配列をネストされたリストで置き換え、徐々にLispの機能(ラムダ式、条件分岐、高階演算子など)を取り込んでいきました。 Jは1990年に最初のASCIIベースのAPLとしてリリースされ、この伝統をさらに近代化しました。 著者はKをPythonで再実装する計画を立てています。これは、`monad` と `dyad` という二つの高階関数を用いてスカラー拡張(ベクトル化)を明示的なループやNumPyなしに可能にします。約100行程度の簡潔なスクリプト(`k.py`)がGitHubで公開され、LispのセマンティクスとAPLのコンパクト表記法の融合を示すものとなります。 この作業は二つのパラダイムが共存できることを示し、開発者に数学的操作をより簡潔に表現する方法を提供します。将来的な数値計算言語設計にも影響を与える可能性があります。
本文
エジプト象形文字――初期の視覚的記号体系
以前投稿した Homoiconic Python では、コードとデータが同一である言語、McCarthy の Lisp を探求しました。ここに示された表現力は並行して生まれた別の道を持っていました。
1956 年に開催されたダートマス会議でジョン・マッカーシーは Newell と Simon が開発したリスト処理言語 IPL に出会います。彼はリストという概念自体は好きでしたが、言語そのものを嫌っていました。そのため、次の二年間を MIT で Lisp を構築することに費やしました。同じ年、ケネス・アイヴェルソンはハーバードで数学を教えており、従来の表記法ではアルゴリズムを十分に表せないことに不満を抱いていました。彼は独自の表記体系を発明し、1962 年に A Programming Language として公開しました。この本が APL の名前の由来となりました。
APL は他と違うものだった。
アイヴェルソンは新しいアルファベット―エジプト象形文字のような――を設計し、各記号に完全な概念を持たせました。
現代 APL の字形
APL は非常に表現力豊かです。以下は Conway の Game of Life を APL で実装した完全版です。
life ← {⊃1 ⍵ ∨.∧ 3 4 = +/ +⌿ ¯1 0 1 ∘.⊖ ¬1 0 1 ⌽¨ ⊂⍵}
Lisp と同様に APL には唯一のデータ構造がありました:配列。
Lisp の場合はリストでした。
このミニマリズムは、より深い祖先関係を示唆しています。
| 特徴 | Lisp | APL |
|---|---|---|
| 発祥 | MIT | ハーバード |
| 主なデータ構造 | リスト | 配列 |
| 理論的基盤 | Church の λ計算 | Curry のコンビネーター |
| デザイン目標 | 機械のためのシンボリック推論 | 数学的アイデアを人間が伝えること |
| 優先度 | 意味的エレガンス | 合成語密度 |
両言語とも複雑なデータ構造を操作し、機能指向であるため、自然にそれらの構造を扱うよう設計されています。両者を組み合わせる提案は、1 つをもう 1 つに埋め込む形や、両方を一般化してより優れたものにする形などが議論されてきました。
1979 年、初のチューリング賞受賞者である Alan Perlis は「APL と LISP ― 組み合わせるべきか、もしそうならどうすればよいか?」というパネルを率いました。パネルは 1 つをもう 1 つに埋め込むか、両方を統合して新たな言語へと拡張するかを討議しましたが結論には至りませんでした。同年、アイヴェルソン自身もチューリング賞を受賞し、「Notation as a Tool of Thought」という講義を行いました。
おそらくあなたは無意識のうちにアイヴェルソンのアイデアを利用しているでしょう。John Baker は NumPy を「Iverson ghost」と呼び、APL の配列プログラミングが Python の構文で再誕したと述べています。ブロードキャスト、ベクトリ化、軸に沿った集約――これらは NumPy の発明ではなく、1960 年代のアイヴェルソンの考えを
np. プレフィックスで英語表記したものです。
ディープラーニングスタック全体(PyTorch, TensorFlow, JAX)は、追加の接尾辞を付けた形でアイヴェルソンの方言を話します。
np.arange(10) → !10 np.cumsum(x) → +\x x[::-1] → |x
同じ概念ですが、入力量が増えます。
Ken Iverson & Arthur Whitney at APL91
Arthur Whitney はアイヴェルソンの弟子であり、両言語を鮮明に把握していました。彼は自身のウェブサイト kparc.com で「lisp and apl」と簡潔に K の系譜を書き、アイヴェルソンのチューリング論文と Perlis の詩的プログラミングへのリンクを貼っていました。2009 年のインタビューでは次のように語っています。
「LISP で実装してコーディングすることは好きだったが、大規模データセットに取り組む際には APL がより良い語彙を持っていると感じた。」
彼は両者の補完的な強みを理解していました。「オリジナル LISP の
car, cdr, cons, cond は好きだったが、あまりに少ない。Common LISP は大きすぎる。一方で APL の 50 程度の操作でちょうど中間点を取ったような感覚でした。」
Whitney が最初に APL を知ったのは 11 歳の時、父親の友人であるアイヴェルソンが 1969 年に端末上で対話型プログラミングをデモしたときです。彼は 1980 年にトロントの I.P. Sharp でアイヴェルソンと共働し、真剣に APL を使い始めました。その後 80 年代には自作オブジェクト指向言語やさまざまな Lisp、Prolog を試み、1988 年に Morgan Stanley に入社。自身の APL 方言を用いて取引システムを構築し、それが A+ となりました。
1990 年、Whitney はアイヴェルソンと Kiln Farm を訪れました。そこで彼らは ASCII を使った新しい APL 方言に取り組んでおり、1 日の午後に Whitney は C 言語で有名なインクナブリウム――一ページだけのインタープリターを完成させました。これはアーサー流です ― C だが APL のように見える。マクロは C を高階言語へ変換し、インタープリターを書いている間に彼は「C で APL を書く」状態になっていました。最初は奇妙に映りますが、すぐに理解できます。これはコードゴルフの原型です――Perl がその用語を作る前から APL ハッカーたちの間で人気でした。
1992 年、Whitney は K を創造しました。J が APL の構文を近代化したのに対し、K は意味論を根本的に変えました。kparc.com では彼は K が両親から何を継承したかを次のように整理しています。
Lisp & APL/K の並行歴史
両者とも機能型、動的、リストと原子で構成される。REPL とレキシカルスコープを備えている。構文は異なる(s-式対 m-式)だが骨格は同じ。
K は APL 伝統から大きく離れ、LISP の影響へと進みました。APL の多次元配列モデルを捨て、入れ子リストに切り替えたのです。Lisp の機能は徐々に導入され、1970 年代には λ と条件文が登場し、1979 年には
map と reduce が加わりました。同年 Perlis が問いかけたように、ASCII は 1989 年の J で実装されました。決定的な転換点は 1992 年――K は APL の多次元配列を捨て、リスト構造へ移行したのです。
K はどんな言語か?(次節の 90 行 Python 実装を使用)
| 式 | 結果 |
|---|---|
| |
| |
| |
| (黄金比) |
| `5{ | +\x}\1,2` |
| (π ― マダヴァー級数) |
| (e) |
| (√2 ― ニュートン法) |
Python で K を構築するには?
Python のリストは Lisp のリストを表現できます(前回の投稿で示しました)。シンボルはすでに ASCII です。APL が特別なのは、すべてがベクトル化されることです。スカラー拡張と、APL の構文糖衣を Lisp の意味論上に乗せたパーサ/エバリュエータが必要です。
monad と dyad
次の 2 つの高階関数は任意の Python 関数をベクトル化します。
atom = lambda x: isinstance(x, (int, float, str)) monad = lambda f: lambda x: f(x) if atom(x) else list(map(monad(f), x)) dyad = lambda f: ( lambda x, y: f(x, y) if atom(x) and atom(y) else list(map(lambda yi: dyad(f)(x, yi), y)) if atom(x) else list(map(lambda xi: dyad(f)(xi, y), x)) if atom(y) else list(map(lambda xi, yi: dyad(f)(xi, yi), x, y)) )
monad は単項関数を、dyad は二項関数をラップし、再帰的にネストされた構造へと展開して原子である部分に適用します。これがベクトル化の核心です。
import math sqrt = monad(math.sqrt) print(sqrt(4)) # 2.0 print(sqrt([4,9,16])) # [2.0, 3.0, 4.0] print(sqrt([[4,9],[16,25]])) # [[2.0, 3.0], [4.0, 5.0]] add = dyad(lambda x,y: x+y) print(add(1,2)) # 3 print(add(10,[1,2,3])) # [11,12,13] print(add([1,2],[10,20])) # [11,22]
スカラー拡張と K の意味論を把握したうえで、100 行以内に全体を実装しようと試みました。これは前任者の伝統を称えるものです。
K 関数:Apply & Eval、パーサ、REPL
(完全な実装は GitHub の
で確認できます)k.py
- Lisp: コード=データ。意味論に重点。
- APL: 表記=思考。構文に重点。
- K: 両者を組み合わせ、より少ない手間で実現。
詳細はリポジトリを確認し、Python で K を試してみてください!