コンテンツにスキップ

「宣言型プログラミング」の版間の差分

出典: フリー百科事典『ウィキペディア(Wikipedia)』
削除された内容 追加された内容
m 説明を短縮する
1行目: 1行目:
'''宣言型プログラミング'''({{lang-en-short|Declarative programming}})は、対象の性質を宣言してプログラムを構成する[[プログラミングパラダイム]]、あるいはそのような性質をもったプログラミングパラダイムの総称である。
{{プログラミングパラダイム}}


総称としての宣言型プログラミングは[[関数型言語|関数型プログラミング]]、[[論理プログラミング]]、[[制約プログラミング]]を含む。これらのプログラミングパラダイムは対象を宣言する性質を共有した特徴として持つ。[[命令型プログラミング]]は[[中央演算処理装置|CPU]]や[[オペレーティングシステム|OS]]への命令列と言えるが、例えば[[LISP]]もコンピュータへの命令列かもしれないが、その理論的基盤は間違いなく[[ラムダ計算]]である。そこでこちらでは、その生い立ちや理論的基盤を考慮して分類することにする。
{{告知|提案|[[Special:Diff/revision/76835741|76835741]] 版までの差し戻し}}


== 概要 ==
{{脚注の不足|date=2021年3月}}
宣言型プログラミングは「対象の性質を宣言してプログラムを構成する」ことで特徴づけられる。すなわち、出力を得る方法ではなく、出力の性質・あるべき状態を記述することを「宣言型」と称する。


一例として宣言型プログラミング言語である[[SQL]]のクエリは「どのようなデータが欲しいか」を宣言しており、[[B木]]の操作などといった「いかにしてデータベースにアクセスするか」という命令・手続きには関与しない。この手法は[[FORTRAN]]、[[C言語]]、[[Java]]等の[[命令型プログラミング]]言語とは全く異なる。命令型では、目的を実現する[[アルゴリズム]]を、その順序に沿う形で記述する。つまり、命令型プログラムでは目的を達成するための方法を「[[プロシージャ|手続き]]」として示すのに対し、宣言型プログラムでは達成すべき目的(出力)を示して、それを実現する手続きは[[システム]](処理系・ランタイム・フレームワークなど)に任せるわけである。
{{複数の問題
| section = 1
| 出典の明記 = 2021年3月3日 (水) 12:25 (UTC)
| 独自研究 = 2021年3月3日 (水) 12:25 (UTC)
}}


総称としての宣言型プログラミングは、[[関数型言語|関数型プログラミング]]、[[論理プログラミング]]、[[制約プログラミング]]の総称である。この立場での「宣言型プログラミング」とは、[[数理論理学]]に基づいて設計されたプログラミング言語のことであり、命令型言語と対立する概念である。関数型言語なら[[ラムダ計算]]や[[コンビネータ論理]]、[[代数学]]などと対応し、論理プログラミングならその式は[[ホーン節]]に対応する。
'''宣言型プログラミング'''({{lang-en-short|''Declarative programming''}})は、総称的に用いられる[[プログラミングパラダイム]]であり、[[プログラミング言語]]および[[プログラミングパラダイム|パラダイム間]]の分類用語として使われることが多い。対義語である[[命令型プログラミング]]との対比概念としてよく用いられる。宣言型は[[プログラミング|プログラミング理論]]のバックボーンである[[数学]]および[[形式論理学]]の性質に準拠したものであり、[[オートマトン|オートマタ理論]]的には[[チューリングマシン|決定性チューリングマシン]]に沿っている。前提と結論、定義と推論、問題と解答、条件と結果、入力と出力などが時系列に関係なく正確に対応して例外なく明示されており、その触媒となる作用、写像、演算などは原則として[[冪等]]であり、それに対する入力要素と出力要素が不可欠になっているという性質を指して宣言的(''declarative'')または平叙的(''declarative'')と言われる。


この2つの定義はある程度オーバーラップしている。特に制約プログラミングでは、解の性質を記述することに注力し、解を求めるためのアルゴリズムは特に指定しないこともある。論理プログラミングにもその傾向がある。とはいっても、制約プログラミング言語や論理プログラミング言語でもアルゴリズムや実装の詳細を記述することは可能ではある(可能であるということは、常にそのようなスタイルでプログラムを書くという意味ではないが)。
概略すると「一つの[[トランザクション]]または一つの[[プログラム (コンピュータ)|プログラム]]実行枠内でのあらゆるオペレーションにおいて、その遷移作用原因になる全情報要素と全環境状態をオペレーションのインプットに内包し、その遷移作用結果になった全情報要素と全環境状態をオペレーションのアウトプットに内包して、遷移作用の法則が不変になっている」というプロセス全般または作業全般を指して宣言的と言われる。遷移作用(''transition function'')の[[冪等|冪等性]]によるインプットとアウトプットの対偶関係は[[参照透過性]]を表わす。サブルーチン処理内容に重点を置いている命令型に対して、宣言型は引数と返り値に焦点を当てているとも言える。


