メタプログラミングとは正確には何ですか?


128

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

その場でコードを生成する機能、または実行時にメソッドと属性を既存のオブジェクトに挿入する機能(メタデータはPython、Ruby、Groovyなどの動的言語で許可されているもの)ですか。


7
あなたがこの回答に興味があるかもしれないstackoverflow.com/questions/2565572/...
ewernli

@ewernli:その答えは実際にはここにあるどの答えよりも優れています!
JD、

回答:


100

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

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

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

最後に、メタプログラミングのもう1つの一般的な形式は、プログラムが自明ではない方法で変化する場合です。LISPはこのことでよく知られており、約10年前にPaul Grahamが擁護したものです。私は彼の具体的なエッセイのいくつかを調べなければならないでしょう。しかし、アイデアは、プログラムがその状態に基づいてプログラムの別の部分を変更するというものです。これにより、現在のほとんどの一般的な言語では非常に難しい、実行時に決定を行うための柔軟性のレベルが可能になります。

まっすぐなアセンブリでプログラミングを行っていた昔の時代には、実行時に自分自身を変更するプログラムが必要であり、非常にありふれたものであったことも注目に値します。

ポールグラハムのエッセイ「Lispの違い」について

多くの言語にはマクロと呼ばれるものがあります。しかし、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%は、他の言語では簡単に実行できないことを実行しています。どんなにブラブプログラマーも、Lispの神秘的な力に対する私の主張について懐疑的であるかもしれません。私たちはこのコードを私たち自身の娯楽のために書いていませんでした。私たちは小さなスタートアップであり、私たちと競合他社との間に技術的な障壁を置くために、できる限りハードにプログラミングしました。

疑わしい人は、ここに何らかの相関関係があるのか​​疑問に思うかもしれません。私たちのコードの大部分は、他の言語では実行するのが非常に難しいことを行っていました。結果として得られたソフトウェアは、競合他社のソフトウェアでは実行できなかったことを実現しました。たぶん、何らかのつながりがあったのでしょう。そのスレッドをフォローすることをお勧めします。老人は松葉杖で歩きながら、目に会う以上のことがあるかもしれません。


6
C ++でのテンプレートのメタプログラミングを忘れないでください。式を実行し、コンパイル時に決定を行い、結果を静的にコンパイルして最終的な実行可能ファイルにする機能。
レミールボー2014年

1
私はショックを受けましたin order to put technical barriers between us and our competitors、そしてこれは正しいです。
Evan Hu

4
自分自身を操作するプログラムは、すべてのメタプログラムのサブセットです。一般にメタプログラミングとは、プログラムを操作するプログラムを意味します。
JD、

55

すばらしい質問です。現在のところ、実際にお客様の質問に正確に回答している回答がないことを大変申し訳ありません。多分私は助けることができます...

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

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

すべて:

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

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

他の回答では、メタプログラムは他のプログラムを生成するプログラムであると主張しています。それらは確かにメタプログラムですが、これらもすべてのメタプログラムのサブセットです。西最速フーリエ変換(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は、標準のMLOCamlを含み、HaskellF#に強い影響を与えたプログラミング言語のMLファミリーに進化したMetaLanguage(ML)を開発しました。これらの言語を使用すると、他の言語を簡単に表現できます。これらの言語では、メタプログラムは最も一般的には、レクサー、パーサー、インタープリター、コンパイラーの形で見られます。

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


33

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

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

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

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


14

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

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

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

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

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

非常に簡潔で思慮深い答え。調査するための良いメニューをくれました。ありがとうございました!
swyx

6

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

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

この方法を探求することに興味がある場合は、この主題を扱った独創的な本の1つである「コンピュータプログラムの構造と解釈」を確認してください。


5

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

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


4

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.