2011-12-20 14 views
5

TDPL, p. 167:¿Cómo es que esta función pura puede modificar el estado no privado?

siempre que el estado mutable en una función es totalmente transitoria (es decir, asignado en la pila) y privado (es decir, no se pasa a lo largo de por referencia a funciones que pueden manchar ella), entonces la función puede considerarse pura.

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

El estado mutable es transitorio porque está en la pila, ¿correcto? Pero no es privado. Entonces, ¿cómo se permite foo() modificar m1?

+0

He intentado limpiar la etiqueta [tag: pure], porque a veces se refiere a funciones virtuales puras, a veces a [puro] (http://beebole.com/pure/) y a veces a [pure ] (http://en.wikipedia.org/wiki/Pure_ (programming_language)) - entre otros. Pero no sé nada sobre [tag: d]. ¿Podría confirmar si la edición de mi etiqueta es apropiada? ¿Funcionaría [tag: puramente funcional] para esta pregunta? Creé [tag: pure-function], así que si [tag: pure-functional] funciona, creo que sería mejor usar la etiqueta existente. –

+0

@RichardJPLeGuen Pure como en [pureza funcional] (http://en.wikipedia.org/wiki/Pure_function), por lo que pure-function funcionaría para esta pregunta. puramente funcional, no tanto. – Arlen

+0

Gracias, @Arlen! –

Respuesta

6

pure se ha ampliado un poco desde el lanzamiento de TDPL, desde pure como TDPL describe resulta demasiado restrictivo para ser útil más allá de las funciones matemáticas simples y similares. Se puede ver en the online documentation para la definición actual, pero en esencia se reduce a esto:

  1. pure funciones no pueden acceder a cualquier nivel de módulo o variables estáticas que pueden ser mutados durante el transcurso del programa (que debe haber const tipos de valor o immutable para acceder desde una función pure).

  2. pure funciones no pueden llamar a ninguna función que no sea pure.

  3. pure funciones no pueden realizar E/S.

Eso es todo. No hay otras restricciones Sin embargo, hay son restricciones adicionales requeridas si se va a optimizar una función pure de modo que solo se llame una vez, incluso si se usa varias veces dentro de una instrucción. A saber:

  • parámetros de la función debe ser immutable o implícitamente convertible en immutable.

En teoría que podría ampliarse a exigir que argumentos de la función deben ser immutable o implícitamente convertible en immutable (de modo que una función con const parámetros podría optimizarse cuando se administra immutable argumentos), pero eso no es actualmente el caso.

Tales funciones de pure a veces se denominan "fuertemente" pure, mientras que aquellas que no se pueden optimizar se conocen como "débilmente" pure. TDPL describe fuertemente las funciones pure. Débilmente se agregaron pure funciones para hacer que pure se pueda usar de manera más general.

Mientras débilmente pure funciones pueden alterar sus argumentos, no pueden alterar el estado global, por lo que cuando son llamados por pure fuertemente funciones (que no puede alterar sus argumentos), la garantía de que el fuerte pure El valor de retorno de la función siempre será el mismo para los mismos argumentos que aún se mantienen. Esencialmente, debido a que las funciones débiles pure no pueden mutar el estado global, son parte del estado privado de la función fuertemente pure a partir de la cual son llamadas. Por lo tanto, está muy alineado con lo que describe Andrei en la sección 5.11.1.1 pure es pure Tiene en TDPL, excepto que el estado privado de la función se ha expandido para permitir funciones que pueden alterar su estado privado sin alterar el estado global .

Otra cosa importante de la nota que se ha agregado desde TDPL con respecto a pure es la inferencia del atributo de la función. pure, nothrow y @safe se deducen para las funciones de plantilla (aunque no para las funciones normales). Entonces, si una función de plantilla puede ser pure, ahora es espure. Su pureza depende de con qué se crea una instancia. Entonces, es posible usar pure con funciones de plantilla, mientras que antes, por lo general no se podía, porque si lo hacía pure, no funcionaría con una función impura. Pero si no lo hizo hacerlo pure, entonces no podría usarlo con una función pure, por lo que era un problema importante para pure. Afortunadamente, atribuimos correcciones de inferencia que ahora sí. Siempre que una función de plantilla siga las reglas enumeradas anteriormente cuando se crea una instancia, entonces se considera pure.

+0

Creo que tendré que dejar que esto se hunda y me acostumbre a cosas como 'puro vacío opIndexAssign (valor T, tamaño_t i) {...}' y 'puro T opIndex (tamaño_t i) const {...} ' – Arlen

+0

Solo piense en 'puro', lo que significa que la función no puede acceder al estado global mutable, y luego permita que el compilador lo optimice cuando pueda. Sí, el modificador 'puro' termina en más funciones que aquellas que son funcionalmente 'puras', pero _es_ todavía lo que hace que las funciones funcionalmente' puras' sean posibles y posibles de optimizar. –

5

La referencia this se considera parte de los parámetros de la función, y como la función es débilmente pura, puede modificar los parámetros. Con el estado de this considerado parte de la entrada, la función todavía cumple la condición de tener la misma salida con la misma entrada.

Considere este ejemplo completamente legal, que da salida a 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); 
} 

Por lo que yo sé, después de TDPL fue puesto en libertad, se amplió la definición de puros. El libro describe funciones fuertemente puras. Después de eso, se han producido dos desarrollos: se agregaron funciones débilmente puras, que pueden cambiar sus parámetros. Además, se ha agregado la inferencia de pureza para las funciones de plantilla para que pueda usar la creación de instancias de una función de plantilla siempre que sea pura incluso si la función de plantilla no está decorada con pure.

Cuestiones relacionadas