コンテンツにスキップ

英文维基 | 中文维基 | 日文维基 | 草榴社区

「メタプログラミング」の版間の差分

出典: フリー百科事典『ウィキペディア(Wikipedia)』
削除された内容 追加された内容
編集の要約なし
G000001 (会話 | 投稿記録)
m LISP、LispからLispへ統一。言語仕様からの逸脱の可能性の言及について調整
 
(7人の利用者による、間の13版が非表示)
1行目: 1行目:
'''メタプログラミング''' ({{Lang-en|metaprogramming}}) {{Efn|"meta-"は「高次」、「超」を表す接頭辞。}}とは[[プログラミング (コンピュータ)|プログラミング]]技法の一種で、一般に「[[プログラム (コンピュータ)|プログラム]]を記述するプログラム」を書くこと、またはそのプログラムを指す{{Sfn|あんどうやすし|2020|p=343}}。対象[[プログラミング言語|言語]]に埋め込まれた[[マクロ言語]]によって行われることもある。
[[ファイル:Atom classes.svg|代替文=|境界|右|フレームなし|215x215ピクセル]]
{{プログラミング・パラダイム}}

'''メタプログラミング'''(''Metaprogramming'')とは、自己反映性のプログラムロジックを操作して、コードまたはデータ定義情報の変容による再帰的かつ帰納的なプログラムの自己修正を表現するためのプログラミング技法である。そのプログラムロジックは[[形而上学|形而上的]]要素になぞらえられて実装面では[[メタデータ]]と呼ばれる。プログラムの自己修正はランタイム時とコンパイル時に大別される。ランタイム時の方はプログラム開始時の動作制約を越えた実行プロセスの最適化を目的にしており[[機械学習]]にも似た性質を持つ。コンパイル時の方は[[ソースコード]]の記述量削減と[[オブジェクトコード]]の最適化を目的にしている。ランタイム時メタの実装方式には[[動的型付け]]向けのメタオブジェクトと[[静的型付け]]向けの[[リフレクション (情報工学)|リフレクション]]がある。コンパイル時メタの実装方式には[[マクロ (コンピュータ用語)|マクロ]]と[[テンプレートメタプログラミング]]がある。[[自動プログラミング]]、{{仮リンク|属性指向プログラミング|en|Attribute-oriented programming|label=}}{{仮リンク|多段階プログラミング|en|Multi-stage programming|label=}}といったスタイルも存在する。メタプログラミングの原点は「[[LISP]]」であり[[人工知能]]研究とも関係性がある。


== 概要 ==
== 概要 ==
一般に、'''[[スクリプト言語]]'''はメタプログラミングが得意だとされている。'''[[コンパイル型言語]]'''は実行前に[[ソースコード]]を[[コンパイラ|一括で変換]]するという特性上、[[インタプリタ|翻訳と実行]]を繰り返すスクリプト言語よりも実行時の割り込みや変換の自由度が低い{{Sfn|あんどうやすし|2020|pp=343-344}}。
代表的なメタプログラミングの例は[[LISP]]のマクロである。LISPではデータ、コードが全て[[S式]]で表現されるが、マクロによりS式が言語処理系に解釈される前に別なS式へと変換することができる。これにより例えば、

(defstruct point (x 0) (y 0))
代表的なメタプログラミングの例は[[Lisp]]のマクロである。Lispはデータ、コードが全て[[S式]]で表現されるが、マクロによりS式が言語処理系に解釈される前に別なS式へと変換することができる。これにより例えば、<syntaxhighlight lang="lisp">
という記述から
(defstruct point (x 0) (y 0))
</syntaxhighlight>という記述から
* 構造体定義 point型
* 構造体定義 point型
* コンストラクタ make-point (省略時の初期値は0, 0)
* コンストラクタ make-point (省略時の初期値は0, 0)
15行目: 14行目:
が自動的に生成される。
が自動的に生成される。


これがメタプログラミングと呼ばれるのは、「自動生成が言語組み込みの機能ではなくLISPのマクロによって記述されており、必要なら同様の機構をプログラマが定義できる」ためである。これは事実上言語文法の拡張に等しく、非常に強力なプログラム能力を得ることになる。反面、マクロは本来文法を逸脱した字句の置き換えであるため、コードが「記述どおりでない」動作を行うことを意味している。そのため一般に必要でないメタプログラミングは避けられるべきとされる。
これがメタプログラミングと呼ばれるのは、「自動生成が言語組み込みの機能ではなくLispのマクロによって記述されており、必要なら同様の機構をプログラマが定義できる」ためである。これは事実上言語文法の拡張に等しく、非常に強力なプログラム能力を得ることになる。反面、マクロは任意の字句の置き換えが可能であるため、展開されたコードが言語の文法から逸脱する可能性があることを意味している。そのため一般に必要でないメタプログラミングは避けられるべきとされる。


