164

Java プラットフォームでの ployglot プログラミングに関するTheServerSide の記事を読んでいました。この記事の一部のコメントでは、メタプログラミングを (おそらくその場で) コードを生成する機能と呼んでいます。

メタプログラミングは、オンザフライでコードを生成する機能ですか、それとも実行時に既存のオブジェクトにメソッドと属性を挿入する機能ですか (Python、Ruby、Groovy などの一部の動的言語が許可するように)。

4

8 に答える 8

129

メタプログラミングとは、プログラムが自分自身を認識したり、自分自身を操作したりできるさまざまな方法を指します。

C# などの言語では、プログラムが自身に関する情報を調べることができるため、リフレクションはメタプログラミングの一種です。たとえば、オブジェクトのすべてのプロパティのリストを返します。

ActionScript などの言語では、実行時に関数を評価して、eval("x" + i) などの新しいプログラムを作成できます。DoSomething() は、i が 1 の場合は x1 というオブジェクトに、i が 2 の場合は x2 というオブジェクトに影響を与えます。

最後に、メタプログラミングのもう 1 つの一般的な形式は、プログラムが自明でない方法で自分自身を変更できる場合です。LISP はこれでよく知られており、約 10 年前に Paul Graham が擁護したものです。私は彼の特定のエッセイのいくつかを調べる必要があります. しかし、その考えは、プログラムがその状態に基づいてプログラムの別の部分を変更するというものです。これにより、今日のほとんどの一般的な言語では非常に困難な、実行時の決定を行うためのある程度の柔軟性が可能になります。

また、単純なアセンブリでプログラミングを行っていた古き良き時代には、実行時に自分自身を変更するプログラムが必要であり、非常に一般的であったことも注目に値します。

Paul Graham のエッセイ"What Made Lisp Different"から:

多くの言語には、マクロと呼ばれるものがあります。しかし、Lisp マクロは独特です。信じられないかもしれませんが、彼らがしていることは括弧に関連しています。Lisp の設計者は、異なるものにするためだけに言語にこれらすべての括弧を入れたわけではありません。Blub プログラマーにとって、Lisp コードは奇妙に見えます。しかし、これらの括弧には理由があります。それらは、Lisp と他の言語との間の根本的な違いの表面的な証拠です。

Lisp コードは、Lisp データ オブジェクトから作成されます。ソースファイルに文字が含まれており、文字列は言語でサポートされているデータ型の 1 つであるという些細な意味ではありません。Lisp コードは、パーサーによって読み取られた後、トラバース可能なデータ構造で構成されます。

コンパイラがどのように機能するかを理解していれば、実際に起こっていることは、Lisp に奇妙な構文があるというよりも、Lisp に構文がないということです。他の言語が解析されるときにコンパイラ内で生成される解析ツリーにプログラムを記述します。ただし、これらの解析ツリーは、プログラムから完全にアクセスできます。それらを操作するプログラムを作成できます。Lisp では、これらのプログラムはマクロと呼ばれます。プログラムを書くプログラムです。

プログラムを書くプログラム?いつそれをしたいですか?Cobol で考えると、それほど頻繁ではありません。Lisp で考えれば、いつでも。ここで強力なマクロの例を挙げて、そこで言うことができれば便利です! どのようにそのことについて?しかし、私がそうしたとしても、Lisp を知らない人にとっては意味不明に見えるだけです。それが何を意味するのかを理解するために知っておく必要のあるすべてをここで説明する余地はありません。Ansi Common Lisp では、私は物事をできるだけ速く進めようとしましたが、それでも 160 ページまでマクロにたどり着きませんでした。

しかし、説得力のあるある種の議論をすることはできると思います。Viaweb エディターのソース コードは、おそらく 20 ~ 25% のマクロでした。マクロは通常の Lisp 関数よりも書きにくく、必要のないときにマクロを使うのはスタイルが悪いと考えられています。したがって、そのコード内のすべてのマクロは、存在する必要があるため存在します。つまり、このプログラムのコードの少なくとも 20 ~ 25% が、他の言語では簡単にできないことを行っているということです。Blub プログラマーが Lisp の不思議な力に対する私の主張に懐疑的であったとしても、これは彼を興味深くさせるはずです。このコードは、私たち自身の楽しみのために書いたものではありません。私たちは小さな新興企業であり、競合他社との間に技術的な障壁を設けるために、できる限り一生懸命プログラミングを行っていました。

不審な人は、ここになんらかの相関関係があるのではないかと考え始めるかもしれません。私たちのコードの大部分は、他の言語では非常に難しいことを行っていました。結果として得られたソフトウェアは、競合他社のソフトウェアではできなかったことを実行しました。なんらかのつながりがあったのかもしれません。そのスレッドに従うことをお勧めします。松葉杖で足を引きずっているその老人には、目に見える以上のものがあるかもしれません。

于 2009-02-05T05:27:51.510 に答える
81

素晴らしい質問です。現在、あなたの質問に正しく答えている答えがないことを非常に残念に思っています。多分私は助けることができる...

メタプログラミングの定義は非常に単純です。それは、プログラムを操作するプログラムを意味します。

あなたの受け入れられた答えは、自分自身を操作するプログラムを言います。これらは確かにメタプログラムですが、すべてのメタプログラムのサブセットです。

全て:

  • パーサー
  • ドメイン固有言語 (DSL)
  • 組み込みドメイン固有言語 (EDSL)
  • コンパイラ
  • 通訳者
  • 用語リライター
  • 定理証明者

メタプログラムです。したがって、GCC コンパイラはメタプログラム、CPython インタプリタはメタプログラム、Mathematica コンピュータ代数システムはメタプログラム、Coq 定理証明器はメタプログラムなどです。

