En programación informática , una función pura es una función que tiene las siguientes propiedades: [ 1 ] [ 2 ]
- Los valores de retorno de la función son idénticos para argumentos idénticos (sin variación con variables estáticas locales , variables no locales , argumentos de referencia mutables o flujos de entrada , es decir, transparencia referencial ), y
- La función no tiene efectos secundarios (no modifica variables no locales, argumentos de referencia mutables ni flujos de entrada/salida).
Ejemplos
funciones puras
Los siguientes ejemplos de funciones de C++ son puros:
floor, devolviendo el piso de un número;max, devolviendo el máximo de dos valores.- la función f , definida como El valor de
void f () { static std :: atomic < unsigned int > x = 0 ; ++ x ; }
xsolo puede observarse dentro de otras invocaciones def(), y comof()no comunica el valor dexa su entorno, es indistinguible de una funciónvoid f() {}que no hace nada. Nótese quexesstd::atomicpara que las modificaciones de múltiples subprocesos que se ejecutanf()concurrentemente no resulten en una condición de carrera de datos , que tiene un comportamiento indefinido en C y C++.
Funciones impuras
Las siguientes funciones de C++ son impuras ya que carecen de la propiedad 1 mencionada anteriormente:
- debido a la variación del valor de retorno con una variable estática
int f () { static int x = 0 ; ++ x ; return x ; }
- debido a la variación del valor de retorno con una variable no local Por la misma razón, por ejemplo, la función de la biblioteca de C++
int f () { return x ; }
sin()no es pura, ya que su resultado depende del modo de redondeo IEEE , que puede cambiarse en tiempo de ejecución. - debido a la variación del valor de retorno con un argumento de referencia mutable
int f ( int * x ) { return * x ; }
- debido a la variación del valor de retorno con una secuencia de entrada
int f () { int x = 0 ; std :: cin >> x ; return x ; }
Las siguientes funciones de C++ son impuras ya que carecen de la propiedad 2 mencionada anteriormente:
- debido a la mutación de una variable estática local
void f () { static int x = 0 ; ++ x ; }
- debido a la mutación de una variable no local
void f () { ++ x ; }
- debido a la mutación de un argumento de referencia mutable
void f ( int * x ) { ++* x ; }
- debido a la mutación de un flujo de salida
void f () { std :: cout << "¡Hola, mundo!" << std :: endl ; }
Las siguientes funciones de C++ son impuras ya que carecen de las propiedades 1 y 2 mencionadas anteriormente:
- debido a la variación del valor de retorno con una variable estática local y la mutación de una variable estática local.
int f () { static int x = 0 ; ++ x ; return x ; }
- debido a la variación del valor de retorno con un flujo de entrada y la mutación de un flujo de entrada
int f () { int x = 0 ; std :: cin >> x ; return x ; }
E/S en funciones puras
La E/S es inherentemente impura: las operaciones de entrada socavan la transparencia referencial y las de salida generan efectos secundarios. Sin embargo, en cierto sentido, una función puede realizar operaciones de entrada o salida y seguir siendo pura si la secuencia de operaciones en los dispositivos de E/S relevantes se modela explícitamente como argumento y resultado, y se considera que las operaciones de E/S fallan cuando la secuencia de entrada no describe las operaciones realizadas desde que comenzó la ejecución del programa.
El segundo punto garantiza que la única secuencia utilizable como argumento debe cambiar con cada acción de E/S; el primero permite que diferentes llamadas a una función que realiza operaciones de E/S devuelvan resultados diferentes debido a que los argumentos de la secuencia han cambiado. [ 3 ] [ 4 ]
La mónada de E/S es un modismo de programación que se utiliza habitualmente para realizar operaciones de entrada/salida en lenguajes puramente funcionales.
Memorización
Los resultados de una función pura se pueden almacenar en caché en una tabla de búsqueda. Cualquier resultado que devuelva una función determinada se almacena en caché, y la próxima vez que se llame a la función con los mismos parámetros de entrada, se devolverá el resultado almacenado en caché en lugar de volver a calcular la función.
La memorización se puede realizar envolviendo la función en otra función ( función contenedora ). [ 5 ]
Mediante la memorización, se puede reducir el esfuerzo computacional que implican los cálculos de la propia función, a costa de la sobrecarga que supone la gestión de la caché y un aumento de los requisitos de memoria.
Un programa en C para el cálculo en caché del factorial ( assert()se interrumpe con un mensaje de error si su argumento es falso; en una máquina de 32 bits, fact(12)no se pueden representar valores más allá de ese valor. [ 6 ] )
static int fact ( int n ) { return n <= 1 ? 1 : fact ( n - 1 ) * n ; }int fact_wrapper ( int n ) { static int cache [ 13 ]; assert ( 0 <= n && n < 13 ); if ( cache [ n ] == 0 ) cache [ n ] = fact ( n ); return cache [ n ]; }Optimizaciones del compilador
Las funciones que poseen únicamente la propiedad 2 mencionada anteriormente —es decir, que no tienen efectos secundarios— permiten técnicas de optimización del compilador, como la eliminación de subexpresiones comunes y la optimización de bucles similar a la de los operadores aritméticos. [ 7 ] Un ejemplo en C++ es el lengthmétodo que devuelve el tamaño de una cadena, el cual depende del contenido de la memoria a la que apunta la cadena, por lo que carece de la propiedad 1 mencionada anteriormente. Sin embargo, en un entorno de un solo hilo , el siguiente código C++
std :: string s = "¡Hola, mundo!" ; int a [ 10 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; int l = 0 ;for ( int i = 0 ; i < 10 ; ++ i ) { l += s . length () + a [ i ]; }se puede optimizar de tal manera que el valor s.length()se calcule solo una vez, antes del bucle.
Algunos lenguajes de programación permiten declarar una propiedad pura a una función:
- En Fortran y D, la
purepalabra clave se puede usar para declarar una función que no tenga efectos secundarios (es decir, que solo tenga la propiedad 2 anterior). [ 8 ] El compilador puede deducir la propiedad 1 a partir de la declaración. [ 9 ] Véase también: Características del lenguaje Fortran 95 § Procedimientos puros . - En GCC , el
pureatributo especifica la propiedad 2, mientras que elconstatributo especifica una función verdaderamente pura con ambas propiedades. [ 10 ] - Los lenguajes que ofrecen ejecución de funciones en tiempo de compilación pueden requerir que las funciones sean puras, a veces con la adición de otras restricciones. Ejemplos incluyen
constexprC++ (ambas propiedades). [ 11 ] Véase también: C++11 § constexpr – Expresiones constantes generalizadas .
Pruebas unitarias
Dado que las funciones puras tienen valores de retorno idénticos para argumentos idénticos , son muy adecuadas para las pruebas unitarias .
Véase también
- Ejecución de funciones en tiempo de compilación : la evaluación de funciones puras en tiempo de compilación.
- Algoritmo determinista : Algoritmo que, dada una entrada particular, siempre producirá la misma salida.
- Idempotencia – Propiedad de las operaciones por la cual pueden aplicarse varias veces sin cambiar el resultado.
- Cálculo lambda – Sistema matemático-lógico
- Estructura de datos puramente funcional : estructura de datos implementable en lenguajes puramente funcionales.
- Reentrada (informática) : Ejecutar una función simultáneamente sin interferir con otras invocaciones.
Referencias
- ↑ Bartosz Milewski (2013). "Fundamentos de Haskell" . Escuela de Haskell . FP Complete. Archivado del original el 27 de octubre de 2016. Consultado el 13 de julio de 2018 .
- ↑ Brian Lonsdorf (2015). "Guía bastante adecuada del profesor Frisby para la programación funcional" . GitHub . Consultado el 20 de marzo de 2020 .
- ↑ Peyton Jones, Simon L. (2003). Haskell 98 Language and Libraries: The Revised Report (PDF) . Cambridge, Reino Unido: Cambridge University Press. pág. 95. ISBN 0-521 826144Consultado el 17 de julio de 2014 .
- ^ Hanus, Michael. "Curry: un lenguaje lógico funcional integrado" (PDF) . www-ps.informatik.uni-kiel.de . Institut für Informatik, Christian-Albrechts-Universität zu Kiel. pag. 33. Archivado desde el original (PDF) el 25 de julio de 2014 . Consultado el 17 de julio de 2014 .
- ↑ Aley, R. (2017). Programación PHP funcional profesional: Estrategias de desarrollo de aplicaciones para la optimización del rendimiento, la concurrencia, la capacidad de prueba y la brevedad del código . SpringerLink : Bücher. Apress. pág. 109. ISBN 978-1-4842-2958-3. Consultado el 04-02-2024 .
- ↑ "Tengo un resultado incorrecto para el factorial de 13, ¿cómo lo soluciono?" . Stack Overflow . Consultado el 24 de septiembre de 2025 .
- ↑ "Atributos de funciones comunes: uso de la colección de compiladores GNU (GCC)" . gcc.gnu.org, la colección de compiladores GNU . Free Software Foundation, Inc. Consultado el 28 de junio de 2018 .
- ↑ Atributo puro en Fortran
- ↑ Atributo puro en el lenguaje D
- ↑ "Atributos de funciones comunes" . Uso de la colección de compiladores GNU (GCC ). Consultado el 22 de julio de 2021 .
- ↑ atributo constexpr en C++
- Programación funcional
- Subrutinas