この用語は、いくつかの異なる文脈で投げかけられているのを耳にします。それは何ですか?
18 に答える
宣言型プログラミングとは、どのようにやりたいかではなく、何をしたいかを記述するような方法でコードを記述することです。その方法を理解するのはコンパイラに任されています。
宣言型プログラミング言語の例は、SQL と Prolog です。
他の回答は、宣言型プログラミングとは何かを説明する素晴らしい仕事をすでに行っているので、それが役立つ理由の例をいくつか紹介します。
コンテキストの独立性
宣言型プログラムは、コンテキストに依存しません。最終的な目標が何であるかを宣言するだけで、その目標に到達するための中間ステップを宣言しないため、同じプログラムをさまざまなコンテキストで使用できます。命令型プログラムはコンテキストに依存することが多いため (たとえば、非表示状態)、これを行うのは困難です。
yacc
例として取り上げます。別名パーサージェネレーターです。コンパイラー コンパイラーは、言語の文法を記述するための外部宣言型 DSL であり、その言語のパーサーが記述から自動的に生成されるようにします。文脈に依存しないため、このような文法ではさまざまなことを行うことができます。
- その文法の C パーサーを生成します ( の元の使用例
yacc
) - その文法の C++ パーサーを生成する
- その文法の Java パーサーを生成する (Jay を使用)
- その文法の C# パーサーを生成する (GPPG を使用)
- その文法の Ruby パーサーを生成する (Racc を使用)
- その文法のツリー視覚化を生成する (GraphViz を使用)
- 単純に、yacc ソース ファイル自体のきれいな印刷、凝った書式設定、および構文の強調表示を行い、それを言語の構文仕様としてリファレンス マニュアルに含めます。
などなど …
最適化
どの手順をどの順序で実行するかをコンピューターに指示する必要がないため、コンピューターはプログラムをより自由に再配置でき、場合によってはいくつかのタスクを並行して実行することさえできます。良い例は、SQL データベースのクエリ プランナーとクエリ オプティマイザーです。ほとんどの SQL データベースでは、実際に実行しているクエリと、実行するように要求したクエリを表示できます。多くの場合、これらのクエリは何も見えませんお互いのように。クエリ プランナーは、ユーザーが夢にも思わなかったようなことを考慮に入れます。たとえば、ディスク プラッターの回転レイテンシーや、まったく別のユーザー向けのまったく別のアプリケーションが同様のクエリを実行したという事実と、ユーザーが使用しているテーブルです。に参加し、ロードを避けるために一生懸命働いたことは、とにかくすでにメモリに入っています。
ここには興味深いトレードオフがあります。機械は、命令型言語の場合よりも、何かを行う方法を理解するために一生懸命働かなければなりませんが、それを理解すると、最適化のための自由度と情報量がはるかに多くなります。ステージ。
大まかに:
宣言型プログラミングは次の傾向があります:-
- 宣言のセット、または宣言型ステートメント。それぞれに意味があり(多くの場合、問題領域にあります)、独立して単独で理解できます。
命令型プログラミングは次の傾向があります:-
- コマンドのシーケンス。それぞれが何らかのアクションを実行します。しかし、これは問題の領域で意味がある場合とない場合があります。
その結果、命令型のスタイルは、読者がシステムが実際に行っていることの仕組みを理解するのに役立ちますが、解決しようとしている問題についてはほとんど洞察を与えない可能性があります。一方、宣言型のスタイルは、読者が問題の領域と、システムが問題の解決に向けて採用するアプローチを理解するのに役立ちますが、力学の問題についてはあまり有益ではありません。
実際のプログラム(ProLogやCなど、スペクトルの終わりを好む言語で書かれたものでも)は、作品のさまざまな複雑さとコミュニケーションのニーズを満たすために、さまざまなポイントでさまざまな程度に両方のスタイルが存在する傾向があります。1つのスタイルが他のスタイルより優れているわけではありません。それらは異なる目的を果たすだけであり、人生の多くのものと同様に、節度が鍵となります。
これが例です。
CSS (HTML ページのスタイル設定に使用) では、イメージ要素を高さ 100 ピクセル、幅 100 ピクセルにしたい場合は、次のようにそれを「宣言」するだけです。
#myImageId {
height: 100px;
width: 100px;
}
CSS は、宣言型の「スタイル シート」言語と見なすことができます。
この CSSを読み取って解釈するブラウザ エンジンは、画像を自由に縦横に自由に表示できます。さまざまなブラウザー エンジン (たとえば、IE 用のエンジン、Chrome 用のエンジン) では、このタスクの実装方法が異なります。
もちろん、独自の実装は宣言型言語ではなく、アセンブリ、C、C++、Java、JavaScript、Python などの手続き型言語で記述されています。そのコードは、段階的に実行される一連のステップです (関数呼び出しが含まれる場合もあります)。ピクセル値の補間や画面へのレンダリングなどを行う場合があります。
申し訳ありませんが、他の多くの回答には同意できません。私は、宣言型プログラミングの定義に関するこの混乱した誤解を止めたいと思います。
意味
サブ式の参照透過性 (RT) は、宣言型プログラミング式の唯一の必須属性です。これは、命令型プログラミングと共有されない唯一の属性であるためです。
宣言型プログラミングのその他の引用された属性は、この RT に由来します。詳細な説明については、上のハイパーリンクをクリックしてください。
スプレッドシートの例
スプレッドシート プログラミングに言及した 2 つの回答がありました。スプレッドシート プログラミング (別名数式) が変更可能なグローバル状態にアクセスしない場合、それは宣言型プログラミングです。これは、変更可能なセルの値が(プログラム全体)のモノリシックな入力と出力であるためです。main()
新しい値は、各数式が実行された後にセルに書き込まれないため、宣言型プログラム (スプレッドシート内のすべての数式の実行) の存続期間中は変更できません。したがって、相互に関連して、式はこれらの可変セルを不変と見なします。RT 関数は、不変のグローバル状態 (および可変のローカル状態) にアクセスできます。
したがって、プログラムの終了時に ( からの出力として) セル内の値をmain()
変更する機能は、ルールのコンテキストで変更可能な格納された値にはなりません。主な違いは、スプレッドシートの数式が実行されるたびにセルの値が更新されないことです。したがって、数式を実行する順序は重要ではありません。すべての宣言式が実行された後、セルの値が更新されます。
宣言型プログラミングは絵であり、命令型プログラミングはその絵を描くための命令です。
コンピューターが目的の場所に到達するために実行する必要がある手順を説明するのではなく、「それが何であるかを伝える」場合は、宣言的なスタイルで書いています。
XML を使用してデータをマークアップする場合、宣言型プログラミングを使用していることになります。これは、「これは人であり、これは誕生日であり、あちらには住所がある」と言っているからです。
より大きな効果を得るために宣言型プログラミングと命令型プログラミングを組み合わせる例をいくつか示します。
Windows Presentation Foundation は、宣言型 XML 構文を使用して、ユーザー インターフェイスがどのようなものか、およびコントロールと基になるデータ構造の間の関係 (バインディング) を記述します。
構造化された構成ファイルは、宣言構文 (「キー = 値」のペアのように単純) を使用して、データの文字列または値が何を意味するかを識別します。
HTML は、テキストの各部分がドキュメント全体に対してどのような役割を持っているかを説明するタグでテキストをマークアップします。
宣言型プログラミングは、宣言、つまり宣言文を使用したプログラミングです。宣言文には、命令文と区別するいくつかのプロパティがあります。特に、宣言は次のとおりです。
- 可換 (並べ替え可能)
- 連想 (再グループ化可能)
- 冪等 (意味を変えずに繰り返すことができる)
- 単調 (宣言は情報を差し引かない)
関連するポイントは、これらはすべて構造的な特性であり、主題と直交しているということです。宣言型は、「What vs. How」に関するものではありません。「what」を宣言するのと同じくらい簡単に、 「how」を宣言 (表現および制約) できます。宣言は内容ではなく構造に関するものです。宣言型プログラミングは、コードを抽象化してリファクタリングする方法、およびコードをサブプログラムにモジュール化する方法に大きな影響を与えますが、ドメイン モデルにはそれほど影響しません。
多くの場合、コンテキストを追加することで、命令型から宣言型に変換できます。たとえば、「左に曲がる。(... 待って...) 右に曲がる」から。「ボブは 11:01 に Foo と Bar の交差点を左折します。Bob は 11:06 に Bar と Baz の交差点を右折します。」後者の場合、文は冪等で交換可能であることに注意してください。一方、前者の場合、文を並べ替えたり繰り返したりすると、プログラムの意味が大きく変化します。
単調に関しては、宣言は可能性を差し引く制約を追加できます。しかし、制約は依然として情報を追加します (より正確には、制約は情報です)。時変宣言が必要な場合は、明示的な時間セマンティクスを使用してこれをモデル化するのが一般的です。たとえば、「ボールは平らです」から「時間 T でボールは平らです」などです。矛盾する 2 つの宣言がある場合、一貫性のない宣言システムになりますが、これはソフトな制約 (優先順位、確率など) を導入するか、パラコンシステント ロジックを活用することで解決できます。
2011 年 12 月にこの質問に回答して以来、宣言型プログラミングの理解を深めてきました。これが私の現在の理解に従います。
私の理解 (研究) の長いバージョンは、このリンクで詳しく説明されています。以下に提供する要約を深く理解するには、このリンクを読む必要があります。
命令型プログラミングは、変更可能な状態が格納および読み取られる場所であるため、プログラム命令の順序付けおよび/または重複により、プログラムの動作 (セマンティクス) が変更される可能性があります (さらには、バグ、つまり意図しない動作が発生することもあります)。
最も素朴で極端な意味で (以前の回答で主張しました)、宣言型プログラミング (DP) は格納されたすべての変更可能な状態を回避しているため、プログラム命令の順序付けおよび/または複製によってプログラムの動作 (セマンティクス) を変更することはできません。 .
ただし、このような極端な定義は、現実の世界ではあまり役に立ちません。ほぼすべてのプログラムが格納された変更可能な状態に関係するからです。新しい状態が保存される前に、プログラム コード全体が入力状態の 1 つの静的コピーで完了するまで実行されるため、スプレッドシートの例は DP のこの極端な定義に準拠しています。その後、いずれかの状態が変更された場合、これが繰り返されます。しかし、現実世界のほとんどのプログラムは、このような状態変化のモノリシック モデルに限定することはできません。
DP のより有用な定義は、プログラミング命令の順序付けおよび/または複製によって不透明なセマンティクスが変更されないことです。言い換えれば、発生するセマンティクスに隠されたランダムな変更はありません。プログラム命令の順序や重複の変更は、プログラムの動作に対して意図的で透過的な変更のみを引き起こします。
次のステップは、どのプログラミング モデルまたはパラダイムが DP を支援するかについて話すことですが、それはここでは問題ではありません。
何かを行う方法ではなく、何をしたいのかをコンピューターに説明すること。
エクセルのページを想像してください。納税申告書を計算するための式が列に入力されています。
すべてのロジックはセル内で宣言されます。計算の順序は、手続き的にではなく、数式自体によって決定されます。
それが宣言型プログラミングのすべてです。プログラムの流れではなく、問題空間と解決策を宣言します。
Prolog は、私が使用した唯一の宣言型言語です。これには別の種類の考え方が必要ですが、典型的な手続き型プログラミング言語以外の何かに触れるためだけに学ぶのは良いことです。
これは、何かがどのように機能するかを記述するのではなく、何をすべきか、またはどうあるべきかを記述することに基づいたプログラミング方法です。
言い換えれば、式で作られたアルゴリズムを書くのではなく、自分が望むようにレイアウトするだけです。2 つの良い例は、HTML と WPF です。
このウィキペディアの記事は良い概要です: http://en.wikipedia.org/wiki/Declarative_programming
宣言型プログラミングとは、「マシンの運用モデルではなく、開発者のメンタルモデルに準拠した言語でプログラミングする行為」です。
宣言型プログラミングと命令型プログラミングの違いは、構造化データの解析の問題によってよく示されています。
命令型プログラムは、相互再帰関数を使用して入力を消費し、データを生成します。宣言型プログラムは、データの構造を定義する文法を表現して、データを解析できるようにします。
これら2つのアプローチの違いは、宣言型プログラムが、ホスト言語よりも問題のメンタルモデルにより密接にマッピングされた新しい言語を作成することです。
奇妙に聞こえるかもしれませんが、宣言型システムのリストに Excel (または実際には任意のスプレッドシート) を追加します。これの良い例をここに示します。
DPは表現する方法なので説明します
- 目標表現、条件-私たちが探しているもの。1つ、多分、または多くありますか?
- いくつかの既知の事実
- 既知の事実を拡張するルール
...そして、目標を見つけるために通常は統合アルゴリズムと連携する控除エンジンがある場合。
私が知る限り、Prologは(おそらく)抽象的な方法で物事を宣言することを目的としているため、Prologのようなプログラミングシステムを説明するために使用され始めました。
上記のユーザーによって定義されているため、意味はますます少なくなっています。HTMLの宣言型プログラミングとは対照的に、Haskellの宣言型プログラミングの間にはギャップがあることは明らかです。
宣言型プログラミングの他のいくつかの例:
- データバインディング用の ASP.Net マークアップ。たとえば、「このグリッドをこのソースで埋める」と言うだけで、それがどのように起こるかはシステムに任せます。
- Linq 式
宣言型プログラミングは、コードのメンタル モデル * を単純化するのに役立ち、最終的にはよりスケーラブルになる可能性があるため、優れています。
たとえば、配列またはリストの各要素に対して何かを行う関数があるとします。従来のコードは次のようになります。
foreach (object item in MyList)
{
DoSomething(item);
}
大したことはありません。しかし、より宣言的な構文を使用し、代わりに DoSomething() をアクションとして定義するとどうなるでしょうか? 次に、次のように言えます。
MyList.ForEach(DoSometing);
もちろん、これはより簡潔です。しかし、あちこちに 2 行のコードを保存するだけでなく、もっと懸念があると思います。たとえば、パフォーマンス。古い方法では、処理は順番に実行する必要がありました。.ForEach() メソッドに、並列処理を自動的に処理できることを通知する方法があればどうでしょうか? 突然、非常に安全な方法でコードをマルチスレッド化し、コードを 1 行だけ変更しました。実際、それを可能にする .Net の拡張機能があります。
- そのリンクをたどると、私の友人によるブログ投稿に移動します。投稿全体は少し長いですが、「The Problem」というタイトルの見出しまで下にスクロールして、問題なくそこから拾うことができます.*
テキストへの回答をどのように提出するかによって異なります。全体として、特定の視点でプログラムを見ることができますが、問題をどの角度から見るかによって異なります。プログラムを始めましょう: Dim Bus, Car, Time, Height As Integr
繰り返しますが、それは問題が全体的に何であるかによって異なります。プログラムの都合上、短縮させていただく場合がございます。これが役に立てば幸いです。そうでない場合はフィードバックが必要です。ありがとうございました。