宣言型プログラミングと命令型プログラミングの違いは何ですか?[閉まっている]


541

私は私にいくつかの光を当てるであろう宣言的および命令的プログラミングの定義を探してウェブを検索してきました。しかし、私が見つけたいくつかのリソースで使用されている言語は、たとえばWikipediaで、気が遠くなるようなものです。誰かがこのテーマに何らかの視点をもたらすかもしれない実際の例を(C#で)持っている人はいますか?


3
命令型はレストランに行き、6ozを注文します。ステーキ(珍しい調理)、フライドポテト(ケチャップ付き)、サイドサラダ(牧場付き)、コーラ(氷なし)。ウェイターは彼が要求したものを正確に配達し、$ 14.50が請求されます。一方、 Declarativeはレストランに出向き、ウェイターにディナーに12ドルくらいしか支払うつもりはなく、ステーキを好むと言っています。ウェイターは6ozで戻ります。ステーキ(中火)、マッシュポテト、蒸しブロッコリー、ディナーロール、コップ一杯の水。彼は11.99ドルを請求されます。
cs_pupil

回答:


786

宣言型プログラミングと命令型プログラミングの優れたC#の例は、LINQです。

不可欠なプログラミング、あなたは、段階的に起こるようにしたいものをコンパイラに伝えます。

たとえば、このコレクションから始めて、奇数を選択します。

List<int> collection = new List<int> { 1, 2, 3, 4, 5 };

命令型プログラミングでは、これをステップ実行して、必要なものを決定します。

List<int> results = new List<int>();
foreach(var num in collection)
{
    if (num % 2 != 0)
          results.Add(num);
}

ここで、私たちは言っています:

  1. 結果コレクションを作成する
  2. コレクション内の各番号をステップスルーします
  3. 番号を確認し、奇数の場合は結果に追加します

宣言型プログラミング、他の一方で、あなたがしたいが、何を記述したコードを書く必要はない、それを取得する方法(ご希望の結果を宣言し、ではなく、ステップバイステップ):

var results = collection.Where( num => num % 2 != 0);

ここでは、「コレクションをステップスルーします。このアイテムを確認してください。奇妙な場合は、結果のコレクションに追加してください。」ではなく、「奇妙な場所にすべてのものを与える」と言います。

多くの場合、コードも両方のデザインが混在しているため、常に白黒であるとは限りません。


8
+1。ただし、最初にLINQについて触れましたが、その例はどのようなものですか?
Zano、

15
collection.Whereは宣言型LINQ拡張メソッドを使用しています。C#言語機能ではなく、宣言型APIを使用しています。ここでメッセージを混在させたくなかったので、宣言メソッドの上に構築された言語の追加を避けました。
リードコプシー、

242
宣言型プログラミングは抽象化のレイヤーにすぎないようです。
Drazen Bjelovuk 2013年

8
これは良い答えですが、純粋でない関数型プログラミングと命令型プログラミングの違いに答えています。collection.WhereはLinqが提供する宣言構文を使用していません- 例としてmsdn.microsoft.com/en-us/library/bb397906.aspxを参照してくださいfrom item in collection where item%2 != 0 select item。宣言形式になります。関数がSystem.Linq名前空間にあるからといって、関数を呼び出しても宣言型プログラミングにはなりません。
ピートカーカム2015

30
@PeteKirkham使用する構文は問題ではありません-宣言型か命令型かは、発生したいことを宣言することと、発生する方法を正確に説明することの両方についてです。統合構文または拡張メソッド構文の使用は、別の問題です。
リードコプシー2015

145

宣言型プログラミングはあなたが欲しいものを言うときであり、命令型言語はあなたが欲しいものを得る方法を言うときです。

Pythonの簡単な例:

# Declarative
small_nums = [x for x in range(20) if x < 5]

# Imperative
small_nums = []
for i in range(20):
    if i < 5:
        small_nums.append(i)

最初の例は宣言型です。これは、リストの作成に関する「実装の詳細」を指定していないためです。

あなたが言っていないので、宣言型スタイルでLINQの結果を使用して、一般的に、C#の例に結びつけるために、どのようにあなたが欲しいものを得ること。あなたはあなたが欲しいものを言っているだけです。SQLについても同じことが言えます。

宣言型プログラミングの利点の1つは、手動で行うよりも優れたコードになる可能性のある決定をコンパイラが行うことができることです。次のようなクエリがある場合、SQLの例で実行します。

SELECT score FROM games WHERE id < 100;

SQLの「コンパイラ」idは、インデックス付きフィールドであることを知っているため、このクエリを「最適化」できます。あるいは、インデックス付けされていない可能性があります。この場合、データセット全体を反復処理する必要があります。あるいは、SQLエンジンは、これが8つのコアすべてを高速な並列検索に利用する絶好の機会であることを知っています。 プログラマとして、あなたはそれらの条件のいずれにも関係がなく、そのように特別なケースを処理するためにコードを書く必要はありません。


30
そのPythonの例は宣言的ではありません。
Juanjo Conti

18
@Juanjo:それはIS decalarative。
missingfaktor 2010

3
ここの最初のステートメントは、2番目のステートメントよりも宣言的ですか?
ゼナ

17
Juanjoおよびzennaに同意-ループ表記は、短い表記にリファクタリングされても、魔法のように宣言型プログラムに変換されません。
Felix Frank

11
@FelixFrankに同意せず、@ missingfaktorの「太字」ステートメントに傾く。これを行う従来の「完全に」宣言的な方法はでありfilter(lambda x: x < 5, range(20))、これは、短い表記にリファクタリングするもう1つの方法です。これは、より簡潔な表記を作成することを明示的に意図して作成された(pep 202を参照)リスト内包表記(明確な「マップ」セクションと「フィルター」セクションを含む)と違いはありません。そしてこの場合、このリストの理解はより明確/慣用的です。
yoniLavi 2015年

100

宣言型と命令型

プログラミングパラダイムは、コンピュータプログラミングの基本的なスタイルです。4つの主要なパラダイムがあります。命令型、宣言型、機能型(宣言型パラダイムのサブセットと見なされます)、オブジェクト指向です。

宣言型プログラミング:制御フロー(方法)を記述せずに、計算のロジック(動作)を表現するプログラミングパラダイムです。宣言型ドメイン固有言語(DSL)のよく知られた例には、CSS、正規表現、SQLのサブセット(SELECTクエリなど)が含まれます。HTML、MXML、XAML、XSLTなどの多くのマークアップ言語は、多くの場合宣言型です。宣言型プログラミングは、一連の命令としてのプログラムと、目的の回答についてのアサーションとしてのプログラムの違いを曖昧にしようとします。

命令型プログラミング:プログラムの状態を変更するステートメントの観点から計算を説明するプログラミングパラダイムです。宣言型プログラムは、プログラミングコマンドまたは数学的表明として二重に見ることができます。

関数型プログラミング:計算を数学関数の評価として扱い、状態や可変データを回避するプログラミングパラダイムです。状態の変化を強調する命令型プログラミングスタイルとは対照的に、関数の適用を強調します。Haskellなどの純粋な関数型言語では、すべての関数に副作用はなく、状態の変化は状態を変換する関数としてのみ表されます。

次のMSDNの命令型プログラミングの例では、1〜10の数値をループして、偶数を見つけます。

var numbersOneThroughTen = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
//With imperative programming, we'd step through this, and decide what we want:
var evenNumbers = new List<int>();
foreach (var number in numbersOneThroughTen)
{    if (number % 2 == 0)
    {
        evenNumbers.Add(number);
    }
}
//The following code uses declarative programming to accomplish the same thing.
// Here, we're saying "Give us everything where it's odd"
var evenNumbers = numbersOneThroughTen.Select(number => number % 2 == 0);

どちらの例でも同じ結果が得られ、一方が他方よりも良くも悪くもありません。最初の例ではより多くのコードが必要ですが、コードはテスト可能であり、命令型アプローチにより実装の詳細を完全に制御できます。2番目の例では、コードが間違いなく読みやすくなっています。ただし、LINQでは、舞台裏で行われる処理を制御できません。LINQが要求された結果を提供することを信頼する必要があります。


7
オブジェクト指向の説明を追加できますか?
mbigras 16


54

上記のすべての回答と他のオンライン投稿では、次のことに言及しています。

  • 宣言型プログラミング、あなたが望むものを記述するコードを書いたが、それを取得する必要はありませんか
  • 命令型プログラミングよりも宣言型プログラミングを優先する必要があります

彼らが私たちに言っていないことは、それを達成する方法です。プログラムの一部をより宣言するには、他の部分が抽象化提供して、実装の詳細(命令コード)を隠す必要があります

  • たとえば、LINQはループ(for、whileなど)よりも宣言的です。たとえば、list.Where()新しいフィルターされたリストを取得するために使用できます。これを機能させるために、マイクロソフトはLINQ抽象化の背後にあるすべての重労働を実行しました。

実際、関数型プログラミングと関数型ライブラリがより宣言的である理由の1つは、ループを抽象化して作成をリスト化し、実装の詳細(ループのある可能性が最も高い命令コード)を裏で隠しているためです。

どのプログラムでも、命令コードと宣言コードの両方が常にあります。目指すべきことは、プログラムの他の部分がそれらを宣言的に使用できるように、抽象化の背後にすべての命令コードを隠すことです。

最後に、関数型プログラミングとLINQはプログラムをより宣言的にすることができますが、より多くの抽象化を提供することにより、いつでもより宣言的にすることができます。例えば:

// JavaScript example

// Least declarative
const bestProducts = [];
for(let i = 0; i < products.length; i++) {
    let product = products[i];
    if (product.rating >= 5 && product.price < 100) {
        bestProducts.push(product);
    }
}


// More declarative
const bestProducts = products.filter(function(product) {
    return product.rating >= 5 && product.price < 100;
});

// Most declarative, implementation details are hidden in a function
const bestProducts = getBestProducts();

PS宣言型プログラミングの極端な例は、新しいドメイン固有言語(DSL)を発明することです。

  1. 文字列検索:カスタム命令コードの代わりに正規表現
  2. React.js:直接的なDOM操作の代わりにJSX
  3. AWS CloudFormation:CLIではなくYAML
  4. リレーショナルデータベース:ISAMやVSAMなどの古い読み書きAPIの代わりにSQL。

宣言型プログラミングには多くの良い例があります:ReactCloudFormationTerraform
engineforce

つまり、「宣言型」プログラミングとは、ジョブを実行するコードを関数に移動することを意味するだけですか。
ギヨームF.

@GuillaumeF。ドメイン固有の抽象化を作成することです。例えば、 -銀行業における:次のような機能を作成する必要がありdebitdeposit代わりにimparativeコードを繰り返すのなどを、account.balance += depositAmount
engineforce

44

宣言型/命令型プログラミングの議論でめったにポップアップしない別の例を追加します。それはユーザーインターフェイスです。

C#では、さまざまなテクノロジーを使用してUIを構築できます。

命令型の最後では、DirectXまたはOpenGLを使用して、ボタン、チェックボックスなどを命令型で行ごと(または実際には三角形ごと)に描画できます。ユーザーインターフェースの描き方はあなた次第です。

宣言の最後には、WPFがあります。基本的にXMLを作成し(技術的には「XAML」)、フレームワークが機能します。あなたはユーザーインターフェースがどのように見えるかを言います。それを行う方法を理解するのはシステム次第です。

とにかく、もう1つ考えるべきことです。1つの言語が宣言的または命令的であるからといって、他の言語の特定の機能がないことを意味するわけではありません。

また、宣言型プログラミングの利点の1つは、コードを読み取ることで目的が通常より簡単に理解されるのに対し、命令型は実行をより細かく制御できることです。

そのすべての要点:

宣言-> whatやりたい

命令型-> howあなたはそれをやりたい


27

私はケンブリッジコースの説明とその例が好きでした:

  • 宣言 - 方法では なくをすべきを指定する
    • 例:HTMLは、画面に描画する方法ではなく、Webページに表示する内容を記述します
  • 必須 - どのように指定する
    • int x; -何(宣言)
    • x=x+1; - どうやって

「それが画面にどのように描かれるべきではない」...それはそれCSS命令的であることを意味するのでしょうか?
Chef_Code 2016年

11
いいえ。それはまた考えることができ、宣言したばかり言うので、何をしたい- 「このセルの境界が青にします」。命令型アプローチ(JavaScript:など)で同じ境界線を描画したいとします。次に、「ポイント(x1、y1)に移動し、このポイントと(x2、y1)の間に青い線を描き、(x2、y1)から(x2、y2)に青い線を描き、青い線を描きます。 (x2、y2)から(x1、y2)へ、(x1、y2)から(x1、y1)へ青い線を引きます。
ROMANIA_engineer 2016年

@ROMANIA_engineer、そのようなケンブリッジコースはどこにありますか?
テストチーム

@ testteam、Googleで次の「cl.cam.ac.uk Teaching ooprog」を検索してください。URLから年を変更できます。
ROMANIA_engineer

@ROMANIA_engineer、了解、ありがとう
テストチーム

26

違いは、主に抽象化の全体的なレベルに関係しています。宣言型を使用すると、ある時点で、個々のステップから離れすぎて、プログラムが結果を取得する方法に関して多くの自由度を持つようになります。


すべての命令は、連続体のどこかに落ちていると見ることができます。

抽象度:

Declarative <<=====|==================>> Imperative

宣言的な実世界の例:

  1. 司書、モビーディックのコピーを私にチェックしてください。(司書は、その裁量で、要求を実行するための最良の方法を選択します)

命令型の実世界の例:

  1. 図書館に行く
  2. ブック編成システムを検索(カードカタログ-オールドスクール)
  3. カードカタログの使い方を研究する(あなたも忘れましたね)
  4. 棚のラベル付けと整理方法を理解します。
  5. 本が棚でどのように整理されているかを理解します。
  6. カードのカタログから本の場所を組織システムと相互参照して、その本を見つける。
  7. 本をチェックアウトシステムに持っていきます。
  8. 本をチェックしてください。

これは、宣言的/命令的というよりも抽象化についてではないですか?あなたはまだ本を持ってくるよう司書に指示しています。
kamathln

回答をより完全なものに更新し、この側面をソリューションに含めました。
Lucent Fox

3
これにはいくつかの真実がありますが、完全な定義ではありません。宣言型プログラミングでは、開始点に関係なく、最終目標を表明します。命令型プログラミングでは、定義された開始点が重要です。それは、住所を与えることと方向を与えることの違いのようなものです。アドレスは、あなたがどんな人であっても役に立ちます。一方、他の場所から始めた場合、方向は無効です。
クトゥトゥ

24

命令型プログラミングでは、コードの実行方法を段階的に定義する必要があります。命令的な方法で方向を示すには、「1st Streetに行き、Mainで左折し、2ブロック進み、Mapleで右折して、左側の3番目の家に立ち寄ります」と言います。宣言型バージョンは、「ドライブのスーの家」のように聞こえるかもしれません。人は何かをする方法を言います。もう1つは、何を行う必要があるかを示しています。

宣言型スタイルには、命令型スタイルに比べて2つの利点があります。

  • 旅行者に長い一連の指示を暗記するように強制するものではありません。
  • これにより、旅行者は可能な限りルートを最適化できます。

Calvert、C Kulkarni、D(2009)。必須のLINQ。Addison Wesley。48。


11

命令型プログラミングは、順序を指定するなど、何をすべきか、どのように行うかをコンピュータに明示的に指示します

C#:

for (int i = 0; i < 10; i++)
{
    System.Console.WriteLine("Hello World!");
}

宣言型とは、コンピュータに何をすべきかを指示するときですが、実際にそれを行う方法ではありません。Datalog / Prologは、この点で頭に浮かぶ最初の言語です。基本的にすべてが宣言型です。あなたは本当に注文を保証することはできません。

C#ははるかに命令的なプログラミング言語ですが、特定のC#機能はLinqのようにより宣言的です

dynamic foo = from c in someCollection
           let x = someValue * 2
           where c.SomeProperty < x
           select new {c.SomeProperty, c.OtherProperty};

同じことを命令的に書くことができます:

dynamic foo = SomeCollection.Where
     (
          c => c.SomeProperty < (SomeValue * 2)
     )
     .Select
     (
          c => new {c.SomeProperty, c.OtherProperty}
     )

(ウィキペディアLinqの例)


2
あなたは、タイプミスを持っている:LINQ文は、宣言されている、いないimperitive(宣言型読みくださいあなたは「C#の機能はLINQのように、より多くの不可欠です」している。
リードCopsey

修正済み(少し前)
マッケイ

8

コンピュータサイエンスでは、宣言型プログラミングは、制御フローを記述せずに計算のロジックを表現するプログラミングパラダイムです。

http://en.wikipedia.org/wiki/Declarative_programmingから

簡単に言えば、宣言型言語は、制御フロー(ループ、ifステートメントなど)の複雑さに欠けるため、よりシンプルです。

良い比較は、ASP.Netの「コードビハインド」モデルです。宣言的な「.ASPX」ファイルと、命令的な「ASPX.CS」コードファイルがあります。スクリプトの宣言的な半分で必要なことをすべて実行できれば、より多くの人が実行中の内容を追跡できることがよくあります。


7

ここでフィリップロバーツから盗む:

  • 命令型プログラミングは、何かを実行する方法をマシンに伝えます(結果として何が起こりたいのか)
  • 宣言型プログラミングは、マシンにあなたが何をしたいのかを伝えます(そしてコンピューターはそれを行う方法を見つけ出します)

2つの例:

1.配列内のすべての数値を2倍にする

命令的に:

var numbers = [1,2,3,4,5]
var doubled = []

for(var i = 0; i < numbers.length; i++) {
  var newNumber = numbers[i] * 2
  doubled.push(newNumber)
}
console.log(doubled) //=> [2,4,6,8,10]

宣言的に:

var numbers = [1,2,3,4,5]

var doubled = numbers.map(function(n) {
  return n * 2
})
console.log(doubled) //=> [2,4,6,8,10]

2.リスト内のすべてのアイテムを合計する

命令的に

var numbers = [1,2,3,4,5]
var total = 0

for(var i = 0; i < numbers.length; i++) {
  total += numbers[i]
}
console.log(total) //=> 15

宣言的に

var numbers = [1,2,3,4,5]

var total = numbers.reduce(function(sum, n) {
  return sum + n
});
console.log(total) //=> 15

命令型の例では、新しい変数を作成し、それを変更して、その新しい値を返す(つまり、発生させる方法)ことに注意してください。一方、宣言型の例は、特定の入力で実行され、初期入力に基づいて新しい値を返します(つまり、 、何が起こりたいのか)。


5
この質問に対する恐ろしいほど多くの回答と同様に、「宣言的」プログラミングの例は関数型プログラミングの例です。「マップ」のセマンティクスは、「この関数を配列の要素に順番に適用する」です。ランタイムに実行順序の余裕を許可していません。
ピートカーカム2015

4

命令型プログラミング
C / C ++、Java、COBOL、FORTRAN、Perl、JavaScriptなどのプログラミング規則を必要とするプログラミング言語。そのような言語で書くプログラマーは、データ処理とプログラミングの知識に基づいて、問題を解決するための適切なアクションの順序を開発する必要があります。

宣言型プログラミング
従来のプログラミングロジックを記述する必要のないコンピューター言語。ユーザーは、C ++やJavaなどの手続き型プログラミング言語で必要なプログラムステップではなく、入力と出力の定義に集中します。

宣言型プログラミングの例は、CSS、HTML、XML、XSLT、RegXです。


2

宣言型プログラムは、多かれ少なかれ「普遍的な」命令型実装/ vmの単なるデータです。

プラス:一部のハードコードされた(およびチェックされた)形式でデータのみを指定することは、いくつかの命令型アルゴリズムのバリアントを直接指定するよりも簡単で、エラーが発生しにくくなります。複雑な仕様の中には、DSL形式でのみ直接記述できないものもあります。DSLのデータ構造で使用されるbestおよびfreqは、セットとテーブルです。要素/行間に依存関係がないためです。依存関係がない場合は、変更の自由とサポートの容易さがあります。(例のモジュールとクラスを比較-満足できるモジュールと脆弱な基本クラスの問題があるクラス)宣言性とDSLのすべての商品は、そのデータ構造(テーブルとセット)の利点からすぐに続きます。別のプラス-DSLが多かれ少なかれ抽象的である(うまく設計されている)場合は、宣言型言語vmの実装を変更できます。たとえば、並列実装を行います。

マイナス:あなたは正しいと思います。一般的な(DSLによってパラメーター化された)命令型のアルゴリズム/ vmの実装は、特定のアルゴリズムよりも低速であるか、メモリを大量に消費している可能性があります。ある場合には。そのようなケースがまれな場合は、忘れてください。ゆっくりしてください。頻度が高い場合は、DSL / vmをいつでも拡張できます。どこか他のすべてのケースが遅くなります、確かに...

PSフレームワークはDSLと命令型の中間にあります。そしてすべての中間的な解決策と同様に...それらは利点ではなく欠陥を組み合わせます。彼らはそれほど安全ではなく、それほど速くありません:)すべてのトレードのジャックhaskellを見てください-それは強力なシンプルなMLと柔軟なメタプログラムPrologの中間であり、それはなんと怪物でしょう。ブール値のみの関数/述語を持つHas​​kellとしてPrologを見ることができます。そしてその柔軟性がHaskellに対してどれほど単純か...


2

C#の宣言型プログラミングツールとしてAttributeクラスについて誰も言及していないのはなぜでしょうか。このページの人気のある答えは、宣言型プログラミングツールとしてのLINQについての話です。

ウィキペディアによると

一般的な宣言型言語には、データベースクエリ言語(SQL、XQueryなど)、正規表現、論理プログラミング、関数型プログラミング、構成管理システムなどがあります。

そのため、関数構文としてのLINQは間違いなく宣言型メソッドですが、構成ツールとしてのC#の属性クラスも宣言型メソッドです。詳細については、次の記事が参考になります。C#属性プログラミングの概要


これは良い点であり、より明白な例だと思います.linqのようなものは依然として必須であると思われるため、違いを知らない人には混乱を招きますが、属性は宣言以外の方法で見るのは難しいです。メンバーに「タグ」を付けて、メンバーに何をしたいかを宣言しますが、どのようにしてその方法を言っているのではありません。それほど重くはありませんが、属性ではロジックをまったく説明していません。ラベルを付けているだけです
user441521

2

モバイルアプリの開発に関する別の例を追加するだけです。iOSとAndroidには、アプリのUIを定義できるインターフェイスビルダーがあります。

これらのビルダーを使用して描画されるUIは本質的に宣言型であり、コンポーネントをドラッグアンドドロップします。実際の描画はフレームワークとシステムの下で実行されます。

しかし、コンポーネント全体をコードで描画することもできますが、それは本質的に必須です。

また、Angular JSのようないくつかの新しい言語は、宣言的にUIを設計することに重点を置いており、同じサポートを提供する他の多くの言語を目にする可能性があります。JavaにはJavaスイングまたはJava FXでネイティブデスクトップアプリを描画するための優れた宣言的な方法がないのと同様に、近い将来、そうなる可能性があります。


Javaは頭字語ではありませんBTW
モルデチャイ

1

私の理解では、どちらの用語も哲学にルーツがあり、宣言型と命令型の知識があります。宣言的知識は、真理の主張、数学の公理のような事実の表明です。それは何かを教えてくれます。命令的、または手続き的知識は、何かに到達する方法を段階的に説明します。それがアルゴリズムの定義です。もしそうなら、コンピュータプログラミング言語を英語と比較してください。宣言文は何かを述べています。退屈な例ですが、Javaで2つの数値が互いに等しいかどうかを表示する宣言的な方法を次に示します。

public static void main(String[] args)
{
    System.out.print("4 = 4.");
}

一方、英語の命令文は、命令を出すか、何らかの要求をします。したがって、命令型プログラミングは単なるコマンドのリストです(これを実行してください)。Javaでユーザー入力を受け入れている間に2つの数値が互いに等しいかどうかを表示する必須の方法を次に示します。

private static Scanner input;    

public static void main(String[] args) 
{
    input = new Scanner(System.in);
    System.out.println();
    System.out.print("Enter an integer value for x: ");
    int x = input.nextInt();
    System.out.print("Enter an integer value for y: ");        
    int y = input.nextInt();

    System.out.println();
    System.out.printf("%d == %d? %s\n", x, y, x == y);
}

基本的に、宣言的知識特定の要素をスキップして、それらの要素に対する抽象化の層を形成します。宣言型プログラミングも同じです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.