Emacs Lisp es un dialecto del lenguaje de programación Lisp utilizado como lenguaje de scripting por Emacs (una familia de editores de texto más comúnmente asociada con GNU Emacs y XEmacs ). Se utiliza para implementar la mayor parte de la funcionalidad de edición incorporada en Emacs, el resto está escrito en C , al igual que el intérprete Lisp . Emacs Lisp también se denomina Elisp , aunque también hay un dialecto Lisp más antiguo y no relacionado con ese nombre. [1]
Paradigma | Funcional , meta , reflectante |
---|---|
Familia | Ceceo |
Diseñada por | Richard Stallman , Guy L. Steele, Jr. |
Desarrollador | Proyecto GNU |
Apareció por primera vez | 1985 |
Lanzamiento estable | 26.2 / 12 de abril de 2019 |
Disciplina de mecanografía | Dinámico , fuerte |
Alcance | Dinámico, opcionalmente léxico |
Plataforma | Emacs |
SO | Multiplataforma |
Licencia | GPLv3 |
Extensiones de nombre de archivo | .el, .elc |
Influenciado por | |
Lisp común , Maclisp |
Los usuarios de Emacs comúnmente escriben código Emacs Lisp para personalizar y extender Emacs. Otras opciones incluyen la característica Customize que ha estado en GNU Emacs desde la versión 20. Escrito en Emacs Lisp, Customize proporciona un conjunto de páginas de preferencias que permiten al usuario establecer opciones y obtener una vista previa de su efecto en la sesión de Emacs en ejecución. Cuando el usuario guarda sus cambios, Customize simplemente escribe el código Emacs Lisp necesario en el archivo de configuración del usuario , que se puede configurar en un archivo especial que solo Customize usa, para evitar la posibilidad de alterar el propio archivo del usuario.
Emacs Lisp también puede funcionar como un lenguaje de scripting , al igual que el shell Unix Bourne o Perl , llamando a Emacs en modo por lotes . De esta forma, se puede llamar desde la línea de comandos o mediante un archivo ejecutable, y sus funciones de edición, como búferes y comandos de movimiento, están disponibles para el programa al igual que en el modo normal. No se presenta una interfaz de usuario cuando Emacs se inicia en modo por lotes; simplemente ejecuta el script pasado y sale, mostrando cualquier salida del script.
Comparado con otros dialectos Lisp
Emacs Lisp está más estrechamente relacionado con Maclisp , con alguna influencia posterior de Common Lisp . [2] Admite métodos de programación imperativos y funcionales . Richard Stallman eligió Lisp como el lenguaje de extensión para su reescritura de Emacs (el editor y corrector de texto original usado (TECO) como su lenguaje de extensión) debido a sus poderosas características, incluida la capacidad de tratar las funciones como datos. Aunque el estándar Common Lisp aún no se había formulado, Scheme existía en el momento en que Stallman estaba reescribiendo Gosling Emacs en GNU Emacs. Eligió no usarlo debido a su rendimiento comparativamente pobre en estaciones de trabajo (a diferencia de las miniordenadores que eran el hogar tradicional de Emacs), y quería desarrollar un dialecto que pensó que sería optimizado más fácilmente. [3]
El dialecto Lisp utilizado en Emacs difiere sustancialmente de los dialectos Common Lisp y Scheme más modernos utilizados para la programación de aplicaciones. Una característica destacada de Emacs Lisp es su uso de alcance dinámico en lugar de léxico por defecto (ver más abajo). Es decir, una función puede hacer referencia a variables locales en el ámbito desde el que se llama, pero no en el ámbito donde se definió.
Ejemplo
Para comprender la lógica detrás de Emacs Lisp, es importante recordar que hay un énfasis en proporcionar estructuras de datos y características específicas para hacer un editor de texto versátil en lugar de implementar un lenguaje de programación de propósito general. Por ejemplo, Emacs Lisp no puede leer fácilmente un archivo una línea a la vez; el archivo completo debe leerse en un búfer de Emacs. Sin embargo, Emacs Lisp proporciona muchas características para navegar y modificar el texto del búfer en una oración, párrafo o un nivel sintáctico superior definido por los modos.
A continuación, se muestra un ejemplo simple de una extensión de Emacs escrita en Emacs Lisp. En Emacs, el área de edición se puede dividir en áreas separadas llamadas ventanas , cada una mostrando un búfer diferente . Un búfer es una región de texto cargada en la memoria de Emacs (posiblemente desde un archivo) que se puede guardar en un documento de texto.
Los usuarios pueden presionar la combinación de C-x 2 teclas predeterminada para abrir una nueva ventana. Esto ejecuta la función Emacs Lisp split-window-below
. Normalmente, cuando aparece la nueva ventana, muestra el mismo búfer que el anterior. Supongamos que deseamos que muestre el siguiente búfer disponible. Para hacer esto, el usuario escribe el siguiente código Emacs Lisp, ya sea en un archivo fuente existente de Emacs Lisp o en un búfer de Emacs vacío:
( defun my-split-window-func () ( interactivo ) ( split-window-below ) ( set-window-buffer ( next-window ) ( other-buffer )))( tecla-conjunto-global "\ C-x2" 'my-split-window-func )
La primera declaración, (defun ...)
define una nueva función, my-split-window-func
que llama split-window-below
(la antigua función de división de ventanas), luego le dice a la nueva ventana que muestre otro búfer (nuevo). La segunda instrucción (global-set-key ...)
vuelve a vincular la secuencia de teclas "Cx 2" a la nueva función.
Esto también se puede escribir utilizando la función denominada asesoramiento , que permite al usuario crear envoltorios alrededor de funciones existentes en lugar de definir las suyas propias. Esto tiene la ventaja de que no es necesario cambiar las combinaciones de teclas y funciona donde se llama a la función original, además de ser más simple de escribir, pero tiene la desventaja de hacer que la depuración sea más complicada. Por esta razón, los consejos no están permitidos en el código fuente de GNU Emacs, [4] pero si un usuario lo desea, la función de consejos puede usarse en su código para reimplementar el código anterior de la siguiente manera:
( defadvice split-window-below ( después de my-window-splitting-advice first () active ) ( set-window-buffer ( next-window ) ( other-buffer )))
Esto indica split-window-below
que se ejecute el código proporcionado por el usuario siempre que sea llamado, antes de ejecutar el resto de la función. También se puede especificar que los consejos se ejecuten después de la función original, alrededor de ella, literalmente envolviendo el original, o para ejecutar condicionalmente la función original según los resultados del consejo.
Emacs 24.4 reemplaza [5] este defadvice
mecanismo con advice-add
, que se dice que es más flexible y simple. [6] El consejo anterior podría volver a implementarse utilizando el nuevo sistema como:
( defun switch-to-next-window-in-split () ( set-window-buffer ( next-window ) ( other-buffer )))( consejo-agregar 'split-window-below : before #' switch-to-next-window-in-split )
Estos cambios entran en vigor tan pronto como se evalúa el código . No es necesario volver a compilar, reiniciar Emacs o incluso repetir un archivo de configuración. Si el código se guarda en un archivo init de Emacs, entonces Emacs cargará la extensión la próxima vez que se inicie. De lo contrario, los cambios deben reevaluarse manualmente cuando se reinicia Emacs.
Código fuente
El código Emacs Lisp se almacena en sistemas de archivos como archivos de texto plano, por convención con el sufijo de nombre de archivo " .el ". El archivo de inicio del usuario es una excepción, a menudo aparece como " .emacs " a pesar de ser evaluado como cualquier código Emacs Lisp. Las versiones recientes de Emacs ( "reciente" en un programa de 40 años de edad, lo que significa más o menos cualquier versión lanzada desde mediados de la década de 1990) también se cargarán ~ / .emacs.el y ~ / .emacs.d / init.el . Además, los usuarios pueden especificar cualquier archivo para cargar como un archivo de configuración en la línea de comando, o indicar explícitamente que no se cargará ningún archivo de configuración. Cuando se cargan los archivos, un componente intérprete del programa Emacs lee y analiza las funciones y variables, almacenándolas en la memoria. Luego están disponibles para otras funciones de edición y para comandos de usuario. Las funciones y variables se pueden modificar y redefinir libremente sin reiniciar el editor o volver a cargar el archivo de configuración.
Para ahorrar tiempo y espacio en la memoria, gran parte de la funcionalidad de Emacs se carga solo cuando es necesario. Cada conjunto de características opcionales enviadas con Emacs se implementa mediante una colección de código de Emacs llamado paquete o biblioteca . Por ejemplo, hay una biblioteca para resaltar palabras clave en el código fuente del programa y una biblioteca para jugar al juego de Tetris . Cada biblioteca se implementa utilizando uno o más archivos fuente de Emacs Lisp. Las bibliotecas pueden definir uno o más modos principales para activar y controlar su función.
Los desarrolladores de Emacs escriben ciertas funciones en C. Estas son primitivas , también llamadas funciones integradas o subrs . Aunque las primitivas se pueden llamar desde el código Lisp, solo se pueden modificar editando los archivos fuente de C y volviendo a compilar. En GNU Emacs , las primitivas no están disponibles como bibliotecas externas; son parte del ejecutable de Emacs. En XEmacs , la carga en tiempo de ejecución de tales primitivas es posible, utilizando el soporte del sistema operativo para la vinculación dinámica. Las funciones pueden escribirse como primitivas porque necesitan acceso a datos externos y bibliotecas que de otro modo no están disponibles en Emacs Lisp, o porque se llaman con la frecuencia suficiente para que la velocidad comparativa de C frente a Emacs Lisp haga una diferencia importante.
Sin embargo, debido a que los errores en el código C pueden conducir fácilmente a violaciones de segmentación o errores más sutiles, que bloquean el editor, y debido a que escribir código C que interactúa correctamente con el recolector de basura Emacs Lisp es propenso a errores, la cantidad de funciones implementadas como primitivas se mantiene al mínimo necesario.
Código de byte
La compilación de bytes puede hacer que el código Emacs Lisp se ejecute más rápido. Emacs contiene un compilador que puede traducir los archivos fuente de Emacs Lisp en una representación especial denominada bytecode . Los archivos de código de bytes Emacs Lisp tienen el sufijo de nombre de archivo " .elc ". En comparación con los archivos de origen, los archivos de código de bytes se cargan más rápido, ocupan menos espacio en el disco, usan menos memoria cuando se cargan y se ejecutan más rápido.
El código de bytes aún se ejecuta más lentamente que las primitivas, pero las funciones cargadas como código de bytes se pueden modificar y volver a cargar fácilmente. Además, los archivos de código de bytes son independientes de la plataforma. El código estándar de Emacs Lisp distribuido con Emacs se carga como código de bytes, aunque los archivos fuente coincidentes también se proporcionan normalmente para la referencia del usuario. Las extensiones proporcionadas por el usuario no suelen estar compiladas por bytes, ya que no son ni tan grandes ni tan intensivas en computación.
Características del idioma
En particular, el paquete "cl" implementa un subconjunto bastante grande de Common Lisp .
Emacs Lisp (a diferencia de otras implementaciones de Lisp) no realiza optimización de llamadas finales . [7] Sin esto, las recursiones de cola pueden eventualmente conducir a un desbordamiento de pila .
La biblioteca apel ayuda a escribir código Emacs Lisp portátil, con la ayuda del puente de plataforma polysylabi.
Emacs Lisp es un Lisp-2, lo que significa que tiene un espacio de nombres de función que está separado del espacio de nombres que usa para otras variables. [8]
Del alcance dinámico al léxico
Al igual que MacLisp, Emacs Lisp usa un alcance dinámico , ofreciendo estático (o léxico) como una opción a partir de la versión 24. [9] Se puede activar configurando la variable local del archivo lexical-binding
. [10] [11]
En el alcance dinámico, si un programador declara una variable dentro del alcance de una función, está disponible para subrutinas llamadas desde dentro de esa función. Originalmente, esto fue pensado como una optimización ; el alcance léxico todavía era poco común y de desempeño incierto. "Le pregunté a RMS cuando estaba implementando emacs lisp por qué tenía un alcance dinámico y su respuesta exacta fue que el alcance léxico era demasiado ineficiente". [12] El alcance dinámico también estaba destinado a proporcionar una mayor flexibilidad para las personalizaciones de los usuarios. Sin embargo, el alcance dinámico tiene varias desventajas. En primer lugar, puede provocar fácilmente errores en programas grandes, debido a interacciones no deseadas entre variables en diferentes funciones. En segundo lugar, el acceso a las variables en el ámbito dinámico es generalmente más lento que en el ámbito léxico. [13]
Además, la lexical-let
macro en el paquete "cl" proporciona un alcance léxico efectivo a los programadores de Emacs Lisp, pero aunque "cl" se usa ampliamente, lexical-let
rara vez se usa.
Referencias
- ^ "HEDRICK en RUTGERS (Mngr DEC-20's / Dir LCSR Comp Facility" (1981-12-18). " " Información sobre la implementación de Common Lisp " " . Carta a "rpg en SU-AI, jonl en MIT-AI". archivado desde el original, el 20/09/2016 . Obtenido 07/28/2019 .
tenemos un poco de experiencia en la implementación de Lisp ahora, ya Elisp (la implementación extendida de Rutgers / UCI Lisp) está esencialmente terminada.
- ^ "GNU Emacs Lisp está inspirado en gran medida por Maclisp , y un poco por Common Lisp. Si conoce Common Lisp, notará muchas similitudes. Sin embargo, muchas características de Common Lisp se han omitido o simplificado para reducir los requisitos de memoria de GNU Emacs. A veces las simplificaciones son tan drásticas que un usuario de Common Lisp puede estar muy confundido. Ocasionalmente señalaremos en qué se diferencia GNU Emacs Lisp de Common Lisp ". - de la sección "Historia" de la "Introducción" al Manual Emacs Lisp, a partir de Emacs 21
- ^ "Así que el desarrollo de ese sistema operativo, el sistema operativo GNU, es lo que me llevó a escribir GNU Emacs. Al hacer esto, me propuse hacer la implementación de Lisp lo más mínima posible. El tamaño de los programas era una gran preocupación. Había gente en aquellos días, en 1985, que tenían máquinas de un megabyte sin memoria virtual. Querían poder usar GNU Emacs. Esto significaba que tenía que mantener el programa lo más pequeño posible ". - de "Mis experiencias Lisp y el desarrollo de GNU Emacs"
- ^ "Re: [Emacs-diffs] / srv / bzr / emacs / trunk r111086: gmm-utils.el (gmm-flet" . Lists.gnu.org. 2012-12-05 . Consultado el 18 de agosto de 2013 .
- ^ "NOTICIAS.24.4" .
- ^ "Portar viejos consejos" .
- ^ "Apéndice C Porting Common Lisp" . Gnu.org . Consultado el 28 de octubre de 2019 .
Los programadores de Lisp querrán tener en cuenta que el compilador actual de Emacs Lisp no optimiza la recursividad de cola
- ^ "Grupos de Google" . groups.google.com .
- ^ "Lanzamiento de Emacs 24.1" . Lists.gnu.org . Consultado el 18 de agosto de 2013 .
- ^ "Enlace léxico" . Lists.gnu.org. 2011-04-01 . Consultado el 18 de agosto de 2013 .
- ^ "Enlace dinámico Vs Enlace léxico" . EmacsWiki. 2013-05-17 . Consultado el 18 de agosto de 2013 .
- ^ "T" . People.csail.mit.edu . Consultado el 18 de agosto de 2013 .
- ^ Featherston, Sam; Winkler, Susanne (2 de junio de 2009). Proceso . Walter de Gruyter. ISBN 978-3-11-021614-1.
enlaces externos
- Sitio web oficial , Proyecto GNU