5

TDPL、p。167:

関数の変更可能な状態が完全に一時的(つまり、スタックに割り当てられている) かつプライベート(つまり、それを汚染する可能性のある関数への参照によって渡されない) である限り、その関数は純粋であると見なすことができます。

import std.stdio : writeln;

struct M{
  int[4] _data;

  pure ref int opIndex(size_t i){ return _data[i]; }
}

pure M foo(ref M m){

  m[0] = 1234;
  return m;
}

void main(){

  M m1 = M([7, 7, 7, 7]);

  writeln(m1);
  foo(m1);
  writeln(m1);
}

// output:
// M([7, 7, 7, 7])
// M([1234, 7, 7, 7])

スタック上にあるため、変更可能な状態は一時的ですよね?しかし、それはプライベートではありません。では、どのようfoo()に変更できるのm1でしょうか?

4

2 に答える 2

6

purepureTDPL が説明するように、単純な数学関数などを超えて有用であるにはあまりにも制限的であることが判明したため、TDPL のリリース以降、少し拡張されました。現在の定義についてはオンライン ドキュメントを参照できますが、基本的には次のようになります。

  1. pure関数は、プログラムの過程で変更できるモジュールレベルまたは静的変数にアクセスできません (それらはconst値型であるかimmutable、関数からアクセスする必要がありpureます)。

  2. pure関数は、そうでない関数を呼び出すことはできませんpure

  3. pure関数は I/O を実行できません。

それでおしまい。その他の制限はありません。ただし、関数がステートメント内で複数回使用されても 1 回だけ呼び出されるように関数を最適化する場合、追加の制限が必要です。pureすなわち:

  • 関数のパラメーターは、immutableまたは暗黙的に に変換可能でなければなりませんimmutable

理論的には、関数の引数immutable暗黙的に変換可能である必要があることを要求するように拡張できますimmutable(引数が指定されたときにパラメーターを持つ関数をconst最適化できるようにするためimmutable) が、現在はそうではありません。

このようなpure関数は "strongly" と呼ばれるpureことがありますが、最適化できない関数は "weakly" と呼ばれpureます。TDPL はpure機能を強力に記述します。より一般的に使用できるpureようにするために、weakly関数が追加されました。pure

弱いpure関数引数を変更できますが、グローバル状態を変更することはできません。そのため、強力pureな関数 (引数を変更できないpure) によって呼び出された場合、強力な関数の戻り値が常に同じであることを保証します。引数はまだ保持されます。基本的に、weaklypure関数はグローバル状態を変更できないため、pure呼び出し元の strong 関数のプライベート状態の一部になります。したがって、関数のプライベート状態が拡張され、グローバル状態を変更せずにプライベート状態を変更できる関数を許可することを除いて、 Andrei がセクション5.11.1.1purepure説明していることと非常に一致しています。

TDPL に関して追加されたもう 1 つの重要な点pureは、関数属性の推論です。purenothrow、および@safeは、テンプレート化された関数に対して推論されます (通常の関数に対してではありません)。したがって、テンプレート化された関数である場合pure、現在は です pure。その純度は、インスタンス化されたものによって異なります。これで、pureテンプレート化された関数で使用できるようになりましたが、以前は通常使用できませんでしたpure。でも作らないpureと関数で使えないpureので大問題でした。pure. 幸いなことに、属性の推論によって修正されるようになりました。テンプレート化された関数がインスタンス化時に上記のルールに従っている限り、それは と見なされpureます。

于 2011-12-20T08:57:57.697 に答える
5

this参照は関数のパラメーターの一部と見なされ、関数は弱純粋であるため、パラメーターを変更できます。入力の一部と見なされる状態でthis、関数は同じ入力で同じ出力を持つという条件を満たします。

を出力するこの完全に正当な例を考えてみましょう2:

import std.stdio : writeln;

struct S
{
    int foo = 0;
    pure void set(size_t i){ foo = i; }
}


void main()
{
    S s;
    s.set(2);
    writeln(s.foo);
}

私の知る限り、TDPL がリリースされた後、ピュアの定義が拡張されました。この本では、強純粋関数について説明しています。その後、2 つの開発が行われました。パラメータを変更できる弱純粋関数が追加されました。また、テンプレート関数が で装飾されていなくても、純粋である限り、テンプレート関数のインスタンス化を使用できるように、テンプレート関数に純度推論が追加されましたpure

于 2011-12-20T08:13:55.533 に答える