这个纯函数如何能够修改非私有状态?

发布于 2024-12-21 22:54:07 字数 554 浏览 0 评论 0原文

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 呢?

TDPL, p. 167:

as long as the mutable state in a function is entirely transitory (i.e., allocated on the stack) and private (i.e., not passed along by reference to functions that may taint it), then the function can be considered pure.

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])

The mutable state is transitory because it's on the stack, correct? But it's not private. So how is foo() allowed to modify m1?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

琴流音 2024-12-28 22:54:07

自 TDPL 发布以来,pure 已经得到了一些扩展,因为 TDPL 所描述的 pure 被证明限制性太大,除了简单的数学函数等之外没有什么用处。您可以查看在线文档了解当前的定义,但它本质上可以归结为:

  1. 函数不能访问任何在程序运行过程中可能发生变化的模块级或静态变量(它们必须是const值类型或不可变)代码> 可以从pure 函数)。

  2. pure 函数无法调用任何非 pure 的函数。

  3. pure 函数无法执行 I/O。

就是这样。没有其他限制。但是,如果要优化pure 函数,使其仅被调用一次,即使它在一条语句中使用多次, 还需要额外的限制。即:

  • 函数的参数必须是不可变或者可以隐式转换为不可变

理论上,这可以扩展为要求函数的参数必须是不可变的或隐式转换为不可变的(以便具有 的函数const 参数在给定不可变 参数时可以进行优化),但目前情况并非如此。

此类函数有时被称为“强”,而那些无法优化的函数则被称为“弱”。 TDPL 强烈描述了函数。添加了弱pure 函数,以使pure 更通用。

虽然弱pure函数可以改变它们的参数,但它们不能改变全局状态,所以当它们被强pure函数(其中< em>不能改变它们的参数),对于相同的参数,强pure函数的返回值始终相同的保证仍然成立。本质上,由于弱pure 函数无法改变全局状态,因此它们是调用它们的强pure 函数的私有状态的一部分。因此,它非常符合 Andrei 在第 5.11.1.1 节中描述的内容 pure 与 TDPL 中的 pure 的作用不同,除了私有状态该函数的功能已扩展为允许可以在不改变全局状态的情况下改变其私有状态的函数。

自 TDPL 以来添加的关于 pure 的另一个重要事项是函数属性推断。 purenothrow@safe 是针对模板化函数进行推断的(尽管对于普通函数而言不是)。因此,如果模板化函数可以,那么现在它。它的纯度取决于它的实例化内容。因此,可以将 pure 与模板化函数一起使用,而以前,您通常不能这样做,因为如果将其设为 pure,它就无法与不纯的函数一起使用功能。但是,如果您没有使其pure,那么您就无法将其与pure函数一起使用,所以这对于pure来说是一个主要问题。幸运的是,属性推断现在解决了这个问题。只要模板化函数在实例化时遵循上面列出的规则,那么它就被认为是

pure has been expanded a bit since the release of TDPL, since pure as TDPL describes turns out to be far too restrictive to be useful beyond simple math functions and the like. You can look at the online documentation for the current definition, but it essentially comes down to this:

  1. pure functions cannot access any module-level or static variables which can be mutated during the course of the program (they must be const value types or immutable to be accessed from a pure function).

  2. pure functions cannot call any functions which are not pure.

  3. pure functions cannot perform I/O.

That's it. There are no other restrictions. However, there are additional restrictions required if a pure function is going to be optimized such that it only gets called one time even if it's used multiple times within a statement. Namely:

  • The function's parameters must be immutable or implicitly convertible to immutable.

In theory that could be expanded to requiring that the function's arguments must be immutable or implicitly convertible to immutable (so that a function with const parameters could be optimized when it's given immutable arguments), but that's not currently the case.

Such pure functions are sometimes referred to as "strongly" pure, whereas those which cannot be optimized would be referred to as "weakly" pure. TDPL describes strongly pure functions. Weakly pure functions were added in order to make pure more generally usable.

While weakly pure functions can alter their arguments, they cannot alter the global state, so when they're called by strongly pure functions (which can't alter their arguments), the guarantee that the strongly pure function's return value will always be the same for the same arguments still holds. Essentially, because the weakly pure functions cannot mutate global state, they're part of the private state of the strongly pure function that they're called from. So, it's very much in line with what Andrei describes in section 5.11.1.1 pure is as pure Does in TDPL, except that the private state of the function has been expanded to allow functions which can alter its private state without altering global state.

Another major thing of note which has been added since TDPL with regards to pure is function attribute inference. pure, nothrow, and @safe are inferred for templated functions (though not for normal functions). So, if a templated function can be pure, now it is pure. Its purity depends on what it's instantiated with. So, it becomes possible to use pure with templated functions, whereas before, you usually couldn't, because if you made it pure, it wouldn't work with an impure function. But if you didn't make it pure, then you couldn't use it with a pure function, so it was a major problem for pure. Fortunately, attribute inference fixes that now though. As long as a templated function follows the rules listed above when it's instantiated, then it's considered pure.

生活了然无味 2024-12-28 22:54:07

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 发布后,pure 的定义得到了扩展。本书描述了强纯函数。之后,发生了两项发展:添加了弱纯函数,允许改变其参数。此外,还为模板函数添加了纯度推断,以便您可以使用模板函数的实例化,只要它是纯的,即使模板函数没有用 pure 修饰。

The this reference is considered part of the function's parameters, and since the function is weakly pure, you can modify the parameters. With the state of this considered part of the input, the function still fulfills the condition of having the same output with the same input.

Consider this entirely legal example, which outputs 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);
}

As far as I know, after TDPL was released, the definition of pure was expanded. The book describes strongly-pure functions. After that, two developments have taken place: weakly-pure functions were added, which are allowed to mutate their parameters. Also, purity-inference has been added for template functions so that you can use a template function's instantiation as long as it's pure even if the template function isn't decorated with pure.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文