一般的に言えば、プログラミング言語の関数や手続きについては誰もが耳にします。しかし、私はこれらの用語をほとんど同じ意味で使用していることを知りました(おそらく非常に間違っています)。
だから、私の質問は:
機能、目的、用途の違いは何ですか?
例をいただければ幸いです。
(define (sqrt x) (newtons-method (lambda (y) (- (square y) x)) 1.0))
。
一般的に言えば、プログラミング言語の関数や手続きについては誰もが耳にします。しかし、私はこれらの用語をほとんど同じ意味で使用していることを知りました(おそらく非常に間違っています)。
だから、私の質問は:
機能、目的、用途の違いは何ですか?
例をいただければ幸いです。
(define (sqrt x) (newtons-method (lambda (y) (- (square y) x)) 1.0))
。
回答:
関数は値を返し、プロシージャはコマンドを実行するだけです。
名前関数は数学に由来します。入力に基づいて値を計算するために使用されます。
プロシージャは、順番に実行できる一連のコマンドです。
ほとんどのプログラミング言語では、関数でさえ一連のコマンドを持つことができます。したがって、違いは値の部分を返すことだけです。
しかし、関数をクリーンに保ちたい場合(関数型言語を見てください)、関数に副作用がないことを確認する必要があります。
これはコンテキストに依存します。
Pascalのような言語では、関数とプロシージャは別個のエンティティであり、値を返すかどうかは異なります。それらは異なる方法で動作します。言語の構文(たとえば、プロシージャコールはステートメントを形成します。式の中でプロシージャコールを使用することはできません。関数呼び出しはステートメントを形成しないため、他のステートメントで使用する必要があります)。したがって、Pascalで育ったプログラマーはそれらを区別します。
C言語のような言語や他の多くの現代言語では、この区別はなくなりました。静的に型付けされた言語では、手続きはおかしな戻り値の型を持つ単なる関数です。これがおそらく、それらが同じ意味で使用されている理由です。
関数型言語では、通常、プロシージャなどはありません-すべてが関数です。
Cの例:
// function
int square( int n ) {
return n * n;
}
// procedure
void display( int n ) {
printf( "The value is %d", n );
}
C標準では手続きについては触れておらず、関数についてのみ述べていることに注意してください。
void function
です。Kernighan&Ritchie Ch 1.7:「Cでは、関数はFortranのサブルーチンまたは関数、またはPascalのプロシージャまたは関数と同等です。」つまり、この答えは間違っています。
SELECT
(だけでなく、DML INSERT
、UPDATE
、DELETE
機能のみを可能にする一方で、その中に文)SELECT
それに声明を。SELECT
ステートメントで使用できませんが、関数はSELECT
ステートメントに埋め込むことができます。WHERE
(またはa HAVING
またはSELECT
)ブロックのどこでも使用できませんが、関数では使用できます。JOIN
、他のテーブルと一緒にブロックで使用できます。JOIN
ブロックやその他の行セット操作で使用できるビューと考えることができます。より厳密には、関数fは、x = yの場合、f(x)= f(y)のプロパティに従います。つまり、同じ引数で呼び出されるたびに同じ結果を計算します(したがって、関数の状態は変更されません)システム。)
したがって、rand()やprint( "Hello")などは関数ではなくプロシージャです。sqrt(2.0)は関数である必要がありますが、どれだけ頻繁に呼び出しても、目に見える影響や状態の変化はなく、常に1.41とそれを返します。
これはよく知られている古い質問ですが、現代のプログラミング言語の研究と設計について、もう少し洞察を共有したいと思います。
伝統的に(構造化プログラミングの意味で)非公式に、プロシージャは「入力」を持ち、プログラム可能な何かを行うための再利用可能な構造的構造です。プロシージャ内で何かを行う必要がある場合、ソースコード(通常は一種の式)でコーディングされたプロシージャコールでプロシージャに(実際の)引数を提供し、プロシージャ本体(提供されるプロシージャの定義で)は、本文で使用される(正式な)パラメータに引数を代入して実行されます。
関数は、ための手順以上である戻り値はまた、体内の「出力」として指定することができます。関数呼び出しは、関数呼び出しの結果を構文的に(通常、他のいくつかの式の部分式として)使用できることを除いて、プロシージャ呼び出しとほぼ同じです。
従来、(関数呼び出しではなく)プロシージャ呼び出しは、出力に関心がないことを示すために使用され、呼び出しが何もしないことを回避するために副作用がなければならないため、命令型プログラミングパラダイムが強調されています。Pascalのような従来のプログラミング言語の多くは、この意図的なスタイルの違いを区別するための「プロシージャ」と「関数」の両方を提供しています。
(明確に言うと、上記の「入力」と「出力」は関数の構文プロパティに基づく簡略化された概念です。多くの言語は、参照/共有によるパラメーターへの引数の受け渡しをサポートし、ユーザーが呼び出し中に引数にエンコードされた情報を転送できるようにします。そのようなパラメータは、単に「入力/出力パラメータ」と呼ばれることさえあります。この機能は、呼び出しで渡されるオブジェクトの性質に基づいており、プロシージャ/関数の機能のプロパティと直交しています。)
ただし、関数呼び出しの結果が必要ない場合は、それを(少なくとも論理的に)無視できます。関数定義/関数呼び出しは、このようにプロシージャ定義/プロシージャ呼び出しと一致している必要があります。C、C ++、JavaなどのALGOLに似た言語はすべて、このように「関数」の機能を提供します。結果の型void
を従来のプロシージャのように見える関数の特殊なケースとしてエンコードすることにより、「プロシージャ」の機能を提供する必要はありません。 " 別々に。これにより、言語設計の肥大化を防ぎます。
SICPについて言及しているため、R n RSで指定されたScheme言語では、プロシージャが計算結果を返す必要がある場合と返さない場合があることに注意してください。これは、従来の「関数」(結果を返す)と「手続き」(何も返さない)の和集合であり、基本的には多くのALGOLのような言語の「関数」の概念と同じです(実際には、呼び出し前のオペランド)。ただし、SRFI-96のような規範的なドキュメントでも、昔ながらの違いがまだあります。
発散の背後にある正確な理由についてはあまり知りませんが、私が経験したように、言語デザイナーは今日、仕様の膨張なしで幸せになるようです。つまり、スタンドアロン機能としての「手順」は不要です。void
タイプのようなテクニックは、副作用が強調されるべき使用をマークするのにすでに十分です。これは、数十年以上人気のあるC言語のような言語での経験を持つユーザーにとってもより自然なものです。さらに、R n RSのように「プロシージャ」が実際にはより広い意味での「関数」である場合に、当惑を回避します。
理論的には、関数呼び出し結果のタイプとして特定の単位タイプを使用して関数を指定し、結果が特殊であることを示すことができます。これにより、従来の手順(呼び出しの結果に関心がない場合)が他の手順と区別されます。言語の設計にはさまざまなスタイルがあります。
#inert
)も動作します。void
ALGOLのような言語の型は、まさにこの手法の例です。ISO C11 _Noreturn
も似ていますが、この種類ではより微妙です。数学から派生した伝統的な概念として、多くの人が知らなくても気にしない多くの黒魔術があります。厳密に言えば、数学の本のようにすべてを明確にすることはできません。CSの本もあまり役に立たないかもしれません。
プログラミング言語に関しては、いくつかの警告があります。
{{{}}, {}}
...)として扱うようにするのは、限られたコンテキスト以外にも多かれ少なかれ同様に不合理です。InsideプロシージャではDML(Insert / Update / Delete)ステートメントを使用できますが、Inside関数ではDMLステートメントを使用できません。
プロシージャは両方の入力/出力パラメーターを持つことができますが、関数は入力パラメーターのみを持つことができます。
ストアドプロシージャでTry-Catchブロックを使用できますが、関数ではTry-Catchブロックを使用できません。
Selectステートメントではストアドプロシージャを使用できませんが、関数ではSelectステートメントで使用できます。
ストアドプロシージャは0またはnの値(最大1024)を返すことができますが、関数は必須である1つの値のみを返すことができます。
ストアドプロシージャは関数から呼び出すことはできませんが、ストアドプロシージャから関数を呼び出すことはできます。
ストアドプロシージャでトランザクションを使用できますが、関数ではトランザクションを使用できません。
Where / Having / selectセクションのSqlステートメントでストアドプロシージャを使用することはできませんが、関数では使用できます。
ストアドプロシージャに参加することはできませんが、関数に参加することはできます。
詳細については、ここをクリックしてください... http://dotnet-developers-cafe.blogspot.in/2013/08/difference-between-stored-procedure-and.html
関数は値を返し、プロシージャはコマンドを実行するだけです。
名前関数は数学に由来します。入力に基づいて値を計算するために使用されます。
プロシージャは、順番に実行できる一連のコマンドです。
ほとんどのプログラミング言語では、関数でさえ一連のコマンドを持つことができます。したがって、違いは値の部分を返すことだけです。
しかし、関数をクリーンに保ちたい場合(関数型言語を見てください)、関数に副作用がないことを確認する必要があります。
関数はSQLステートメント内で使用できますが、プロシージャはSQLステートメント内では使用できません。
Insert、Update、およびCreateステートメントを関数に含めることはできませんが、プロシージャはこれらのステートメントを持つことができます。
プロシージャはトランザクションをサポートしますが、関数はトランザクションをサポートしません。
関数は値を1つだけ返す必要があります(別の値はOUT変数で返すことができます)が、プロシージャは同じ数のデータセットと戻り値を返します。
関数とプロシージャの両方の実行プランがキャッシュされるため、どちらの場合もパフォーマンスは同じです。
私はこれらの答えのほとんどで何度も何度も何度も何度も見続けることに反対しています。関数を関数にするのは、それが値を返すことです。
関数は、値を返す古いメソッドだけではありません。そうではない:メソッドが実際の関数になるためには、常に特定の入力が与えられた場合と同じ値を返す必要があります。関数ではないメソッドの例として、random
ほとんどの言語のメソッドがあります。これは、値を返すものの、値が常に同じであるとは限らないためです。
したがって、関数はマップに似ています(たとえばx -> x'
、1次元関数の場合)。これは通常のメソッドと関数の非常に重要な違いです。実際の関数を処理する場合、タイミングと評価の順序は、非関数では常にそうであるとは限らないため、どこでも重要ではないためです。
次に、関数ではないが値を返すメソッドの別の例を示します。
// The following is pseudo code:
g(x) = {
if (morning()) {
g = 2 * x;
}
else {
g = x;
}
return g;
}
さらに、プロシージャは値を返さないという概念に反対します。プロシージャは、関数またはメソッドについて話す特定の方法にすぎません。つまり、プロシージャが定義または実装する基になるメソッドが値を返す場合、そのプロシージャが値を返すものを推測します。SICPから次のスニペットを例にとります。
// We can immediately translate this definition into a recursive procedure
// for computing Fibonacci numbers:
(define (fib n)
(cond ((= n 0) 0)
((= n 1) 1)
(else (+ (fib (- n 1))
(fib (- n 2))))))
最近、再帰的な手続きについて聞いたことがありますか?彼らは再帰関数(実際の関数)について話していて、それは値を返し、「手続き」という単語を使用しています。それでは、違いは何ですか?
(上記の意味以外に)関数のもう1つの考え方は、数字1のような理想の抽象的な表現です。手順は、その実際の実装です。個人的には互換性があると思います。
(注、私が提供するリンクからその章を読んだ場合、理解するのが難しい概念は、関数とプロシージャの違いではなく、プロセスとプロシージャの違いであることに気付くかもしれません。再帰プロシージャには、反復プロセス?)
手順の類似体はレシピです。例えば; make-pies
このマシンと呼ばれるマシンが成分を受け取り、(fruit, milk, flower, eggs, sugar, heat)
このマシンがを返すとしpie
ます。
このマシンの表現は次のようになります
make-pies (fruit, milk, flower, eggs, sugar, heat) = {
return (heat (add fruit (mix eggs flower milk)))
}
もちろん、パイを作る唯一の方法ではありません。
この場合、次のことがわかります。
A function is to a machine
as a procedure is to a recipe
as attributes are to ingredients
as output is to product
その類推は問題ありませんが、コンピュータプログラムを扱う場合、すべてが抽象的であることを考慮に入れると壊れます。したがって、レシピをマシンに送る場合とは異なり、抽象化されている2つのものを比較しています。同じかもしれない二つのこと。そして、私はそれらは(すべての意図と目的のために)同じものであると考えています。
С#/ Javaに関しては、関数は特定の値を返すコードのブロックですが、プロシージャはvoid(何もない)を返すコードのブロックです。C#/ Javaでは、関数とプロシージャの両方がメソッドと呼ばれることがよくあります。
//This is a function
public DateTime GetCurrentDate()
{
return DateTime.Now.Date;
}
//This is a procedure(always return void)
public void LogMessage()
{
Console.WriteLine("Just an example message.");
}
プロシージャ:1. プロシージャは、パラメータ化された計算を定義するステートメントのコレクションです。2.プロシージャは値を返すことができません。
3.プロシージャは関数から呼び出すことはできません。
関数 1. 関数は構造的に手順に似ていますが、意味的には数学関数に基づいてモデル化されています。2.値を返すことができます3.関数はプロシージャから呼び出すことができます。
プロシージャと関数はどちらもサブルーチンです。これらの唯一の違いは、プロシージャは複数の(または少なくとも実行可能な)値を返すのに対し、関数は1つの値しか返せないということです(これは、通常、1つの値しか見つからないため、数学で関数表記が使用される理由です)ある時点で)一部のプログラミング言語はこれらのルールに従っていないが、これはそれらの真の定義です
return
何もしません。あなたは両方について起こり得る副作用について話している(言語で許可されている場合)。