世界を動かす技術を、日本語で。

フォース: 自己生成するプログラミング言語

概要

  • 本記事は Forth言語 の発見と、その歴史的文脈についての 筆者自身の体験記
  • Charles H. Moore によるForthの「シンプルさ」への追求を中心テーマとする
  • Forthの特徴的な RPN記法スタックベース設計 について解説
  • Forthの誤解や魅力、他言語との比較を通じて プログラミング思考の変化 を語る
  • Concatenative programming など高度な概念にも触れる

Charles H. Mooreとシンプルさの追求

  • 筆者が Forth に興味を持ったきっかけは、 Usenet 時代の伝説や逸話との出会い
  • 1990年代の comp.lang. *グループでの議論や、Perlの流行の記憶
  • 本やネットの情報だけでなく、 コミュニティのフォークロア が学びの中心だった時代背景
  • Forthは「整数の値さえ自由に変えられる」という 柔軟性 を持つ言語として語られていた
  • ゲーム開発者James Hagueのブログ「programming in the twenty-first century」がForth再挑戦の後押しに

Forthの伝説とRPN記法

  • Forthの 最大の特徴 は、 後置記法(RPN: Reverse Polish Notation) の採用
  • RPNは「3 4 +」のように、 演算子を後ろに書く ことでカッコなしで計算式を記述可能
  • HP-35電卓のような RPN電卓 が一時代を築き、RPNの知名度を高めた
  • Unixの dcbc プログラムもRPNやインフィックス記法の例として紹介
  • RPNは 計算の順序や入れ子構造をシンプルに表現 できる利点を持つ

スタックベース設計

  • Forthは データスタック を中心に設計された スタックベース言語

  • 「PUSH」「POP」「SWAP」「DUP」などの スタック操作命令 が基本

  • スタックを使うことで 中間値に名前を付けずに処理を進められる

  • 例:「3 4 * 5 6 * + .」のようなコードで、 逐次的にスタックを操作し計算

  • スタック利用により 冗長な変数名や一時変数が不要 となり、コードの簡潔さを実現

    • 体言止め例:
      • スタック操作による計算過程の明示
      • 命名不要な中間値の処理
      • スタックの状態遷移

Forthのユーモアと表現力

  • Forthでは「CAKE DUP HAVE EAT」のような 英語的表現 も可能
  • 適切な単語選択 で、詩的またはユーモラスなコード表現が可能
  • スタック利用 により、 暗黙的処理 (implicit programming)が自然に実現
  • 名前付けの煩雑さからの解放と コードの簡潔化
  • 命名不要な処理の快適さと、 point-freeプログラミング との親和性

Forthの本質と誤解

  • Forthは RPN記法スタックベース だけでは語り尽くせない
  • Concatenative programming という新たな概念への到達
  • Forthの学びは「見た目」や「構文」以上に 歴史的文脈や設計思想 の理解が重要
  • シンプルさと柔軟性 の追求がForthの真髄
  • Charles H. Moore の思想に触れることで、 プログラミング観の転換 を体験

このように、ForthやCharles H. Mooreの「シンプルさ」へのこだわりは、単なる言語仕様を超えた 思想的・歴史的意義 を持つ。 RPN記法スタックベース の背後にある「なぜそうなったのか」、 Concatenative programming 的な発想が、現代のプログラミングにも新たな視点を与えている。

Hackerたちの意見

なんでこんな言語は広がらないんだろう? 忘れられた強力な言語って、これが初めてじゃないよね。他にもSmallTalkやCommon Lisp(コミュニティが小さい)なんかがある。もしかして、ある言語は「強すぎる」から? それって、私たちの業界についてどういうことを示してるんだろう? まだそんなに進化してないってこと? そう思うのは、簡単な言語(Python、Ruby、JSとか)が圧倒的に主流になってるから。

よりシンプルな説明をすると、Forthではスタックを維持しなきゃいけなくて、そのスタックの変更を短期記憶に留める必要があるんだ。大体、3つの数字だけだけどね。一方でCとかだと、ページの下を見れば変数があるから、短期記憶への負担がずっと少ない。よく書かれた高レベルのForthの単語は、その制約を超えて、Cではなかなか見られないほど読みやすいことが多い。ただ、他のプログラマーが元の問題解決者と同じように問題を見えるべきだとは期待されるべきじゃないっていう議論もあるよね。

