「動的プログラミング言語」の版間の差分
2021-09-24T17:40:19(UTC)版へ差し戻し: 動的言語とインタプリタ、ランタイム、Lispのeval、継続、の各種の説明の出典がなくかつ一般的でない独創的な説明であるため、手動巻き戻しをします。 タグ: 手動差し戻し 2017年版ソースエディター |
「Lispのeval、継続、の各種の説明」は昨年以前の文章をそのまま残したものです(分散しているのをまとめただけ)それを問題視しながら、それの記載版に巻き戻すことを良しとする矛盾した編集はお止めください。 タグ: 差し戻し済み ビジュアルエディター |
||
1行目: | 1行目: | ||
{{プログラミング・パラダイム}} |
|||
'''動的プログラミング言語'''({{lang-en-short|dynamic programming language}})は、コンピュータ・[[プログラミング言語]]において、一般に[[コンパイラ|コンパイル]]などの準備段階に済まされることが多いことを、準備時ではなく実行時に行うプログラミング言語処理系(の言語)である。本来は実装(処理系)のことを指すべきであるが、一般にその言語を指して議論されることが多い。もっぱら[[高水準言語]]が多い。'''動的言語'''({{lang-en-short|dynamic language}})とも。例えば、[[型システム]]による型チェックや、値の[[型変換]]、[[束縛 (情報工学)#名前束縛|名前束縛]]などを、コンパイルなどの実行準備時ではなく実行時に行う。そういった「動的さ」により、[[ソースコード|コード]]の追加や[[オブジェクト (プログラミング)|オブジェクト]]や定義の拡張や[[型システム]]の変更によるプログラムの拡張、といったことが行いやすい、ということが利点とされる。これらの動作は静的な処理系でも手間はかかるがエミュレート可能である(例えばJavaのJDK/JREでも、[[Javaクラスローダー|クラスローダー]]を活用すれば可能である)。一方、動的言語ではそういったことが、直接的にサポートされる。 |
|||
'''動的プログラミング言語'''({{lang-en-short|dynamic programming language}})は、[[高水準言語]]の分類であり、対義語である静的プログラミング言語が[[コンパイラ|コンパイル]]時に決定して済ませている作業(オペレーション)の多くを、[[コンパイラ|コンパイル]]時ではなく実行時(ランタイム)に決定するという方針を取っている言語である。[[インタプリタ]]言語では各行の解釈で、ランタイム決定されるオペレーションが多いものを指して動的プログラミングとしている。[[動的型付け]]を採用していることが多いが、全てではない。 |
|||
ランタイムで決定されるオペレーションとは、[[データ型|型]]のキャスト、[[データ]]のバインディング、[[プログラムコード|コード]]のディスパッチ、{{仮リンク|Symbol (プログラミング)|en|Symbol (programming)|label=シンボル}}の評価、[[式 (プログラミング)|式]]の評価、[[オブジェクト (プログラミング)|オブジェクト]]の修正拡張、[[メタデータ]]の変更、[[型システム]]の変更、[[モジュール]]の追加、[[ソフトウェアコンポーネント|コンポーネント]]の注入、ランタイムコードの生成など多岐に渡っている。 |
|||
動的言語と[[動的型付け]]は同じ概念ではないし、全ての動的言語が必ずしも動的型付き言語というわけではない。たとえば[[Smalltalk]]環境の一つである{{仮リンク|Strongtalk|en|Strongtalk}}やGradualtalkは動的な言語にも拘わらず静的型検査が可能となっている。しかし多くの動的言語は動的型付き言語である。 |
|||
これらは静的プログラミング言語でも可能にされていることがあるが、大抵は複雑化していてパフォーマンスコストも大きくなりがちである。これらを直接サポートしている動的プログラミング言語は、この面で大きなアドバンテージがある。このテーマでは[[スクリプト言語]]がしばしば引き合いに出される。動的プログラミングを初めて実装した言語は[[LISP]]とされている。 |
|||
== 定義の限界と曖昧さ == |
|||
動的言語の定義は、「コンパイル」と「実行時」の区別だけでなく、「コード」と「データ」の区別も関わってくるため、非常にあいまいである。[[仮想機械]]や[[実行時コンパイラ]]など、[[機械語]]に何らかの抽象化を施し、機械語を実行時に生成する言語処理系は多い。一般に、ある言語が動的であるとは、その言語の能力を明確に表しているというよりも、動的な機能の使い易さを指しているといえる。 |
|||
== 動的プロセスの種類 == |
|||
== 実装 == |
|||
===Eval=== |
|||
動的プログラミングの概念を密接な関連のある機構がいくつか存在する。それらは必ずしも動的言語として必須とは言えないが、動的言語と呼ばれるものに広く採用されているのも確かである。 |
|||
==={{lang|en|eval}}=== |
|||
{{読み仮名|{{lang|en|[[eval]]}}|イーバル}}とは、{{lang|en|[[LISP]]}}で導入された用語であり、[[S式]]と呼ばれるデータ構造で表現される命令列を実行するプロセスを指している。今日では、{{lang|en|eval}} と言えばテキストなど機械語以外のデータで表されたプログラムを実行する何らかの機構やプロセスを指す。多くの言語では({{lang|en|LISP}}とは異なり)プログラムテキストを読むこととそれを内部表現に変換すること、さらには内部表現から実際の動作に変換することを区別しないため、新たなプログラムテキストの評価はそういった言語の一般的性質である。それらの言語で、プログラムの実行プロセスが {{lang|en|eval}} に他ならない場合、これを[[インタプリタ]]言語と呼ぶ。 |
{{読み仮名|{{lang|en|[[eval]]}}|イーバル}}とは、{{lang|en|[[LISP]]}}で導入された用語であり、[[S式]]と呼ばれるデータ構造で表現される命令列を実行するプロセスを指している。今日では、{{lang|en|eval}} と言えばテキストなど機械語以外のデータで表されたプログラムを実行する何らかの機構やプロセスを指す。多くの言語では({{lang|en|LISP}}とは異なり)プログラムテキストを読むこととそれを内部表現に変換すること、さらには内部表現から実際の動作に変換することを区別しないため、新たなプログラムテキストの評価はそういった言語の一般的性質である。それらの言語で、プログラムの実行プロセスが {{lang|en|eval}} に他ならない場合、これを[[インタプリタ]]言語と呼ぶ。 |
||
==== 高階関数 ==== |
|||
{{仮リンク|エリック・マイヤー|en|Erik Meijer (computer scientist)}}とピーター・ドレイトンは、実行時に実行コードをロード可能な任意の言語は(たとえ、そのコードがDLLの機械語コードだとしても)、一種の {{lang|en|eval}} 機能を備えていると言えるとした。彼らは[[高階関数]]が動的プログラミングの本質であるとし、「{{lang|en|eval}} は高階関数の代用品にすぎない」とした<ref>{{cite web | url=http://pico.vub.ac.be/~wdmeuter/RDL04/papers/Meijer.pdf | title=Static Typing Where Possible, Dynamic Typing When Needed: The End of the Cold War Between Programming Languages | author=Meijer, Erik and Peter Drayton | year=2005 | publisher=[[マイクロソフト|Microsoft]] Corporation | accessdate = 2008年1月18日}}</ref>。 |
{{仮リンク|エリック・マイヤー|en|Erik Meijer (computer scientist)}}とピーター・ドレイトンは、実行時に実行コードをロード可能な任意の言語は(たとえ、そのコードがDLLの機械語コードだとしても)、一種の {{lang|en|eval}} 機能を備えていると言えるとした。彼らは[[高階関数]]が動的プログラミングの本質であるとし、「{{lang|en|eval}} は高階関数の代用品にすぎない」とした<ref>{{cite web | url=http://pico.vub.ac.be/~wdmeuter/RDL04/papers/Meijer.pdf | title=Static Typing Where Possible, Dynamic Typing When Needed: The End of the Cold War Between Programming Languages | author=Meijer, Erik and Peter Drayton | year=2005 | publisher=[[マイクロソフト|Microsoft]] Corporation | accessdate = 2008年1月18日}}</ref>。 |
||
⚫ | |||
=== オブジェクトシステムや型システムの実行時変更 === |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
=== Typing === |
|||
Typing(型付け)は、計算対象にするための値の計算適合性(演算適合性)を定義して、それを判定する作業である。静的プログラミングではコンパイル時に定義と判定が行われて、不適合判定ならコンパイルエラーになる。 |
|||
LispやSmalltalkをはじめ幾つかの言語は分岐や反復の専用の制御構文を持たない。無名関数と高階関数の組み合わせによって全てを代用している。<syntaxhighlight lang="smalltalk"> |
|||
動的プログラミングでは、ランタイムの中で値の計算適合性の再定義が可能である。これは[[動的型付け]]と言われる。同様に値が計算対象になる度に判定することが可能であり、これは[[ダックタイピング]]などと言われる。 |
|||
⚫ | |||
Casting(型キャスト)は、値の[[型変換]]の中で、値に何らかの修正を加えないで型変換することを指す用語である。キャストには複数の用法があるが、派生型→基底型変換のアップキャストと、基底型→派生型変換のダウンキャストが多用される。アップキャストは型安全とされるが、ダウンキャストはそうではない。静的なキャストではダウンキャストのチェック不可なので型安全でなくなる。 |
|||
動的なキャストでは、ダウンキャストのランタイムチェック可能で、不適合ならランタイムエラーを発生させるので、一定の型安全性が保証される。 |
|||
=== Binding === |
|||
Binding(束縛)とは、シンボル(変数名・関数名)に、コンテンツ([[データ]]・[[コードブロック]]・[[オブジェクト (プログラミング)|オブジェクト]]・[[モジュール]]・[[ソフトウェアコンポーネント|コンポーネント]])を結合する作業全般を指している。静的プログラミングではコンパイル時に結合関係が決定される。 |
|||
動的プログラミングでは実行時に結合関係が決められて、[[ポリモーフィズム]]などを表現する。 |
|||
=== Dispatch === |
|||
ディスパッチは、シンボルに束縛されている複数の[[コードブロック]]のどれかを選択して、それを実行するという作業を指している。 |
|||
その機構の代表例は[[仮想関数テーブル]]であり、これは呼出し元型名と実行コードブロックのマッピング表を[[メソッド (計算機科学)|メソッド]]名に束縛している。メソッド名と仮想関数テーブルの結合関係は、コンパイル時決定される。仮想関数テーブル上の実行コードブロック選択は、実行時決定される。これは典型的な動的ディスパッチである。 |
|||
なお、束縛とディスパッチが同時遂行されるケースもあり、こちらではメソッド名と仮想関数テーブルの結合関係が、実行時決定される。これは動的バインディングとも解釈される動的ディスパッチになる。 |
|||
動的プロセスからは外れるが、静的ディスパッチもあり、これは[[ジェネリックプログラミング|ジェネリック]]機構を利用して、仮想関数テーブル上の実行コードブロック選択もコンパイル時に決定してしまう作業を指している。 |
|||
=== Message passing === |
|||
⚫ | |||
<syntaxhighlight lang="smalltalk"> |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
</syntaxhighlight> |
|||
⚫ | |||
また、分岐や反復や例外処理などの制御フローもメッセージ式で行われる。無名関数をメッセージとして送ることで、それによる高階関数の表現も可能である。下記はSmalltallkによる例外処理の例である。クラス登録と同じく言語機能による専用構文ではない。<syntaxhighlight lang="smalltalk"> |
|||
[ |
[ |
||
Error signal: '処理失敗'. |
Error signal: '処理失敗'. |
||
35行目: | 57行目: | ||
"例外を捕捉" |
"例外を捕捉" |
||
]. |
]. |
||
</syntaxhighlight> |
|||
</syntaxhighlight>上記はSmalltallkによる例外処理の例である。クラス登録と同じく言語機能による専用構文ではない。 |
|||
=== Alteration === |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
=== |
=== Reflection === |
||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
=== Linking === |
|||
「[[メッセージ転送]]」も参照のこと。 |
|||
[[動的リンク]]や[[Javaクラスローダー|クラスローディング]]などである。 |
|||
=== 関数型プログラミング === |
|||
[[関数型言語|関数型プログラミング]]の概念は多くの動的言語に備わっている。これも LISP を起源としている。 |
|||
⚫ | |||
⚫ | |||
=== イントロスペクション === |
|||
⚫ | |||
=== |
=== Macros === |
||
動的プログラミング言語の中には、コードのイントロスペクションと eval 機能を組み合わせて[[マクロ (コンピュータ用語)|マクロ]]と呼ばれる機能を提供するものもある。[[C言語]]や[[C++]]におけるマクロは、プログラム内の文字列を置換するサブセット的かつ静的な機能でしかない。これに対し動的言語では、マクロはコンパイラ内部へのアクセスを提供し、実行時にも完全なアクセスを提供する。従って、コードの最適化にも関わり、言語の文法や構文を変化させる能力を持っている。 |
動的プログラミング言語の中には、コードのイントロスペクションと eval 機能を組み合わせて[[マクロ (コンピュータ用語)|マクロ]]と呼ばれる機能を提供するものもある。[[C言語]]や[[C++]]におけるマクロは、プログラム内の文字列を置換するサブセット的かつ静的な機能でしかない。これに対し動的言語では、マクロはコンパイラ内部へのアクセスを提供し、実行時にも完全なアクセスを提供する。従って、コードの最適化にも関わり、言語の文法や構文を変化させる能力を持っている。 |
||
== 言語 == |
== 動的言語の一覧 == |
||
<div style="{{column-count|3}}"> |
|||
<div style="float: left; vertical-align: top; white-space: nowrap; margin-right: 1em;"> |
|||
*[[APL]] |
*[[APL]] |
||
*[[Befunge]] |
*[[Befunge]] |
||
76行目: | 94行目: | ||
*[[Forth]] |
*[[Forth]] |
||
*[[Groovy]] |
*[[Groovy]] |
||
</div><div style="float: left; vertical-align: top; white-space: nowrap; margin-right: 1em;"> |
|||
*[[HyperTalk]] |
*[[HyperTalk]] |
||
*[[Io (プログラミング言語)|Io]] |
*[[Io (プログラミング言語)|Io]] |
||
93行目: | 110行目: | ||
*[[REBOL]] |
*[[REBOL]] |
||
*[[Ruby]] |
*[[Ruby]] |
||
</div><div style="float: left; vertical-align: top; white-space: nowrap; margin-right: 1em;"> |
|||
*[[Smalltalk]] |
*[[Smalltalk]] |
||
**[[Bistro]] |
**[[Bistro]] |
||
109行目: | 125行目: | ||
*[[Windows PowerShell]] |
*[[Windows PowerShell]] |
||
*[[xHarbour]] |
*[[xHarbour]] |
||
</div> |
</div> |
||
[[アセンブリ言語]]、[[C言語]]、[[C++]]、初期の [[Java]]、[[FORTRAN]] などは動的プログラミング言語ではない。 |
|||
== 脚注 == |
== 脚注 == |
||
120行目: | 134行目: | ||
{{プログラミング言語の関連項目}} |
{{プログラミング言語の関連項目}} |
||
{{デフォルトソート:とうてきふろくらみんくけんこ}} |
{{デフォルトソート:とうてきふろくらみんくけんこ}} |
||
[[Category:プログラミング言語の分類]] |
[[Category:プログラミング言語の分類]] |
2021年11月24日 (水) 02:35時点における版
プログラミング・パラダイム |
---|
動的プログラミング言語(英: dynamic programming language)は、高水準言語の分類であり、対義語である静的プログラミング言語がコンパイル時に決定して済ませている作業(オペレーション)の多くを、コンパイル時ではなく実行時(ランタイム)に決定するという方針を取っている言語である。インタプリタ言語では各行の解釈で、ランタイム決定されるオペレーションが多いものを指して動的プログラミングとしている。動的型付けを採用していることが多いが、全てではない。
ランタイムで決定されるオペレーションとは、型のキャスト、データのバインディング、コードのディスパッチ、シンボルの評価、式の評価、オブジェクトの修正拡張、メタデータの変更、型システムの変更、モジュールの追加、コンポーネントの注入、ランタイムコードの生成など多岐に渡っている。
これらは静的プログラミング言語でも可能にされていることがあるが、大抵は複雑化していてパフォーマンスコストも大きくなりがちである。これらを直接サポートしている動的プログラミング言語は、この面で大きなアドバンテージがある。このテーマではスクリプト言語がしばしば引き合いに出される。動的プログラミングを初めて実装した言語はLISPとされている。
動的プロセスの種類
Eval
エリック・マイヤーとピーター・ドレイトンは、実行時に実行コードをロード可能な任意の言語は(たとえ、そのコードがDLLの機械語コードだとしても)、一種の eval 機能を備えていると言えるとした。彼らは高階関数が動的プログラミングの本質であるとし、「eval は高階関数の代用品にすぎない」とした[1]。
動的言語における別の機能として継続がある。継続は、再呼び出し可能な実行状態を表している。例えば、構文解析器が中間結果と継続を返し、後で再呼び出しされると、入力の構文解析を再開する。継続はクロージャなどのスコープと複雑に関連している。このため、継続を提供している動的言語は多くはない。
Typing
Typing(型付け)は、計算対象にするための値の計算適合性(演算適合性)を定義して、それを判定する作業である。静的プログラミングではコンパイル時に定義と判定が行われて、不適合判定ならコンパイルエラーになる。
動的プログラミングでは、ランタイムの中で値の計算適合性の再定義が可能である。これは動的型付けと言われる。同様に値が計算対象になる度に判定することが可能であり、これはダックタイピングなどと言われる。
Casting
Casting(型キャスト)は、値の型変換の中で、値に何らかの修正を加えないで型変換することを指す用語である。キャストには複数の用法があるが、派生型→基底型変換のアップキャストと、基底型→派生型変換のダウンキャストが多用される。アップキャストは型安全とされるが、ダウンキャストはそうではない。静的なキャストではダウンキャストのチェック不可なので型安全でなくなる。
動的なキャストでは、ダウンキャストのランタイムチェック可能で、不適合ならランタイムエラーを発生させるので、一定の型安全性が保証される。
Binding
Binding(束縛)とは、シンボル(変数名・関数名)に、コンテンツ(データ・コードブロック・オブジェクト・モジュール・コンポーネント)を結合する作業全般を指している。静的プログラミングではコンパイル時に結合関係が決定される。
動的プログラミングでは実行時に結合関係が決められて、ポリモーフィズムなどを表現する。
Dispatch
ディスパッチは、シンボルに束縛されている複数のコードブロックのどれかを選択して、それを実行するという作業を指している。
その機構の代表例は仮想関数テーブルであり、これは呼出し元型名と実行コードブロックのマッピング表をメソッド名に束縛している。メソッド名と仮想関数テーブルの結合関係は、コンパイル時決定される。仮想関数テーブル上の実行コードブロック選択は、実行時決定される。これは典型的な動的ディスパッチである。
なお、束縛とディスパッチが同時遂行されるケースもあり、こちらではメソッド名と仮想関数テーブルの結合関係が、実行時決定される。これは動的バインディングとも解釈される動的ディスパッチになる。
動的プロセスからは外れるが、静的ディスパッチもあり、これはジェネリック機構を利用して、仮想関数テーブル上の実行コードブロック選択もコンパイル時に決定してしまう作業を指している。
Message passing
Smalltalk系統のオブジェクト指向言語にみられる。一つのメソッドに複数セレクターと紐づけたり、全てのメッセージを受け取るメソッドを定義することで、メッセージを受信するオブジェクトがメッセージと同じセレクターを持つメソッドを備えていなくてもメッセージを受信できる。
"#onClick:を使ったメッセージをopen:メソッドに転送させる。"
FileEventHandler
addSelector: #onClick:
withMethod: FileEventHandler >> #open:.
上記はSmalltalkで既に#open:というセレクターを持っているメソッドに#onClick:というセレクターを追加している。
また、分岐や反復や例外処理などの制御フローもメッセージ式で行われる。無名関数をメッセージとして送ることで、それによる高階関数の表現も可能である。下記はSmalltallkによる例外処理の例である。クラス登録と同じく言語機能による専用構文ではない。
[
Error signal: '処理失敗'.
]
on: Exception
do:
[ :exception |
"例外を捕捉"
].
Alteration
動的言語では、オブジェクトシステムや型システムを実行時に変更できるのが一般的である。これはすなわち、実行時定義に従って新たなオブジェクトを生成したり、既存の型やオブジェクトの合成に基づいて新たなオブジェクトを生成することを意味する。また、継承関係や型の木構造の変更も指していて、既存の型の振る舞いも(特にメソッド呼び出しの観点で)それによって変化する。Smalltalkのクラス登録などが顕著な例である。
Object
subclass: #Some
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Example'.
上記はクラス定義用の専用構文ではなく、Objectというクラスオブジェクトにクラス登録用のメッセージを送っているだけである。実行中に登録しているが削除も実行中に可能である。
Reflection
イントロスペクションは多くの動的言語で見られ、自分自身の構造・コード・型・データなどを解析するプログラムによく使われる。これは総称型やポリモーフィズムの値について型を決定するのと似たようなものである。プログラムのコードをデータとして完全に解析可能な場合もあり、例えば LISP ではプログラムをS式として解析可能である。
Linking
Macros
動的プログラミング言語の中には、コードのイントロスペクションと eval 機能を組み合わせてマクロと呼ばれる機能を提供するものもある。C言語やC++におけるマクロは、プログラム内の文字列を置換するサブセット的かつ静的な機能でしかない。これに対し動的言語では、マクロはコンパイラ内部へのアクセスを提供し、実行時にも完全なアクセスを提供する。従って、コードの最適化にも関わり、言語の文法や構文を変化させる能力を持っている。
動的言語の一覧
脚注
- ^ Meijer, Erik and Peter Drayton (2005年). “Static Typing Where Possible, Dynamic Typing When Needed: The End of the Cold War Between Programming Languages”. Microsoft Corporation. 2008年1月18日閲覧。
外部リンク
- Dynamic Languages[リンク切れ] by David Ascher.