同様に命令型プログラミング言語であっても、プログラムを宣言型のスタイル・パラダイムで書くことは可能である。この場合、宣言的でない詳細をライブラリやフレームワークで[[カプセル化]]するのが一般的である。例えば、単体テストのフレームワークである[[JUnit]]で[[リフレクション (情報工学)|リフレクション]]を使ったスタイルがある。
== 来歴 ==


宣言型のスタイルがよくあらわれる例には[[ドメイン固有言語]] (DSL) がある。また[[冪等#情報工学における冪等|冪等]]性が求められる箇所でもしばしば用いられる。なぜならあるべき状態の宣言は何度宣言しても同じ状態になる(冪等である)からである。
{{複数の問題
| section = 1
| 出典の明記 = 2021年3月3日 (水) 12:25 (UTC)
| 独自研究 = 2021年3月3日 (水) 12:25 (UTC)
}}

宣言型プログラミングは、プログラミング言語のための分類用語としての性格が強い総称的なプログラミングパラダイムなので、どうしてそのような分類が必要になったのかという視点から解釈するのが理解への早道になる。宣言型と命令型という二大分類が定義された背景には、数学や[[形式論理学]]([[数理論理学]])をバックボーンにしたコンピュータ原理とプログラミング言語理論の成立過程がある。あらゆる問題への解法において、数学や[[形式論理学]]の性質を引き継いでいる従来の方式が宣言型であり、[[計算機科学]]が持つようになった特有の方式が命令型である。宣言型は問題と解答の二者限定の平叙な関係の計算であるのに対して、その関係に状態(''state'')というものが加えられた計算の方は命令型となった。”状態”は問題内で宣言されていない潜在要素であり、命令型の計算は同じ問題でもその時の”状態”によって解答が変化した。計算過程による”状態”の変動とそれによる後続計算への影響は[[副作用 (プログラム)|副作用]]と呼ばれる。”状態”の影響が無い平叙な計算と、”状態”に影響される手続き的な計算はコンピュータ計算性質の根本的な分かれ目になったので、前者の宣言型と後者の命令型というプログラミング理論上の二大分類が生まれた。

[[オートマトン|オートマタ理論]]的には、計算は遷移関数(''transition function'')、問題は入力値、解答は出力値、状態は遷移関数の[[非決定性チューリングマシン|非決定性]]に読み替えられる。プログラム的には、計算はサブルーチン、問題は引数、解答は返り値、状態はサブルーチン内外の静的メモリデータに読み替えられる。状態による計算の複雑性の拡充は、[[ノイマン型]]のコンピュータ機構に適したものだったので[[機械語]]と[[低水準言語]]([[アセンブリ言語|アセンブラ]])はその必要性から命令型で構築された。また最初期の[[高水準言語]]([[FORTRAN]]、[[COBOL]]、[[ALGOL]])も[[ノイマン型]]の性質に適した命令型になった。1950年代半ばからの高水準言語の普及につれて、命令型が利点的に拡充した計算の複雑性が今度は問題として挙げられるようになり、1960年代になると数学への原点回帰とも言える宣言型がその解決策として注目され始めた。また[[並行計算]]と宣言型の適性も認識され始めた。1970年代になると宣言型は非ノイマン型コンピュータ構築のためのパラダイムとしても重視されるようになった。

1960年代から[[メインフレーム]]上の[[並行計算]][[データフロープログラミング|データフロープログラム]]が普及しそのための[[低水準言語]]はより平叙的な性質を示していた。また[[述語論理]]を基礎にした[[論理プログラミング]]の研究も始まりその中で実装された数々の言語もより平叙的な性質を持っていたが、1969年稼働の「[[Planner]]」は手続き的性質を備えていた。

== 特徴 ==

{{複数の問題
| section = 1
| 出典の明記 = 2021年3月3日 (水) 12:25 (UTC)
| 独自研究 = 2021年3月3日 (水) 12:25 (UTC)
}}

宣言型プログラミングとは端的に述べると、あらゆる遷移関数(''transition function'')において、状態遷移の原因になるあらゆる情報要素とあらゆる環境情報を遷移関数の引数に収納しており、状態遷移の結果になったあらゆる情報要素とあらゆる環境情報が遷移関数の返り値に収納されており、それら引数と返り値と遷移関数の整合性を維持するために、同じ引数に対する遷移関数の処理内容と返り値の一定化が保証されているというプロセス全般の構築を意味している。これらの仕様は主に[[参照透過性]]というプログラム概念に結び付けられている。これらの仕様を実現するための実装スタイルを箇条書きすると大抵は以下のようなものになる。

* '''関数'''へのパラメータ引数に状態遷移の原因になるあらゆる情報要素と環境要素が内包されており、同関数からのリターン値に状態遷移の結果になったあらゆる情報要素と環境要素が内包されている。
* 同じパラメータ引数に対する関数の処理内容は常に同一であり、そのリターン値も常に同一である。
* 関数の実行には原則的にパラメータ引数の入力を必要とする。入力の無い関数は上述の状態と副作用に依存した稼働方式になるからである。
* 実行された関数は原則的にリターン値の出力を要求される。出力の空白は次の関数への入力の喪失を意味するのでプロセス停止に繋がる。
*'''式'''をプログラムの基本単位とする。式は関数または演算子をノードにした入力と出力の連鎖体であり、式自体が最終出力値と同義になる。式は初期入力値を与えられて計算実行される。この計算実行は評価と呼ばれる。初期入力値は引数と呼ばれる。最終出力値は評価値と呼ばれる。
*初期入力値を与えられた式はその計算実行を保留する事もできる。その保留状態の式の任意時の計算実行は'''遅延評価'''と呼ばれる。
*保留状態の式を値として他の式の初期入力値にする事もできる。これは'''名前渡し'''と呼ばれる。保留状態の式は'''継続'''とも呼ばれる。
*数学上の性質から変数は再代入されない。この視点による変数への初期代入は変数への値の束縛と呼ばれる。この仕組みは'''束縛変数'''と呼ばれる。式の引数も束縛変数である。再代入禁止は'''不変性'''と言い換えられる。
*束縛変数に対する'''自由変数'''という概念がある。自由変数は(A)未束縛状態の変数、(B)式内で引数以外が束縛されている変数、(C)式内で再代入可能になっている変数など複数の意味がある。(A)はパターンマッチングで大きな意味を持つ。
宣言型プログラミングとは上述の関数の性質および式、遅延評価、名前渡し、継続、束縛変数、不変性、自由変数といった要点の用法に専念しているプログラミングである。別の言い方をすると命令型プログラミングでも上述の関数の性質と要点の用法に専念すれば、それは自ずと宣言型プログラミングになる。パラダイム間でこれらの性質を特に受け継いでいるのが、[[関数型プログラミング]]、[[論理プログラミング]]、[[データフロープログラミング]]などである。他にも[[制約プログラミング]]はそれだけで独立しているものではないが、[[全称量化子]]と個体の間に横たわるあらゆる中間状態を指した制約という情報要素を扱う性質から、必然的に宣言型における関数の性質と要点の用法に専念されていることが多い。関数は[[存在量化子]]と同義であり、制約も関数とは異なる形態の[[存在量化子]]なので、後者を扱うための前者は[[参照透過性|参照透過]]である方が都合がよいからである。


== 利点 ==
== 利点 ==
62行目: 28行目:


注意点として、状態は分離されているのであり、状態が消滅したわけではない。宣言型プログラミングの場合、light変数にてあるべきライトの状態 "ON"/"OFF" を保持しておき、現在の時刻に基づいてlight変数を切り替え、それが「廊下の電気は{light}である」という宣言に反映されて実際に廊下の電気がONになるというような形になる。light変数という状態は存在しており、これが宣言部分と分離され、宣言部分は最新のlight変数が示す今の電気があるべき状態のみを反映した(過去の電気状態履歴とは無関係な)形になっている<ref>前回のViewの状態に依存せずに、最終的に描画されるViewを宣言的に記述できる [https://speakerdeck.com/sonatard/xuan-yan-de-ui?slide=37 sonatard. (2019) 宣言的UI. p.37]</ref>。命令的プログラミングで問題となった予測の困難さは、light変数の履歴予測の困難さに分離されている。light変数を誰がいつ操作したかは依然として追跡の難しい問題であるが、宣言部分が分離されたことで問題の所在が限局したものになっている。
注意点として、状態は分離されているのであり、状態が消滅したわけではない。宣言型プログラミングの場合、light変数にてあるべきライトの状態 "ON"/"OFF" を保持しておき、現在の時刻に基づいてlight変数を切り替え、それが「廊下の電気は{light}である」という宣言に反映されて実際に廊下の電気がONになるというような形になる。light変数という状態は存在しており、これが宣言部分と分離され、宣言部分は最新のlight変数が示す今の電気があるべき状態のみを反映した(過去の電気状態履歴とは無関係な)形になっている<ref>前回のViewの状態に依存せずに、最終的に描画されるViewを宣言的に記述できる [https://speakerdeck.com/sonatard/xuan-yan-de-ui?slide=37 sonatard. (2019) 宣言的UI. p.37]</ref>。命令的プログラミングで問題となった予測の困難さは、light変数の履歴予測の困難さに分離されている。light変数を誰がいつ操作したかは依然として追跡の難しい問題であるが、宣言部分が分離されたことで問題の所在が限局したものになっている。

==例==
宣言型プログラミング的側面を持つフレームワーク:
*[[JUnit]]

宣言型プログラミングをサポートするドメイン固有言語:

*[[XSL Transformations|XSLT]] は、[[Extensible Markup Language|XML]]文書の変換のためのチューリング完全な宣言型言語
*[[SQL]] は、[[関係データベース]]のクエリのための宣言的要素を持つ。チューリング完全。
*[[:en:TK Solver|TK Solver]]

宣言型プログラミングをサポートする関数型/論理型/制約型のプログラミング言語:
*関数: [[Erlang]]、[[Haskell]]、[[LISP]]
*論理: [[Prolog]]、[[Concurrent Prolog]]、[[Guarded Horn Clauses|GHC]]、[[:en:Mercury_programming_language|Mercury]]
*制約: [[Oz (プログラミング言語)|Oz]]、[[Constraint Handling Rules]]

利用される局面

* {{節リンク|グラフィカルユーザインタフェース|宣言的UI}}


== 脚注 ==
== 脚注 ==
76行目: 61行目:
== 関連項目 ==
== 関連項目 ==
*[[ドメイン固有言語]]
*[[ドメイン固有言語]]
*[[プログラミング (コンピュータ)|プログラミング]]
*[[問い合わせ言語]]
*[[プログラミングパラダイム]]
*[[マークアップ言語]]
**[[命令型プログラミング]]
**[[手続き型プログラミング]]
**[[非手続き型言語]]
*[[コンピュータ言語]]
**[[プログラミング言語]]
***[[宣言型プログラミング|宣言型言語]]
****[[関数型言語]]
****[[論理型言語]]
*****[[制約論理プログラミング言語]]
*****[[並行論理プログラミング言語]]
*****[[並行制約プログラミング言語]]


== 外部リンク ==
== 外部リンク ==
90行目: 86行目:
{{プログラミング言語の関連項目}}
{{プログラミング言語の関連項目}}


{{Normdaten}}
{{DEFAULTSORT:せんけんかたふろくらみんく}}
{{DEFAULTSORT:せんけんかたふろくらみんく}}
[[Category:プログラミングパラダイム]]
[[Category:プログラミングパラダイム]]

2021年3月13日 (土) 15:43時点における版

宣言型プログラミング: Declarative programming)は、対象の性質を宣言してプログラムを構成するプログラミングパラダイム、あるいはそのような性質をもったプログラミングパラダイムの総称である。

総称としての宣言型プログラミングは関数型プログラミング論理プログラミング制約プログラミングを含む。これらのプログラミングパラダイムは対象を宣言する性質を共有した特徴として持つ。命令型プログラミングCPUOSへの命令列と言えるが、例えばLISPもコンピュータへの命令列かもしれないが、その理論的基盤は間違いなくラムダ計算である。そこでこちらでは、その生い立ちや理論的基盤を考慮して分類することにする。

概要

宣言型プログラミングは「対象の性質を宣言してプログラムを構成する」ことで特徴づけられる。すなわち、出力を得る方法ではなく、出力の性質・あるべき状態を記述することを「宣言型」と称する。

一例として宣言型プログラミング言語であるSQLのクエリは「どのようなデータが欲しいか」を宣言しており、B木の操作などといった「いかにしてデータベースにアクセスするか」という命令・手続きには関与しない。この手法はFORTRANC言語Java等の命令型プログラミング言語とは全く異なる。命令型では、目的を実現するアルゴリズムを、その順序に沿う形で記述する。つまり、命令型プログラムでは目的を達成するための方法を「手続き」として示すのに対し、宣言型プログラムでは達成すべき目的(出力)を示して、それを実現する手続きはシステム(処理系・ランタイム・フレームワークなど)に任せるわけである。

総称としての宣言型プログラミングは、関数型プログラミング論理プログラミング制約プログラミングの総称である。この立場での「宣言型プログラミング」とは、数理論理学に基づいて設計されたプログラミング言語のことであり、命令型言語と対立する概念である。関数型言語ならラムダ計算コンビネータ論理代数学などと対応し、論理プログラミングならその式はホーン節に対応する。

この2つの定義はある程度オーバーラップしている。特に制約プログラミングでは、解の性質を記述することに注力し、解を求めるためのアルゴリズムは特に指定しないこともある。論理プログラミングにもその傾向がある。とはいっても、制約プログラミング言語や論理プログラミング言語でもアルゴリズムや実装の詳細を記述することは可能ではある(可能であるということは、常にそのようなスタイルでプログラムを書くという意味ではないが)。

同様に命令型プログラミング言語であっても、プログラムを宣言型のスタイル・パラダイムで書くことは可能である。この場合、宣言的でない詳細をライブラリやフレームワークでカプセル化するのが一般的である。例えば、単体テストのフレームワークであるJUnitリフレクションを使ったスタイルがある。

宣言型のスタイルがよくあらわれる例にはドメイン固有言語 (DSL) がある。また冪等性が求められる箇所でもしばしば用いられる。なぜならあるべき状態の宣言は何度宣言しても同じ状態になる(冪等である)からである。

利点

宣言型プログラミングは以下の利点を持つ[1]

  • 状態の分離: 宣言部分の出力を予測するために状態履歴とそれを起こすコードを探る必要が無くなる

宣言型プログラミングでは宣言部分と状態を分離できる。なぜなら宣言部分ではあるべき状態を宣言するため、その前にどうなっていたかは無関係であるからである。例えば「廊下の電気はONである」と宣言した場合、現在の廊下の電気がONであれOFFであれ、(宣言された)なるべき状態はONであり、現在の状態とは無関係である。すなわち宣言型プログラミングでは時間と共にどう変わるか(=状態)を宣言部分で考える必要がなくなる[2]

もし命令型プログラミングを用いて「廊下のスイッチを押す」という命令をコーディングして廊下の電気を制御した場合、実行後の電気がONかOFFかは現在の値に依存する。ゆえに出力を予測するには状態の履歴を知っている必要がある。そして状態の履歴を知るためには、状態を操作しうる他のコードを把握し、その操作履歴を知る必要がある。ON/OFFの2状態ならまだしも、多数の状態が相互作用する多数のオブジェクトから操作される場合、状態の予測は著しく困難になり、デバッグを含めたプログラミングが難しくなりうる。一方で宣言型プログラミングの場合、宣言部分は状態履歴を必要としないため、宣言部分の出力は常に明確である。

注意点として、状態は分離されているのであり、状態が消滅したわけではない。宣言型プログラミングの場合、light変数にてあるべきライトの状態 "ON"/"OFF" を保持しておき、現在の時刻に基づいてlight変数を切り替え、それが「廊下の電気は{light}である」という宣言に反映されて実際に廊下の電気がONになるというような形になる。light変数という状態は存在しており、これが宣言部分と分離され、宣言部分は最新のlight変数が示す今の電気があるべき状態のみを反映した(過去の電気状態履歴とは無関係な)形になっている[3]。命令的プログラミングで問題となった予測の困難さは、light変数の履歴予測の困難さに分離されている。light変数を誰がいつ操作したかは依然として追跡の難しい問題であるが、宣言部分が分離されたことで問題の所在が限局したものになっている。

宣言型プログラミング的側面を持つフレームワーク:

宣言型プログラミングをサポートするドメイン固有言語:

宣言型プログラミングをサポートする関数型/論理型/制約型のプログラミング言語:

利用される局面

脚注

  1. ^ 時間軸と何が起きたかを意識せずに宣言的に記述できる sonatard. (2019) 宣言的UI. p.37
  2. ^ Here is the critical thing. We no longer need to think about how our UI changes over time. What happens is, when we get in the data, we show what it should look like. We show what the next state is. And then framework controls how to get from one state into the other. And so now we no longer need to think about it. And that's the critical piece. Leland Richardson (2019-10-24) "Understanding Compose (Android Dev Summit '19)"
  3. ^ 前回のViewの状態に依存せずに、最終的に描画されるViewを宣言的に記述できる sonatard. (2019) 宣言的UI. p.37

参考文献

関連項目

外部リンク