Skip to content

Instantly share code, notes, and snippets.

@nfunato
Last active August 17, 2022 15:28
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nfunato/a7f5320f72f1ea644064aeff60fbd171 to your computer and use it in GitHub Desktop.
Save nfunato/a7f5320f72f1ea644064aeff60fbd171 to your computer and use it in GitHub Desktop.
------------------------------------------------------------------
以下の翻訳文は、Felix Winkelmann の Thoughts on Forth Programming
(http://call-with-current-continuation.org/articles/forth.txt) の
翻訳であり、原著者の許可を得て公開するものです。
2021-09-01 Nobuhiko FUNATO (nfunato @ acm . org)
更新履歴:
2021-09-02(rev10): Shiro Kawaiさんにご指摘いただいた誤訳訂正/改善を反映
2021-09-02(rev09): 公開初版
------------------------------------------------------------------
この文書は、私のForthの哲学に関する理解と、それを特に興味深いものにしている
いくつかの属性を、Forthとその使い方について私が重要と思うことと一緒に記述す
る試みです。これらはすべて私の個人的意見であり、ドグマと見なすべきではありま
せん。私はこれまで様々なプログラミング言語を使ってきましたが、そのほとんどが
好きではありませんでした。SchemeやPrologのように非常にエレガントで強力な言語
もあると思いますが、Forthのようにプログラミングの再考を求める言語はありません。
Forthは、一人の人間や少人数のプログラマのグループに合わせて作られた、非常に
「個人主義的」なものです。その理由のほとんどは、Forthシステムを自分で実装す
ることが自然で比較的簡単であること(そしてそうすべきであること)と、言語に本質
的に可鍛性があり、個人のニーズに適応することによります。したがって、私が書いて
いることは、プログラミング言語であると同時にエンジニアリング哲学でもある
Forthの一つの見方に過ぎません。
私の認識では、Forthプログラマには2つの考え方の流派が存在します。一方は、極端
なシンプルさ、ミニマリズム、短い定義、そして可能な限りハードウェアに近いところ
まで降りていくことを好む「古典派」です。
もう一方は、他の言語に見られる機能で古典的なForthモデルを拡張し、一般的に
機能やツールを追加することで、よりコンピューティングの主流にアクセスしやすい言語
にしようと努力する「現代派」です。後者は、概してスタック、逆ポーランド記法、重い
リファクタリングといったアイデアを、一般的に現代のプログラミング言語に不可欠で
望ましいと考えられているものと混ぜ合わせようとしていますが、結果として変な記法を
備えたLispのようなものになっています。私は個人的には前者の陣営に属していますが、
それは後に続く文章でより明らかになるでしょう。
まず第一に、Forthはかなり風変わりでとっぴに見えるいくつかの基本的な特性を土台と
しています。それはForthがマイクロコンピュータ時代に(今日の基準では)非常に限られた
容量を提供するマシン上で誕生したことから、シンプルさとコンパクトさに根ざしている
ことによります。しかし、これらの属性は、ある種の独特の利点をもたらします。
そのような特性の1つは、逆ポーランド記法の使用とローカル変数の欠如あるいは省略です。
サブルーチンやプリミティブへの引数渡しはスタック上で行われるため、コードのファクタ
リング(分解)はとるに足らないものになります。式は、関数型プログラミングの「ポイント
フリー」スタイルのように、文脈から取り出して新しい定義に移動することができます。
短い定義と(通常は)低いサブルーチン呼び出しオーバーヘッドを強調することは、共通の
コードシーケンスを分離することをさらに示唆しています。ローカル変数の使用はこれを
難しくすることが、ローカル変数の機能を避けるべき理由です。
もう一つの便利な機能は、後から(ワードの)値を再定義しても以前の使用箇所の意味に
影響を与えない超静的な環境です。これにより、既にコンパイルされたコードの安定性が
大幅に向上し、既存のワードをシャドウイングすることが後からコードを定義するうえで
問題とならない限り、既存の定義に対する代替の名前を見つけるプレッシャーが軽減されます。
Forthはボキャブラリーを使った非常に強力な名前空間システムを提供していますが、
シャドウイングが問題にならない限り、環境を汚染しないように名前空間を分離することは
厳密には必要ではありません。
Forthは通常、対話的に動作します。基本的な read-eval-print-loop は非常にシンプル
なので、すべての機能を対話的な方法でテストできます。Forthを実装する際に最初に行う
ことの一つは、トップレベルインタプリタを動くようにすることです。デバイスドライバを対話的に
デバッグできることを想像してみてください(それも、高レベル言語でデバッグできるように
なる前に膨大な量のコードがすでに存在して動作しなければならないLispマシンの前に
座らずに)。組込みシステムのプログラミング、テスト、調査がどれだけ簡単にできるかを
垣間見ることができます。
非常に初期の段階での対話的なデバッグは、ボトムアップがForthでの設計や実装のいつもの
やり方であることをほのめかしています。これは、即興やハッキングの匂いがしますが、
私たちの心は、トップダウンの方法論、事前の設計、レイヤ化されたアーキテクチャ、
最初に計画を立ててから構築を行うという理想に縛られていて、解決しようとしている
問題を完全に把握していることはめったになく、要件、期待、基礎となるシステムの知識が
事前に完全にわかっていることは単に真実では無い、という事実を無視しているだけなのです。
Forthにはメモリしかありません。メモリ内のストレージのワードサイズとバイトサイズの
セル、そしてスタックです。アセンブリ言語のレベルにステップダウンするのは面倒に
聞こえるかもしれませんが、メモリレイアウトのあらゆる側面を完全に制御することが
できます。あなたとマシンのアーキテクチャの間には人工的な障壁はありませんし、
フォン・ノイマン・マシンに乗っていないと思わせようとする抽象化もありません。
実際、フォン・ノイマン・マシンの上に乗っているのですから。
そして、そう認めることで、最終的に真の公開されたマシンリソースへのアクセスが
手に入るのです。これは良いことで、すべてのC言語プログラマは
このレベルのアクセスが可能(そしてそれを必要としている)ですが、Forthプログラマは、
コンパイラの透過性の無い操作や、不明確な構造レイアウトや定義されていない動作の
ような、邪魔になる脆い抽象化には驚かされないでしょう。言語標準に反してプログラム
する場合、常にそれを解釈する人たちに翻弄されることになりますが、実装に反して
プログラムする場合は、特に自分で実装を作った場合は、不明瞭な点は何もありません。
Forthには「yak-shaving」はありません: 自分とゴールとの間にあるものはすべて
そこに自分で置かれてきたものです。これは、プログラミングの仕事の多くは他人の仕事が
何に使われるかを予想して彼らの失敗を回避すること(それは実際は不可能ですが)であると
教えてくれる興味深い経験です。
それは、マシンに直接アクセスできるようにしようとしているにもかかわらず誤った安全性を
感じさせ、邪魔になったときに回避策を必要とするあらゆる種類の制限を提供したり、
習得に一生かかるようなかなり難しい安全性のモデルを課している言語ではさらに悪化します。
マシンへの低レベルの直接アクセスを提供し、同時に自動メモリ管理のような高レベル環境の
すべての利点を提供する一つの言語を手にすることはできません。どこかに、より多くのコード、
より多くの定型文、より脆弱で人工的な抽象化を必要とするだけの目立ったギャップがあること
でしょう。私たちは両方の方法を持ちたいと思っていますし、その二分法を苦痛でなくすることを
約束する人は誰でも信じますが、それはすべて失敗しています。マシンから離れすぎて、
言語、コンパイラ、または「パラダイム」を喜ばせるためだけに何かをしてしまうからです。
ここで性能の話を持ち出す人がいることでしょう。モダンで複雑な言語は単純なインタプリタ型
言語にはできないヘビーな最適化を提供しているのだと(とはいえ、Forthインタプリタは非常に
低レベルで、コンパイルされたコードと解釈されるコードの境界は非常に薄く、多くのCPUで
インタプリタは2つか3つのマシン命令で構成されていますが)。これは技術的には正しいのですが、
このような重い最適化作業が必要かどうかは議論の余地があります。あなたのコードの
ほとんどは、最近作り出されているブロートウェア(bloatware)の中で実行されることは
めったに(あるいは決して)ないでしょうが、実行時パフォーマンスの調査は、やや宗教的な
意味合いを持っています。私たちは、あらゆるサイクルの速度を維持しつつ、メモリ
トラフィックやキャッシュミスを増加させる膨大な量のコードを気にすることはありません。
ネイティブコードコンパイラを提供する多くのForthシステムがありますが(中には非常に
洗練されたものもあります)、多くの場合これは必要なく、メモリと複雑さの点でコストが
かかるだけです。高度に最適化されたコンパイラが暗示するセキュリティへの影響を無視
するとしても、ソースから生成されたコードを完全に理解できることは、満足感があり、
心強いものです。
これは、構文レベルだけでなく、抽象化レベルでのコンパクトさにつながります。ソフト
ウェアを理解できないことが、プログラマが知るべきではない詳細からプログラマを守ろう
とするレイヤーの増殖につながっています。オペレーティングシステム(それ自身の抽象化を
凝集したもの)はランタイムライブラリの下にあり、ランタイムライブラリはアプリケーション
レベルのライブラリのベースとなり、言語レベルの抽象化の基盤となっています。
抽象化のため、あるいはそれ以上の抽象化のために、増え続ける抽象化の塔は、実際に
実行していることについての知識の不足を認めることです。これは今日では良いことだと
考えられていますが(「無知は力なり」)、実際にはデメリット以外の何物でもありません。
そもそも、オペレーティングシステムの機能やバイナリファイルフォーマット、ハード
ウェアへの直接アクセスなどの低レベルのインタフェースは、一般的に見られるような
難解で禁じられたものではありません。それらのインタフェースは、(たとえあるとしても)
ひどく文書化されているか、特定のシステムやアプリケーションに特有の文書化されていない
拡張機能が含まれているだけです。あるいは、インタフェースの「良い」部分はソフトウェア
担当者に任せると決めたハードウェアエンジニアが粗雑に設計しただけかもしれません。
Forthでは、理想的には2つの層を持つことになります: 手元の問題に対するプログラミング
インタフェースを提供するアプリケーション層と、外部デバイスにアクセスするための
プリミティブを提供するハードウェア層です。本当の芸術は、この2つの層を統合することです。
しかし、芸術とは学ぶものではなく、他の方法 - 純粋な経験や内省 - によって身につける
ものです。
チャック・ムーアのようなForthプログラミングの上層部にいる人たちは、自分たちでハード
ウェアを設計してForthから使いやすいインタフェースを作るようにしていますが、ツール、
言語、標準、パラダイムといった面でそれ自体の負荷が生じますから、すべての人のための
ものではありません。
ムーア氏といえば、彼はForthプログラミングのために、一見自明のことのように見えても、
それを実行するために積極的な努力をしないと空虚な言葉になってしまう賢明なルールを
いくつか示してくれました。
大原則は「シンプルに」です。確かに、私たちは皆それを望んでいます。しかし、なぜ
これほど多くのひどく複雑なプロトコルやアーキテクチャが存在するのでしょうか?
それは、誰もこのアドバイスを真剣に受け止めていないからです。結局のところ、複雑さ
とはプログラマーの醍醐味、あるいは、それを極めたという感触なのです。しかし、実際に
複雑さを追求するために必要な謙虚さは、私たちの職業の中では滅多に見られないものです。
シンプルさとは、シンプルなコードを意味するだけでなく、要件、特徴、全体の機能を
シンプルにすることを意味します。ベルやホイッスル、素敵なユーザーインタフェース、
目の保養、無駄なインタフェースやプロトコル、レガシーサポート、その他、必要不可欠と
されているすべてのもの(実際には本当の品質の埋め合わせに過ぎないのですが)を落とす
ことを意味するのです。
物事をシンプルに保つための原則には、2つの重要なコロラリーがあります。第一に、
「憶測をしない」ということ、つまり、将来の使用を想定したコードを書いたり、抽象化
したりしないことです。確信が持てないことを計画するのではなく、今持っている要件を
満たしてください。
2つ目のコロラリーは「自分でやれ」です。このアドバイスを真面目に受け止めた場合、
これは深刻な影響を及ぼします。これはまた、ソフトウェア開発者が決して恐れるべき
ではなく、実際に楽しむべきものである、学ぶことの必要性を強調しています。すべてを
自分で行うことで、平凡な抽象化や、役に立たないものでいっぱいの肥大化したライブラリや、
そのコードを使っているかもしれないアプリケーションの普遍性を説明できない人による
普遍的な使用を目的として書かれたコードにはびこるバグなどを理解する必要から解放されます。
再利用は、それが慎重に疑われているという最初の兆候があるにもかかわらず、ドグマに
なっています。再利用を強調するということは、資産を生産し、永続的な価値(コードベース
や知的財産と呼んでいます)を創造しようとする産業界の動きを示しているにすぎません。
それは、ソフトウェアが腐っているという事実を否定する幻想です。あなたがライブラリを
再利用しているのは、通常はほんの一部に過ぎませんが、あなたは使われていない機能や
無意味な機能、特にあなたのものではないバグのためにお金を払っているのです。
そして、これは重要なポイントです: すべてを自分で行うことで、自分が制作したソフト
ウェアをよりよく理解することができます。自分のニーズに合わせて、あらゆるレベルで
修正することができます。バイナリのすべてのバイトを(正しく行えば)計算できるように
なります。最後にそんなことができたのはいつですか? つまり、Forthでプログラミング
するということは、常に自分で実装し、「標準」を気にしないということです。昔から
言われているように "If you have seen one Forth - then you have seen one
Forth. "という古いことわざがあります。そして、それは全く問題ありません。
一人のプログラマがアプリケーション全体の責任を負う時代は終わったと言われています。
私たちはチームで考え、後から来た人たちが責任を引き継ぐことを考えるべきだと言われて
います。マルチメガバイトのアプリケーションや、ウェブスケールの誇大妄想の観点から
考えるなら、この考え方は適切かもしれませんが、ソフトウェアは儚く、陳腐化し、腐敗し、
最終的には腐ってしまうということを再び否定しています。この考え方は、ソフトウェア
開発に調整された理想主義的モデルから生まれたもので、開発者はレゴのピースをつなぎ
合わせる大きな機械の中の小さな歯車です。この考え方は、基本的な前提条件が変わること、
要件が変わること、そして、大量の機能を大量のコードで変更しなければならないときに、
どのプログラミング言語も現実の問題に適切に対処できないことを否定する考え方です。
私たちは、少しの再設計、1つか2つの新しいレイヤー、たくさんのユニットテストで十分で
あり、いつか私たちはこのすべてをきれいにするだろうと、それはさほど悪くないふりを
しています。大きな「書き換え」は、なにか考えられない、言葉にできない、弱さや失敗を
認めることです。これはまったくナンセンス、あるいはプロパガンダです。「ベスト
プラクティス」に従うことは、直感を無視し、新しいアプローチでの実験を避けて、
他のみんなと同じ間違いを繰り返すことを意味します。
ここで関係してくるのは標準の問題です。Forthの標準がありますが、それをあまり深刻に
受け止めるべきではありません。標準は、あなたが作業するプラットフォーム上では最適では
ないかもしれないインタフェースデザインを課しています。それは不可能なことをしよう
とする試みです。つまり、ある言語の使用に関する曖昧さを、すべての可能な状況で、
すべての可能なプラットフォームで、すべての可能なアプリケーションで解決しようと
いうことです。その意図はもちろん、再利用を簡単にし、移植を容易にすることです。
しかし、これについてはすでに話しました。標準は役に立つことがありますが、準拠する
こと自体が目的ではありません。さらに、普遍的な標準は定義上、非常に曖昧でなければ
なりません。対象となるプラットフォームが増えれば増えるほど、すべての可能性のある
実装をカバーするために、より曖昧にならざるを得ません。そうなると、C(またはC++)言語の
標準で見られる、弁護士やそのように考える人にしか理解できない信じられないほど複雑な
動作記述に終わることになります。
誰もコードを共有することができないとは言っていませんし、他人のコードを理解することを
学ぶべきではないとも言っていませんし、デザインは一匹狼にため込まれるべきだとも
言っていません。しかし、多くの場合、特定のアプリケーションやコンポーネントの主要な
設計と実装の作業を行うのは、一人のプログラマーや非常に小さなチームであることを
理解すべきです。なぜなら、プログラムには(単純なものであっても)、主題、形式的または
非公式な要件、異なる設計決定の結果の可能性などの両方に知的に深く関与すること(中断
しないようにお願いします!)が要求されるからです。大規模な設計会議のように、誰もが
いつでも何をしているのかを正確に把握しているような大規模なチームで行われるのは神話です。
バグの修正やメンテナンスのために、より大きなチームに仕事を分散させることは可能かも
しれませんが、その段階では、ソフトウェアはすでに、多かれ少なかれ死にかけています。
何十年もかかるかもしれませんが、一人の人間がゼロからコア機能を書き換えることが
不可能になったら、ソフトウェアは死んでいます。いいえ、理想的なのは「あ な た」が
それを書いて、それを理解し、それを維持し、変更し、必要に応じて何度でも書き直し
(コンパクトさを覚えていますか?)、それを棄てて別のことをするということです。
Forthは実用的な問題を解決するための言語です。LEDをON/OFFするための言語であり、
モーターを動かすための言語であり、ピクセルをフレームバッファに書き込むための言語であり、
デバイスドライバを書くための言語であり、シングルボードコンピュータ上で実行可能なものを
立ち上げるための言語です。また、データを検索したり、ソートしたり、操作したりするための
言語でもあり、必ずどうにかしてそのような仕事になってしまう単調でつらい仕事を実装する
ための言語でもあります。XMLやJSONをパースしたいのであれば、確かに可能ですが、それだけ
では幸せにはなれません。これは、他の無意味な抽象化の上に無意味な抽象化を書くための
言語ではありませんし、特定の問題を今日の流行りのアルゴリズムやデータフォーマットを
使って可能な限り一般的な方法で解決するライブラリを書くための言語でもありません。
仮想マシンやアセンブラ、カスタムデータフォーマットを書くためには優れたツールです。
問題をForthで実装するのが当たり前になるほど単純化し、同時に意図した目標を達成する
ことができれば、あなたは正しい道を歩んでいることになります。既成概念にとらわれない
思考と多くの思索を必要としますが、その代わりに、動くのがやっとで、すぐに腐ってしまう
コードや、今まで書いてきたことを後悔し、書き換えや置き換えが難しくなるほど成長した
負債となるコードの山とならないであろう何かを得ることができます。
「良い」Forthのコードを書くのは非常に難しいことです。あるいは、少なくとも私が考える
良い Forth のコードは、他の人が考える良いコードとは異なるかもしれません。Forthは
「書くだけの言語」と呼ばれてきましたが、それは、すべてが明らかになるところまでコードを
単純化するための追加の努力が必要だからに他なりません。これは芸術であり、超越の瞬間であり、
私が到達したことがあるとは言いませんが、時々、その瞬間を垣間見ることがあり、もし私が
これに一生懸命取り組めば、それはとてもシンプルになり、十分に分解され、明白で明確な
名前を使って、すべてのものがうまく収まるという事実の暗示を感じます。プログラマーが
たまに経験するこの瞬間です。短くてシンプルなコードが、余計な荷物を持たずに、簡単に
理解できるように、やるべきことをやってくれるのです。Forthでそれを実現するのはずっと
難しく、より多くの時間と多くの書き換えが必要になるかもしれませんが、その結果は、より
小さく、はるかにシンプルで、完全に自己完結していて、信頼できないコードによる負担が
ないので、さらに満足感が得られます。あなたが、子供たちを人身御供にするMoloch神に
なっている「生産性」に対する衝動を忘れたとき、品質、優雅さ、芸術と呼ばれる特別の
ものを達成することができるかもしれません。それは一生かかるかもしれないし、そこまで
到達することはないかもしれないが、それでもあなたはそれのために努力すべきです。
さもなければ、あなたは機械の歯車のままで、信じられないほど複雑な「ソフトウェアスタック」
で開発し、不十分で脆い言語を使い、かろうじて一致するインタフェースをあまりにも肥大化した
ライブラリのごく一部に接続し、理解できないほどの複雑さの洒落にならないツールを使って、
なぜすべてがクソなのか、なぜ実際にプログラミングを楽しんで、自分が達成したことを心から
誇りに思うことができた最後の時間は、あなたが子供の頃だったのか、と自分自身に問いかけて
いることでしょう...
------------------------------------------------------------------------------
以下の翻訳文は、Felix Winkelmann の Thoughts on Forth Programming
(http://call-with-current-continuation.org/articles/forth.txt) の
翻訳であり、原著者の許可を得て公開するものです。
2021-09-01 Nobuhiko FUNATO (nfunato @ acm . org)
note: push RAW button of gist to fill japanese paragraphs correctly
更新履歴:
2021-09-02(rev10): Shiro Kawaiさんにご指摘いただいた誤訳訂正/改善を反映
2021-09-02(rev09): 公開初版
------------------------------------------------------------------------------
This is an attempt to describe my understanding of Forth philosophy and some of its attributes that make it in my opinion particularly interesting, together with things I find important about the language and its use. All of this is my personal opinion, and should not be seen as dogma. I have used various programming languages and didn't like most of them. I think there are some very elegant and powerful languages, like Scheme or Prolog, but none of them require such a rethinking of programming, as Forth does.
この文書は、私のForthの哲学に関する理解と、それを特に興味深いものにしているいくつかの属性を、Forthとその使い方について私が重要と思うことと一緒に記述する試みです。これらはすべて私の個人的意見であり、ドグマと見なすべきではありません。私はこれまで様々なプログラミング言語を使ってきましたが、そのほとんどが好きではありませんでした。SchemeやPrologのように非常にエレガントで強力な言語もあると思いますが、Forthのようにプログラミングの再考を求める言語はありません。
Forth is quite "invidualistic", tailored to single persons or small groups of programmers, mostly because it is natural and relatively straightforward to implement a Forth system yourself (and you should) and because the language is inherently malleable and adapts to your needs. Therefore what I write is just one way of seeing Forth, which is both a programming language and a engineering philosophy.
Forthは、一人の人間や少人数のプログラマのグループに合わせて作られた、非常に「個人主義的」なものです。その理由のほとんどは、Forthシステムを自分で実装することが自然で比較的簡単であること(そしてそうすべきであること)と、言語に本質的に可鍛性があり、個人のニーズに適応することによります。したがって、私が書いていることは、プログラミング言語であると同時にエンジニアリング哲学でもあるForthの一つの見方に過ぎません。
As I perceive it, there exist two schools of thought among Forth programmers: the "classical" school that prefers extreme simplicity, minimalism, short definitions and being down to the metal as much as possible, and on the other hand the "modern" school that extends the classic Forth model with features found in other languages and which generally strives for making the language more accessible to the computing mainstream by adding features, tools and generally attempts to mix the ideas of stacks, reverse polish notation and heavy refactoring with that what is commonly thought as both essential and desirable for contemporary programming languages, but what just ends up being some sort of Lisp with a funny notation. I personally belong to the former camp which will become more obvious in the passages that follow.
私の認識では、Forthプログラマには2つの考え方の流派が存在します。一方は、極端なシンプルさ、ミニマリズム、短い定義、そして可能な限りハードウェアに近いところまで降りていくことを好む「古典派」です。もう一方は、他の言語に見られる機能で古典的なForthモデルを拡張し、一般的に機能やツールを追加することで、よりコンピューティングの主流にアクセスしやすい言語にしようと努力する「現代派」です。後者は、概してスタック、逆ポーランド記法、重いリファクタリングといったアイデアを、一般的に現代のプログラミング言語に不可欠で望ましいと考えられているものと混ぜ合わせようとしていますが、結果として変な記法を備えたLispのようなものになっています。私は個人的には前者の陣営に属していますが、それは後に続く文章でより明らかになるでしょう。
First, Forth builds on some fundamental properties that make it quite idiosyncratic and may appear quirky, due to its roots in simplicity and compactness, considering that it emerged in the microcomputer era, on machines that provided (for today's standards) severely limited capacity. Yet these attributes result in certain rather peculiar advantages. One such property is the use of reverse polish notation and the lack or eschewal of local variables. As argument-passing to subroutines and primitives takes place on the stack, factoring the code becomes nearly trivial - expressions can be taken out of context and moved into new definitions, just as in the "pointfree" style of functional programming. The emphasis on short definitions and (usually) a low subroutine call overhead additionally suggests isolating common code sequences. Local variables make this much more difficult which is why local variable facilities should be avoided.
まず第一に、Forthはかなり風変わりでとっぴに見えるいくつかの基本的な特性を土台としています。それはForthがマイクロコンピュータ時代に(今日の基準では)非常に限られた容量を提供するマシン上で誕生したことから、シンプルさとコンパクトさに根ざしていることによります。しかし、これらの属性は、ある種の独特の利点をもたらします。
そのような特性の1つは、逆ポーランド記法の使用とローカル変数の欠如あるいは省略です。サブルーチンやプリミティブへの引数渡しはスタック上で行われるため、コードのファクタリング(分解)はとるに足らないものになります。式は、関数型プログラミングの「ポイントフリー」スタイルのように、文脈から取り出して新しい定義に移動することができます。短い定義と(通常は)低いサブルーチン呼び出しオーバーヘッドを強調することは、共通のコードシーケンスを分離することをさらに示唆しています。ローカル変数の使用はこれを難しくすることが、ローカル変数の機能を避けるべき理由です。
Another useful feature is the hyperstatic environment, where later redefinition of values does not change the meaning of previous uses. This greatly enhances the stability of already compiled code and reduces the pressure to find alternative names for existing definitions, if shadowing of already defined words does not present a problem for code defined later. Even though Forth provides a quite powerful namespacing system using vocabularies, it is not strictly necessary to isolate namespaces just to avoid polluting the environment, unless shadowing is an issue.
もう一つの便利な機能は、後から(ワードの)値を再定義しても以前の使用箇所の意味に影響を与えない超静的な環境です。これにより、既にコンパイルされたコードの安定性が大幅に向上し、既存のワードをシャドウイングすることが後からコードを定義するうえで問題とならない限り、既存の定義に対する代替の名前を見つけるプレッシャーが軽減されます。Forthはボキャブラリーを使った非常に強力な名前空間システムを提供していますが、シャドウイングが問題にならない限り、環境を汚染しないように名前空間を分離することは厳密には必要ではありません。
Forth is usually interactive. Since the basic read-eval-print-loop is so simple, you are able to test all functionality in an interactive manner, as one of the first things you do is when implementing a forth is bringing up the toplevel interpreter. Imagine being able to debug device drivers interactively (and not sitting in front of a Lisp machine where already huge amounts of code must exist and work before you are even able to do so in a high-level language) and you get a glimpse of how much easier embedded systems programming, testing and exploration can be.
Forthは通常、対話的に動作します。基本的な read-eval-print-loop は非常にシンプルなので、すべての機能を対話的な方法でテストできます。Forthを実装する際に最初に行うことの一つは、トップレベルインタプリタを動くようにすることです。デバイスドライバを対話的にデバッグできることを想像してみてください(それも、高レベル言語でデバッグできるようになる前に膨大な量のコードがすでに存在して動作しなければならないLispマシンの前に座らずに)。組込みシステムのプログラミング、テスト、調査がどれだけ簡単にできるかを垣間見ることができます。
Interactive debugging at the very early stage also hints at the fact that bottom up is the usual way of designing and implementing things in Forth. This carries with it a smell of improvisation and hacking, but only because our mind is still conditioned on top-down methodologies, on up-front design, layered architectures and an ideal of planning first and doing the construction later, ignoring the fact that we seldom have a full grasp of the complete problem we are trying to solve, and that requirements, expectations and the knowledge of the underlying system are fully known in advance, which is simply not true.
非常に初期の段階での対話的なデバッグは、ボトムアップがForthでの設計や実装のいつものやり方であることをほのめかしています。これは、即興やハッキングの匂いがしますが、私たちの心は、トップダウンの方法論、事前の設計、レイヤ化されたアーキテクチャ、最初に計画を立ててから構築を行うという理想に縛られていて、解決しようとしている問題を完全に把握していることはめったになく、要件、期待、基礎となるシステムの知識が事前に完全にわかっていることは単に真実では無い、という事実を無視しているだけなのです。
In Forth there is only memory - word and byte-sized cells of storage in memory, and stacks. You step down on the level of assembly language which may sound daunting, yet gives you full control over every aspect of memory layout. There are no artificial barriers between you and the machine's architecture, no abstractions that try to make you believe you are not on a von Neumann machine, because that's what you are and acknowleding this gives you in the end true, unveiled access to the machine's resources. This is good, every C programmer has this level of access (and needs it), but the Forth programmer will not be surprised by intransparent machinations of the compiler and brittle abstraction that just get in the way, like unclear structure layout or undefined behaviour. When you program against a language standard, you are always at the mercy of those who interpret it, but if you program against an implementation then there is nothing unclear, especially if you made the implementation yourself. In Forth, there is no "yak-shaving": everything that is between you and your goal has been placed there by yourself, this is an interesting experience that just shows you how much of programming work involves doing workarounds for other people's failures to anticipate what their work will be used for (and which is something that is actually impossible.)
Forthにはメモリしかありません。メモリ内のストレージのワードサイズとバイトサイズのセル、そしてスタックです。アセンブリ言語のレベルにステップダウンするのは面倒に聞こえるかもしれませんが、メモリレイアウトのあらゆる側面を完全に制御することができます。あなたとマシンのアーキテクチャの間には人工的な障壁はありませんし、フォン・ノイマン・マシンに乗っていないと思わせようとする抽象化もありません。実際、フォン・ノイマン・マシンの上に乗っているのですから。そして、そう認めることで、最終的に真の公開されたマシンリソースへのアクセスが手に入るのです。これは良いことで、すべてのC言語プログラマはこのレベルのアクセスが可能(そしてそれを必要としている)ですが、Forthプログラマは、コンパイラの透過性の無い操作や、不明確な構造レイアウトや定義されていない動作のような、邪魔になる脆い抽象化には驚かされないでしょう。言語標準に反してプログラムする場合、常にそれを解釈する人たちに翻弄されることになりますが、実装に反してプログラムする場合は、特に自分で実装を作った場合は、不明瞭な点は何もありません。Forthには「yak-shaving」はありません: 自分とゴールとの間にあるものはすべてそこに自分で置かれてきたものです。これは、プログラミングの仕事の多くは他人の仕事が何に使われるかを予想して彼らの失敗を回避すること(それは実際は不可能ですが)であると教えてくれる興味深い経験です。
It just gets worse in languages that attempt to have direct machine access, yet provide all sorts of restrictions that give a false feeling of security and which require workarounds when these restrictions are in the way, or that impose a model of safety that in its significant complexity requires a lifelong study to truely master. You can't have both a language that provides direct low-level access to the machine and that at the same time give you all advantages of a high-level environment like automatic memory management. There will be a noticable gap somewhere that will just require more code, more boilerplate, more fragile and artificial abstractions. We want to have it both ways, and believe anybody who promises to make that dichotomy less painful, but it all fails, as it just moves too far away from the machine, making you do things just to please the language, the compiler, or the "paradigm".
それは、マシンに直接アクセスできるようにしようとしているにもかかわらず誤った安全性を感じさせ、邪魔になったときに回避策を必要とするあらゆる種類の制限を提供したり、習得に一生かかるようなかなり難しい安全性のモデルを課している言語ではさらに悪化します。マシンへの低レベルの直接アクセスを提供し、同時に自動メモリ管理のような高レベル環境のすべての利点を提供する一つの言語を手にすることはできません。どこかに、より多くのコード、より多くの定型文、より脆弱で人工的な抽象化を必要とするだけの目立ったギャップがあることでしょう。私たちは両方の方法を持ちたいと思っていますし、その二分法を苦痛でなくすることを約束する人は誰でも信じますが、それはすべて失敗しています。マシンから離れすぎて、言語、コンパイラ、または「パラダイム」を喜ばせるためだけに何かをしてしまうからです。
Now some may bring forward the performance side of things, that more modern and more complex languages provide heavy duty optimizations that a language that is basically interpreted can not support (albeit the Forth interpreter is so low-level that the boundary between compiled code and interpreted code becomes very thin, and on many CPUs the interpreter consists of two or three machine instructions). This is technically true, but whether you need all this heavy optimization work is an open question: most of your code runs seldom (or never), particularly in the bloatware that is produced nowadays, and the search for runtime performance has taken on a somewhat religious meaning. We try to eke out every cycle of speed, yet never worry about the huge amounts of code involved, which increase memory traffic and cache misses. There are many Forth systems that provide native code compilers (and some of them are quite sophisticated), but often this is not needed and just costs more in terms of memory and complexity. It is satisfying and reassuring to be able to fully understand the code that is generated from your sources, even if we ignore the security implications that highly optimizing compilers imply.
ここで性能の話を持ち出す人がいることでしょう。モダンで複雑な言語は単純なインタプリタ型言語にはできないヘビーな最適化を提供しているのだと(とはいえ、Forthインタプリタは非常に低レベルで、コンパイルされたコードと解釈されるコードの境界は非常に薄く、多くのCPUでインタプリタは2つか3つのマシン命令で構成されていますが)。これは技術的には正しいのですが、このような重い最適化作業が必要かどうかは議論の余地があります。あなたのコードのほとんどは、最近作り出されているブロートウェア(bloatware)の中で実行されることはめったに(あるいは決して)ないでしょうが、実行時パフォーマンスの調査は、やや宗教的な意味合いを持っています。私たちは、あらゆるサイクルの速度を維持しつつ、メモリトラフィックやキャッシュミスを増加させる膨大な量のコードを気にすることはありません。ネイティブコードコンパイラを提供する多くのForthシステムがありますが(中には非常に洗練されたものもあります)、多くの場合これは必要なく、メモリと複雑さの点でコストがかかるだけです。高度に最適化されたコンパイラが暗示するセキュリティへの影響を無視するとしても、ソースから生成されたコードを完全に理解できることは、満足感があり、心強いものです。
Which leads us to compactness, not only on the syntactic level, but on the abstraction level. The inability to understand software has led to a proliferation of layers, trying to shield the programmer from details that he ought not know about. Operating systems (agglomerating their own abstractions) live below runtime libraries, which in turn are the base for application level libraries that lay the ground for language-level abstractions, an ever growing tower of abstraction for abstractions sake, or better: the admission of our lack of knowledge about what is actually executing. This is considered a good thing nowadays ("ignorance is strength"), but it actually gives you nothing but disadvantages. First, the low-level interfaces to the functionality of operating systems, binary file formats or direct hardware access aren't as arcane and forbidding as they are commonly seen. They are only badly documented (if at all), or contain undocumented extensions specific to particular systems or applications. Or they are just shoddily designed by hardware engineers that have decided that the "nice" part of the interface can be done by the software guys.
これは、構文レベルだけでなく、抽象化レベルでのコンパクトさにつながります。ソフトウェアを理解できないことが、プログラマが知るべきではない詳細からプログラマを守ろうとするレイヤーの増殖につながっています。オペレーティングシステム(それ自身の抽象化を凝集したもの)はランタイムライブラリの下にあり、ランタイムライブラリはアプリケーションレベルのライブラリのベースとなり、言語レベルの抽象化の基盤となっています。抽象化のため、あるいはそれ以上の抽象化のために、増え続ける抽象化の塔は、実際に実行していることについての知識の不足を認めることです。これは今日では良いことだと考えられていますが(「無知は力なり」)、実際にはデメリット以外の何物でもありません。そもそも、オペレーティングシステムの機能やバイナリファイルフォーマット、ハードウェアへの直接アクセスなどの低レベルのインタフェースは、一般的に見られるような難解で禁じられたものではありません。それらのインタフェースは、(たとえあるとしても)ひどく文書化されているか、特定のシステムやアプリケーションに特有の文書化されていない拡張機能が含まれているだけです。あるいは、インタフェースの「良い」部分はソフトウェア担当者に任せると決めたハードウェアエンジニアが粗雑に設計しただけかもしれません。
In Forth, you ideally just have two layers: the application layer that provides your programming interface to the problem at hand, and a hardware layer that gives you primitives for accessing external devices. The real art is then to unify these two layers, but art is not something that you learn, you acquire it by other means: by pure experience and reflection.
Forthでは、理想的には2つの層を持つことになります: 手元の問題に対するプログラミングインタフェースを提供するアプリケーション層と、外部デバイスにアクセスするためのプリミティブを提供するハードウェア層です。本当の芸術は、この2つの層を統合することです。しかし、芸術とは学ぶものではなく、他の方法 - 純粋な経験や内省 - によって身につけるものです。
People in the upper echelons of Forth programming (like Chuck Moore) design their own hardware and make sure that the interfaces are easy to use from Forth, but that's not for everybody and brings its own baggage in terms of tools, languages, standards, paradigms.
チャック・ムーアのようなForthプログラミングの上層部にいる人たちは、自分たちでハードウェアを設計してForthから使いやすいインタフェースを作るようにしていますが、ツール、言語、標準、パラダイムといった面でそれ自体の負荷が生じますから、すべての人のためのものではありません。
Speaking of Mr. Moore: he laid down some wise rules for Forth programming that appear self-evident but remain hollow phrases if you don't take an active effort to enforce them.
ムーア氏といえば、彼はForthプログラミングのために、一見自明のことのように見えても、それを実行するために積極的な努力をしないと空虚な言葉になってしまう賢明なルールをいくつか示してくれました。
The main principle is to "keep it simple". Sure, we all want that. But why do so many insanely complex protocols and architectures exist? Because no one takes this advice really seriously. After all, complexity is what programmers thrive for, or better, the impression of mastering it. Yet, the humbleness required to actually pursue it is pretty uncommon among our profession. Simplicity not only means simple code, it also means to simplify the requirements, the features, the whole functionality. It means to drop the bells and whistles, the nice user interfaces, the eye candy, the useless interfaces and protocols, th legacy support and all the other things that are purported to be indespensable, but in reality are just compensations for real quality.
大原則は「シンプルに」です。確かに、私たちは皆それを望んでいます。しかし、なぜこれほど多くのひどく複雑なプロトコルやアーキテクチャが存在するのでしょうか? それは、誰もこのアドバイスを真剣に受け止めていないからです。結局のところ、複雑さとはプログラマーの醍醐味、あるいは、それを極めたという感触なのです。しかし、実際に複雑さを追求するために必要な謙虚さは、私たちの職業の中では滅多に見られないものです。シンプルさとは、シンプルなコードを意味するだけでなく、要件、特徴、全体の機能をシンプルにすることを意味します。ベルやホイッスル、素敵なユーザーインタフェース、目の保養、無駄なインタフェースやプロトコル、レガシーサポート、その他、必要不可欠とされているすべてのもの(実際には本当の品質の埋め合わせに過ぎないのですが)を落とすことを意味するのです。
The principle to keep things simple has two important corrollaries: First, "do not speculate" - do not write code or create abstractions that are only intended for a possible use in the futrue. Meet the requirements that you have now instead of planning for things that you can not be sure about.
物事をシンプルに保つための原則には、2つの重要なコロラリーがあります。第一に、「憶測をしない」ということ、つまり、将来の使用を想定したコードを書いたり、抽象化したりしないことです。確信が持てないことを計画するのではなく、今持っている要件を満たしてください。
The second corrollary is "do it yourself". This has severe repercussions if you take this advice seriously. It also emphasizes the need to learn, something a software developer should never be afraid of and should actually enjoy. Doing everything yourself frees you from having to understand mediocre abstractions, bloated libraries full of useless stuff, and the bugs that necessarily infest code that was written for universal use by people who have not (and can not) account for the universality of applications that may possibly use that code. Reuse has become a dogma, even though there are first signs that it is carefully questioned. That emphasis on reuse just demonstrates the industrial drive to produce assets, to create lasting value (call it codebases or intellectual property). It's an illusion that denies the fact of software rot. What you reuse of a library is usually just a tiny part, but you pay for all the unused or pointless functionality and particularly for the bugs that are not yours.
2つ目のコロラリーは「自分でやれ」です。このアドバイスを真面目に受け止めた場合、これは深刻な影響を及ぼします。これはまた、ソフトウェア開発者が決して恐れるべきではなく、実際に楽しむべきものである、学ぶことの必要性を強調しています。すべてを自分で行うことで、平凡な抽象化や、役に立たないものでいっぱいの肥大化したライブラリや、そのコードを使っているかもしれないアプリケーションの普遍性を説明できない人による普遍的な使用を目的として書かれたコードにはびこるバグなどを理解する必要から解放されます。再利用は、それが慎重に疑われているという最初の兆候があるにもかかわらず、ドグマになっています。再利用を強調するということは、資産を生産し、永続的な価値(コードベースや知的財産と呼んでいます)を創造しようとする産業界の動きを示しているにすぎません。それは、ソフトウェアが腐っているという事実を否定する幻想です。あなたがライブラリを再利用しているのは、通常はほんの一部に過ぎませんが、あなたは使われていない機能や無意味な機能、特にあなたのものではないバグのためにお金を払っているのです。
And this is an important point: to do everything yourself gives you a superior understanding of the software you produce. It allows you to modify it at every level to your needs. It makes it possible to be able to account for every byte (if you do it right) in your binary. When was the last time you were able to do that? So to program in Forth means, you invariably implement it yourself, and don't worry about "standards". As the old saying goes: "If you have seen one Forth - then you have seen one Forth." And that's totally ok.
そして、これは重要なポイントです: すべてを自分で行うことで、自分が制作したソフトウェアをよりよく理解することができます。自分のニーズに合わせて、あらゆるレベルで修正することができます。バイナリのすべてのバイトを(正しく行えば)計算できるようになります。最後にそんなことができたのはいつですか? つまり、Forthでプログラミングするということは、常に自分で実装し、「標準」を気にしないということです。昔から言われているように "If you have seen one Forth - then you have seen one Forth. "という古いことわざがあります。そして、それは全く問題ありません。
The age were single programmers were responsible for whole applications are over, they say. We are supposed to think in teams and think of those that come after us, taking over the responsibility. That thinking may be appropriate if we think in terms of multimegabyte applications, of all that web-scale megalomania, that, once again, denies that software remains ephemeral and gets stale, fouls and finally rots. That thinking is born out of a taylorized idealistic model of software development where the developers are little cogs in a big machine who plug together pieces of Lego. It is a thinking that denies that the underlying assumptions change, that requirements change, and that no programming language adequately addresses the very real problems involved when large amounts of functionality has to change in large amounts of code. We just pretend it isn't that bad, that a bit of redesign, one or two new layers and lots of unit testing will be enough and that, one day, we will clean this all up. the big "rewrite" is something unthinkable, unspeakable, an admission of weakness, of failure. This is all nonsense, or better: propaganda. Following "best practices" just means repeating the same mistakes as everybody else, ignoring intuition and avoid experimenting with new approaches.
一人のプログラマがアプリケーション全体の責任を負う時代は終わったと言われています。私たちはチームで考え、後から来た人たちが責任を引き継ぐことを考えるべきだと言われています。マルチメガバイトのアプリケーションや、ウェブスケールの誇大妄想の観点から考えるなら、この考え方は適切かもしれませんが、ソフトウェアは儚く、陳腐化し、腐敗し、最終的には腐ってしまうということを再び否定しています。この考え方は、ソフトウェア開発に調整された理想主義的モデルから生まれたもので、開発者はレゴのピースをつなぎ合わせる大きな機械の中の小さな歯車です。この考え方は、基本的な前提条件が変わること、要件が変わること、そして、大量の機能を大量のコードで変更しなければならないときに、どのプログラミング言語も現実の問題に適切に対処できないことを否定する考え方です。私たちは、少しの再設計、1つか2つの新しいレイヤー、たくさんのユニットテストで十分であり、いつか私たちはこのすべてをきれいにするだろうと、それはさほど悪くないふりをしています。大きな「書き換え」は、なにか考えられない、言葉にできない、弱さや失敗を認めることです。これはまったくナンセンス、あるいはプロパガンダです。「ベストプラクティス」に従うことは、直感を無視し、新しいアプローチでの実験を避けて、他のみんなと同じ間違いを繰り返すことを意味します。
What plays into this is the matter of standards. There are Forth standards, but one shouldn't take them too seriously. Standards impose interface designs that may be suboptimal on the platform you work on. They are an attempt to do the impossible: to once settle all ambiguities regarding the use of a language in all possible situations, for all possible platforms, for all possible applications. The intention is, of course, to simplify reuse, to ease porting. But we already talked about this. Standards can be helpful, but compliance should not be a goal in itself. Additionally, a universal standard must by definition be extremely vague. The more platforms are covered, the more vague it must become to cover all possible implementations, which ends in absurdly complex behavioural descriptions like you see in the C (or C++) standard, that can only be understood by Lawyers or those that think like them.
ここで関係してくるのは標準の問題です。Forthの標準がありますが、それをあまり深刻に受け止めるべきではありません。標準は、あなたが作業するプラットフォーム上では最適ではないかもしれないインタフェースデザインを課しています。それは不可能なことをしようとする試みです。つまり、ある言語の使用に関する曖昧さを、すべての可能な状況で、すべての可能なプラットフォームで、すべての可能なアプリケーションで解決しようということです。その意図はもちろん、再利用を簡単にし、移植を容易にすることです。しかし、これについてはすでに話しました。標準は役に立つことがありますが、準拠すること自体が目的ではありません。さらに、普遍的な標準は定義上、非常に曖昧でなければなりません。対象となるプラットフォームが増えれば増えるほど、すべての可能性のある実装をカバーするために、より曖昧にならざるを得ません。そうなると、C(またはC++)言語の標準で見られる、弁護士やそのように考える人にしか理解できない信じられないほど複雑な動作記述に終わることになります。
And nobody says that code can't be shared, that one should not learn to understand other people's code or that designs should be hoarded by lone rangers. But we should understand that in many cases it is a single programmer or very small team that does the main design and implementation work for a particular application, or component, simply because programs (even simple ones) require getting intellectually deeply involved (without interruptions, please!) into both the subject matter, the formal or informal requirements, the possible outcomes of different design decisions and so on. The big design meeting up front, the large team where everybody knows exactly what everybody is doing at any moment, is a myth. For fixing bugs and maintenance it may be possible to spread the work over larger teams, but at that stage the software is already dying, more or less slowly. It may take decades, but once it becomes infeasible for a single person to rewrite the core functionality from scratch, it is dead. No, the ideal is: y o u write it, you understand it, you maintain and change it, you rewrite it as often as necessary (remember compactness?), you throw it away and do something else.
誰もコードを共有することができないとは言っていませんし、他人のコードを理解することを学ぶべきではないとも言っていませんし、デザインは一匹狼にため込まれるべきだとも言っていません。しかし、多くの場合、特定のアプリケーションやコンポーネントの主要な設計と実装の作業を行うのは、一人のプログラマーや非常に小さなチームであることを理解すべきです。なぜなら、プログラムには(単純なものであっても)、主題、形式的または非公式な要件、異なる設計決定の結果の可能性などの両方に知的に深く関与すること(中断しないようにお願いします!)が要求されるからです。大規模な設計会議のように、誰もがいつでも何をしているのかを正確に把握しているような大規模なチームで行われるのは神話です。バグの修正やメンテナンスのために、より大きなチームに仕事を分散させることは可能かもしれませんが、その段階では、ソフトウェアはすでに、多かれ少なかれ死にかけています。何十年もかかるかもしれませんが、一人の人間がゼロからコア機能を書き換えることが不可能になったら、ソフトウェアは死んでいます。いいえ、理想的なのは「あ な た」がそれを書いて、それを理解し、それを維持し、変更し、必要に応じて何度でも書き直し(コンパクトさを覚えていますか?)、それを棄てて別のことをするということです。
Forth is a language for solving practical problems. It is a language for turning LEDs on and off, for moving motors, for writing pixels into a frame buffer, for writing device drivers, for bringing up something runnable on single board computers. It is also a language for searching, sorting and manipulating data and implementing the gruntwork that will always be in one or the other way a job like that. If you want to parse XML or JSON, it is surely possible, but it won't make you happy. It is not a language for writing meaningless abstractions on top of other meaningless abstractions, or for writing a library that solves a specific problem in the most possible general way, using that fancy algorithm or data format that happens to be hip today. It is an excellent tool for writing virtual machines, assemblers, or custom data formats. Once you are willing to simplify the problem to the point where it is natural to implement it in Forth, while at the same time you are just able to fulfil the intended goal, you are on the right path. It requires out-of-the-box thinking and a lot of thought, but rewards you with something that stands a better chance of not being just another pile of code that barely works, quickly rots, or ends up being a liability that you regret having ever written and that has grown to a point where rewriting or replacing it becomes harder and harder.
Forthは実用的な問題を解決するための言語です。LEDをON/OFFするための言語であり、モーターを動かすための言語であり、ピクセルをフレームバッファに書き込むための言語であり、デバイスドライバを書くための言語であり、シングルボードコンピュータ上で実行可能なものを立ち上げるための言語です。また、データを検索したり、ソートしたり、操作したりするための言語でもあり、必ずどうにかしてそのような仕事になってしまう単調でつらい仕事を実装するための言語でもあります。XMLやJSONをパースしたいのであれば、確かに可能ですが、それだけでは幸せにはなれません。これは、他の無意味な抽象化の上に無意味な抽象化を書くための言語ではありませんし、特定の問題を今日の流行りのアルゴリズムやデータフォーマットを使って可能な限り一般的な方法で解決するライブラリを書くための言語でもありません。仮想マシンやアセンブラ、カスタムデータフォーマットを書くためには優れたツールです。問題をForthで実装するのが当たり前になるほど単純化し、同時に意図した目標を達成することができれば、あなたは正しい道を歩んでいることになります。既成概念にとらわれない思考と多くの思索を必要としますが、その代わりに、動くのがやっとで、すぐに腐ってしまうコードや、今まで書いてきたことを後悔し、書き換えや置き換えが難しくなるほど成長した負債となるコードの山とならないであろう何かを得ることができます。
Writing "good" Forth code is very hard, or at least what I consider good Forth code, which may be different from what others consider good. Forth has been called a "write only language", but only because it requires an additional effort to simplify your code to a point where everything becomes obvious. This is an art, it is a moment of transcendence, which I don't claim to have ever reached, but sometimes I get a glimpse of it, an inkling of the fact that if I would work very hard on this, it will become so simple, so heavily factored, using such obvious and clear names that everything just falls into place. It is this moment that programmers experience every once in a while, where a short, simple piece of code just does what it is supposed to do, without any extra baggage, easily understandable. To achieve it in Forth is much harder, it may require more time, many rewrites, but the results are even more satisfying, as the result is smaller, much simpler, fully self-contained and not burdened by code that you can not trust. When you forget about that urge of productivity, which has become the moloch we sacrifice our children to, you may be able to achieve that particular thing that is called quality, elegance, art. It may take a lifetime, you may never reach that far, but still you should strive for it.
「良い」Forthのコードを書くのは非常に難しいことです。あるいは、少なくとも私が考える良い Forth のコードは、他の人が考える良いコードとは異なるかもしれません。Forthは「書くだけの言語」と呼ばれてきましたが、それは、すべてが明らかになるところまでコードを単純化するための追加の努力が必要だからに他なりません。これは芸術であり、超越の瞬間であり、私が到達したことがあるとは言いませんが、時々、その瞬間を垣間見ることがあり、もし私がこれに一生懸命取り組めば、それはとてもシンプルになり、十分に分解され、明白で明確な名前を使って、すべてのものがうまく収まるという事実の暗示を感じます。プログラマーがたまに経験するこの瞬間です。短くてシンプルなコードが、余計な荷物を持たずに、簡単に理解できるように、やるべきことをやってくれるのです。Forthでそれを実現するのはずっと難しく、より多くの時間と多くの書き換えが必要になるかもしれませんが、その結果は、より小さく、はるかにシンプルで、完全に自己完結していて、信頼できないコードによる負担がないので、さらに満足感が得られます。あなたが、子供たちを人身御供にするMoloch神になっている「生産性」に対する衝動を忘れたとき、品質、優雅さ、芸術と呼ばれる特別のものを達成することができるかもしれません。それは一生かかるかもしれないし、そこまで到達することはないかもしれないが、それでもあなたはそれのために努力すべきです。
Or you remain a cog in the machine, developing on absurdly convoluted "software stacks", using inadequate and brittle languages, connect barely matching interfaces to only small parts of too many bloated libraries, using insanely sophisticated tools of incomprehensble complexity and trot on, asking yourself why everything sucks and why the last time you actually enjoyed programming and were you could be genuinely and deservedly proud on what you accomplished, was when you were a kid...
さもなければ、あなたは機械の歯車のままで、信じられないほど複雑な「ソフトウェアスタック」で開発し、不十分で脆い言語を使い、かろうじて一致するインタフェースをあまりにも肥大化したライブラリのごく一部に接続し、理解できないほどの複雑さの洒落にならないツールを使って、なぜすべてがクソなのか、なぜ実際にプログラミングを楽しんで、自分が達成したことを心から誇りに思うことができた最後の時間は、あなたが子供の頃だったのか、と自分自身に問いかけていることでしょう...
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Thoughts on Forth Programming (Japanese translation)</title>
</head>
<body>
<pre>
------------------------------------------------------------------------------
以下の翻訳文は、Felix Winkelmann の Thoughts on Forth Programming
(http://call-with-current-continuation.org/articles/forth.txt) の
翻訳であり、原著者の許可を得て公開するものです。
2021-09-01 Nobuhiko FUNATO (nfunato @ acm . org)
更新履歴:
2021-09-02(rev10): Shiro Kawaiさんにご指摘いただいた誤訳訂正/改善を反映
2021-09-02(rev09): 公開初版
------------------------------------------------------------------------------
</pre>
<p>この文書は、私のForthの哲学に関する理解と、それを特に興味深いものにしている
いくつかの属性を、Forthとその使い方について私が重要と思うことと一緒に記述す
る試みです。これらはすべて私の個人的意見であり、ドグマと見なすべきではありま
せん。私はこれまで様々なプログラミング言語を使ってきましたが、そのほとんどが
好きではありませんでした。SchemeやPrologのように非常にエレガントで強力な言語
もあると思いますが、Forthのようにプログラミングの再考を求める言語はありません。</p>
<p>Forthは、一人の人間や少人数のプログラマのグループに合わせて作られた、非常に
「個人主義的」なものです。その理由のほとんどは、Forthシステムを自分で実装す
ることが自然で比較的簡単であること(そしてそうすべきであること)と、言語に本質
的に可鍛性があり、個人のニーズに適応することによります。したがって、私が書いて
いることは、プログラミング言語であると同時にエンジニアリング哲学でもある
Forthの一つの見方に過ぎません。</p>
<p>私の認識では、Forthプログラマには2つの考え方の流派が存在します。一方は、極端
なシンプルさ、ミニマリズム、短い定義、そして可能な限りハードウェアに近いところ
まで降りていくことを好む「古典派」です。
もう一方は、他の言語に見られる機能で古典的なForthモデルを拡張し、一般的に
機能やツールを追加することで、よりコンピューティングの主流にアクセスしやすい言語
にしようと努力する「現代派」です。後者は、概してスタック、逆ポーランド記法、重い
リファクタリングといったアイデアを、一般的に現代のプログラミング言語に不可欠で
望ましいと考えられているものと混ぜ合わせようとしていますが、結果として変な記法を
備えたLispのようなものになっています。私は個人的には前者の陣営に属していますが、
それは後に続く文章でより明らかになるでしょう。</p>
<p>まず第一に、Forthはかなり風変わりでとっぴに見えるいくつかの基本的な特性を土台と
しています。それはForthがマイクロコンピュータ時代に(今日の基準では)非常に限られた
容量を提供するマシン上で誕生したことから、シンプルさとコンパクトさに根ざしている
ことによります。しかし、これらの属性は、ある種の独特の利点をもたらします。</p>
<p>そのような特性の1つは、逆ポーランド記法の使用とローカル変数の欠如あるいは省略です。
サブルーチンやプリミティブへの引数渡しはスタック上で行われるため、コードのファクタ
リング(分解)はとるに足らないものになります。式は、関数型プログラミングの「ポイント
フリー」スタイルのように、文脈から取り出して新しい定義に移動することができます。
短い定義と(通常は)低いサブルーチン呼び出しオーバーヘッドを強調することは、共通の
コードシーケンスを分離することをさらに示唆しています。ローカル変数の使用はこれを
難しくすることが、ローカル変数の機能を避けるべき理由です。</p>
<p>もう一つの便利な機能は、後から(ワードの)値を再定義しても以前の使用箇所の意味に
影響を与えない超静的な環境です。これにより、既にコンパイルされたコードの安定性が
大幅に向上し、既存のワードをシャドウイングすることが後からコードを定義するうえで
問題とならない限り、既存の定義に対する代替の名前を見つけるプレッシャーが軽減されます。
Forthはボキャブラリーを使った非常に強力な名前空間システムを提供していますが、
シャドウイングが問題にならない限り、環境を汚染しないように名前空間を分離することは
厳密には必要ではありません。</p>
<p>Forthは通常、対話的に動作します。基本的な read-eval-print-loop は非常にシンプル
なので、すべての機能を対話的な方法でテストできます。Forthを実装する際に最初に行う
ことの一つは、トップレベルインタプリタを動くようにすることです。デバイスドライバを対話的に
デバッグできることを想像してみてください(それも、高レベル言語でデバッグできるように
なる前に膨大な量のコードがすでに存在して動作しなければならないLispマシンの前に
座らずに)。組込みシステムのプログラミング、テスト、調査がどれだけ簡単にできるかを
垣間見ることができます。</p>
<p>非常に初期の段階での対話的なデバッグは、ボトムアップがForthでの設計や実装のいつもの
やり方であることをほのめかしています。これは、即興やハッキングの匂いがしますが、
私たちの心は、トップダウンの方法論、事前の設計、レイヤ化されたアーキテクチャ、
最初に計画を立ててから構築を行うという理想に縛られていて、解決しようとしている
問題を完全に把握していることはめったになく、要件、期待、基礎となるシステムの知識が
事前に完全にわかっていることは単に真実では無い、という事実を無視しているだけなのです。</p>
<p>Forthにはメモリしかありません。メモリ内のストレージのワードサイズとバイトサイズの
セル、そしてスタックです。アセンブリ言語のレベルにステップダウンするのは面倒に
聞こえるかもしれませんが、メモリレイアウトのあらゆる側面を完全に制御することが
できます。あなたとマシンのアーキテクチャの間には人工的な障壁はありませんし、
フォン・ノイマン・マシンに乗っていないと思わせようとする抽象化もありません。
実際、フォン・ノイマン・マシンの上に乗っているのですから。
そして、そう認めることで、最終的に真の公開されたマシンリソースへのアクセスが
手に入るのです。これは良いことで、すべてのC言語プログラマは
このレベルのアクセスが可能(そしてそれを必要としている)ですが、Forthプログラマは、
コンパイラの透過性の無い操作や、不明確な構造レイアウトや定義されていない動作の
ような、邪魔になる脆い抽象化には驚かされないでしょう。言語標準に反してプログラム
する場合、常にそれを解釈する人たちに翻弄されることになりますが、実装に反して
プログラムする場合は、特に自分で実装を作った場合は、不明瞭な点は何もありません。
Forthには「yak-shaving」はありません: 自分とゴールとの間にあるものはすべて
そこに自分で置かれてきたものです。これは、プログラミングの仕事の多くは他人の仕事が
何に使われるかを予想して彼らの失敗を回避すること(それは実際は不可能ですが)であると
教えてくれる興味深い経験です。</p>
<p>それは、マシンに直接アクセスできるようにしようとしているにもかかわらず誤った安全性を
感じさせ、邪魔になったときに回避策を必要とするあらゆる種類の制限を提供したり、
習得に一生かかるようなかなり難しい安全性のモデルを課している言語ではさらに悪化します。
マシンへの低レベルの直接アクセスを提供し、同時に自動メモリ管理のような高レベル環境の
すべての利点を提供する一つの言語を手にすることはできません。どこかに、より多くのコード、
より多くの定型文、より脆弱で人工的な抽象化を必要とするだけの目立ったギャップがあること
でしょう。私たちは両方の方法を持ちたいと思っていますし、その二分法を苦痛でなくすることを
約束する人は誰でも信じますが、それはすべて失敗しています。マシンから離れすぎて、
言語、コンパイラ、または「パラダイム」を喜ばせるためだけに何かをしてしまうからです。</p>
<p>ここで性能の話を持ち出す人がいることでしょう。モダンで複雑な言語は単純なインタプリタ型
言語にはできないヘビーな最適化を提供しているのだと(とはいえ、Forthインタプリタは非常に
低レベルで、コンパイルされたコードと解釈されるコードの境界は非常に薄く、多くのCPUで
インタプリタは2つか3つのマシン命令で構成されていますが)。これは技術的には正しいのですが、
このような重い最適化作業が必要かどうかは議論の余地があります。あなたのコードの
ほとんどは、最近作り出されているブロートウェア(bloatware)の中で実行されることは
めったに(あるいは決して)ないでしょうが、実行時パフォーマンスの調査は、やや宗教的な
意味合いを持っています。私たちは、あらゆるサイクルの速度を維持しつつ、メモリ
トラフィックやキャッシュミスを増加させる膨大な量のコードを気にすることはありません。
ネイティブコードコンパイラを提供する多くのForthシステムがありますが(中には非常に
洗練されたものもあります)、多くの場合これは必要なく、メモリと複雑さの点でコストが
かかるだけです。高度に最適化されたコンパイラが暗示するセキュリティへの影響を無視
するとしても、ソースから生成されたコードを完全に理解できることは、満足感があり、
心強いものです。</p>
<p>これは、構文レベルだけでなく、抽象化レベルでのコンパクトさにつながります。ソフト
ウェアを理解できないことが、プログラマが知るべきではない詳細からプログラマを守ろう
とするレイヤーの増殖につながっています。オペレーティングシステム(それ自身の抽象化を
凝集したもの)はランタイムライブラリの下にあり、ランタイムライブラリはアプリケーション
レベルのライブラリのベースとなり、言語レベルの抽象化の基盤となっています。
抽象化のため、あるいはそれ以上の抽象化のために、増え続ける抽象化の塔は、実際に
実行していることについての知識の不足を認めることです。これは今日では良いことだと
考えられていますが(「無知は力なり」)、実際にはデメリット以外の何物でもありません。
そもそも、オペレーティングシステムの機能やバイナリファイルフォーマット、ハード
ウェアへの直接アクセスなどの低レベルのインタフェースは、一般的に見られるような
難解で禁じられたものではありません。それらのインタフェースは、(たとえあるとしても)
ひどく文書化されているか、特定のシステムやアプリケーションに特有の文書化されていない
拡張機能が含まれているだけです。あるいは、インタフェースの「良い」部分はソフトウェア
担当者に任せると決めたハードウェアエンジニアが粗雑に設計しただけかもしれません。</p>
<p>Forthでは、理想的には2つの層を持つことになります: 手元の問題に対するプログラミング
インタフェースを提供するアプリケーション層と、外部デバイスにアクセスするための
プリミティブを提供するハードウェア層です。本当の芸術は、この2つの層を統合することです。
しかし、芸術とは学ぶものではなく、他の方法 - 純粋な経験や内省 - によって身につける
ものです。</p>
<p>チャック・ムーアのようなForthプログラミングの上層部にいる人たちは、自分たちでハード
ウェアを設計してForthから使いやすいインタフェースを作るようにしていますが、ツール、
言語、標準、パラダイムといった面でそれ自体の負荷が生じますから、すべての人のための
ものではありません。</p>
<p>ムーア氏といえば、彼はForthプログラミングのために、一見自明のことのように見えても、
それを実行するために積極的な努力をしないと空虚な言葉になってしまう賢明なルールを
いくつか示してくれました。</p>
<p>大原則は「シンプルに」です。確かに、私たちは皆それを望んでいます。しかし、なぜ
これほど多くのひどく複雑なプロトコルやアーキテクチャが存在するのでしょうか?
それは、誰もこのアドバイスを真剣に受け止めていないからです。結局のところ、複雑さ
とはプログラマーの醍醐味、あるいは、それを極めたという感触なのです。しかし、実際に
複雑さを追求するために必要な謙虚さは、私たちの職業の中では滅多に見られないものです。
シンプルさとは、シンプルなコードを意味するだけでなく、要件、特徴、全体の機能を
シンプルにすることを意味します。ベルやホイッスル、素敵なユーザーインタフェース、
目の保養、無駄なインタフェースやプロトコル、レガシーサポート、その他、必要不可欠と
されているすべてのもの(実際には本当の品質の埋め合わせに過ぎないのですが)を落とす
ことを意味するのです。</p>
<p>物事をシンプルに保つための原則には、2つの重要なコロラリーがあります。第一に、
「憶測をしない」ということ、つまり、将来の使用を想定したコードを書いたり、抽象化
したりしないことです。確信が持てないことを計画するのではなく、今持っている要件を
満たしてください。</p>
<p>2つ目のコロラリーは「自分でやれ」です。このアドバイスを真面目に受け止めた場合、
これは深刻な影響を及ぼします。これはまた、ソフトウェア開発者が決して恐れるべき
ではなく、実際に楽しむべきものである、学ぶことの必要性を強調しています。すべてを
自分で行うことで、平凡な抽象化や、役に立たないものでいっぱいの肥大化したライブラリや、
そのコードを使っているかもしれないアプリケーションの普遍性を説明できない人による
普遍的な使用を目的として書かれたコードにはびこるバグなどを理解する必要から解放されます。
再利用は、それが慎重に疑われているという最初の兆候があるにもかかわらず、ドグマに
なっています。再利用を強調するということは、資産を生産し、永続的な価値(コードベース
や知的財産と呼んでいます)を創造しようとする産業界の動きを示しているにすぎません。
それは、ソフトウェアが腐っているという事実を否定する幻想です。あなたがライブラリを
再利用しているのは、通常はほんの一部に過ぎませんが、あなたは使われていない機能や
無意味な機能、特にあなたのものではないバグのためにお金を払っているのです。</p>
<p>そして、これは重要なポイントです: すべてを自分で行うことで、自分が制作したソフト
ウェアをよりよく理解することができます。自分のニーズに合わせて、あらゆるレベルで
修正することができます。バイナリのすべてのバイトを(正しく行えば)計算できるように
なります。最後にそんなことができたのはいつですか? つまり、Forthでプログラミング
するということは、常に自分で実装し、「標準」を気にしないということです。昔から
言われているように "If you have seen one Forth - then you have seen one
Forth. "という古いことわざがあります。そして、それは全く問題ありません。</p>
<p>一人のプログラマがアプリケーション全体の責任を負う時代は終わったと言われています。
私たちはチームで考え、後から来た人たちが責任を引き継ぐことを考えるべきだと言われて
います。マルチメガバイトのアプリケーションや、ウェブスケールの誇大妄想の観点から
考えるなら、この考え方は適切かもしれませんが、ソフトウェアは儚く、陳腐化し、腐敗し、
最終的には腐ってしまうということを再び否定しています。この考え方は、ソフトウェア
開発に調整された理想主義的モデルから生まれたもので、開発者はレゴのピースをつなぎ
合わせる大きな機械の中の小さな歯車です。この考え方は、基本的な前提条件が変わること、
要件が変わること、そして、大量の機能を大量のコードで変更しなければならないときに、
どのプログラミング言語も現実の問題に適切に対処できないことを否定する考え方です。
私たちは、少しの再設計、1つか2つの新しいレイヤー、たくさんのユニットテストで十分で
あり、いつか私たちはこのすべてをきれいにするだろうと、それはさほど悪くないふりを
しています。大きな「書き換え」は、なにか考えられない、言葉にできない、弱さや失敗を
認めることです。これはまったくナンセンス、あるいはプロパガンダです。「ベスト
プラクティス」に従うことは、直感を無視し、新しいアプローチでの実験を避けて、
他のみんなと同じ間違いを繰り返すことを意味します。</p>
<p>ここで関係してくるのは標準の問題です。Forthの標準がありますが、それをあまり深刻に
受け止めるべきではありません。標準は、あなたが作業するプラットフォーム上では最適では
ないかもしれないインタフェースデザインを課しています。それは不可能なことをしよう
とする試みです。つまり、ある言語の使用に関する曖昧さを、すべての可能な状況で、
すべての可能なプラットフォームで、すべての可能なアプリケーションで解決しようと
いうことです。その意図はもちろん、再利用を簡単にし、移植を容易にすることです。
しかし、これについてはすでに話しました。標準は役に立つことがありますが、準拠する
こと自体が目的ではありません。さらに、普遍的な標準は定義上、非常に曖昧でなければ
なりません。対象となるプラットフォームが増えれば増えるほど、すべての可能性のある
実装をカバーするために、より曖昧にならざるを得ません。そうなると、C(またはC++)言語の
標準で見られる、弁護士やそのように考える人にしか理解できない信じられないほど複雑な
動作記述に終わることになります。</p>
<p>誰もコードを共有することができないとは言っていませんし、他人のコードを理解することを
学ぶべきではないとも言っていませんし、デザインは一匹狼にため込まれるべきだとも
言っていません。しかし、多くの場合、特定のアプリケーションやコンポーネントの主要な
設計と実装の作業を行うのは、一人のプログラマーや非常に小さなチームであることを
理解すべきです。なぜなら、プログラムには(単純なものであっても)、主題、形式的または
非公式な要件、異なる設計決定の結果の可能性などの両方に知的に深く関与すること(中断
しないようにお願いします!)が要求されるからです。大規模な設計会議のように、誰もが
いつでも何をしているのかを正確に把握しているような大規模なチームで行われるのは神話です。
バグの修正やメンテナンスのために、より大きなチームに仕事を分散させることは可能かも
しれませんが、その段階では、ソフトウェアはすでに、多かれ少なかれ死にかけています。
何十年もかかるかもしれませんが、一人の人間がゼロからコア機能を書き換えることが
不可能になったら、ソフトウェアは死んでいます。いいえ、理想的なのは「あ な た」が
それを書いて、それを理解し、それを維持し、変更し、必要に応じて何度でも書き直し
(コンパクトさを覚えていますか?)、それを棄てて別のことをするということです。</p>
<p>Forthは実用的な問題を解決するための言語です。LEDをON/OFFするための言語であり、
モーターを動かすための言語であり、ピクセルをフレームバッファに書き込むための言語であり、
デバイスドライバを書くための言語であり、シングルボードコンピュータ上で実行可能なものを
立ち上げるための言語です。また、データを検索したり、ソートしたり、操作したりするための
言語でもあり、必ずどうにかしてそのような仕事になってしまう単調でつらい仕事を実装する
ための言語でもあります。XMLやJSONをパースしたいのであれば、確かに可能ですが、それだけ
では幸せにはなれません。これは、他の無意味な抽象化の上に無意味な抽象化を書くための
言語ではありませんし、特定の問題を今日の流行りのアルゴリズムやデータフォーマットを
使って可能な限り一般的な方法で解決するライブラリを書くための言語でもありません。
仮想マシンやアセンブラ、カスタムデータフォーマットを書くためには優れたツールです。
問題をForthで実装するのが当たり前になるほど単純化し、同時に意図した目標を達成する
ことができれば、あなたは正しい道を歩んでいることになります。既成概念にとらわれない
思考と多くの思索を必要としますが、その代わりに、動くのがやっとで、すぐに腐ってしまう
コードや、今まで書いてきたことを後悔し、書き換えや置き換えが難しくなるほど成長した
負債となるコードの山とならないであろう何かを得ることができます。</p>
<p>「良い」Forthのコードを書くのは非常に難しいことです。あるいは、少なくとも私が考える
良い Forth のコードは、他の人が考える良いコードとは異なるかもしれません。Forthは
「書くだけの言語」と呼ばれてきましたが、それは、すべてが明らかになるところまでコードを
単純化するための追加の努力が必要だからに他なりません。これは芸術であり、超越の瞬間であり、
私が到達したことがあるとは言いませんが、時々、その瞬間を垣間見ることがあり、もし私が
これに一生懸命取り組めば、それはとてもシンプルになり、十分に分解され、明白で明確な
名前を使って、すべてのものがうまく収まるという事実の暗示を感じます。プログラマーが
たまに経験するこの瞬間です。短くてシンプルなコードが、余計な荷物を持たずに、簡単に
理解できるように、やるべきことをやってくれるのです。Forthでそれを実現するのはずっと
難しく、より多くの時間と多くの書き換えが必要になるかもしれませんが、その結果は、より
小さく、はるかにシンプルで、完全に自己完結していて、信頼できないコードによる負担が
ないので、さらに満足感が得られます。あなたが、子供たちを人身御供にするMoloch神に
なっている「生産性」に対する衝動を忘れたとき、品質、優雅さ、芸術と呼ばれる特別の
ものを達成することができるかもしれません。それは一生かかるかもしれないし、そこまで
到達することはないかもしれないが、それでもあなたはそれのために努力すべきです。</p>
<p>さもなければ、あなたは機械の歯車のままで、信じられないほど複雑な「ソフトウェアスタック」
で開発し、不十分で脆い言語を使い、かろうじて一致するインタフェースをあまりにも肥大化した
ライブラリのごく一部に接続し、理解できないほどの複雑さの洒落にならないツールを使って、
なぜすべてがクソなのか、なぜ実際にプログラミングを楽しんで、自分が達成したことを心から
誇りに思うことができた最後の時間は、あなたが子供の頃だったのか、と自分自身に問いかけて
いることでしょう...</p>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment