Funciones de primera clase

En informática , un lenguaje de programación tiene funciones de primera clase si trata las funciones como objetos de primera clase . En particular, esto significa que el lenguaje admite pasar funciones como argumentos a otras funciones, devolverlas como resultado de otras funciones, asignarlas a variables o almacenarlas en estructuras de datos [1] . Algunos teóricos de lenguajes de programación consideran necesario soportar también funciones anónimas [2] . En los lenguajes con funciones de primera clase, los nombres de las funciones no tienen un estatus especial, se tratan como valores normales cuyo tipo es una función [3] . El término fue utilizado por primera vez por Christopher Strachey en el contexto de "funciones como objetos de primera clase" a mediados de la década de 1960 [4] .

Las funciones de primera clase son una parte integral de la programación funcional , en la que el uso de funciones de orden superior es una práctica estándar. Un ejemplo simple de una función de orden superior sería la función Map , que toma una función y una lista como argumentos y devuelve la lista después de aplicar la función a cada elemento de la lista. Para que un lenguaje de programación admita Map , debe admitir funciones de paso como argumento.

Existen algunas dificultades para implementar pasar funciones como argumentos y devolverlas como resultados, especialmente en presencia de variables no locales introducidas en funciones anidadas y anidadas . Históricamente, se les ha llamado problemas funarg , del inglés "function argument" [5] . Los primeros lenguajes de programación imperativos solucionaron estos problemas eliminando el soporte para funciones de retorno como resultado, o eliminando funciones anidadas y, por lo tanto, variables no locales (particularmente C ). Lisp , uno de los primeros lenguajes de programación funcional, adopta un enfoque de alcance dinámico , donde las variables no locales devuelven la definición más cercana de esas variables al punto en el que se llamó a la función, en lugar del punto en el que se declaró. El soporte completo para el contexto léxico de las funciones de primer orden se introdujo en Scheme e implica tratar las referencias a funciones como cierres en lugar de puros [4] , lo que a su vez requiere el uso de recolección de basura .

Conceptos

Esta sección analiza cómo se implementan lenguajes de programación específicos en lenguajes funcionales con funciones de primer orden ( Haskell ) versus lenguajes imperativos donde las funciones son objetos de segundo orden ( C ).

Funciones de orden superior: pasar una función como argumento

En los lenguajes donde las funciones son objetos de primer orden, las funciones se pueden pasar como argumentos a otras funciones como cualquier otro valor. Entonces, por ejemplo, en Haskell :

mapa :: ( a -> b ) -> [ a ] ​​​​-> [ b ] mapa f [] = [] mapa f ( x : xs ) = f x : mapa f xs

Los lenguajes donde las funciones no son objetos de primer orden permiten implementar funciones de orden superior mediante el uso de delegados .

Los punteros en el lenguaje C , con algunas restricciones, le permiten crear funciones de orden superior (puede pasar y devolver la dirección de una función con nombre, pero no puede generar nuevas funciones):

mapa vacío ( int ( * f )( int ), int x [], size_t n ) { para ( int i = 0 ; i < n ; i ++ ) x [ yo ] = f ( x [ yo ]); }

Funciones anónimas y anidadas

En los lenguajes que admiten funciones anónimas, puede pasar una función de este tipo como argumento a una función de orden superior:

principal = mapa ( \ x -> 3 * x + 1 ) [ 1 , 2 , 3 , 4 , 5 ]

En idiomas que no admiten funciones anónimas, primero debe vincular la función al nombre:

int f ( int x ) { devuelve 3 * x + 1 ; } int principal () { internacional [] = { 1 , 2 , 3 , 4 , 5 } ; mapa ( f , l , 5 ); }

Variables no locales y cierres

Si un lenguaje de programación admite funciones anónimas o anidadas, es bastante lógico suponer que se referirán a variables fuera del cuerpo de la función:

principal = sea a = 3 b = 1 en el mapa ( \ x -> a * x + b ) [ 1 , 2 , 3 , 4 , 5 ]

Cuando las funciones se representan en forma pura, surge la pregunta de cómo pasar valores fuera del cuerpo de la función. En este caso, debe construir el cierre manualmente, y en esta etapa no es necesario hablar de funciones de primera clase.

estructura typedef { int ( * f )( int , int , int ); int * a ; int * b ; } cierre_t ; mapa vacío ( cierre_t * cierre , int x [], tamaño_t n ) { para ( int i = 0 ; i < n ; ++ i ) x [ i ] = ( * cierre -> f )( * cierre -> a , * cierre -> b , x [ i ]); } int f ( int a , int b , int x ) { devuelve a * x + b ; } vacío principal () { internacional [] = { 1 , 2 , 3 , 4 , 5 } ; int a = 3 ; int b = 1 ; cierre_t cierre = { f , &a , & b }; mapa ( & cierre , l , 5 ); }

Funciones de orden superior: funciones de retorno como resultado

Devolver una función en realidad devuelve su cierre. En el ejemplo de C, todas las variables locales encerradas en el cierre quedarán fuera del alcance tan pronto como regrese la función que constituye el cierre. Forzar el cierre más tarde puede conducir a un comportamiento indefinido.

Véase también

Notas

  1. Abelson, Haroldo ; Sussman, Gerald Jay Estructura e Interpretación de Programas de Computador  (Inglés) . - MIT Press , 1984. - P. Sección 1.3 Formulación de abstracciones con procedimientos de orden superior . - ISBN 0-262-01077-1 .
  2. Pragmática del lenguaje de programación , por Michael Lee Scott, sección 11.2 "Programación funcional".
  3. Roberto Ierusalimschy; Luiz Henrique de Figueiredo; Waldemar Celes. La implementación de Lua 5.0  (neopr.) . Archivado desde el original el 23 de junio de 2017.
  4. 1 2 Rod Burstall, "Christopher Strachey: comprensión de los lenguajes de programación", Computación simbólica y de orden superior 13:52 ( 2000)
  5. Joel Moisés . "La función de FUNCIÓN en LISP, o por qué el problema de FUNARG debería llamarse problema del entorno" Archivado el 3 de abril de 2015 en Wayback Machine . Memo AI 199 del MIT, 1970.

Literatura

Enlaces