たとえば、文字列を整形して出力するformat関数
たとえば、文字列を整形して出力するformat関数<syntaxhighlight lang="lisp">
(format t "hello,world")
(format t "hello,world")
を用いた例<ref>Peter Siebel: Practical Common Lisp 第三章の8から引用</ref>を紹介する。LispのS式がLispフォームになるためには、「S式の最初の要素は(関数、マクロ、特殊フォーム)のいずれかではならない。」しかし、
</syntaxhighlight>を用いた例<ref>{{Cite web |url=https://archive.org/details/practical-common-lisp_seibel/page/n1/mode/2up?view=theater |title=Practical Common Lisp |access-date=2023-12-11 |publisher=Internet Archive |last=Seibel |first=Peter |date=2005-04-11 |page=95}}</ref>を紹介する。LispのS式がLispフォームになるためには、「S式の最初の要素は(関数、マクロ、特殊フォーム)のいずれかではならない。」しかし、<syntaxhighlight lang="lisp">
(defmacro backwards (expr) (reverse expr))
(defmacro backwards (expr) (reverse expr))
を定義すると、以下のように書ける:
</syntaxhighlight>を定義すると、以下のように書ける:<syntaxhighlight lang="lisp">
(backwards ("hello,world" t format))
(backwards ("hello,world" t format))
このことは、Lispのマクロが、'''上のかぎ括弧「」で括った言語仕様を変更し、独自の文法を作り上げた'''とも考えられる。しかし、この文法は、通常のLispにおいて期待されるような構成をしていない「記述どおりでない動作を行うプログラム」の一例であり、コードの可読性を損なう恐れのある不必要なメタプログラミングである。
</syntaxhighlight>このことは、Lispのマクロが、'''上のかぎ括弧「」で括った言語仕様を変更し、独自の文法を作り上げた'''とも考えられる。しかし、この文法は、通常のLispにおいて期待されるような構成をしていない「記述どおりでない動作を行うプログラム」の一例であり、コードの可読性を損なう恐れのある不必要なメタプログラミングである。


メタプログラミングの他の例としては[[C++]]における「[[テンプレートメタプログラミング]]」などが挙げられる。
メタプログラミングの他の例としては[[C++]]における「[[テンプレートメタプログラミング]]」などが挙げられる。

== 危険性 ==
ただ、メタプログラミングが強力な手段である以上、それに伴う[[危険性]]も理解しておかねばならない。

次は[[JavaScript]]におけるメタプログラミングの例である。<syntaxhighlight lang="javascript" line="1">
const add = new Function(..."xy", "return x + y");

add(2, 3); // => 5
</syntaxhighlight>この例では、[[文字列]]から[[サブルーチン|関数]]<code>add</code>を生成したうえで、その関数を利用して計算を行っている{{Efn|ただの例であって、推奨されない書き方である点に十分に留意}}。

ただ、このような野放図な使い方をすると、<code>Function</code>[[コンストラクタ]]に与える引数を打ち間違えただけで'''破壊的かつ致命的な結果'''を引き起こす場合がある。

そこでJavaScriptでは、「既存の機能を拡張する」ことに注力した、

* Proxy
* Reflect

というオブジェクトを提供している{{Sfn|あんどうやすし|2020|p=345-346}}。このように、目的ありきの手段として使用することにより、危険性を最小限にまで抑えながら強みを最大化することができる。


== 脚注 ==
== 脚注 ==

=== 出典 ===
<references/>
<references/>

=== 註釈 ===
{{Notelist}}

== 参考文献 ==

* {{Citebook|和書 |title=ハンズオンJavaScript |date=2020-11-13 |year=2020 |publisher=オライリー・ジャパン |ref=harv |author=あんどうやすし |chapter=メタプログラミングを学ぶ |isbn=978-4-87311-922-9 |edition=初版 |location=東京}}


== 関連項目 ==
== 関連項目 ==
* [[Common Lisp]]
* [[Scheme]]
* [[LISP]]
* [[LISP]]
* [[REBOL]]
* [[REBOL]]
* [[クワイン (プログラミング)]]
* [[クワイン (プログラミング)]]
* [[ドメイン固有言語]] - メタプログラミングにより構築することもできる。
* [[部分評価]]
* [[部分評価]]
{{プログラミング言語の関連項目}}
* [[ドメイン固有言語]] - メタプログラミングにより構築することもできる。


{{メタ}}
[[Category:プログラミング|めたふろくらみんく]]
[[Category:プログラミング|めたふろくらみんく]]
[[Category:プログラミングパラダイム|めたふろくらみんく]]
[[Category:プログラミングパラダイム|めたふろくらみんく]]

2024年1月13日 (土) 02:08時点における最新版

メタプログラミング (英語: metaprogramming) [注釈 1]とはプログラミング技法の一種で、一般に「プログラムを記述するプログラム」を書くこと、またはそのプログラムを指す[1]。対象言語に埋め込まれたマクロ言語によって行われることもある。

概要

[編集]

一般に、スクリプト言語はメタプログラミングが得意だとされている。コンパイル型言語は実行前にソースコード一括で変換するという特性上、翻訳と実行を繰り返すスクリプト言語よりも実行時の割り込みや変換の自由度が低い[2]

代表的なメタプログラミングの例はLispのマクロである。Lispはデータ、コードが全てS式で表現されるが、マクロによりS式が言語処理系に解釈される前に別なS式へと変換することができる。これにより例えば、

(defstruct point (x 0) (y 0))

という記述から

  • 構造体定義 point型
  • コンストラクタ make-point (省略時の初期値は0, 0)
  • アクセサ point-x point-y
  • 複製 copy-point
  • 述語 point-p

が自動的に生成される。

これがメタプログラミングと呼ばれるのは、「自動生成が言語組み込みの機能ではなくLispのマクロによって記述されており、必要なら同様の機構をプログラマが定義できる」ためである。これは事実上言語文法の拡張に等しく、非常に強力なプログラム能力を得ることになる。反面、マクロは任意の字句の置き換えが可能であるため、展開されたコードが言語の文法から逸脱する可能性があることを意味している。そのため一般に必要でないメタプログラミングは避けられるべきとされる。

たとえば、文字列を整形して出力するformat関数

(format t "hello,world")

を用いた例[3]を紹介する。LispのS式がLispフォームになるためには、「S式の最初の要素は(関数、マクロ、特殊フォーム)のいずれかではならない。」しかし、

(defmacro backwards (expr) (reverse expr))

を定義すると、以下のように書ける:

(backwards ("hello,world" t format))

このことは、Lispのマクロが、上のかぎ括弧「」で括った言語仕様を変更し、独自の文法を作り上げたとも考えられる。しかし、この文法は、通常のLispにおいて期待されるような構成をしていない「記述どおりでない動作を行うプログラム」の一例であり、コードの可読性を損なう恐れのある不必要なメタプログラミングである。

メタプログラミングの他の例としてはC++における「テンプレートメタプログラミング」などが挙げられる。

危険性

[編集]

ただ、メタプログラミングが強力な手段である以上、それに伴う危険性も理解しておかねばならない。

次はJavaScriptにおけるメタプログラミングの例である。

const add = new Function(..."xy", "return x + y");

add(2, 3); // => 5

この例では、文字列から関数addを生成したうえで、その関数を利用して計算を行っている[注釈 2]

ただ、このような野放図な使い方をすると、Functionコンストラクタに与える引数を打ち間違えただけで破壊的かつ致命的な結果を引き起こす場合がある。

そこでJavaScriptでは、「既存の機能を拡張する」ことに注力した、

  • Proxy
  • Reflect

というオブジェクトを提供している[4]。このように、目的ありきの手段として使用することにより、危険性を最小限にまで抑えながら強みを最大化することができる。

脚注

[編集]

出典

[編集]
  1. ^ あんどうやすし 2020, p. 343.
  2. ^ あんどうやすし 2020, pp. 343–344.
  3. ^ Seibel, Peter (2005年4月11日). “Practical Common Lisp”. Internet Archive. p. 95. 2023年12月11日閲覧。
  4. ^ あんどうやすし 2020, p. 345-346.

註釈

[編集]
  1. ^ "meta-"は「高次」、「超」を表す接頭辞。
  2. ^ ただの例であって、推奨されない書き方である点に十分に留意

参考文献

[編集]
  • あんどうやすし「メタプログラミングを学ぶ」『ハンズオンJavaScript』(初版)オライリー・ジャパン、東京、2020年11月13日。ISBN 978-4-87311-922-9 

関連項目

[編集]