83

今日、私は純粋な関数について読んでいましたが、その使用法に混乱しました:

関数が同じ入力セットに対して同じ値セットを返し、目に見える副作用がない場合、その関数は純粋であると言われます。

たとえばstrlen()、 は純粋な関数rand()ですが、 は不純な関数です。

__attribute__ ((pure)) int fun(int i)
{
    return i*i;
}

int main()
{
    int i=10;
    printf("%d",fun(i));//outputs 100
    return 0;
}

http://ideone.com/33XJU

上記のプログラムは、pure宣言がない場合と同じように動作します。

pure[出力に変化がない場合]として関数を宣言する利点は何ですか?

4

6 に答える 6

146

pure関数について特定の最適化を行うことができることをコンパイラーに知らせます。次のようなコードを想像してください。

for (int i = 0; i < 1000; i++)
{
    printf("%d", fun(10));
}

fun(10)純粋な関数を使用すると、コンパイラは、1000 回ではなく、1 回だけ評価する必要があることを認識できます。複雑な関数の場合、これは大きなメリットです。

于 2012-06-22T09:48:38.393 に答える
34

関数が「純粋」であると言うときは、外部から見える副作用がないことを保証していることになります (コメントが言うように、嘘をつくと悪いことが起こる可能性があります)。関数が「純粋」であることを知ることは、コンパイラにとって利点があり、コンパイラはこの知識を使用して特定の最適化を行うことができます。

GCCのドキュメントpureが属性について述べていることは次のとおりです。

ピュア

多くの関数は戻り値以外には影響を与えず、それらの戻り値はパラメーターやグローバル変数のみに依存します。このような関数は、算術演算子と同様に、一般的な部分式の削除とループの最適化の対象となります。これらの関数は属性 pure で宣言する必要があります。例えば、

          int square (int) __attribute__ ((pure));

フィリップの答えは、関数が「純粋」であることを知ることがループの最適化にどのように役立つかをすでに示しています。

これは一般的な部分式の除去のためのものです (与えられたfooものは純粋です):

a = foo (99) * x + y;
b = foo (99) * x + z;

になることができる:

_tmp = foo (99) * x;
a = _tmp + y;
b = _tmp + z;
于 2012-06-22T09:49:19.873 に答える
29

実行時の利点に加えて、純関数はコードを読むときに推論するのがはるかに簡単です。さらに、戻り値はパラメーターの値のみに依存することがわかっているため、純粋な関数をテストする方がはるかに簡単です。

于 2012-06-22T09:56:18.780 に答える
15

非純粋関数

int foo(int x, int y) // possible side-effects

は純関数の拡張のようなものです

int bar(int x, int y) // guaranteed no side-effects

明示的な関数引数 x、y に加えて、残りの宇宙 (またはコンピューターが通信できるもの) を暗黙の潜在的な入力として持っています。同様に、明示的な整数の戻り値に加えて、コンピューターが書き込むことができるものはすべて、暗黙的に戻り値の一部になります。

非純粋な関数よりも純粋な関数について推論する方がはるかに簡単である理由は明らかです。

于 2012-06-22T15:08:37.497 に答える
4

一般に、純粋な関数には、コンパイラが利用できる非純粋な関数よりも 3 つの利点があります。

キャッシング

100000回呼び出されている純粋な関数fがあるとしましょう。これは決定論的であり、そのパラメーターのみに依存するため、コンパイラーはその値を一度計算し、必要に応じて使用できます

並列処理

純粋な関数は共有メモリの読み取りや書き込みを行わないため、予期しない結果を招くことなく個別のスレッドで実行できます

参照渡し

関数f(struct t)は引数tを値で取得します。一方、関数が純粋であると宣言されている場合、コンパイラは へのt参照渡しを行うことができますが、 の値が変更されず、パフォーマンスが向上することを保証します。ft


コンパイル時の考慮事項に加えて、純粋な関数は非常に簡単にテストできます。呼び出すだけです。

オブジェクトを作成したり、DB/ファイル システムへの接続をモックしたりする必要はありません。

于 2015-05-13T18:53:32.733 に答える