
リテラルプログラミング(LP)は、 1984年にドナルド・クヌースによって導入されたプログラミングパラダイムであり、コンピュータプログラムの動作原理を英語などの自然言語で説明し、マクロや従来のソースコードの断片を散りばめ(埋め込み) 、そこからコンパイル可能なソースコードを生成できるというものです。[ 1 ]このアプローチは、再現可能な研究やオープンアクセスを目的として、科学計算やデータサイエンスで日常的に使用されています。[ 2 ]リテラルプログラミングツールは、今日では何百万人ものプログラマーによって使用されています。[ 3 ]
ドナルド・クヌースが提唱したリテラルプログラミングパラダイムは、コンパイラによって課せられた方法と順序でコンピュータプログラムを記述することから離れ、代わりにプログラマーが思考の論理と流れによって要求される順序でプログラムを開発するためのマクロを提供するものです。[ 4 ]リテラルプログラムは、マクロを使用して抽象化と従来のソースコードを隠蔽し、エッセイのテキストに近い、より自然な言語での論理の説明として記述されます。
リテラルプログラミングツールは、ソースファイルから 2 つの表現を取得するために使用されます。1 つはコンパイラまたはインタプリタが理解できる「絡み合った」コード、もう 1 つはフォーマットされたドキュメントとして表示するためのもので、リテラルソースから「織り込まれた」ものと言われています。[ 5 ]第一世代のリテラルプログラミングツールはコンピュータ言語に特化していましたが、後期のものは言語に依存せず、個々のプログラミング言語を超えて存在します。
リテラルプログラミングは、1984年にドナルド・クヌースによって初めて導入されました。彼は、人間にとって適切な文学となるプログラムを作成することを意図していました。彼は、アルゴリズムとデジタルタイポグラフィの研究の一環として、スタンフォード大学でそれを実装しました。実装は「WEB」と呼ばれました。これは、まだコンピューティングに適用されていない数少ない英語の3文字の単語の1つであると彼が考えていたためです。[ 6 ]しかし、それは、単純な材料から繊細に組み立てられたソフトウェアの複雑な性質に似ています。[ 1 ]リテラルプログラミングの実践は、特にデータサイエンスにおいて、計算ノートブックの使用により、2010年代に重要な復活を遂げました。
リテラルプログラミングとは、プログラムロジックを人間が理解できる言語で記述し、その中に(基本的なマークアップで区切られた)コードスニペットやマクロを含めることです。リテラルソースファイル内のマクロは、プログラミング問題を解決する際に人間が作成した抽象概念を記述する、タイトルや説明文のようなものであり、コードの一部や低レベルのマクロを隠蔽する役割を果たします。これらのマクロは、コンピュータサイエンスの教育で一般的に用いられる擬似コードのアルゴリズムに似ています。こうした任意の説明文は、プログラマーによってその場で作成される正確な新しい演算子となり、基盤となるプログラミング言語の上にメタ言語を形成します。
プリプロセッサは、任意の階層、あるいは「相互接続されたマクロのウェブ」 [ 7 ]を置き換えて、1つのコマンド(「tangle」)でコンパイル可能なソースコードを生成し、別のコマンド(「weave」)でドキュメントを生成するために使用されます。プリプロセッサはまた、マクロの内容を書き出し、リテラルプログラムソースファイルのテキスト内の任意の場所に既に作成されたマクロを追加する機能も提供し、それによって従来のプログラミング言語によって課せられた制約を念頭に置いたり、思考の流れを中断したりする必要性をなくします。
クヌースによれば、[ 8 ] [ 9 ] リテラルプログラミングは、プログラマーにプログラムの背後にある考えを明示的に記述することを強制し、考えの浅い設計上の決定をより明確にするため、より高品質なプログラムを提供する。クヌースはまた、リテラルプログラミングは、追加機能ではなく、プログラム作成中に自分の考えを説明する過程で自然に形成される一流のドキュメントシステムを提供すると主張している。[ 10 ]結果として得られるドキュメントにより、作成者はいつでも自分の思考プロセスを再開でき、他のプログラマーはプログラムの構造をより容易に理解できる。これは、コンパイラによって課せられた順序に従うソースコードがプログラマーに提示され、コードとその関連するコメントからプログラムの背後にある思考プロセスを解読しなければならない従来のドキュメントとは異なる。リテラルプログラミングのメタ言語機能は、思考を促進し、コードをより高い「鳥瞰図」で捉え、心が保持および処理できる概念の数を増やすとも主張されている。この概念が、商用レベルのプログラムのような大規模なプログラミングにも適用可能であることは、TeXコードをリテラル プログラムとして編集することで証明されている。[ 8 ]
クヌースはまた、リテラルプログラミングによってソフトウェアを複数の環境に簡単に移植できると主張し、TeXの実装を例として挙げている。[ 11 ]
リテラルプログラミングは、ソースコードとコメントの両方を含む共通ファイルから生成されるフォーマット済みドキュメント(これは正しくはドキュメント生成と呼ばれます)またはコードに含まれる膨大な量のコメントのみを指すと誤解されることが非常に多いです[12]。これはリテラルプログラミングの逆です。十分に文書化されたコードまたはコードから抽出されたドキュメントはコードの構造に従い、ドキュメントはコードに埋め込まれます。一方、リテラルプログラミングでは、コードがドキュメントに埋め込まれ、コードはドキュメントの構造に従います。
この誤解から、 Perl Plain Old DocumentationやJava Javadocシステムなどのコメント抽出ツールが「リテラルプログラミングツール」であるという主張が生まれています。しかし、これらのツールは自然言語マクロシステムの背後に隠された「抽象概念の網」を実装しておらず、ソースコードの順序を機械が強制する順序から人間の心にとって都合の良い順序に変更する機能も提供していないため、Knuthが意図した意味でのリテラルプログラミングツールとは適切に呼べません。[ 12 ] [ 13 ]
リテラルプログラミングの実装は、次の2つのステップで構成されます。
織り方と絡み方は同じ素材で行われるため、互いに一貫性がある。
リテラルプログラミングの典型的な例として、標準的なUnix ワードカウントプログラムのリテラル実装が挙げられますwc。クヌースは著書『リテラルプログラミング』の第12章で、この例のCWEB版を紹介しました。同じ例は後にnowebリテラルプログラミングツール用に書き直されました。[ 14 ]この例は、リテラルプログラミングの基本要素をよく示しています。
次のwcリテラルプログラム[ 14 ]の抜粋は、自然言語の任意の記述フレーズがリテラルプログラムでマクロを作成するためにどのように使用されるかを示しています。マクロはリテラルプログラミング言語の新しい「演算子」として機能し、コードの塊や他のマクロを隠します。マークアップ表記は、マクロを示す二重山括弧()で構成されています。nowebファイルでは、この記号はドキュメントの塊の開始を示します。この記号は、リテラルプログラミングツールがマクロのウェブを展開し始める最上位のノードである「ルート」を表します。実際には、展開されたソースコードの書き出しは、任意のセクションまたはサブセクション(つまり、等号で指定されたコード片)から行うことができるため、1つのリテラルプログラムファイルには、マシンソースコードを含む複数のファイルが含まれる可能性があります。<<...>>@<<*>><<name of the chunk>>=
wcの目的は、ファイル一覧内の行数、単語数、および/または文字数をカウントすることです。ファイル内の行数は... /詳細な説明/それでは、nowebプログラムwc.nwによって定義されるファイルwc.cの概要を以下に示します。<< * >> = <<インクルードするヘッダーファイル>> <<定義>> <<グローバル変数>> <<関数>> <<メインプログラム>> @標準入出力定義を含める必要があります。フォーマットされた出力を標準出力と標準エラー出力に送信したいからです。<<含めるヘッダーファイル>> = #include < stdio.h> @チャンクの展開は、リテラルプログラムのテキストファイル内の任意の場所で行うことができます。必ずしも囲んでいるチャンク内で配列されている順序である必要はなく、プログラム全体を包括する説明テキストに反映されている論理に従って行われます。
マクロは、標準ドキュメントの「セクション名」とは異なります。リテラルプログラミングのマクロは、実際のコードを隠蔽し、低レベルの機械語演算子、多くの場合、論理演算子(if、whileやなど)の中で使用できますcase。これは、次のwcリテラルプログラムで確認できます。[ 14 ]
カウントを行うこの部分は、実は最も簡単に書けるものの1つです。各文字を見て、それが単語の始まりか終わりかに応じて状態を変更します。<<ファイルのスキャン>>= while ( 1 ) { <<バッファが空の場合は埋める。ファイルの終わりで中断>> c = * ptr ++ ; if ( c > ' ' && c < 0177 ) { /* 可視ASCIIコード */ if ( ! in_word ) { word_count ++ ; in_word = 1 ; } continue ; } if ( c == '\n' ) line_count ++ ; else if ( c != ' ' && c != '\t' ) continue ; in_word = 0 ; /* c は改行、スペース、またはタブ */ } @マクロはコードの塊や他のマクロを表し、トップダウンやボトムアップの「チャンキング」やサブセクションよりも一般的です。ドナルド・クヌースは、このことに気付いたとき、プログラムをさまざまな部分の網として考えるようになったと述べています。[ 1 ]
noweb の知識を持つプログラムでは、マクロの背後にあるチャンクは、その表示順序が自由であることに加えて、で導入されると、後からファイル内の任意の場所で単にを記述してコンテンツを追加するだけで拡張できます。次のスニペットがそれを示しています (はドキュメントフォーマッタによって読みやすさのために追加され、コードには含まれていません)。[ 14 ]<<...>>=<<name of the chunk>>=+
プログラムの開始時に、総計値をゼロに初期化する必要があります。 これらの変数をメイン関数のローカル変数にした場合、この初期化を行う必要があります。 明示的に。ただし、C のグローバル変数は自動的にゼロに設定されます。(あるいは、静的に)ゼロにした 。(分かりますか?) <<グローバル変数>> + =longtot_word_count,tot_line_count,総文字数;/* total number of words, lines, chars */@
リテラルプログラムのドキュメントは、プログラムの作成の一部として作成されます。ソースコードのサイドノートとして提供されるコメントの代わりに、リテラルプログラムには各レベルの概念の説明が含まれており、下位レベルの概念は適切な場所に後回しにされるため、思考の伝達がより容易になります。上記のリテラルプログラムの抜粋は、プログラムの説明とソースコードがどのように織り込まれているかを示しています。このようなアイデアの説明は、文学作品のような思考の流れを生み出します。クヌースは、インタラクティブフィクションゲーム「Colossal Cave Adventure」wcのコードを説明する「小説」を執筆しました。[ 15 ]
最初に公開されたリテラルプログラミング環境は、1981 年に Knuth が自身のTeX組版システム用に導入したWEBです。これは、基盤となるプログラミング言語としてPascalを使用し、ドキュメントの組版には TeX を使用しています。コメント付きの完全な TeX ソースコードは、Knuth の5 巻からなるComputers and Typesettingの巻 B であるTeX: The programに掲載されています。Knuth は、1979 年という早い時期から DOC と呼ばれるリテラルプログラミングシステムを個人的に使用していました。彼はPierre-Arnoul de Marneffeのアイデアに触発されました。[ 28 ] Knuth と Silvio Levy によって書かれた無料のCWEBは、 CとC++用に WEB を適応させたもので、ほとんどのオペレーティングシステムで動作し、TeX およびPDFドキュメントを生成できます。
以下に挙げるように、リテラルプログラミングの概念には他にも様々な実装方法があります。これらのうち比較的新しいものの多くはマクロを持たないため、人間の論理の順序という原則に準拠しておらず、いわば「半リテラル」なツールと言えるでしょう。しかしながら、これらのツールはコードのセル単位の実行を可能にするため、探索的なプログラミングツールに近いと言えます。
その他の便利なツールには以下のようなものがあります。
.hsおよび.lhs)をサポートしています。後者はリテラルHaskellを表します。リテラルスクリプトは完全なLaTeXソーステキストであると同時に、変更を加えることなくコンパイルできます。これは、インタプリタがコード環境内のテキストのみをコンパイルするためです。例: % ここに関数の説明文を記述します: \begin { code } fact 0 = 1 fact ( n + 1 ) = ( n + 1 ) * fact n \end { code } ここにさらにテキストがあります コードは、リチャード・バード式にマークすることもできます。その場合、各行は不等号とスペースで始まり、コードの前後には空白行が入ります。
LaTeXパッケージは、ソースコードを装飾するために使用できる環境をlistings提供します。これを使用して、Haskell 内でシンボルを次のように出力するための環境を定義できます。lstlistingcode
\newenvironment { code }{ \lstlistings [language=Haskell] }{ \endlstlistings }\ begin { code } comp : :( beta- > gamma ) - > ( alpha- > beta ) - > ( alpha- > gamma ) ( g`comp`f ) x = g ( fx ) \ end { code }以下のように設定できます。
トップダウンとボトムアップは対立する手法であり、一方はプログラムの説明に適しており、もう一方はプログラムの作成に適している、という印象を持っていました。しかし、WEBでの経験を積むにつれ、プログラムはツリー構造ではなくウェブ構造として捉えるのが最適であるため、トップダウンとボトムアップのどちらかをきっぱりと選択する必要はないということに気づきました。階層構造は確かに存在しますが、プログラムにおいて最も重要なのは構造的な関係性です。複雑なソフトウェアは、単純な部品とそれらの部品間の単純な関係性から構成されます。プログラマーの役割は、それらの部品と関係性を、トップダウンやボトムアップといった厳密に定められた順序ではなく、人間が理解しやすい順序で記述することです。
—ドナルド・E・クヌース、『リテラル・プログラミング』[1]
WEBのマクロは、最大で1つのパラメータしか持つことができません。これもまた、簡潔さを期すために行ったことです。複数のパラメータを使用するほとんどのケースは、実際には1つのパラメータの場合に簡略化できることに気づいたからです。たとえば、[例省略]のようなものを定義したいとします 。つまり、あるマクロの名前を別のマクロのパラメータとして使用できるということです。
—ドナルド・E・クヌース、『リテラル・プログラミング』[1]
TeX
プロジェクトから生まれた最も重要なものであることは間違いありません
。これまで以上に速く、より確実にプログラムを記述および保守できるようになっただけでなく、1980 年代以来、私の最大の喜びの源の 1 つであり、時には実際に不可欠なものでした。MMIX
メタ シミュレータなどの私の主要なプログラムのいくつかは、私が聞いたことのある他の方法論では記述できませんでした。その複雑さは、私の限られた脳では処理するにはあまりにも困難すぎました。リテラル プログラミングがなければ、この事業全体が惨めに失敗していたでしょう。...
リテラル
プログラミングは、通常のレベルの成果を超えるために必要なものです。
WEBを使う中で私が学んだもう一つの驚くべきことは、従来のプログラミング言語を使っていたせいで、自分が気づいていなかったにもかかわらず、質の低いプログラムを書いていたということでした。当初、WEBは単なるドキュメント作成ツールとして使うつもりでしたが、実際には、他の言語で書いていたプログラムよりも、WEBで書いたプログラムの方が優れていることに気づきました。
—ドナルド・E・クヌース、『リテラル・プログラミング』[1]
このように、WEB言語は、プログラムを「意識の流れ」のような順序で表現することを可能にします。TANGLEは、PASCALコンパイラが要求する形式にすべてを整理することができます。このWEBの特徴はおそらく最大の強みであり、たとえPASCALのみで書かれたプログラムに十分なコメントが付けられていても、WEBで書かれたプログラムは、同じプログラムよりもはるかに読みやすくなります。そして、プログラマーが大規模なプログラムを、心理的に正しい順序で探索すべきウェブとして捉えることができるようになったため、トップダウンかボトムアップかという問題にこだわる必要がなくなったという事実は、おそらく私が最近の経験から学んだ 最大の教訓です。
—ドナルド・E・クヌース、『リテラル・プログラミング』[1]
私が「WEB」という名前を選んだのは、それがまだコンピュータに使われていない数少ない3文字の英単語の一つだったからです。しかし、時が経つにつれ、この名前を非常に気に入ってきました。なぜなら、複雑なソフトウェアは、まさにシンプルな素材を繊細に組み合わせたウェブとして捉えるのが最適だと考えるようになったからです。複雑なシステムを理解するには、そのシンプルな部分を理解し、それらの部分と隣接する部分との間のシンプルな関係を理解する必要があります。プログラムをアイデアのウェブとして表現すれば、その構造的な特性を自然かつ満足のいく形で強調できるのです。
—ドナルド・E・クヌース、『リテラル・プログラミング』[1]