聞いた話だと、Forthでは基本的に環境がそれぞれ違って、すごくカスタマイズされてるから、結局は各Forthプログラマーが自分のニーズに合わせた言語を作ることになるんだ。だから、こういうのはコラボレーションがちょっと難しい。僕が知ってる唯一の真剣なForthプログラマーは、森の中で一人でやってる人なんだ。美的な観点からは、この言語がすごく好きだけど、特に協力して物事を進めるのにはどうかな? でも、もしかしたら誰かがその状況を変えるためのツールを作るかもしれないね。

プログラミング言語の有用性を測るのに「力」ってあんまり役に立たないと思う。プログラムを指定する観点から考えると、プログラミング言語ができる最も役立つことの一つは、書けないプログラムを排除することなんだ。そういう意味では、制約は欠点じゃなくて、むしろ特徴なんだよね。

僕が働いてたところには、大きなForthのコードベースがあって、ミッションクリティカルなことをやってたんだ。それを理解するまでが大変だったけど、すごく面白かったし、何百人、何千人もの人が触れたり、作業したり、学んだりしてた。でも、平均的な開発者にはかなり厳しい道のりだったから、結局、同じものをクソみたいなほぼCの解釈言語で作り直すことにしたんだ。確かに、そうすることで多くの人が理解しやすくなったけど、解決策はあまりエレガントじゃなかった。

残念ながら、私たちの業界は主にレンガ職人のようなもので、低賃金で使い捨ての従業員を扱う技術に走りがちなんだ。SVスタイルの大規模な給与は、世界中どこでも見られるわけじゃない。多くの国では、GitやOfficeを使っているかどうかに関わらず、オフィスワーカーの給料は似たり寄ったりだよ。

キャリアの初期に、たくさんのPerlを使っている職場で働けたのはラッキーだったし、Damian Conwayの『Object Oriented Perl』を読めたのも良かった。あの本は本当に素晴らしくて、私の考えを広げてくれた。オブジェクト指向プログラミングのさまざまなアプローチの例がたくさん載っていて、私が夢にも思わなかったほどの内容だった。そして、それらをすべてPerlで実装する方法も示してくれた。すごい力だよ! Perlのモットー「やり方はいくつもある」にぴったり合ってた。でも、私たちのコードベースにはやり方がいくつもあって、異なる部分が互換性のないオブジェクトシステムを使ってたから、全部を学んで互いに動かすのは大変だった。後に、オブジェクト指向プログラミングの一つのスタイルだけをサポートする言語に移れたのはホッとしたよ。

強力な言語は人々に不必要に複雑なことをさせるんだ。不必要に複雑なことは理解しにくい。理解しにくいのは良くない。重要なコードは、書かれるよりもずっと多くの回数読まれたり拡張されたりするから、シンプルさが実際には他の多くのことよりも優れているよ。

それは別の時代のための別の解決策だね。Forthは、最小限のアセンブリ言語で自己ホストできる強力で表現力豊かなプログラミング言語を書くための素晴らしい方法だった。Forthが最初に開発された冷蔵庫サイズのコンピュータは、メモリが二桁キロバイト(たぶん8192kワード、16ビットワード)で、指示を300kHzくらいで処理してた。今のキーボードのCaps Lock LEDを動かすマイクロコントローラーは、100倍速くて100倍のメモリを持ってる。今は、エディタ、コンパイラ、ターゲットバイナリをそんな小さなマシンに詰め込む必要はないんだ。マイクロコントローラー用に開発するなら、単に「大きな」コンピュータでCを使えばいいし、想像を超えるほど強力だよ。1990年代の昔、私はZ80でForthをターゲットにした組み込みシステムの開発環境を使ってたけど、それは少なくとも10年前のもので、当時は5年も古かった。今、あなたが私の言葉を半分のサンドイッチのサイズのガラスのスライスで読んでいるなら、それはForthが最初に書かれた時の世界中のコンピューティングパワーよりも遥かに多いんだ。Forthのようなものをゼロから書くのは素晴らしい経験で、(レジスタをロードしてACIAを始動させて端末にテキストを送信するためのアセンブリコードのことね)エミュレートされた80年代初期のホームコンピュータでやるのは、背後にあるチップが何をしているのかを理解するのに良い方法だと思うし、それが「本物」の言語、例えばGoやPythonやCのプログラマーとしてのスキルを向上させると思う。

