Articulo de referencia

Función pura

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 argumento...

En programación informática , una función pura es una función que tiene las siguientes propiedades: [ 1 ] [ 2 ]

  1. 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
  2. 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
    void f () { static std :: atomic < unsigned int > x = 0 ; ++ x ; }
    El valor de xsolo puede observarse dentro de otras invocaciones de f(), y como f()no comunica el valor de xa su entorno, es indistinguible de una función void f() {}que no hace nada. Nótese que xes std::atomicpara que las modificaciones de múltiples subprocesos que se ejecutan f()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
    int f () { return x ; }
    Por la misma razón, por ejemplo, la función de la biblioteca de C++ 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:

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

Referencias

  1. 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 .
  2. Brian Lonsdorf (2015). "Guía bastante adecuada del profesor Frisby para la programación funcional" . GitHub . Consultado el 20 de marzo de 2020 .
  3. 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 .
  4. ^ 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 . 
  5. 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 .
  6. "Tengo un resultado incorrecto para el factorial de 13, ¿cómo lo soluciono?" . Stack Overflow . Consultado el 24 de septiembre de 2025 .
  7. "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 .
  8. Atributo puro en Fortran
  9. Atributo puro en el lenguaje D
  10. "Atributos de funciones comunes" . Uso de la colección de compiladores GNU (GCC ). Consultado el 22 de julio de 2021 .
  11. atributo constexpr en C++