コンテンツにスキップ

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

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

出典: フリー百科事典『ウィキペディア(Wikipedia)』
削除された内容 追加された内容
m Botによる: {{Normdaten}}を追加
編集の要約なし
1行目: 1行目:
'''宣言型プログラミング'''({{lang-en-short|Declarative programming}})は過程ではなく対象を定義してプログラムを構成する[[プログラミングパラダイム]]である<ref name=":0">"what declarative programming is. Intuitively, it is programming by defining the what (the results we want to achieve) without explaining the how (the algorithms, etc., needed to achieve the results). " P. Van Roy and S. Haridi (2001). [[コンピュータプログラミングの概念・技法・モデル|''コンピュータプログラミングの概念・技法・モデル'']]. p.117.</ref>。
{{プログラミング・パラダイム}}'''宣言型プログラミング'''({{lang-en-short|Declarative programming}})は過程(How)ではなく対象(What)を定義してプログラムを構成する[[プログラミングパラダイム]]である<ref name=":0">"what declarative programming is. Intuitively, it is programming by defining the what (the results we want to achieve) without explaining the how (the algorithms, etc., needed to achieve the results). " P. Van Roy and S. Haridi (2001). [[コンピュータプログラミングの概念・技法・モデル|''コンピュータプログラミングの概念・技法・モデル'']]. p.117.</ref>。ここでのWhatとは、[[数学]]や[[形式論理学|形式論理]]([[数理論理学]])における数値・代数・計算式記号を、計算機用解釈で置き換えた入力値・遷移作用・出力値のセットを指す。[[ラムダ計算]]では変数・ラムダ抽象・適用および簡約のコンビネーションになる。プログラムの世界では引数・関数・返り値になってその組み合わせが[[式 (プログラミング)|式]]になり、関数もまた[[自由変数と束縛変数|束縛変数と自由変数]]を内包した式になる。関数は後述の[[参照透過性]]の順守が原則にされているので、たとえ複雑なプロセス記述の関数であっても、数学での計算記号と同等に見なして扱うことが出来る。こうした数学の性質に準拠したプログラミングが宣言型(declarative)と呼ばれており、宣言型のプログラムは[[数学的証明]]に似た[[形式的検証]]が可能になっている。宣言型は、[[計算機科学]]特有の性質である[[副作用 (プログラム)|副作用]]に寛容な[[命令型プログラミング]]の対義概念として扱われることが多く、主にプログラミング言語の分類に用いられる総称的なパラダイム名義でもある。[[オートマトン|オートマタ理論]]的には[[チューリングマシン|決定性チューリングマシン]]に沿っている

「プログラム内のあらゆるオペレーションにおいて、そのインプットに遷移原因になる全情報要素と全環境状態を内包し、そのアウトプットに遷移結果になった全情報要素と全環境状態を内包して、その遷移作用の法則が恒久的不変になっている」といった計算性質のプロセス全般を指して宣言的と言われる。遷移作用(transition function)の[[冪等|冪等性]]によるインプットとアウトプットの対偶関係は[[参照透過性]]と呼ばれるものになる。


== 概要 ==
== 概要 ==

2021年4月13日 (火) 06:17時点における版

宣言型プログラミング: Declarative programming)は、過程(How)ではなく対象(What)を定義してプログラムを構成するプログラミングパラダイムである[1]。ここでのWhatとは、数学形式論理数理論理学)における数値・代数・計算式記号を、計算機用解釈で置き換えた入力値・遷移作用・出力値のセットを指す。ラムダ計算では変数・ラムダ抽象・適用および簡約のコンビネーションになる。プログラムの世界では引数・関数・返り値になってその組み合わせがになり、関数もまた束縛変数と自由変数を内包した式になる。関数は後述の参照透過性の順守が原則にされているので、たとえ複雑なプロセス記述の関数であっても、数学での計算記号と同等に見なして扱うことが出来る。こうした数学の性質に準拠したプログラミングが宣言型(declarative)と呼ばれており、宣言型のプログラムは数学的証明に似た形式的検証が可能になっている。宣言型は、計算機科学特有の性質である副作用に寛容な命令型プログラミングの対義概念として扱われることが多く、主にプログラミング言語の分類に用いられる総称的なパラダイム名義でもある。オートマタ理論的には決定性チューリングマシンに沿っている。

「プログラム内のあらゆるオペレーションにおいて、そのインプットに遷移原因になる全情報要素と全環境状態を内包し、そのアウトプットに遷移結果になった全情報要素と全環境状態を内包して、その遷移作用の法則が恒久的不変になっている」といった計算性質のプロセス全般を指して宣言的と言われる。遷移作用(transition function)の冪等性によるインプットとアウトプットの対偶関係は参照透過性と呼ばれるものになる。

概要

