En los lenguajes de programación Lisp , una fexpr es una función cuyos operandos se le pasan sin ser evaluados. Cuando se llama a una fexpr, solo se evalúa su cuerpo; no se realizan otras evaluaciones salvo cuando la fexpr las inicia explícitamente. En cambio, cuando se llama a una función Lisp ordinaria, los operandos se evalúan automáticamente y solo se proporcionan a la función los resultados de dichas evaluaciones; y cuando se llama a una macro Lisp (tradicional) , los operandos se pasan sin evaluar, pero el resultado que devuelve la macro se evalúa automáticamente.
Origen del nombre "fexpr"
En las primeras versiones de Lisp, el entorno asignaba cada símbolo a una lista de asociación , en lugar de directamente a un valor. [ 1 ] Las claves estándar para estas listas incluían dos claves utilizadas para almacenar un valor de datos, que se buscaba cuando el símbolo aparecía como argumento ( APVAL y APVAL1 ); y cuatro claves utilizadas para almacenar una función, que se buscaba cuando el símbolo aparecía como operador. De las claves de función, SUBR indicaba una función ordinaria compilada, cuyos operandos se evaluaban y se le pasaban; FSUBR indicaba una forma especial compilada, cuyos operandos se pasaban sin evaluar; EXPR indicaba una función ordinaria definida por el usuario; y FEXPR indicaba una forma especial definida por el usuario. La única diferencia entre una FEXPR y una EXPR era si los operandos se evaluaban automáticamente.
En su uso original estricto, una FEXPR es, por lo tanto, una función definida por el usuario cuyos operandos se pasan sin evaluar. Sin embargo, en usos posteriores, el término fexpr puede describir cualquier función de primera clase cuyos operandos se pasan sin evaluar, independientemente de si la función es primitiva o definida por el usuario. [ 2 ]
Ejemplo
Como ejemplo sencillo de cómo funcionan las fexprs, aquí tenemos una definición de fexpr escrita en el lenguaje de programación Kernel , similar a Scheme . (Por convención en Kernel, los nombres de las fexprs siempre empiezan con $ ).
( $definir! $f ( $vau ( x y z ) e ( $if ( >=? ( eval x e ) 0 ) ( eval y e ) ( eval z e ))))Esta definición proporciona una expresión funcional llamada $f , que toma tres operandos. Cuando se llama a la expresión funcional, se crea un entorno local extendiendo el entorno estático donde se definió. Luego se crean enlaces locales: los símbolos x , y y z se enlazan a los tres operandos de la llamada a la expresión funcional, y el símbolo e se enlaza al entorno dinámico desde el que se llama a la expresión funcional. El cuerpo de la expresión funcional, ($if ... ) , se evalúa en este entorno local, y el resultado de esa evaluación se convierte en el resultado de la llamada a la expresión funcional. El efecto neto es que el primer operando se evalúa en el entorno dinámico y, dependiendo de si el resultado de esa evaluación es no negativo, se evalúa el segundo o el tercer operando y se devuelve ese resultado. El otro operando, ya sea el tercero o el segundo, no se evalúa.
Este ejemplo tiene un ámbito estático : el entorno local es una extensión del entorno estático. Antes de 1980, los lenguajes Lisp que admitían fexprs tenían principalmente un ámbito dinámico: el entorno local era una extensión del entorno dinámico, en lugar del estático. [ 3 ] Sin embargo, a veces seguía siendo necesario proporcionar un nombre local para el entorno dinámico, para evitar capturar los nombres de los parámetros locales. [ 4 ]
Uso generalizado y desuso
El soporte para fexpr continuó en Lisp 1.5 , el último dialecto sustancialmente estándar de Lisp antes de que se fragmentara en múltiples lenguajes. [ 5 ] En la década de 1970, los dos lenguajes Lisp dominantes [ 6 ] — MacLisp e Interlisp — ambos soportaban fexprs. [ 7 ]
En la Conferencia de 1980 sobre Lisp y Programación Funcional , Kent Pitman presentó un artículo titulado "Formas especiales en Lisp", en el que analizó las ventajas y desventajas de las macros y las fexprs, y finalmente las desaconsejó. Su principal objeción era que, en un dialecto de Lisp que permite fexprs, el análisis estático no puede determinar de forma general si un operador representa una función ordinaria o una fexpr ; por lo tanto, no puede determinar si los operandos se evaluarán o no. En particular, el compilador no puede saber si una subexpresión se puede optimizar de forma segura, ya que podría tratarse como datos no evaluados en tiempo de ejecución.
Las MACRO ofrecen un mecanismo adecuado para especificar definiciones de formas especiales y... las FEXPR no. ... Se sugiere que, en el diseño de futuros dialectos de Lisp, se debería considerar seriamente la propuesta de omitir por completo las FEXPR del lenguaje . [ 8 ]
Desde el declive de MacLisp e Interlisp, los dos lenguajes Lisp que habían alcanzado el dominio en 1993 [ 9 ] — Scheme y Common Lisp — no admiten fexprs. newLISP sí admite fexprs, pero las llama "macros". En Picolisp, todas las funciones integradas son fsubrs , mientras que las funciones de nivel Lisp son exprs, fexprs, lexprs o una mezcla de estas.
Fexprs desde 1980
A partir del 3-Lisp de Brian Smith en 1982, se han ideado varios dialectos experimentales de Lisp para explorar los límites de la reflexión computacional . Para admitir la reflexión, estos Lisp admiten procedimientos que pueden reificar diversas estructuras de datos relacionadas con la llamada a los mismos , incluidos los operandos no evaluados de la llamada, lo que convierte a estos procedimientos en fexprs. A finales de la década de 1990, los fexprs se asociaron principalmente con la reflexión computacional. [ 10 ]
Se han obtenido algunos resultados teóricos sobre fexprs. En 1993, John C. Mitchell utilizó Lisp con fexprs como ejemplo de un lenguaje de programación cuyas expresiones fuente no pueden ser formalmente abstractas (porque la sintaxis concreta de una expresión fuente siempre puede extraerse de un contexto en el que sea un operando de un fexpr). [ 11 ] En 1998, Mitchell Wand demostró que añadir un dispositivo fexpr al cálculo lambda —un dispositivo que suprime la reescritura de operandos— produce un sistema formal con una teoría ecuacional trivial , lo que hace imposible realizar optimizaciones de fuente a fuente sin un análisis de todo el programa . [ 10 ] En 2007, John N. Shutt propuso una extensión del cálculo lambda que modelaría fexprs sin suprimir la reescritura de operandos, evitando potencialmente el resultado de Wand. [ 12 ]
Véase también
Los siguientes lenguajes implementan fexprs o equivalentes cercanos:
- El lenguaje de programación ECL proporciona un tipo de parámetro ("bind-class")
UNEVAL, que especifica que se debe vincular un árbol de sintaxis para la expresión del argumento al parámetro. - io , los métodos (bloques) pueden usar introspección, usándola
callpara referirse a toda la llamada y manipularla. Consulte las ranuras call y self en io . - El kernel se utiliza
$vaupara crear fexprs, de forma similar a comolambdase crean funciones en Scheme . - newLISP se utiliza
define-macropara definir fexprs. Consulte la sección "Macros Fexpr y macros de reescritura" . - En PicoLisp ,
(de foo X ...)define una fexprfooque, al ser llamada, se vinculaXa la lista de expresiones de argumentos no evaluadas. Véase Evaluación en PicoLisp . - Los parámetros de R generalmente están vinculados a promesas (lo que resulta en una evaluación perezosa ), y al llamar
substitute(param)a un parámetro se obtiene la expresión del argumento, consulte Sustituciones en R. - En REBOL , las expresiones de argumentos que no se evalúan deben ir entre corchetes por quien llama a la función. En otras palabras, no se puede definir una función llamada que impida la evaluación de argumentos. Consulte este artículo con ejemplos. En este sentido, REBOL no tiene fexprs, simplemente facilita la emulación de algunos de sus usos. En un lenguaje con fexprs propiamente dichas, las llamadas a fexprs se comportan como llamadas a funciones normales. En REBOL, en cambio, las llamadas donde los argumentos no se evalúan siempre se comportan de forma diferente a las llamadas a funciones normales.
Notas a pie de página
- ↑ McCarthy et al., Manual del programador de Lisp I , págs. 88 – 91.
- ↑ Pitman, The Revised MacLisp Manual , pág. 75.
- ↑ Steele y Gabriel, "La evolución de Lisp", págs. 239-240 .
- ↑ Pitman, El manual revisado de MacLisp , pág. 62
- ↑ Steele y Gabriel, "La evolución de Lisp", págs. 231-232.
- ↑ Steele y Gabriel, "La evolución del Lisp", pág. 235.
- ↑ Pitman, The Revised MacLisp Manual , pág. 182.
- ↑ Pitman, "Formas especiales en Lisp", pág. 179.
- ↑ Steele y Gabriel, "La evolución delLisp", págs. 245-248
- 1 2 Wand, "La teoría de Fexprs es trivial", pág. 189.
- ↑ Mitchell, "Sobre la abstracción y el poder expresivo de los lenguajes de programación", sección 7.
- ↑ Shutt, "cálculos de vau y la teoría de fexprs".
Referencias
- McCarthy, J.; Brayton , R .; Edwards, D .; Fox, P .; Hodes, L .; Luckham, D.; Maling , K .; Park, D .; Russell, S. (marzo de 1960), Manual del programador de LISP I (PDF) , Boston , Massachusetts : Grupo de Inteligencia Artificial, Centro de Computación e Investigación del MITConsultado el 11 de mayo de 2010.
- John C. Mitchell, «Sobre la abstracción y el poder expresivo de los lenguajes de programación» , Science of Computer Programming 212 (1993), págs. 141-163 . (Número especial de artículos del Simposio sobre Aspectos Teóricos del Software Informático, Sendai, Japón, 1991). Consultado el 24 de enero de 2008.
- Kent M. Pitman, "Formas especiales en Lisp" , Actas de la Conferencia ACM de 1980 sobre Lisp y Programación Funcional, 1980, págs. 179-187 . Consultado el 25 de enero de 2008.
- Kent M. Pitman, Manual revisado de MacLisp (edición del sábado por la noche), Informe técnico 295 del Laboratorio de Ciencias de la Computación del MIT, 21 de mayo de 1983.
- John N. Shutt, "cálculos de vau y la teoría de fexprs", charla, Serie de Simposios sobre Lenguajes y Sistemas de Programación de Nueva Inglaterra (NEPLS) , 18 de octubre de 2007. Resumen consultado el 27 de enero de 2008.
- Guy L. Steele y Richard P. Gabriel, " La evolución de Lisp", ACM SIGPLAN Notices 28 n.º 3 (marzo de 1993), págs. 231-270 .
- Mitchell Wand, "La teoría de Fexprs es trivial" , LISP and Symbolic Computation 10 n.º 3 (mayo de 1998), págs. 189-199 . Consultado el 25 de enero de 2008.
- Lisp (lenguaje de programación)
- Estructuras de programación