どうしてこういう言語はスケールしないんだろう?スタニスラフ・ダツコフスキーがうまく説明してるよね。

これはシンプルな抽象化の状況で、すべてを含むプログラミング環境への移行だと思う。ジョーディ・ラフォージは、エンタープライズであまりコードを書かない。彼は単にコンピュータに異常のモデルを作ってもらって、アイデアをテストするんだ。ある意味、Pythonのような現代の言語は(LLMが出る前から)その現実にかなり近づける。もちろん、言語の基本を知っておく必要はあったけど、それはかなり最小限で、基本的なビルディングブロックを使ってライブラリを組み合わせてアプリケーションを作ることができた。Pythonには、ほとんど何でもできる良いライブラリがあって、これが標準だから、タスクにあまり時間がかからないのが期待される。自分のnumpyやscipyのライブラリを使った解決策を作るのに3年かかるなんて、上司には言えないよ。ライブラリを組み合わせるのが求められてるんだ。だからMITはSICPをSchemeからPythonに移したんだよ。全然違う世界だよ。Forthでは、すべてのプログラムが問題の完全な解決策をゼロからまとめた芸術作品なんだ。その創造者であるチャック・ムーアは、自分のForthソフトウェアと最適に動作するチップを自分で製造するほどのレベルに達してる。この言語たちはライブラリを持っていたけど、簡単に共有できなかったし、PerlのCPANができる前はリポジトリもなかった。Perlはしばらくの間人気があったけど、Pythonは組み込みのオブジェクト指向を持つシンプルな言語で勝った(Perlのアプローチは本当にハッキーな組み込みオブジェクト指向か、ライブラリをダウンロードする必要があったから)。正直なところ、私は10年間いろんな言語(Common Lisp、Prolog、APL、C、Ada、Smalltalk、Perl、C#、C++、Tcl、Lua、Rustなど)を試して、最適なものを探してたけど、専門家にはなれなかった。でも、自分のニーズに合ったものとして、Pythonが一番だと結論づけた。Common Lispの本を読むのに多くの時間を無駄にしたけど、Pythonで同じことをする方がずっと簡単だった。ゲームエンジンを作るようなことをしているなら、あなたの経験は変わるだろうけど、多くの人はプロセスの自動化やそんな感じのことをやっていて、Pythonの方がCommon Lispよりも環境やツールの利点から優れている。あと、PythonはLispほど概念的に美しくはないけど、学ぶのはずっと簡単だと思った。構文が自分に合ってて、好きな人もいるよね。

多くの人がLispのシンプルさを持ち上げるけど、Forthも似たようなもので、あまり評価されてないよね。悲しいことに、僕がForthで書いたコードは... PostScriptだけなんだ。そう、PostScriptはForthの方言なんだよ。子供の頃、Apple ][でのGraFORTHのデモにすごく感動したんだ。3Dワイヤーフレームアニメーションがあって、当時は魔法みたいだった。

子供の頃、Apple ][でのGraFORTHのデモにすごくワクワクしたんだ。3Dワイヤーフレームアニメーションがあって、当時は魔法みたいだった。最初のコンピュータ(Apple II)で遅い整数BASICから逃げたくてGraFORTHを作ったんだ。きれいなグラフィックスを出すために大きなアセンブリコードのブロックを使ったから、Forthが単独で何ができるかについて誤解を招いたかもしれない。その後、浮動小数点をサポートするTransFORTHというバリエーションも書いた。GraFORTHとTransFORTHを組み合わせたかったけど、コンピュータのRAMが足りなかった。無邪気な時代で、パーソナルコンピューティングの尻尾が犬を振り回す前の世界だったね。

ForthとLispの違いは本当に明確だよ。Forthのソースコードは完全に暗黙的な構造で、どの関数がどの引数で呼ばれているのかも分からない。Lispは完全に明示的な構造だから、読むのも編集するのもずっと楽なんだ。Lispは全体のプログラミング言語を作るのに、たった一つの原始(ラムダ)だけで済むけど、Forthは使えるようにするために多くの原始が必要で、言語の核心的なアイデアを壊しちゃうんだよね。Lispのエレガンスは、結局Forthには欠けてる。

Forthが好きだけど、実際のものを作るのが難しいなら、Factor(https://factorcode.org/)がForthの良いところをほぼ全部取り入れて、もっと扱いやすくデザインされてるよ。Slava Pestovが設計したんだけど(彼はSwiftにも関わってたと思う)、正直言って、ウェブアプリや他のプログラムを作るのがすごく楽しいし、Forthよりずっと読みやすいよ。

NeWS/HyperNeWSでPostScriptを使ってプログラミングしていた頃の思い出はとても良い。あの環境でしか見たことがないことがたくさんあったから。編集:公平に言うと、PostScriptに依存していたのは魅力を制限していたかもしれないけど、実際には本当に好きだったんだ。

興味のある方へ:Appleシリコンのサポートはありません。

Forthには特別な思い入れがあって、ウェブプログラミング用のちょっとしたForth風のインタープリターをいじってるんだ。実用的なものじゃなくても、楽しむためにね。一つのコンセプトとして「現在の選択」という考えを加えて、使える語彙を定義したり、DOM要素を選んで操作したりするんだ。今は実験中。 https://github.com/srikumarks/pjs 編集: 子供の頃、BASICは好きじゃなかったけど、楽しいことができたから、好きな言語のためにBASICでインタープリターを作ったら、Forthみたいになったんだ(その時はForthのこと知らなかった)。35年経った今でも、まだあの子供のままなんだな。

以前はLispやForth、Joy(それにFactorやHaskell)みたいな言語のファンだったけど、実際に私が本当に求めていたのは(型なしの)ラムダ計算だったんだ(普遍的な言語として)。(コンビネータ論理はラムダ計算の似たような表現だけど、抽象化を始めると違いはすぐに消える。)全ての(一般的な)プログラミング言語の意味論をラムダ計算で表現できれば、自動プログラム翻訳のためのしっかりした基盤ができると思う。それを目指すべきだよ。言語のバベルの塔は誰にも役立たない。今の私の課題は型理論なんだ。だから、型の概念をラムダ項に直接埋め込もうとしてる。そうすれば、組み合わせたときに「自動的に型チェック」される感じになる。これにおいて重要なのは、ラムダ抽象を使わないラムダ項だと思う。これらの項はまだ解釈されていないミニDSLのように考えられるからね。とにかく、構成の計算(や他の一般的な形式論理)を型なしラムダ計算に翻訳できれば、自動定理証明にも役立つだろう。理論的には可能なはずだけど、私の知識では、こういうハードコアな形式化を実際にやった人はいないみたい。

なんで特に型なしなの?

Loaderの数を計算する643バイトのCプログラムを1850ビット(232バイト未満)に短縮するために、型なしラムダ計算で構成の計算を実装したんだ。これは、私の関数型ビジービーバー関数が達成したマイルストーンの一つだよ。

そして、私たちはそれを目指すべきだ。言語のバベルの塔は誰にも役立たない。具体的にどういう意味なの?プログラミング言語の数が実際には役に立たない、むしろ有害だってこと?

たくさんの言語(Forthを含む)はLCに対して本当にマッピングが悪い。ポータビリティを重視したForthの文書を読んでみて。

FORTHはエレガントで、シンプルすぎて実装したくなるけど、どんな言語でも4を12で定義するのは許されるべきじゃないよ。長期的に見て、これが良い結果をもたらす状況なんてないからね。FORTHだけじゃなくて、Perlや他の言語にも影響する問題があって、たくさんのことを暗黙的に扱うんだよね(例えば、スタックや関数への引数とか)。ほとんどの人が、明示的な方が暗黙的より読みやすいって同意してると思う。

どんな言語でも4を12で定義するのは許されるべきじゃないよ。長期的に見て、これが良い結果をもたらす状況なんてないからね。スキルソーは回転する刃に指を突っ込むことを許すべきじゃないけど、ほとんどの人はそれが愚かで危険なことだって知ってるよね。

RPNインタープリターは、非常に少ないコアメモリで動くんだ。だから、コアメモリが10キロバイト未満のコンピュータでは人気だった。でも、複数のプログラマーや大規模なコードベースでのソフトウェアエンジニアリングには最悪だよ。構造やインターフェース、モジュール、データ抽象化が欠けてて、現代の言語に期待するようなものがない。私たちはこれを「中華料理のコーディング」って呼んでたんだ。10分後には、自分が何をコーディングしたのか全く分からなくなってる。

「名前なしで作業する(暗黙的またはタシットまたはポイントフリーのプログラミングとも呼ばれる)は、時にはより自然でイライラしない計算方法だ。名前を取り除くことで、より簡潔なコードが得られることもある。そして、少ないコードは良いコードだ。」Forthは本当に物事の名前を付ける負担を減らしてくれるの?結果に名前を付けないけど、言葉に名前を付ける負担はどうなるの?(私の印象では、Forthのプログラムには、名前付き変数がある言語の同等のプログラムよりも多くの言葉があるように感じる。)

この引用は、Jのような暗黙的スタイルをサポートする配列言語にとっては、もっと意味があると思う。Jの「トレイン」は、たくさんの変数を使わずに物事をスムーズに進めてくれる。Aaron HsuのCo Dfnsコンパイラ(ここやYouTubeで話題になってるやつ)も、Dyalog APLでこのスタイルを使ってるよ。Forthは連結的だから、たくさんの変数を気にせずに単語を重ねていける。だから、Forthに関しては部分的に正しいと思う。

うん、記事のように言うつもりはなかったな。Forthは変数よりもプロセスの名前を付けることに重点があると思う。

私の最初の本格的なソフトウェアエンジニアの仕事では、「フルーツマシン」のためにたくさんのForthを書いたんだ。アメリカの同等のものは分からないけど、これはイギリスのパブにかなり一般的な低額賭博機だよ。コアプロセッサは6809で、インタープリターが超小型で実装が簡単だったからForthが選ばれたんだ。テストしながらコードをすぐに更新したり調整したりできるインタラクティブな方法が本当にありがたかった。DUPやSWAPでスタックの状態を頭に入れておくのが少し疲れたけど、それはたぶん私の未熟さと、物事を十分に分解していなかったからだと思う。彼らは68000ベースのビデオゲーム機の基盤としてForthを使い続けたけど、ビデオポーカーのハンドクラシファイアではCを使うことになった。主に、目標の返済率約98%を達成するために、これらの新しい「ペンティウム」プロセッサの一つで多くのシミュレーションを実行したかったからだ。

アメリカでは、これらのことを「スロットマシン」って呼んでるよ。

1980年8月のByteマガジンに魅了されたよ。その号はForthに特化した表紙だった。実装が簡単だと言われていて、新しいKIM-1 6502ボードでそれをやってみようと思ったんだ。でも、大学に行くときにKIM-1を失ってしまって、人生は次の45年間、別の道に進むことを強いられた。約1年前、ようやくForthの実装に取り組む夢を実現しようとして、宇宙飛行シミュレーションゲームにForthベースのフライトマネジメントコンピュータを組み込んでいるところだ。今は、Godotで主にC#やGDscriptのコードを書く代わりに、このちょっと変わったエレガントな言語を使って役立つデバイスを作る方法を考えている。楽しいよ。面白いのは、ForthのコードをGitHubで完全に別のプロジェクトとして作成できたこと(https://github.com/Eccentric-Anomalies/Sky-Dart-FMS)で、許可のあるオープンソースライセンスを付けている。もし誰かが私のゲームに出てくるような本物の宇宙船を作ったら、FMSのコードを実際のコンピュータで使って動かせるかもしれない。リンクされた記事の中で特に心に響いた部分がある。「Forthを実装して、その仕組みを理解する」そして「でも、これが教えてくれないことに気をつけて」。本を読むだけで実装を理解するのは、魅力的なパズルだった。動かすことができたとき、実際にForthコードを書く経験がゼロだと気づいた。楽しんでいるけど、ちょっと変わった抽象的なアセンブリ言語で書いているような感じだ。