宣言型プログラミングでは対象の定義 =「何(What)を得たいか」を宣言してプログラムを構成し、逆にそれを得る過程・手続き・アルゴリズム =「どうやって(How)得るか」を記述しない[1][2]。すなわち、出力を得る方法ではなく、出力の性質・あるべき状態を記述することが「宣言型」である。

例えば「朝ごはん」をプログラムする。やり方の1つは食べたいもの =「メニュー」を宣言する方法である。もう1つは調理過程 =「レシピ」を記述する方法である。レシピが一切わからなくても結果として作られる朝ごはんを定義することはできるし、逆に何ができるかわからなくてもとにかく1つ1つの調理作業を記述することでも朝ごはんはプログラムできる。宣言型プログラミングは前者すなわちメニューを宣言するスタイル(= プログラミングパラダイム)である。

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

宣言型プログラミングは得るものを宣言する。これに起因した宣言型プログラミングの特徴がある。

  • 参照透過性: 同じ引数ならば常に同じ出力を返す[3](得るもの = 出力を定義するスタイルなので出力は揺るがない)
    • 独立
    • 状態を持たない
    • 決定的

宣言型プログラミングのもつ性質は他の様々なプログラミングパラダイムでも見られる。例えば関数型プログラミング論理プログラミング制約プログラミングが挙げられる。これらは数理論理学に基づいて設計されたプログラミング言語であり、命令型言語と対立する概念である。関数型言語ならラムダ計算コンビネータ論理代数学などと対応し、論理プログラミングならその式はホーン節に対応する。命令型プログラミングCPUOSへの命令列と言えるが、例えばLISPもコンピュータへの命令列かもしれないが、その理論的基盤は間違いなくラムダ計算である。制約プログラミングや論理プログラミングでは解の性質のみを記述し解を求めるアルゴリズムは指定しないこともある。命令型言語で宣言型プログラミングを行う場合、手続き的な詳細をカプセル化する。例えば単体テストフレームワークJUnitではリフレクションが用いられる。

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

利点

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

  • 結果を得る過程の抽象化[4]: 宣言側の簡略化、内部実装側の最適化
  • 状態の分離: 宣言部分の出力を予測するために状態履歴とそれを起こすコードを探る必要が無くなる[5][6]

手続きの最適化

宣言型プログラミングは対象(What)を宣言により抽象化し手続き(How)と分離する。分離された手続きはランタイム等の内部実装によって処理される。ゆえに宣言型プログラミングではプログラムへ影響を与えずに手続きを最適化できる。

例えば宣言的UIで宣言が更新された際、全てのUI要素を再描画するのがもっとも単純な内部実装になる。しかし内部で宣言を保持しておき更新時に差分を得てその部分のみ更新すること(差分更新)でパフォーマンスを最適化できる[7]。宣言型プログラミングをおこなっているUIプログラマー目線ではこれは内部実装の最適化であり、UIプログラム自体には一切の変更が必要ない。

このように手続きが内部へ隠蔽される特性のおかげで、宣言型プログラミングは手続きの最適化を容易に行える。

状態の分離

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

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

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

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

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

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

利用される局面

脚注

  1. ^ a b "what declarative programming is. Intuitively, it is programming by defining the what (the results we want to achieve) without explaining the how (the algorithms, etc., needed to achieve the results). " P. Van Roy and S. Haridi (2001). コンピュータプログラミングの概念・技法・モデル. p.117.
  2. ^ 「宣言的記述を行う高水準言語の主要なお題目は『どうやって計算するか(How)ではなく, 何を計算するか(What)を記述する』というものである.」 Chikayama (2014). Software: Thirty Past Years and the Futures. コンピュータソフトウェア, Vol.31, No.2, p.9.
  3. ^ "We say the operation is declarative if, whenever called with the same arguments, it returns the same results independent of any other computation state." P. Van Roy and S. Haridi (2001). コンピュータプログラミングの概念・技法・モデル. p.113.
  4. ^ "programming concept where an ideal ... representation ... is kept in memory and synced with the “real” DOM by a library ... This approach enables the declarative API ... : You tell React what state you want the UI to be in, and it makes sure the DOM matches that state. This abstracts out the attribute manipulation, event handling ..." React. Virtual DOM and Internals.
  5. ^ 時間軸と何が起きたかを意識せずに宣言的に記述できる sonatard. (2019) 宣言的UI. p.37
  6. ^ "React provides a declarative API so that you don’t have to worry about exactly what changes on every update." React. Reconciliation.
  7. ^ "declarative UI ... works by conceptually regenerating the entire screen from scratch, then applying only the necessary changes." Thinking in Compose. Jetpack Compose.
  8. ^ 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)"
  9. ^ 前回のViewの状態に依存せずに、最終的に描画されるViewを宣言的に記述できる sonatard. (2019) 宣言的UI. p.37

参考文献

関連項目

外部リンク