他の回答では、メタプログラムは他のプログラムを生成するプログラムであると主張しています。これらは確かにメタプログラムですが、すべてのメタプログラムのサブセットです。Fastest Fourier Transform in the West (FFTW) ライブラリは、このようなメタプログラムの例です。ソースコードはほとんどがOCamlで書かれており、特定のマシン向けに最適化された高性能の高速フーリエ変換ルーチンを作成するために組み合わされた C コードのビット (コードレットと呼ばれる) を生成します。そのライブラリは、実際には Matlab で FFT ルーチンを提供するために使用されます。FORTRANの初期の頃から、人々は数十年にわたって数値計算法を生成するプログラムを作成してきました。

メタプログラミングのサポートを統合した最初のプログラミング言語は、1950 年代後半の LIST プロセッサ (LISP) 言語でした。LISP 1.5には、メタプログラミングを容易にする多くの機能が含まれていました。まず、LISP のコア データ型はネストされたリスト、つまり のようなツリーです(a (b c) d)。これは、LISP コードがデータ構造としてネイティブに表現できることを意味します。これはホモイコニシティとして知られています。次に、LISP コードは QUOTE を使用して簡単にデータに変換できます。たとえば、(+ 1 2 3)1+2+3(QUOTE (+ 1 2 3))を追加し、評価時に 1+2+3 を追加する式を作成します。第 3 に、LISP は、ホスト インタープリターまたはコンパイラーを使用して、実行時に生成された LISP コードを含む LISP コードを実行時に評価できるメタ循環エバリュエーターを提供しました。LISP の子孫には、SchemeClojureが含まれます. これらすべての言語で、メタプログラミングは、通常はマクロを使用して自分自身を変更するプログラムの形で最も一般的に見られます。

1970 年代に、Robin Milner はMetaLanguage (ML) を開発しました。これは、 Standard MLOCamlを含むプログラミング言語の ML ファミリに進化し、HaskellF#に大きな影響を与えました。これらの言語を使用すると、他の言語を簡単に表現できます。これらの言語では、メタプログラムは、レクサー、パーサー、インタープリター、およびコンパイラーの形で最も一般的に見られます。

1994 年、Erwin Unruh は、C++ テンプレート システムがチューリング完全であり、コンパイル時に任意のプログラムを実行するために使用できることを発見しましたC++ テンプレート メタプログラミングは、 Blitz++ ライブラリで数値メソッドを生成することを含む、さまざまなことにメタプログラミングを (ab) 使用する、洗われていない大衆にメタプログラミングをもたらしました。

于 2017-02-14T07:59:25.417 に答える
40

まあ、メタプログラミングはプログラミングだけですが、基本的には「コードを書くコードを書く」ことです。

プログラムが独自の構造と動作を観察および変更できる場合、あなたが言及する機能はリフレクションと呼ばれ、メタプログラミングの一種です。

動的に型付けされた言語には、これらの言語の解釈された性質によって可能になった強力なランタイム リフレクション機能があります...

静的型付き言語には、強力なメタプログラミング手法もあります。たとえば、C++テンプレート メタプログラミング...

于 2009-02-05T05:33:25.880 に答える
15

これは私の個人的な意見であり、おそらく最も自由度の高いメタプログラミングの定義です。

私はそれが含まれていると思います:

  1. コンパイル コード生成またはランタイム コード生成 (または両方)
  2. アスペクト指向思考またはアスペクト指向プログラミング
  3. ドライ思考

これらのいずれかを組み合わせて使用​​ することで、そこに到達できると思います。

  1. 反射
  2. DSL (ドメイン固有言語)
  3. 属性 (.NET) または注釈 (Java)
  4. ジェネリック (.NET/Java)
  5. テンプレート (C++)
  6. method_missing (Ruby)
  7. クロージャ / ファースト クラス関数 / デリゲート
  8. AOP - アスペクト指向プログラミング
于 2009-02-05T05:42:41.137 に答える
6

メタプログラミングとは、他のプログラム (またはそれ自体) をデータとして作成または操作するコンピューター プログラムを作成すること、またはコンパイル時に実行される作業の一部を実行時に実行するコンピューター プログラムを作成することです。多くの場合、これにより、プログラマーはすべてのコードを手動で記述する場合と同じ時間でより多くのことを行うことができます。また、プログラムは、再コンパイルせずに新しい状況を効率的に処理する柔軟性が向上します。(ソース。)

基本的には、より多くのコードを出力するコードを作成し、それを実行して何らかの目標を達成することです。これは通常、同じ言語内で (javascript を使用して javascript 文字列を作成してevalから)、別の言語を発行するために (.NET を使用して Windows バッチ ファイルを作成します) 実行されます。

于 2009-02-05T05:21:30.243 に答える
6

メタプログラミングとは、別のプログラムを出力するプログラムを作成することです。これは、Lisp のような言語が本当に得意とすることです。Java のような言語よりも、Ruby、Lisp、Scheme などの実際のマクロ (C++ マクロではなく、マクロが出力するコードを操作できるもの) をサポートする言語で行う方がはるかに簡単です。

1 つの実装は、特定のタスクを達成するためにプログラミング言語を拡張する方法である「ドメイン固有言語」を作成することです。正しく行えば、信じられないほど強力です。Ruby on Rails は、この種のプログラミングの良い例です。

この方法を探求することに興味がある場合は、この主題をカバーする重要な本の 1 つである、コンピューター プログラムの構造と解釈を調べてください。

于 2009-02-05T05:27:47.063 に答える
4

ウィキペディアには、このトピックに関する素晴らしい記事があります。何かをメタプログラミングとして認定するために実行時の変更を行う必要はありません。たとえば、多くの人が C++ テンプレートを使用して、コンパイル時にメタプログラミングを行います。

于 2009-02-05T05:21:30.820 に答える