This is emacs-lisp-intro-es.info, produced by makeinfo version 7.2 from
emacs-lisp-intro-es.texi.

Esto es una ‘Introducción a la Programación en Emacs Lisp’, para
personas que no son programadoras.

   Traducido desde la edición 3.10.

   Copyright © 2015 Libremanuals.

   Publicado por el:

     Libremanuals,                      <http://www.libremanuals.net/>


   ISBN: 978-84-608-5935-2

   Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; there being
no Invariant Section, with the Front-Cover Texts being "A GNU Manual",
and with the Back-Cover Texts as in (a) below.  A copy of the license is
included in the section entitled "GNU Free Documentation License".

   (a) The FSF's Back-Cover Text is: "You have the freedom to copy and
modify this GNU manual.  Buying copies from the FSF supports it in
developing GNU and promoting software freedom."
INFO-DIR-SECTION GNU Emacs Lisp
START-INFO-DIR-ENTRY
* Introducción a Emacs Lisp: (eintr).  Una introducción simple a la
                                           programación a Emacs Lisp
END-INFO-DIR-ENTRY


File: emacs-lisp-intro-es.info,  Node: Top,  Next: Prefacio,  Up: (dir)

Una Introducción a la Programación en Emacs Lisp
************************************************

Esto es una ‘Introducción a la Programación en Emacs Lisp’, para
personas que no son programadoras.

   Traducido desde la edición 3.10.

   Copyright © 2015 Libremanuals.

   Publicado por el:

     Libremanuals,                      <http://www.libremanuals.net/>


   ISBN: 978-84-608-5935-2

   Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; there being
no Invariant Section, with the Front-Cover Texts being "A GNU Manual",
and with the Back-Cover Texts as in (a) below.  A copy of the license is
included in the section entitled "GNU Free Documentation License".

   (a) The FSF's Back-Cover Text is: "You have the freedom to copy and
modify this GNU manual.  Buying copies from the FSF supports it in
developing GNU and promoting software freedom."

   Este menú maestro primero lista cada capítulo e indexa; entonces
lista cada nodo en cada capítulo.

* Menu:

* Prefacio::                 Qué buscas
* Procesamiento de listas::  ¿Qué es Lisp?
* Practicando evaluación::  Ejecutando varios programas.
* Escribiendo funciones::    Cómo escribir definiciones de funciones.
* Un paseo a través de los búffers::  Explorando unas pocas funciones
                                            relacionadas con los búffers.
* Más complejidad::        Unas pocas, incluso más complejas funciones.
* Encogiendo y extendiendo::  Restringiéndote a tí y a Emacs a una
                                región.
* Car cdr y cons::           Funciones fundamentales en Lisp.
* Cortando y almacenando texto::  Eliminando texto y guardándolo.
* Implementación de listas::  Cómo las listas se implementan en el
                                  ordenador
* Pegando::                  Pegando texto almacenado.
* Bucles y recursión::     Cómo repetir un proceso.
* Buscar regexp::            Búsquedas de expresiones regulares.
* Contando palabras::        Una revisión de repetición y regexps.
* Palabras en una función::  Contando palabras en una ‘defun’.
* Leyendo un grafo::         Un grafo prototipo imprimiendo una función.
* Inicialización de Emacs::  Cómo escribir un fichero ‘.emacs’.
* Depurando::                Cómo ejecutar los depuradores de Emacs Lisp.
* Conclusión::             Ahora tienes las bases.
* the-the::                  Un apéndice: cómo encontrar palabras
                               reduplicadas.
* Kill Ring::                Un apéndice: cómo el kill ring funciona.
* Grafo completo::           Cómo crear un grafo con ejes etiquetados.
* Software Libre y Manuales Libres::  Software Libre y Manuales Libres
* GNU Free Documentation License::  GNU Free Documentation License
* Índice::                 Índice
* Acerca del Autor::         Acerca del Autor

 -- El Listado Detallado de Nodos --



Prefacio



* Por qué::                ¿Por qué aprender Emacs Lisp?
* Leyendo este texto::       Leer, ganar familiaridad, coger hábitos...
* Quien eres::               Para quien es este escrito.
* Historia de Lisp::         Historia de Lisp
* Nota para principiantes::  Tu puedes leer esto como un novato
* Se agradece::              Se agradece

Procesamiento de listas



* Listas Lisp::              ¿Qué son listas?
* Ejecutar un programa::     Cualquier lista en Lisp es un programa listo
                               para ejecutarse.
* Creando errores::          Generando un mensaje de error.
* Nombres y definiciones::   Nombres de símbolos y
                               definiciones de función.
* Interpréte Lisp::        Qué hace el intérprete Lisp.
* Evaluación::             Ejecutando un programa.
* Variables::                Devolviendo un valor desde una variable.
* Argumentos::               Pasando información a una función.
* set y setq::               Configurando el valor de una variable.
* Resumen::                  Los mayores puntos.
* Ejercicios de mensajes de error::  Ejercicios de mensajes de error

Listas Lisp



* Listas de números::      Lista tener números, otras listas, en ellas.
* Átomos Lisp::            Entidades Elementales.
* Espacios en blanco en listas::  Formatenado listas para ser legibles.
* Escribiendo listas::       Cómo GNU Emacs te ayuda a escribir listas.

El intérprete Lisp



* Complicaciones::           Variables, formas especiales, Listas.
* Compilación de bytes::   Especialmente procesando código por la
                               velocidad.

Evaluación



* Cómo el intérprete actúa::  Devolver y Efectos Colaterales...
* Evaluando listas propias::  Listas con listas...

Variables



* Ejemplo de rellenar columna::  Ejemplo de rellenar columna
* Función vacía::  El mensaje de error para un
                                     símbolo sin una función.
* Variable vacía::  El mensaje de error para un
                                    símbolo sin un valor.

Argumentos



* Tipos de datos::           Tipos de datos pasados a una función.
* Argumentos como variables o listas::  Un argumento puede ser el valor de
                                          una variable o lista.
* Número de variables de argumentos::  Algunas funciones pueden tomar un
                                           número variable de argumentos.
* Tipo incorrecto de argumento::  Pasando un argumento del tipo incorrecto a
                                    una función.
* message::                  Una función útil para enviar mensajes.

Configurando el valor de una variable



* Usando set::               Configurando valores.
* Usando setq::              Configurando un valor citado.
* Contando::                 Usando ‘setq’ para contar.

Practicando evaluación



* Cómo evaluar::           Escribiendo comandos de edición o con
                               ‘C-x C-e’.
* Nombres de búffer::      Buffers y ficheros son diferentes.
* Obteniendo búffers::     Obteniendo un buffer por sí
                               mismo, no solamente su nombre.
* Cambiando búffers::      Cómo cambiar a otro buffer.
* Tamaño de búffer y localizaciones::  Dónde el punto está
                                             localizado y el tamaño del
                                             buffer.
* Ejercicio de evaluación::  Ejercicio de evaluación

Cómo escribir definiciones de funciones



* Funciones primitivas::     Funciones primitivas
* defun::                    La forma especial ‘defun’.
* Instalar::                 Instalar una definición de función.
* Interactive::              Creando una función interactive.
* Opciones de interactive.::  Diferentes opciones para ‘interactive’.
* Instalación Permanente::  Instalando código permanentemente.
* let::                      Creando e inicializando variables locales.
* if::                       ¿Y qué si?
* else::                     Expresiones If-then-else.
* Verdad y falsedad::        Que considera Lisp falso y cierto.
* save-excursion::           Guardando la traza del punto, la marca, y el
                               buffer.
* Revisar::                  Revisar
* Ejercicios defun::         Ejercicios defun

Instalar una definición de función



* Efecto de instalación::  Efecto de instalación
* Cambiar un defun::         Cómo cambiar una definición de función

Crear una función interactive



* multiply-by-seven interactivo::  Un resumen
* multiply-by-seven en detalle::  La versión interactive.

‘let’



* Prevenir confusión::     Prevenir confusión
* Partes de la expresión let::  Partes de la expresión let
* Ejemplo de expresión let::  Ejemplo de expresión let
* Variables let inicializadas::  Variables let inicializadas

La forma especial ‘if’



* if en más detalle::      if en más detalle
* tipo-de-animal en detalle::  Un ejemplo de una expresión ‘if’.

Verdad y falsedad en Emacs Lisp



* nil explicado::            ‘nil’ tiene dos significados.

‘save-excursion’



* Punto y marca::            Una revisión de varias localizaciones.
* Plantilla para save-excursion::  Plantilla para save-excursion

Unas pocas funciones de buffer relacionadas



* Encontrando más::        Cómo encontrar más información.
* simplified-beginning-of-buffer::  Muestra ‘goto-char’,
                                      ‘point-min’, y ‘push-mark’.
* mark-whole-buffer::        Casi lo mismo que ‘beginning-of-buffer’.
* append-to-buffer::         Usa ‘save-excursion’ y
                               ‘insert-buffer-substring’.
* Revisa lo relacionado con el búffer::  Revisa
* Ejercicios de búffer::   Ejercicios de búffer

La definición de ‘mark-whole-buffer’



* resumen de mark-whole-buffer::  resumen de mark-whole-buffer
* Cuerpo de mark-whole-buffer::  Solo tres líneas de código.

La definición de ‘append-to-buffer’



* resumen de append-to-buffer::  resumen de append-to-buffer
* append interactivo::       Una expresión interactiva de dos partes.
* cuerpo append-to-buffer::  Incorpora una expresión ‘let’.
* append save-excursion::    Cómo ‘save-excursion’ trabaja.

Unas pocas funciones más complejas



* copy-to-buffer::           Con ‘set-buffer’,
                               ‘get-buffer-create’.
* insert-buffer::            Solo lectura, y con ‘or’.
* beginning-of-buffer::      Muestra ‘goto-char’, ‘point-min’, y
                               ‘push-mark’.
* Revisar el segundo búffer relacionado::  Revisar el segundo búffer
                                               relacionado
* Ejercicio opcional::       Ejercicio opcional

La definición de ‘insert-buffer’



* código insert-buffer::   código insert-buffer
* insert-buffer interactivo::  Cuando tu puedes leer, pero no escribir.
* cuerpo insert-buffer::     El cuerpo tiene un ‘or’ y un ‘let’.
* si y o::                   Usando un ‘if’ en vez de un ‘or’.
* Insertar o::               Cómo la expresión ‘or’ funciona.
* Insertar let::             Dos expresiones ‘save-excursion’.
* Nuevo insert-buffer::      Nuevo insert-buffer

La expresión interactiva en ‘insert-buffer’



* Búffer solo lectura::    Cuando un buffer no puede ser modificado.
* b para interactivo::       Un buffer existe o además su nombre.

Definición completa de ‘beginning-of-buffer’



* Argumentos opcionales::    Argumentos opcionales
* beginning-of-buffer opt arg::  Ejemplo con argumento opcional.
* Completo beginning-of-buffer::  Completo beginning-of-buffer

‘beginning-of-buffer’ con un argumento



* Desenmarañar beginning-of-buffer::  Desenmarañar beginning-of-buffer
* El caso del buffer largo::  El caso del buffer largo
* Pequeño caso de búffer::  Pequeño caso de búffer

Encogiendo y extendiendo



* Ventajas de encoger::      Las ventajas de encoger
* save-restriction::         La forma especial ‘save-restriction’.
* what-line::                El número de la línea que
                               apunta está activa.
* Ejercicio narrow::         Ejercicio narrow

‘car’, ‘cdr’, ‘cons’: Funciones fundamentales



* Nombres extraños::       Un lado histórico: ¿por qué
                               los nombres extraños?
* car y cdr::                Funciones para extraer parte de una lista.
* cons::                     Construyendo una lista.
* nthcdr::                   Llamando ‘cdr’ repetidamente.
* nth::                      nth
* setcar::                   Cambiando el primer elemento de una lista.
* setcdr::                   Cambiando el resto de una lista.
* Ejercicio cons::           Ejercicio cons

‘cons’



* Construir una lista::      Construir una lista
* length::                   Cómo encontrar el tamaño de una lista.

Cortando y almacenando texto



* Almacenando Texto::        El texto está almacenado en una lista.
* zap-to-char::              Cortando texto a un carácter.
* kill-region::              Cortando texto de una región.
* copy-region-as-kill::      Una definición para copiar texto.
* Disgresión dentro de C::  Nota menor en macros del lenguaje de
                                programación C.
* defvar::                   Cómo dar a una variable un valor inicial.
* Revisión de cons y search-fwd::  Revisión de cons y search-fwd
* Buscar ejercicios::        Buscar ejercicios

‘zap-to-char’



* Completar zap-to-char::    La implementación completa.
* zap-to-char interactivo::  Una expresión interactiva de tres partes.
* cuerpo zap-to-char::       Un resumen corto
* search-forward::           Cómo buscar una cadena.
* progn::                    La forma especial ‘progn’.
* Resumiendo zap-to-char::   Usando ‘point’ y ‘search-forward’.

‘kill-region’



* Completa kill-region::     La definición de función.
* condition-case::           Tratando con un problema.
* Macro Lisp::               Macro Lisp

‘copy-region-as-kill’



* Completar copy-region-as-kill::  La definición completa de función.
* cuerpo copy-region-as-kill::  El cuerpo de ‘copy-region-as-kill’.

El cuerpo de ‘copy-region-as-kill’



* last-command & this-command::  last-command & this-command
* Función kill-append::    Función kill-append
* Función kill-new::       Función kill-new

Inicializando una variable con ‘defvar’



* Mira el valor actual de la variable::  Mira el valor actual de la variable
* defvar y asterisk::        defvar y asterisk

Cómo las listas se implementan



* Listas diagramadas::       Listas diagramadas
* Símbolos como cajas::  Explorando una metáfora poderosa.
* Ejercicio Lista::          Ejercicio Lista

Pegando texto



* Resumen del anillo de la muerte::  Resumen del anillo de la muerte
* kill-ring-yank-pointer::   El anillo de la muerte es una lista.
* pegar Ejercicio nthcdr::   La variable ‘kill-ring-yank-pointer’.

Bucles y recursión



* while::                    Causando un cierto código para repetir.
* Dolist y dotimes::         Dolist y dotimes
* Recursión::              Causando que una función se llame a
                               sí misma.
* Ejercicio de Bucle::       Ejercicio de Bucle

‘while’



* Bucles while::             Repetir tantas veces como el test devuelva
                               verdadero.
* Ejemplo de bucle::         Un bucle ‘while’ que usa una lista.
* print-elements-of-list::   Usos ‘while’, ‘car’, ‘cdr’.
* Incrementando el Bucle::   Un bucle con un contador de incremento.
* Incrementando los detalles de los bucles::  Incrementando los detalles de
                                                los bucles
* Bucle que se decrementa::  Un bucle con un decrementando contador.

Detalles de un bucle que se incrementa



* Ejemplo de Incremento::    Contando esquinas en un triángulo.
* Partes Inc de Ejemplo::    Las partes de la definición de función.
* Ejemplo Inc junto::        Poniendo la definición de función junta.

Bucle que decrementa



* Ejemplo de Decremento::    Más piedras en la playa.
* Partes de Ejemplo Dec::    Las partes de la definición de función.
* Ejemplo Dec junto::        Poniendo la definición de función junta.

Ahorra tiempo: ‘dolist’ y ‘dotimes’



* dolist::                   dolist
* dotimes::                  dotimes

Recursión



* Construyendo robots::      Mismo modelo, diferente número serie ...
* Partes de definición recursiva::  Paseo hasta que tu pares ...
* Recursión con lista::    Usando una lista con el test si para recurso.
* Función recursiva triángulo::  Función recursiva triángulo
* Recursión con cond::     Recursión con cond
* Patrones recursivos::      Plantillas usadas con frecuencia.
* Sin Aplazar::              No almacenar trabajo ...
* No aplazar la solución::  No aplazar la solución

Recursión en lugar de un contador



* Ejemplo recursivo y argumento con valor 1 o 2::  Ejemplo recursivo y
                                                     argumento con valor 1 o 2
* Ejemplo Recursivo de 3 o 4 argumentos::  Ejemplo Recursivo de 3 o 4
                                             argumentos

Patrones recursivos



* Cada::                     Cada
* Acumular::                 Acumular
* Guardar::                  Guardar

Búsquedas de expresiones regulares



* sentence-end::             La expresión regular para
                               ‘sentence-end’.
* re-search-forward::        Muy similar a ‘search-forward’.
* forward-sentence::         Un ejemplo sencillo de búsqueda con
                               expresiones regulares.
* forward-paragraph::        Un ejemplo complejo de alguna cosa.
* etags::                    Cómo crear tu propia tabla ‘TAGS’.
* Revisar regexp::           Revisar regexp
* Ejercicios re-search::     Ejercicios re-search

‘forward-sentence’



* Completa forward-sentence::  Completa forward-sentence
* Bucles while fwd-sentence::  Dos bucles ‘while’.
* Volver a buscar la frase en sentido directo::  Una búsqueda de
                                                   expresión regular.

‘forward-paragraph’: una mina de oro de funciones



* forward-paragraph en breve::  Partes clave de la definición de la
                                  función.
* fwd-para let::             La expresión ‘let*’.
* fwd-para while::           El bucle ‘while’ con modo hacia adelante.

Contando: repetición y regexps



* Por qué Contar Palabras::  Por qué Contar Palabras
* count-words-example::      Usa un regexp, pero encuentra un problema.
* recursive-count-words::    Empezar en caso de que no haya palabras en la
                               región.
* Ejercicio de Contar::      Ejercicio de Contar

La función ‘count-words-example’



* Diseñar count-words-example::  La definición usando un bucle
                                     ‘while’.
* Error de espacio en blanco::  El error de espacio en blanco en
                                  ‘count-words-example’.

Contando palabras en una ‘defun’



* Divide y vencerás::      Divide y vencerás
* Palabras y Símbolos::  ¿Qué contar?
* Sintaxis::                 ¿Qué constituye una palabra o
                               símbolo?
* count-words-in-defun::     Similar a ‘count-words-example’.
* Varias funciones::         Contando varias funciones en un fichero.
* Encontrar un fichero::     ¿Quieres buscar en un fichero?
* lengths-list-file::        Una lista de los tamaños de muchas
                               definiciones.
* Varios ficheros::          Contando en definiciones en diferentes
                               ficheros.
* Varios ficheros recursivamente::  Recursivamente contando en diferentes
                                      ficheros.
* Preparar los datos::       Preparar los datos para mostrarlos en un grafo.

Contar palabras en ‘defuns’ en diferentes ficheros



* lengths-list-many-files::  Devolver una lista de tamaños de funciones.
* append::                   Adjuntar una lista a otra.

Preparar los datos para mostrarlos en un grafo



* Datos para mostrar en detalle::  Datos para mostrar en detalle
* Ordenando::                Ordenando listas.
* Listar ficheros::          Creando una lista de ficheros.
* Contando definiciones de función::  Contando definiciones de función

Leyendo un grafo



* Columnas de un grafo::     Columnas de un grafo
* graph-body-print::         Cómo imprimir el cuerpo de un grafo.
* recursive-graph-body-print::  recursive-graph-body-print
* Ejes Impresos::            Ejes Impresos
* Ejercicio de Línea de Grafo::  Ejercicio de
                                                 Línea de Grafo

Tu fichero ‘.emacs’



* Configuración por defecto::  Configuración por defecto
* Site-wide Init::           Se puede escribir site-wide ficheros init.
* defcustom::                Emacs escribirá código para ti.
* Empezando un fichero .emacs::  Cómo escribir un ‘fichero .emacs’.
* Texto y Autorelleno::      Corta líneas automáticamente.
* Alias de correo::          Usar abreviaciones para direcciones de correo
                               electrónico.
* Indentar modo de tabulaciones::  No usar tabulaciones con TeX
* Atajos de teclado::        Crear algunos atajos de teclado personales.
* Mapas de teclado::         Más acerca de atajos de teclado.
* Cargando ficheros::        Cargar (por ej. evaluar) ficheros
                               automáticamente.
* Autocarga::                Crear funciones disponibles.
* Extensión simple::       Definir una función; enlazarla a una tecla.
* Colores X11::              Colores en X.
* Miscelánea::             Miscelánea
* Mode Line::                Cómo personalizar tu mode line.

Depurando



* depurar::                  Cómo usar el depurador construido.
* debug-on-entry::           Empezar depurando cuando se llama a una
                               función.
* debug-on-quit::            Empezar depurando cuando se sale con ‘C-g’.
* edebug::                   Cómo usar Edebug, un depurador a nivel de
                               fuentes.
* Ejercicios de depuración::  Ejercicios de depuración

Manejando el anillo de la muerte



* Qué hace el anillo de la muerte::  Qué hace el anillo de la muerte
* current-kill::             current-kill
* pegar::                    Pegar una copia de un elemento ya cortado.
* yank-pop::                 Insertar elemento apuntado.
* fichero anillo::           fichero anillo

La función ‘current-kill’



* Código para current-kill::  Código para current-kill
* Comprendiendo current-kill::  Comprendiendo current-kill

‘current-kill’ en outline



* Cuerpo de current-kill::   Cuerpo de current-kill
* Disgresión concerniente de error::  Cómo confundir humanos, pero no
                                          ordenadores.
* Determinando el elemento::  Determinando el elemento

Un grafo con ejes etiquetados



* Ejemplo etiquetado::       Ejemplo etiquetado
* print-graph Varlist::      Expresión ‘let’ en ‘print-graph’.
* print-Y-axis::             Imprimir una etiqueta para los ejes verticales.
* print-X-axis::             Imprimir una etiqueta horizontal.
* Imprimir Grafo Entero::    La función para imprimir un grafo completo.

La función ‘print-Y-axis’



* print-Y-axis en Detalle::  print-Y-axis en Detalle
* Altura de etiqueta::       ¿Qué altura para el eje Y?
* Calcular un resto::        Cómo calcular el resto de una división.
* Elemento del Eje Y::       Construir una línea para el eje
                               Y.
* Y-axis-column::            Generar una lista de etiquetas del eje Y.
* Penúltimo print-Y-axis::  Una versión no muy final.

La función ‘print-X-axis’



* Diferencias similares::    Mucho como ‘print-Y-axis’, pero no
                               exactamente.
* Eje X marca tic::          Crear marcas de tic para los ejes horizontales.

Imprimiendo el grafo completo



* La versión final::       Unos pocos cambios
* Testear print-graph::      Ejecutar un rápido test.
* Graficar palabras en funciones::  Ejecutando el código final.
* lambda::                   Cómo escribir una función anónima.
* mapcar::                   Aplicar una función a elementos de una lista.
* Otro Error::               Todavía otro error ... más
                               insidioso.
* Grafo impreso final::      ¡El grafo en sí!


File: emacs-lisp-intro-es.info,  Node: Prefacio,  Next: Procesamiento de listas,  Prev: Top,  Up: Top

Prefacio
********

La mayoría del entorno integrado GNU Emacs está escrito en el lenguaje
de programación llamado Emacs Lisp.  El código escrito en este lenguaje
de programación es el software--el conjunto de instrucciones--que cuenta
al ordenador qué hacer cuando tu le das comandos.  Emacs está diseñado
de forma que se puede escribir nuevo código en Emacs Lisp y fácilmente
instalarlo como una extensión al editor.

   (GNU Emacs se define muchas veces como un "editor extensible", pero
hace mucho más que proporcionar capacidad de edición.  Es mejor
referirse a Emacs como un "entorno de computación extensible".  Sin
embargo, esta frase es un poco pretenciosa.  Es más fácil referirse a
Emacs simplemente como un editor.  De hecho, cada cosa que se hace en
Emacs--encontrar la fecha Maya y fases de la luna, simplificar
polinomios, depurar código, administrar ficheros, leer cartas, escribir
libros--todas estas actividades son maneras de editar en un sentido
amplio de la palabra.)

* Menu:

* Por qué::                ¿Por qué aprender Emacs Lisp?
* Leyendo este texto::       Leer, ganar familiaridad, coger hábitos...
* Quien eres::               Para quien es este escrito.
* Historia de Lisp::         Historia de Lisp
* Nota para principiantes::  Tu puedes leer esto como un novato
* Se agradece::              Se agradece


File: emacs-lisp-intro-es.info,  Node: Por qué,  Next: Leyendo este texto,  Up: Prefacio

¿Por qué estudiar Emacs Lisp?
=============================

Aunque Emacs Lisp normalmente se asocia solo con Emacs, es un lenguaje
de programación completo.  Se puede usar Emacs Lisp del mismo modo que
con cualquier otro lenguaje de programación.

   Quizás se quiere comprender la programación; quizás se quiere
extender Emacs; o quizás se quiere llegar a ser un programador.  Esta
introducción a Emacs Lisp está diseñada para ayudar a empezar en todo
esto: para guiarse en el aprendizaje de los fundamentos de programación,
y de manera más importante, para enseñar como uno mismo puede ir más
allá.


File: emacs-lisp-intro-es.info,  Node: Leyendo este texto,  Next: Quien eres,  Prev: Por qué,  Up: Prefacio

Leyendo este texto
==================

A través de este libro, se verán pequeños programas de ejemplo que se
pueden ejecutar dentro de Emacs.  Si se lee este documento en Info
dentro de GNU Emacs, se pueden ejecutar los programas tal y como
aparecen.  (Esto es fácil de hacer y se explica cuando los ejemplos se
presentan).  Alternativamente, se puede leer esta introducción como un
libro impreso mientras se está sentando con un ordenador ejecutando
Emacs.  (Esto es lo que me gusta hacer; me gustan los libros impresos.)
Si no se está ejecutando Emacs, todavía se puede leer este libro, pero
en este caso, lo mejor es tratarlo como una novela, o como una guía de
víaje a un país aún no visitado: interesante, pero no es lo mismo que
estar allí.

   Gran parte de esta introducción se dedica a paseos guiados de código
usado en GNU Emacs.  Estos paseos están diseñados para dos propósitos:
primero, familiarizarse con código real que funciona (código que se usa
cada día); y, segundo, familiarizarse con cómo funciona Emacs.  Es
interesante ver cómo se implementa un entorno completamente operativo.
También, espero que se adquiera el hábito de navegar a través del código
fuente.  Se puede aprender mucho comparando código de otros con el
propio, ganando nuevas ideas.  Tener GNU Emacs es como tener la cueva
del dragón de los tesoros.

   Además de aprender acerca de Emacs como editor y Emacs Lisp como
lenguaje de programación, los ejemplos y visitas guiadas le darán una
oportunidad para familiarizarse con Emacs como un entorno de
programación Lisp.  GNU Emacs soporta programación y provee herramientas
que llegarán a usarse cómodamente, como ‘M-.’ (la clave que invoca el
comando ‘find-tag’).  También aprendera sobre búffers y otros objetos
que forman parte del entorno.  Aprender estas funcionalidades de Emacs
es como aprender nuevas rutas alrededor de tu hogar.

   Finalmente, espero poder transmitir algunas habilidades de Emacs para
aprender aspectos de programación que no se conocen.  Con frecuencia se
puede usar Emacs para ayudar a comprender qué puzzles encontrar o como
hacer alguna cosa nueva.  Este auto-descubrimiento no es solo un placer,
también es una ventaja.


File: emacs-lisp-intro-es.info,  Node: Quien eres,  Next: Historia de Lisp,  Prev: Leyendo este texto,  Up: Prefacio

Para quien está esto escrito
============================

Este texto está escrito como una introducción elemental para personas
que no son programadoras.  Quien ya programa, puede no estar satisfecho
con este libro.  La razón es que un programador puede tener que
convertirse en experto leyendo manuales de referencia y este texto no
está organizado como un manual de referencia.

   Un programador experto que revisó este texto me dijo:

     Prefiero aprender desde manuales de referencia.  Yo "me sumerjo" en
     cada párrafo y "subo a por aire" entre párrafos.

     Cuando llego al fin de un párrafo, asumo que este asunto está
     hecho, finalizado, que conozco cada cosa que necesito (con la
     posible excepción del caso en el que el siguiente párrafo empiece
     hablando acerca de eso mismo en más detalle).  Yo espero que un
     manual de referencia bien escrito no tendrá un montón de
     redundancia, y tendrá excelentes punteros a (un) lugar donde está
     la información que quiero.

   ¡Esta introducción no está escrita para esta persona!

   Primero, intento decir cada cosa al menos tres veces: primero,
introducirlo; segundo, mostrarlo en contexto; y tercero, mostrarlo en un
contexto diferente, o revisarlo.

   Segundo, yo no siempre pongo toda la información acerca de un asunto
en un mismo lugar, ni mucho menos en un párrafo.  Desde mi punto de
vista, se necesita una carga bastante fuerte en el lector.  En vez de
eso intento explicar solo lo que se necesita saber en el momento.
(Algunas veces incluyo una pequeña información extra, para que no haya
sorpresas más tarde cuando la información adicional se presente
formalmente.)

   Cuando uno lee este texto, no espera aprender todo la primera vez.
Frecuentemente, solo necesita hacer un 'reconocimiento' con alguno de
los elementos mencionados.  Mi esperanza es haber estructurado el texto
y dar suficientes indicios que dejarán alerta de lo que es importante y
concentrarse en ellos.

   Es necesario "sumergirse" en algunos párrafos; no hay otro modo de
leerlos.  Pero yo he intentado guardar el número de tales párrafos.
Este libro pretende ser como una colina asequible, en vez de una montaña
abrumadora.

   Esta introducción de ‘Programación en Emacs Lisp’ viene acompañada de
un documento complementario.  *note El Manual de Referencia de GNU Emacs
Lisp: (El Manual de Referencia de GNU Emacs Lisp)Arriba.  El manual de
referencia tiene más detalles que esta introducción.  En el manual de
referencia, toda la información sobre un asunto está concentrada en un
lugar.  Se debe cambiar si es como el programador citado arriba.  Y, por
supuesto, después de haber leido esta ‘Introducción’, será muy útil
consultar el ‘Manual de Referencia’ al escribir programas propios.


File: emacs-lisp-intro-es.info,  Node: Historia de Lisp,  Next: Nota para principiantes,  Prev: Quien eres,  Up: Prefacio

Historia de Lisp
================

Lisp fué originariamente desarrollado en los 50 en el Instituto
Tecnológico de Massachusetts para investigar en inteligencia artificial.
El gran poder del lenguaje Lisp lo hace superior para otros propósitos
también, tal como escribir comandos de edición y entornos integrados.

   GNU Emacs Lisp está fuertemente inspirado en Maclisp, que está
escrito en el MIT en los sesenta.  Está en cierto modo inspirado en
Common Lisp, que llega a ser un estándar en los 80.  Sin embargo, Emacs
Lisp es mucho más simple que Common Lisp.  (La distribución estándar de
Emacs contiene un fichero de extensiones opcional, ‘cl.el’, que añade
muchas funcionalidades a Emacs Lisp.)


File: emacs-lisp-intro-es.info,  Node: Nota para principiantes,  Next: Se agradece,  Prev: Historia de Lisp,  Up: Prefacio

Una nota para principiantes
===========================

Aunque no se conozca GNU Emacs, este documento puede resultar útil.  Sin
embargo, es mejor aprender Emacs, al menos aprender a moverse alrededor
de la pantalla del ordenador.  Uno puede aprender de manera autodidacta
cómo usar Emacs con el tutorial on-line.  Para usarlo, se debe escribir
‘C-h t’.  (Esto significa que se presione la tecla <CTRL> y la ‘h’ al
mismo tiempo, y después se presiona ‘t’).

   Con frecuencia, también aludo a uno de los comandos de Emacs estándar
listando las teclas que se presionan para invocar el comando y, luego
dar el nombre del comando entre paréntesis, asi: ‘M-C-\’
(‘indent-region’).  Esto significa invocar el comando ‘indent-region’
presionando ‘M-C-\’.(Si lo desea, se pueden cambiar las teclas que son
escritas para invocar el comando; esto se llama “rebinding”.  *Note
Mapas de Teclado: Mapas de teclado.)  La abreviación ‘M-C-\’ significa
que se presiona la tecla <META>, <CTRL>, y <\> todo al mismo tiempo.
(En muchos teclados modernos la tecla <META> es etiquetada con <ALT>.)
Algunas veces una combinación como esta se llama _keychord_, puesto que
es similar a tocar un acorde en un piano.  Si el teclado no tiene una
tecla <META>, en su lugar se usa la tecla <ESC> como prefijo.  En este
caso ‘M-C-\’ significa que se presiona y libera <ESC> y luego presiona
la tecla <CTRL> y la tecla <\> al mismo tiempo.  Pero normalmente
‘M-C-\’ significa presionar la tecla <CTRL> junto a la tecla que está
etiquetada <ALT> y, al mismo tiempo, presionar la tecla <\>.

   Además de pulsar una sola combinación de teclas, se puede prefijar lo
que se escribe con ‘C-u’, que es llamado el 'argumento universal'.  El
atajo ‘C-u’ pasa a ser un argumento para el comando subsiguiente.  De
este modo, para indentar una región de texto plano a 6 espacios, se
marca la región, y entonces se presiona ‘C-u 6 M-C-\’.  (Si no se
especifica un número, Emacs pasa el número 4 al comando o de otra manera
ejecuta el comando de manera diferente).  *Note Argumentos Numéricos:
(emacs)Argumentos.

   Si se está leyendo esto en Info usando GNU Emacs, se puede avanzar a
través de este documento completo solo presionando la barra de espacio,
<SPC>.  (Para aprender acerca de Info, presiona ‘C-h i’ y luego
selecciona Info.)

   Una nota en terminología: cuando uso la palabra Lisp sola, con
frecuencia me estoy refiriendo a los dialectos de Lisp en general, pero
cuando hablo de Emacs Lisp, me estoy refiriendo a GNU Emacs Lisp en
particular.


File: emacs-lisp-intro-es.info,  Node: Se agradece,  Prev: Nota para principiantes,  Up: Prefacio

Se agradece
===========

Estoy agradecido a todas las personas que me ayudaron con este libro.
Especialmente agradecido a Jim Blandy, Noah Friedman, Jim Kingdon,
Roland McGrath, Frank Ritter, Randy Smith, Richard M. Stallman, y
Melissa Weisshaus.  Gracias también a Philip Johnson y David Stampe por
su ánimo paciente.  Mis errores son míos.

                                                     Robert J. Chassell
                                                          <bob@gnu.org>


File: emacs-lisp-intro-es.info,  Node: Procesamiento de listas,  Next: Practicando evaluación,  Prev: Prefacio,  Up: Top

1 Procesamiento de listas
*************************

Para el ojo inexperto, Lisp es un lenguaje de programación extraño.  En
código Lisp hay paréntesis por todas partes.  Algunas personas incluso
reclaman que el nombre signfica 'Lots of Isolated Silly Parentheses'
('Montones de Paréntesis Aislados Estúpidos').  Pero la protesta no
tiene fundamento.  Lisp es para procesamiento de listas, y el lenguaje
de programación maneja _listas_ (y listas de listas) poniéndolas entre
paréntesis.  Los paréntesis marcan los límites de la lista.  Algunas
veces una lista va precedida por un apóstrofe simple o una marca de
cita, ‘'’(1) Las listas son el fundamento de Lisp.

* Menu:

* Listas Lisp::              ¿Qué son listas?
* Ejecutar un programa::     Cualquier lista en Lisp es un programa listo
                               para ejecutarse.
* Creando errores::          Generando un mensaje de error.
* Nombres y definiciones::   Nombres de símbolos y
                               definiciones de función.
* Interpréte Lisp::        Qué hace el intérprete Lisp.
* Evaluación::             Ejecutando un programa.
* Variables::                Devolviendo un valor desde una variable.
* Argumentos::               Pasando información a una función.
* set y setq::               Configurando el valor de una variable.
* Resumen::                  Los mayores puntos.
* Ejercicios de mensajes de error::  Ejercicios de mensajes de error

   ---------- Footnotes ----------

   (1) El apóstrofo o comilla es una abreviación para la función
‘quote’; no necesitas pensar acerca de funciones ahora; las funciones se
definen en *note Generar un mensaje de error: Creando errores.


File: emacs-lisp-intro-es.info,  Node: Listas Lisp,  Next: Ejecutar un programa,  Up: Procesamiento de listas

1.1 Listas Lisp
===============

En Lisp, una lista como esta: ‘'(rosa violeta margarita botóndeoro)’.
Esta lista es precedida por una comilla.  Bien, podría estar escrita de
la siguente manera, que se parece más al tipo de lista con la que se
está familiarizado:

     '(rosa
       violeta
       margarita
       botóndeoro)

Los elementos de esta lista son los nombres de 4 flores diferentes,
separados por espacios en blanco y rodeados de paréntesis, como flores
en un campo con un muro de piedras alrededor de ellas.

* Menu:

* Listas de números::      Lista tener números, otras listas, en ellas.
* Átomos Lisp::            Entidades Elementales.
* Espacios en blanco en listas::  Formatenado listas para ser legibles.
* Escribiendo listas::       Cómo GNU Emacs te ayuda a escribir listas.


File: emacs-lisp-intro-es.info,  Node: Listas de números,  Next: Átomos Lisp,  Up: Listas Lisp

Números, listas dentro de listas
--------------------------------

Las listas pueden también tener números dentro, como en esta lista: ‘(+
2 2)’.  Esta lista tiene un signo más, ‘+’, seguido por dos ‘2’, cada
uno separado por espacios en blanco.

   En Lisp, tanto datos como programas están representados de la misma
manera; es decir, són a la vez listas de palabras, números, u otras
listas, separadas por espacios en blanco y rodeadas de paréntesis.
(Puesto que un programa son datos, un programa puede fácilmente servir
datos a otros programas; esta es una funcionalidad muy poderosa de
Lisp.)  (Incidentalmente, estas dos marcas de paréntesis _no_ son listas
Lisp, porque contienen ‘;’ y ‘.’ como marcas de puntuación.)

   Aquí hay otra lista, esta vez con una lista dentro:

     '(esta lista tiene (una lista dentro de ella))

   Los componentes de esta lista son las palabras ‘esta’, ‘lista’,
‘tiene’, y la lista ‘(una lista dentro de ella)’.  La lista interior se
construye con las palabras ‘una’, ‘lista’, ‘dentro’, ‘de’, ‘ella’.


File: emacs-lisp-intro-es.info,  Node: Átomos Lisp,  Next: Espacios en blanco en listas,  Prev: Listas de números,  Up: Listas Lisp

1.1.1 Átomos Lisp
-----------------

En Lisp, lo que hemos estado llamando palabras son en realidad “átomos”.
Este término viene del significado histórico de la palabra átomo, que
significa 'indivisible'.  En lo que a Lisp concierne, las palabras que
hemos estado usando en las listas no pueden ser divididas en pequeñas
partes, sin perder su significado dentro del programa; lo mismo ocurre
con números y símbolos de un caracterer como ‘+’.  Por otro lado, a
diferencia de un átomo, una lista puede ser dividida en pequeñas partes.
Ver *note ‘car’: (‘cdr’ y ‘cons’)Car cdr y cons.

   En una lista, los átomos se separan unos de otros por espacios en
blanco.  Pueden ir pegados a un paréntesis.

   Técnicamente hablando, una lista en Lisp consiste de paréntesis
alrededor de átomos separados por espacios en blanco o alrededor de
otras lista o alrededor de ambos átomos u otras listas.  Una lista puede
tener solo un átomo o no tener absolutamente nada en ella.  Una lista
con nada dentro se ve así: ‘()’, y se llama “lista vacía”.  A diferencia
de cualquier otra cosa, una lista vacía es tanto un átomo, como una
lista al mismo tiempo.

   La representación impresa de átomos y listas se llama “expresiones
simbólicas” o, más concisamente, “s-expresiones”.  La palabra
“expresión” por sí misma puede referir o bien a la representación
impresa, o al átomo o a la lista como se maneja internamente en el
ordenador.  Con frecuencia, las personas usan el término “expresión”
indiscriminadamente.  (También, en muchos textos, la palabra “forma” se
usa como un sinónimo para la expresión.)

   Por cierto, los átomos que componen nuestro universo fueron nombrados
así cuando se pensaba que eran indivisibles; pero pero se ha encontrado
que los átomos fisicos no son indivisibles.  Las partes pueden dividir
un átomo o puede fisionarse en 2 partes de igual tamaño.  Los átomos
físicos se nombraron prematuramente, antes de que su verdadera
naturaleza fuese encontrada.  En Lisp, ciertos tipos de átomos, como un
array, pueden ser separados en partes; pero el mecanismo de hacer esto
es diferente de el mecanismo para dividir una lista.  En lo que se
refiere a operaciones de lista, los átomos de una lista son
indivisibles.

   Como en español, el significado de las letras que componen un átomo
Lisp difiere del significado de las letras compuestas como una palabra.
Por ejemplo, la expresión ‘ay’, es completamente diferente de las dos
palabras ‘a’, e ‘y’.

   Hay muchos tipos de átomos en la naturaleza, pero solo unos pocos en
Lisp: por ejemplo, “números”, tales como 37, 511, o 1729, y “símbolos”,
tales como ‘+’, ‘foo’, o ‘forward-line’.  Las palabras que hemos listado
en los ejemplos anteriores son todos símbolos.  En una conversación
cotidiana de Lisp, la palabra "átomo" no se usa con frecuencia, porque
los programadores normalmente intentan ser más específicos acerca de que
tipo de átomo están tratando.  La programación Lisp es sobre todo de
símbolos (y algunas veces números) con listas.  (De ese modo, tres
palabras rodeadas de paréntesis son una apropiada lista en Lisp, ya que
consiste de átomos, que en este caso son símbolos, separados por
espacios en blanco y cerrados por paréntesis, sin ninguna puntuación no
Lisp.)

   Texto entre comillas--incluso frases o párrafos--son también un
átomo.  Aquí hay un ejemplo:

     '(esta lista incluye "texto entre comillas.")

En Lisp, todo el texto citado incluyendo la marca de puntuación y los
espacios en blanco son un solo átomo.  Este tipo de átomo es llamado
“string” (por 'cadena de caracteres') y es el tipo de cosa que es usada
para mensajes que un ordenador puede imprimir para que un humano lea.
Las cadenas son un tipo de átomo diferente a los números, o símbolos y
se usan de manera diferente.


File: emacs-lisp-intro-es.info,  Node: Espacios en blanco en listas,  Next: Escribiendo listas,  Prev: Átomos Lisp,  Up: Listas Lisp

1.1.2 Espacios en blanco en listas
----------------------------------

La cantidad de espacios en blanco en una lista no importa.  Desde el
punto de vista del lenguaje Lisp,

     '(esta lista
        parece esto)

es exactamente lo mismo que esto:

     '(esta lista parece esto)

   Ambos ejemplos muestran que en Lisp es la misma lista, la lista hecha
de los símbolos ‘esta’, ‘lista’, ‘parece’, y ‘esto’ en este orden.

   Los espacios en blanco adicionales y los saltos de línea están
diseñados para crear una lista más legible por humanos.  Cuando Lisp lee
la expresión, asimila los espacios en blanco extra (pero necesita tener
al menos un espacio entre átomos en orden para contarlos aparte.)

   Aunque parezca raro, los ejemplos que hemos visto cubren casi todo lo
aparece en las listas Lisp.  Cualquier otra lista en Lisp se ve más o
menos igual a uno de estos ejemplos, excepto que la lista puede ser más
larga y más compleja.  En resumen, una lista está entre paréntesis, una
cadena está entre comillas, un símbolo parece como una palabra, y un
número parece un número.  (Para ciertas situaciones, corchetes, puntos y
otros caracteres especiales pueden ser usados; sin embargo; iremos
bastante lejos sin ellos.)


File: emacs-lisp-intro-es.info,  Node: Escribiendo listas,  Prev: Espacios en blanco en listas,  Up: Listas Lisp

1.1.3 GNU Emacs te ayuda a escribir listas
------------------------------------------

Cuando se escribe una expresión Lisp en GNU Emacs usando bien el modo de
Interacción Lisp o el modo Emacs Lisp, están disponibles varios comandos
para formatear la expresión Lisp, de modo que sea fácil de leer.  Por
ejemplo, presionando la tecla <TAB> automáticamente se indenta la línea
donde se encuetra el cursor a la cantidad correcta.  Un comando para
indentar apropiadamente el código en una región está asociado a ‘M-C-\’.
La indentación está diseñada de modo que se pueda ver qué elementos
percecen a cada lista--los elementos de una sublista están más
indentados que los elementos de una lista cerrada.

   Además, cuando se escribe un paréntesis de cierre, Emacs
momentáneamente salta el cursor atrás para hacer el matching
(emparejamiento) con el paréntesis de apertura, para ver cuál es.  Esto
es muy útil, ya que cada lista que se escribe en Lisp debe tener sus
paréntesis emparejados con sus paréntesis de apertura.  (Ver *note Modos
Mayores: (El Manual de GNU Emacs)Modos Mayores, para más información
acerca de modos de Emacs.)


File: emacs-lisp-intro-es.info,  Node: Ejecutar un programa,  Next: Creando errores,  Prev: Listas Lisp,  Up: Procesamiento de listas

1.2 Ejecutar un programa
========================

Una lista en Lisp --cualquier lista-- es un programa listo para ser
ejecutado.  Si lo ejecutas (lo que la jerga Lisp llama “evaluar”), el
ordenador hará una de tres cosas: nada excepto devolverte la lista
misma; enviar un mensaje de error; o, tomar el primer símbolo en la
lista como un comando para hacer alguna cosa.  (¡Normalmente, es lo
último de estas tres cosas de lo que realmente se quiere!).

   El apóstrofe, ‘'’, que se pone enfrente de algúnos ejemplos de lista
en secciones anteriores se llama “quote”; (citar); cuando precede a una
lista, se informa a Lisp no hacer nada con la lista, mas que la tomarla
tal como está escrita.  Pero si no hay una cita precediendo la lista, el
primer ítem de la lista es especial: es un comando para que el ordenador
obedezca.  (En Lisp, estos comandos son llamados _funciones_.)  A
continuación se muestra la lista no citada ‘(+ 2 2)’, por lo que Lisp
comprende que ‘+’ es una instrucción para hacer alguna cosa con el resto
de la lista: suma los números que siguen.

   Si estás leyendo esto dentro de GNU Emacs en Info, aquí está como
puedes evaluar una lista: coloca tu cursor justo después del paréntesis
derecho de la siguiente lista y presiona ‘C-x C-e’:

     (+ 2 2)

Verás que el número ‘4’ aparece en el área echo.  (En la jerga, lo que
acabas de hacer es "evaluar la lista."  El área echo es la línea en la
parte inferior de la pantalla que muestra o hace "echo" del texto).
Ahora intenta la misma cosa con una lista citada: posiciona el cursor
justo después de la siguiente lista y presiona ‘C-x C-e’:

     '(esto es una lista con comillas)

Se verá aparecer ‘(esto es una lista con comillas)’ en el área echo.

   En ambos casos, lo que estás haciendo es dar un comando al programa
dentro de GNU Emacs llamado “intérprete Lisp” -- dando al intérprete un
comando para evaluar la expresión.  El nombre del intérprete Lisp viene
de la palabra para la tarea hecha por un humano que viene con el
significado de una expresión -- quien lo "interpreta".

   También se puede evaluar un átomo que no es parte de una lista -- uno
que no está rodeado por paréntesis; de nuevo, el intérprete Lisp traduce
desde la expresión humanamente legible al lenguaje del ordenador.  Pero
antes de discutir esto (ver *note Variables::), vamos a discutir lo que
el intérprete de Lisp hace cuando tu creas el error.


File: emacs-lisp-intro-es.info,  Node: Creando errores,  Next: Nombres y definiciones,  Prev: Ejecutar un programa,  Up: Procesamiento de listas

1.3 Generar un mensaje de error
===============================

No se preocupe si genera un mensaje de error de manera accidental, ahora
daremos un comando al intérprete de Lisp que genara un mensaje de error.
Esta es una accion inofensiva; y de hecho, a menudo se intenta generar
mensajes de error de manera intencional.  Una vez se comprende la jerga,
los mensajes de error pueden ser informativos.  En vez de ser llamados
mensajes de "error", deberían ser llamados mensajes de "ayuda".  Son
como letreros para un viajero en un país extraño; descifrarlos puede ser
duro, pero una vez comprendidos, pueden señalar el camino.

   El mensaje de error es generado por un depurador de código
incorporado dentro de GNU Emacs.  Así se 'entra al depurador'.  Se puede
salir del depurador pulsando ‘q’.

   Lo que se hace es evaluar una lista que no está citada y no tiene un
comando con significado como su primer elemento.  Aquí hay una lista
casi exactamente igual a la que acabamos de usar, pero sin la cita al
inicio.  Coloque el cursor a la derecha donde esta finaliza y presione
‘C-x C-e’:

     (esto es una lista sin cita)

   Se abrirá una ventana ‘*Backtrace*’ y se verá lo siguiente:

     ---------- Buffer: *Backtrace* ----------
     Debugger entered--Lisp error: (void-function esto)
       (esto es una lista sin cita)
       eval((esto es una lista sin cita) nil)
       eval-last-sexp-1(nil)
       eval-last-sexp(nil)
       call-interactively(eval-last-sexp nil nil)
       command-execute(eval-last-sexp)
     ---------- Buffer: *Backtrace* ----------

Su cursor estará en esta ventana (puede tener que esperar unos pocos
segundos antes de que sea visible).  Para salir del depurador y de su
ventana, presione:

     q

Por favor, ahora pulsa ‘q’, así se comprueba que se puede salir del
depurador.  A continuacion, presione "‘C-x C-e’ una vez más para
re-entrar.

   Sobre la base de lo que ya sabemos, casi podemos leer este mensaje de
error.

   Leer el búffer ‘*Backtrace*’ de abajo hacia arriba; informa lo que
Emacs ha hecho.  Cuando se presiona ‘C-x C-e’, se hace una llamada
interactiva a el comando ‘eval-last-sexp’.  ‘eval’ es una abreviatura
para 'evaluar' y ‘sexp’ es una abreviatura para 'expresión simbólica'.
El comando significa 'evalúa la última expresión simbólica', que es la
expresión justo antes de tu cursor.

   Cada línea anterior a esta cuenta lo que el intérprete de Lisp evaluo
después.  La acción más reciente está en la parte superior.  El búffer
es llamado ‘*Backtrace*’ ya que permite realizar un seguimiento de Emacs
hacia atrás.

   En la parte superior del búffer ‘*Backtrace*’, verá la línea:

     Debugger entered--Lisp error: (void-function esto)

El intérprete Lisp intentó evaluar el primer átomo de la lista, la
palabra ‘esto’.  Esta es la acción que generó el mensaje de error
‘void-function esto’.

   El mensaje contiene las palabras ‘void-function’ y ‘esto’.

   La palabra ‘function’ fué mencionada antes.  Es una palabra muy
importante.  Para nuestros propósitos, podemos definirla diciendo que
una “función” (_function_) es un conjunto de instrucciones para decirle
al ordenador que haga alguna cosa.

   Ahora podemos empezar a comprender el mensaje de error:
‘void-function this’.  La función (que es, la palabra ‘this’) no tiene
la definición de ningun conjunto de instrucciones que el ordenador pueda
realizar.

   La palabra ligeramente extraña, ‘void-function’, está diseñada para
cubrir la forma en que Emacs Lisp lo implementa, que es cuando un
símbolo no tiene una definición de función atribuido, el sitio que
contiene la instrucción esta 'vacío' (‘void’).

   Por otro lado, ya que fuimos capaces de añadir 2 más 2 de manera
exitosa, evaluando ‘(+ 2 2)’, se puede inferir que el símbolo ‘+’ debe
tener un conjunto de instrucciones que el ordenador ejecuta y estas
instrucciones deben sumar los números despues del ‘+’.

   Es posible evitar que Emacs entre en el depurador en casos como este.
No se explicará cómo hacer esto aquí, pero se mencionará un resultado
asi, porque se puede encontrar una situación similar si hay un error en
algún código de Emacs que este usando.  En tales casos, verá solo una
línea del mensaje de error; aparecer en el área echo con el siguente
aspecto

     Symbol's function definition is void: esto

El mensaje aparece tan pronto se presiono una tecla, aunque sólo sea
para mover el cursor.

   Conocemos el significado de la palabra ‘Símbolo’.  Se refiere al
primer átomo de la lista, la palabra ‘este’.  La palabra ‘función’ se
refiere a las instrucciones que dicen al ordenador que hacer.
(Técnicamente, el símbolo indica al ordenador donde encontrar las
instrucciones, pero esta es una complicación que podemos ignorar por el
momento.)

   El mensaje de error puede ser comprendido: ‘La definición del símbolo
está vacía: este’.  El símbolo (que es, la palabra ‘este’) carece de
instrucciones que el ordenador realize.


File: emacs-lisp-intro-es.info,  Node: Nombres y definiciones,  Next: Interpréte Lisp,  Prev: Creando errores,  Up: Procesamiento de listas

1.4 Nombres de símbolos y definiciones de funciones
===================================================

Se puede articular otra característica de Lisp basada en lo que se
discutió hace tiempo--una característica importante: un símbolo, como
‘+’, no es en sí mismo el conjunto de instrucciones que el ordenador
realiza.  En su lugar, el símbolo es usado, quizás temporalmente, como
una manera de localizar la definición o conjunto de instrucciones.  Lo
que vemos es el nombre con el cual se pueden encontrar las
instrucciones.  Los nombres de las personas funcionan de la misma
manera.  Por ejemplo, puede referirse a mi como ‘Bob’; sin embargo, no
soy las letras ‘B’, ‘o’, ‘b’ pero soy, o o fuí, conscientemente asociado
con una forma de vida particular.  El nombre no soy yo, pero puede ser
usado para referirme.

   En Lisp, un conjunto de instrucciones puede ligarse a varios nombres.
Por ejemplo, las instrucciones de ordenador para añadir números pueden
ser enlazados al símbolo ‘más’ tan bien como el símbolo ‘+’ (y se
encuantran en algunos dialectos de Lisp).  Entre humanos, puede
referirse a ‘Robert’ tan bien como ‘Bob’ y en otras palabras también.

   Por otra parte, un símbolo puede estar ligado solo con una función a
la vez.  De lo contrario, el ordenador estaría confundido acerca de qué
definición usar.  Si este fuera el caso, solo una persona en el mundo
podría llamarse ‘Bob’.  Sin embargo, la definición de función a la que
el nombre hace referencia puede cambiarse fácilmente.  (Ver *note
Instalar una Definición de Función: Instalar.)

   Ya que Emacs Lisp es extenso, se acostumbra nombrar los símbolos de
un modo que pueda establecerse a que parte de Emacs pertenece la
función.  En consecuencia, todos los nombres de funciones relacionadas
con Texinfo empiezan con ‘texinfo-’ y aquellas relaciondas con la
lectura de correo empiezan con ‘rmail-’.


File: emacs-lisp-intro-es.info,  Node: Interpréte Lisp,  Next: Evaluación,  Prev: Nombres y definiciones,  Up: Procesamiento de listas

1.5 El intérprete Lisp
======================

Basado en lo que se ha visto, ahora podemos empezar a entender lo que el
intéprete Lisp hace cuando mandamos a evaluar una lista.  Primero,
examina si hay un símbolo cita antes de la lista; si lo hay, el
intérprete nos da la lista.  Por otro lado, si no hay cita, el intéprete
mira si el primer elemento en la lista tiene una definición de función.
Si no, el intérprete imprime un mensaje de error.

   Así es como Lisp trabaja.  Simple.  Hay complicaciones añadidas que
veremos en un minuto, pero estos son los fundamentos.  Claro está, para
escribir programas Lisp, se necesita conocer como escribir definiciones
de función y vincularlas a nombres, y como hacer esto sin confundirnos a
nosotros mismos o al ordenador.

* Menu:

* Complicaciones::           Variables, formas especiales, Listas.
* Compilación de bytes::   Especialmente procesando código por la
                               velocidad.


File: emacs-lisp-intro-es.info,  Node: Complicaciones,  Next: Compilación de bytes,  Up: Interpréte Lisp

Complicaciones
--------------

Ahora, una primera complicación.  Además de las listas, el intérprete
Lisp puede evaluar un símbolo no citado que no tiene paréntesis en torno
a el.  El intérprete Lisp intentará determinar el valor del símbolo como
una “variable”.  Esta situación es descrita en el apartado de las
variablesla.  (Ver *note Variables::.)

   La segunda complicación ocurre debido a que algunas funciones son
inusuales y no funcionan de la manera habitual.  Estas son llamadas
“formas especiales”.  Son usadas para trabajos especiales, como definir
una función, y no son muchas de ellas.  En los siguientes capítulos, se
introducirán varias de las formas especiales más importantes.

   La tercera y final complicación es la siguiente: si la función que el
intérprete Lisp está buscando no es una forma especial, y si es parte de
una lista, el intérprete Lisp mira si la lista tiene una lista dentro de
ella.  Si hay una lista dentro, el intérprete Lisp primero descubre qué
hacer con la lista interior, y luego trabaja en la lista exterior.  Si
aún hay otra lista embebida dentro de la lista interna, trabaja en esta
primero, y así.  Siempre se trabaja en la lista más interna primero.  El
intérprete trabaja en la lista más interana primero, para evaluar el
resultado de esta lista.  El resultado puede ser usado por la expresión
entre paréntesis.

   Por lo demás, el intérprete trabaja de izquierda a derecha, desde una
expresión a la siguiente.


File: emacs-lisp-intro-es.info,  Node: Compilación de bytes,  Prev: Complicaciones,  Up: Interpréte Lisp

1.5.1 Compilación de bytes
--------------------------

Otro aspecto de interpretación: el intérprete Lisp es capaz de
interpretar dos tipos de entidad: código humanamente legible, en el que
nos centraremos exclusivamente, y código especialmente procesado,
llamado “byte compilado”, que no es humanamente legible.  El código
máquina compilado se ejecuta más rápido que el código humanamente
legible.

   Tu puedes transformar código legible por humanos en código compilado
ejecutando uno de los comandos de compilacion como ‘byte-compile-file’.
El código compilado es normalmente almacenado en un fichero que finaliza
con una extensión ‘.elc’ en vez de una extensión ‘.el’.  Verás ambos
tipos de ficheros en el directorio ‘emacs/lisp’; los ficheros para leer
estos tienen la extensión ‘.el’.

   Como una cuestión práctica, para hacer la mayoría de las cosas como
personalizar o extender Emacs, no necesitas compilar byte; y no
comentare el asunto aquí.  Ver *note Compilación de Byte:
(elisp)Compilación de Byte, para una completa descripción sobre compilar
código.


File: emacs-lisp-intro-es.info,  Node: Evaluación,  Next: Variables,  Prev: Interpréte Lisp,  Up: Procesamiento de listas

1.6 Evaluación
==============

Cuando el intérprete Lisp trabaja en una expresión, el término para la
actividad es llamada “evaluación”.  Decimos que el intérprete 'evalúa la
expresión'.  Yo he usado este término varias veces antes.  La palabra
proviene de su uso en el lenguaje cotidiano, 'para determinar el valor o
la cantidad de; para estimar' de acuerdo a ‘Webster's New Collegiate
Dictionary’.

* Menu:

* Cómo el intérprete actúa::  Devolver y Efectos Colaterales...
* Evaluando listas propias::  Listas con listas...


File: emacs-lisp-intro-es.info,  Node: Cómo el intérprete actúa,  Next: Evaluando listas propias,  Up: Evaluación

Cómo el intérprete actúa
------------------------

Después de evaluar una expresión, el intérprete Lisp normalmente
“devuelve” el valor que el ordenador produce al llevar a cabo las
instrucciones encontradas en la definición de la función, o quizás dará
esta función y producirá un mensaje de error.  (El intérprete puede
también quedarse colgado, por así decirlo, a una función diferente o
puede intentar repetir continuamente lo que está haciendo y para siempre
en lo que se llama un 'bucle infinito'.  Estas acciones son menos
comunes; y pueden ignorarse).  Más frecuentemente, el intérprete
devuelve un valor.

   Al mismo tiempo el intérprete devuelve un valor, puede hacer
cualquier cosa más también, tal como mover un cursor o copiar un
fichero; este otro tipo de acción es llamado “efecto secundario”.
Acciones que los humanos creen que son importantes tales como imprimir
resultados, con frecuencia son, "efectos secundarios" del intérprete
Lisp.  La jerga puede sonar peculiar, pero resulta que es bastante fácil
aprender a utilazar los efectos secundarios.

   En resumen, evaluar una expresión simbólica normalmente causa que el
intérprete devuelva un valor y tal vez llevar a cabo un efecto
secundario; o al menos produce un error.


File: emacs-lisp-intro-es.info,  Node: Evaluando listas propias,  Prev: Cómo el intérprete actúa,  Up: Evaluación

1.6.1 Evaluando listas propias
------------------------------

Si la evaluación se aplica a una lista que está dentro de una lista, la
lista externa puede usar el valor devuelto por la primera evaluación
como información cuando la lista externa es evaluada.  Esto explica por
qué las expresiones internas son evaluadas primero: los valores
devueltos son usados por las expresiones externas.

   Nosotros podemos investigar este proceso evaluando otro ejemplo
adicional.  Coloca tu cursor después de la siguiente expresión y
presiona ‘C-x C-e’:

     (+ 2 (+ 3 3))

El número 8 aparecerá en el área echo.

   Lo que ocurre es que el intérprete Lisp primero evalúa la expresión
interna, ‘(+ 3 3)’, para que el valor 6 se devuelva; a continuación
evalúa la expresión externa como si fuera escrita ‘(+ 2 6)’, que
devuelve el valor 8.  Puesto que no hay más expresiones entre parentesis
a evaluar el intérprete imprime este valor en el área echo.

   Ahora es fácil comprender el nombre del comando invocado por el atajo
‘C-x C-e’: el nombre es ‘eval-last-sexp’.  Las letras ‘sexp’ son una
abreviación para 'expresión simbólica', y ‘eval’ es una abreviación para
'evaluar'.  El comando significa 'evaluar la última expresión
simbólica'.

   Como un experimento, puedes intentar evaluar la expresión poniendo el
cursor al principio de la siguiente línea inmediatamente después de la
expresión, o dentro de la expresión.

   Aquí hay otra copia de la expresión:

     (+ 2 (+ 3 3))

Si se posiciona el cursor al principio de la línea en blanco que sigue
inmediatamente a la expresión y presionas ‘C-x C-e’, todavía se obtendrá
el valor 8 impreso en el área echo.  Ahora intenta poner el cursor
dentro de la expresión.  Si lo coloca justo después del penultimo
paréntesis (dara la impresión de situarse sobre el último paréntesis),
¡obtendrá un 6 impreso en el área echo!  Esto es porque el comando
evalúa la expresión ‘(+ 3 3)’.

   Ahora coloque el cursor inmediatamente después de un número.
Presiona ‘C-x C-e’ y obtendrá el número en sí.  En Lisp, si evalúas un
número, obtienes el número en sí--así es cómo los números difieren de
los símbolos.  Si se evalúa una lista que inicia con un símbolo como
‘+’, tendrás un valor devuelto que es el resultado del ordenador tras
ejecutar las instrucciones que aparecen en la definición de la función
adjunta a este nombre.  Si un símbolo por sí mismo es evaluado, algo
diferente sucede, como veremos en la siguiente sección.


File: emacs-lisp-intro-es.info,  Node: Variables,  Next: Argumentos,  Prev: Evaluación,  Up: Procesamiento de listas

1.7 Variables
=============

En Emacs Lisp, un símbolo puede estar ligado a un valor como a una
definición de función.  Las dos son diferentes.  La definición de
función es un conjunto de instrucciones que el ordenador ejecuta.  Un
valor, por otro lado, es algo, como un número o un nombre, que puede
variar (es por ello, que tal símbolo es llamado variable).  El valor de
un símbolo puede ser cualquier expresión en Lisp, por ejemplo un
símbolo, número, lista, o cadena.  Un símbolo que tiene un valor es con
frecuencia llamado una “variable”.

   Un símbolo puede tener ambos, una definición de función y un valor
adjunto al mismo tiempo.  O puede tener solo uno u otro.  Los dos son
independientes.  Esto es algo similar a la forma en que el nombre
Cambridge puede referirse a la ciudad en Massachusetts y tener alguna
información ligada al nombre, por ejemplo, un "gran centro de
programación".

   Otra forma de pensar en esto es imaginar un símbolo como un mueble
con cajones.  La definición de función se pone en un cajón, el valor en
otro, y asi sucesivamente.  Lo que se pone en el cajón que contiene el
valor puede ser cambiado sin afectar los contenidos del cajón que
almacena la definición de función, y viceversa.

* Menu:

* Ejemplo de rellenar columna::  Ejemplo de rellenar columna
* Función vacía::  El mensaje de error para un
                                     símbolo sin una función.
* Variable vacía::  El mensaje de error para un
                                    símbolo sin un valor.


File: emacs-lisp-intro-es.info,  Node: Ejemplo de rellenar columna,  Next: Función vacía,  Up: Variables

‘fill-column’, un ejemplo de variable
-------------------------------------

La variable ‘fill-column’ ilustra un símbolo con un valor adjunto: en
cada buffer de GNU Emacs, este símbolo se establece a algún valor,
normalmente 72 o 70, pero algunas veces a algún otro valor.  Para
encontrar el valor de este símbolo, evalúalo por sí mismo.  Si está
leyendo esto en Info dentro de GNU Emacs, puedes hacer esto poniendo el
cursor después del símbolo y pulsar ‘C-x C-e’:

     fill-column

Después de presionar ‘C-x C-e’, Emacs imprimió el número 72 en mi área
echo.  Este es el valor que he establecido para ‘fill-column’ mientras
escribo esto.  Puede ser diferente para ti en tu búffer Info.  Observe
que el valor devuelto como una variable es impreso exactamente de la
misma forma que el valor devuelto por una función tras ejecutar sus
instrucciones.  Desde el punto de vista del intérprete Lisp, un valor
devuelto es un valor devuelto.  Que tipo de expresión sea, deja de
importar una vez que el valor se conoce.

   Un símbolo puede tener cualquier valor ligado a él o, siendo
tecnicos, se puede “bind” (asociar) la variable a un valor: a un número,
por ejemplo 72; a una cadena, ‘\"como esta\"’; a una lista, como ‘(abeto
pino roble)’; podemos incluso asociar una variable a una definición de
función.

   Un símbolo puede vincularse a un valor de varias maneras.  Ver *note
Configurando el valor de una variable: set y setq, para obtener
información sobre una manera de hacer esto.


File: emacs-lisp-intro-es.info,  Node: Función vacía,  Next: Variable vacía,  Prev: Ejemplo de rellenar columna,  Up: Variables

1.7.1 Mensaje de error de un símbolo sin una función
----------------------------------------------------

Cuando se evalúa ‘fill-column’ para encontrar el valor de una variable,
no se ponen paréntesis alrededor de la palabra.  Esto es porque no
pretendemos usarlos como un nombre de función.

   Si ‘fill-column’ fuese el primer o único elemento de una lista, el
intérprete de Lisp intentaría encontrar la definición de función
adjunta.  Pero ‘fill-column’ no tiene una definición de función.  Prueba
evaluando esto:

     (fill-column)

Se creará un buffer ‘*Backtrace*’ que dice:

     ---------- Buffer: *Backtrace* ----------
     Debugger entered--Lisp error: (void-function fill-column)
       (fill-column)
       eval((fill-column))
       eval-last-sexp-1(nil)
       eval-last-sexp(nil)
       call-interactively(eval-last-sexp)
     ---------- Buffer: *Backtrace* ----------

(Recuerda, para salir del depurador y hacer que la ventana del depurador
desaparezca, presiona ‘q’ en el buffer ‘*Backtrace*’.)


File: emacs-lisp-intro-es.info,  Node: Variable vacía,  Prev: Función vacía,  Up: Variables

1.7.2 Mensaje de error de un símbolo sin un valor
-------------------------------------------------

Si se intenta evaluar un símbolo que no tiene un valor asociado,
recibirá un mensaje de error.  Esto se puede ver experimentando con
nuestra suma 2 más 2.  En la siguiente expresión, pon el cursor correcto
después del ‘+’, antes del primer número 2, presiona ‘C-x C-e’:

     (+ 2 2)

En GNU Emacs 24, se creará un buffer ‘*Backtrace*’ que dice:

     ---------- Buffer: *Backtrace* ----------
     Debugger entered--Lisp error: (void-variable +)
       eval(+)
       eval-last-sexp-1(nil)
       eval-last-sexp(nil)
       call-interactively(eval-last-sexp)
     ---------- Buffer: *Backtrace* ----------

(De nuevo, se puede salir del depurador pulsando ‘q’ en el búffer
‘*Backtrace*’.)

   Esta traza es diferente del primer mensaje de error que vimos, que
dijimos, ‘Debugger entered--Lisp error: (void-function esto)’.  En este
caso, la función no tiene una valor como una variable; mientras en el
otro mensaje de error, la función (la palabra 'esto') no tuvo una
definición.

   En este experimento con el ‘+’, lo que se hizo fué causar que el
intérprete Lisp evalúe el ‘+’ y busque el valor de la variable en vez de
la definición de la función.  Hicimos esto colocando el cursor justo
después del símbolo en lugar de ponerlo al final de los paréntesis que
cierran la lista como hicimos antes.  Como consecuencia, el intérprete
Lisp evaluó la s-expresión anterior, que en este caso fué el ‘+’ en sí.

   Ya que ‘+’ no tiene un valor asociado, solo la definición de función,
el mensaje de error informa que el valor del símbolo como una variable
estaba vacío.


File: emacs-lisp-intro-es.info,  Node: Argumentos,  Next: set y setq,  Prev: Variables,  Up: Procesamiento de listas

1.8 Argumentos
==============

Para ver cómo la información se pasa a las funciones, veamos de nuevo a
nuestro viejo recurso, la adición de dos más dos.  En Lisp, esto se
escribe como sigue:

     (+ 2 2)

   Si se evalúa esta expresión, el número 4 aparecerá en tu área echo.
Lo que el intérprete de Lisp hace es sumar los números despues del ‘+’.

   Los números sumados por ‘+’ son llamados “argumentos” de la función
‘+’.  Estos números son la información que se da o “pasa” a la función.

   La palabra 'argumento' viene del ámbito de las matemáticas y no se
refiere a una disputa entre 2 personas, sino que se refiere a la
información presentada a la función, en este caso, al ‘+’.  En Lisp, los
argumentos de una función son los átomos o listas que siguen a la
función.  Los valores devueltos por la evaluación de estos átomos o
listas son pasados a la función.  Funciones diferentes requieren
diferentes números de argumentos; algunas funciones no requieren ninguno
en absoluto.(1)

* Menu:

* Tipos de datos::           Tipos de datos pasados a una función.
* Argumentos como variables o listas::  Un argumento puede ser el valor de
                                          una variable o lista.
* Número de variables de argumentos::  Algunas funciones pueden tomar un
                                           número variable de argumentos.
* Tipo incorrecto de argumento::  Pasando un argumento del tipo incorrecto a
                                    una función.
* message::                  Una función útil para enviar mensajes.

   ---------- Footnotes ----------

   (1) Es curioso trazar la ruta por la cual la palabra 'argumento'
llego a tener dos significados distintos, uno en matemáticas y el otro
en el inglés cotidiano.  De acuerdo al ‘Oxford English Dictionary’, la
palabra deriva del Latín para ‘dejar claro, probar’, por lo tanto, paso
a significar, por un hilo de derivación, 'la evidencia ofrecida como
prueba', es decir 'la información que se ofrece', que conduce a su
significado en Lisp.  Pero en el otro hilo de derivación, paso a
significar 'afirmar de una manera lo que otros pueden afirmar en
contra', lo que llevó a la disputa del significado de la palabra.
(Nótese aquí que la palabra Inglésa tiene dos definiciones diferentes
adjuntas al mismo tiempo.  En contraste, en Emacs Lisp, un símbolo no
puede tener dos definiciones de función diferentes al mismo tiempo.)


File: emacs-lisp-intro-es.info,  Node: Tipos de datos,  Next: Argumentos como variables o listas,  Up: Argumentos

1.8.1 Tipos de argumentos de datos
----------------------------------

Los tipos de datos que deberían ser pasados a una función dependen de
que tipo de información usan.  Los argumentos de una función como ‘+’
deben tener valores que son números, puesto que ‘+’ añade números.
Otras funciones usan diferentes tipos de datos para sus argumentos.

   Por ejemplo, la función ‘concat’ concatena o une dos o más cadenas de
texto para producir una cadena.  Los argumentos son cadenas.  La
concatenación de los dos caracteres de cadenas ‘abc’, ‘def’ produce una
cadena ‘abcdef’.  Esto puede ser visto evaluando lo siguiente:

     (concat "abc" "def")

El valor producido para evaluar esta expresión es ‘"abcdef"’.

   Una función tal como ‘substring’ usa como argumento tanto una cadena
como números.  La función devuelve una parte de la cadena, una subcadena
del primer argumento.  Esta función toma tres argumentos.  Su primer
argumento es la cadena de caracteres, el segundo y tercer argumento son
números que indican el principio y el fin de la subcadena.  Los números
son un conteo del número de caracteres (incluyendo espacios y
puntuaciones) desde el principio de la cadena.

   Por ejemplo, si evalúa lo siguiente:

     (substring "El rápido zorro marrón saltó." 10 15)

se verá ‘"zorro"’ en el área echo.  Los argumentos son la cadena y los
dos números.

   Nótese que la cadena pasada a ‘substring’ es un solo átomo apesar de
estar compuesto de varias palabras separadas por espacios.  Lisp
considera que cualquier cosa entre dos marcas de cita es parte de la
cadena, incluyendo los espacios.  Se puede pensar la función ‘substring’
como un tipo de 'acelerador de particulas' ya que toma un átomo
indivisible y extrae una parte.  Sin embargo, ‘substring’ solo es capaz
de extraer una subcadena desde un argumento que es una cadena, no otro
tipo de átomo tal como un número o símbolo.


File: emacs-lisp-intro-es.info,  Node: Argumentos como variables o listas,  Next: Número de variables de argumentos,  Prev: Tipos de datos,  Up: Argumentos

1.8.2 Un argumento como el valor de una variable o lista
--------------------------------------------------------

Un argumento puede ser un símbolo que devuelva un valor cuando es
evaluado.  Por ejemplo, evaluar el símbolo ‘fill-column’ en si, devuelve
un número.  Este número puede ser usado en una adición.

   Posicionar el cursor después de la siguiente expresión y presiona
‘C-x C-e’:

     (+ 2 fill-column)

El valor será dos más el número que se obtiene al evaluar solamente
‘fill-column’.  En mí caso, este es 74, porque mi valor de ‘fill-column’
es 72.

   Como acabamos de ver, un argumento puede ser un símbolo que devuelve
un valor cuando se evalúa.  Además, un argumento puede ser una lista que
devuelve un valor cuando es evaluada.  Por ejemplo, en la siguiente
expresión, los argumentos de la función ‘concat’ son las cadenas ‘"Los"’
y ‘" zorros rojos."’ y la lista ‘(number-to-string (+ 2 fill-column))’.

     (concat "Los " (number-to-string (+ 2 fill-column)) " zorros rojos.")

Si se evalúa esta expresión--y si, como con mi Emacs, ‘fill-column’ se
evalúa a 72--aparecerá ‘"Los 74 zorros rojos."’ en el área echo.
(Nótese que se debe poner espacio después de la palabra ‘Los’ y antes de
la palabra ‘rojos’ y así es como aparecerá en la cadena final.  La
función ‘number-to-string’ convierte el entero que devuelve la función
de adición a una cadena.  ‘number-to-string’ también se conoce como
‘int-to-string’.)


File: emacs-lisp-intro-es.info,  Node: Número de variables de argumentos,  Next: Tipo incorrecto de argumento,  Prev: Argumentos como variables o listas,  Up: Argumentos

1.8.3 Número de variables de argumentos
---------------------------------------

Algunas funciones, como ‘concat’, ‘+’, o ‘*’, toman cualquier número de
argumentos.  (El ‘*’ es el símbolo para multiplicar.)  Esto puede ser
visto evaluando cada una de las siguientes expresiones de la forma
habitual.  Lo que verás en el área echo se imprime en este texto después
de ‘⇒’, que se puede leer como 'evaluar a'.

   En el primer conjunto, las funciones no tienen argumentos:

     (+)       ⇒ 0

     (*)       ⇒ 1

   En este conjunto, las funciones tienen un argumento cada una:

     (+ 3)     ⇒ 3

     (* 3)     ⇒ 3

   En este conjunto, las funciones tienen tres argumentos cada una:

     (+ 3 4 5) ⇒ 12

     (* 3 4 5) ⇒ 60


File: emacs-lisp-intro-es.info,  Node: Tipo incorrecto de argumento,  Next: message,  Prev: Número de variables de argumentos,  Up: Argumentos

1.8.4 Usando el tipo incorrecto de objeto como un argumento
-----------------------------------------------------------

Cuando a una función se le pasa un argumento del tipo incorrecto, el
interpréte Lisp produce un mensaje de error.  Por ejemplo, la función
‘+’ espera que los valores de sus argumentos sean números.  Como un
experimento podemos pasar el símbolo citado ‘hola’ en vez de un número.
Coloca el cursor después de la siguiente expresión y presiona ‘C-x C-e’:

     (+ 2 'hola)

Al hacer esto se generará un mensaje de error.  Lo qué ha ocurrido es
que ‘+’ ha intentado añadir el 2 al valor devuelto por ‘'hola’, pero el
valor devuelto por ‘'hola’ es el símbolo ‘hola’, no un número.  Solo los
números pueden ser añadidos.  Por tanto ‘+’ no pudo llevar a cabo su
adición.

   Se creará e introducirá un búffer ‘*Backtrace*’ que dice:

     ---------- Buffer: *Backtrace* ----------
     Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p hola)
       +(2 hola)
       eval((+ 2 (quote hola)))
       eval-last-sexp-1(nil)
       eval-last-sexp(nil)
       call-interactively(eval-last-sexp)
     ---------- Buffer: *Backtrace* ----------

   Como de costumbre, el mensaje de error intenta ser útil y tiene
sentido después de aprender cómo leerlo.(1)

   La primera parte del mensaje de error es sencilla; dice ‘wrong type
argument’ (tipo de argumento incorrecto).  A continuación viene la
misteriosa palabra tecnica ‘number-or-marker-p’.  Esta palabra está
intentando decirte qué tipo de argumento espera ‘+’.

   El símbolo ‘number-or-marker-p’ dice que el intérprete Lisp está
intentando determinar si la información presentada (el valor del
argumento) es un número o una marca (un objeto especial que representa
una posición de buffer).  Lo que hace es probar si se le estan dando
numeros a sumar a ‘+’.  También chequea si el argumento es algo llamado
un marcador, que es una caracteristica específica de Emacs Lisp.  (En
Emacs, las ubicaciones en un búffer se registran como marcadores.
Cuando se establece la marca con el comando ‘C-@’ o ‘C-<SPC>’, su
posición se guarda como un marcador.  La marca puede ser considerada
como un número--el número de caracteres es la localización desde el
principio del búffer.)  En Emacs Lisp, ‘+’ se puede utilizar para añadir
el valor numérico de los marcadores como números.

   La ‘p’ de ‘number-or-marker-p’ es la encarnación de una práctica
iniciada en los primeros días de la programación Lisp.  La ‘p’ significa
'predicado'.  En la jerga usada por los primeros investigadores de Lisp,
un predicado se refiere a una función para determinar si alguna
propiedad es verdadera o falsa.  Así la ‘p’ nos dice que
‘number-or-marker-p’ es el nombre de una función que determina si el
argumento dado es un número o una marca.  Otros símbolos Lisp que
finalizan en ‘p’ incluyen ‘zerop’, una función que chequea si su
argumento tienen el valor de cero, y ‘listp’, una función que prueba si
su argumento es una lista.

   Finalmente, la última parte del mensaje de error es el símbolo
‘hola’.  Este es el valor del argumento dado a ‘+’.  Si a la adición se
le hubiese pasado el tipo correcto de objeto, el valor habría sido un
número, como 37, en lugar de un símbolo como ‘hola’.  Pero entonces no
habrías obtenido el mensaje de error.

   ---------- Footnotes ----------

   (1) ‘(quote hola)’ es una expansión de la abreviatura ‘'hola’.


File: emacs-lisp-intro-es.info,  Node: message,  Prev: Tipo incorrecto de argumento,  Up: Argumentos

1.8.5 La función ‘message’
--------------------------

Al igual que ‘+’, la función ‘message’ toma un número variable de
argumentos.  Se utiliza para enviar mensajes al usuario y es tan útil
que vamos a describirla.

   Se impre un mensaje en el área echo.  Por ejemplo, puede imprimir un
mensaje en su área echo evaluando la siguiente lista:

     (message "¡Este mensaje aparece en el área echo!")

   Toda la cadena entre comillas dobles es un unico argumento y se
imprime en su totalidad.  (Nótese que en este ejemplo, el mensaje en sí
aparece en el área echo entre comillas dobles; esto se debe a que ves el
valor devuelto por la función ‘message’.  En la mayoría de programas que
escribiras, el texto será impreso en el área echo como un efecto
secundario de ‘message’, sin las comillas.  Ver *note
‘multiply-by-seven’ en detalle: multiply-by-seven en detalle, para un
ejemplo de esto.)

   Sin embargo, si hay un ‘%s’ en la cadena de caracteres citada, la
función ‘message’ no imprime el ‘%s’ como tal, pero mira el siguente
argumento a continuación de la cadena.  Se evalúa el segundo argumento e
imprime el valor en la ubicación de la cadena donde está el ‘%s’ .

   Puede ver esto colocando el cursor después de la siguiente expresión
y presionar ‘C-x C-e’:

     (message "El nombre de este búffer es: %s." (buffer-name))

En Info, ‘"El nombre de este búffer es: *info*."’ aparecerá en el área
echo.  La función ‘buffer-name’ devuelve el nombre del búffer como una
cadena, que la función ‘message’ inserta en lugar de ‘%s’.

   Para imprimir un valor como un entero, utiliza ‘%d’ de la misma forma
que ‘%s’.  Por ejemplo, para imprimir un mensaje en el área echo que
indique el valor de ‘fill-column’, evalúa lo siguiente:

     (message "El valor de fill-column es %d." fill-column)

En mi sistema, cuando evalúo esta lista, ‘"El valor de fill-column es
72"’ aparece en mi área echo(1)

   Si hay más de un ‘%s’ en la cadena citada, el valor del primer
argumento después de la cadena citada se imprime en la posición del
primer ‘%s’ y el valor del segundo argunmento se imprime en la posición
del segundo ‘%s’, y así sucesivamente.

   Por ejemplo, si se evalúa lo siguiente,

     (message "¡Hay %d %s en la oficina!"
              (- fill-column 14) "elefantes rosas")

un mensaje característico aparecerá en el área echo.  En mi sistema dice
‘"¡Hay 58 elefantes rosas en la oficina!"’

   Se evalua la expresión ‘(- fill-column 14)’ y el número resultante se
inserta en lugar del ‘%d’; y la cadena entre comillas dobles,
‘"elefantes rosas"’, se trata como un solo argumento y se inserta en
lugar del ‘%s’.  (Esto es decir, una cadena entre comillas dobles se
evalúa así misma, como un número.)

   Finalmente, aquí está un ejemplo algo complejo que no solo ilustra el
cálculo de un número, también muestra como se puede usar una expresión
dentro de una expresión para generar el texto que sustituira el ‘%s’:

     (message "Él vió %d %s"
              (- fill-column 36)
              (concat (substring
                       "Los rápidos zorros marrones saltaron." 12 18)
                       " rojos trotando."))

   En este ejemplo, ‘message’ tiene tres argumentos: la cadena, ‘"Él vió
%d %s"’, la expresión, ‘(- fill-column 32)’, y la expresión a partir de
la función ‘concat’.  El valor resultante desde la evaluación de ‘(-
fill-column 32)’ se inserta en lugar del ‘%d’; y el valor devuelto por
la expresión que inicia con ‘concat’ se inserta en lugar del ‘%s’.

   Cuando ‘fill-column’ es 70 y se evalúa la expresión, aparecera el
mensaje ‘"Él vió 41 zorros rojos trotando."’ en tu área echo.

   ---------- Footnotes ----------

   (1) Actualmente, puede usar ‘%s’ para imprimir un número.  Es no
específico.  ‘%d’ imprime solo la parte de un número a la izquierda del
punto decimal, y no cualquier cosa que no es un número.


File: emacs-lisp-intro-es.info,  Node: set y setq,  Next: Resumen,  Prev: Argumentos,  Up: Procesamiento de listas

1.9 Configurando el valor de una variable
=========================================

Hay varias formas de asignar un valor a una variable.  Una de ellas es
usar la función ‘set’ o la función ‘setq’.  Otra forma es usar ‘let’
(*note let::).  (La jerga para este proceso es “bind” (ligar) una
variable a un valor.)

   Las siguientes secciones no solo describen cómo operan ‘set’ y
‘setq’, también ilustran como se pasan los argumentos.

* Menu:

* Usando set::               Configurando valores.
* Usando setq::              Configurando un valor citado.
* Contando::                 Usando ‘setq’ para contar.


File: emacs-lisp-intro-es.info,  Node: Usando set,  Next: Usando setq,  Up: set y setq

1.9.1 Usando ‘set’
------------------

Para establecer el valor del símbolo ‘flores’ a la lista ‘'(rosa violeta
margarita botóndeoro)’, evalúa la siguiente expresión colocando el
cursor después de la expresión y presiona ‘C-x C-e’.

     (set 'flores '(rosa violeta margarita botóndeoro))

La lista ‘(rosa violeta margarita botóndeoro)’ aparecerá en el área
echo.  Esto es _devuelto_ por la función ‘set’.  Como efecto secundario,
el símbolo ‘flores’ está ligado a la lista; es decir, el símbolo
‘flores’, puede ser visto como una variable, que entrega la lista como
su valor.  (Este proceso, ilustra un efecto lateral al intérprete Lisp:
asignando el valor, que puede ser el efecto primario en el que los
humanos estamos interesados.  Esto se debe a que cada función Lisp debe
devolver un valor si no se obtiene un error, pero solo tendrá un efecto
secundario si está diseñado para tener uno.)

   Después de evaluar la expresión ‘set’, se puede evaluar el símbolo
‘flores’ y devolverá el valor asignado.  Aquí está el símbolo.  Coloca
el cursor al final de este y presiona ‘C-x C-e’.

     flores

Cuando se evalúa ‘flores’, la lista ‘(rosa violeta margarita
botóndeoro)’ aparece en el área echo.

   Por cierto, si se evalúa ‘'flores’, la variable con una comilla en
frente, lo que verá en el área echo es el símbolo en sí mismo: ‘flores’.
Aquí está el símbolo citado, para que pueda probar esto:

     'flores

   Nótese también, que cuando se usa ‘set’, se necesitan citar ambos
argumentos de ‘set’, a menos que los quiera evaluar.  Puesto que
nosotros no queremos evaluar, ni la variable ‘flores’, ni la lista
‘(rosa violeta margarita botóndeoro)’, ambos se citan.  (Cuando se usa
‘set’ sin citar su primer argumento, el primer argumento se evalúa antes
de realizar cualquier otra cosa.  Si hizo esto y ‘flores’ no tenía ya un
valor, se tendría un mensaje de error con el ‘Valor de símbolo como
variable vacío’; por otro lado, si ‘flores’ regreso un valor después de
ser evaluado, ‘set’ intentaría establecer el valor que fue devuelto.
Hay situaciones donde esto el justo lo que la función a de hacer, pero
tales situaciones son poco frecuentes.)


File: emacs-lisp-intro-es.info,  Node: Usando setq,  Next: Contando,  Prev: Usando set,  Up: set y setq

1.9.2 Usando ‘setq’
-------------------

Como una cuestión práctica, casi siempre se cita el primer argumento de
‘set’.  La combinación de ‘set’ y un primer argumento citado es tan
común que tiene nombre propio: la forma especial ‘setq’.  Esta forma
especial es igual a ‘set’ excepto que el primer argumento se cita
automáticamente, por lo que no necesita escribir la marca de cita.
También, como una conveniencia añadida, ‘setq’ permite asignar varias
variables diferentes a diferentes valores, todo en una expresión.

   Para establecer el valor de la variable ‘carnívoros’ a la lista
‘'(leon tigre leopardo)’ usando ‘setq’, se utiliza la siguiente
expresión:

     (setq carnivoros '(leon tigre leopardo))

Esto es exactamente lo mismo que usar ‘set’ excepto que el primer
argumento se cita automáticamente por ‘setq’.  (La ‘q’ en ‘setq’
significa ‘quote’.)

   Con ‘set’, la expresión que se vería es:

     (set 'carnivoros '(leon tigre leopardo))

   Además, ‘setq’ se puede utilizar para asignar diferentes valores a
diferentes variables.  El primer argumento se une a al valor del segundo
argumento, el tercer argumento se une a al valor del cuarto argumento, y
así sucesivamente.  Por ejemplo, se podría usar lo siguiente para
asignar una lista de árboles al símbolo ‘arboles’ y una lista de
herbívoros al símbolo ‘herbivoros’:

     (setq arboles '(pino abeto roble arce)
           herbivoros '(gacela antilope cebra))

(La expresión podría también haber estado en una sola línea, pero podría
no caber en una página; y a los humanos les resulta más fácil leer
listas con un formato agradable.)

   Aunque he estado usando el término 'asignar', hay otra forma de
pensar respecto a el funcionamiento de ‘set’ y ‘setq’; y consiste en
decir que ‘set’ y ‘setq’ crean un símbolo que _apunta_ a la lista.  Esta
ultima forma de pensar es muy común y en los capítulos siguientes
deberiamos encontrar al menos un símbolo con un 'puntero' como parte de
su nombre.  El nombre es elegido porque el símbolo tiene un valor,
específicamente una lista, unida a el; o, expresado de otra manera, el
símbolo se ajusta para "apuntar" a la lista.


File: emacs-lisp-intro-es.info,  Node: Contando,  Prev: Usando setq,  Up: set y setq

1.9.3 Contando
--------------

He aquí un ejemplo que muestra cómo usar ‘setq’ en un contador.  Se
podría usar esto para contar cuantas veces una parte de un programa se
repite.  En primer lugar asigna una variable a cero; a continuación suma
uno al número cada vez que el programa se repita.  Para ello, se
necesita una variable que sirve como un contador, y dos expresiones: una
expresión ‘setq’ inicial que asigna la variable contador a cero; y una
segunda expresión ‘setq’ que incrementa el contador cada vez se evalua.

     (setq contador 0)                ; Llamemos a esto el inicializador.

     (setq contador (+ contador 1))   ; Este es el incremento.

     contador                         ; Esste es el contador.

(El texto que sigue al ‘;’ son los comentarios.  Ver *Note Cambiar una
definición de función: Cambiar un defun.)

   Si evalúas la primera de estas expresiones, el inicializador, ‘(setq
contador 0)’, y luego evalúas la tercera expresión, ‘contador’, el
número ‘0’ aparecerá en el área echo.  Si a continuación se evalúa la
segunda expresión, el incremento, ‘(setq contador (+ contador 1))’, el
contador tendrá el valor 1.  Así que si evalúas de nuevo ‘contador’, el
número ‘1’ aparecerá en el área echo.  Cada vez que se evalúa la segunda
expresión, el valor del contador será incrementado.

   Al evalúar el incremento, ‘(setq contador (+ contador 1))’, el
intérprete Lisp primero evalúa la lista interna; esta es la adición.
Con el fin de evaluar esta lista, se debe evaluar la variable ‘contador’
y el número ‘1’.  Cuando evalúa la variable ‘contador’, se recibe su
valor actual.  Se pasa este valor y el número ‘1’ a ‘+’ que los añade.
La suma es devuelta como el valor de la list interior y pasa a ‘setq’
que asigna la variable ‘contador’ a este nuevo valor.  Por lo tanto, el
valor de la variable ‘contador’, cambia.


File: emacs-lisp-intro-es.info,  Node: Resumen,  Next: Ejercicios de mensajes de error,  Prev: set y setq,  Up: Procesamiento de listas

1.10 Resumen
============

Aprender Lisp es como subir una colina en la que la primera parte es la
más empinada.  Ahora has subido la parte más difícil; lo que queda se
vuelve más fácil a medida que avanzas hacia adelante.

   En resumen,

   • Los programas Lisp se componen de expresiones, que son listas o
     átomos individuales.

   • La listas se componen de cero o más átomos o listas internas,
     separadas por espacios en blanco y rodeadas por paréntesis.  Una
     lista puede estar vacía.

   • Los átomos son símbolos multi-carácter, como ‘forward-paragraph’,
     símbolos de un solo caracterer como ‘+’, cadenas de caracteres
     entre comillas dobles, o números.

   • Un número se evalúa a sí mismo.

   • Una cadena entre comillas dobles también se evalúa a sí mismo.

   • Cuando se evalúa un símbolo a sí mismo, su valor se devuelve.

   • Cuando se evalúa una lista, el intérprete Lisp mira el primer
     símbolo en la lista y luego la definición de función asociada a
     este símbolo.  A continuación, las instrucciones en la definición
     de función se llevan a cabo.

   • Una marca de cita, ' , le indica al intérprete Lisp que devuelva la
     siguiente expresión como esta escrita, y no la evalúa como lo haria
     si la cita no estuviera alli.

   • Los argumentos son la información que se pasa a una función.  Los
     argumentos a una función son computados evaluando el resto de los
     elementos de la lista de la que la función es el primer elemento.

   • Una función siempre devuelve un valor cuando se evalúa (a menos que
     obtenga un error); además, también se puede llevar a cabo algun
     tipo de acción llamado "efecto secundario".  En muchos casos, el
     propósito principal de una función es crear un efecto secundario.


File: emacs-lisp-intro-es.info,  Node: Ejercicios de mensajes de error,  Prev: Resumen,  Up: Procesamiento de listas

1.11 Ejercicios
===============

Unos ejercicios sencillos:

   • Generar un mensaje de error evaluando un símbolo apropiado que no
     está entre paréntesis.

   • Generar un mensaje de error evaluando un símbolo apropiado que está
     entre paréntesis.

   • Crear un contador que se incrementa en dos en lugar de uno.

   • Escribe una expresión que imprima un mensaje en el área eco cuando
     es evaluada.


File: emacs-lisp-intro-es.info,  Node: Practicando evaluación,  Next: Escribiendo funciones,  Prev: Procesamiento de listas,  Up: Top

2 Practicando evaluación
************************

Antes de aprender como escribir una definición de función en Emacs Lisp,
es útil gastar un poco de tiempo evaluando varias expresiones que ya han
sido escritas.  Estas expresiones serán listas con funciones como su
primer (y con frecuencia único) elemento.  Dado que algunas de las
funciones asociadas con búffers son a la vez simples e interesantes,
vamos a iniciar con estas.  En esta sección, vamos a evaluar algunas de
este tipo.  En otra sección, estudiaremos el código de varias otras
funciones relacionadas con búffers, para ver la forma cómo fueron
escritas.

* Menu:

* Cómo evaluar::           Escribiendo comandos de edición o con
                               ‘C-x C-e’.
* Nombres de búffer::      Buffers y ficheros son diferentes.
* Obteniendo búffers::     Obteniendo un buffer por sí
                               mismo, no solamente su nombre.
* Cambiando búffers::      Cómo cambiar a otro buffer.
* Tamaño de búffer y localizaciones::  Dónde el punto está
                                             localizado y el tamaño del
                                             buffer.
* Ejercicio de evaluación::  Ejercicio de evaluación


File: emacs-lisp-intro-es.info,  Node: Cómo evaluar,  Next: Nombres de búffer,  Up: Practicando evaluación

Cómo evaluar
============

Siempre que proporciona un comando de edición a Emacs Lisp, como el
comando para mover el cursor o para desplazarse por la pantalla, se está
evaluando una expresión, de la cual el primer elemento es una función.
Así es cómo funciona Emacs.

   Al presionar las teclas, se causa que el intérprete Lisp evalúe una
expresión que devuelve resultados.  Incluso escribir texto plano implica
evalúar una función Emacs Lisp, en este caso, se utiliza
‘self-insert-command’, que simplemente inserta el caracter escrito.  Las
funciones que se evalúan presionando atajos de teclado se llaman
funciones “interactive”, o “comandos”; como crear una función
interactive será ilustrado en el capítulo sobre cómo escribir
definiciones de funciones.  Ver *note Creando una Función Interactive:
Interactive.

   Además de presionar comandos de teclado, hemos visto una segunda
manera de evaluar una expresión: colocar el cursor después de una lista
y presionar ‘C-x C-e’.  Esto es lo que se hará en el resto de esta
sección.  Hay otras maneras de evaluar una expresión; que serán
descritas cuando llegemos a ellas.

   Ademas de utilizarse para practicar la evaluación, las funciones
mostradas en las siguientes secciones son importantes por derecho
propio.  Un estudio de estas funciones deja claro la distinción entre
búffers y ficheros, cómo cambiar a un búffer, y como determinar una
ubicación dentro de ella.


File: emacs-lisp-intro-es.info,  Node: Nombres de búffer,  Next: Obteniendo búffers,  Prev: Cómo evaluar,  Up: Practicando evaluación

2.1 Nombres de búffer
=====================

Las dos funciones, ‘buffer-name’ y ‘buffer-file-name’, muestran la
diferencia entre un fichero y un búffer.  Cuando se evalúa la siguiente
expresión, ‘(buffer-name)’, el nombre del buffer aparece en el area eco.
Al evaluar ‘(buffer-file-name)’, el nombre del fichero al que se
relaciona el búffer aparece en el área echo.  Normalmente, el nombre
devuelto por ‘(buffer-name)’ es el mismo que el nombre del fichero al
que hace referencia, y el nombre devuelto por ‘(buffer-file-name)’ es la
ruta completa del fichero.

   Un fichero y un búffer son dos entidades diferentes.  Un fichero es
información grabada de manera permanente en el ordenador (a menos que se
borre).  Un búffer, por otro lado, es información dentro de Emacs que
desaparecerá al final de la sesión de edición (o cuando se mate el
búffer).  Normalmente, un búffer contiene información que se ha copiado
desde un fichero; decimos que el búffer está “visitando” este fichero.
Esta copia es la que se trabaja y modifica.  Los cambios al búffer no
cambian el fichero, hasta ser guardados.  Al guardar el búffer, el
búffer se copia en el fichero y por lo tanto se guarda de forma
permanente.

   Si está leyendo esto en Info dentro de GNU Emacs, puede evaluar cada
una de las siguientes expresiones colocando el cursor después de estas y
pulsando ‘C-x C-e’.

     (buffer-name)

     (buffer-file-name)

Cuando hago esto en Info, el valor devuelto para la evaluación de
‘(buffer-name)’ es ‘"*info*"’, y el valor devuelto por evaluar
‘(buffer-file-name)’ es ‘nil’.

   Por otro lado, mientras escribo este documento, el valor devuelto por
la evaluación de ‘(buffer-name)’ es ‘"introduction.texinfo"’, y el valor
devuelto por la evaluación de ‘(buffer-file-name)’ es
‘"/gnu/work/intro/introduction.texinfo"’.

   El primero es el nombre del búffer y el segundo es el nombre del
fichero.  En Info, el nombre del búffer es ‘"*info*"’.  Info no apunta a
ningún fichero, por lo que el resultado de evaluar ‘(buffer-file-name)’]
es ‘nil’.  El símbolo ‘nil’ proviene del Latin, significa 'nada'; en
este caso, significa que el búffer no está asociado con ningun fichero.
(En Lisp, ‘nil’ también se usa con el significado de 'falso' y es
sinómino para lista vacía, ‘()’.)

   Cuando estoy escribiendo, el nombre de mi búffer es
‘"introduction.texinfo"’.  El nombre del fichero al que se apunta es
‘"/gnu/work/intro/introduction.texinfo"’.

   (En las expresiones, los paréntesis hacen que el intérprete Lisp
trate a ‘buffer-name’ y ‘buffer-file-name’ como funciones; sin los
paréntesis, el intérprete intentaría evaluar los símbolos como
variables.  Ver *note Variables::.)

   A pesar de la distinción entre ficheros y búffers, con frecuencia
encontrara que hay personas que se refieren a un fichero cuando quieren
un búffer y vice-versa.  En realidad, la mayoría de la gente dice,
"Estoy editando un fichero," en lugar de decir, "Estoy editando un
búffer que pronto voy a guardar en un fichero."  Esto casi siempre queda
claro a partir del contexto de lo que las personas quieren decir.  No
obstante, al tratar con programas de ordenador, es importante tener la
distinción en mente, ya que el ordenador no es tan inteligente como una
persona.

   Por cierto, la palabra 'búffer', viene del significado de la palabra
como un cojín que amortigua la fuerza de una colisión.  En los primeros
ordenadores, un búffer amortiguaba la interacción entre los ficheros y
la unidad central de procesamiento de la cumputadora.  Los tambores o
cintas que contenian un fichero y la unidad de procesamiento eran piezas
de equipamiento muy diferentes entre si, trabajando a sus propias
velocidades, por rachas.  El búffer hizo posible que ambos trabajaran
juntos de manera efectiva.  Con el tiempo, el búffer pasó de ser un
intermediario, a un lugar de almacenamiento temporal, donde se realiza
el trabajo.  Esta transformación se parace bastante a la de un pequeño
puerto que se convierte en una gran ciudad: una vez fué el lugar donde
la carga era depositada temporalmente antes de ser cargada en los
barcos; despues se convirtio en un centro comercial y cultural por
derecho propio.

   No todos los búffers están asociados con ficheros.  Por ejemplo, el
búffer ‘*scratch*’ no visita ningun fichero.  Del mismo modo, un búffer
‘*Help*’ no está asociado a ningun fichero.

   Antaño, cuando se carecia de un fichero ‘~/.emacs’ y se iniciava una
sesión Emacs escribiendo unicamente el comando ‘emacs’, sin nombrar
ningun fichero, Emacs iniciaba con el búffer ‘*scratch*’ visible.  Hoy
en día, vera una pantalla de vienvenida.  Se puede seguir uno de los
comandos sugeridos en dicha pantalla, visitar un fichero, o presionar la
barra espaciadora para llegar al búffer ‘*scratch*’.

   Si cambia al búffer ‘*scratch*’, escriba ‘(buffer-name)’, coloque el
cursor al final de la expresión, y presione ‘C-x C-e’ para evaluar la
expresión.  El nombre ‘*scratch*’ será devuelto y aparecerá en el área
echo.  ‘*scratch*’ es el nombre del búffer.  Al escribir y evalúar
‘(buffer-file-name)’ en el búffer ‘*scratch*’, ‘nil’ aparecerá en el
área echo, igual que cuando evalúa ‘(buffer-file-name)’ en Info.

   Por cierto, si se encuentra en el búffer ‘*scratch*’ y quiere que el
valor devuelto por una expresión aparesca en el búffer en sí y no en el
área echo, presione ‘C-u C-x C-e’ en lugar de ‘C-x C-e’.  Esto causa que
el valor devuelto aparezca después de la expresión.  El búffer se verá
así:

     (buffer-name)"*scratch*"

No se puede hacer esto en Info ya que Info es de solo lectura y no se
permitirá cambiar el contenido del búffer.  Pero puedes hacer esto en
cualquier búffer que se puede editar; y cuando se escribe código o
documentación (como este libro), esta funcionalidad es muy útil.


File: emacs-lisp-intro-es.info,  Node: Obteniendo búffers,  Next: Cambiando búffers,  Prev: Nombres de búffer,  Up: Practicando evaluación

2.2 Obteniendo búffers
======================

La función ‘buffer-name’ devuelve el _nombre_ del búffer; para obtener
el búffer _en sí_, una función diferente es necesaria: la función
‘current-buffer’.  Si usa esta función en el código, lo que se obtiene
es el búffer en sí.

   Un nombre y el objeto o entidad a la que se refiere el nombre son
cosas diferentes entre si.  Tu no eres tu nombre, eres una persona a la
que se refieren los demas por tu nombre.  Si pides hablar con Jorge y
alguien te entrega una tarjeta con las letras ‘J’, ‘o’, ‘r’, ‘g’, y ‘e’
escritas, podrías divertirte, pero no estarías satisfecho.  No quieres
hablar con el nombre, sino con la persona a la que el nombre se refiere.
Un búffer es similar: el nombre del búffer scratch es ‘*scratch*’, pero
el nombre no es el búffer.  Para obtener un búffer en sí, se necesita
usar una función como ‘current-buffer’.

   Sin embargo, hay una ligera complicación: si evalúas ‘current-buffer’
en una expresión por sí sola, como haremos aquí, lo que ves es una
representación impresa del nombre del búffer sin los contenidos del
búffer.  Emacs funciona de esta forma por dos razones: el búffer puede
contener miles de líneas--demasiado largo para ser mostrado
convenientemente; y, otro búffer puede tener los mismos contenidos pero
un nombre diferente, y es importante distinguir entre ellos.

   Aquí hay una expresión conteniendo la función:

     (current-buffer)

Si evalúa esta expresión en Info de la manera habitual, ‘#<buffer
*info*>’ aparecerá en el área echo.  El formato especial indica que el
búffer en sí está siendo devuelto, en lugar de solo su nombre.

   Por cierto, si bien puedes escribir un número o símbolo en un
programa, no se puede hacer esto con la representación impresa del
búffer: la única manera de obtener un búffer en sí mismo es con una
función tal como ‘current-buffer’.

   Un función relacionada es ‘other-buffer’.  Esta devuelve el último
buffer seleccionado distino al que te encuentras actualmente, no una
representación impresa de su nombre.  Si recientemente has ido y vuelto
del búffer ‘*scratch*’, ‘other-buffer’ devolverá este búffer.

   Se puede ver esto evaluando la expresión:

     (other-buffer)

Verás que ‘#<buffer *scratch*>’ aparece en el área echo, o el nombre de
cualquier otro búffer cambiado anteriormente a partir del más
reciente(1)

   ---------- Footnotes ----------

   (1) En realidad, por defecto, si el búffer desde el que has cambiado
es visible por tí en otra ventana, ‘other-buffer’ elegirá el búffer más
reciente que no puedes ver; esto es una sutileza que a menudo olvido.


File: emacs-lisp-intro-es.info,  Node: Cambiando búffers,  Next: Tamaño de búffer y localizaciones,  Prev: Obteniendo búffers,  Up: Practicando evaluación

2.3 Cambiando búffers
=====================

La función ‘other-buffer’ realmente proporciona un búffer cuando se
utiliza como argumento de una función que requiera uno.  Podemos ver
esto usando ‘other-buffer’ y ‘switch-to-buffer’ para cambiar a un búffer
diferente.

   Pero primero, una breve introducción a la función ‘switch-to-buffer’.
Cuando cambia de ida y vuelta de Info al búffer ‘*scratch*’ para evaluar
‘(buffer-name)’, normalmente se presiona ‘C-x b’ y se pasa
‘*scratch*’(1) en el minibuffer cuando se le solicita el nombre del
búffer al que se quiere cambiar.  El atajo, ‘C-x b’, hace que el
intérprete Lisp evalúe la función interactiva ‘switch-to-buffer’.  Como
hemos dicho anteriormente, así es como funciona Emacs: diferentes atajos
de teclado llaman o ejecutan diferentes funciones.  Por ejemplo, ‘C-f’
llama a ‘forward-char’, ‘M-e’ llama a ‘forward-sentence’, etc'etera.

   Escribiendo ‘switch-to-buffer’ en una expresión, y dándole un búffer
para cambiar, se puede cambiar de búffers tal y como hace ‘C-x b’.

     (switch-to-buffer (other-buffer))

El símbolo ‘switch-to-buffer’ es el primer elemento de la lista, por lo
que el intérprete Lisp lo tratará como una función y llevara a cavo las
instrucciones adjuntas al mismo.  Pero antes de hacer esto, el
intérprete observara que ‘other-buffer’ está dentro de paréntesis y
trabaja en este símbolo primero.  ‘other-buffer’ es el primer (y en este
caso, el único) elemento de esta lista, por lo que el intérprete Lisp
llama o ejecuta la función.  Esto devuelve un buffer distinto al actual.
A continuación, el intérprete ejecuta ‘switch-to-buffer’, pasando, como
argumento, el búffer devuelto, que es al que Emacs cambia.  Si estás
leyendo esto en Info, prueba esto ahora.  Evalúa la expresión.  (Para
volver, presiona ‘C-x b <RET>’.)(2).

   En los ejemplos de las secciones siguentes, veras con más frecuencia
la función ‘set-buffer’ que ‘switch-to-buffer’.  Esto es porque a
diferencia de los programas de ordenador: los humanos tienen ojos y
esperan ver el búffer en el que están trabajando en la terminal de su
ordenador.  Esto es tan obvio, que casi no hace falta decirlo.  Sin
embargo, los programas no tienen ojos.  Cuando un programa de ordenador
trabaja en un búffer, el búffer no necesita ser visible en la pantalla.

   ‘switch-to-buffer’ está diseñado para los seres humanos y hace dos
cosas diferentes: cambia el búffer a el que Emacs dirige la atención; y
cambia el búffer mostrada en la ventana al nuevo búffer.  ‘set-buffer’,
por otro lado, solo hace una cosa: cambia la atención del programa del
ordenador a un búffer diferente.  El búffer en la pantalla permanece sin
cambios (por supuesto, normalmente no ocurre nada hasta que el comando
termina de ejecutarse).

   También, acabamos introduciendo otro término tecnico, la palabra
“llamada”.  Cuando evalúas una lista en la que el primer símbolo es una
función, estás llamando a esta función.  El uso del término viene de la
noción de la función como una entidad que puede hacer algo por ti cuando
la 'llamas' -- al igual que un fontanero es una entidad que puede
arreglar una fuga si le llamas.

   ---------- Footnotes ----------

   (1) O mejor, para evitar escribir, probablemente solo necesite pulsar
‘RET’ si ‘*scratch*’ es el buffer por defecto, de ser diferente, solo
escriba parte del nombre, por ejemplo ‘*sc’, luego presione la tecla
‘TAB’ para hacer que se expanda el nombre completo, y finalmente pulsa
‘RET’

   (2) Recuerda, esta expresión te desplaza al búffer más reciente que
no puedas ver.  Si realmente quieres ir al ultimo búffers seleccionado,
incluso si es visible, es necesario evaluar la siguiente expresión más
compleja:
     (switch-to-buffer (other-buffer (current-buffer) t))
   En este caso, el primer argumento de ‘other-buffer’ le dice a que
búffer saltar --el actual-- y el segundo argumento le indica a
‘other-buffer’ que esta BIEN cambiar a un búffer visible.  La utilidad
de ‘switch-to-buffer’ es llevarte a una ventana invisible ya que
probablemente usarías ‘C-x o’ (‘other-window’) para ir a otro búffer
visible


File: emacs-lisp-intro-es.info,  Node: Tamaño de búffer y localizaciones,  Next: Ejercicio de evaluación,  Prev: Cambiando búffers,  Up: Practicando evaluación

2.4 Tamaño de búffer y la ubicación del punto
=============================================

Por último, vamos a ver varias funciones bastante simples,
‘buffer-size’, ‘point’, ‘point-min’, y ‘point-max’.  Estas entregan
información sobre el tamaño de un búffer y la ubicación del punto dentro
de este.

   La función ‘buffer-size’ te dice el tamaño del búffer actual; es
decir, la función devuelve un conteo del número de caracteres en el
buffer.

     (buffer-size)

Puedes evaluar esto de la forma habitual, coloca el cursor después de la
expresión y presiona ‘C-x C-e’.

   En Emacs, la posición actual del cursor es llamada “punto”.  La
expresión ‘(point)’ devuelve un número que informa donde está situado el
cursor como un conteo del número de caracteres desde el principio del
búffer hasta el punto.

   Puedes ver el conteo de caracteres del punto para este búffer
evaluando la siguiente expresión de la forma habitual:

     (point)

Mientras escribo esto, el valor de ‘point’ es 65724.  La función ‘point’
se utiliza con frecuencia en algunos de los ejemplos mas adelante en
este libro.

   El valor del punto depende, por supuesto, de su posición dentro del
búffer.  Si se evalúa el punto en este lugar, el número será mayor:

     (point)

Para mí, el valor del punto en esta posición es 66043, lo que significa
que hay 319 caracteres (incluyendo espacios) entre las dos expresiones.
(Sin duda, se verán diferentes números, puesto que se ha editado esto
desde que se evaluó (point).)

   La función ‘point-min’ es similar a ‘point’, pero devuelve el valor
mínimo permisible del punto en el búffer actual.  Este es el número 1 a
menos que “narrowing” esté en efecto.  (Narrowing, _Encogiendo_ es un
mecanismo mediante el cual puedes restringirte a ti mismo, o un
programa, a operar solo en un parte de un búffer.  *note Encogiendo y
extendiendo::.)  Del mismo modo, la función ‘point-max’ devuelve el
valor del valor máximo permisible del punto en el búffer actual.


File: emacs-lisp-intro-es.info,  Node: Ejercicio de evaluación,  Prev: Tamaño de búffer y localizaciones,  Up: Practicando evaluación

2.5 Ejercicio
=============

Busca un fichero en el que trabajar y avanza hasta la mitad.  Encuentra
el nombre de búffer, el nombre del fichero, su tamaño, y la posición en
el fichero.


File: emacs-lisp-intro-es.info,  Node: Escribiendo funciones,  Next: Un paseo a través de los búffers,  Prev: Practicando evaluación,  Up: Top

3 Cómo escribir definiciones de funciones
*****************************************

Cuando el intérprete evalúa una lista, mira si el primer símbolo en la
lista tiene una definición adjunta; o, dicho de otro modo, si el símbolo
apunta a una definición de función.  Si lo hace, el ordenador lleva a
cabo las instrucciones que aparecen en la definición.  Un símbolo que
tiene una definición de función se llamada, simplemente, una función
(aunque hablando con propiedad, la definición es la función y el símbolo
se refiere a ella.)

* Menu:

* Funciones primitivas::     Funciones primitivas
* defun::                    La forma especial ‘defun’.
* Instalar::                 Instalar una definición de función.
* Interactive::              Creando una función interactive.
* Opciones de interactive.::  Diferentes opciones para ‘interactive’.
* Instalación Permanente::  Instalando código permanentemente.
* let::                      Creando e inicializando variables locales.
* if::                       ¿Y qué si?
* else::                     Expresiones If-then-else.
* Verdad y falsedad::        Que considera Lisp falso y cierto.
* save-excursion::           Guardando la traza del punto, la marca, y el
                               buffer.
* Revisar::                  Revisar
* Ejercicios defun::         Ejercicios defun


File: emacs-lisp-intro-es.info,  Node: Funciones primitivas,  Next: defun,  Up: Escribiendo funciones

Una vía acerca de funciones primitivas
======================================

Todas las funciones se definen en términos de otras funciones, a
excepcion de algunas “primitivas” que estan escritas en el lenguaje de
programación C. Cuando escribas definiciones de funciones, deben
escribirse en Emacs Lisp y utilizar otras funciones como bloques de
construcción.  Algunas de las funciones a utilizar estaran a su vez
escritas en Emacs Lisp (quizás por tí) y algunas serán primitivas
escritas en C. Las funciones primitivas se usan exactamente igual que
las escritas en Emacs Lisp y se comportan de igual forma.  Están
escritas en C para que podamos ejecutar fácilmente GNU Emacs en
cualquier ordenador que tenga la potencia suficiente y pueda ejecutar C.

   Permíteme volver a enfatizar esto: cuando se escribe código en Emacs
Lisp, no se distinge entre el uso de funciones escritas en C y el uso de
funciones escritas en Emacs Lisp.  La diferencia es irrevelante.
Menciononé la distinción solo porque es interesante conocerla.  De
hecho, a menos de que investigues, no sabras si una función previamente
escrita esta en Emacs Lisp o en C.


File: emacs-lisp-intro-es.info,  Node: defun,  Next: Instalar,  Prev: Funciones primitivas,  Up: Escribiendo funciones

3.1 La forma especial ‘defun’
=============================

En Lisp, un símbolo como ‘mark-whole-buffer’ tiene código unido a el que
le dice al ordenador que hacer cuando se invoca la función.  Este código
se denomina la “definición de función” y se crea mediante la evaluación
de una expresión Lisp que comienza con el símbolo ‘defun’ (que es una
abreviatura para _define function_ (definir función)).  Porque ‘defun’
no evalúa sus argumentos en la forma habitual, eso se llama “forma
especial”.

   En las siguientes secciones, miraremos en definiciones de función
partiendo del código fuente de Emacs, por ejemplo ‘mark-whole-buffer’.
En esta sección, describiremos una definición de función sencilla, para
que puedas ver su aspecto.  Esta definición de función usa aritmética
porque es un ejemplo simple.  A algunas personas les disgutan los
ejemplos usando aritmética; sin embargo, si usted es tal persona, no se
desespere.  Casi ningun código a estudiar en el resto de esta
introducción implica aritmética o matemáticas.  Los ejemplos de manera
mayoritaria involucran texto en una forma u otra.

   Una definición de función tiene un máximo de cinco partes despues de
la palabra ‘defun’:

  1. El nombre del símbolo al que la definición de función debe
     vincularse.

  2. Una lista de los argumentos que serán pasados a la función.  Si no
     hay argumentos que pasar, tendremos una lista vacía, ‘()’.

  3. Documentación describiendo la función.  (Técnicamente opcional,
     pero fuertemente recomendada.)

  4. Opcionalmente, una expresión para hacer que la función interactive
     pueda usarse presionando ‘M-x’ seguido del nombre de la función; o
     pulsando una tecla o atajo de teclado.

  5. El código que indica a el ordenador qué hacer: el “cuerpo” de la
     definición de función.

   Es útil pensar en las cinco partes de una definición de función
siendo organizadas como una plantilla, con slots para cada parte:

     (defun NOMBRE-DE-FUNCIÓN (ARGUMENTOS...)
       "DOCUMENTACION-OPCIONAL..."
       (interactive ARGUMENT-PASSING-INFO)     ; opcional
       CUERPO...)

   A modo de ejemplo, aquí está el código de una función que multiplica
su argumento por 7.  (Este ejemplo no es interactivo.  Ver *note Creando
una Función Interactive: Interactive, para esta información.)

     (defun multiplicar-por-siete (numero)
       "Multiplica NUMERO por siete."
       (* 7 numero))

   Esta definición comienza con un paréntesis y el símbolo ‘defun’
seguido por el nombre de la función.

   El nombre de la función es seguido por una lista que contiene los
argumentos que serán pasados a la función.  Esta lista se llama “lista
de argumentos”.  En este ejemplo, la lista solo tiene un elemento, el
símbolo ‘numero’.  Cuando se utiliza la función, el símbolo será
asociado al valor que se utiliza como argumento de la función

   En lugar de elegir la palabra ‘numero’ para el nombre del argumento,
podría haber escogido cualquier otro nombre.  Por ejemplo, la palabra
‘multiplicando’.  Escogi la palabra 'numero' porque indica qué tipo de
valor se pretende para este espacio; pero podría haber elegido
'multiplicando' para indicar el rol que jugara el valor en el
funcionamiento de la función.  Podría haberlo llamado ‘foogle’, pero
habría sido una mala elección porque no comunicaria qué significa.  La
elección del nombre es responsabilidad del programador y debe elegirse
para hacer que el significado de la función sea claro.

   De hecho, se puede elegir cualquier nombre que se desee para un
símbolo en una lista de argumentos, incluso el nombre del símbolo usado
en alguna otra función: el nombre a usar en una lista de argumentos es
privado para esta definición particular.  En esta definición, el nombre
hace referencia a una entidad diferente a cualquiera que utilice el
mismo nombre fuera de la definición de función.  Supón que tu familia te
apoda 'Enano'; cuando tus familiares digan 'Enano', queren hacer
referencia a ti.  Pero fuera de tu familia, en una película, por
ejemplo, el nombre 'Enano' se refiere a alguien más.  Debido a que el
nombre en una lista de argumentos es privado para la definición de la
función, se puede cambiar el valor de un símbolo dentro del cuerpo de
una función sin cambiar su valor fuera de la función.  El efecto es
similar al producido por la expresión ‘let’.  (Ver sección *note ‘let’:
let.)

   La lista de argumentos es seguida por la cadena de documentación que
describe la función.  Esto es lo que ves cuando presionas ‘C-h f’ y
escribes el nombre de una función.  Por cierto, cuando escribas una
cadena de documentación como esta, debes confeccionar la primer línea
como una sentencia completa ya que algunos comandos, como ‘apropos’,
imprimen solo la primer línea de una cadena de documentación de varias
líneas.  Ademas, no debes indentar la segunda línea de la cadena de
documentación, si tienes una, porque se ve extraño al utilizar ‘C-h f’
(‘describe-function’).  La cadena de documentación es opcional, pero es
tan útil, que deberías incluirla en casi cualquier función que escribas.

   La tercera línea del ejemplo consiste en el cuerpo de la definición
de función.  (La mayoría de las definiciones de función, claro esta, son
más extensas que esta.)  En esta función, el cuerpo es la lista, ‘(* 7
numero)’, que indica multiplicar el valor de NUMERO por 7.  (En Emacs
Lisp, ‘*’ es la función para la multiplicación, al igual que ‘+’ es la
función de la adición.

   Cuando se utiliza la función ‘multiplicar-por-siente’, el argumento
‘numero’ se evalúa al numero que desees usar.  He aquí un ejemplo que
muestra como utilizar ‘multiplicar-por-siente’; pero ¡no intentes
evaluar esto primero!.

     (multiplicar-por-siente 3)

El símbolo ‘numero’, especificado en la definición de función en la
siguiente sección, se da o "une a" el valor 3 en el actual uso de la
función.  Note que aunque ‘numero’ estaba dentro de paréntesis en la
definición de función, el argumento pasado a la función
‘multiplicar-por-siente’ no está entre paréntesis.  Los paréntesis se
escriben en la definición de función para que el ordenador pueda
averiguar donde termina la lista de argumentos e inicia el resto de la
definición de función.

   Si evalúas este ejemplo, es probable que obtengas un mensaje de
error.  (¡adelante, intentalo!)  Esto se debe a que hemos escrito la
definición de función pero aún no se a comunicado al ordenador la
definición -- no hemos instalado (o 'cargado') la definición de función
en Emacs.  Instalar una función es el proceso comunicar al intérprete
Lisp la definición de la función.  La instalación se describe en la
siguiente sección.


File: emacs-lisp-intro-es.info,  Node: Instalar,  Next: Interactive,  Prev: defun,  Up: Escribiendo funciones

3.2 Instalar una definición de función
======================================

Si estás leyendo esto dentro de Info en Emacs, puedes probar la función
‘multiply-by-seven’ evaluando en primer ]ugar la definición de función y
luego evaluar ‘(multiplicar-por-siente 3)’.  Hay una copia de la
definición a continuación.  Coloca el cursor después del último
paréntesis de la definición de función y presiona ‘C-x C-e’.  Al hacer
esto, ‘multiplicar-por-siente’ aparecerá en el área echo.  (Lo que
significa es que cuando una definición de función se evalua, el valor
devuelto es el nombre de la función definida.)  Al mismo tiempo, esta
acción instala la definición de función.

     (defun multiplicar-por-siete (numero)
       "Multiplica NUMERO por siete."
       (* 7 numero))

Al evaluar este ‘defun’, estas instanlado ‘multiply-by-seven’ en Emacs.
La función es ahora solo una parte de Emacs como ‘forward-word’ o
cualquier otra función de edición que utilices.
(‘multiplicar-por-siente’ seguira instalado hasta que salgas de Emacs.
Para volver a cargar el código automáticamente cada vez que Emacs
inicie, ver *note Instalar Código Permanentemente: Instalación
Permanente.)

* Menu:

* Efecto de instalación::  Efecto de instalación
* Cambiar un defun::         Cómo cambiar una definición de función


File: emacs-lisp-intro-es.info,  Node: Efecto de instalación,  Next: Cambiar un defun,  Up: Instalar

El efecto de instalación
------------------------

Puedes ver el efecto de instalar ‘multiplicar-por-siente’ evaluando el
siguiente ejemplo.  Coloca el cursor después de la siguiente expresión y
presiona ‘C-x C-e’.  El número 21 aparacerá en el área echo.

     (multiplicar-por-siente 3)

   Si lo deseas, puedes leer la documentación de la función presiona
‘C-h f’ (‘describe-function’) y luego escribe el nombre de la función,
‘multiplicar-por-siente’.  Al hacer esto, una ventana ‘*Help*’ aparecerá
en tu pantalla diciendo:

     multiplicar-por-siente is a Lisp function.
     (multiplicar-por-siente NUMERO)

     Multiplica NUMERO por siete.

(Para volver a una sola ventana en la pantalla, presiona ‘C-x 1’.)


File: emacs-lisp-intro-es.info,  Node: Cambiar un defun,  Prev: Efecto de instalación,  Up: Instalar

3.2.1 Cambiar una definición de función
---------------------------------------

Si deseas modificar al código de ‘multiplicar-por-siente’, simplemente
reescríbelo.  Para instalar la nueva versión en lugar de la vieja,
evalúa la nueva definición de la función.  Esta, es la forma de
modificar el código en Emacs.  Es muy simple,

   A modo de ejemplo, puedes cambiar la función ‘multiplicar-por-siente’
para sumar el número a sí mismo siete veces en lugar de multiplicar el
número por siete.  Esto produce el mismo resultado, pero por una ruta
diferente.  Al mismo tiempo, añadiremos un comentario al codigo; un
comentario es texto que el intérprete Lisp ignora, pero un lector humano
puede encontrar útil o esclarecedor.  El comentario es que esto es la
"segunda versión".

     (defun multiplicar-por-siente (numero)       ; Segunda versión.
       "Multiplica NUMERO por siete."
       (+ numero numero numero numero numero numero numero))

   El comentario sigue a un punto y coma, ‘;’.  En Lisp culquier cosa en
una línea despues de un punto y coma es un comentario.  El fin de la
línea es el fin del comentario.  Para extender un comentario por dos o
más líneas, inicia cada línea con un punto y coma.

   *Note Empezando un Fichero ‘.emacs’: Beginning a .emacs File, y *note
Comentarios: (elisp)Comments, para más informacion sobre los
comentarios.

   Se puede instalar esta versión de la función ‘multiply-by-seven’
evaluando esta de la misma forma en que se evaluó la primer función:
coloca el cursor después del último paréntesis y presiona ‘C-x C-e’.

   En resumen, esta es la forma en que puedes escribir código en Emacs
Lisp: escribes una función; la instalas; la pruebas; luego haces
correciones y mejoras e instálalas de nuevo.


File: emacs-lisp-intro-es.info,  Node: Interactive,  Next: Opciones de interactive.,  Prev: Instalar,  Up: Escribiendo funciones

3.3 Crear una función interactive
=================================

Haces a una función interactiva colocando una lista que inicia con la
clase especial ‘interactive’ inmediatamente después de la documentación.
Un usuario puede invocar una función interactiva con ‘M-x’ seguido del
nombre de la función; o con un atajo de teclado ligado a esta, por
ejemplo, pulsa ‘C-n’ para ‘next-line’ o ‘C-x h’ para
‘mark-whole-buffer’.

   Curiosamente, cuando se llama a una función interactiva
interactivamente, el valor devuelto no se muestra automáticamente en el
área echo.  Esto se bede a que a menudo se llama a una función
interactiva para sus efectos secundarios, tales como avanzar hacia
adelante por palabra o línea, y no para el valor devuelto.  Si el valor
devuelto fuera mostrado en el área echo cada vez que presionas una
tecla, distraería mucho

* Menu:

* multiply-by-seven interactivo::  Un resumen
* multiply-by-seven en detalle::  La versión interactive.


File: emacs-lisp-intro-es.info,  Node: multiply-by-seven interactivo,  Next: multiply-by-seven en detalle,  Up: Interactive

Un ‘multiply-by-seven’ interactivo, Un resumen
----------------------------------------------

Tanto el uso de la forma especial ‘interactive’ y una forma de mostrar
un valor en el área echo pueden ilustrarse creando una versión
interactiva de ‘multiplicar-por-siente’.

   Aquí está el código:

     (defun multiplicar-por-siente (numero)       ; Versión Interactiva.
       "Multiplica NUMERO por siete."
       (interactive "p")
       (message "El resultado es %d" (* 7 numero)))

Para instalar este código colaca el cursor después del ultimo parentesis
y presiona ‘C-x C-e’.  El nombre de la función aparecerá en el área
echo.  Despues, puedes utilizar este código al presionar ‘C-u’ seguido
de un número, lugo ‘M-x multiplicar-por-siente’ y finalmente <RET>.  La
frase ‘El resultado es ...’ seguida por el producto aparecerá en el área
echo

   Hablando en terminos mas generales, puedes invocar una función como
ésta de dos maneras:

  1. Al escribir un argumento prefijo que contiene el número a pasar, y
     a continuación presionar ‘M-x’ y escribir el nombre de la función,
     como ocurre con ‘C-u 3 M-x forward-sentence’; o,

  2. Al escribir cualquier tecla o atajo de teclado ligado a la funcion
     a tratar, como ocurre con ‘C-u 3 M-e’.

Ambos ejemplos operan de forma identica moviendo el punto hacia
adelantes tres frases.  (Si ‘multiply-by-seven’ no estuviese ligado a
una tecla, no podría ser usado como ejemplo de enlace a tecla.

   (*Note Algunos Atajos de Teclas: Atajos de teclado, para aprender
como vincular un comando a una tecla.)

   Un argumento prefijo se pasa a una función interactiva pulsando la
tecla <META> seguida por un número, por ejemplo, ‘M-3 M-e’, o con ‘C-u’
y luego un número, por ejemplo, ‘C-u 3 M-e’ (si presionas ‘C-u’ sin
ningun número, el valor por defecto es 4).


File: emacs-lisp-intro-es.info,  Node: multiply-by-seven en detalle,  Prev: multiply-by-seven interactivo,  Up: Interactive

3.3.1 ‘multiplicar-por-siente’ interactivo
------------------------------------------

Veamos la clase especial ‘interactive’ y despues la función ‘message’ en
la versión interactiva de ‘multiplicar-por-siente’.  Recordaras que la
definición de función tiene el siguente aspecto:

     (defun multiplicar-por-siente (numero)       ; Versión Interactiva.
       "Multiplica NUMERO por siete."
       (interactive "p")
       (message "El resultado es %d" (* 7 numero)))

   En esta función, la expresión, ‘(interactive "p")’, es una lista de
dos elementos.  La ‘"p"’ le indica a Emacs que debe pasar el argumento
prefijo a la función y utilizar este valor para el argumento de la
función.

   El argumento debe ser un número.  Esto significa que el símbolo
‘numero’ estara asociado a un número en la línea:

     (message "El resultado es %d" (* 7 numero))

Por ejemplo, si tu argumento prefijo es 5, el intérprete Lisp evaluará
la línea como si fuera:

     (message "El resultado es %d" (* 7 5))

(Si estás leyendo esto en GNU Emacs, puedes evaluar esta expresión por
ti mismo.)  Primera, el intérprete evaluará la lista interna, que es ‘(*
7 5)’.  Esto devuelve un valor de 35.  A continuación, se evaluará la
lista externa, pasando los valores del segundo y posteriores elementos
de la lista a la función ‘message’.

   Como hemos visto, ‘message’ es una función Emacs Lisp especialmente
diseñada para enviar un mensaje de una línea al usuario.  (*Note La
función ‘message’: message.) En resumen, la función ‘message’ imprime su
primer argumento en el área echo tal cual, exceptuando las apariciones
de ‘%d’, o ‘%s’ (y varias otras secuencias de control que no hemos
mencionado).  Cuando aparece una secuencia de control, la función
observa al segundo o posteriores argumentos e imprime el valor del
argumento en la ubicación donde se encuentra la secuencia de control.

   En la función interactiva ‘multiplicar-por-siente’, la cadena de
control es ‘%d’, que requiere un número, y el valor devuelto por la
evaluación de ‘(* 7 5)’ es el número 35.  Por consiguiente, el número 35
se imprime en lugar de ‘%d’ y el mensaje es ‘El resultado es 35’.

   (Nótese que cuando llamas a la función ‘multiplicar-por-siente’, el
mensaje se imprime sin comillas, pero cuando llamas a ‘message’, el
texto se impreme entre comillas.  Esto se debe a que el valor devuelto
por ‘message’ aparece en el área echo cuando evalúas una expresión cuyo
primer elemento es ‘message’; pero si se integra en una función,
‘message’ imprime el texto como un efecto secundario sin comillas.)


File: emacs-lisp-intro-es.info,  Node: Opciones de interactive.,  Next: Instalación Permanente,  Prev: Interactive,  Up: Escribiendo funciones

3.4 Diferentes opciones para ‘interactive’
==========================================

En el ejemplo, ‘multiplicar-por-siente’ usa ‘"p"’ como el argumento para
‘interactive’.  Este argumento indica a Emacs que interprete cualquier
cosa que escriba despues de ‘C-u’ o del comando <META> como un número
que sera el argumento a pasar a la función.  Emacs tiene más de veinte
caracteres predefinidos para usar con ‘interactive’.  En casi todos los
casos, una de estas opciones te permitira pasar la información adecuada
interactivamente a una función.  (*Note Carácteres Código para
‘interactive’: (elisp)Interactive Codes.).

   Considera la función ‘zap-to-char’.  Su expresión interactiva es

     (interactive "p\ncZap to char: ")

   La primer parte del argumento de ‘interactive’ es ‘p’, con el que ya
estás familiarizado.  Este argumento le indica a Emacs intepretar un
'prefijo', como un número que se pasa a la función.  Puedes especificar
un prefijo plesionando ‘C-u’ seguido por un número o igualmente con
<META> seguido por un número.  El prefijo es un número de caracteres
especifico.  De este modo, si el prefijo es tres y el caracter
establecido es ‘x’, entonces se borrará todo el texto incluido el tercer
‘x’ siguiente.  Si no se establece un prefijo, entonces borras todo el
texto incluido el cuarto carácter establecido, pero no más.

   La ‘c’ indica a la función el nombre del carácter que va a eliminar.

   Más formalmente, una función con dos o más argumentos puede tener
información que pasa a cada argumento añadiendo partes en la cadena
viene despues de ‘interactive’.  Cuando haces esto, la información se
pasa a cada argumento en el mismo orden que se especifica en la lista
‘interactive’.  En la cadena, cada parte está separada de la siguiente
parte por un ‘\n’, que significa nueva línea.  Por ejemplo, a ‘p’ puede
continuar un ‘\n’ y un ‘cZap to char:’.  Esto hace que Emacs pase el
valor del argumento prefijo (si lo hay) y el carácter.

   En este caso, la definición de función se parace a la siguiente,
donde ‘arg’ y ‘char’ son los símbolos que ‘interactive’ vincula el
argumento prefijo y el caracter especificado:

     (defun NOMBRE-DE-FUNCION (arg char)
       "DOCUMENTACION..."
       (interactive "p\ncZap to char: ")
       CUERPO-DE-FUNCION...)

(El espacio después del punto y coma en pantalla hace que se vea mejor.
*Note La Definición de ‘copy-to-buffer’: copy-to-buffer, para un
ejemplo.)

   Cuando una función no toma argumentos, ‘interactive’ no requiere
ninguno.  Una función asi contiene unicamente la expresión
‘(interactive)’.  La función ‘mark-whole-buffer’ es asi.

   Alternativamente, si los códigos de letras especiales no son
adecuados para tu aplicación, puedes pasar tus propios argumentos a
‘interactive’ como una lista.

   *Note La Definición de ‘append-to-buffer’: append-to-buffer, para un
ejemplo.  *Note Usando ‘interactive’: (elisp)Using Interactive, para una
explicación más completa acerca de esta técnica.


File: emacs-lisp-intro-es.info,  Node: Instalación Permanente,  Next: let,  Prev: Opciones de interactive.,  Up: Escribiendo funciones

3.5 Instalar código permanentemente
===================================

Cuando instalas una definición de función evaluada por ti, permanecera
instalada hasta que salgas de Emacs.  La proxima vez que inicies una
nueva sesión de Emacs, la función no será instalada a menos que evalúes
de nuevo la definición.

   En algún punto, podrias necesitar que el código se instale
automáticamente cada vez que inicies una nueva sesión de Emacs.  Hay
varias formas de hacer esto:

   • Si tienes código solo para tu uso, puedes poner el código de la
     definición de función en el fichero de inicialización ‘.emacs’.
     Cuando se inicia Emacs, el fichero ‘.emacs’ se evalúa automática y
     se instalan todas sus definiciones de función.  *Note Tu Fichero
     ‘.emacs’: Inicialización de Emacs.

   • Como Alternativa, puedes poner las definiciones de función en uno o
     más ficheros y usar la función ‘load’ para hacer que Emacs evalue y
     con ello instale cada una de las funciones en los ficheros.  *Note
     Cargando ficheros: Cargando ficheros.

   • En tercer lugar, si tienes código que todo tu sitio va a utilizar,
     es normal ponerlo en un fichero llamado ‘site-init.el’ que se carga
     cuando se construye Emacs.  Esto hace que el código este disponible
     a cualquiera que use tu máquina.  (Mira el fichero ‘INSTALL’ que
     forma parte de la distribución Emacs.)

   Finalmente, si tienes código que cualquier usuario de Emacs puede
querer, puedes publicarlo en una red de ordenadores o enviar una copia a
la Free Software Foundation.  (Al hacer esto, por favor, licencia el
código y su documentación bajo una licencia que permita a otras personas
ejecutar, copiar, estudiar, modificar, y redistribuir el código y te
proteja de quien tome tu trabajo.)  Si envias una copia de tu código a
la Free Software Foundation, y lo proteges apropiadamente de tí mismo y
otros, puede ser incluido en la siguiente version de Emacs.  En gran
parte, esta es la forma como ha crecido Emacs a través de los años, por
donaciones.


File: emacs-lisp-intro-es.info,  Node: let,  Next: if,  Prev: Instalación Permanente,  Up: Escribiendo funciones

3.6 ‘let’
=========

La expresión ‘let’ es una forma especial en Lisp que tendras que
utilizar en la mayoría de las definiciones de función.

   ‘let’ se utiliza para unir o enlazar un símbolo a un valor de tal
manera que el intérprete no confunda la variable con otra variable del
mismo nombre que no forma parte de la función.

   Para comprender por qué la forma especial ‘let’ es necesaria,
considera la situación donde eres dueño de una casa que generalmente
vinculas con 'la casa', como en la frase, "La casa necesita pintura."
Si visitas a un amigo y tu anfitrión hace referencia a 'la casa', es
probable que se refiera a _su_ casa, no a la tuya, es decir, es una casa
distinta.

   Si tu amigo se refiere a su casa y tu crees que él se está refiriéndo
a tu casa, puedes tener cierta confusión.  Lo mismo podria ocurrir en
Lisp si una variable que se utiliza dentro de una función tiene el mismo
que una variable usada dentro de otra función, y las dos no tienen la
intención de referirse al mismo valor.  La forma especial ‘let’ previene
este tipo de confusión.

* Menu:

* Prevenir confusión::     Prevenir confusión
* Partes de la expresión let::  Partes de la expresión let
* Ejemplo de expresión let::  Ejemplo de expresión let
* Variables let inicializadas::  Variables let inicializadas


File: emacs-lisp-intro-es.info,  Node: Prevenir confusión,  Next: Partes de la expresión let,  Up: let

‘let’ evita confusiones
-----------------------

La forma especial ‘let’ evita confusiones.  ‘let’ crea un nombre para
una “variable local” que eclipsa cualquier uso del mismo nombre fuera de
la expresión ‘let’.  Esto es como entender que siempre que tu anfitrión
se refiera a 'la casa', significa su casa, no la tuya.  (Los símbolos
usados en las listas de argumentos funcionan de la misma manera.  *Note
La Forma Especial ‘defun’: defun.)

   Las variable locales por una expresión ‘let’ conservan su valor
_solo_ dentro de la expresión ‘let’ misma (y dentro de expresiones
llamadas dentro de la expresión ‘let’); las variables locales no tiene
efecto fuera de la expresión ‘let’.

   Otra forma de pensar respecto a ‘let’ es que es como un ‘setq’ que es
temporal y local.  Los valores establecidos por ‘let’ son
automáticamente deshechos cuando termina el ‘let’.  La configuración
solo afecta a las expresiones que se encuentran dentro de los limites de
la expresión ‘let’.  En jerga informatica, diríamos "la union de un
simbolo es visible solo en las funciones llamadas en la forma ‘let’; en
Emacs Lisp, el alcance es dinámico, no léxico."

   ‘let’ puede crear más de una variable a la vez.  Ademas, ‘let’ da a
cada variable que crea un valor inicial, ya sea un valor especificado
por tí, o ‘nil’.  (En la jerga, eso se llama 'unir la variable al
valor'.)  Después que ‘let’ ha creado y unido las variables, ejecuta el
código en el cuerpo del ‘let’ y devuelve el valor de la última expresión
en el cuerpo, como el valor de toda la expresión ‘let’.  ('Ejecutar' es
un término tecnico que significa evaluar una lista: proviene del
significando de la palabra 'llevar a la práctica' (‘Diccionario de
Inglés de Oxford’).  Dado que evalúas una expresión para realizar una
acción, 'ejecutar' ha evolucionado como un sinónimo para 'evaluar'.)


File: emacs-lisp-intro-es.info,  Node: Partes de la expresión let,  Next: Ejemplo de expresión let,  Prev: Prevenir confusión,  Up: let

3.6.1 Las partes de una expresión ‘let’
---------------------------------------

Una expresión ‘let’ es una lista de tres partes.  La primer parte es el
símbolo ‘let’.  La segunda parte es una lista, denominada “varlist”
(lista de variables), cada uno de cuyos elementos es un símbolo por sí
mismo o una lista de dos elementos, el primer elemento es un símbolo.
La tercera parte de la expresión ‘let’ es el cuerpo del ‘let’.  El
cuerpo normalmente consiste de una o más listas.

   Una plantilla para una expresión ‘let’ se parece a esto:

     (let VARLIST BODY...)

Los símbolos en la varlist son las variables que dan los valores
iniciales para la forma especial ‘let’.  Los símbolos por sí solos
reciven el valor inicial de ‘nil’; y cada símbolo que es el primer
elemento de una lista de dos elementos es unido al valor que el devuelto
cuando el intérprete Lisp evalúa el segundo elemento.

   De este modo, una varlist como: ‘(thread (needles 3))’.  En este
caso, dentro una expresión ‘let’, Emacs une el símbolo ‘thread’ a un
valor inicial de ‘nil’, y une el símbolo ‘needles’ a un valor inicial de
3.

   Cuando escribes una expresión ‘let’, lo que haces es poner las
expresiones apropiadas en los huecos de la plantilla de expresión ‘let’.

   Si la varlist está compuesta de listas de 2 elementos, como suele ser
el caso, la plantilla de la expresión ‘let’ es la siguiente:

     (let ((VARIABLE VALOR)
           (VARIABLE VALOR)
           ...)
       CUERPO...)


File: emacs-lisp-intro-es.info,  Node: Ejemplo de expresión let,  Next: Variables let inicializadas,  Prev: Partes de la expresión let,  Up: let

3.6.2 Ejemplo de Expresión ‘let’
--------------------------------

La siguiente expresión crea y da valores iniciales a las dos variables
‘cebra’ y ‘tigre’.  El cuerpo de la expresión ‘let’ es una lista que
llama a la función ‘message’.

     (let ((cebra 'rayas)
           (tigre 'fiero))
       (message "Un tipo de animal tiene %s y otro es %s."
                cebra tigre))

   Aquí, la varlist es ‘((cebra 'rayas) (tigre 'fiero))’.

   Las dos variables son ‘cebra’ y ‘tigre’.  Cada variable es el primer
elemento de una lista de dos elementos y cada valor es el segundo
elemento de su lista de dos elementos.  En la varlist, Emacs une la
variable ‘cebra’ al valor ‘rayas’(1), y une la variable ‘tigre’ al valor
‘fiero’.  En este ejemplo, ambos valores son símbolos precedidos por una
cita.  Los valores podrían muy bien haber sido otra lista o una cadena.
El cuerpo de ‘let’ sigue después de la lista que contiene las variables.
En este ejemplo, el cuerpo es una lista que usa la función ‘message’
para imprimir una cadena en el área echo.

   Puedes evaluar el ejemplo de la forma habitual, coloca el cursor
después del último paréntesis y presiona ‘C-x C-e’.  Al hacer esto,
aparecerá lo siguiente en el área echo:

     "Un tipo de animal tiene rayas y otro es fiero."

   Como hemos visto antes, la función ‘message’ imprime su primer
argumento, excepto por ‘%s’.  En este ejemplo, el valor de la variable
‘cebra’ se imprime en la posición del primer ‘%s’ y el valor de la
variable ‘tigre’ se imprime en la posición del segundo ‘%s’.

   ---------- Footnotes ----------

   (1) De acuerdo con Jared Diamond en ‘Guns, Germs, and Steel’, "...
las cebras se vuelven increiblemente peligrosas a medida que envejecen"
pero la demanda aquí es que no llegan a ser fieras como un tigre.
(1997, W. W. Norton and Co., ISBN 0-393-03894-2, pagina 171)


File: emacs-lisp-intro-es.info,  Node: Variables let inicializadas,  Prev: Ejemplo de expresión let,  Up: let

3.6.3 Variables sin inicializar en un sentencia ‘let’
-----------------------------------------------------

Si no se une a las variables en una sentencia ‘let’ con valores
iniciales específicos, automáticamente seran unidos a un valor inicial
de ‘nil’, como en la siguiente expresión:

     (let ((abedul 3)
           pino
           abeto
           (roble 'algunos))
       (message
        "Aquí están %d variables con %s, %s, y el valor %s."
        abedul pino abeto roble))

Aquí, la varlist es ‘((abedul 3) pino abeto (roble 'algunos))’.

   Si evalúas esta expresión de la forma habitual, aparecerá lo
siguiente en el área echo:

     "Aquí están 3 variables con nil, nil, y el valor algunos."

En este ejemplo, Emacs une el símbolo ‘abedul’ al número 3, une los
símbolos ‘pino’ y ‘abeto’ a ‘nil’, y une el símbolo ‘roble’ al valor
‘algunos’.

   Observe que en la primera parte de ‘let’, las variables ‘pino’ y
‘abeto’ son unicamente átomos que no están rodeados por paréntesis; esto
se debe a que están siendo unidos a ‘nil’, la lista vacía.  Pero ‘roble’
se une a ‘algunos’ por ello es parte de la lista ‘(roble 'algunos)’.  De
manera similar, ‘abedul’ se une al número 3 en una lista con este
número.  (Ya que un número se evalúa a sí mismo, el número no necesita
ser citado.  Ademas, el número se imprime en el mensaje usando un ‘%d’
en lugar de un ‘%s’.)  Las cuatro variables como un grupo son puestas
dentro de una lista para delimitarla de el cuerpo de ‘let’.


File: emacs-lisp-intro-es.info,  Node: if,  Next: else,  Prev: let,  Up: Escribiendo funciones

3.7 La forma especial ‘if’
==========================

Además de ‘let’ y ‘defun’, esta la forma especial condicional ‘if’.
Esta forma se utiliza para indicar al computador que tome decisiones.
Puedes escribir definiciones de función sin necesidad de utilizar ‘if’,
pero se usa con bastante frecuencia, y es lo suficientemente importante
como para incluirse aquí.  Se utiliza, por ejemplo, en el código para la
función ‘beginning-of-buffer’.

   La idea básica detras de ‘if’, es que "_if_ (si) una prueba es verdad
_then_ (entonces) se evalua la expresión."  Si la prueba no es verdad,
la expresión no se evalua.  Por ejemplo, podría tomar una decisión como,
"¡si es cálido y soleado, entonces ir a la playa!"

* Menu:

* if en más detalle::      if en más detalle
* tipo-de-animal en detalle::  Un ejemplo de una expresión ‘if’.


File: emacs-lisp-intro-es.info,  Node: if en más detalle,  Next: tipo-de-animal en detalle,  Up: if

‘if’ en más detalle
-------------------

Al escribir una expresión ‘if’ en Lisp no se utiliza la palabra 'then';
la prueba y la acción son el segundo y tercer elementos de la lista cuyo
primer elemento es ‘if’.  No obstante, la parte de la prueba en una
expresión ‘if’ a menudo se llamada “if-part” (_parte-si_) y el segundo
argumento a menudo se llamada “then-part” (_parte-entonces_).

   Adembas, cuando se escribe una expresión ‘if’, la
prueba-verdadero-o-falso normalmente se escribe en la misma línea que el
símbolo ‘if’, pero la acción a llevar a cabo si la prueba es verdadera,
"then-part" (_parte-entonces_), se escribe en la segunda y siguientes
líneas.  Esto hace que la expresión ‘if’ sea mas fácil de leer.

     (if PRUEBA-VERDADERO-O-FALSO
         ACCION-A-REALIZAR-SI-EL-TEST-ES-CIERTO)

La prueba-verdadero-o-falso es una expresión que evalua el intérprete
Lisp.

   Aquí hay un ejemplo que puedes evaluar.  La prueba consiste en si el
número 5 es mayor que el número 4.  Ya que es así, se imprime el mensaje
‘¡5 es mayor que 4!’.

     (if (> 5 4)                           ; parte-si
         (message "¡5 es mayor que 4!"))   ; parte-entonces

(La función ‘>’ comprueba si su primer argumento es mayor que su segundo
argumento y devuelve verdadero si lo es.)

   Por supuesto, en un caso real, la prueba en una expresión ‘if’ no
será siempre la misma, como en la expresión ‘(> 5 4)’.  En su lugar, al
menos una de las variables utilizadas en la prueba estara unida a un
valor de antemano desconocido.  (Si el valor se conoce de antemano, ¡no
necesitamos realizar la prueba!)

   Por ejemplo, el valor puede estar unido a un argumento de una
definición de función.  En la siguiente definición de función, el tipo
de animal es un valor que se pasa a la función.  Si el valor unido a
‘caracteristica’ es ‘fiero’, entonces se imprime el mensaje, ‘¡Es un
tigre!’; de otro modo, se devolvera ‘nil’.

     (defun tipo-de-animal (caracteristica)
       "Imprime el mensaje en el área echo dependiendo de CARACTERISTICA.
     Si la CARACTERISTICA es el símbolo `fiero',
     entonces advierte que es un tigre."
       (if (equal caracteristica 'fiera)
           (message "¡Es un tigre!")))

Si estás leyendo esto dentro de GNU Emacs, puedes evaluar la definición
de función de la forma habitual para instalarlo en Emacs, y luego puedes
evaluar las dos expresiones siguientes para ver los resultados:

     (tipo-de-animal 'fiero)
     (tipo-de-animal 'cebra)

Al evaluar ‘(tipo-de-animal 'fiero)’, veras el siguiente mensaje impreso
en el área echo: ‘"¡Es un tigre!"’; y cuando se evalúa ‘(tipo-de-animal
'cebra)’ verás ‘nil’ impreso en el área echo.


File: emacs-lisp-intro-es.info,  Node: tipo-de-animal en detalle,  Prev: if en más detalle,  Up: if

3.7.1 La función ‘tipo-de-animal’ en detalle
--------------------------------------------

Veamos la función ‘tipo-de-animal’ en detalle.

   La definición de función ‘tipo-de-animal’ se escribio llenando los
espacios de dos plantillas, la primera para la definición de función
como un todo, y la seguanda para una expresión ‘if’.

   La plantilla para cada función no interactiva es:

     (defun NOMBRE-DE-FUNCION (LISTA-DE-ARGUMENTOS)
       "DOCUMENTACION..."
       CUERPO...)

   Las partes de la función que encajan con esta plantilla se ven asi:

     (defun tipo-de-animal (caracteristica)
       "Imprime el mensaje en el área echo dependiendo de CARACTERISTICA.
     Si la CARACTERISTICA es el símbolo `fiero',
     entonces advierte que es un tigre."
       CUERPO: LA EXPRESIÓN if)

   El nombre de función es ‘tipo-de-animal’; se pasa al valor de un
argumento.  A la lista de argumentos se sigue una cadena de
documentación multi-línea.  La cadena de documentación se incluye en el
ejemplo porque es un buen hábito escribir la cadena de documentación
para cada definición de función.  El cuerpo de la definición de función
consiste en la expresión ‘if’.

   La plantilla para una expresión ‘if’ se ve así:

     (if PRUEBA-VERDADERO-O-FALSO
         ACCION-A-REALIZAR-SI-LA-PRUEBA-DEVUELVE-VERDADERO)

   En la función ‘tipo-de-animal’, el código para ‘if’ se ve así:

     (if (equal caracteristica 'fiero)
         (message "¡Es un tigre!")))

   Aquí, está la expresión prueba-verdadero-o-falso

     (equal caracteristica 'fiero)

En Lisp, ‘equal’ es una función que determina si su primer argumento es
igual a su segundo argumento.  El segundo argumento es el símbolo citado
‘'fiero’ y el primer argumento es el valor del símbolo ‘caracteristico’
-- en otras palabras, el argumento pasado a esta función.

   En la primer prueba de ‘tipo-de-animal’, el argumento ‘fiero’ se pasa
a ‘tipo-de-animal’.  Ya que ‘fiero’ es igual a ‘fiero’, la expresión,
‘(equal caracteristica 'fiero)’, devuelve el valor verdadero.  Cuando
esto sucede, ‘if’ evalúa el segundo argumento o la parte-entonces del
‘if’: ‘(message "¡Es un tigre!")’.

   Por otro lado, en la segunda prueba de ‘tipo-de-animal’, se pasa el
argumento ‘cebra’ a ‘tipo-de-animal’.  ‘cebra’ no es igual a ‘fiero’,
por lo que la parte-entonces no se evalua y se devuelve ‘nil’ por la
expresión ‘if’ (_si_).


File: emacs-lisp-intro-es.info,  Node: else,  Next: Verdad y falsedad,  Prev: if,  Up: Escribiendo funciones

3.8 Expresiones if-then-else
============================

Una expresión ‘if’ puede tener un tercer argumento opcional, llamado la
“parte-de_otro_modo”, en caso de que la prueba-verdadero-o-falso
devuelva falso.  Cuando esto sucede, el segundo argumento o then-part de
la expresión ‘if’ global, _no_ se evalúa, pero el tercer argumento o la
parte-de_otro_modo _se_ evalúa.  Podría pensar en esto como la
alternativa del día nublado para la decisión "si es cálido y soleado,
entonces ir a la playa, de otro modo ¡leer un libro!"

   La palabra "else" ("de otro modo") no se escribe en el código Lisp;
la parte-de_otro_modo de una expresión ‘if’ viene después de la
parte-entonces.  En Lisp, la parte-de_otro_modo suele escribirse al
inicio de una nueva línea y se indenta menos que la parte-entonces:

     (if PRUEBA-VERDADERO-O-FALSO
         ACCION-A-REALIZAR-SI-LA-PRUEVA-DEVUELVE-VERDADERO
       ACCION-A-REALIZAR-SI-LA-PRUEBA-DEVUELVE-FALSO)

   Por ejemplo, la siguiente expresión ‘if’ imprime el mensaje ‘¡4 no es
mayor que 5!’ al evaluarse en la forma habitual:

     (if (> 4 5)                                   ; parte-si
         (message "¡4 falsamente es mayor que 5!") ; parte-entonces
       (message "¡4 no es mayor que 5!"))          ; parte-resto

Nótese que los diferentes niveles de indentación hacen fácil distinguir
la parte then desde la parte resto.  (GNU Emacs tiene varios comandos
que automáticamente indenta expresiones correctamente ‘if’ _si_.  *Note
GNU Emacs te ayuda a escribir listas: Escribiendo listas.)

   Podemos extender la función ‘tipo-de-animal’ para incluir una parte
else para simplemente incorporar una parte adicional para la expresión
‘if’ _si_.

   Se puede ver las consecuencias de hacer esto si se evalúa la
siguiente versión de la definición de función ‘type-of-animal’
(_tipo-de-animal_) para instalarlo y entonces evaluar las dos
expresiones subsiguientes para pasar diferentes argumentos para la
función.

     (defun tipo-de-animal (caracteristica)  ; Segunda versión.
       "Imprime el mensaje en el área echo dependiendo de CARACTERISTICA.
     Si la CARACTERISTICA es el símbolo `fiera',
     entonces avisa de un tigre; sino di que no es una fiera."
       (if (equal caracteristica 'fiera)
           (message "¡Es un tigre!")
         (message "¡No es una fiera!")))

     (tipo-de-animal 'fiero)
     (tipo-de-animal 'cebra)

Cuando se evalúa ‘(tipo-de-animal 'fiera)’, se verá el siguiente mensaje
impreso en el área echo: ‘"¡Eso es un tigre!"’; pero cuando se evalúa
‘(tipo-de-animal 'cebra)’, se verá ‘"¡No es una fiera!"’.

   (De acuerdo, si la CARACTERÍSTICA fuera ‘feroz’, el mensaje ‘"¡No es
una fiera!"’ sería impreso; ¡y sería erróneo!  Cuando se escribe código,
se necesita tener en cuenta la posibilidad que algunos argumentos será
probado por ‘if’ _si_ y escribir tu programa de acuerdo.


File: emacs-lisp-intro-es.info,  Node: Verdad y falsedad,  Next: save-excursion,  Prev: else,  Up: Escribiendo funciones

3.9 Verdad y falsedad en Emacs Lisp
===================================

Hay un aspecto importante para el test de verdad en una expresión ‘if’
(_si_).  Así, hemos hablado de 'verdad' y 'mentira' como valores de
predicados como si fueran nuevos tipos de objetos Emacs Lisp.  En
efecto, 'falso' es solo nuestro viejo amigo ‘nil’.  Cualquier otra es
'verdadero'.

   La expresión chequea si verdad se interpreta como (“true”)
_verdadero_ si el resultado de evaluarlo es un valor que no es ‘nil’.
En otras palabras, el resultado del test se considera cierto si el valor
devuelto es un número como 47, una cadena tal como ‘"hola"’, o un
símbolo (otro como ‘nil’) tal como ‘flores’, o una lista (tan larga como
eso no está vacía) ¡o incluso un búffer!

* Menu:

* nil explicado::            ‘nil’ tiene dos significados.


File: emacs-lisp-intro-es.info,  Node: nil explicado,  Up: Verdad y falsedad

Una explicación de ‘nil’
------------------------

Antes de ilustrar un test para verdad, se necesita una explicación de
‘nil’.

   En Emacs Lisp, el símbolo ‘nil’ tiene dos significados.  Primero,
está el significado de la lista vacía.  Segundo, está el valor de falso
y es el valor devuelto cuando el test test-verdadero-o-falso salga
falso.  ‘nil’.  Tan lejos como el intérprete Lisp es concebido, ‘()’ y
‘nil’ son el mismo.  Los humanos, sin embargo, tienden a usar ‘nil’ para
falso y ‘()’ para la lista vacía.

   En Emacs Lisp, cualquier valor que no es ‘nil’ -- no es una lista
vacía -- es considerado verdad.  Esto significa que si una evaluación
devuelve alguna cosa que no es una lista vacía, una expresión ‘if’
devuelve verdad.  Por ejemplo, si un número es puesto en el slot para el
test, será evaluado y devolverá por sí mismo, desde lo que hacen los
números cuando se evalúan.  En este condicional, la expresión ‘if’
devuelve verdad.  La expresión se chequea como falso solo cuando ‘nil’,
una lista vacía, es devuelta evaluando la expresión.

   Se puede ver esto evaluando las dos expresiones en los siguientes
ejemplos.

   En el primer ejemplo, número 4 es evaluado como el test en la
expresión ‘if’ y se devuelve por sí mismo; por consiguiente, la
then-part de la expresión es evaluada y devuelta: ‘true’ aparece en el
área echo.  En el segundo ejemplo, ‘nil’ indica falso; por consiguiente,
el else-part de la expresión es evaluada y devuelta: ‘false’ aparece en
el área echo.

     (if 4
         'true
       'false)

     (if nil
         'true
       'false)

   Incidentalmente, si algún otro valor útil no está disponible para un
test que devuelve cierto, entonces el intérprete Lisp retornará el
símbolo ‘t’ para cierto.  Por ejemplo, la expresión ‘(> 5 4)’ devuelve
‘t’ cuando se evalúa, como puedes ver evaluándolo en el camino usual:

     (> 5 4)

Por otro lado, esta función devuelve ‘nil’ si el test es falso.

     (> 4 5)


File: emacs-lisp-intro-es.info,  Node: save-excursion,  Next: Revisar,  Prev: Verdad y falsedad,  Up: Escribiendo funciones

3.10 ‘save-excursion’
=====================

La función ‘save-excursion’ es la cuarta y última forma especial que se
discutirá en este capítulo.

   En Emacs Lisp hay programas usados para edición, la función
‘save-excursion’ es muy común.  Eso guarda la posición de punto y marca,
ejecuta el cuerpo de la función, y entonces restaura el punto y marca a
sus posiciones previas si sus posiciones fueran cambiadas.  Su propósito
primario es guardar que el usuario sea sorprendido y molesto por
movimientos inesperados de punto y marca.

* Menu:

* Punto y marca::            Una revisión de varias localizaciones.
* Plantilla para save-excursion::  Plantilla para save-excursion


File: emacs-lisp-intro-es.info,  Node: Punto y marca,  Next: Plantilla para save-excursion,  Up: save-excursion

Punto y Marca
-------------

Antes de discutir ‘save-excursion’, sin embargo, puede ser útil primero
revisar que punto y marca están en GNU Emacs.  “Punto” es la posición
actual del cursor.  En cualquier lugar que el cursor se posicione hay un
punto.  De manera más precisa, en terminales donde el cursor parece
estar en lo alto de un carácter, el punto está inmediatamente antes del
carácter.  En Emacs Lisp, punto es un entero.  El primer carácter en un
búffer es el número uno, el segundo es el número dos, y así.  La función
‘punto’ devuelve la posición actual del cursor como un número.  Cada
búffer tiene su propio valor para el punto.

   La “marca” es otra posición en el búffer; su valor puede ser asignado
con un comando tal como ‘C-<SPC>’ (‘set-mark-command’).  Si una marca ha
sido asignada, se puede usar el comando ‘C-x C-x’
(‘exchange-point-and-mark’) para hacer que el cursor salte a la marca y
asignar la marca para la posición previa del punto.  Además, si tu
asignas otra marca, la posición puede ser guardada por este camino.  Se
puede saltar al cursor para una marca guardada escribiendo ‘C-u C-<SPC>’
una o más veces.

   La parte del búffer entre el punto y la marca es llamada “la región”.
Numerosos comandos trabajan en la región, incluyendo ‘center-region’,
‘count-lines-region’, ‘kill-region’ y ‘print-region’.

   La forma especial ‘save-excursion’ salva las posiciones del punto y
la marca y restaura estas posiciones después del código con el cuerpo de
la forma especial es evaluada por el intérprete Lisp.  De este modo, si
el punto fuera en el principio de una pieza de texto y algún código
movido apunta al fin del búffer, el ‘save-excursion’ no apuntaría a
donde fué antes, después las expresiones en el cuerpo de las que fueron
evaluadas.

   En Emacs, una función frecuentemente mueve el punto como parte de sus
trabajos internos incluso aunque un usuario no espere esto.  Por
ejemplo, ‘count-lines-region’ se mueve al punto.  Para prevenir al
usuario que se preocupe por el salto que es inesperado y (desde el punto
de vista del usuario) innecesario, ‘save-excursion’ es con frecuencia
usado para punto y marca en la posición esperada por el usuario.  El uso
de ‘save-excursion’ es un buen guarda casas.

   Para estar seguro que la casa está limpia, ‘save-excursion’ restaura
los valores de punto y marca incluso si alguna cosa va mal en el código
dentro de eso (o, para ser más preciso y usar la jerga apropiada, "en
caso de salida anormal").  Esta funcionalidad es muy útil.

   Además grabando los valores de punto y marca, ‘save-excursion’ guarda
la traza del actual buffer, y lo restaura, también.  Esto significa que
puedes escribir código que cambiará el buffer y tener que
‘save-excursion’ vuelva al buffer original.  Esto es como
‘save-excursion’ es usado en ‘append-to-buffer’.  (*Note La Definición
de ‘append-to-buffer’: append-to-buffer.)


File: emacs-lisp-intro-es.info,  Node: Plantilla para save-excursion,  Prev: Punto y marca,  Up: save-excursion

3.10.1 Plantilla para una expresión ‘save-excursion’
----------------------------------------------------

La plantilla para código usando ‘save-excursion’ es simple:

     (save-excursion
       BODY...)

El cuerpo de la función es una o más expresiones que serán evaluadas en
secuencia por el intérprete Lisp.  Si hay más de una expresión en el
cuerpo, el valor de la última será devuelto como el valor de la función
‘save-excursion’.  Las otras expresiones en el cuerpo son evaluadas solo
por sus efectos laterales; y ‘save-excursion’ en sí es usado solo por su
efecto lateral (que está restaurando las posiciones de punto y marca).

   Para más detalles, la siguiente plantilla explica ‘save-excursion’

     (save-excursion
       PRIMERA-EXPRESION-EN-EL-CUERPO
       SEGUNDA-EXPRESION-EN-EL-CUERPO
       TERCERA-EXPRESION-EN-EL-CUERPO
        ...
       ULTIMA-EXPRESION-EN-EL-CUERPO)

Una expresión, de acuerdo, puede ser un símbolo por sí mismo o una
lista.

   En código Emacs Lisp, una expresión ‘save-excursion’ con frecuencia
ocurre el cuerpo de una expresión ‘let’.  Eso se ve como esto:

     (let VARLIST
       (save-excursion
         BODY...))


File: emacs-lisp-intro-es.info,  Node: Revisar,  Next: Ejercicios defun,  Prev: save-excursion,  Up: Escribiendo funciones

3.11 Revisar
============

En los últimos pocos capítulos se han introducido un número limpio de
funciones y formas especiales.  Aquí se han descrito brevemente, con
unas pocas funciones similares que no han sido mencionadas todavía.

‘eval-last-sexp’
     Evalúa la última expresión simbólica antes de la posición actual
     del punto.  El valor es impreso en el área echo a menos que la
     función sea invocada con un argumento; en este caso, la salida es
     impresa en el actual búffer.  Este comando está normalmente
     asociado a ‘C-x C-e’.

‘defun’
     Definir función.  Esta forma especial ha subido a cinco partes: el
     nombre una plantilla para los argumentos que serán pasados a la
     documentación de la función, una declaración interactiva opcional,
     y el cuerpo de la definición.

     Por ejemplo, en las primeras versiones de Emacs, la definición de
     función era como sigue.  (Eso es ligeramente más complejo ahora que
     si busca el primer caracter de espacio no en blanco en vez del
     primer caracter visible.)

          (defun volver-a-indentacion ()
            "Mover el punto al primer caracter visible en linea."
            (interactive)
            (beginning-of-line 1)
            (skip-chars-forward " \t"))

‘interactive’
     Declara al intérprete que la función puede ser usada
     interactivamente.  Esta forma especial puede ser seguida por una
     cadena con una o más partes que pasan la información a los
     argumentos de la función, en secuencia.  Estas partes pueden
     también contar al intérprete para mostrar la información.  Parte de
     las cadenas son separadas por nuevas líneas, ‘\n’.

     Caracteres de código común son:

     ‘b’
          El nombre de un búffer existente.

     ‘f’
          El nombre de un fichero existente

     ‘p’
          El argumento prefijo numérico.  (Nótese que esta 'p' es
          minúscula.)

     ‘r’
          El Punto y la marca, como dos argumentos numéricos, el más
          pequeño primero.  Esta es la única letra que especifica dos
          argumentos sucesivos en vez de uno.

     *Note Caracteres de Código para ‘interactive’: (elisp)Códigos
     Interactivos, para una lista de caracteres de código.

‘let’
     Declara que una lista de variables es para usarla con el cuerpo del
     ‘let’ y darles un valor inicial, bien ‘nil’ o un valor específico;
     entonces se evaluarán el resto de las expresiones en el cuerpo del
     ‘let’ y devolver el valor de la última.  Dentro del cuerpo del
     ‘let’, el intérprete Lisp no ve los valores de las variables de los
     mismos nombres que son asociados fuera del ‘let’.

     Por ejemplo,

          (let ((foo (nombre-de-buffer))
                (bar (tamagno-de-buffer)))
            (message
             "Este buffer es %s y tiene %d caracteres."
             foo bar))

‘save-excursion’
     Graba los valores de punto y marca y el actual búffer antes de
     evaluar el cuerpo de esta forma especial.  Restaura los valores de
     punto y marca y el búffer después de esto.

     Por ejemplo,

          (message "Hay %d caracteres dentro de este buffer."
                   (- (point)
                      (save-excursion
                        (goto-char (point-min)) (point))))

‘if’
     Evalúa el primer argumento a la función; si es verdad, evalúa el
     segundo argumento; lo demás evalúa el tercer argumento, si hay uno.

     La forma especial ‘if’ es llamada “condicional”.  Hay otros
     condicionales en Emacs Lisp, pero ‘if’ es quizás lo más comúnmente
     usado.

     Por ejemplo,

          (if (= 22 version-de-emacs-mayor)
              (message "Esta es la versión 22 de Emacs")
            (message "Esta no es la versión 22 Emacs"))

‘<’
‘>’
‘<=’
‘>=’
     La función ‘<’ chequea si su primer argumento es más pequeño que su
     segundo argumento.  Una función correspondiente, ‘>’, chequea si el
     primer argumento es mayor que el segundo.  De otro modo, ‘<=’
     chequea si el primer argumento es menor o igual al segundo y ‘>=’
     chequea si el primer argumento es mayor o igual al segundo.  En
     todos los casos, ambos argumentos deben ser números o marcas (las
     marcas indican posiciones en búffers).

‘=’
     La función ‘=’ chequea si dos argumentos, ambos números o
     marcadores, son iguales.

‘equal’
‘eq’
     Chequea si dos objetos son el mismo.  ‘equal’ usa un signicado de
     la palabra 'mismo' y ‘eq’ usa otro: ‘equal’ devuelve cierto si los
     dos objetos tienen una estructura y contenidos similares, tal como
     dos copias del mismo libro.  En una mano, ‘eq’, devuelve cierto si
     ambos argumentos son actualmente el mismo objeto.

‘string<’
‘string-lessp’
‘string=’
‘string-equal’
     La función ‘string-lessp’ chequea si su primer argumento es más
     pequeño que el segundo.  En resumen, el nombre alternativo para la
     misma función (un ‘defalias’) es ‘string’.

     Los argumentos para ‘string-lessp’ deben ser cadenas o símbolos; la
     ordenación es lexicográfica, así el caso es significativo.  Los
     nombres impresos de símbolos son usado en vez de símbolos por sí
     mismos.

     Una cadena vacía, ‘"\"’, es una cadena sin caracteres dentro, es
     más pequeña que cualquier cadena de caracteres.

     ‘string-equal’ provee el test correpondiente para igualdad.  Su
     corto nombre alternativo es ‘string=’.  No hay funciones test que
     correponden a >, ‘>=’.

‘message’
     Imprime un mensaje en el área echo.  El primer argumento es una
     cadena que puede contener, ‘%s’, ‘%d’, o ‘%c’ para imprimir el
     valor de argumentos que siguen la cadena.  El argumento usado por
     ‘%d’ debe ser un número.  El argumento usado por ‘%c’ debe ser un
     número de código ASCII; eso será impreso como el caracter con este
     código ASCII.  (Otras varias %-secuencias no han sido mencionadas.)

‘setq’
‘set’
     La función ‘setq’ asigna el valor de su primer argumento al valor
     del segundo argumento.  El primer argumento está automáticamente
     citado por ‘setq’.  Eso hace lo mismo para los pares de argumentos.
     Otra función, ‘set’, toma solo dos argumentos y evalúa ambos de
     ellos antes de configurar el valor devuelto por su primer argumento
     al valor devuelto por su segundo argumento.

‘buffer-name’
     Sin un argumento, devuelve el nombre del búffer, como una cadena.

‘buffer-file-name’
     Sin un argumento, devuelve el nombre del fichero si el búffer lo
     está visitando.

‘current-buffer’
     Devuelve el búffer en el que Emacs es activo; eso puede no ser el
     búffer que es visible en la pantalla.

‘other-buffer’
     Devuelve el búffer seleccionado más recientemente (otro que el
     búffer pasado a ‘other-buffer’ como un argumento y otro en vez de
     el búffer actual).

‘switch-to-buffer’
     Selecciona un búffer para que Emacs esté activo y lo muestre en la
     ventana actual y así los usuarios puedan mirarlo.  Normalmente se
     empareja a ‘C-x b’.

‘set-buffer’
     Cambia la atención de Emacs a un búffer en el que los programas se
     ejecutarán.  No altera lo que la ventana está mostrando.

‘buffer-size’
     Devuelve el número de caracteres en el búffer actual.

‘punto’
     Devuelve el valor de la actual posición del cursor, como un entero
     contando el número de caracteres desde el principio del búffer.

‘point-min’
     Devuelve el valor mínimo permisible del punto en el búffer actual.
     Esto es 1, a menos que la contracción esté en efecto

‘point-max’
     Devuelve el valor del máximo valor permisible del punto en el
     búffer actual.  Esto es el fin del búffer, a menos que la
     contracción esté en efecto


File: emacs-lisp-intro-es.info,  Node: Ejercicios defun,  Prev: Revisar,  Up: Escribiendo funciones

3.12 Ejercicios
===============

   • Escribe una función no interactiva que doble el valor de su
     argumento, un número.  Luego haz la función interactiva.

   • Escribe una función que chequee si el valor actual de ‘fill-column’
     es más grande que el argumento pasado a la función, y si es así,
     imprime un mensaje apropiado.


File: emacs-lisp-intro-es.info,  Node: Un paseo a través de los búffers,  Next: Más complejidad,  Prev: Escribiendo funciones,  Up: Top

4 Unas pocas funciones de buffer relacionadas
*********************************************

En este capítulo estudiamos en detalle varias de las funciones usadas en
GNU Emacs.  Esto se llama un "paseo a través".  Estas funciones son
usadas como ejemplos de código Lisp, pero no son ejemplos imaginarios;
con la excepción del primero, la definición de función simplificada,
esta funciones muestran el actual código usado en GNU Emacs.  Se puede
aprender mucho desde estas definiciones.  Las funciones descritas aquí
están todas relacionadas a búffers.  Después, estudiaremos otras
funciones.

* Menu:

* Encontrando más::        Cómo encontrar más información.
* simplified-beginning-of-buffer::  Muestra ‘goto-char’,
                                      ‘point-min’, y ‘push-mark’.
* mark-whole-buffer::        Casi lo mismo que ‘beginning-of-buffer’.
* append-to-buffer::         Usa ‘save-excursion’ y
                               ‘insert-buffer-substring’.
* Revisa lo relacionado con el búffer::  Revisa
* Ejercicios de búffer::   Ejercicios de búffer


File: emacs-lisp-intro-es.info,  Node: Encontrando más,  Next: simplified-beginning-of-buffer,  Up: Un paseo a través de los búffers

4.1 Encontrando más información
===============================

En este paseo, se describe cada nueva función como viene, algunas veces
en detalle y algunas veces brevemente.  Si está interesado, se puede
obtener la documentación completa de cualquier función Emacs Lisp en
cualquier momento escribiendo ‘C-h f’ y entonces el nombre de la función
(y entonces <RET>.  De manera similar, se puede obtener la documentación
completa para una variable escribiendo ‘C-h v’, después el nombre de la
variable (y entonces <RET>).

   También, en ‘describe-function’, se encontrará la localización de la
definición de la función.

   Poner el punto dentro del nombre del fichero que contiene la función
y presiona la tecla <RET>.  En este caso, <RET> significa ‘push-button’
en vez de 'return' o 'enter'.  Emacs tomará directamente a la definición
de la función.

   De manera más general, si quieres ver una función en su fichero
fuente original, se puede usar la función ‘find-tag’ para saltar dentro.
‘find-tag’ funciona con una amplia variedad de lenguajes, no solo Lisp,
y C, y funciona con texto de no programación también.  Por ejemplo,
‘find-tag’ saltará a los varios nodos en el fichero fuente Texinfo de
este documento.  La función ‘find-tag’ depende de 'tablas de etiquetas'
que graba las localizaciones de las funciones, variables, y otros ítems
para los que ‘find-tag’ salta.

   Para usar el comando ‘find-tag’, escribe ‘M-.’ (por ej., presionando
la tecla <META>, o al menos escribe la tecla <ESC> y entonces escribe la
tecla punto), entonces, en la pantalla, se escribe el nombre de la
función cuyo código fuente se quiere ver, tal como ‘mark-whole-buffer’,
y luego escribe <RET>.  Emacs cambiará el búffer y mostrará el código
fuente para la función en la pantalla.  Para volver al búffer actual,
escribe ‘C-x b <RET>’.  (En algunos teclados, la tecla <META> es
etiquetada con <ALT>.)

   Dependiendo de cómo los valores iniciales por defecto de tu copia de
Emacs son asignados se puede también necesitar especificar la posición
de tu 'tabla de tags', que es un fichero llamado ‘TAGS’.  Por ejemplo,
si se está interesado en fuentes de Emacs, la tabla de tags que se
desea, si ya ha sido creada para tí, estará en un subdirectorio del
directorio ‘/usr/local/share/emacs’; de este modo se usaría el comando
‘M-x visit-tags-table’ y especifica una ruta tal como
‘/usr/local/share/emacs/22.1.1/lisp/TAGS’.  Si la tabla tags no ha sido
creada, tendrás que crearla por tí mismo.  Será un fichero tal como
‘/usr/local/src/emacs/src/TAGS’.

   Para crear un fichero ‘TAGS’ en un directorio específico, cambia a
este directorio en Emacs usando un comando ‘M-x cd’, o lista el
directorio como ‘etags *.el’ como el comando para ejecutar:

     M-x compile RET etags *.el RET

   Para más información, ver *note Crea tu propio fichero ‘TAGS’: etags.

   Después de llegar a estar más familiarizado con Emacs Lisp, se
encontrará frecuentemente usar ‘find-tag’ para navegar tu camino
alrededor del código fuente; y se crearán tus propias tablas ‘TAGS’.

   Incidentalmente, los ficheros que contienen código Lisp son
convencionalmente llamadas “librerías”.  La metáfora se deriva que una
librería, tal como la librería de leyes o una librería de ingeniería, en
vez de una librería general.  Cada librería, o fichero, contiene
funciones que se relacionan a un asunto particular o actividad, tal como
‘abbrev.el’ para manejar abreviaciones y otros atajos, y ‘help.el’ para
la ayuda on-line.  (Algunas veces varias librerías proporcionan código
para una actividad simple, como varios ‘rmail...’ ficheros proveen
código para leer correos electrónicos.)  En ‘El Manual de GNU Emacs’, tu
verás varias frases tales como "El comando ‘C-h p’ te permite buscar el
estándar de las librerías Emacs Lisp por las palabras claves.


File: emacs-lisp-intro-es.info,  Node: simplified-beginning-of-buffer,  Next: mark-whole-buffer,  Prev: Encontrando más,  Up: Un paseo a través de los búffers

4.2 Una definición simplificada de ‘beginning-of-buffer’
========================================================

El comando ‘beginning-of-buffer’ es una buena función para empezar ya
puedes tener cierta familiaridad con eso y es fácil de comprender.
Usado como un comando interactivo, ‘beginning-of-buffer’ mueve el cursor
al principio del búffer, dejando la marca en la posición previa.  Eso es
generalmente asignados a ‘M-<’.

   En esta sección, se discutirá una versión ordenada de la función que
muestra como eso es lo usado más frecuentemente.  Esta función ordenada
trabaja como se escribe, pero no contiene el código para una función
compleja.  En otra sección, describiremos la función entera.  (*Note
Definición Completa de ‘beginnning-of-buffer’: beginning-of-buffer.)

   Antes de mirar en el código, permítenos considerar que la definición
de función tiene que contener: eso debe incluir una expresión que crea
la función interactiva así puede ser llamado escribiendo ‘M-x
beginning-of-buffer’ o escribiendo unos atajos tales como ‘M-<’; debe
incluir código para dejar una marca en la posición original en el
búffer; y debe incluir código el cursor al principio del búffer.

   Aquí está el texto completo la versión ordenada de la función:

     (defun simplified-beginning-of-buffer ()
       "Mover punto al principio del bufer; dejar marca en la posición previa."
       (interactive)
       (push-mark)
       (goto-char (point-min)))

   Como todas las definiciones de función, esta definición tiene cinco
partes siguiendo la forma especial ‘defun’:

  1. El nombre: en este ejemplo, ‘simplified-beginning-of-buffer’.

  2. Una lista de los argumentos: en este ejemplo, una lista vacía,
     ‘()’,

  3. La cadena de documentación.

  4. La expresión interactive.

  5. El cuerpo.

En esta definición de función, la lista de argumentos está vacía; esto
significa que esta función no requiere argumentos.  (Cuando se busca la
definición para la función completa, se verá que puede pasarse un
argumento opcional.)

   La expresión interactiva cuenta a Emacs que la función se pretende
ser usada interactivamente.  En este ejemplo, ‘interactive’ no tiene un
argumento porque ‘simplified-beginning-of-buffer’ no se requiere.

   El cuerpo de la función consiste de dos líneas:

     (push-mark)
     (goto-char (point-min))

   La primera de estas líneas es la expresión, ‘(push-mark)’.  Cuando
esta expresión es evaluado por el intérprete Lisp, eso asigna una marca
en la posición actual del cursor, siempre y cuando esto pueda ser.  La
posición de esta marca está guardada en el anillo de marcas.

   La siguiente línea es ‘(goto-char (point-min))’.  Esta expresión
salta el cursor al punto mínimo en el búffer, esto es, para el comienzo
del búffer (o al principio de la porción accesible del búffer si eso
está encogido.  *Note Encogiendo y extendiendo: Encogiendo y
extendiendo.)

   El comando ‘push-mark’ estable una marca en el lugar donde el cursor
fué localizado antes que fuera movido al principio del búffer por la
expresión ‘(goto-char (point-min))’.  Consiguientemente, puedes, si lo
deseas, volver donde estabas originalmente escribiendo ‘C-x C-x’.

   ¡Esto es todo lo que hay para la definición de función!

   Cuando se lee código como este y vuelve a una función no familiar,
tal como ‘goto-char’, se puede encontrar que se hace usando el comando
‘describe-function’.  Para usar este comando, escribe ‘C-h f’ y entonces
escribe en el nombre de la función y presiona <RET>.  El comando
‘describe-function’ imprimirá la documentaciń de la cadena de la función
en una ventana ‘*Help*’.  Por ejemplo, la documentación para ‘goto-char’
es:

     Asignar punto a POSITION, un número o marca
     Empezando el buffer es la posición (point-min), y el final es
     (point-max).

La función es un argumento es la posición deseada.

(La consola para ‘describe-function’ te ofrecerá el símbolo abajo o
precediendo al cursor, así se puede guardar escribiendo al posicionar el
cursor a la derecha o después de la función y entonces escribir ‘C-h f
<RET>’.)

   La definición de función ‘end-of-buffer’ está escrito en el mismo
modo que la definición ‘beginnig-of-buffer’ excepto que el cuerpo de la
función contenga la expresión ‘(goto-char (point-max))’ en lugar de
‘(goto-char (point-min))’


File: emacs-lisp-intro-es.info,  Node: mark-whole-buffer,  Next: append-to-buffer,  Prev: simplified-beginning-of-buffer,  Up: Un paseo a través de los búffers

4.3 La definición de ‘mark-whole-buffer’
========================================

La función ‘mark-whole-buffer’ no es tan difícil de comprender que la
función ‘simplified-beginning-of-buffer’.  En este caso, sin embargo, se
verá la función completa, no una versión ordenada.

   La función ‘mark-whole-buffer’ no está comúnmente usada como la
función ‘beginning-of-buffer’, pero eso no es útil: eso marca un búffer
completo como una región poniendo el punto al principio y una marca al
fin del búffer.  Eso está generalmente asociado a ‘C-x h’.

* Menu:

* resumen de mark-whole-buffer::  resumen de mark-whole-buffer
* Cuerpo de mark-whole-buffer::  Solo tres líneas de código.


File: emacs-lisp-intro-es.info,  Node: resumen de mark-whole-buffer,  Next: Cuerpo de mark-whole-buffer,  Up: mark-whole-buffer

Un resumen de ‘mark-whole-buffer’
---------------------------------

En GNU Emacs 22, el código para la función completa se parece a:

     (defun mark-whole-buffer ()
       "Pon el punto al principio y marca el fin del búffer.
     Probablemante no deberías usar esta función en
       programas Lisp; normalmente un error para una función Lisp usa
       cualquier subrrutina que usa o asigna la marca."
       (interactive)
       (push-mark (point))
       (push-mark (point-max) nil t)
       (goto-char (point-min)))

   Como todas las otras funciones, la función ‘mark-whole-buffer’ se
ajusta dentro de la plantilla para una definición.  La plantilla se
parece a esta:

     (defun NAME-OF-FUNCTION (ARGUMENT-LIST)
       "DOCUMENTATION..."
       (INTERACTIVE-EXPRESSION...)
       BODY...)

   Aquí está cómo la función trabaja: el nombre de la función es
‘mark-whole-buffer’; eso es seguida por un argumento de lista vacía,
‘()’, que significa que la función no requiere argumentos.  La
documentación viene la siguiente.

   La siguiente línea es una expresión ‘(interactive)’ que cuenta a
Emacs que la función será usada interactivamente.  Estos detalles son
similares a la función ‘simplified-beginning-of-buffer’ descrita en la
sección previa


File: emacs-lisp-intro-es.info,  Node: Cuerpo de mark-whole-buffer,  Prev: resumen de mark-whole-buffer,  Up: mark-whole-buffer

4.3.1 Cuerpo de ‘mark-whole-buffer’
-----------------------------------

El cuerpo de la función ‘mark-whole-buffer’ consiste en tres líneas de
código:

     (push-mark (point))
     (push-mark (point-max) nil t)
     (goto-char (point-min))

   El primero de estas líneas es la expresión, ‘(push-mark (point))’.

   Esta línea hace exactamente el mismo trabajo que la primera línea del
cuerpo de la función ‘simplified-beginning-of-buffer’, que está escrita
‘(push-mark)’.  En ambos casos, el intérprete Lisp asigna una marca en
la posición actual del cursor.

   No sé por qué en la expresión ‘mark-whole-buffer’ está escrito
‘(push-mark (point))’ y en la expresión ‘beginning-of-buffer’ está
escrito ‘(push-mark)’.  Quizás quien escribió el código no sabía que los
argumentos para ‘push-mark’ son opcionales y que si ‘push-mark’ no se
pasa como argumento, la función automáticamente asigna la marca en la
localización del punto por defecto.  O quizás la expresión fué escrita
así como para parelizar la estructura de la siguiente línea.  En
cualquier caso, la línea causa que Emacs determine la posición del punto
y asigne una marca allí.

   En las primeras versiones de GNU Emacs, la siguiente línea de
‘mark-whole-buffer’ fué ‘(push-mark (point-max))’.  Esta expresión
asigna una marca en el punto en el búffer que tiene el número más alto.
Esto será el fin del búffer (o, si el búffer es encogida, el fin de la
porción accesible del búffer.  *Note Encogiendo y extendiendo:
Encogiendo y extendiendo, para más acerca de encoger).  Después esta
marca ha sido asignada, la marca previa, uno asigna un punto, pero no se
asigna largo, pero Emacs recuerda su posición, solo como todas las otras
marcas recientes son siempre recordadas.  Esto significa que se puede,
si lo deseas, vuelve a esta posición escribiendo ‘C-u C-<SPC>’ dos
veces.

   En GNU Emacs 22, el ‘(point-max)’ es ligeramente más complicado.  La
línea lee

     (push-mark (point-max) nil t)

La expresión funciona cerca de lo mismo que antes.  Eso asigna una marca
en el lugar numerado más alto que se puede en el búffer.  Sin embargo,
en esta versión, ‘push-mark’ tiene dos argumentos adicionales.  El
segundo argumento para ‘push-mark’ es ‘nil’.  Esto cuenta la función que
_mostraría_ un mensaje que dice 'Marca asignada' cuando eso empuja la
marca.  El tercer argumento es ‘t’.  Esto cuenta ‘push-mark’ para
activar la marca cuando el modo Transient Mark está activado.  Transient
Mark mode ilumina la región de marca activa.  Con frecuencia desactivada

   Finalmente, la última línea de la función es ‘(goto-char
(point-min))’.  Esto es escrito exactamente el mismo camino camino como
está escrito ‘beginning-of-buffer’.  La expresión mueve el cursor al
mínimo punto en el búffer, que es, al principio del búfferr (o para el
principio de la porción accesible del búffer).  Como un resultado de
esto, punto está emplazado al principio del búffer y la marca está
asignada al fin del búffer.  El búffer completo es, más allá, la región.


File: emacs-lisp-intro-es.info,  Node: append-to-buffer,  Next: Revisa lo relacionado con el búffer,  Prev: mark-whole-buffer,  Up: Un paseo a través de los búffers

4.4 La definición de ‘append-to-buffer’
=======================================

El comando ‘append-to-buffer’ es más complejo que el comando
‘mark-whole-buffer’.  Lo que hace es copiar la región (que es, la parte
del búffer entre punto y marca) desde el buffer actual a un búffer
específico.

* Menu:

* resumen de append-to-buffer::  resumen de append-to-buffer
* append interactivo::       Una expresión interactiva de dos partes.
* cuerpo append-to-buffer::  Incorpora una expresión ‘let’.
* append save-excursion::    Cómo ‘save-excursion’ trabaja.


File: emacs-lisp-intro-es.info,  Node: resumen de append-to-buffer,  Next: append interactivo,  Up: append-to-buffer

Un resumen de ‘append-to-buffer’
--------------------------------

El comando ‘append-to-buffer’ usa la función ‘insert-buffer-substring’
para copiar la región.  ‘insert-buffer-substring’ es descrita por su
nombre: eso toma una cadena de caracteres desde parte de un búffer, una
"subcadena", y las inserta dentro de otro búffer.

   La mayoría de ‘append-to-buffer’ se refiere con la configuración de
las condiciones para ‘insert-buffer-substring’ para trabajar: el código
debe especificar ambos el búffer para el que el texto irá, la ventana
viene y va, y la región que será copiada.

   Aquí está el texto completo de la función:

     (defun append-to-buffer (buffer start end)
       "Introduce al búffer específico el texto de la
       región. Esto es insertado de este búffer antes de su punto.

     Cuando se llama desde un programa, se dan tres argumentos:
     BUFFER (o nombre del búffer), START y END.
     START y END especifica la porción del búffer actual para ser copiado."
       (interactive
        (list (read-buffer "Append to buffer: " (other-buffer
                                                 (current-buffer) t))
              (region-beginning) (region-end)))
       (let ((oldbuf (current-buffer)))
         (save-excursion
           (let* ((append-to (get-buffer-create buffer))
                  (windows (get-buffer-window-list append-to t t))
                  point)
             (set-buffer append-to)
             (setq point (point))
             (barf-if-buffer-read-only)
             (insert-buffer-substring oldbuf start end)
             (dolist (window windows)
               (when (= (window-point window) point)
                 (set-window-point window (point))))))))

   La función puede ser comprendida buscando como series de plantillas
rellenas

   La plantilla de fuera es para la definición de la función.  En esta
función, se ve como esto (con varios slots rellenos):

     (defun append-to-buffer (buffer start end)
       "DOCUMENTACION..."
       (interactive ...)
       CUERPO...)

   La primera línea de la función incluye su nombre y los tres
argumentos.  Los argumentos son el ‘búffer’ que el texto será copiado, y
el ‘start’ y ‘end’ de la región en el buffer actual que será copiado.

   La siguiente parte de la función es la documentación, que es claro y
completo.  Como es convencional, los tres argumentos son escritos en
mayúsculas así se notificarán fácilmente.  Incluso mejor, son descritas
en el mismo orden como en la lista de argumentos.

   Nótese que la documentación distingue entre un búffer y su nombre.
(La función puede manejar otro.)


File: emacs-lisp-intro-es.info,  Node: append interactivo,  Next: cuerpo append-to-buffer,  Prev: resumen de append-to-buffer,  Up: append-to-buffer

4.4.1 La expresión interactiva ‘append-to-buffer’
-------------------------------------------------

Desde que la función ‘append-to-buffer’ será usada interactivamente, la
función debe tener una expresión ‘interactive’.  (Para una revisión de
‘interactive’, ver *note Creando una Función Interactive: Interactive.)
La expresión se lee de la siguiente manera:

     (interactive
      (list (read-buffer
             "Agrega al buffer: "
             (other-buffer (current-buffer) t))
            (region-beginning)
            (region-end)))

Esta expresión no es una con letras separadas por partes, como se
describe antes.  En vez de eso, empieza una lista con estas partes:

   La primera parte de la lista es una expresión para leer el nombre de
un búffer y lo devuelve como una cadena.  Esto es ‘read-buffer’.  La
función requiere una consola como su primer argumento, ‘"Asocia al
buffer: "’.  Su segundo argumento cuenta el comando que valora para
proporciona si no especifica cualquier cosa.

   En este caso este segundo argumento es una expresión conteniendo la
función ‘other-buffer’, una excepción, y una ‘t’, para verdad.

   El primer argumento para ‘other-buffer’, la excepción, es todavía
otra función, ‘other-buffer’.  Esto es no yendo a ser devuelto.  El
segundo argumento es el símbolo para verdad, ‘t’.  Esto cuenta
‘other-buffer’ que puede mostrar búffers visibles (excepto en este caso,
eso no mostrará el búffer actual, que tiene sentido).

   La expresión se ve como:

     (other-buffer (current-buffer) t)

   El segundo y tercer argumento de la expresión ‘list’ son
‘(region-beginning)’ y ‘(region-end)’.  Estas dos funciones especifican
el principio el y el final del texto que se adjunta.

   Originalmente, el comando usaba las letras ‘B’ y ‘r’.  La expresión
completa ‘interactive’ es así:

     (interactive "BAsociar al buffer: \nr")

Pero cuando esto fué hecho, el valor por defecto del búffer cambió a ser
invisible.  Esto no se quería.

   (La consola estaba separada del segundo argumento con una nueva
línea, ‘\n’.  Estaba seguido por un ‘r’ que contaba a Emacs emparejar
los dos argumentos que siguen el símbolo ‘buffer’ en la lista de
argumentos de la función (que es, ‘start’ y ‘end’) para los valores de
punto y marca.  Este argumento trabajó bien.)


File: emacs-lisp-intro-es.info,  Node: cuerpo append-to-buffer,  Next: append save-excursion,  Prev: append interactivo,  Up: append-to-buffer

4.4.2 El cuerpo de ‘append-to-buffer’
-------------------------------------

El cuerpo de la función ‘append-to-buffer’ empieza con ‘let’.

   Como se ha visto antes (*note ‘let’: let.), el propósito de una
expresión ‘let’ es crear y dar valores iniciales a una o más variable
que solo serán usada con el cuerpo del ‘let’.  Esto significa que tal
variable no será confuso con cualquier variable del mismo nombre fuera
de la expresión ‘let’.

   Podemos ver como la expresión ‘let’ se ajusta dentro de la función
como un todo mostrando una plantilla para ‘append-to-buffer’ con la
expresión ‘let’ en línea:

     (defun append-to-buffer (buffer start end)
       "DOCUMENTACION..."
       (interactive ...)
       (let ((VARIABLE VALOR))
             CUERPO...)

   La expresión ‘let’ tiene tres elementos:

  1. El símbolo ‘let’;

  2. Una varlist conteniendo, en este caso, una lista simple de dos
     elementos, ‘(VARIABLE VALUE)’;

  3. El cuerpo de la expresión ‘let’.

   En la función ‘append-to-buffer’, la varlist se parece a esto:

     (oldbuf (current-buffer))

En esta parte de la expresión ‘let’, una variable, ‘oldbuf’ es
emparejada al valor devuelto por la expresión ‘(current-buffer)’.  La
variable, ‘oldbuf’, es usada para guardar la traza del búffer en el que
tu estás trabajando y desde el que se copiará.

   El elemento o elementos de una varlist son rodeados por un conjunto
de paréntesis así el intérprete Lisp puede distinguir la varlist desde
el cuerpo del ‘let’.  Como consecuencia, la lista de dos elementos con
la varlist está rodeados por un circunscrito conjunto de paréntesis.
Las líneas se ven así:

     (let ((oldbuf (current-buffer)))
       ... )

Los dos paréntesis antes de ‘oldbuf’ podrían sorprenderte si no fuera
porque los primeros paréntesis antes de ‘oldbuf’ marcan el límite de la
varlist y el segundo paréntesis marca el principio de la lista de dos
elementos, ‘(oldbuf (current-buffer))’.


File: emacs-lisp-intro-es.info,  Node: append save-excursion,  Prev: cuerpo append-to-buffer,  Up: append-to-buffer

4.4.3 ‘save-excursion’ en ‘append-to-buffer’
--------------------------------------------

El cuerpo de la expresión ‘let’ en ‘append-to-buffer’ consiste de una
expresión ‘save-excursion’.

   La función ‘save-excursion’ guarda las localizaciones de punto y la
marca, y las restaura a estas posiciones después de las expresiones en
el cuerpo de la ejecución completa ‘save-excursion’.  Además,
‘save-excursion’ completa la ejecución.  Además, ‘save-excursion’ guarda
la traza del búffer original, y lo restaura.  Esto es cómo
‘save-excursion’ que se usa en ‘append-to-buffer’.

   Incidentalmente, no se valora nada aquí que una función Lisp es
normalmente formateada así que cada cosa que es encerrada en conjunto
multilínea que es indentada más a la derecha que el primer símbolo.  En
esta definición de función, el ‘let’ es indentado más que ‘defun’, y el
‘save-excursion’ es indentado más que el ‘let’, como esto:

     (defun ...
       ...
       ...
       (let...
         (save-excursion
           ...

Esta convención formatea que sea fácil de ver que las líneas en el
cuerpo de ‘save-excursion’, solo como ‘save-excurion’ por sí mismo están
encerradas por los paréntesis asociados con el ‘let’:

     (let ((oldbuf (current-buffer)))
       (save-excursion
         ...
         (set-buffer ...)
         (insert-buffer-substring oldbuf start end)
         ...))

   El uso de la función ‘save-excursion’ puede ser vista como un proceso
de rellenar slots de una plantilla:

     (save-excursion
       PRIMERA-EXPRESION-EN-CUERPO
       SEGUNDA-EXPRESION-EN-CUERPO
        ...
       ULTIMA-EXPRESION-EN-CUERPO)

En esta función, el cuerpo de ‘save-excursion’ contiene solo una
expresión, la expresión ‘let*’.  Se conoce una función ‘let’.  La
función ‘let*’ es diferente.  Eso tiene un ‘*’ en su nombre.  Eso
permite a Emacs asignar cada variable de su varlist en secuencia, una
después de otra.

   Su funcionalidad crítica es que las variable después en la varlist
puedan hacer uso de los valores para los que Emacs asigna variables
pronto en la varlist.  *Note La expresión ‘let*’: fwd-para let.

   Se obviarán funciones como ‘let*’ y se focalizará en dos: la función
‘set-buffer’ y la función ‘insert-buffer-substring’.

   En antaño, la expresión ‘set-buffer’ era simple:

     (set-buffer (get-buffer-create buffer))

pero ahora eso es

     (set-buffer append-to)

‘append-to’ se asigna a ‘(get-buffer-create-buffer)’ pronto en la
expresión ‘let*’.  Esta asociación extra no sería necesaria excepto para
este ‘append-to’ es usado después en la varlist como un argumento para
‘get-buffer-window-list’.

   La definición de la función ‘append-to-buffer’ inserta texto desde el
búffer en el que estás actualmente a un buffer nombrado.  Eso sucede que
‘insert-buffer-substring’ copia texto desde otro búffer al búffer
actual, solo el inverso -- que es porque la definición
‘append-to-buffer’ empieza con un ‘let’ que asocia el símbolo local
‘oldbuf’ al valor devuelto por ‘current-buffer’.

   La expresión ‘insert-buffer-substring’ se ve como esto:

     (insert-buffer-substring oldbuf start end)

La función ‘insert-buffer-substring’ copia una cadena _from_ al búffer
especificado como su primer argumento e inserta la cadena dentro del
búffer presente.  En este caso, el argumento para
‘insert-buffer-substring’ es el valor de la variable creada y asociada
por el ‘let’, llama al valor de ‘oldbuf’, que fué el búffer actual
cuando tu diste el comando ‘append-to-buffer’.

   Después de que ‘insert-buffer-substring’ ha hecho su trabajo,
‘save-excursion’ restaurará la acción al búffer original y
‘append-to-buffer’ habrá hecho su trabajo.

   Escrito en forma esquelética, los trabajos del cuerpo se ven como
esto:

     (let (BIND-oldbuf-TO-VALUE-OF-current-buffer)
       (save-excursion                       ; Guarda la traza del búffer.
         CHANGE-BUFFER
         INSERT-SUBSTRING-FROM-oldbuf-INTO-BUFFER)

       CHANGE-BACK-TO-ORIGINAL-BUFFER-WHEN-FINISHED
     LET-THE-LOCAL-MEANING-OF-oldbuf-DISAPPEAR-WHEN-FINISHED

   En resumen, ‘append-to-buffer’ funciona como sigue: se guarda el
valor del búffer actual en la variable llamada ‘oldbuf’.  Se obtiene el
nuevo búffer (creando uno si necesita ser) y cambia la atención de Emacs
a eso.  Usando el valor de ‘oldbuf’, inserta la región del texto desde
el viejo búffer dentro del nuevo búffer; y entonces usando
‘save-excursion’, trae atrás a tu búffer original.

   Buscando ‘append-to-buffer’, se ha explorado una función limpia
compleja.  Eso muestra como usar ‘let’ y ‘save-excursion’, y como
cambiar y volver desde otro buffer.  Muchas definiciones de función usan
‘let’, ‘save-excursion’, y ‘set-buffer’ de este modo.


File: emacs-lisp-intro-es.info,  Node: Revisa lo relacionado con el búffer,  Next: Ejercicios de búffer,  Prev: append-to-buffer,  Up: Un paseo a través de los búffers

4.5 Revisar
===========

Aquí está un breve resumen de varias funciones discutidas en este
capítulo.

‘describe-function’
‘describe-variable’
     Imprime la documentación para una función o variable.
     Convencionalmente asociada a ‘C-h f’ y ‘C-h v’.

‘find-tag’
     Encuentra el fichero que contiene la fuente para una función o
     variable y cambia buffer a él, posicionando el punto al principio
     del ítem.  Convencionalmente emparejado a ‘M-.’ (esto es un período
     seguiendo la tecla <META>).

‘save-excursion’
     Guarda la localización de punto y marca y restaura sus valores
     después de los argumentos para ‘save-excursion’ y han sido
     evaluados.  También, recuerda el buffer actual y devuélvelo.

‘push-mark’
     Asigna la marca en una localización y graba el valor de la marca
     previa en el anillo de la marca.  La marca es una localización en
     el búffer que guarda su posición relativa incluso si el texto es
     añadido o borrado desde el búffer.

‘goto-char’
     Asigna punto a la localización especificada por el valor del
     argumento, que puede ser un número, una marca, o una expresión que
     devuelve el número de una posición, tal como ‘(point-min)’.

‘insert-buffer-substring’
     Copia una región de texto desde un búffer que es pasado a la
     función como un argumento e inserta la región dentro del búffer
     actual.

‘mark-whole-buffer’
     Marca el búffer completo como una región.  Normalmente asignado a
     ‘C-x h’.

‘set-buffer’
     Cambia la atención de Emacs a otro búffer, pero no cambies la
     ventana siendo mostrada.  Usado cuando el programa en vez de un
     humano trabaja en un búffer diferente.

‘get-buffer-create’
‘get-buffer’
     Encuentra un búffer nombrado o crea uno si un búffer de este nombre
     no existe.  La función ‘get-buffer’ devuelve ‘nil’ si el nombre del
     búffer no existe.


File: emacs-lisp-intro-es.info,  Node: Ejercicios de búffer,  Prev: Revisa lo relacionado con el búffer,  Up: Un paseo a través de los búffers

4.6 Ejercicios
==============

   • Escribe tu propia definición de función ‘simplified-end-of-buffer’;
     entonces testea para ver si funciona.

   • Usa ‘if’ y ‘get-buffer’ para escribir una función que imprime un
     mensaje contando si un buffer existe.

   • Usando ‘find-tag’, encuentra la fuente para la función
     ‘copy-to-buffer’


File: emacs-lisp-intro-es.info,  Node: Más complejidad,  Next: Encogiendo y extendiendo,  Prev: Un paseo a través de los búffers,  Up: Top

5 Unas pocas funciones más complejas
************************************

En este capítulo, se construye lo que se aprendió en los capítulos
previos mirando en funciones más complejas.  La función ‘copy-to-buffer’
ilustra el uso de expresiones ‘save-excursion’ en una definición,
mientras la función ‘insert-buffer’ ilustra el uso de un asterisco en
una expresión ‘interactive’, uso de ‘o’, y la importante distinción
entre un nombre y el objeto para el que el nombre se refiere.

* Menu:

* copy-to-buffer::           Con ‘set-buffer’,
                               ‘get-buffer-create’.
* insert-buffer::            Solo lectura, y con ‘or’.
* beginning-of-buffer::      Muestra ‘goto-char’, ‘point-min’, y
                               ‘push-mark’.
* Revisar el segundo búffer relacionado::  Revisar el segundo búffer
                                               relacionado
* Ejercicio opcional::       Ejercicio opcional


File: emacs-lisp-intro-es.info,  Node: copy-to-buffer,  Next: insert-buffer,  Up: Más complejidad

5.1 La definición de ‘copy-to-buffer’
=====================================

Después de comprender cómo se trabaja ‘append-to-buffer’, es fácil para
comprender ‘copy-to-buffer’.  Esta función copia texto dentro de un
búffer, pero en vez de añadir al segundo búffer, se reemplaza a todo el
texto previo en el segundo búffer.

   El cuerpo de ‘copy-to-buffer’ se ve como esto,

     ...
     (interactive "BCopy to buffer: \nr")
     (let ((oldbuf (current-buffer)))
       (with-current-buffer (get-buffer-create buffer)
         (barf-if-buffer-read-only)
         (erase-buffer)
         (save-excursion
           (insert-buffer-substring oldbuf start end)))))

   La función ‘copy-to-buffer’ tiene una expresión simple ‘interactive’
en vez de ‘append-to-buffer’.

   La definición entonces dice:

     (with-current-buffer (get-buffer-create buffer) ...

   Primero, mira en la expresión interna más temprana; que es evaluada
primero.  Esta expresión empieza con ‘get-buffer-create buffer’.  La
función cuenta al ordenador para usar el búffer con el nombre
específicado como uno para el que estás copiando, o si tal búffer no
existe, créalo.  Entonces, la función ‘with-current-buffer’ evalúa su
cuerpo con este búffer temporalmente al actual.

   (Esto demuestra otro camino para cambiar la atención del ordenador
pero no los usuarios.  La función ‘append-to-buffer’ muestra como hacer
lo mismo con ‘save-excursion’ y ‘set-buffer’.  ‘with-current-buffer’ es
uno nuevo, y argumentablemente fácil, mecanismo.)

   La función ‘barf-if-buffer-read-only’ envía un mensaje de error
diciendo al búffer es de solo lectura si no se puede modificar.

   La siguiente línea tiene la función ‘erase-buffer’ como sus únicos
contenidos.  Este función borra el búffer.

   Finalmente, las últimas dos líneas contienen la expresión
‘save-excursion’ con ‘insert-buffer-substring’ como su cuerpo.  La
expresión ‘insert-buffer-substring’ copia el texto desde el búffer en el
que se está (y no se ha visto el ordenador puesta su atención, así no se
sabe que este búffer es ahora llamado ‘oldbuf’).

   De manera incidental, esto es lo que significa por 'reemplazo'.  Para
reemplazar texto Emacs se borra el texto previo y entonces se inserta el
nuevo texto.

   El código fuente, del cuerpo de ‘copy-to-buffer’ se parece a esto:

     (let (BIND-oldbuf-TO-VALUE-OF-current-buffer)
         (WITH-THE-BUFFER-YOU-ARE-COPYING-TO
           (BUT-DO-NOT-ERASE-OR-COPY-TO-A-READ-ONLY-BUFFER)
           (erase-buffer)
           (save-excursion
             INSERT-SUBSTRING-FROM-oldbuf-INTO-BUFFER)))


File: emacs-lisp-intro-es.info,  Node: insert-buffer,  Next: beginning-of-buffer,  Prev: copy-to-buffer,  Up: Más complejidad

5.2 La definición de ‘insert-buffer’
====================================

‘insert-buffer’ es todavía una función relacionada con el búffer.  Este
comando copia otro búffer _dentro_ del búffer actual.  Es lo inverso de
‘append-to-buffer’ o ‘copy-to-buffer’, desde que se copia una región de
texto _desde_ el búffer actual a otro búffer.

   Aquí hay una discusión basada en el código original.  El código era
simplificado en 2003 y es duro de comprender.

   (*Note Nuevo Cuerpo para ‘insert-buffer’: Nuevo insert-buffer, para
ver una discusión del nuevo cuerpo.)

   Además, este código ilustra el uso de ‘interactive’ con un búffer que
podría ser “read-only” y la distinción entre el nombre de un objeto y el
objeto actualmente referido.

* Menu:

* código insert-buffer::   código insert-buffer
* insert-buffer interactivo::  Cuando tu puedes leer, pero no escribir.
* cuerpo insert-buffer::     El cuerpo tiene un ‘or’ y un ‘let’.
* si y o::                   Usando un ‘if’ en vez de un ‘or’.
* Insertar o::               Cómo la expresión ‘or’ funciona.
* Insertar let::             Dos expresiones ‘save-excursion’.
* Nuevo insert-buffer::      Nuevo insert-buffer


File: emacs-lisp-intro-es.info,  Node: código insert-buffer,  Next: insert-buffer interactivo,  Up: insert-buffer

El código para ‘insert-buffer’
------------------------------

Aquí está el primer código

     (defun insert-buffer (buffer)
       "Inserta después del punto los contenidos del BUFFER.
     Pon la marca después del texto insertado.
     El BUFFER puede ser un buffer un nombre de buffer."
       (interactive "*bInsert buffer: ")
       (or (bufferp buffer)
           (setq buffer (get-buffer buffer)))
       (let (start end newmark)
         (save-excursion
           (save-excursion
             (set-buffer buffer)
             (setq start (point-min) end (point-max)))
           (insert-buffer-substring buffer start end)
           (setq newmark (point)))
         (push-mark newmark)))

   Como con otras definiciones de función, se puede usar una plantilla
para visión de la función:

     (defun insert-buffer (buffer)
       "DOCUMENTATION..."
       (interactive "*bInsert buffer: ")
       BODY...)


File: emacs-lisp-intro-es.info,  Node: insert-buffer interactivo,  Next: cuerpo insert-buffer,  Prev: código insert-buffer,  Up: insert-buffer

5.2.1 La expresión interactiva en ‘insert-buffer’
-------------------------------------------------

En ‘insert-buffer’, el argumetno para la declaración ‘interactive’ tiene
dos partes, un asterisco, ‘*’, y ‘bInserta un buffer: ’.

* Menu:

* Búffer solo lectura::    Cuando un buffer no puede ser modificado.
* b para interactivo::       Un buffer existe o además su nombre.


File: emacs-lisp-intro-es.info,  Node: Búffer solo lectura,  Next: b para interactivo,  Up: insert-buffer interactivo

Un búffer de solo lectura
.........................

El asterisco se utliza en la situación cuando el búffer actual es un
búffer de solo lectura -- un búffer que no puede ser modificado.  Si
‘insert-buffer’ es llamado cuando el búffer actual es de solo lectura,
un mensaje a este efecto está impreso en el área echo y el terminal
puede avisar; no se permite insertar cualquier cosa dentro del búffer.
El asterisco no necesita ser seguido por una nueva línea para separarse
desde el siguiente argumento.


File: emacs-lisp-intro-es.info,  Node: b para interactivo,  Prev: Búffer solo lectura,  Up: insert-buffer interactivo

‘b’ en una expresión interactiva
................................

El siguiente argumento en la expresión interactiva empieza con una tecla
minúscula ‘b’.  (Esto es diferente desde el código para
‘append-to-buffer’, que usa una mayúscula ‘B’.  *Note La Definición de
‘append-to-buffer’: append-to-buffer.)  La tecla minúscula cuenta al
intérprete Lisp que el argumento para ‘insert-buffer’ sería un buffer
existente o sino su nombre.  (La mayúscula ‘B’ provee para la
posibilidad que el búffer no existe.)  Emacs te mostrará en pantalla el
nombre del búffer, ofreciendo un búffer por defecto, con la compleción
de nombre habilitado.  Si el búffer no existe, se recibe un mensaje que
dice "No concuerda"; tu terminal te avisa también.

   El nuevo y simplificado código genera una lista ‘interactive’.  Eso
usa las funciones ‘barf-if-buffer-read-only’ y ‘read-buffer’ con las que
estamos ya familiarizados y la forma especial ‘progn’ con los que no.
(Eso será descrito después).


File: emacs-lisp-intro-es.info,  Node: cuerpo insert-buffer,  Next: si y o,  Prev: insert-buffer interactivo,  Up: insert-buffer

5.2.2 El cuerpo de la función ‘insert-buffer’
---------------------------------------------

El cuerpo de la función ‘insert-buffer’ tiene dos partes principales:
una expresión ‘or’ y una expresión ‘let’.  El propósito de la expresión
‘or’ es asegurar que el argumento ‘buffer’ es emparejado a un búffer y
no solo el nombre de un búffer.  El cuerpo de la expresión ‘let’
contiene el código que copia los otros búffers dentro del búffer.

   En el "outline" (esquema), las dos expresiones se ajustan dentro de
la función ‘insert-buffer’ como esto:

     (defun insert-buffer (buffer)
       "DOCUMENTATION..."
       (interactive "*bInsertar buffer: ")
       (or ...
           ...
       (let (VARLIST)
           BODY-OF-let... )

   Para comprender como la expresión ‘or’ asegura que el argumento
‘buffer’ es emparejado a un buffer y no al nombre de un búffer, es
primero necesario comprender la función ‘or’.

   Antes de hacer esto, permíteme reescribir esta parte de la función
usando ‘if’ así puedes ver que es hecho en una manera que será familiar.


File: emacs-lisp-intro-es.info,  Node: si y o,  Next: Insertar o,  Prev: cuerpo insert-buffer,  Up: insert-buffer

5.2.3 ‘insert-buffer’ con un ‘if’ en vez de un ‘or’
---------------------------------------------------

El trabajo que debe ser hecho y asegura el valor de ‘buffer’ es un
búffer en sí mismo y no el nombre de un búffer.  Si el valor es el
nombre, entonces el búffer en sí debe ser obtenido.

   Te puedes imaginar a tí mismo en una conferencia donde un acomodador
está observando una lista con tu nombre dentro y mirándote: el
acomodador sabe "asociar" tu nombre, pero no a tí; pero cuando el
acomodador te encuentra y te toma el brazo, el acomodador llega a
"asociarte" a tí.

   En Lisp, se podría describir esta situación así:

     (if (not (holding-on-to-guest))
         (find-and-take-arm-of-guest))

   Se quiere hacer la misma cosa con un búffer -- si no tenemos el
búffer en sí, queremos tenerlo.

   Usando un predicado llamado ‘bufferp’ que nos cuenta si tenemos un
búffer (en vez de su nombre), se puede escribir el código como este:

     (if (not (bufferp buffer))              ; if-part
         (setq buffer (get-buffer buffer)))  ; then-part

Aquí, el true-or-false-test de la expresión ‘if’ es
‘(not (bufferp buffer))’; y la then-part es la expresión
‘(setq buffer (get-buffer buffer))’.

   En el test, la función ‘bufferp’ devuelve cierto si su argumento es
un búffer -- pero falso si su argumento es el nombre del búffer.  (El
último carácter del nombre de la función ‘bufferp’ es el carácter ‘p’;
como se vió antes, tal uso de ‘p’ es una convención que indica que la
función es un predicado, que es un término que significa que la función
determinará si alguna propiedad es verdadera o falsa.  *Note Usando el
objeto de tipo incorrecto como un argumento: Tipo incorrecto de
argumento.)

   La función ‘not’ precede la expresión ‘(bufferp buffer)’, así el
true-or-false-test se ve como esto:

     (not (bufferp buffer))

‘no’ es una función que devuelve cierto si su argumento es falso y falso
si su argumento es verdadero.  Así si ‘(bufferp buffer)’ devuelve
cierto, la expresión ‘no’ devuelve falso y vice-versa: que es "no
cierto" es falso que es "no falso" es verdadero.

   Usando este test, la expresión ‘if’ trabaja como sigue: cuando el
valor de la variable ‘buffer’ está actualmente en un búffer en vez de su
nombre, el test true-or-false-test devuelve false y la expresión ‘if’ no
evalúa la parte then-part.  Esto está bien, desde que no necesita para
hacer cualquier cosa para la variable ‘buffer’ si es realmente un
búffer.

   Por otro lado, cuando el valor de ‘buffer’ no es un buffer en sí,
pero el nombre de un buffer, el true-or-false-test devuelve cierto y la
then-part de la expresión es evaluada.  En este caso, la then-part es
‘(setq buffer (get-buffer buffer))’.  Esta expresión usa la función
‘get-buffer’ para devolver un buffer actual en sí, dado su nombre.  El
‘setq’ entonces asigna la variable ‘buffer’ al valor del buffer en sí,
reemplazando su valor previo (que era el nombre del buffer).


File: emacs-lisp-intro-es.info,  Node: Insertar o,  Next: Insertar let,  Prev: si y o,  Up: insert-buffer

5.2.4 El ‘or’ en el cuerpo
--------------------------

El propósito de la expresión ‘or’ en la función ‘insert-buffer’ es
asegurar que el argumento ‘buffer’ está asociado a un búffer y no solo
al nombre de un búffer.  La sección previa muestra como el trabajo
podría haber sido hecho usando una expresión ‘if’.  Sin embargo, la
función ‘insert-buffer’ actualmente usa ‘or’.  Para comprender esto, es
necesario comprender como ‘or’ trabaja.

   Una función ‘or’ puede tener cualquier número de argumentos.  Eso
evalúa cada argumento en turno y devuelve el valor del primero de sus
argumentos que no es ‘nil’.  También, y esto es una funcionalidad
crucial de ‘or’, eso no evalúa cualquier argumentos subsiguientes
después devolviendo el primer valor no-‘nil’.

   La expresión ‘or’ se ve como esto:

     (or (bufferp buffer)
         (setq buffer (get-buffer buffer)))

El primer argumento a ‘or’ es la expresión ‘(bufferp buffer)’.  Esta
expresión devuelve cierto (un valor no-‘nil’) si el búffer es
actualmente un búffer, y no solo el nombre de un búffer.  En la
expresión ‘or’, si este es el caso, la expresión ‘or’ devuelve esto el
valor cierto y no evalúa la siguiente expresión -- y esto es bueno para
nosotros, desde que nosotros no queremos hacer cualquier cosa al valor
de ‘buffer’ si eso es realmente un búffer.

   Por otro lado, si el valor de ‘(bufferp buffer)’ es ‘nil’, que será
si el valor de ‘buffer’ es el nombre de un buffer, el intérprete Lisp
evalúa el siguiente elemento de la expresión.  Esta es la expresión
‘(setq buffer (get-buffer buffer))’.  Esta expresión devuelve un valor
no-‘nil’, que es el valor para el que asigna la variable ‘buffer’ -- y
este valor es un búffer en sí, no el nombre de un búffer.

   El resultado de todo esto es que el símbolo ‘buffer’ es siempre
asociado a un búffer en sí en vez del nombre de un búffer.  Toda es
necesario porque la función ‘set-buffer’ en una línea siguiente trabaja
con un buffer en sí, no con el nombre de un búffer.

   Incidentalmente, usando ‘or’, la situación con el acomodador se vería
así:

     (or (holding-on-to-guest) (find-and-take-arm-of-guest))


File: emacs-lisp-intro-es.info,  Node: Insertar let,  Next: Nuevo insert-buffer,  Prev: Insertar o,  Up: insert-buffer

5.2.5 La expresión ‘let’ en ‘insert-buffer’
-------------------------------------------

Después asegurando que la variable ‘buffer’ se refiere a un buffer en sí
y no solo al nombre de un buffer, la función ‘insert-buffer’ continúa
con una expresión ‘let’.  Esto especifica tres variables locales,
‘start’, ‘end’ y ‘newmark’ y los asocia al valor inicial ‘nil’.  Estas
variables son usadas dentro del resto de ‘let’ y temporalmente se oculta
con cualquier otra ocurrencia de variables del mismo nombre en Emacs
hasta el fin del ‘let’.

   El cuerpo del ‘let’ contiene dos expresiones ‘save-excursion’.
Primero, miraremos la expresión ‘save-excursion’ en detalle.  La
expresión se parece a esto:

     (save-excursion
       (set-buffer buffer)
       (setq start (point-min) end (point-max)))

La expresión ‘(set-buffer buffer)’ cambia la atención de Emacs desde el
búffer actual a uno desde el que el texto será copiado.  En este búffer
las variables ‘start’ y ‘end’ se asignadan al principio y al fin del
búffer, usando los comandos ‘point-min’ y ‘point-max’.  Note que tenemos
aquí una ilustración de cómo ‘setq’ es capaz de asignar dos variables en
la misma expresión.  El primer argumento de ‘setq’ es asignar al valor
del segundo, y su tercer argumento está asignado al valor del cuarto.

   Después el cuerpo del ‘save-excursion’ propio es evaluado, el
‘save-excursion’ restaura el búffer original, pero ‘start’ y ‘end’
permanece asignado a los valores del principio y fin del búffer en el
que el texto será copiado.

   La expresión por fuera ‘save-excursion’ se ve como:

     (save-excursion
       (INNER-save-excursion-EXPRESSION
          (GO-TO-NEW-BUFFER-AND-SET-start-AND-end)
       (insert-buffer-substring buffer start end)
       (setq newmark (point)))

La función ‘insert-buffer-substring’ copia el texto _dento_ del búffer
_desde_ la región indicada por ‘start’ y ‘end’ en el ‘búffer’.  Desde el
total del segundo búffer cae entre ‘start’ y ‘end’, el todo del segundo
búffer es copiado dentro del búffer que estás editando.  Lo siguiente,
el valor del punto, que será al fin del texto insertado, es grabado en
la variable ‘newmark’.

   Después el cuerpo de ‘save-excursion’ es evaluado, punto y marca son
recolocados a sus lugares originales.

   Sin embargo, es conveniente localizar una marca al fin del texto
nuevamente insertado y localizar el punto al principio.  La variable
‘newmark’ graba el fin del texto insertado.  En la última línea de la
expresión ‘let’, la expresión de la función ‘(push-mark newmark)’ asigna
una marca a esta posición.  (La posición previa de la marca está todavía
accesible; está grabado en la marca del anillo y se puede regresar a eso
con ‘C-u C-<SPC>’.)  Mientras tanto, el punto está localizado al
principio del texto insertado, que está donde estaba antes de ser
llamado la función que inserta, la posición de lo que estaba guardado
por la primera ‘save-excursion’.

   La expresión ‘let’ se parece a esto:

     (let (start end newmark)
       (save-excursion
         (save-excursion
           (set-buffer buffer)
           (setq start (point-min) end (point-max)))
         (insert-buffer-substring buffer start end)
         (setq newmark (point)))
       (push-mark newmark))

   Como la función ‘append-to-buffer’, la función ‘insert-buffer’ usa
‘let’, ‘save-excursion’ y ‘set-buffer’.  Además, la función ilustra un
camino para usar ‘o’.  Toda estas funciones están construyendo el bloque
que se encontrarán y usarán una y otra vez.


File: emacs-lisp-intro-es.info,  Node: Nuevo insert-buffer,  Prev: Insertar let,  Up: insert-buffer

5.2.6 Nuevo cuerpo para ‘insert-buffer’
---------------------------------------

El cuerpo en la versión de GNU Emacs 22 es más confuso que en el
original.

   Consiste de dos expresiones

       (push-mark
        (save-excursion
          (insert-buffer-substring (get-buffer buffer))
          (point)))

        nil

excepto, y esto es lo que los novicios confunden, un trabajo muy
importante es hecho dentro de la expresión ‘push-mark’.

   La función ‘get-buffer’ devuelve un búffer con el nombre
proporcionado.  Se tomará nota de que la función _no_ se llama
‘get-buffer-create’; eso no crea un búffer si uno no existe ya.  El
búffer devuelto por ‘get-buffer’, un búffer existente, es pasado a
‘insert-buffer-substring’, que inserta el total del búffer (desde que no
se especificón ninguna cosa más).

   La posición dentro del buffer es insertado es grabado por
‘push-mark’.  Entonces la función devuelve ‘nil’, el valor de su último
comando.  Pon otro camino, la función ‘insert-buffer’ existe solo para
producir un efecto lateral, insertando otro buffer, no para devolver
cualquier valor.


File: emacs-lisp-intro-es.info,  Node: beginning-of-buffer,  Next: Revisar el segundo búffer relacionado,  Prev: insert-buffer,  Up: Más complejidad

5.3 Definición completa de ‘beginning-of-buffer’
================================================

La estructura básica de la función ‘beginning-of-buffer’ ya ha sido
discutida.  (*Note Una Definición Simplificada ‘beginning-of-buffer’:
simplified-beginning-of-buffer.).  Esta sección describe la parte
compleja de la definición.

   Como se describe previamente, cuando se invoca sin un argumento,
‘beginning-of-buffer’ mueve el cursor al principio del búffer (en
realidad, al principio de la porción accesible del búffer), dejando la
marca en la posición previa.  Sin embargo, cuando el comando es invocado
con un número entre uno y diez, la función considera que número será una
fracción del tamaño del búffer, medido en decenas, y Emacs mueve el
cursor en esta fracción del camino desde el principio del búffer.  De
este modo, se puede o bien llamar a esta función con la tecla comando
‘M-<’, que moverá el cursor al principio del búffer, o con una tecla tal
como ‘C-u 7 M-<’ que moverá el cursor a un punto 70% del camino a través
del búffer.  Si un número más grande de diez es usado para el argumento
que se mueve al final del búffer.

   La función ‘beginning-of-buffer’ puede ser llamada con o sin
argumentos.  El uso del argumento es opcional.

* Menu:

* Argumentos opcionales::    Argumentos opcionales
* beginning-of-buffer opt arg::  Ejemplo con argumento opcional.
* Completo beginning-of-buffer::  Completo beginning-of-buffer


File: emacs-lisp-intro-es.info,  Node: Argumentos opcionales,  Next: beginning-of-buffer opt arg,  Up: beginning-of-buffer

5.3.1 Argumentos opcionales
---------------------------

A menos que se cuente de otro modo, Lisp espera que una función con un
argumento en su definición de función se llame con un valor para este
argumento.  Si esto no ocurre, se obtiene un error y un mensaje que dice
‘Número de argumentos erróneo’.

   Sin embargo, los argumentos opcionales son una funcionalidad de Lisp:
una “palabra clave” particular es usada para contar al intérprete Lisp
que un argumento es opcional.  La palabra clave es ‘&optional’.  (El ‘&’
en frente de ‘opcional’ es parte de la palabra clave.)  En una
definición de función, si un argumento sigue a la palabra clave
‘&optional’, ningún valor necesita ser pasado a este argumento cuando la
función se llama.

   La primera línea de la definición de función de ‘beginning-of-buffer’
tiene lo siguiente:

     (defun beginning-of-buffer (&optional arg)

   En el "outline" (esquema), la función completa se parece a esto:

     (defun beginning-of-buffer (&optional arg)
       "DOCUMENTATION..."
       (interactive "P")
       (or (IS-THE-ARGUMENT-A-CONS-CELL arg)
           (and ARE-BOTH-TRANSIENT-MARK-MODE-AND-MARK-ACTIVE-TRUE)
           (push-mark))
       (let (DETERMINE-SIZE-AND-SET-IT)
       (goto-char
         (IF-THERE-IS-AN-ARGUMENT
             FIGURE-OUT-WHERE-TO-GO
           ELSE-GO-TO
           (point-min))))
        DO-NICETY

   La función es similar a la función ‘simplified-beginning-of-buffer’
excepto que la expresión ‘interactive’ tiene ‘"P"’ como un argumento y
la función ‘goto-char’ es seguida por una expresión if-then-else que
figura donde poner el cursor si hay un argumento que no es un cons cell.

   (Puesto que no se explica un cons cell en muchos capítulos, por
favor, considere ignorar la función ‘consp’.  *note Cómo las Listas son
Implementadas: Implementación de listas, y *note Cons Cell y Tipos de
Listas: (elisp)Tipo de Cons Cell.).

   El ‘"P"’ en la expresión ‘interactive’ cuenta a Emacs cómo pasar un
argumento prefijo, si hay uno, a la función en forma plana.  Un
argumento prefijo se crea escribiendo la tecla <META> seguida por un
número, o escribiendo ‘C-u’ y entonces un número.  (Si no escribes un
número, ‘C-u’ por defecto a un cons cell con un 4.  Una minúscula ‘"p"’
en la expresión ‘interactive’ causa a la función convertir un argumento
prefijo a un número.)

   El true-or-false-test de la expresión ‘if’ se ve compleja, pero no lo
es: se chequea si ‘arg’ tiene un valor que no es ‘nil’ y si es un cons
cell.  (Esto es lo que ‘consp’ hace; chequea si su argumento es un cons
cell.)  Si ‘arg’ tiene un valor que no es ‘nil’ (y no es un cons cell.),
que será el caso si ‘beginning-of-buffer’ se llama con un argumento,
entonces este true-or-false-test devolverá cierto y la then-part de la
expresión ‘if’ falsa.  Por otro lado, si ‘beginning-of-bufer’ no se
llama con un argumento, el valor de ‘arg’ será ‘nil’ y la else-part de
la expresión ‘if’ se evaluará.  La else-part es simple ‘point-min’, y
esto es lo de fuera, la expresión ‘goto-char’ es ‘(goto-char
(point-min))’, que es cómo se vió la función ‘beginning-of-buffer’ en su
forma simplificada.


File: emacs-lisp-intro-es.info,  Node: beginning-of-buffer opt arg,  Next: Completo beginning-of-buffer,  Prev: Argumentos opcionales,  Up: beginning-of-buffer

5.3.2 ‘beginning-of-buffer’ con un argumento
--------------------------------------------

Cuando ‘beginning-of-buffer’ se llama con un argumento, una expresión es
evaluada que calcula que valor pasa a ‘goto-char’.  Esto es incluso
complicado a primera vista.  Eso incluye una expresión ‘if’ propia y
mucha aritmética.  Se ve así:

     (if (> (buffer-size) 10000)
         ;; ¡Evitar sobrecarga para grandes tamaños de búffer!
                               (* (prefix-numeric-value arg)
                                  (/ size 10))
       (/
        (+ 10
           (*
            size (prefix-numeric-value arg))) 10)))

* Menu:

* Desenmarañar beginning-of-buffer::  Desenmarañar beginning-of-buffer
* El caso del buffer largo::  El caso del buffer largo
* Pequeño caso de búffer::  Pequeño caso de búffer


File: emacs-lisp-intro-es.info,  Node: Desenmarañar beginning-of-buffer,  Next: El caso del buffer largo,  Up: beginning-of-buffer opt arg

Desenmarañar ‘beginning-of-buffer’
..................................

Como otras expresiones que se ven complejas, la expresión condicional
con ‘beginning-of-buffer’ puede ser desenredada mirándola por partes de
una plantilla, en este caso, la plantilla par una expresión
if-then-else.  En forma esquelética, la expresión se ve así:

     (if (BUFFER-IS-LARGE
         DIVIDE-BUFFER-SIZE-BY-10-AND-MULTIPLY-BY-ARG
       ELSE-USE-ALTERNATE-CALCULATION

   El true-or-fase-test de esta expresión ‘if’ propia chequea el tamaño
del buffer.  La razón para esto es que la versión vieja de Emacs 18
usaba números que no son más grandes que 8 millones o así y en la
computación que seguía, el programador temía que Emacs podría intentar
usar a través de largos números si el búffer fuera largo.  El término
'sobrecarga', que se mencionó en el comentario, significa que los
números son grandes.  Las versiones más recientes de Emacs usan números
largos, pero este código no ha sido tocado, solo porque la gente ahora
mira en búffers que están lejos, tan lejos como antes.

   Hay dos casos: si el búffer es largo, o si no.


File: emacs-lisp-intro-es.info,  Node: El caso del buffer largo,  Next: Pequeño caso de búffer,  Prev: Desenmarañar beginning-of-buffer,  Up: beginning-of-buffer opt arg

Qué ocurre en un búffer largo
.............................

En ‘beginning-of-buffer’, la expresión propia ‘if’ chequea si el tamaño
del búffer es mayor que 10000 caracteres.  Para hacer esto, se usa la
función ‘>’ y la computación de ‘size’ que viene desde la expresión let.

   Hace tiempo, se usaba la función ‘buffer-size’.  No solo esta función
era llamada varias veces, eso daba el tamaño del búffer completo, no la
parte accesible.  La computación tiene mucho más sentido cuando se
maneja solo la parte accesible.  (*Note Encogiendo y extendiendo:
Encogiendo y extendiendo, para más información en focalizar la atención
para una parte 'accesible'.)

   La línea se parece a esto:

     (if (> size 10000)

Cuando el búffer es largo, el then-part de la expresión ‘if’ se evalúa.
Eso se lee así (después de ser formateado para una fácil lectura):

     (*
       (prefix-numeric-value arg)
       (/ size 10))

Esta expresión es una multiplicación, con dos argumentos para la función
‘*’.

   El primer argumento es ‘(prefix-numeric-value arg)’.  Cuando ‘"P"’ se
usa como argumento para ‘interactive’, el valor pasado para la función
como argumento es un "argumento prefijo crudo", y no un número.  (Es un
número en una lista).  Para desarrollar la aritmética, una conversión es
necesaria, y ‘prefix-numeric-value’ hace el trabajo.

   El segundo argumento es ‘(/ size 10)’.  Esta expresión divide el
valor numérico por diez -- el valor numérico del tamaño de la porción
accesible del búffer.  Esto produce un número que cuenta cuántos
caracteres crean una decena del tamaño del búffer.  (En Lisp, ‘/’ es
usado para división, solo como ‘*’ es usado para multiplicación.)

   En la expresión de la multiplicación como un todo, esta cantidad se
multiplica por el valor del argumento prefijo -- la multiplicación se
parece a:

     (* NUMERIC-VALUE-OF-PREFIX-ARG
        NUMBER-OF-CHARACTERS-IN-ONE-TENTH-OF-THE-ACCESSIBLE-BUFFER)

Si, por ejemplo, el argumento prefijo es ‘7’, el valor one-tenth será
multiplicado por 7 para dar una posición del 70% del camino.

   El resultado de todo esto es que si la porción accesible del búffer
es largo, la expresión ‘goto-char’ se lee esto:

     (goto-char (* (prefix-numeric-value arg)
                   (/ size 10)))

   Esto pone el cursor donde se quiere.


File: emacs-lisp-intro-es.info,  Node: Pequeño caso de búffer,  Prev: El caso del buffer largo,  Up: beginning-of-buffer opt arg

Qué ocurre en un búffer pequeño
...............................

Si el búffer contiene poco más de 10000 caracteres, una computación
ligeramente diferente es medida.  Se podría pensar que esto no es
necesario, desde que la primera computación podría hacer el trabajo.
Sin embargo, en un búffer pequeño, el primer método puede no poner el
cursor en la línea exactamente deseada; el segundo método hace un
trabajo mejor.

   El código se parece a esto:

     (/ (+ 10 (* size (prefix-numeric-value arg))) 10))

Este es el código en el que se ve qué ocurre descubriendo como las
funciones se embeben entre paréntesis.  Eso es fácil de leer si se
reformatea con cada expresión indentada más profundamente que la
expresión que encierra:

       (/
        (+ 10
           (*
            size
            (prefix-numeric-value arg)))
        10))

Mirando los paréntesis, se ve que la operación propia es
‘(prefix-numeric-value arg)’, que convierte el argumento plano para un
número.  En la siguiente expresión, este número es multiplicado por el
tamaño de la porción accesible del búffer:

     (* size (prefix-numeric-value arg))

Esta multiplicación crea un número que puede ser más largo que el tamaño
del buffer -- siete veces más larga si el argumento es 7, por ejemplo.
Diez se aãnade a éste nũmero y finalmente el número es dividido por 10
para proporcionar un valor que es un carácter más largo que la posición
de porcentaje en el búffer.

   El número que resulta de todo esto se pasa a ‘goto-char’ y el cursor
se mueve a este punto.


File: emacs-lisp-intro-es.info,  Node: Completo beginning-of-buffer,  Prev: beginning-of-buffer opt arg,  Up: beginning-of-buffer

5.3.3 El ‘beginning-of-buffer’ completo
---------------------------------------

Aquí está el texto completo de la función ‘beginning-of-buffer’:

     (defun beginning-of-buffer (&optional arg)
       "Mueve el punto al principio del buffer;
     deja marca en la posición previa.
     Con prefijo \\[universal-argument],
     no se asigna una marca en la posición previa.
     Con el argumento numérico N, pon el
     punto N/10 del camino desde el principio.

     Si el búffer está encogido
     este comando usa el principio y tamaño
     de la parte accesible del búffer.

     ¡No use este comando en programas Lisp!
     \(goto-char (point-min)) es rápido
     y evita poseer la marca."
       (interactive "P")
       (or (consp arg)
           (and transient-mark-mode mark-active)
           (push-mark))
       (let ((size (- (point-max) (point-min))))
         (goto-char (if (and arg (not (consp arg)))
                        (+ (point-min)
                           (if (> size 10000)
                               ;; ¡Evita sobrecarga para grandes tamaños de búffer!
                               (* (prefix-numeric-value arg)
                                  (/ size 10))
                             (/ (+ 10 (* size (prefix-numeric-value arg)))
                                10)))
                      (point-min))))
       (if arg (forward-line 1)))

Excepto por dos pequeños puntos, la discusión previa muestra cómo esta
función trabaja.  El primer punto trata un detalle en la cadena de
documentación, y el segundo concierne la última línea de la función.

   En la cadena de documentación, hay referencia a una expresión:

     \\[universal-argument]

Un ‘\\’ es usado antes de la primera llave de esta expresión.  Este ‘\\’
le cuenta al intérprete Lisp sustituir qué clave está actualmente
emparejada a los ‘[...]’.  En el caso de ‘universal-argument’, que es
normalmente ‘C-u’, pero eso podría ser diferente.  (*Note Consejos para
Cadenas de Documentación: (elisp)Consejos de Documentación, para más
información.)

   Finalmente, la última línea del comando ‘beginning-of-buffer’ dice
mover el punto al principio de la siguiente línea si el comando es
invocado con un argumento:

     (if arg (forward-line 1)))

Esto pone el cursor al principio de la primera línea después de las
apropiadas decenas de posiciones en el búffer.  Esto significa que el
cursor está siempre localizado _al menos_ las decenas solicitadas del
camino a través del búffer, que es un bien que es, quizás, no necesario,
pero que, si no ocurrió, estaría seguro de dibujar rumores.

   Por otro lado, eso significa que si se especifica el comando con un
‘C-u’, sin un número, que es decir, si el 'prefijo de argumento plano'
es simplemente un cons cell, entonces el comando te pone al principio de
la segunda línea ... no sé si este se pretende ningún trato con el
código para evitar que esto ocurre.


File: emacs-lisp-intro-es.info,  Node: Revisar el segundo búffer relacionado,  Next: Ejercicio opcional,  Prev: beginning-of-buffer,  Up: Más complejidad

5.4 Revisar
===========

Aquí hay un breve resumen de los asuntos cubierto en este capítulo.

‘or’
     Evalúa cada argumento en secuencia, y devuelve el valor del primer
     argumento que no es ‘nil’, si ninguno devuelve un valor que no es
     ‘nil’, devuelve ‘nil’.  En breve, devuelve el primer valor de
     verdad de los argumento; devuelve un valor cierto si un _or_
     cualquier de los otros son verdad.

‘and’
     Evalúa cada argumento en secuencia, y si cualquiera es ‘nil’,
     devuelve ‘nil’; si ninguno es ‘nil’, devuelve el valor del último
     argumento.  En breve, devuelve un valor cierto solo si todos los
     argumentos cierto; devuelve un valor cierto si un _and_ cada uno de
     los otros son ciertos.

‘&optional’
     Una palabra clave usaba para indicar que un argumento a una
     definición de función es opcional; esto significa que la función
     puede ser evaluado sin el argumento, si se desea.

‘prefix-numeric-value’
     Convierte el 'argumento prefijo plano' producido por ‘(interactive
     "P")’ a un valor numérico.

‘forward-line’
     Mueve el punto hacia delante al principio de la siguiente línea, o
     si el argumento es más de uno, hacia delante varias líneas.  Si eso
     no se puede mover tan lejos hacia delante como se puede,
     ‘forward-line’ va hacia delante tan lejos como se puede y entonces
     devuelve un contaje del número de líneas adicionales que no pudo
     moverse.

‘erase-buffer’
     Borra todos los contenidos del búffer actual.

‘bufferp’
     Devuelve ‘t’ si su argumento es un búffer; de otro modo devuelve
     ‘nil’.


File: emacs-lisp-intro-es.info,  Node: Ejercicio opcional,  Prev: Revisar el segundo búffer relacionado,  Up: Más complejidad

5.5 Ejercicio de argumento ‘opcional’
=====================================

Escribe una función interactiva con un argumento opcional que chequee si
su argumento, un número, es mayor o igual, o al menos, menos que el
valor de ‘fill-column’, y lo escribe, en un mensaje.  Sin embargo, si no
se pasa un argumento a la función, usa 56 como un valor por defecto.


File: emacs-lisp-intro-es.info,  Node: Encogiendo y extendiendo,  Next: Car cdr y cons,  Prev: Más complejidad,  Up: Top

6 Encogiendo y extendiendo
**************************

Encoger es una funcionalidad de Emacs que hace posible focalizar en una
parte específica de un búffer, y funcionar sin cambiar accidentalmente
otras partes.  Encoger normalmente se deshabilita puesto que puede
confundir a novatos.

* Menu:

* Ventajas de encoger::      Las ventajas de encoger
* save-restriction::         La forma especial ‘save-restriction’.
* what-line::                El número de la línea que
                               apunta está activa.
* Ejercicio narrow::         Ejercicio narrow


File: emacs-lisp-intro-es.info,  Node: Ventajas de encoger,  Next: save-restriction,  Up: Encogiendo y extendiendo

Las ventajas de encoger
=======================

Con encoger, el resto del búffer se hace invisible, como si no
estuviera.  Esto es una ventaja si, por ejemplo, se quiere reemplazar
una palabra en una parte del búffer pero no otro: se encoge la parte que
se quiere y el reemplazo se trae solo en esta sección, no en el resto
del búffer.  Las búsquedas solo funcionarán con una región encogida, no
fuera de una, así si tu estás arreglando una parte de un documento, se
puede guardar en sí desde encontrar partes accidentalmente que no
necesitas arreglar encongiendo solo la región que quieres.  (La tecla
asociada a ‘narrow-to-region’ es ‘C-x n n’.)

   Sin embargo, encoger hace que el resto del búffer sea invisible, esto
puede asustar a gente quien inadvertidamente invoca a encoger y pensar
que se ha borrado una parte de su fichero.  Más allá, el comando ‘undo’
(que es normalmente emparejado a ‘C-x u’) no se deja encoger, así las
personas pueden llegar a estar bastante desesperadas si no conocen que
ellas pueden volver al resto de un búffer para visibilizarlo con el
comando ‘widen’.  (El emparejamiento de la tecla para ‘widen’ es ‘C-x n
w’.)

   Encoger es tan útil al intérprete Lisp como para las personas.  Con
frecuencia, una función Emacs Lisp está diseñada para trabajar en solo
parte de un búffer; o de manera conversa, una función Emacs Lisp
necesita trabajar en todo un búffer que ha sido encogido.  La función
‘what-line’, por ejemplo, borra el encogimiento desde un búffer, si eso
tiene cualquier encogimiento y cuando eso ha finalizado su trabajo,
restaura el encogimiento que haya.  Por otro lado, la función
‘count-lines’, que es llamada por ‘what-line’, usa el encogimiento para
restringirse a sí misma solo a la porción del búffer en el que se está
interesado y entonces restaura la situación previa.


File: emacs-lisp-intro-es.info,  Node: save-restriction,  Next: what-line,  Prev: Ventajas de encoger,  Up: Encogiendo y extendiendo

6.1 La forma especial ‘save-restriction’
========================================

En Emacs Lisp, se puede usar la forma especial ‘save-restriction’ para
guardar la traza siempre que el encogimiento esté en efecto.  Cuando el
intérprete Lisp se encuentra con ‘save-restriction’, eso ejecuta el
código en el cuerpo de la expresión ‘save-restriction’, y entonces
deshace cualquier cambio para encoger lo que el código causó.  Si, por
ejemplo, el búffer está encogido y el código que sigue al comando
‘save-restriction’ devuelve el búffer para su región encogida.  En el
comando ‘what-line’, cualquier encogimiento del búffer que se puede
tener se deshace por el comando ‘widen’ que inmediatamente sigue el
comando ‘save-restriction’.  Cualquier encogimiento original es
restaurado solo antes de la compleción de la función.

   La plantilla para una expresión ‘save-restriction’ es simple:

     (save-restriction
       BODY... )

El cuerpo del ‘save-restriction’ es una o más expresiones que serán
evaluadas en secuencia por el intérprete Lisp.

   Finalmente, un punto a anotar: cuando se usa tanto ‘save-excursion’ y
‘save-restriction’, uno correcto después del otro, deberías usar
‘save-excursion’ fuera.  Si se escribe en el orden inverso, se podría
fallar para grabar el encogimiento en el búffer para el que Emacs cambia
después de llamar a ‘save-excursion’.  De este modo, cuando se escribe
junto a ‘save-excursion’ y ‘save-restriction’ sería escrito así:

     (save-excursion
       (save-restriction
         BODY...))

   En otras circunstancias, cuando no se escribe junto, las formas
especiales ‘save-excursion’ y ‘save-restriction’ deben ser escritas en
el orden apropiado para la función.

   Por ejemplo,

       (save-restriction
         (widen)
         (save-excursion
         BODY...))


File: emacs-lisp-intro-es.info,  Node: what-line,  Next: Ejercicio narrow,  Prev: save-restriction,  Up: Encogiendo y extendiendo

6.2 ‘what-line’
===============

El comando ‘what-line’ cuenta el número de la línea en la que el cursor
se ha localizado.  La función ilustra el uso de los comandos
‘save-restriction’ y ‘save-excursion’.  Aquí está el texto original de
la función:

     (defun what-line ()
       "Imprime el número de línea actual (en el búffer)
       del punto."
       (interactive)
       (save-restriction
         (widen)
         (save-excursion
           (beginning-of-line)
           (message "Línea %d"
                    (1+ (count-lines 1 (point)))))))

   (En versiones recientes de GNU Emacs, la función ‘what-line’ se ha
expandido para contar el número de líneas en un búffer encogido tan bien
como el número de líneas en un búffer ampliado.  La versión reciente es
más compleja que la versión que se muestra.  Alguien sintiéndose
venturoso, podría querer mirarla después de entender como esta versión
funciona.  Probablemente se necesitará usar ‘C-h f’
(‘describe-function’).  La versión nueva usa un condicional para
determinar si el búffer se ha encogido.

   (También, eso usa ‘line-number-at-pos’, que otras expresiones
simples, tales como ‘(goto-char (point-min))’, mueve el punto al
principio de la línea actual con ‘(forward-line 0)’ en vez de
‘beginning-of-line’.)

   La función ‘what-line’ como se muestra aquí tiene una línea de
documentación y es interactiva, como se esperaría.  Las dos líneas
siguientes usan las funciones ‘save-restriction’ y ‘widen’.

   La forma especial ‘save-restriction’ nota que encogiendo es en
efecto, si cualquiera, en el buffer actual y restaura que encogiendo
después del código en el cuerpo del ‘save-restriction’ ha sido evaluada.

   La forma especial ‘save-restriction’ es seguida por ‘widen’.  Esta
función deshace cualquier distancia del actual búffer que puede haber
tenido cuando ‘what-line’ se llame.  (La distancia que había es la
distancia que ‘save-restriction’ recuerda.)  Esta ampliación se hace
posible para la línea contando comandos a contar desde el principio del
búffer.  De otro modo, se habría limitado para contar con la región
accesible.  Cualquier distancia original se restaura solo antes de la
compleción de la función por la forma especial ‘save-restriction’.

   La llamada a ‘widen’ es seguida por ‘save-excursion’, que guarda la
posición del cursor (por ej., el punto) y de la marca, y la restaura
después el código en el cuerpo del ‘save-excursion’ usa la función
‘beginning-of-line’ para mover el punto.

   (Nótese que la expresión ‘(widen)’ viene entre las formas especiales
‘save-restriction’ y ‘save-excursion’.  Cuando se escribe las dos
expresiones ‘save- ...’ en secuencia, escribe ‘save-excursion’
finalmente.)

   Las últimas dos líneas de la función ‘what-line’ son funciones para
contar el número de líneas en el búffer y entonces imprimir el número en
el área echo.

     (message "Line %d"
              (1+ (count-lines 1 (point)))))))

   La función ‘message’ imprime un mensaje de una línea abajo de la
pantalla Emacs.  El primer argumento está dentro de marcas de cita y
está impreso como una cadena de caracteres.  Sin embargo, se puede
contener una expresión ‘%d’ para imprimir un argumento siguiente.  ‘%d’
imprime el argumento como un decimal, así el mensaje dirá alguna cosa
tal como ‘Línea 243’.

   El número que está impreso en lugar de ‘%d’ está computada por la
última línea de la función:

     (1+ (count-lines 1 (point)))

Lo que esto hace es contar las líneas entre la primera posición del
búffer indicada por el ‘1’, y el ‘(point)’, y entonces se añade uno a
este número.  (La función ‘1+’ añade uno a su argumento.)  Se añade a
eso porque la línea 2 tiene solo una línea antes, y ‘count-lines’ cuenta
solo las líneas _antes_ de la línea actual.

   Después de que ‘count-lines’ ha hecho su trabajo, y el mensaje ha
sido impreso en el área echo, la función ‘save-excursion’ restaura punto
y marca a sus posiciones originales; y ‘save-restriction’ restaura la
contracción original, si la hay.


File: emacs-lisp-intro-es.info,  Node: Ejercicio narrow,  Prev: what-line,  Up: Encogiendo y extendiendo

6.3 Ejercicio de encoger
========================

Escribe una función que mostrará los primeros 60 caracteres del búffer
actual, incluso si se ha encogido el búffer a su mitad así que la
primera línea es inaccesible.  Restaura punto, marca y encogimiento.
Para este ejercicio, se necesita usa un popurri entero de funciones,
incluyendo ‘save-restriction’, ‘widen’, ‘goto-char’, ‘point-min’,
‘message’, y ‘buffer-substring’.

   (‘buffer-substring’ es una función previamente no mencionada que
tendrá que investigarla cada cual por uno mismo; o quizás tendrá que
usarse ‘buffer-substring-no-properties’ o ‘filter-buffer-substring’ ...,
o todavía otras funciones.  Las propiedades de texto son una
funcionalidad que de otro modo no serían discutidas aquí.  *Note
Propiedades de Texto: (elisp)Propiedades de Texto.)

   Además, ¿realmente se necesita ‘goto-char’ o ‘point-min’?  ¿O se
puede escribir la función sin ellos?


File: emacs-lisp-intro-es.info,  Node: Car cdr y cons,  Next: Cortando y almacenando texto,  Prev: Encogiendo y extendiendo,  Up: Top

7 ‘car’, ‘cdr’, ‘cons’: Funciones fundamentales
***********************************************

En Lisp, ‘car’, ‘cdr’, y ‘cons’ son funciones fundamentales.  La función
‘cons’ es usada para construir listas, y las funciones ‘car’ y ‘cdr’ son
usadas para tomarlas aparte.

   En el paseo guiado a través de la función ‘copy-region-as-kill’, se
verá ‘cons’ tan bien como dos variantes de ‘cdr’, llamadas ‘setcdr’ y
‘nthcdr’.  (*Note copy-region-as-kill::.)

* Menu:

* Nombres extraños::       Un lado histórico: ¿por qué
                               los nombres extraños?
* car y cdr::                Funciones para extraer parte de una lista.
* cons::                     Construyendo una lista.
* nthcdr::                   Llamando ‘cdr’ repetidamente.
* nth::                      nth
* setcar::                   Cambiando el primer elemento de una lista.
* setcdr::                   Cambiando el resto de una lista.
* Ejercicio cons::           Ejercicio cons


File: emacs-lisp-intro-es.info,  Node: Nombres extraños,  Next: car y cdr,  Up: Car cdr y cons

Nombres extraños
================

El nombre de la función ‘cons’ es razonable: es una abreviación de la
palabra 'constructo'.  Los orígenes de los nombres ‘car’ y ‘cdr’, por
otro lado, son esotéricos: ‘car’ es un acrónimo de la frase 'Contenidos
de la parte de la Dirección del Registro'; y ‘cdr’ (pronunciado
'could-er') es un acrónimo de la frase 'Contenidos del Decremento del
Registro'.  Estas frases se refieren a piezas específicas de hardware en
el ordenador en el que el Lisp original fué desarrollado.  El resto de
frases han sido completamente irrelevantes por más de 25 años a
cualquiera pensando acerca de Lisp.  Ninguno, excepto unos pocos
académicos valientes han empezado a usar nombres más razonables para
estas funciones, los viejos términos están todavía en uso.  En
particular, los términos usados en el código fuente Emacs Lisp, que
usaremos en esta introducción.


File: emacs-lisp-intro-es.info,  Node: car y cdr,  Next: cons,  Prev: Nombres extraños,  Up: Car cdr y cons

7.1 ‘car’ y ‘cdr’
=================

El CAR de una lista es, bastante simple, el primer ítem en la lista.  De
este modo, el CAR de la lista ‘(rosa violeta margarita botóndeoro)’ es
‘rosa’.

   Si está leyendo en Info y en GNU Emacs, se puede ver esto evaluando
lo siguiente:

     (car '(rosa violeta margarita botóndeoro))

Después de evaluar la expresión, ‘rosa’ aparecerá en el área echo.

   Claramente, un nombre más razonable para la función ‘car’ sería
‘first’ y esto es con frecuencia lo que se sugiere.

   ‘car’ no elimina el primer ítem de la lista; solo se informa de lo
que hay.  Después de que ‘car’ se haya aplicado a una lista, la lista es
todavía la misma que era.  En la jerga, ‘car’ es 'no-destructiva'.  Esta
funcionalidad deja de ser importante.

   El CDR de una lista es el resto de la lista, que es, la función ‘cdr’
que devuelve la parte de la lista que sigue el primer ítem.  De este
modo, mientras el CAR de la lista ‘'(rosa violeta margarita botóndeoro)’
es ‘rosa’, el resto de la lista, el valor devuelto por la función ‘cdr’,
es ‘(violeta margarita botóndeoro)’.

   Se puede ver esto evaluando lo siguiente del modo usual:

     (cdr '(rosa violeta margarita botóndeoro))

Cuando se evalúa esto, ‘(violeta margarita botóndeoro)’ aparecerá en el
área echo.

   Al igual que ‘car’, ‘cdr’ no elimina los elementos desde la lista --
solo devuelve un informe de lo que el segundo y subsiguientes elementos
son.

   En el ejemplo, la lista de flores se cita.  Si no, el intérprete Lisp
intentaría evaluar la lista llamando a ‘rosa’ como una función.  En este
ejemplo, no queremos hacer esto.

   Claramente, un nombre más razonable para ‘cdr’ sería ‘rest’.

   (Hay una lección aquí: cuando se nombran nuevas funciones, considere
muy cuidadosamente lo que se está haciendo, ya que puede estar pegadas
con los nombres largos que se esperan.  La razón es que este documento
perpetúa estos nombres que el código fuente de Emacs Lisp usa, y si no
los usaba, se estaría un duro rato leyendo el código; pero, por favor,
se debe intentar evitar usar estos términos por uno mismo.  Las personas
que vengan después se lo agradecerán.

   Cuando ‘car’ y ‘cdr’ se aplica a una lista hecha de símbolos, tal
como la lista ‘(pino roble abeto arce)’, el elemento de la lista
devuelta por la función ‘car’ es el símbolo ‘pino’ sin cualquier
paréntesis alrededor.  ‘pino’ es el primer elemento en la lista.  Sin
embargo, el CDR de la lista es una lista por sí misma, ‘(roble abeto
arce)’, como se puede ver evaluando las siguientes expresiones en el
modo usual:

     (car '(pino roble abeto arce))

     (cdr '(pino roble abeto arce))

   Por otro lado, en una lista de listas, el primer elemento es en sí
mismo una lista.  ‘char’ devuelve este primer elemento como una lista.
Por ejemplo, la siguiente lista contiene tres sublistas, una lista de
carnívoros, una lista de herbívoros y una lista de mamíferos:

     (car '((leon tigre leopardo)
            (gacela antilope cebra)
            (ballena delfin foca)))

En este ejemplo, el primer elemento de CAR de la lista es la lista de
carnívoros, ‘(leon tigre leopardo)’, y el resto de la lista es ‘((gacela
antilope cebra) (ballena delfin foca))’.

     (cdr '((leon tigre leopardo)
            (gacela antilope cebra)
            (ballena delfin)))

   Es un valor decir de nuevo que ‘car’ y ‘cdr’ son no destructivos --
esto es, no se modifican o cambian listas para las que ser aplicados.
Esto es muy importante por cómo son usados.

   También, en el primer capítulo, en la discusión acerca de átomos, yo
dije que en Lisp, "ciertos tipos de átomos, tales como un array, pueden
separarse en partes; pero el mecanismo de hacer esto es diferente del
mecanismo de separar una lista.  Desde que Lisp se conoce, los átomos de
una lista son indivisibles."  (*Note Átomos Lisp::.)  El ‘car’ y el
‘cdr’ son funciones que son usadas para dividir listas y son
consideradas fundamentales para Lisp.  Puesto que no pueden dividir o
ganar acceso a las partes de un array, un array es considerado un átomo.
De otro modo, la otra función fundamental, ‘cons’, se puede poner cerca
o construir una lista, pero no un array.  (Los arrays son manejados por
funciones de array específicas.  *Note Arrays: (elisp)Arrays.)


File: emacs-lisp-intro-es.info,  Node: cons,  Next: nthcdr,  Prev: car y cdr,  Up: Car cdr y cons

7.2 ‘cons’
==========

La función ‘cons’ construye listas; eso es lo inverso de ‘car’ y ‘cdr’.
Por ejemplo, ‘cons’ puede usarse para crear una lista de cuatro
elementos desde los tres elementos de la lista, ‘(abeto roble arce)’:

     (cons 'pino '(abeto roble arce))

Después de evaluar esto, se verá lo siguiente:

     (pino abeto roble arce)

aparece en el área echo.  ‘cons’ causa la creación de una nueva lista en
el que el elemento es seguido por los elementos de la lista original.

   Con frecuencia decimos que '‘cons’ pone un nuevo elemento al
principio de una lista; adjunta o empuja el elemento dentro de la
lista', pero esta frase puede ser incorrecta, puesto que ‘cons’ no
cambia a una lista existente, pero crea una nueva.

   Como ‘car’ y ‘cdr’, ‘cons’ es no destructivo.

* Menu:

* Construir una lista::      Construir una lista
* length::                   Cómo encontrar el tamaño de una lista.


File: emacs-lisp-intro-es.info,  Node: Construir una lista,  Next: length,  Up: cons

Construir una lista
-------------------

‘cons’ debe tener una lista para adjuntar a(1) No se puede empezar desde
absolutamente nada.  Si se está construyendo una lista, se necesita
proveer al menos una lista vacía al principio.  Aquí hay una serie de
expresiones ‘cons’ que construyen una lista de flores.  Si está leyendo
esto en Info en GNU Emacs, se puede evaluar cada una de las expresiones
en el camino usual; el valor es impreso en este texto después de ‘⇒’,
que puede leer como 'evalúas para'.

     (cons 'botóndeoro ())
          ⇒ (botóndeoro)

     (cons 'margarita '(botóndeoro))
          ⇒ (margarita botóndeoro)

     (cons 'violeta '(margarita botóndeoro))
          ⇒ (violeta margarita botóndeoro)

     (cons 'rosa '(violeta margarita botóndeoro))
          ⇒ (rosa violeta margarita botóndeoro)

En el primer ejemplo, la lista vacía se muestra como ‘()’ y después se
construye una lista de ‘botóndeoro’ seguida por la lista vacía.  Como se
puede ver, la lista vacía no se muestra en la lista que fué construida.
Todo lo que se ve es ‘(botóndeoro)’.  La lista vacía no cuenta como un
elemento de una lista porque no hay nada en una lista vacía.
Generalmente hablando, una lista vacía es invisible.

   El segundo ejemplo, ‘(cons 'margarita '(botóndeoro))’ construye una
nueva lista de dos elemento poniendo ‘margarita’ en frente de
‘botóndeoro’; y el tercer ejemplo construye una lista de tres elementos
poniendo ‘violeta’ en frente de ‘margarita’ y ‘botóndeoro’.

   ---------- Footnotes ----------

   (1) Actualmente, se puede ‘cons’ un elemento para un átomo para
producir a para punteado.  Los pares punteados no se discuten aquí; ver
*note Notación de Para Punteado: (elisp)Notación de Pares Punteados.


File: emacs-lisp-intro-es.info,  Node: length,  Prev: Construir una lista,  Up: cons

7.2.1 Encuentra el tamaño de una lista: ‘length’
------------------------------------------------

Se pueden encontrar cuántos elementos hay en una lista usando la función
Lisp ‘length’, como en los siguientes ejemplos:

     (length '(botóndeoro))
          ⇒ 1

     (length '(margarita botóndeoro))
          ⇒ 2

     (length (cons 'violeta '(margarita botóndeoro)))
          ⇒ 3

En el tercer ejemplo, la función ‘cons’ es usada para construir una
lista de tres elementos que entonces se pasa a la función ‘length’ como
su argumento.

   Se puede también usar ‘length’ para contar el número de elementos en
una lista vacía:

     (length ())
          ⇒ 0

Como se esperaría, el número de elementos en una lista vacía es cero.

   Un experimento interesante es encontrar qué ocurre si se intenta
encontrar el tamaño de una no lista en todo; que es, si se intenta
llamar a ‘length’ sin darle un argumento, incluso una lista no vacía:

     (length )

Lo que se ve, si se evalúa esto, es el mensaje de error

     Lisp error: (wrong-number-of-arguments length 0)

Esto significa que la función recibe el número incorrecto de argumentos,
cero, cuando se espera algún otro número de argumentos.  En este caso,
se espera un argumento, el argumento de una lista cuyo tamaño de la
función se está midiendo.  (Nótese que _una_ lista es _un_ argumento,
incluso si la lista tiene muchos elementos dentro.)

   La parte del mensaje de error que dice ‘length’ es el nombre de la
función.


File: emacs-lisp-intro-es.info,  Node: nthcdr,  Next: nth,  Prev: cons,  Up: Car cdr y cons

7.3 ‘nthcdr’
============

La función ‘nthcdr’ está asociada con la función ‘cdr’.  Que lo que hace
es tomar la CDR de una lista repetidamente.

   Si se toma el CDR de la lista ‘(pino roble abeto arce)’, será
devuelta la lista ‘(roble abeto arce)’.  Si se repite esto en lo que se
devolvió, se devolverá lista lista ‘(abeto arce)’.  (De acuerdo, se
repite CDR en la lista original solo se dará CDR desde la función que no
cambia la lista.  Se necesita evaluar el CDR del CDR y así.)  Si se
contiúa esto, finalmente será devuelta una lista vacía, que en este
caso, en vez de ser mostrada como ‘()’ es mostrado como ‘nil’.

   Para revisar, aquí hay una serie de CDRs repetidos, el siguiente ‘⇒’
muestra lo que se devuelve.

     (cdr '(pino roble abeto arce))
          ⇒(roble abeto arce)

     (cdr '(roble abeto arce))
          ⇒ (abeto arce)

     (cdr '(abeto arce))
          ⇒(arce)

     (cdr '(arce))
          ⇒ nil

     (cdr 'nil)
          ⇒ nil

     (cdr ())
          ⇒ nil

   También se pueden hacer varios CDRs sin imprimir los valores así:

     (cdr (cdr '(pino roble abeto arce)))
          ⇒ (abeto arce)

En este ejemplo, el intérprete Lisp evalúa la lista propia dentro.  La
lista de dentro está entre comillas, así solo pasa la lista del ‘cdr’
más interno.  Este ‘cdr’ pasa una lista hecho del segundo y
subsiguientes elementos de la lista al ‘cdr’ más externo, que produce
una lista compuesta del tercer y subsiguientes elementos de la lista
original.  En este ejemplo, la función ‘cdr’ se repite y devuelve una
lista que consiste de la lista original sin sus primeros dos elementos.

   La función ‘nthcdr’ hace lo mismo que repitiendo la llamada a ‘cdr’.
En el siguiente ejemplo, el segundo argumento se pasa a la función
‘nthcdr’, a través con la lista, y el valor devuelto es la lista sin sus
primeros dos ítems, que son exactamente los mismos dos ‘cdr’ en la
lista:

     (nthcdr 2 '(pino roble abeto arce))
          ⇒ (abeto arce)

   Usando la lista original de cuatro elementos, se puede ver qué ocurre
cuando varios argumentos numéricos son pasados a ‘nthcdr’, incluyendo 0,
1, y 5:

     ;; Deja la lista como estaba.
     (nthcdr 0 '(pine fir oak maple))
          ⇒ (pino roble abeto arce)

     ;; Devuelve una copia sin el primer elemento.
     (nthcdr 1 '(pine fir oak maple))
          ⇒ (fir oak maple)

     ;; Devuelve una copia de la lista sin tres elementos.
     (nthcdr 3 '(pine fir oak maple))
          ⇒ (maple)

     ;; Devuelve la lista faltando los cuatro elementos.
     (nthcdr 4 '(pine fir oak maple))
          ⇒ nil

     ;; Devuelve una copia sin los elementos.
     (nthcdr 5 '(pine fir oak maple))
          ⇒ nil


File: emacs-lisp-intro-es.info,  Node: nth,  Next: setcar,  Prev: nthcdr,  Up: Car cdr y cons

7.4 ‘nth’
=========

La función ‘nthcdr’ toma el CDR de una lista repetidamente.  La función
‘nth’ toma el CAR del resultado devuelto por ‘nthcdr’.  Devuelve el
elemento Nth de la lista.

   De este modo, si no fuera definido en C para velocidad, la definición
de ‘nth’ sería:

     (defun nth (n list)
       "Devuelve el elemento Nth de Lista.
     N cuenta desde cero. Si Lista no es larga, nil es devuelto".
       (car (nthcdr n list)))

(Originalmente, ‘nth’ fué definido en Emacs Lisp en ‘subr.el’, pero su
definición fué rehecha en C en los 1980s.)

   La función ‘nth’ devuelve un elemento simple de una lista.  Esto
puede ser muy conveniente.

   Nótese que los elementos son numerados desde cero, no desde uno.  Es
decir, el primer elemento de una lista, su CAR es el elemento cero.
Esto se llama contar en 'base cero' y con frecuencia las personas tienen
la costumbre del que el primer elemento en una lista sea el número uno,
eso es 'basado en uno'.

   Por ejemplo:

     (nth 0 '("uno" "dos" "tres"))
         ⇒ "uno"

     (nth 1 '("uno" "dos" "tres"))
         ⇒ "dos"

   Es valorable mencionar que ‘nth’, como ‘nthcdr’ y ‘cdr’, no cambia la
lista original -- la función no es destructiva.  En contraste con las
funciones ‘setcar’ y ‘setcdr’.


File: emacs-lisp-intro-es.info,  Node: setcar,  Next: setcdr,  Prev: nth,  Up: Car cdr y cons

7.5 ‘setcar’
============

Como se podría adivinar desde sus nombres, las funciones ‘setcar’ y
‘setcdr’ asignan el CAR o la CDR de una lista a un nuevo valor.  Ellos
actualmente cambia la lista original, no como ‘car’ y ‘cdr’ que deja la
lista original como estaba.  Un camino para encontrar cómo esto funciona
es experimentar.  Se comenzará con la función ‘setcar’.

   Primero, podemos crear una lista y entonces asignar el valor de una
variable a la lista usando la función ‘setq’.  Aquí hay una lista de
animales:

     (setq animales '(antilope jirafa leon tigre))

Si está leyendo esto en Info dentro de GNU Emacs, se puede evaluar esta
expresión del modo usual, posicionando el cursor después de la expresión
y escribiendo ‘C-x C-e’.  Esto es una de las ventajas de tener el
intérprete construido dentro del entorno de computación.
Incidentalmente, cuando no hay nada en la línea después del paréntesis
final, tal como un comentario, el punto puede estar en la siguiente
línea.  De este modo, si tu cursor está en la primera columna de la
siguiente línea, no se necesita mover.  En realidad, Emacs permite
cualquier cantidad de espacio en blanco después del paréntesis final.)

   Cuando se evalúa la variable ‘animal’, vemos que está asociada a la
lista ‘(antelope giraffer lion tiger)’:

     animales
          ⇒ (antilope jirafa leon tigre)

Por otro lado, la variable ‘animales’ apunta a la lista ‘(antilope
jirafa leon tigre)’.

   Lo siguiente, es evaluar la función ‘setcar’ mientras le pasa dos
argumentos, la variable ‘animales’ y el símbolo citado ‘hipopotamo’;
esto se hace escribiendo la lista de tres elementos ‘(setcar animales
'hipopotamo)’ y entonces evaluando en el modo usual:

     (setcar animales 'hipopotamo)

Después de evaluar esta expresión, evalúa la variable ‘animales’ de
nuevo.  Se puede ver que la lista de animales ha cambiado:

     animales
          ⇒ (hipopótamo jirafa leon tigre)

El primer elemento en la lista, ‘antilope’ se reemplaza por
‘hipopotamo’.

   Así se puede ver que ‘setcar’ no añadió un nuevo elemento a la lista
como ‘cons’ tendría; eso reemplazó ‘antílope’ con ‘hipopótamo’; eso
_cambió_ la lista.


File: emacs-lisp-intro-es.info,  Node: setcdr,  Next: Ejercicio cons,  Prev: setcar,  Up: Car cdr y cons

7.6 ‘setcdr’
============

La función ‘setcdr’ es similar a la función ‘setcar’, excepto que la
función reemplaza el segundo y subsiguientes elementos de una lista en
vez del primer elemento.

   (Para ver cómo se cambia el último elemento de una lista, mira hacia
delante a la *note La función ‘kill-new’: Función kill-new, que usa las
funciones ‘nthcdr’ y ‘setcdr’.)

   Para ver cómo esto funciona, asigna el valor de la variable a una
lista de animales domesticados evaluando la siguiente expresión:

     (setq animales-domesticos '(caballo vaca oveja cabra))

Si ahora se evalúa la lista, lo que se devuelve es ‘(caballo vaca oveja
cabra)’:

     animales-domesticos
          ⇒ (caballo vaca oveja cabra)

   Lo siguiente, evalúa ‘setcdr’ con dos argumentos, el nombre de la
variable que tiene una lista como su valor, y la lista para la que el
CDR de la primera lista sea asignada;

     (setcdr animales-domesticos '(gato perro))

Si se evalúa esta expresión, la lista ‘(gato perro)’ aparecerá en el
área echo.  Este es el valor devuelto por la función.  El resultado en
el que estamos interesados es el "efecto lateral", que se puede ver
evaluando la variable ‘domesticated-animals’:

     animales-domesticos
          ⇒ (caballo gato perro)

En realidad, la lista es cambiada desde ‘(caballo vaca oveja cabra)’ a
‘(caballo gato perro)’.  El CDR de la lista es cambiada desde ‘(vaca
oveja cabra)’ a ‘(gato perro)’.


File: emacs-lisp-intro-es.info,  Node: Ejercicio cons,  Prev: setcdr,  Up: Car cdr y cons

7.7 Ejercicio
=============

Construye una lista de cuatro pájaros evaluando varias expresiones con
‘cons’.  Encuentra que ocurre cuando ‘cons’ una lista dentro de sí.
Reemplaza el primer elemento de la lista de cuatro pájaros con un pez.
Reemplaza el resto de esta lista con una lista de otro pez.


File: emacs-lisp-intro-es.info,  Node: Cortando y almacenando texto,  Next: Implementación de listas,  Prev: Car cdr y cons,  Up: Top

8 Cortando y almacenando texto
******************************

Siempre y cuando se corte o pegue texto de un búffer con un comando
'kill' en GNU Emacs, se almacenará dentro de una lista que se puede
traer con un comando 'yank'.

   (El uso de la palabra 'kill' _matar, cortar_ en Emacs para procesos
que específicamente _no_ destruyen los valores de las entidades es un
accidente histórico desafortunado.  Una palabra mucho más apropiada
debería ser 'clip' _cortar_ puesto que es lo que los comandos de corte
hacen; ellos cortan texto fuera de un búffer y lo ponen dentro del
almacenamiento desde el que puede traerse.  Con frecuencia ha sido
tentada de reemplazar globalmente todas las ocurrencia de 'kill' _matar,
cortar_ en las fuentes de Emacs con 'clip' _cortar_ y todas las
ocurrencias de 'killed' _cortado, muerto_ con 'clipped' _cortado_.)

* Menu:

* Almacenando Texto::        El texto está almacenado en una lista.
* zap-to-char::              Cortando texto a un carácter.
* kill-region::              Cortando texto de una región.
* copy-region-as-kill::      Una definición para copiar texto.
* Disgresión dentro de C::  Nota menor en macros del lenguaje de
                                programación C.
* defvar::                   Cómo dar a una variable un valor inicial.
* Revisión de cons y search-fwd::  Revisión de cons y search-fwd
* Buscar ejercicios::        Buscar ejercicios


File: emacs-lisp-intro-es.info,  Node: Almacenando Texto,  Next: zap-to-char,  Up: Cortando y almacenando texto

Almacenando texto en una lista
==============================

Cuando el texto se corta de un búffer, es almacenado en una lista.
Piezas sucesivas de texto se almacenan en la lista sucesivamente, así la
lista podría verse así:

     ("una pieza de texto" "pieza previa")

La función ‘cons’ puede usarse para crear una nueva lista desde una
pieza de texto (un 'átomo', para usar la jerga) y una lista existente,
como esta:

     (cons "otra pieza"
           '("una pieza de texto" "pieza previa"))

Si se evalúa esta expresión, una lista de tres elementos aparecerá en el
área echo:

     ("otra pieza" "una pieza de texto" "pieza previa")

   Con las funciones ‘car’ y ‘nthcdr’, se puede recuperar siempre la
pieza de texto que se quiere.  Por ejemplo, en el siguiente código,
‘nthcdr 1 ...’ devuelve la lista con el primer ítem eliminado; y el
‘car’ devuelve el primer elemento de este resto -- el segundo elemento
de la lista original:

     (car (nthcdr 1 '("otra pieza"
                      "una pieza de texto"
                      "pieza previa")))
          ⇒ "una pieza de texto"

   Las funciones actuales en Emacs son más complejas que esto, de
acuerdo.  El código para cortar y recuperar texto tiene que ser escrito
de modo que Emacs pueda ver qué elemento en la lista se quiere -- el
primer, segundo, tercer o cualquier otro.  Además, cuando tiene el fin
de la lista, Emacs daría el primer elemento de la lista, en lugar de
nada.

   La lista que maneja las piezas de texto se llama “kill ring” (anillo
de la muerte).  Este capítulo lidera una descripción del anillo de la
muerte y como eso se usa por la primera traza de cómo la función
‘zap-to-char’ funciona.  Esta función usa (o 'llama') a una función que
invoca a otra función que manipula el anillo de la muerte.  De este
modo, antes de lograr las montañas, se escalan las colinas.

   Un capítulo subsiguiente describe cómo el texto que se corta desde el
búffer se recupera.  *Note Pegando Texto: Pegando.


File: emacs-lisp-intro-es.info,  Node: zap-to-char,  Next: kill-region,  Prev: Almacenando Texto,  Up: Cortando y almacenando texto

8.1 ‘zap-to-char’
=================

La función ‘zap-to-char’ cambió poco entre GNU Emacs versión 19 y GNU
Emacs versión 22.  Sin embargo, ‘zap-to-char’ llama a otra función,
‘kill-region’, que se reescribió más.

   La función ‘kill-region’ en Emacs 19 es compleja, pero no usa código
que es importante en este momento.  Se obviará.

   La función ‘kill-region’ en Emacs 22 es más de fácil leer que la
misma función en Emacs 19 e introduce un concepto muy importante, que el
error maneja.  Nosotros pasearemos a través de la función.

   Pero primero, déjanos ver en la función interactive ‘zap-to-char’.

* Menu:

* Completar zap-to-char::    La implementación completa.
* zap-to-char interactivo::  Una expresión interactiva de tres partes.
* cuerpo zap-to-char::       Un resumen corto
* search-forward::           Cómo buscar una cadena.
* progn::                    La forma especial ‘progn’.
* Resumiendo zap-to-char::   Usando ‘point’ y ‘search-forward’.


File: emacs-lisp-intro-es.info,  Node: Completar zap-to-char,  Next: zap-to-char interactivo,  Up: zap-to-char

La implementación completa ‘zap-to-char’
----------------------------------------

La función ‘zap-to-char’ elimina el texto en la región entre la
localización del curso (por ej.  punto) para incluir la siguiente
ocurrencia de un caracter específico.  El texto que ‘zap-to-char’ borra
es puesto en el kill ring _anillo de la muerte_; y puede ser recuperado
desde el kill ring _anillo de la muerte_ escribiendo ‘C-y’ (‘yank’).  Si
el comando dado es un argumento, eso borra texto a través de este número
de ocurrencias.  De este modo, si el cursor estuviera al principio de
esta frase y el carácter fuera ‘s’, ‘De este modo’ sería borrado.  Si el
argumento fueran dos, ‘De este modo, si el cursor’ se borrase, y
incluiría la ‘s’ en el ‘cursor’.

   Si el carácter específico no encuentra ‘zap-to-char’ dirá "Búsqueda
fallida", eso cuenta el carácter que se escribió, y no eliminó cualquier
texto.

   En orden para determinar cuánto texto eliminar ‘zap-to-char’ usa una
función de búsqueda.  Las búsquedas son usadas extensivamente en el
código que manipula texto, y focalizará la atención en ellos tan bien
como el comando de borrado.

   Aquí está el texto completo de la versión 22 de la función:

     (defun zap-to-char (arg char)
       "Corta e incluye ARG'th ocurrencia de CHAR
     En caso de ser ignorada si `case-fold-search' es no nulo en el
       búffer actual.
     Para ir atrás si ARG es negativo; error si CHAR no se encuentra."
       (interactive "p\ncZap to char: ")
       (if (char-table-p translation-table-for-input)
           (setq char (or (aref translation-table-for-input char) char)))
       (kill-region (point) (progn
                              (search-forward (char-to-string char)
                                              nil nil arg)
                              (point))))

   La documentación es en línea.  Se necesita conocer el significado de
la jerga de la palabra 'kill'.


File: emacs-lisp-intro-es.info,  Node: zap-to-char interactivo,  Next: cuerpo zap-to-char,  Prev: Completar zap-to-char,  Up: zap-to-char

8.1.1 La expresión ‘interactive’
--------------------------------

La expresión interactiva en el comando ‘zap-to-char’ se ve así:

     (interactive "p\ncZap to char: ")

   La parte con comillas, ‘"p\ncZap to char: "’ _Cortar a caracter_,
especifica dos cosas diferentes.  Primero, y más simple es el ‘p’.  Este
parte se separa desde la siguiente parte por una nueva línea, ‘\n’.  El
‘p’ significa que la parte del primero argumento a la función será
pasando el valor de un 'prefijo procesado'.  El argumento prefijo es
pasado escribiendo ‘C-u’ y un número, o ‘M-’ y un número.  Si la función
es llamada interactivamente sin un prefijo, el número que se pasa es 1.

   La segunda parte de ‘"p\ncZap a caracter: "’ es ‘cZap a carácter:’.
En esta parte, la tecla baja ‘c’ indica que ‘interactive’ espera una
consola que el argumento será un caracter.  La consola sigue el ‘c’ y es
la cadena ‘Zap a caracter: ’ (con un espacio después del punto y coma
para hacerlo bien).

   Todo lo que se hace es preparar los argumentos para ‘zap-to-char’ así
están en el tipo correcto, y dan al usuario un prompt.

   En un búffer de solo lectura, la función ‘zap-to-char’ copia el texto
al anillo de la muerte, no se elimina.  El área echo muestra un mensaje
diciendo que el búffer es de solo lectura.  También, la terminal avisa
con un pitido.


File: emacs-lisp-intro-es.info,  Node: cuerpo zap-to-char,  Next: search-forward,  Prev: zap-to-char interactivo,  Up: zap-to-char

8.1.2 El cuerpo de ‘zap-to-char’
--------------------------------

El cuerpo de la función ‘zap-to-char’ contiene el código que mata (que
se borra/corta) el texto en la región desde la posición actual del
cursor e incluyendo el carácter especificado.

   La primera parte del código se ve como:

     (if (char-table-p translation-table-for-input)
         (setq char (or (aref translation-table-for-input char) char)))
     (kill-region (point) (progn
                            (search-forward (char-to-string char) nil nil arg)
                            (point)))

‘char-table-p’ es una función prescrita no vista.  Eso determina si sus
argumentos son una tabla de caracteres.  Así, se asigna el carácter
pasado a ‘zap-to-char’ a uno de ellos, si este carácter existe, o al
carácter en sí.  (Esto llega a ser importante para ciertos caracteres en
lenguajes no Europeos.  La función ‘aref’ extrae un elemento desde un
array.  Eso es una función específica de array que no está descrita en
este documento.  *Note Arrays: (elisp)Array.)

Lo que devuelve ‘(point)’ es la posición actual del cursor.

   La siguiente parte del código es una expresión usando ‘progn’.  El
cuerpo del ‘progn’ se basa en llamadas a ‘search-forward’ y ‘point’.

   Es fácil comprender cómo ‘progn’ funciona después de aprender acerca
de ‘search-forward’, así se verá en ‘search-forward’ y entonces en
‘progn’.


File: emacs-lisp-intro-es.info,  Node: search-forward,  Next: progn,  Prev: cuerpo zap-to-char,  Up: zap-to-char

8.1.3 La función ‘search-forward’
---------------------------------

La función ‘search-forward’ se usa para localizar el
zapped-for-character en ‘zap-to-char’.  Si la búsqueda es exitosa,
‘search-forward’ deja el punto inmediatamente después del último
carácter en la cadena objetivo.  (En ‘zap-to-char’, la cadena objetivo
es solo un carácter largo.  ‘zap-to-char’ usa la función
‘char-to-string’ para asegurar que el ordenador trata este carácter como
una cadena).  Si la búsqueda es hacia atrás, ‘search-forward’ deja el
punto solo antes del primer carácter en el objetivo.  También,
‘search-forward’ devuelve ‘t’ para verdad.  (Moviendo el punto allí es
un 'efecto lateral'.)

   En ‘zap-to-char’, la función ‘search-forward’ se ve así:

     (search-forward (char-to-string char) nil nil arg)

   La función ‘search-forward’ toma cuatro argumentos:

  1. El primer argumento es el objetivo, para el que es buscado.  Esto
     debe ser una cadena, tal como ‘"z"’.

     Cuando eso ocurre, el argumento pasado a ‘zap-to-char’ es un
     caracter simple.  Debido a la forma en la que los ordenadores son
     construidos, el intérprete Lisp puede tratar un caracter simple
     siendo diferente desde una cadena de caracteres.  Dentro del
     ordenador, un caracter simple tiene un formato electrónico en vez
     de una cadena de un caracter.  (Un caracter simple puede con
     frecuencia ser grabado en el ordenador usando exactamente un byte;
     pero una cadena puede ser larga, y el ordenador necesita estar
     listo para esto.)  Desde que la función ‘search-forward’ busca una
     cadena, el caracter que la función ‘zap-to-char’ recibe como
     argumento debe ser convertida dentro del ordenador de un formato a
     otro; de otro modo, la función ‘search-forward’ fallará.  La
     función ‘char-to-string’ es usada para hacer esta conversión.

  2. El segundo argumento asocia la búsqueda; eso se especifica como una
     posición en el búffer.  En este caso, la búsqueda puede ir al final
     del búffer, así no se asigna y el segundo argumento es ‘nil’.

  3. El tercer argumento cuenta la función que haría si la búsqueda cae
     -- eso puede señalar un error (e imprimir un mensaje) o puede
     devolver ‘nil’.  Un ‘nil’ como tercer argumento hace que la función
     señale un error cuando la búsqueda falla.

  4. El cuarto argumento ‘search-forward’ es el contaje repetido --
     cuántas ocurrencias de la cadena para buscar.  Este argumento es
     opcional y si la función es llamada sin un contaje repetido, este
     argumento pasa el valor 1.  Si este argumento es negativo, la
     búsqueda va hacia atrás.

   En la forma de plantilla, una expresión ‘search-forward’ se ve así:

     (search-forward "CADENA-A-BUSCAR"
                     LIMITE-DE-BUSQUEDA
                     QUE-HACER-SI-LA-BUSQUEDA-FALLA
                     REPETIR-CONTAJE)

   Lo siguiente es echar un vistazo a ‘progn’.


File: emacs-lisp-intro-es.info,  Node: progn,  Next: Resumiendo zap-to-char,  Prev: search-forward,  Up: zap-to-char

8.1.4 La forma especial ‘progn’
-------------------------------

‘progn’ es una forma especial que causa que cada uno de sus argumentos
puedan ser evaluados en secuencia y entonces devuelve el valor del
último.  Las expresiones precedentes son evaluadas solo por los efectos
laterales que ellos desarrollan.  Los valores producidos por ellos son
descartados.

   La plantilla para una expresión ‘progn’ es muy simple:

     (progn
       BODY...)

   En ‘zap-to-char’, la expresión ‘progn’ tiene que hacer dos cosas:
poner el punto en la posición exacta; y devolver la posición del punto
de modo que ‘kill-region’ conoce cómo de lejos se copia.

   El primer argumento de ‘progn’ es ‘search-forward’.  Cuando
‘search-forward’ encuentra la cadena, la función deja el punto
inmediatamente después del último caracter en la cadena objetivo.  (En
este caso la cadena objetivo es solo un carácter largo.)  Si la búsqueda
es hacia atrás, ‘search-forward’ deja el punto justo antes del primer
carácter en el objetivo.  El movimiento del punto es un efecto lateral.

   El segundo y último argumento de ‘progn’ es la expresión ‘(point)’.
Esta expresión devuelve el valor del punto, que en este caso será la
localización para la que se ha movido por ‘search-forward’.  (En la
fuente, una línea que cuenta la función para ir al carácter previo, si
se está yendo hacia delante, se comentó en 1999; yo no recuerdo si esta
funcionalidad o no funcionalidad era siempre parte de las fuentes
distribuidas.)  El valor de ‘point’ se devuelve por la expresión ‘progn’
y se pasa a ‘kill-region’ como el segundo argumento de ‘kill-region’ .


File: emacs-lisp-intro-es.info,  Node: Resumiendo zap-to-char,  Prev: progn,  Up: zap-to-char

8.1.5 Resumiendo ‘zap-to-char’
------------------------------

Ahora que se ha visto cómo ‘search-forward’ y ‘progn’ trabajan, se puede
ver cómo la función ‘zap-to-char’ funciona como un todo.

   El primer argumento de ‘kill-region’ es la posición del cursor cuando
el comando ‘zap-to-char’ da -- el valor del punto en este momento.  Con
el ‘progn’, la búsqueda de la función mueve el punto a solo después del
zapped-to-character y ‘point’ devuelve el valor de localización.  La
función ‘kill-region’ pone junto a estos dos valores de punto, el
primero como el principio de la región y el segundo como el fin de la
región, y borra la región.

   La forma especial ‘progn’ se necesita porque el comando ‘kill-region’
toma dos argumentos; y fallaría si ‘search-forward’ y expresiones
‘point’ fueran escritas en secuencia como dos argumentos adicionales.
La expresión ‘progn’ es un argumento simple para ‘kill-region’ y
devuelve un valor para que ‘kill-region’ se necesite por su segundo
argumento.


File: emacs-lisp-intro-es.info,  Node: kill-region,  Next: copy-region-as-kill,  Prev: zap-to-char,  Up: Cortando y almacenando texto

8.2 ‘kill-region’
=================

La función ‘zap-to-char’ usa la función ‘kill-region’.  Esta función
corta texto desde una región y copia este texto al kill ring _anillo de
la muerte_, desde el que puede ser recuperado.

   Tanto la versión de Emacs 22 de esta función usa ‘condition-case’ y
‘copy-region-as-kill’, ambas se explicarán.  ‘condition-case’ es una
forma especial importante.

   En esencia, la función ‘kill-region’ llama a ‘condition-case’, que
toma tres argumentos.  En esta función, el primer argumento no hace
nada.  El segundo argumento contiene el código hace el trabajo cuando
todo va bien.  El tercer argumento contiene el código que se llama en el
evento de un error.

* Menu:

* Completa kill-region::     La definición de función.
* condition-case::           Tratando con un problema.
* Macro Lisp::               Macro Lisp


File: emacs-lisp-intro-es.info,  Node: Completa kill-region,  Next: condition-case,  Up: kill-region

La definición completa ‘kill-region’
------------------------------------

Ahora se puede volver a través del código ‘condition-case’ en un
momento.  Primero, se echa un vistazo a la definición de ‘kill-region’,
con comentarios añadidos:

     (defun kill-region (beg end)
       "Kill (\"corta\") texto entre punto y marca.
     Esto borra el texto desde el búffer y lo guarda en anillo de la
       muerte _kill ring_.
     El comando \\[yank] puede recuperarse desde allí. ...
      "

       ;; • Desde materias de orden, pasa el punto primero.
       (interactive (list (point) (mark)))
       ;; • Y cuéntanos si no podemos cortar el texto.
       ;; `a menos que' sea un `if' sin una then-part.
       (unless (and beg end)
         (error "La marca no está asignada ahora, así que
       no hay región"))

       ;; • `condition-case' toma tres argumentos
       ;;    Si el primer argumento es nulo, como aquí
       ;;    la información acerca del error no está
       ;;    almacenada para ser usada por otra función
       (condition-case nil

           ;; • El segundo argumento a `condition-case' cuenta lo que el
           ;;    intérprete que hace cuando todo va bien.

           ;;    Empieza con una función `let' que extrae la cadena
           ;;    y chequea si existe. Si es así (esto es lo
           ;;    que `when' chequea), eso llama a una función `if' que
           ;;    determina si el comando previo que era otra llamada
           ;;    si el comando previo fué otra llamada a `kill-region';
           ;;    si lo era, entonces el siguiente texto se añade
           ;;    cuando se chequea), eso llama a una función `if' que
           ;;    determina si el comando previo era otra llamada a
           ;;    `kill-region'; si era eso, entonces el nuevo texto es
           ;;    añadido al texto previo; si no, entonces una función
           ;;    diferente, `kill-new' se llama.

           ;;    La función `kill-append' concatena la nueva cadena y
           ;;    la vieja.  La función `kill-new' inserta texto dentro de
           ;;    ítem en el kill ring _anillo de la muerte_.

           ;;    `when' es un `if' sin una parte else.  El segundo `when'
           ;;    de nuevo chequea si la cadena actual existe;
           ;;    por añadidura, eso chequea si el comando previo fuese
           ;;    otra llamada a `kill-region'. Si una u otra condición
           ;;    es verdadero, entonces eso configura el actual comando a
           ;;    ser `kill-region'.
           (let ((string (filter-buffer-substring beg end t)))
             (when string                    ;STRING is nil if BEG = END
               ;; Add that string to the kill ring, one way or another.
               (if (eq last-command 'kill-region)
                   ;;    − `yank-handler' es un argumento opcional para
                   ;;    `kill-region' que cuenta el `kill-append' y funciones
                   ;;    `kill-new' como tratan con propiedades añadidas
                   ;;    al texto, tal como `negrilla' o `itálica'
                   (kill-append string (< end beg) yank-handler)
                 (kill-new string nil yank-handler)))
             (when (or string (eq last-command 'kill-region))
               (setq this-command 'kill-region))
             nil)

         ;;  • El tercer argumento a `condition-case' cuenta el intérprete
         ;;  qué hacer con un error.
         ;;    El tercer argumento tiene una parte de condiciones y una
         ;;    parte del cuerpo.
         ;;    Si las condiciones se encuentra (en este caso,
         ;;             si el texto o búffer son de solo lectura)
         ;;    entonces el cuerpo es ejecutado.
         ;;    La primera parte del tercer es el siguiente:
         ((buffer-read-only text-read-only) ;; parte if
          ;; ...  parte then-part
          (copy-region-as-kill beg end)
          ;;    Lo siguiente, también como parte de la then-part, asigna this-command, así
          ;;    será asignado en un error
          (setq this-command 'kill-region)
          ;;    Finalmente, en la then-part, envía un mensaje
          ;;    si se puede copiar el texto al anillo de la muerte
          ;;    _kill ring_ sin señalar un error, pero no si no se puede.

          (if kill-read-only-ok
              (progn (message "Lee solo texto copiado para el kill ring") nil)
            (barf-if-buffer-read-only)
            ;; If the buffer isn't read-only, the text is.
            (signal 'text-read-only (list (current-buffer)))))


File: emacs-lisp-intro-es.info,  Node: condition-case,  Next: Macro Lisp,  Prev: Completa kill-region,  Up: kill-region

8.2.1 ‘condition-case’
----------------------

Como se ha visto antes (*note Genera un Mensaje de Error: Creando
errores.), cuando el intérprete Emacs Lisp tiene problemas evaluando una
expresión, se provee de una ayuda; en jerga, se dice "signaling an
error" _señalando un error_.  Normalmente, el ordenador para el programa
y te muestra un mensaje.

   Sin embargo, algunos programas garantizan acciones complicadas.  Eso
no pararía en un error.  En la función ‘kill-region’, la mayoría parece
un error que intentará cortar texto que es de solo lectura y no puede
ser eliminado.  Así la función ‘kill-region’ contiene código para
manejar esta circunstancia.  Este código, hace que el cuerpo de la
función ‘kill-region’, esté dentro de una forma especial
‘condition-case’.

   La plantilla para ‘condition-case’ se parece a esto:

     (condition-case
       VAR
       BODYFORM
       ERROR-HANDLER...)

   El segundo argumento, BODYFORM es sencillo.  La forma especial
‘condition-case’ causa que el intérprete Lisp evalúe el código en
BODYFORM.  Si ningún error ocurre, la forma especial devuelve el valor
del código y produce efectos laterales, si hay.

   En resumen, la parte BODYFORM de una expresión ‘condition-case’
determina qué ocurre cuando cualquier cosa funciona correctamente.

   Sin embargo, si un error ocurre, entre sus otras acciones, la función
genera la señal de error que definirá uno o más errores de nombres de
condición.

   Un manejador de errores es el tercer argumento para ‘condition-case’.
Un manejador de errores tiene dos partes, un CONDITION-NAME y un BODY.
Si la parte CONDITION-NAME tiene un manejador de errores encuentra un
nombre de condición generado por un error, entonces la parte del BODY
del manejador de errores se ejecuta.

   Como se esperaría, la parte CONDITION-NAME de un manejador de errores
puede ser así, un nombre de condición simple o una lista de nombres de
condición.

   También, una expresión completa ‘condition-case’ puede contener más
de un manejador de errores.  Cuando un error ocurre, el primer manejador
aplicable se ejecuta.

   Finalmente, el primer argumento a la expresión ‘condition-case’, es
el argumento VAR, que es algunas veces asignado a una variable que
contiene información acerca del error.  Sin embargo, si este argumento
es nulo, como es el caso en ‘kill-region’, esta información se descarta.

   En breve, en la función ‘kill-region’, el código ‘condition-case’
funciona así:

     SI NO HAY ERRORES, EJECUTA SOLO ESTE CÓDIGO
         PERO, SI HAY ERRORES, EJECUTA ESTE OTRO CÓDIGO.


File: emacs-lisp-intro-es.info,  Node: Macro Lisp,  Prev: condition-case,  Up: kill-region

8.2.2 Macro Lisp
----------------

La parte de la expresión ‘condition-case’ que se evalúa en la
expectativa de que todo va bien si tiene un ‘when’.  El código usa
‘when’ para determinar si la variable ‘string’ (_cadena_) apunta al
texto que existe.

   Una expresión ‘when’ es simplemente una conveniencia de
programadores.  Eso es un ‘if’ sin la posibilidad de una cláusula else.
En tu mente, se puede reemplazar ‘when’ con ‘if’ y comprender de que va.
Esto es lo que el intérprete Lisp hace.

   Técnicamente hablando, ‘when’ es una macro Lisp.  Una “macro” Lisp
permite definir una nueva construcción de control y otras
funcionalidades del lenguaje.  Eso cuenta al intérprete cómo computar
otra expresión Lisp que dejará de computar el valor.  En este caso, la
'otra expresión' es una expresión ‘if’.

   La definición de función también tiene una macro ‘unless’; que
acompaña a ‘when’.  La macro ‘unless’ es un ‘if’ sin una cláusula then.

   Para más acerca de macros Lisp, ver *note Macros: (elisp)Macros.  El
lenguaje de programación C también provee macros.  Estos son diferentes,
pero también útiles.

   Guardando la macro ‘when’, en la expresión ‘condition-case’, cuando
la cadena tiene contenido, entonces otra expresión condicional se
ejecuta.  Esto es un ‘if’ tanto con una then-part y como con una
else-part.

     (if (eq last-command 'kill-region)
         (kill-append string (< end beg) yank-handler)
       (kill-new string nil yank-handler))

   La parte then (then-part) se evalúa si el comando previo fué otra
llamada para ‘kill-region’; si no, se evalúa la parte else (else-part)

   ‘yank-handler’ es un argumento opcional para ‘kill-region’ que cuenta
cómo las funciones ‘kill-append’ y ‘kill-new’ se tratan con propiedades
añadidas al texto, tal como 'negrilla' o 'itálica'.

   ‘last-command’ es una variable que viene con Emacs y que no se ha
visto antes.  Normalmente, siempre y cuando una función se ejecute,
Emacs asigna el valor de ‘last-command’ al comando previo.

   En este segmento de la definición, la expresión ‘if’ chequea si el
comando previo era ‘kill-region’.  Si era eso,

     (kill-append string (< end beg) yank-handler)

Se concatena una copia del nuevo texto cortado al texto cortado
previamente en el kill ring _anillo de la muerte_.


File: emacs-lisp-intro-es.info,  Node: copy-region-as-kill,  Next: Disgresión dentro de C,  Prev: kill-region,  Up: Cortando y almacenando texto

8.3 ‘copy-region-as-kill’
=========================

La función ‘copy-region-as-kill’ copia una región de texto desde un
búffer y (via ‘kill-append’ o ‘kill-new’) lo guarda en el ‘kill-ring’.

   Si se llama a ‘copy-region-as-kill’ inmediatamente después de un
comando ‘kill-region’, Emacs inserta el texto nuevamente copiado al
texto copiado previamente.  Esto significa que si se pega el texto, se
obtiene todo, tanto esto, como la operación previa.  Por otro lado, si
algún otro comando precede la ‘copy-region-as-kill’, la función copia el
texto dentro de una entrada separada el kill ring _anillo de la muerte_.

* Menu:

* Completar copy-region-as-kill::  La definición completa de función.
* cuerpo copy-region-as-kill::  El cuerpo de ‘copy-region-as-kill’.


File: emacs-lisp-intro-es.info,  Node: Completar copy-region-as-kill,  Next: cuerpo copy-region-as-kill,  Up: copy-region-as-kill

La definición de la función completa ‘copy-region-as-kill’.
-----------------------------------------------------------

Aquí está el texto completo de la versión 22 de la función
‘copy-region-as-kill’:

     (defun copy-region-as-kill (beg end)
       "Guarda la región como si estuviera cortada, pero no la cortes.
     En el modo Marca de Tránsito _Transient Mark_, se desactiva la
       marca.
     Si `interprogram-cut-function' es no nulo, también se guarda el
       texto para una sistema de ventanas de cortar y pegar."
       (interactive "r")
       (if (eq last-command 'kill-region)
           (kill-append (filter-buffer-substring beg end) (< end beg))
         (kill-new (filter-buffer-substring beg end)))
       (if transient-mark-mode
           (setq deactivate-mark t))
       nil)

   De normal, esta función puede ser dividida dentro sus componentes:

     (defun copy-region-as-kill (ARGUMENT-LIST)
       "DOCUMENTATION..."
       (interactive "r")
       BODY...)

   Los argumentos son ‘beg’ y ‘end’ y la función es interactiva con
‘"r"’, así los dos argumentos deben referirse al principio y al final de
la región.  Si ha estado leyendo a través de este documento desde el
principio, comprendiendo estas partes de una función casi llegaría a ser
rutina.

   La documentación es algo confusa a menos que se recuerde que la
palabra 'kill' _matar, cortar_ tiene un significado diferente de la
usual.  La 'Marca Transitoria' y ‘interprogram-cut-function’ comenta
explicar ciertos efectos laterales.

   Después de que se ha asignado una marca, un búffer siempre contiene
una región.  Si se desea se puede usar el modo Marca Transitoria para
iluminar la región temporalmente.  (Nadie quiere iluminar la región todo
el rato, así el modo Marca Transitoria subrraya solo en el momento
apropiado.  Muchas personas desactivan el modo Marca Transitoria, así la
región nunca se ilumina.)

   También, un sistema de ventanas permite copiar, cortar y pegar entre
programas diferentes.  En el sistema de X windows, por ejemplo, la
función ‘interprogram-cut-function’ es ‘x-select-text’, que funciona con
el sistema de ventanas equivalente del kill ring de Emacs.

   El cuerpo de la función ‘copy-region-as-kill’ empieza con una
cláusula ‘if’.  Lo que esta cláusula hace es distinguir entre dos
situaciones diferentes: si este comando se ejecuta o no inmediatamente
después de un comando previo ‘kill-region’.  En el primer caso, la nueva
región se concatena al texto copiado previamente.  De otro modo, eso se
inserta al principio del anillo de la muerte _kill ring_ como una pieza
separada de texto desde la pieza previa.

   Las dos líneas de la función previene la región desde la iluminación
si el modo Transient Mark _Marca Transitoria_ está activado.

   El cuerpo de ‘copy-region-as-kill’ merece discusión en detalle.


File: emacs-lisp-intro-es.info,  Node: cuerpo copy-region-as-kill,  Prev: Completar copy-region-as-kill,  Up: copy-region-as-kill

8.3.1 El cuerpo de ‘copy-region-as-kill’
----------------------------------------

La función ‘copy-region-as-kil’ funciona de un modo parecido a la
función ‘kill-region’.  Ambas están escritas de un modo que dos o más
textos cortados en una fila combinan su texto en una entrada simple.  Si
se pega el texto desde el anillo de la muerte _kill ring_, se tiene todo
en una pieza.  Más allá, los cortes de textos que se cortan hacia
adelante desde la posición actual del cursor se añaden al fin del texto
copiado previamente y comanda este texto copiado vaya hacia atrás al
principio del texto copiado previamente.  De este modo, las palabras en
el texto están en el orden apropiado.

   Como ‘kill-region’, la función ‘copy-region-as-kill’ hace uso de la
variable ‘last-command’ que deja traza del comando de Emacs previo.

* Menu:

* last-command & this-command::  last-command & this-command
* Función kill-append::    Función kill-append
* Función kill-new::       Función kill-new


File: emacs-lisp-intro-es.info,  Node: last-command & this-command,  Next: Función kill-append,  Up: cuerpo copy-region-as-kill

‘last-command’ y ‘this-command’
...............................

Normalmente, siempre y cuando una función se ejecuta, Emacs asigna el
valor de ‘this-command’ a la función que se ejecuta (que en este caso
sería ‘copy-region-as-kill’).  Al mismo tiempo, Emacs asigna el valor de
‘last-command’ al valor previo de ‘this-command’.

   En la primera parte del cuerpo de la función ‘copy-region-as-kill’,
una expresión ‘if’ determina si el valor de ‘last-command’ es
‘kill-region’.  Si es así, la then-part de la expresión ‘if’ se evalúa;
eso usa la función ‘kill-append’ para concatenar el texto copiado en
esta llamada a la función con el texto ya en el primer elemento (el CAR
del anillo de la muerte.  Por otro lado, si el valor de ‘last-command’
no es ‘kill-region’, entonces la función ‘copy-region-as-kill’ adjunta
un nuevo elemento al anillo de la muerte _kill ring_ usando la función
‘kill-new’.

   La expresión ‘or’ se ve así; usa ‘eq’:

       (if (eq last-command 'kill-region)
           ;; parte then
           (kill-append  (filter-buffer-substring beg end) (< end beg))
         ;; parte else
         (kill-new  (filter-buffer-substring beg end)))

   (La función ‘filter-buffer-substring’ devuelve una subcadena filtrada
del búffer, cualquiera.  Opcionalmente -- los argumentos no están aquí,
así nunca está hecho -- la función puede borrar el texto inicial o
devolver el texto sin sus propiedades; esta función es un reemplazo para
la vieja función ‘buffer-substring’, que viene antes que las propiedades
del texto fuesen implementadas.)

La función ‘eq’ chequea si su primer argumento es el mismo objeto Lisp
que su segundo argumento.  La función ‘eq’ es similar a la función
‘equal’ en esto que es usado para chequear para igualdad, pero difiere
en esto que determina si dos representaciones son actualmente el mismo
objeto dentro del ordenador, pero con diferentes nombres.  ‘equal’
determina si la estructura y contenidos de dos expresiones son la misma.

   Si el comando previo era ‘kill-region’, entonces el intérprete Emacs
Lisp llama a la función ‘kill-append’


File: emacs-lisp-intro-es.info,  Node: Función kill-append,  Next: Función kill-new,  Prev: last-command & this-command,  Up: cuerpo copy-region-as-kill

La función ‘kill-append’
........................

La función ‘kill-new’ se ve como así:

     (defun kill-append (string before-p &optional yank-handler)
       "Inserta STRING al fin del último corte en el anillo de la muerte _kill ring_.
     Si BEFORE-P es no nulo, inserta STRING.
     ... "
       (let* ((cur (car kill-ring)))
         (kill-new (if before-p (concat string cur) (concat cur string))
                   (or (= (length cur) 0)
                       (equal yank-handler
                              (get-text-property 0 'yank-handler cur)))
                   yank-handler)))

La función ‘kill-append’ es limpia.  Usa la función ‘kill-new’, que
discutiremos en más detalle en un momento.

   (También, la función provee un argumento opcional llamado
‘yank-handler’; cuando se invoque, este argumento cuenta a la función
cómo tratar con la propiedades añadidas al texto, tales como 'negrilla'
o 'itálicas'.)

   Eso tiene una función ‘let*’ para asignar el valor del primer
elemento del kill ring a ‘cur’.  (No se sabe por qué la función no usa
‘let’; solo un valor es asignado en la expresión.  ¿Quizás esto es un
error que no produce problemas?

   Considera el condicional que es uno de los dos argumentos para
‘kill-new’.  Eso usa ‘concat’ para concatenar el nuevo texto al CAR del
anillo de la muerte _kill ring_.  Si eso se concatena atrás o delante
depende de los resultados de una expresión ‘if’:

     (if before-p                            ; if-part
         (concat string cur)                 ; then-part
       (concat cur string))                  ; else-part

Si la región cortada está antes que la región que se cortó en el último
comando, entonces debería ser puesto antes que el material salvador en
el anterior corte _kill_; y de manera contraria, si el texto cortado
sigue lo que fué cortado, eso sería añadido después del texto previo.
La expresión ‘if’ depende del predicado ‘before-p’ para decidir si el
texto nuevamente salvado es puesto antes o después.

   El símbolo ‘before-p’ es el nombre de uno de los argumentos a
‘kill-append’.  Cuando la función ‘kill-append’ se evalúa, se asocia al
valor devuelto evaluando el argumento actual.  En este caso, esta es la
expresión ‘(< end beg)’.  Esta expresión no determina directamente si el
texto cortado en este comando se localiza antes o después del texto
cortado del último comando; lo que hace es determinar si el valor de la
variable ‘end’ es menor que el valor de la variable ‘beg’.  Si es así,
significa que el usuario se encara al principio del búffer.  También, el
resultado de evaluar la expresión del predicado.  ‘(< end beg)’, será
verdadero y el texto se concatena antes del texto previo.  Por otro
lado, si el valor de la variable ‘end’ es mayor que el valor del la
variable ‘beg’, el texto será concatenado después del texto previo.

   Cuando el texto nuevamente guardado se concatena, entonces la cadena
con el nuevo texto será concatenado antes del viejo texto:

     (concat string cur)

Pero si el texto será añadido, eso será concatenado después del viejo
texto:

     (concat cur string))

   Para comprender cómo funciona esto, primero se necesita revisar la
función ‘concat’.  La función ‘concat’ enlaza junto o une dos cadenas de
texto.  El resultado es una cadena.  Por ejemplo:

     (concat "abc" "def")
          ⇒ "abcdef"

     (concat "nuevo "
             (car '("primer elemento" "segundo elemento")))
          ⇒ "nuevo primer elemento"

     (concat (car
             '("primer elemento" "segundo elemento")) " modificado")
          ⇒ "primer elemento modificado"

   Ahora puede tener sentido ‘kill-append’: eso modifica los contenidos
del anillo de la muerte _kill ring_.  El anillo de la muerte _kill ring_
es una lista, en la que cada elemento es texto guardado.  La función
‘kill-append’ usa la función ‘kill-new’ que usa la función ‘setcar’.


File: emacs-lisp-intro-es.info,  Node: Función kill-new,  Prev: Función kill-append,  Up: cuerpo copy-region-as-kill

La función ‘kill-new’
.....................

La función ‘kill-new’ se ve de esta manera:

     (defun kill-new (string &optional replace yank-handler)
       "Crea STRING el último corte en el anillo de la muerte _kill
       ring_.
     Asigna `kill-ring-yank-pointer' para apuntarlo.

     Si `interprogram-cut-function' es no nulo, aplícalo a su
      STRING.
     Segundo argumento opcional REPLACE no-nulo significa que STRING
      reemplazará el frente del kill ring, en vez de ser aãndido a la lista.
     ..."
       (if (> (length string) 0)
           (if yank-handler
               (put-text-property 0 (length string)
                                  'yank-handler yank-handler string))
         (if yank-handler
             (signal 'args-out-of-range
                     (list string "yank-handler specified for empty string"))))
       (if (fboundp 'menu-bar-update-yank-menu)
           (menu-bar-update-yank-menu string (and replace (car kill-ring))))
       (if (and replace kill-ring)
           (setcar kill-ring string)
         (push string kill-ring)
         (if (> (length kill-ring) kill-ring-max)
             (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
       (setq kill-ring-yank-pointer kill-ring)
       (if interprogram-cut-function
           (funcall interprogram-cut-function string (not replace))))

   (Vea que la función no es interactiva.)

   Normalmente, se mira a esta función en partes.

   La definición de la función tiene un argumento opcional
‘yank-handler’, que cuando se invoca cuenta la función de cómo tratar
con propiedades añadidas al texto, tal como 'negrilla' o 'itálica'.
Nosotros evitaremos esto.

   La primer línea de la documentación tiene sentido:

     Crea la CADENA la última copia en el anillo de la muerte _kill
     ring_.

Permite saltarse el resto de la documentación por el momento.

También, permite salir de la expresión inicial ‘if’ y estas líneas de
código involucrando ‘menu-bar-update-yank-menu’.  Nosotros explicaremos
debajo.

   Las líneas críticas son estas:

       (if (and replace kill-ring)
           ;; entonces
           (setcar kill-ring string)
         ;; resto
       (push string kill-ring)
         (setq kill-ring (cons string kill-ring))
         (if (> (length kill-ring) kill-ring-max)
             ;; avoid overly long kill ring
             (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
       (setq kill-ring-yank-pointer kill-ring)
       (if interprogram-cut-function
           (funcall interprogram-cut-function string (not replace))))

   El test condicional es ‘(and replace kill-ring)’.  Esto será verdad
cuando dos condiciones se encuentran: el anillo de la muerte _kill ring_
tiene alguna cosa dentro, y la variable ‘replace’ es verdad.

   Cuando la función ‘kill-append’ asigna ‘replace’ para ser cierto y
cuando el anillo de la muerte _kill ring_ tiene al menos un ítem en eso,
la expresión ‘setcar’ es ejecutada.

     (setcar kill-ring string)

   La función ‘setcar’ actualemten cambia el primer elemento del anillo
de la muerte (‘kill-ring’ lista al valor de ‘string’.  Eso reemplaza el
primer elemento.

   Por otro lado, si el kill ring está vacío, o reemplazar es falso, la
else-part de la condición está ejecutado:

     (push string kill-ring)

   ‘push’ pone su primer argumento dentro del segundo.  Es similar al
viejo.

     (setq kill-ring (cons string kill-ring))

   o el nuevo

     (add-to-list kill-ring string)

Cuando eso es falso, la expresión primero construye una nueva versión
del anillo de la muerte _kill ring_ añadiendo ‘string’ al anillo de la
muerte _kill ring_ como un nuevo elemento (que es lo que ‘push’ hace).
Entonces ejecuta un segundo ‘if’ cláusula.  Este segundo ‘if’ cláusula
guarada el anillo de la muerte _kill ring_ desde el creciente demasiado
largo.

   Déjanos mirar estas dos expresiones en orden.

   La línea ‘push’ de la parte else asigna el nuevo valor del kill ring
_anillo de la muerte_ a que resultados añaden la cadena siendo cortada
al viejo anillo de la muerte _kill ring_

   Nosotros podemos ver cómo esto funciona con un ejemplo.

   Primero,

     (setq example-list '("aqui una clausula" "otra clausula"))

Después de evaluar esta expresión con ‘C-x C-e’, se puede evaluar
‘example-list’ y mira lo que devuelve:

     example-list
          ⇒ ("aquí hay una claúsula" "otra claúsula")

Ahora, se puede añadir un nuevo elemento en esta lista evaluando la
siguiente expresión:

     (push "una tercera cláusula" lista-de-ejemplo)

Cuando se evalúa ‘example-list’, se encuentra su valor es:

     example-list
          ⇒ ("una tercera claúsula" "aquí hay una
          claúsula" "otra claúsula")

De este modo, la tercera claúsula se añade a la lista con ‘push’.

   Ahora para la segunda parte de la claúsula ‘if’.  Esta expresión deja
el kill ring desde lo creciente demasiado largo.  Eso se ve de la
siguiente manera:

     (if (> (length kill-ring) kill-ring-max)
         (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))

   El código chequea si el tamaño del anillo de la muerte _kill ring_ es
más grande que el máximo tamaño permitido.  Este es el valor de
‘kill-ring-max’ (que es 60, por defecto).  Si el tamaño del anillo de la
muerte _kill ring_ es demasiado largo, entonces este código asigna el
último elemento del anillo de la muerte _kill ring_ a ‘nil’.  Eso hace
esto usando dos funciones, ‘nthcdr’ y ‘setcdr’.

   Nosotros vemos que ‘setcdr’ temprano (*note ‘setcdr’: setcdr.).  Eso
asigna el CDR de una lista, solo como ‘setcar’ asigna el CAR de una
lista.  En este caso, sin embargo, ‘setcdr’ no estará configurando el
CDR del kill ring completo; la función ‘nthcdr’ es usada para causarlo
para asignar el CDR del siguiente al último elemento del kill ring --
esto significa que desde el CDR del siguiente al último elemnto del kill
ring _anillo de la muerte_, eso asignará el último elemento del kill
ring _anillo de la muerte_.

   La función ‘nthcdr’ funciona repetidamente tomando el CDR de una
lista -- eso toma el CDR del CDR del CDR ....  Eso hace esto N veces y
devuelve los resultados.  (*Note ‘nthcdr’: nthcdr.)

   De este modo, si teniamos una lista de cuatro elemento que era
supuestamente de tres elementos, se podría asignar el CDR del siguiente
al último elemento a ‘nil’, y por eso se ordena la lista.  (Si se asigna
el último elemento a algún otro valor a ‘nil’, que se podría hacer,
entonces no se habría ordenado la lista.  *Note ‘setcdr’: setcdr.)

   Se puede ver ordenando la evaluación de las siguientes tres
expresiones en turno.  Primero asigna el valor de ‘arboles’ a ‘(arce
encina pino abedul)’ entonces asigna el CDR de su segundo CDR y entonces
encuentra el valor de ‘arboles’.

     (setq arboles '(arce encina pino abedul))
          ⇒ (arce encina pino abedul)

     (setcdr (nthcdr 2 arboles) nil)
          ⇒ nil

     árboles
          ⇒ (arce encina pino)

(El valor devuelto por la expresión ‘setcdr’ es ‘nil’ desde que es que
el CDR es asignado.)

   Para repetir, en ‘kill-new’, la función ‘nthcdr’ toma el CDR un
número de veces que es uno menos que el tamaño máximo permitido del
anillo de la muerte _kill ring_ y ‘setcdr’ asigna el CDR de este
elemento (que será el resto de los elementos en el anillo muerte) para
‘nil’.  Esto previene el anillo de la muerte _kill ring_ desde lo que
crece demasiado largo.

   De la siguiente a la última expresión en la función ‘kill-new’ es

     (setq kill-ring-yank-pointer kill-ring)

   El ‘kill-ring-yank-pointer’ es una variable global que es asignado
para ser el ‘kill-ring’.

   Incluso aunque el ‘kill-ring-yank-pointer’ es llamado un ‘puntero’,
eso es una variable solo como el anillo de la muerte _kill ring_.  Sin
embargo, el nombre que ha sido elegido para ayudar a humanos a
comprender cómo la variable se usa.

   Ahora, para devolver rápido una expresión en el cuerpo de la función:

       (if (fboundp 'menu-bar-update-yank-menu)
            (menu-bar-update-yank-menu string (and replace (car kill-ring))))

Empieza con una expresión ‘if’

   En este caso, la expresión chequea primero si
‘menu-bar-update-yank-menu’ existe como una función, y si así, se llama.
La función ‘fboundp’ devuelve cierto si el símbolo que se chequea tiene
una definición de función que 'no es vacía'.  Si el símbolo de la
definición de función fuera vacío, recibiría un mensaje de error, como
se hizo cuando se crearon errores intencionalmente (*note Genera un
Mensaje de Error: Creando errores.).

La then-part contiene una expresión cuyo primer elemento es la función
‘and’.

   La forma especial ‘and’ evalúa cada uno de sus argumentos hasta que
uno de los argumentos devuelva un valor de ‘nil’, en cuyo caso la
expresión ‘and’ devuelve ‘nil’; sin embargo, si ninguno de los
argumentos devuelve una valor de ‘nil’, el valor resultante desde la
evaluación el último argumento es devuelto.  (Desde que tal valor no es
‘nil’, eso es considerado cierto en Emacs Lisp.)  En otras palabras, una
expresión ‘and’ devuelve un valor cierto solo si todos sus argumentos
son verdaderos.  (*Note Revisar el segundo búffer relacionado::.)

   La expresión determina si el segundo argumento
‘menu-bar-update-yank-menu’ es verdadero o no.

   ‘menu-bar-update-yank-menu’ es una de la funciones que lo hace
posible para usar el menu 'Seleccionar y Pegar' en el ítem Editar de una
barra de menu; usando un ratón, se pueden mirar varias piezas de texto
que se han guardado y se selecciona una pieza para pegar.

   La última expresión en la función ‘kill-new’ añade las cadenas
nuevamente copiadas a aquella facilidad que existe copiando y pegando
entre diferentes programas ejecutando un sistema de ventanas.  En el
Sistema de Ventanas de X, por ejemplo, la función ‘x-select-text’ toma
la cadena y la almacena en memoria operada por X.  Se puede pegar la
cadena en otro programa, tal como un Xterm.

   La expresión se ve como:

       (if interprogram-cut-function
           (funcall interprogram-cut-function string (not replace))))

   Si ‘interprogram-cut-function’ existe, entonces Emacs ejecuta
‘funcall’, que en vez de llamar a su primer argumento como una función,
pasa los argumentos que permanecen en eso.  (Incidentalmente, tan lejos
como se puede ver, esta expresión ‘if’ podría ser reemplazado por una
expresión ‘and’ similar a uno en la primera parte de la función.)

   Estamos yendo a discutir sistemas de ventanas y otros programas más
allá pero meramente nota que este es un mecanismo que habilita GNU Emacs
a trabajar fácilmente y bien con otros programas.

   Este código para emplazar texot en el anillo de la muerte _kill
ring_, concatenado con un elemento existente o como un nuevo elemento,
nos lidera al código para traer texto que ha sido cortado del búffer --
los comandos de corte.  Sin embargo, antes de discutir los comandos de
corte, es mejor aprender cómo las listas son implementadas en un
ordenador.  Esto dejará claro tales misterios como el uso del término
'puntero'.  Pero antes de esto, nos desviaremos a C.


File: emacs-lisp-intro-es.info,  Node: Disgresión dentro de C,  Next: defvar,  Prev: copy-region-as-kill,  Up: Cortando y almacenando texto

8.4 Disgresión dentro de C
==========================

La función ‘copy-region-as-kill’ (*note ‘copy-region-as-kill’:
copy-region-as-kill.) usa la función ‘filter-buffer-substring’, que en
vez de eso usa la función ‘delete-and-extract-region’.  Eso elimina los
contenidos de una región y no se puede volverlos a tener.

   Al contrario que el otro código discutido aquí, la función
‘delete-and-extract-region’ no está escrita en Emacs Lisp; eso está
escrito en C y es una de las primitivas del sistema GNU Emacs.  Puesto
que es muy simple, se hará la disgresión brevemente desde el Lisp y se
describe aquí.

   Como muchas de las otras primitivas Emacs,
‘delete-and-extract-region’ se escribe como una instancia de una macro
C, una macro es una plantilla para codificar.  La macro completa se
parece a esto:

     DEFUN ("delete-and-extract-region", Fdelete_and_extract_region,
            Sdelete_and_extract_region, 2, 2, 0,
            doc: /* Borra el texto entre START y END y lo devuelve.  */)
            (Lisp_Object start, Lisp_Object end)
     {
       validate_region (&start, &end);
       if (XINT (start) == XINT (end))
         return empty_unibyte_string;
       return del_range_1 (XINT (start), XINT (end), 1, 1);
     }

   Sin ir dentro de los detalles de la macro que escribe el proceso, se
hará un apunte de esta macro que empieza con la palabra ‘DEFUN’.  La
palabra ‘DEFUN’ fué elegida puesto que el código sirve para el mismo
propósito que ‘defun’ hace en Lisp.  (La macro C ‘DEFUN’ definida en
‘emacs/src/lisp.h’.)

   El palabra ‘DEFUN’ tiene siete partes dentro de los paréntesis:

   • La primera parte es el nombre dado a la función en Lisp,
     ‘delete-and-extract-region’.

   • La segunda parte es el nombre de la función en C,
     ‘Fdelete_and_extract_region’.  Por convención, eso empieza con ‘F’.
     Puesto que C no usa guiones en nombres, los guiones bajos son
     usados a su vez.

   • La tercera parte es el nombre para la estructura constante C que
     registra información en esta función para uso interno.  Es el
     nombre de la función en C pero empieza con una ‘S’ en vez de una
     ‘F’.

   • Las partes cuarta y quinta especifican el número mínimo y máximo de
     argumentos que la función puede tener.  Esta función demanda
     exactamente 2 argumentos.

   • La sexta parte está cerca del argumento que sigue la declaración
     ‘interactive’ en una función escrita en Lisp: una carta seguida,
     quizás, por una consola.  La única diferencia con Lisp es que si la
     macro se llama sin argumentos.  Entonces se escribe un ‘0’ (que es
     una 'cadena nula'), como en esta macro.

     Si se fueran a especificar argumentos, se emplazarían entre marcas
     de comillas.  La macro C para ‘goto-char’ incluye ‘\"NGoto char \"’
     en esta posición se indica que la función espera un prefijo plano,
     en este caso, una localización numérica en un búffer, y provee una
     consola.

   • La séptima parte es una cadena de documentación, solo como la única
     para una función escrita en Emacs Lisp.  Esto es escrito como un
     comentario C. (Cuando se escribe Emacs, el programa
     ‘lib-src/make-docfile’ extrae estos comentarios y los usa para
     crear la documentación "real".)

   En una macro C, los parámetros son los siguientes, con una frase de
este tipo de objeto se siguen por lo que podría ser llamado el 'cuerpo'
de la macro.  Para ‘delete-and-extract-region’ el 'cuerpo' consiste de
las siguientes cuatro líneas:

     validate_region (&start, &end);
     if (XINT (start) == XINT (end))
       return build_string ("");
     return del_range_1 (XINT (start), XINT (end), 1, 1);

   La función ‘validate_region’ chequea si los valores pasados como el
principio y fin de la región son el tipo apropiado y son del mismo
rango.  Si las posiciones del principio y fin son las mismas, entonces
se devuelve una cadena vacía.

   La función ‘del_range_1’ actualmente borra el texto.  Eso es una
función compleja que no miraremos.  Eso actualiza el búffer y hace otras
cosas.  Sin embargo, es el valorable mirar los dos argumentos pasados
para ‘del_range’.  Estos son ‘XINT (start)’ y ‘XINT (end)’.

   Tan lejos como el lenguaje C es concebido, ‘start’ y ‘end’ son dos
enteros que marcan el principio y el fin de la región para ser
borrada(1).

   En las primeras versiones de Emacs, estos dos números fueron 32 bits
de longitud, pero el código está lentamente siendo generalizado para
manejar otras longitudes.  Tres de los bits disponibles son usados para
especificar el tipo de información; los bits permanecen ser usados como
'contenido'.

   ‘XINT’ es una macro C que extrae los números relevantes desde la
colección larga de bits; los otros tres bits se descartan.

   El comando en ‘delete-and-extract-region’ se parece a esto:

     del_range_1 (XINT (start), XINT (end), 1, 1);

Esto borra la región entre la posición del principio, ‘start’, y la
posición final, ‘end’.

   Desde el punto de vista de la persona que escribe Lisp, Emacs es muy
simple; pero oculta en el fondo un gran trato de complejidad para hacer
todo el trabajo.

   ---------- Footnotes ----------

   (1) Más precisamente, y requiriendo conocimiento más experto para
comprender, los dos enteros son del tipo 'Lisp_Object', que puede
también ser una unión C en vez de un tipo de entero.


File: emacs-lisp-intro-es.info,  Node: defvar,  Next: Revisión de cons y search-fwd,  Prev: Disgresión dentro de C,  Up: Cortando y almacenando texto

8.5 Inicializando una variable con ‘defvar’
===========================================

La función ‘copy-region-as-kill’ es escrita en Emacs Lisp.  Dos
funciones con eso, ‘kill-append’ y ‘kill-new’, copiar una región en un
búffer y guardarlo en una variable llamada el ‘kill-ring’.  Esta sección
describe cómo la variable ‘kill-ring’ es creada e inicializada usando la
forma especial ‘defvar’.

   (De nuevo se nota que el término ‘kill-ring’ es un sin nombre.  El
texto que es cortado fuera del búffer puede ser traido; eso no es un
corpus de anillo, pero un anillo de texto resucitable.)

   En Emacs Lisp, una variable tal como ‘kill-ring’ es creada y dada por
un valor inicial usando la forma especial ‘defvar’.  El nombre viene de
"definir variable".

   La forma especial ‘defvar’ es similar a ‘setq’ en este se configura
el valor de una variable.  Eso no es ‘setq’ en dos modos; primero solo
configura el valor de la variable si la variable no tiene ya un valor.
Si la variable ya tiene un valor, ‘defvar’ no sobreescribe el valor
existente.  Segundo, ‘defvar’ tiene una cadena de documentación.

   (Otra forma especial, ‘defcustom’, está diseñado para variables que
la gente personaliza.  Eso tiene más funcionalidades que ‘defvar’.
(*Note Configurando Variables con ‘defcustom’: defcustom.)

* Menu:

* Mira el valor actual de la variable::  Mira el valor actual de la variable
* defvar y asterisk::        defvar y asterisk


File: emacs-lisp-intro-es.info,  Node: Mira el valor actual de la variable,  Next: defvar y asterisk,  Up: defvar

Mirando el actual valor de una variable
---------------------------------------

Se puede ver el actual valor de una variable, cualquier variable, usando
la función ‘describe-variable’, que es normalmente invocado escribiendo
‘C-h v’.  Si se escribe ‘C-h v’ y ‘kill-ring’ (seguido por <RET>), se
verá que hay en tu anillo de la muerte actual _kill ring_ al ser pulsado
-- ¡esto puede ser bastante tranquilo!  A la inversa, si no has estado
haciendo nada esta sesión en Emacs, excepto leer este documento, se
puede no tener nada dentro.  También, se verá la documentación para
‘kill-ring’:

     Documentación:
     Lista de secuencias de texto muerto (guardado).
     Desde que el (kill ring) se supone que interactua bien con
     cut-and-paste facilita ofrecer por sistemas de ventanas,
     debería usar esta variable
     interactúa bin con `interprogram-cut-function' y
     `interprogram-paste-function'. Las funciones `kill-new',
     `kill-append', y `current-kill' se suponen para implementar esta
     interacción; se puede querer usarlo en vez de manipular en anillo de
     la muerte _kill ring_ directamente.

   El kill ring _anillo de la muerte_ está definido por un ‘defvar’ del
siguiente modo:

     (defvar kill-ring nil
       "Lista de secuencia de textos cortados.
     ...")

En esta definición de variable, la variable es dada un valor inicial de
‘nil’, que tiene sentido, desde que si no se ha guardado nada, no se
quiere nada si se da un comando ‘yank’.  La cadena de documentación es
escrito solo como la cadena de documentación de un ‘defun’.  Como con la
cadena de documentación sería una frase completa, desde que algunos
comandos, como ‘apropos’, imprime solo la primera línea de
documentación.  Las líneas de exito no serían indentadas; de otro modo
se mira cuando se usa ‘C-h v’ (‘describe-variable’).


File: emacs-lisp-intro-es.info,  Node: defvar y asterisk,  Prev: Mira el valor actual de la variable,  Up: defvar

8.5.1 ‘defvar’ y un asterisco
-----------------------------

En el pasado, Emacs usaba la forma especial ‘defvar’ tanto para
variables interna que no esperaría que un usuario cambie y para
variables que espera un usuario cambie.  Aunque se puede todavía usar
‘defvar’ para variables personalizadas, por favor, usa ‘defcustom’ en
vez, desde que la forma especial provee una ruta dentro de los comando
de Personalización.  (*Note Especificando Variables usando ‘defcustom’:
defcustom.)

   Cuando se especifica una variable usando la forma especial ‘defvar’,
se podría distinguir una variable que un usuario podría querer cambiar
desde otros escribiendo, ‘*’, en la primera columna de su cadena de
documentación.  Por ejemplo:

     (defvar shell-command-default-error-buffer nil
       "*Nombre de buffer para `shell-command' ... salir del error.
     ... ")

Tu podrías (y todavía puedes) usar el comando ‘set-variable’ para
cambiar el valor de ‘shell-command-default-error-buffer’ temporalmente.
Sin embargo, las opciones configuradas usando ‘set-variable’ no están
asignadas solo por la duración de tu sesión de edición.  Los nuevos
valores no están guardados entre sesiones.  Cada vez que Emacs empieza,
lee el valor original, a menos que tu cambia el valor con tu fichero
‘.emacs’, si configurándolo manualmente o usando ‘customize’.  *Note Tu
Fichero ‘.emacs’: Inicialización de Emacs.

   Para mí, el mayor uso del comando ‘set-variable’ es sugerir variables
que se podrían querer asignar en mi fichero ‘.emacs’.  Ahora hay más de
700 variables, demasiadas para recordarlas fácilmente.  Afortunadamente,
se puede presionar <TAB> después de llamar al comando ‘M-x set-variable’
para ver la lista de variables.  (*Note Examinando y Configurando
Variables: (emacs)Examinando.)


File: emacs-lisp-intro-es.info,  Node: Revisión de cons y search-fwd,  Next: Buscar ejercicios,  Prev: defvar,  Up: Cortando y almacenando texto

8.6 Revisar
===========

Aquí hay un breve resumen de algunas funciones introducidas
recientemente.

‘car’
‘cdr’
     ‘car’ devuelve el primer elemento de una lista; ‘cdr’ devuelve el
     segundo y subsiguientes elementos de una lista.

     Por ejemplo:

          (car '(1 2 3 4 5 6 7))
               ⇒ 1
          (cdr '(1 2 3 4 5 6 7))
               ⇒ (2 3 4 5 6 7)

‘cons’
     ‘cons’ construye una lista enlazando su primer argumento a su
     segundo argumento.

     Por ejemplo:

          (cons 1 '(2 3 4))
               ⇒ (1 2 3 4)

‘funcall’
     ‘funcall’ evalúa su primer argumento como una función.  Así pasa
     los argumentos que permanecen a su primer argumento.

‘nthcdr’
     Devuelve el resultado de tomar CDR 'n' veces en una lista.  El
     'resto del resto', como estaba

     Por ejemplo:

          (nthcdr 3 '(1 2 3 4 5 6 7))
               ⇒ (4 5 6 7)

‘setcar’
‘setcdr’
     ‘setcar’ cambia el primer elemento de una lista; ‘setcdr’ cambia el
     segundo y subsiguiente elementos de una lista.

     Por ejemplo:

          (setq triple '(1 2 3))

          (setcar triple '37)

          triple
               ⇒ (37 2 3)

          (setcdr triple '("foo" "bar"))

          triple
               ⇒ (37 "foo" "bar")

‘progn’
     Evalúa cada argumento en secuencia y entonces devuelve el valor del
     último.

     Por ejemplo:

          (progn 1 2 3 4)
               ⇒ 4

‘save-restriction’
     Graba siempre que encoger esté en efecto en el búffer, si
     cualquiera, restaura este encogimiento después de evaluar los
     argumentos.

‘search-forward’
     Buscar una cadena, y si la cadena es encontrada, mueve el punto.
     Con una expresión regular, usa algo similar a ‘re-search-forward’.
     (*Note Búsquedas de Expresiones Regulares: Buscar regexp, para una
     explicación de expresiones regulares patrones y búsquedas.)

     ‘search-forward’ y ‘re-search-forward’ tiene cuatro argumentos:

       1. La cadena o la expresión regular para buscar.

       2. Opcionalmente, el límite de la búsqueda.

       3. Opcionalmente, que haces si la búsqueda falla, devuelve ‘nil’
          o un mensaje de error.

       4. Opcionalmente, cuántas veces se puede repetir la búsqueda; si
          es negativa, la búsqueda va hacia atrás.

‘kill-region’
‘delete-and-extract-region’
‘copy-region-as-kill’

     ‘kill-region’ corta el texto entre punto y marca desde el búffer y
     almacena ese texto en el anillo de la muerte _kill ring_, así se
     puede obtener pegándolo.

     ‘copy-region-as-kill’ copia el texto entre punto y marca dentro del
     anillo de la muerte _kill ring_, que se puede obtener pegándolo.
     La función no corta o borra el texto desde el búffer.

   ‘delete-and-extract-region’ elimina el texto entre el punto y marca
desde el búffer y a través.  No se puede volver.  Esto no es un comando
interactivo.)


File: emacs-lisp-intro-es.info,  Node: Buscar ejercicios,  Prev: Revisión de cons y search-fwd,  Up: Cortando y almacenando texto

8.7 Buscando ejercicios
=======================

   • Escribe una función interactiva que busca una cadena.  Si la
     búsqueda encuentra la cadena, deja el punto después y muestra un
     mensaje que dice "¡Encontrado!".  (No use ‘search-forward’ como
     nombre de esta función; si se hace, se sobreescribirá la versión
     existente ‘search-forward’ que viene con Emacs.  Use un nombre tal
     como ‘test-search’ en vez de eso.

   • Escribe una función que imprime el tercer elemento del kill ring
     _anillo de la muerte_ en el área echo, si cualquiera; si el kill
     ring _anillo de la muerte_ no contiene un tercer elemento, imprime
     un mensaje apropiado.


File: emacs-lisp-intro-es.info,  Node: Implementación de listas,  Next: Pegando,  Prev: Cortando y almacenando texto,  Up: Top

9 Cómo las listas se implementan
********************************

En Lisp, los átomos se graban de manera simple, si la implementación no
es sencilla en la práctica, no es, nada sencilla en la teoría.  El átomo
‘rosa’, por ejemplo, se graba como las cuatro letras contiguas ‘r’, ‘o’,
‘s’, ‘a’.  Una lista, por otro lado, se guarda de manera diferente.  El
mecanismo es igualmente simple, pero toma un momento para tener usada la
idea.  Una lista se guarda usando una serie de pares de punteros.  En
las series, el primer puntero en cada par de puntos a un átomo o a otra
lista, y el segundo puntero en cada par al siguiente par, o al símbolo
‘nil’, que marca el fin de la lista.

   Un puntero por sí mismo es poco simple a la dirección electrónica de
la que está apuntada.  Aquí, una lista se guarda como una serie de
direcciones electrónicas.

* Menu:

* Listas diagramadas::       Listas diagramadas
* Símbolos como cajas::  Explorando una metáfora poderosa.
* Ejercicio Lista::          Ejercicio Lista


File: emacs-lisp-intro-es.info,  Node: Listas diagramadas,  Next: Símbolos como cajas,  Up: Implementación de listas

Listas diagramadas
==================

Por ejemplo, la lista ‘(rosa violeta botóndeoro)’ tiene tres elementos,
‘rosa’, ‘violeta’, y ‘botóndeoro’.  En el ordenador, la dirección
electrónica de ‘rosa’ se graba en un segmento de memoria del ordenador a
través de la dirección que da la dirección electrónica de donde el átomo
‘violeta’ está localizado; y esta dirección (la que cuenta donde
‘violeta’ está se localiza) se guarda con una dirección que cuenta donde
la dirección para el átomo ‘botóndeoro’ se localiza.

   Esto parece más complicado de lo que es y es más fácil visto en un
diagrama:

         ___ ___      ___ ___      ___ ___
        |___|___|--> |___|___|--> |___|___|--> nil
          |            |            |
          |            |            |
          ---> rosa    ---> violeta ---> botóndeoro


En el diagrama, cada caja representa una palabra de memoria del
ordenador que maneja un objeto Lisp, normalmente en la forma de una
dirección de memoria.  Las cajas, por ej.  las direcciones, están en
pares.  Cada flecha apunta a lo que la dirección es la dirección de, si
un átomo u otro par de direcciones.  La primera caja es la dirección
electrónica de ‘rosa’ y la flecha apunta a ‘rosa’; la segunda caja es la
dirección del siguiente par de cajas, la primera parte de la que es la
dirección de ‘violeta’ y la segunda parte es la dirección del siguiente
par.  La última caja apunta al símbolo ‘nil’, que marca el fin de la
lista.

   Cuando una variable es configurado a una lista con una función tal
como ‘setq’, almacena la dirección de la primera caja en la variable.
De este modo, la evaluación de la expresión es:

     (setq ramo '(rosa violeta botóndeoro))

crea una situación como esta:

     ramo
          |
          |     ___ ___      ___ ___      ___ ___
           --> |___|___|--> |___|___|--> |___|___|--> nil
                 |            |            |
                 |            |            |
                  --> rosa     --> violeta   --> botóndeoro


En este ejemplo, el símbolo ‘ramo’ maneja la dirección del primer par de
cajas.

   Esta misma lista puede ser ilustrada en un modo diferente de
anotación de cajas como esta:

     ramo
      |
      |    --------------       ----------------       --------------------
      |   | car   | cdr  |     | car     | cdr  |     | car         | cdr  |
       -->| rosa  |   o------->| violeta |   o------->| botóndeoro |  nil |
          |       |      |     |         |      |     |             |      |
           --------------       ----------------       --------------------


   (Los símbolos consisten de más pares de direcciones, pero la
estructura de un símbolo es hecha de direcciones.  De manera profunda,
el símbolo ‘ramo’ consiste de un grupo de cajas-de-direcciones, una que
es la dirección de la palabra impresa ‘ramo’, una segunda de la que es
la dirección de una definición de función adjunta al símbolo, si
cualquiera, un tercero del que es la dirección del primer par de
cajas-de-direccion para la lista ‘(rosa violeta botóndeoro)’, y así.
Aquí se está mostrando que la tercera caja de dirección del símbolo
apunta al primer par de cajas-de-direccion para la lista.)

   Si un símbolo se asigna al CDR de una lista, la lista en sí no
cambia; el símbolo simplemente tiene una dirección abajo de la lista.
(En la jerga, CAR y CDR son 'no destructivos'.)  De este modo, se evalúa
la siguiente expresión

     (setq flores (cdr ramo))

produce esto:


     ramo        flores
       |              |
       |     ___ ___  |     ___ ___      ___ ___
        --> |   |   |  --> |   |   |    |   |   |
            |___|___|----> |___|___|--> |___|___|--> nil
              |              |            |
              |              |            |
               --> rosa       --> violeta  --> botóndeoro



El valor de ‘flores’ es ‘(violeta botóndeoro)’, esto es decir que el
símbolo ‘flores’ maneja la dirección del par address-boxes el primero
que maneja la dirección de ‘violeta’, y el segundo que maneja la
dirección de ‘botóndeoro’.

   Un par de cajas-de-direcciones se llama una “cons cell” o “par de
puntos”.  *Note la Célula Cons y los Tipos Lista: (elisp)Tipo de Célula
Cons, y *note Notación de Pares de Puntos: (elisp)Notación de Pares de
Puntos, para más información acerca de células cons y pares de puntos.

   La función ‘cons’ añade un nuevo par de direcciones al frente de una
serie de direcciones como son mostradas debajo.  Por ejemplo, evaluando
la expresión

     (setq ramo (cons 'lila ramo))

produce:


     ramo                       flores
       |                             |
       |     ___ ___        ___ ___  |     ___ ___       ___ ___
        --> |   |   |      |   |   |  --> |   |   |     |   |   |
            |___|___|----> |___|___|----> |___|___|---->|___|___|--> nil
              |              |              |             |
              |              |              |             |
               --> lila      --> rosa       --> violeta    --> botóndeoro



Sin embargo, esto no cambia el valor del símbolo ‘flores’, así puedes
ver evaluando lo siguiente,

     (eq (cdr (cdr ramo)) flores)

que devuelve ‘t’ para verdad.

   Hasta que se resetea, ‘flores’ todavía tiene el valor de ‘(violeta
botóndeoro)’; que es, eso tiene la dirección de la celula cons cuya
primera dirección es ‘violeta’.  También, esto no altera cualquier
célula prexistente cons; ellas está todavía allí.

   De este modo, en Lisp, tiene el CDR de una lista, se obtiene la
dirección del siguiente cons en las serie; para tener el CAR de una
lista, se obtiene la dirección del primer elemento de la lista; para
‘cons’ un nuevo elemento en una lista, se añade una nueva célula cons al
frente de la lista.  ¡Esto es todo lo que hay así!  ¡La estructura
subyacente de Lisp es brillantemente simple!

   ¿Y qué hace la última dirección en una serie de células cons se
refieren?  Eso es la dirección de la lista vacía, de ‘nil’.

   En resumen, cuando una variable Lisp es asignada a un valor, eso
provee con la dirección de la lista a la que la variable se refiere.


File: emacs-lisp-intro-es.info,  Node: Símbolos como cajas,  Next: Ejercicio Lista,  Prev: Listas diagramadas,  Up: Implementación de listas

9.1 Símbolos como una caja con cajones
======================================

En una sección temprana, se sugería que se podría imaginar un símbolo
siendo una caja con cajones.  La definición de función se pone en un
cajón, el valor en otro, y así.  Lo que se pone en el cajón maneja el
valor que puede cambiarse sin afectar a los contenidos del cajón
manejando la definición de función, y viceversa.

   Actualmente, lo que está puesto en cada cajón es la dirección del
valor o definición de función.  Eso es como si se encontrara un viejo
cajón en el ático, y en uno de sus cajones se encontrara un mapa dándote
direcciones a donde está el tesoro escondido.

   (Además de su nombre, la definición del símbolo, y un valor de la
variable, un símbolo tiene un 'cajón' para una “lista de propiedades”
que puede ser usada para grabar otra información.  Las listas de
propiedades no se discuten aquí; ver *note Listas de Propiedades:
(elisp)Listas de Propiedades.)

   Aquí hay una representación visionaria:


                 Caja de Cajones            Contenidos de Cajones

                 __   o0O0o   __
               /                 \
              ---------------------
             |    direcciones al   |            [mapeo a]
             | nombre del simbolo  |             ramo
             |                     |
             +---------------------+
             |  direcciones a la   |
             |  definición del   |             [nunca]
             |    simbolo          |
             +---------------------+
             |    direcciones al   |            [mapeo a]
             |   valor de variable |       (rosa violeta botóndeoro)
             |                     |
             +---------------------+
             |    direcciones a la |
             |lista de propiedades |             [no descrito aquí]
             |                     |
             +---------------------+
             |/                   \|




File: emacs-lisp-intro-es.info,  Node: Ejercicio Lista,  Prev: Símbolos como cajas,  Up: Implementación de listas

9.2 Ejercicio
=============

Asignar ‘flores’ a ‘violeta’ y ‘botóndeoro’.  Asigna dos flores más en
esta lista y asigna esta nueva lista a ‘mas-flores’.  Asigna el CAR de
‘flores’ a un pez.  ¿Qué lista contiene ahora ‘mas-flores’?


File: emacs-lisp-intro-es.info,  Node: Pegando,  Next: Bucles y recursión,  Prev: Implementación de listas,  Up: Top

10 Pegando texto
****************

Siempre y cuando se corta texto fuera de un búffer con un comando 'kill'
en GNU Emacs, se puede traer con un comando 'pegar'.  El texto cortado
del búffer es puesto en el anillo de la muerte y en los comandos pegar,
se insertan los contenidos apropiados del kill ring detrás de un búffer
(no necesariamente el búffer original).

   Un simple comando ‘C-y’ (‘yank’) inserta el primer ítem desde el
anillo de la muerte _kill ring_ dentro del actual búffer.  Si el comando
‘C-y’ es seguido inmediatamente para ‘M-y’, el primer elemento se
reemplaza por el segundo elemento.  Los sucesivos comandos ‘M-y’
reemplazan el segundo elemento con el tercer, cuarto, o quinto elemento,
y así.  Cuando se llega al último elemento en el anillo de la muerte
_kill ring_, se reemplaza por el primer elemento y el ciclo se repite.
(De este modo, el kill ring se llama un 'anillo' en vez de solo una
'lista'.  Sin embargo, la estructura de de datos actual que maneja el
texto es una lista.  *Note Manejando el anillo de la muerte _kill ring_:
Qué hace el anillo de la muerte, para los detalles de cómo la lista es
manejada como un anillo.)

* Menu:

* Resumen del anillo de la muerte::  Resumen del anillo de la muerte
* kill-ring-yank-pointer::   El anillo de la muerte es una lista.
* pegar Ejercicio nthcdr::   La variable ‘kill-ring-yank-pointer’.


File: emacs-lisp-intro-es.info,  Node: Resumen del anillo de la muerte,  Next: kill-ring-yank-pointer,  Up: Pegando

10.1 Resumen del anillo de la muerte
====================================

El anillo de la muerte _kill ring_ es una lista de cadenas textuales.
Esto es lo que se ve:

     ("algún texto" "una pieza diferente pieza de texto"
     "todavía más texto")

   Si estos fueran los contenidos de mi anillo de la muerte _kill ring_
y yo presionara ‘C-y’, la cadena de caracteres diciendo ‘algún texto’
sería insertado en este búffer donde mi cursor está localizado.

   El comando ‘yank’ _pegar_ es también usado para duplicar texto
copiándolo.  El texto copiado no es cortado desde el búffer, pero una
copia de eso se pone en el anillo de la muerte _kill ring_ y se inserta
pegándolo.

   Tres funciones se usan para atraer texto desde el anillo de la muerte
_kill ring_: ‘yank’ (_pegar_), que normalmente se asocian a ‘C-y’;
‘yank-pop’, que normalmente se asocia a ‘M-y’; y ‘rotate-yank-pointer’,
que se usa por las otras dos funciones.

   Estas funciones se refieren al kill ring _anillo de la muerte_ a
través de una variable llamada el ‘kill-ring-yank-pointer’.  En vez de
eso, la inserción del código para ambos son las funciones ‘yank’ y
‘yank-pop’:

     (insert (car kill-ring-yank-pointer))

(Bien, no más.  En GNU Emacs 22, la función se ha reemplazado por
‘insert-for-yank’ que llama a ‘insert-for-yank-1’ repetitivamente para
cada segmento ‘yank-handler’.  En vez de eso, ‘insert-for-yank-1’
destituye las propiedades de texto desde el texto insertado de acuerdo a
‘yank-excluded-properties’.  De otro modo, eso es como ‘insert’.
Nosotros lo pegamos con un ‘insert’ plano puesto que sea fácil de
comprender.)

   Para empezar a comprender cómo ‘yank’ y ‘yank-pop’ funcionan, primero
es necesario mirar en la variable ‘kill-ring-yank-pointer’.


File: emacs-lisp-intro-es.info,  Node: kill-ring-yank-pointer,  Next: pegar Ejercicio nthcdr,  Prev: Resumen del anillo de la muerte,  Up: Pegando

10.2 La variable ‘kill-ring-yank-pointer’
=========================================

‘kill-ring-yank-pointer’ es una variable, solo como ‘kill-ring’ es una
variable.  Eso apunta a alguna cosa siendo asignada al valor de lo que
apunta, como cualquier otra variable Lisp.

   De este modo, si el valor del kill ring es:

     ("algún texto" "una pieza diferente pieza de texto"
     "todavía más texto")

y el ‘kill-ring-yank-pointer’ apunta a la segunda cláusula, el valor de
‘kill-ring-yank-pointer’ es:

     ("una pieza diferente de texto" "todavía más texto")

   Como se explica en el capítulo previo (*Note Implementación de
listas::), el ordenador no guarda dos copias diferentes del texto siendo
apuntado por ambos el ‘kill-ring’ (el _anillo de la muerte_) y el
‘kill-ring-yank-pointer’ (el _puntero de pegar el anillo de la muerte_).
Las palabras "una pieza diferente de texto" y "todavía más texto" no
están duplicadas.  En vez de eso, las dos variables Lisp apuntan a las
mismas piezas de texto.  Aquí hay un diagrama:

     kill-ring     kill-ring-yank-pointer
         |               |
         |      ___ ___  |     ___ ___      ___ ___
          ---> |   |   |  --> |   |   |    |   |   |
               |___|___|----> |___|___|--> |___|___|--> nil
                 |              |            |
                 |              |            |
                 |              |             --> "todavía más texto"
                 |              |
                 |               --> "una pieza diferente de texto"
                 |
                  --> "algo de texto"



   Tanto la variable ‘kill-ring’ y la variable ‘kill-ring-yank-pointer’
son punteros.  Pero el kill ring _anillo de la muerte_ en sí es
normalmente descrito como si fuera actualmente de lo que está compuesto.
El ‘kill-ring’ se refiere a lo que es la lista en vez de lo que apunta a
la lista.  Conversando, el ‘kill-ring-yank-pointer’ se refiere a como se
apunta a una lista.

   Estas dos maneras hablar acerca de la misma cosa suena confuso al
principio pero tiene sentido para reflexionar.  El kill ring _anillo de
la muerte_ es generalmente pensado como la estructura completa de datos
que manejan la información de lo que se ha cortado reciéntemente de los
búffers de Emacs.  El ‘kill-ring-yank-pointer’ en la otra mano, sirve
para indicar -- que es, para 'apuntar a' -- esta parte del anillo de la
muerte del que el primer elemento (el CAR) será insertado.


File: emacs-lisp-intro-es.info,  Node: pegar Ejercicio nthcdr,  Prev: kill-ring-yank-pointer,  Up: Pegando

10.3 Ejercicios con ‘yank’ y ‘nthcdr’
=====================================

   • Usando ‘C-h v’ (‘describe-variable’), mira en el valor de tu kill
     ring _anillo de la muerte_.  Añade varios ítems a tu anillo de la
     muerte _kill ring_; mira en su valor de nuevo.  Usando ‘M-y’
     (‘yank-pop’, mueve todo el camino alrededor del kill ring _anillo
     de la muerte_.  ¿Cuántos ítems estaban en tu kill ring _anillo de
     la muerte_?  Encuentra el valor de ‘kill-ring-max’.  ¿Estaba tu
     anillo de la muerte _kill ring_ completo, o podrías haber guardado
     más bloques de texto dentro?

   • Usando ‘nthcrd’ y ‘car’, construye una serie de expresiones para
     devolver, el primer, segundo, tercer y cuarto elemento de una
     lista.


File: emacs-lisp-intro-es.info,  Node: Bucles y recursión,  Next: Buscar regexp,  Prev: Pegando,  Up: Top

11 Bucles y recursión
*********************

Emacs Lisp tiene dos caminos primarios para causar una expresión, o una
serie de expresiones, para ser evaluado repetidamente: uno usa un bucle
‘while’, y el otro usa “recursión”.

   La repetición puede ser valorable.  Por ejemplo, para mover hacia
delante cuatro frases, tu solo necesitas escribir un programa que moverá
hacia delante una frase y entonces repite el proceso cuatro veces.  Ya
que un ordenador no está aburrido o cansado, tal acción repetitiva no
tiene los efectos de borrado por equivocación o exceso que pueden tener
los humanos.

   La gente mayoritariamente escribe funciones de Emacs Lisp usando
bucles ‘while’; pero se puede usar recursión, que provee un poderoso
camino mental para resolver problemas(1).

* Menu:

* while::                    Causando un cierto código para repetir.
* Dolist y dotimes::         Dolist y dotimes
* Recursión::              Causando que una función se llame a
                               sí misma.
* Ejercicio de Bucle::       Ejercicio de Bucle

   ---------- Footnotes ----------

   (1) Se pueden escribir funciones recursivas para ser frugal o basura
mental o recursos de ordenador; como eso ocurre, los métodos que la
gente encuentra fáciles -- son frugales de 'recursos mentales' --
algunas veces usan recursos de ordenador considerables.  Emacs fué
diseñado para ejecutarse en máquinas que ahora se consideran limitadas y
sus configuraciones por defecto son conservadoras.  Se puede querer
incrementar los valores de ‘max-specdl-size’ y ‘max-lisp-eval-depth’.
En mi fichero ‘.emacs’, yo los asigno a 15 o 30 veces su valor por
defecto.


File: emacs-lisp-intro-es.info,  Node: while,  Next: Dolist y dotimes,  Up: Bucles y recursión

11.1 ‘while’
============

La forma especial ‘while’ chequea si el valor devuelto para evaluar el
primer argumento es verdadero o falso.  Esto es parecido a lo que el
intérprete Lisp hace con un ‘if’; el intérprete hace lo siguiente, sin
embargo, es diferente.

   En una expresión ‘while’, si el valor devuelto por evaluar el primer
argumento es falso, el intérprete Lisp descarta el resto de la expresión
(el “cuerpo” de la expresión) y no la evalúa.  Sin embargo, si el valor
es cierto, el intérprete Lisp evalúa el cuerpo de la expresión y
entonces de nuevo chequea si el primer argumento para ‘while’ es cierto
o falso.  Si el valor devuelto de evaluar el primer argumento es cierto
de nuevo, el intérprete Lisp evalúa el cuerpo de la expresión.

   La plantilla para una expresión ‘while’ se ve así:

     (while TEST-VERDADERO-O-FALSO
       CUERPO...)

* Menu:

* Bucles while::             Repetir tantas veces como el test devuelva
                               verdadero.
* Ejemplo de bucle::         Un bucle ‘while’ que usa una lista.
* print-elements-of-list::   Usos ‘while’, ‘car’, ‘cdr’.
* Incrementando el Bucle::   Un bucle con un contador de incremento.
* Incrementando los detalles de los bucles::  Incrementando los detalles de
                                                los bucles
* Bucle que se decrementa::  Un bucle con un decrementando contador.


File: emacs-lisp-intro-es.info,  Node: Bucles while,  Next: Ejemplo de bucle,  Up: while

Bucles con ‘while’
------------------

En el momento en el que el true-or-false-test de la expresión ‘while’
devuelve un valor cierto cuando eso se evalúa, el cuerpo es
repetidamente evaluado.  Este proceso se llama bucle puesto que el
intérprete Lisp repite la misma cosa una y otra vez, como un avión
haciendo un loop.  Cuando el resultado de evaluar el true-or-false-test
es falso, el intérprete Lisp no evalúa el resto de la expresión ‘while’
y 'existe el bucle'.

   Claramente, si el valor devuelto evaluando el primer argumento para
‘while’ es siempre cierto, el cuerpo siguiente será evaluado una y otra
vez ... y ... para siempre.  Recíprocamente, si el valor devuelto nunca
es cierto, las expresiones en el cuerpo nunca serán evaluadas.  La
fortaleza de escribir un bucle ‘while’ consiste de elegir un mecanismo
tal que el true-or-false-test devuelva cierto solo el número de veces
que requieren las subsiguientes expresiones para ser evaluadas, y
entonces tener el test devuelto a falso.

   El valor devuelto evaluando ‘while’ es el valor del
true-or-false-test.  Una consecuencia interesante de esto es que un
bucle ‘while’ que evalúa sin errores devolverá ‘nil’ o falso sin
dignidad de si eso ha girado 1 o 100 veces o ninguna.  ¡Una expresión
‘while’ que se evalúa de manera exitosa nunca devuelve un valor cierto!
Lo que esto significa es que ‘while’ es siempre evaluado por sus efectos
laterales, que es decir, las consecuencias de evaluar las expresiones
con el cuerpo del bucle ‘while’.  Esto tiene sentido.  Eso no es el mero
acto del bucle que es deseado, pero las consecuencias de lo que ocurre
cuando las expresiones en el bucle son repetidamente evaluadas.


File: emacs-lisp-intro-es.info,  Node: Ejemplo de bucle,  Next: print-elements-of-list,  Prev: Bucles while,  Up: while

11.1.1 Un bucle ‘while’ y una lista
-----------------------------------

Un camino común para controlar un bucle ‘while’ es chequear si una lista
tiene cualquier elemento.  Si eso se hace, el bucle se repite; pero si
no, la repetición se finaliza.  Puesto que esto es una técnica
importante, se creará un breve ejemplo para ilustrarlo.

   Un camino simple para chequear si una lista tiene elementos es
evaluar la lista: si eso no tiene elementos, si es una lista vacía y
devuelve la lista vacía, ‘()’, que es un sinónimo para ‘nil’ o falso.
Por otro lado, una lista con elementos devolverá estos elementos cuando
eso se evalúa.  Puesto que Emacs Lisp considera como cierto cualquier
valor que no es ‘nil’, una lista que devuelve elementos chequeará cierto
en un bucle ‘while’.

   Por ejemplo, se puede asignar la variable ‘empty-list’ a ‘nil’ para
evaluar la siguiente expresión ‘setq’:

     (setq lista-vacia ())

Después de evaluar la expresión ‘setq’, se puede evaluar la variable
‘lista-vacia’ es el camino normal, posicionando el cursor después del
símbolo y escribiendo ‘C-x C-e’; ‘nil’ aparecerá en tu área echo:

     lista-vacia

   Por otro lado, si se asigna una variable para ser una lista con
elementos, la lista aparecerá cuando se evalúe la variable, como se
puede ver evaluando las siguientes dos expresiones:

     (setq animales '(gacela jirafa leon tigre))

     animales

   De este modo, para un bucle ‘while’ que chequea si hay cualquier ítem
en la lista ‘animales’, la primera parte del bucle será escrito así:

     (while animales
            ...

Cuando el ‘while’ chequea su primer argumento, la variable ‘animales’ se
evalúa.  Eso devuelve una lista.  Mientras la lista tiene elementos, el
‘while’ considera los resultados del test para ser verdadero; pero
cuando la lista es vacía, eso considera los resultados del test para ser
falso.

   Para prevenir que el bucle ‘while’ se ejecute siempre, se necesita
proporcionar algún mecanismo.  Una técnica usada con frecuencia es tener
una de las subsiguientes formas en la expresión ‘while’ que asigna el
valor de la lista para ser el CDR de la lista.  Cada vez que la función
‘cdr’ se evalúa, se va reduciendo, hasta que finalmente solo queda la
lista vacía.  En este punto, el test del bucle ‘while’ devolverá falso,
y los argumentos para el ‘while’ no se evaluarán.

   Por ejemplo, la lista de animales asociada a la variable ‘animals’ se
puede asignar a ser el CDR de la lista original con la siguiente
expresión:

     (setq animals (cdr animals))

Si se han evaluado las expresiones previas y entonces se evalúa esta
expresión, se verá ‘(jirafa leon tigre)’ que aparecerá en el área echo.
Si se evalúa la expresiń de nuevo, ‘(leon tigre)’ aparecerá en el área
echo.  Si se evalúa de nuevo, ‘(tigre)’ y todavía de nuevo aparecerá la
lista vacía y se mostrará como ‘nil’.

   Una plantilla para un bucle ‘while’ usa la función ‘cdr’
repetidamente para causar el true-or-false-test finalmente para chequear
la veracidad y se parece a esto:

     (while TEST-WHETHER-LIST-IS-EMPTY
       BODY...
       SET-LIST-TO-CDR-OF-LIST)

   Este chequeo y uso de ‘cdr’ puede ser puesto junto a una función que
va a través de una lista e imprime cada elemento de la lista en una
línea de sí misma.


File: emacs-lisp-intro-es.info,  Node: print-elements-of-list,  Next: Incrementando el Bucle,  Prev: Ejemplo de bucle,  Up: while

11.1.2 Un ejemplo: ‘imprimir-elementos-de-la-lista’
---------------------------------------------------

La función ‘imprimir-elementos-de-la-lista’ ilustra un bucle ‘while’ con
una lista.

   La función requiere varias líneas por su salida.  Si estás leyendo
esto en una instancia reciente de GNU Emacs, se puede evaluar la
siguiente expresión dentro de Info, de normal.

   Si se está usando una versión antigua de Emacs, es necesario copiar
las expresiones necesarias para el búffer ‘*scratch*’ y evaluarlas allí.
Esto es porque el área echo tenía solo una línea en las versiones
antiguas.

   Se pueden copiar las expresiones marcando el principio de la región
con ‘C-<SPC>’ (‘set-mark-command’), moviendo el cursor al fin de la
región y entonces copiando la región usando ‘M-w’ (‘kill-ring-save’, que
llama a ‘copy-region-as-kill’ y entonces provee realimentación visual).
En el búffer ‘*scratch*’, se pueden copiar las expresiones escribiendo
‘C-y’ (‘yank’).

   Después de haber copiado las expresiones al búffer ‘*scratch*’, se
evalúa cada expresión en orden.  Asegúrese de evaluar la última
expresión, ‘(imprimir-elementos-de-la-lista animales)’, escribiendo ‘C-u
C-x C-e’, que es, dando un argumento para ‘eval-last-sexp’.  Esto
causará el resultado de la evaluación para ser impreso en el búffer
‘*scratch*’ en vez de siendo impreso en el área echo.  (De otro modo se
verá alguna cosa como esto en tu área echo:
‘^Jgacela^J^Jjirafa^J^Jleon^J^Jtigre^Jnulo’, en cada ‘^J’ se estructura
una 'nueva línea'.)

   En una instancia de GNU Emacs reciente, se pueden evaluar estas
expresiones directamente en el búffer Info, y el área echo crecerá para
mostrar los resultados.

     (setq animales '(gacela jirafa leon tigre))

     (defun imprimir-elementos-de-la-lista (list)
       "Imprime cada elemento de LIST en una línea."
       (while list
         (print (car list))
         (setq list (cdr list))))

     (imprimir-elementos-de-la-lista animales)

Cuando se evalúan las tres expresiones en secuencia, se verá esto:

     gacela

     jirafa

     leon

     tigre
     nil

   Cada elemento de la lista se imprime en una línea en sí (que es lo
que la función ‘print’ hace) y entonces el valor devuelto por la función
se imprime.  Desde que la última expresión en la función es el bucle
‘while’, y desde que el bucle ‘while’ siempre devuelve ‘nil’, un ‘nil’
se imprime después del último elemento de la lista.


File: emacs-lisp-intro-es.info,  Node: Incrementando el Bucle,  Next: Incrementando los detalles de los bucles,  Prev: print-elements-of-list,  Up: while

11.1.3 Un bucle con un contaje incremental
------------------------------------------

Un bucle no es útil a menos que pare cuando debe.  Bajo el control de un
bucle con una lista, un camino común de parar un bucle es escribir el
primer argumento como un test que devuelve falso cuando el número
correcto de repeticiones es completo.  Esto significa que el bucle debe
tener un contador -- una expresión que cuenta cuántas veces el bucle se
repite a sí mismo.


File: emacs-lisp-intro-es.info,  Node: Incrementando los detalles de los bucles,  Next: Bucle que se decrementa,  Prev: Incrementando el Bucle,  Up: while

Detalles de un bucle que se incrementa
--------------------------------------

El test para un bucle con un contador de incremento puede ser una
expresión tal como ‘(< contador numero-deseado)’ que devuelve ‘t’ para
verdad si el valor de ‘contador’ es menor que el ‘numero-deseado’ de
repeticiones y ‘nil’ para falso si el valor de ‘contador’ es igual a o
es mayor que el ‘numero-deseado’.  La expresión que incrementa el
contador puede ser un simple ‘setq’ tal como ‘(setq contador (1+
contador))’, donde ‘1+’ es una función construida en Emacs Lisp que
añade 1 a su argumento.  (La expresión ‘(1+ contador)’ tiene el mismo
resultado que ‘(+ contador 1)’, que es fácil de leer para un humano.)

   La plantilla para un bucle ‘while’ controlado por un contador que se
incrementa se parece a esto:

     ASIGNAR-CONTADOR-AL-VALOR-INICIAL
     (while (< contador numero-deseado)         ; true-or-false-test
       BODY...
       (setq contador (1+ contador)))              ; incremento

Note que se necesita asignar el valor inicial de ‘contador’; normalmente
asignado a 1.

* Menu:

* Ejemplo de Incremento::    Contando esquinas en un triángulo.
* Partes Inc de Ejemplo::    Las partes de la definición de función.
* Ejemplo Inc junto::        Poniendo la definición de función junta.


File: emacs-lisp-intro-es.info,  Node: Ejemplo de Incremento,  Next: Partes Inc de Ejemplo,  Up: Incrementando los detalles de los bucles

Ejemplo con contador incremental
................................

Supón que estás jugando en la playa y decides crear un triángulo de
asteriscos, poniendo un asterisco en la primera fila, dos en la segunda
fila, tres en la tercera fila y así:


                    *
                   * *
                  * * *
                 * * * *

(Hace 2500 años, Pitágoras y otras desarrollaron los principios de la
teoría de números considerando preguntas como esta.)

   Supón que quieres saber cuántos asteriscos necesitarás crear para un
triángulo con 7 filas

   Claramente, lo que necesitas hacer es añadir los números de 1 a 7.
Hay dos caminos para hacer esto; se puede comenzar con los números más
pequeños, uno, y añadir la lista en secuencia, 1, 2, 3, 4 y así; o
empieza con el número más largo y añade la lista bajando: 7, 6, 5, 4 y
así.  Porque ambos mecanismos ilustran caminos comunes de escribir el
bucle ‘while’, crearemos dos ejemplos, uno contando hacia arriba y el
otro contando hacia abajo.  En este primer ejemplo, empezaremos con 1 y
añadimos 2, 3, 4 y así.

   Si se quiere sumar toda una lista de números, el camino más fácil
para hacer eso es sumar todos los números a la vez.  Sin embargo, si no
se sabe cuántos números tendrá la lista, o si se requiere estar
preparado para una lista muy larga, entonces se necesita diseñar la
adición, esto es, repetir un proceso simple muchas veces en vez de hacer
un proceso más complejo.

   Por ejemplo, en vez de añadir todos los asteriscos a la vez, lo que
se puede hacer es añadir el número de asteriscos en la primera fila, 1,
para el número en la segunda fila, 2, y entonces añadir el total de
estas dos filas a la tercera fila, 3.  Entonces se puede añadir el
número en la cuarta fila, 4, al total de las primeras tres filas; y así.

   La característica crítica del proceso es que cada acción repetitiva
sea simple.  En este caso, en cada paso nosotros añadimos solo dos
números, el número de asteriscos en la fila y el total ya encontrado.
Este proceso de añadir dos números es repetido de nuevo y de nuevo hasta
la última fila que ha sido añadida al total de todas las filas
precedentes.  En un bucle más complejo la acción repetitiva podría no
ser tan simple, pero será tan simple como hacer todo a la vez.


File: emacs-lisp-intro-es.info,  Node: Partes Inc de Ejemplo,  Next: Ejemplo Inc junto,  Prev: Ejemplo de Incremento,  Up: Incrementando los detalles de los bucles

Las partes de la definición de función
......................................

El análisis precedente nos da los bonos de nuestra definición de
función: primero, necesitaremos una variable que podemos llamar ‘total’
que será el número total de asteriscos.  Esto será el valor devuelto por
la función.

   Segundo, sabemos que la función requerirá un argumento: este
argumento será el número de filas en el triángulo.  Eso puede llamarse
‘number-of-rows’.

   Finalmente, se necesita una variable para usarse como contador.  Se
podría llamar a esta variable ‘counter’, pero un nombre mejor es
‘row-number’.  Debido a que lo que el contador hace en esta función es
contar filas, y un programa debería escribirse para ser comprendido en
la medida de lo posible.

   Cuando el intérprete Lisp primero empieza evaluando las expresiones
de la función, el valor de ‘total’ estaría asignado a cero, ya que no
hemos añadido cualquier cosa a eso.  Entonces la función añadiría el
número de asteriscos en la primera fila al total, y entonces añade el
número de asteriscos en la segunda al total, y entonces añade el número
de asteriscos a la tercera fila al total, y así, hasta que no hay más
filas a la izquierda para añadir.

   Ambos ‘total’ y ‘row-number’ se usan solo dentro de la función, así
ellos pueden ser declarados como variables locales con ‘let’ y valores
iniciales dados.  Claramente, el valor inicial para total sería 0.  El
valor inicial de ‘row-number’ sería 1, desde que se comienza con la
primera fila.  Esto significa que la frase ‘let’ se parece a esto:

       (let ((total 0)
             (row-number 1))
         BODY...)

   Después de que las variables internas se declaran y se asignan a sus
valores iniciales se podría empezar el bucle ‘while’.  La expresión que
sirve como el test devolvería un valor de ‘t’ para la verdad tan grande
como el ‘row-number’ que es menor o igual al ‘number-of-rows’.  (La
expresión devuelve cierto solo si el número de fila es menor que el
número de filas en el triángulo, la última fila nunca será añadida al
total; aquí el número de fila tiene que ser menor o igual el número de
filas.))

   Lisp provee la función ‘<=’ que devuelve cierto si el valor de su
primer argumento es menor o igual al valor de su segundo argumento y
falso de otro modo.  Así la expresión que el ‘while’ evaluará como si su
test se vería como esto:

     (<= row-number number-of-rows)

   El número de asteriscos puede encontrarse repetidamente añadiendo el
número de asteriscos en una fila al total ya encontrado.  Puesto que el
número de asteriscos en la fila es igual al número de la fila, el total
puede encontrarse añadiendo el número de filas al total.  (Claramente,
en una situación más compleja, el número de asteriscos en la fila podría
ser relacionada al número de la fila en un camino más complicado; si
este fuera el caso, el número de fila sería reemplazado por la expresión
apropiada.)

     (setq total (+ total row-number))

Lo que esto hace es asignar el nuevo valor de ‘total’ a ser igual a la
suma de añadiendo el número de asteriscos en la fila al total previo.

   Después de configurar el valor de ‘total’, las condiciones deben ser
establecidas para la siguiente repetición del bucle, si hay alguna.
Esto se hace incrementando el valor de la variable ‘row-number’, que
sirve como un contador.  Después que la variable ‘row-number’ ha sido
incrementada, el true-or-false-test al principio del bucle ‘while’
chequea si su valor es todavía menor o igual al valor del
‘number-of-rows’ y si eso es, añade el nuevo valor de la variable
‘row-number’ al ‘total’ de la repetición del bucle.

   La función construida en Emacs Lisp ‘1+’ añade 1 a un número, así la
variable ‘row-number’ puede ser incrementado con esta expresión:

     (setq row-number (1+ row-number))


File: emacs-lisp-intro-es.info,  Node: Ejemplo Inc junto,  Prev: Partes Inc de Ejemplo,  Up: Incrementando los detalles de los bucles

Poniendo la definición de la función junta
..........................................

Nosotros hemos creado las partes para la definición de la función; ahora
necesitamos ponerlas juntas.

   Primero, los contenidos de la expresión ‘while’:

     (while (<= row-number number-of-rows)   ; true-or-false-test
       (setq total (+ total row-number))
       (setq row-number (1+ row-number)))    ; incremento

   Tener la expresión ‘let’ de varlist, se acerca a completar el cuerpo
de la definición de función.  Sin embargo, eso requiere un elemento
final, la necesidad para la que es alguna cosa pequeña.

   El toque final es emplazar la variable ‘total’ en una línea por sí
misma después de la expresión ‘while’.  De otro modo, el valor devuelto
por la función completa es el valor de la última expresión que es
evaluada en el cuerpo del ‘let’, y este es el valor devuelto por el
‘while’ que es siempre ‘nil’.

   Esto puede no ser evidente a primera vista.  Eso casi se ve como si
la expresión de incremento es la última expresión de la función
completa.  Pero esta expresión es parte del cuerpo del ‘while’; eso es
el último elemento de la lista que empieza con el símbolo ‘while’.  Más
allá, el bucle ‘while’ completo es una lista con el cuerpo del ‘let’.

   En línea (_outline_), la función se parece a esto:

     (defun NAME-OF-FUNCTION (ARGUMENT-LIST)
       "DOCUMENTATION..."
       (let (VARLIST)
         (while (TRUE-OR-FALSE-TEST)
           BODY-OF-WHILE... )
         ... ))                    ; Necesita la expresión final aquí.

   El resultado de evaluar el ‘let’ es que lo que está yendo para
devolver el ‘defun’ desde el ‘let’ que no está embebido con cualquier
lista que contiene, excepto para la ‘defun’ como un todo.  Sin embargo,
si el ‘while’ es el último elemento de la expresión ‘let’, la función
siempre devolverá ‘nil’.  ¡Esto no es lo que quiero!  En vez de eso, lo
que queremos es el valor de la variable ‘total’.  Eso devuelve
simplemente emplazando el símbolo como el último elemento de la lista
empezando con ‘let’.  Eso se evalúa después de los elementos precedentes
de la lista evaluada, que significa que eso se evaluó después de haber
sido asignado el valor correcto para el total.

   Eso puede ser fácil de ver imprimiendo la lista empezando con ‘let’
todo en una línea.  Este formato hace evidente que las expresiones
VARLIST y ‘while’ son el segundo el tercer elementos de la lista
empezando con ‘let’, y el ‘total’ es el último elemento:

     (let (VARLIST) (while (TRUE-OR-FALSE-TEST)
     BODY-OF-WHILE... ) total)

   Poniendo cualquier cosa junta, la definición de función ‘triangle’ se
parece a esto:

     (defun triangle (number-of-rows)    ; Versión con
                                         ;  contador de incremento.
       "Añade el número de asteriscos en un triángulo.
     La primera fila tiene un asterisco, la segunda fila dos asteriscos,
     la tercera fila tres asteriscos, y así.
     El argumento es NUMBER-OF-ROWS."
       (let ((total 0)
             (row-number 1))
         (while (<= row-number number-of-rows)
           (setq total (+ total row-number))
           (setq row-number (1+ row-number)))
         total))

   Después de haber instalado ‘triangle’ para evaluar la función, se
puede probar.  Aquí hay dos ejemplos:

     (triangle 4)

     (triangle 7)

La suma del primero de cuatro números es 10 y la suma de los primeros
siete números es 28.


File: emacs-lisp-intro-es.info,  Node: Bucle que se decrementa,  Prev: Incrementando los detalles de los bucles,  Up: while

11.1.4 Bucle que decrementa
---------------------------

Otro camino común para escribir un bucle ‘while’ es escribir el test así
que determina si un contador es mayor que cero.  Así tan largo es el
contador mayor que cero, el bucle se repite.  Pero cuando el contador es
igual o menor que cero, el bucle se para.  Para este trabajo, el
contador tiene que empezar mayor que cero y entonces se hace más pequeño
y pequeño por una forma que es evaluada repetidamente.

   El test será una expresión tal como ‘(> counter 0)’ que devuelve ‘t’
_cierto_ si el valor de ‘counter’ es mayor que cero, y ‘nil’ _falso_ si
el valor de ‘counter’ es igual a o menor que cero.  La expresión hace
que el número menor y menor puede ser un simple ‘setq’ tal como ‘(setq
counter (1- counter)’, donde ‘1-’ es una función construida en Emacs
Lisp que sustrae 1 de su argumento.

   La plantilla para decrementar el bucle ‘while’ se ve así:

     (while (> counter 0)                    ; test-verdadero-o-falso
       BODY...
       (setq counter (1- counter)))          ; decremento

* Menu:

* Ejemplo de Decremento::    Más piedras en la playa.
* Partes de Ejemplo Dec::    Las partes de la definición de función.
* Ejemplo Dec junto::        Poniendo la definición de función junta.


File: emacs-lisp-intro-es.info,  Node: Ejemplo de Decremento,  Next: Partes de Ejemplo Dec,  Up: Bucle que se decrementa

Ejemplo con el contador que se decrementa
.........................................

Para ilustrar un bucle con un contador de decremento, reescribirá la
función ‘triangle’ así como el contador se decrementa a cero.

   Esto es lo inverso de la versión temprana de la función.  En este
caso, para encontrar cuántos asteriscos son necesarios para crear un
triángulo con 3 filas, añade el número de asteriscos en la tercera fila,
3, para el número en la fila precedente, 2, y entonces añade el total de
estas dos filas a la fila que lo precede, 1.

   Más allá, para encontrar el número de asteriscos en un triángulo con
7 filas, añade el número de asteriscos en la fila siete, 7, al número en
la fila precedente, que es 6, y entonces añade el total de estas dos
filas a la fila esta que lo precede, que es 5, y así.  Como en el
ejemplo previo, cada adición solo involucra la adición de dos números,
el total de las filas ya se añadió y el número de asteriscos en la fila
que está siendo añadida al total.  Este proceso de añadir dos números se
repite de nuevo y de nuevo hasta que no haya más asteriscos que añadir.

   Sabemos con cuántos asteriscos empezar: el número de asteriscos en la
última fila es igual al número de filas.  Si el triángulo tiene siete
filas, el número de asteriscos en la última fila es 7.  Más allá,
sabemos cuántos asteriscos están en la fila precedente: eso es uno menos
que el número en la fila.


File: emacs-lisp-intro-es.info,  Node: Partes de Ejemplo Dec,  Next: Ejemplo Dec junto,  Prev: Ejemplo de Decremento,  Up: Bucle que se decrementa

Las partes de la definición de función
......................................

Empezamos con tres variables: el número total de filas en el triángulo;
el número de asteriscos en una fila; y el número total de asteriscos,
que es lo que queremos calcular.  Estas variables pueden llamarse
‘number-of-rows’, ‘number-of-pebbles-in-row’, y ‘total’,
respectivamente.

   Ambos ‘total’ y ‘number-of-pebbles-in-row’ se usan solo dentro de la
función y se declaran con ‘let’.  El valor inicial de ‘total’ sería
cero.  Sin embargo, el valor inicial de ‘number-of-pebbles-in-row’ sería
igual al número de filas en el triángulo, desde la adición empezará con
la fila más larga.

   Esto significa que el principio de la expresión ‘let’ se verá así:

     (let ((total 0)
           (number-of-pebbles-in-row number-of-rows))
       BODY...)

   El número total de asteriscos puede encontrarse repetidamente
añadiendo el número de asteriscos en una fila para el total ya
encontrado, que, se evalúa repetidamente en la siguiente expresión:

     (setq total (+ total number-of-pebbles-in-row))

Después el ‘number-of-pebbles-in-row’ se añade al ‘total’, el
‘number-of-pebbles-in-row’ sería decrementado por uno, desde que la
siguiente vez el bucle repite, la fila precedente será añadida al total.

   El número de asteriscos en una fila precedente es uno menos que el
número de asteriscos en una fila, así la función Emacs Lisp construida
‘1-’ puede usarse para computar el número de asteriscos de la fila
precedente.  Esto puede ser hecho con la siguiente expresión:

     (setq number-of-pebbles-in-row
           (1- number-of-pebbles-in-row))

   Finalmente, sabemos que el bucle ‘while’ pararía creando repetidas
adiciones cuando no hay asteriscos en una fila.  Así el test para el
bucle ‘while’ es simple:

     (while (> number-of-pebbles-in-row 0)


File: emacs-lisp-intro-es.info,  Node: Ejemplo Dec junto,  Prev: Partes de Ejemplo Dec,  Up: Bucle que se decrementa

Poniendo la definición de la función junta
..........................................

Se pueden poner estas expresiones juntas para crear una definición de
función que funcione.  Sin embargo, al examinarlas, encontraremos que
una de la variables locales ¡es innecesaria!

   La definición de función se ve como esto:

     ;;; Primero la versión substractiva.
     (defun triangle (number-of-rows)
       "Añade el número de asteriscos en un triángulo."
       (let ((total 0)
             (number-of-pebbles-in-row number-of-rows))
         (while (> number-of-pebbles-in-row 0)
           (setq total (+ total number-of-pebbles-in-row))
           (setq number-of-pebbles-in-row
                 (1- number-of-pebbles-in-row)))
         total))

   Como se dijo, esta función funciona.

   Sin embargo, no se necesita ‘number-of-pebbles-in-row’.

   Cuando la función ‘triangle’ se evalúa, el símbolo ‘number-of-rows’
será asociado al número, dando un valor inicial.  Este número puede ser
cambiado en el cuerpo de la función si hubiera una variable local, sin
miedo de que tal cambio se efectuará el valor de la variable fuera de la
función.  Esto es una característica muy útil de Lisp; eso significa que
la variable ‘number-of-rows’ puede ser usada en cualquier lugar en la
función donde ‘number-of-pebbles-in-row’ se usa.

   Aquí hay una segunda versión de la función escrita un poco más
limpiamente:

     (defun triangle (number)                ; Segunda versión.
       "Devuelve la suma de números 1 a través de NUMBER inclusive."
       (let ((total 0))
         (while (> number 0)
           (setq total (+ total number))
           (setq number (1- number)))
         total))

   En breve, un bucle ‘while’ apropiadamente escrito consistirá de tres
partes:

  1. Un test que devuelva falso después de que el bucle ha repetido por
     sí mismo el número de veces correcto.

  2. Una expresión de la evaluación de que devolverá el valor deseado
     después de ser repetidamente evaluado.

  3. Una expresión para cambiar el valor pasado al true-or-false-test
     así el test devuelve falso después de que el bucle se ha repetido
     por sí mismo el número de veces correcto.


File: emacs-lisp-intro-es.info,  Node: Dolist y dotimes,  Next: Recursión,  Prev: while,  Up: Bucles y recursión

11.2 Ahorra tiempo: ‘dolist’ y ‘dotimes’
========================================

Además de ‘while’, tanto ‘dolist’ como ‘dotimes’ proveen un bucle.
Algunas veces estos son rápidos para escribir el bucle equivalente
‘while’.  Ambos son macros Lisp.  (*Note Macros: (elisp)Macros.)

   ‘dolist’ funciona como un bucle ‘while’ con 'CDRs que bajan la
lista': ‘dolist’ automáticamente ordena la lista cada vez que la lista
hace bucles -- toma la CDR de la lista -- y asocia el CAR de cada
versión ordenada de la lista al primero de sus argumentos.

   ‘dotimes’ repite el bucle un número específico de veces: tu
especificas el número.

* Menu:

* dolist::                   dolist
* dotimes::                  dotimes


File: emacs-lisp-intro-es.info,  Node: dolist,  Next: dotimes,  Up: Dolist y dotimes

La macro ‘dolist’
-----------------

Supón, por ejemplo, que quieres invertir una lista, así que "primero",
"segundo", "tercero" llega a ser "tercero", "segundo", "primero".

   En la práctica, usarías la función ‘reverse’, como esta:

     (setq animales '(gacela jirafa leon tigre))

     (reverse animales)

Aquí se ve cómo se podría invertir la lista usando un bucle ‘while’:

     (setq animales '(gacela jirafa leon tigre))

     (defun reverse-list-with-while (list)
       "Usando while, invierte el orden de LIST."
       (let (value)  ; asegura que la lista comienza vacía
         (while list
           (setq value (cons (car list) value))
           (setq list (cdr list)))
         value))

     (reverse-list-with-while animales)

Y aquí se ve cómo podría usarse la macro ‘dolist’:

     (setq animales '(gacela jirafa leon tigre))

     (defun reverse-list-with-dolist (list)
       "Usando dolist, reverse, la orden de la LISTA."
       (let (value)  ; asegura que la lista empieza vacía
         (dolist (element list value)
           (setq value (cons element value)))))

     (reverse-list-with-dolist animals)

En Info, se puede localizar su cursor después de cerrar paréntesis de
cada expresión y escribir ‘C-x C-e’; en cada caso, se vería

     (tigre leon jirafa gacela)

en el área echo.

   Para este ejemplo, la función ‘reverse’ existente es obviamente la
mejor.  El bucle ‘while’ es solo como nuestro primer ejemplo (*note Un
bucle ‘while’ y una lista: Ejemplo de bucle.).  El ‘while’ primero
chequea si la lista tiene elementos; si es así, eso construye una nueva
lista añadiendo el primer elemento de la lista a la lista existente (que
en la primera iteración del bucle es ‘nil’).  Puesto que el segundo
elemento está asignado en frente del segundo elemento, la lista es
inversa.

   En la expresión que usa el bucle ‘while’, la expresión
‘(setq list (cdr list))’ ordena la lista, así el bucle ‘while’
finalmente para.  Además, se proporciona la expresión ‘cons’ con un
nuevo primer elemento creando una nueva lista y se ordena en cada
repetición del bucle.

   La expresión ‘dolist’ hace lo mismo que la expresión ‘while’, excepto
que la macro ‘dolist’ hace algo del trabajo que se tiene que hacer
cuando se escribe una expresión ‘while’.

   Al igual que el bucle ‘while’, tenemos el bucle ‘dolist’.  Lo que es
diferente es que automáticamente ordena la lista cada vez que se repite
-- eso es 'recorrer los CDRs de la lista' en sí -- y eso automáticamente
asocia el CAR de cada versión ordenada de la lista al primero de sus
argumentos.

   En el ejemplo, el CAR de cada versión ordenada de la lista se refiere
a usar el símbolo ‘element’, la lista en sí se llama ‘list’, y el valor
devuelto se llama ‘value’.  El resto de la expresión ‘dolist’ es el
cuerpo.

   La expresión ‘dolist’ asocia el CAR de cada versión ordenada de la
lista al ‘element’ y entonces evalúa el cuerpo de la expresión y repite
el bucle.  El resultado es devuelto en ‘value’.


File: emacs-lisp-intro-es.info,  Node: dotimes,  Prev: dolist,  Up: Dolist y dotimes

La macro ‘dotimes’
------------------

La macro ‘dotimes’ es similar a ‘dolist’, excepto que el bucle se repite
un número específico de veces.

   El primer argumento ‘dotimes’ se asigna a los números 0, 1, 2 y así
vuelve al bucle, y el valor del tercer argumento se devuelve.  Se
necesita proveer el valor del segundo argumento, que es cuántas veces la
macro hace el bucle.

   Por ejemplo, lo siguiente asocia los números de 0 en adelante, pero
no incluyendo, el número 3 al primer argumento, NÚMERO, y entonces
construye una lista de los tres números.  (El primer número es 0, el
segundo número es 1, y el tercer número es 2; esto crea un total de tres
números en todo, empezando con cero como el primer número.)

     (let (value)      ; de otro modo un valor es una variable vacía
       (dotimes (number 3 value)
         (setq value (cons number value))))

     ⇒ (2 1 0)

‘dotimes’ devuelve ‘value’, así el camino para usar ‘dotimes’ es para
operar en alguna expresión el número de veces NUMBER y entonces devolver
el resultado, como una lista o un átomo.

   Aquí hay un ejemplo de una ‘defun’ que usa ‘dotimes’ para añadir el
número de asteriscos en un triángulo.

     (defun triangle-using-dotimes (number-of-rows)
       "Usando dotimes, añade el número de asteriscos en un triángulo."
     (let ((total 0))  ; de otro modo un total es una variable vacía
       (dotimes (number number-of-rows total)
         (setq total (+ total (1+ number))))))

     (triangle-using-dotimes 4)


File: emacs-lisp-intro-es.info,  Node: Recursión,  Next: Ejercicio de Bucle,  Prev: Dolist y dotimes,  Up: Bucles y recursión

11.3 Recursión
==============

Una función recursiva contiene código que hace que el intérprete Lisp
llame a un programa que ejecute el código en sí, pero con argumentos
ligeramente diferentes.  El código ejecuta exactamente lo mismo porque
eso tiene el mismo nombre.  Sin embargo, incluso aunque el programa
tenga el mismo nombre, no es la misma entidad.  Eso es diferente.  En la
jerga, se dice es una 'instancia' diferente.

   Finalmente, si el programa se escribe correctamente, los 'argumentos
ligeramente diferentes' llegan a ser suficientemente diferentes puesto
que los primeros argumentos de la instancia final se pararán.

* Menu:

* Construyendo robots::      Mismo modelo, diferente número serie ...
* Partes de definición recursiva::  Paseo hasta que tu pares ...
* Recursión con lista::    Usando una lista con el test si para recurso.
* Función recursiva triángulo::  Función recursiva triángulo
* Recursión con cond::     Recursión con cond
* Patrones recursivos::      Plantillas usadas con frecuencia.
* Sin Aplazar::              No almacenar trabajo ...
* No aplazar la solución::  No aplazar la solución


File: emacs-lisp-intro-es.info,  Node: Construyendo robots,  Next: Partes de definición recursiva,  Up: Recursión

11.3.1 Construyendo robots: Extendiendo la metáfora
---------------------------------------------------

Algunas veces es útil pensar en un programa en ejecución como un robot
que hace un trabajo.  Haciendo su trabajo, una función recursiva llama a
un segundo robot para que le ayude.  El segundo robot es idéntico al
primero en cada paso, excepto que el segundo robot ayuda al primero y se
han pasado diferentes argumentos en vez del primero.

   En una función recursiva, el segundo robot puede llamar a un tercero;
y el tercero puede llamar a un cuarto, y así.  Cada una de estos es una
entidad diferente; pero todos son clones.

   Desde que cada robot tiene instrucciones ligeramente diferentes --
los argumentos diferirán desde un robot al siguiente -- el último robot
conocería cuando pare.

   Permite expandir la metáfora en el que un programa de ordenador es un
robot.

   Una definición de función provee impresiones para un robot.  Cuando
se instala una definición de función, que es, cuando se evalúa una forma
especial ‘defun’, se instala el equipamiento para construir robots.  Eso
es como si tu estuvieras en una fábrica, configurando una línea de
ensamblaje.  Los robots con el mismo nombre son construidos de acuerdo a
las mismas impresiones.  Así ellos tienen, como estaban, el mismo
'número de modelo', pero un diferente 'número de serie'.

   Nosotros con frecuencia decimos que una función recursiva 'se llama
así misma'.  Esto significa que las instrucciones en una función
recursiva causa que el intérprete de Lisp ejecute una función diferente
que tiene el mismo nombre y hace el mismo trabajo que el primero, pero
con diferentes argumentos.

   Es importante que los argumentos difieran desde una instancia a la
siguiente; de otro modo, el proceso nunca parará.


File: emacs-lisp-intro-es.info,  Node: Partes de definición recursiva,  Next: Recursión con lista,  Prev: Construyendo robots,  Up: Recursión

11.3.2 Las partes de una definición recursiva
---------------------------------------------

Una función recursiva típicamente contiene una expresión condicional que
tiene tres partes:

  1. Un true-or-false-test que determina si la función se llama de
     nuevo, aquí se llama el “do-again-test”.

  2. El nombre de la función.  Cuando este nombre se llama, es una nueva
     instancia de la función -- un nuevo robot, así -- se crea y se dice
     qué hacer.

  3. Una expresión que devuelve un valor diferente cada vez que la
     función se llama, aquí llamada la “next-step-expression”.
     Consecuentemente, el argumento (o argumentos) pasados a la nueva
     instancia de la función serán diferentes puesto que se pasa a la
     instancia previa.  Esto causa la expresión condicional, que el
     “do-again-test”, devuelva falso después del número correcto de
     repeticiones.

   Las funciones recursivas pueden ser más simples que cualquier otro
tipo de funciones.  De manera profunda, cuando la gente empieza a
usarlas, con frecuencia se miran así misteriosamente de manera tan
simple como incompresible.  Como montar en bicicleta, leer una función
recursiva es duro al principio, pero después es simple.

   Hay varios patrones recursivos diferentes.  Un patrón muy simple se
parece a:

     (defun NAME-OF-RECURSIVE-FUNCTION (ARGUMENT-LIST)
       "DOCUMENTATION..."
       (if DO-AGAIN-TEST
         BODY...
         (NAME-OF-RECURSIVE-FUNCTION
              NEXT-STEP-EXPRESSION)))

   Cada vez que una función recursiva es evaluada, una nueva instancia
se crea y se dice qué hacer.  Los argumentos le dicen a la instancia qué
hacer.

   Un argumento se empareja al valor de la next-step-expresion.  Cada
instancia se ejecuta con un valor diferente de la next-step-expression.

   El valor en la next-step-expression es usado en la do-again-test.

   El valor devuelto por la next-step-expression es pasada a las nuevas
instancias de la función, que lo evalúa (o alguna transformación de eso)
para determinar si continuar o parar.  El next-step-expression está
diseñado así que el do-again-test devuelve falso cuando la función no se
repetiría mucho.

   El do-again-test es algunas veces llamado la “condición de parar”,
puesto que sirve para parar las repeticiones cuando se devuelve falso.


File: emacs-lisp-intro-es.info,  Node: Recursión con lista,  Next: Función recursiva triángulo,  Prev: Partes de definición recursiva,  Up: Recursión

11.3.3 Recursión con una lista
------------------------------

El ejemplo de un bucle ‘while’ que imprimió los elementos de una lista
de números puede ser escrito recursivamente.  Aquí está el código,
incluyendo una expresión para asignar el valor de la variable ‘animales’
a una lista.

   Si está leyendo esto en el Info de Emacs, se puede evaluar esta
expresión directamente en Info.  De otro modo, se debe copiar el ejemplo
al búffer ‘*scratch*’ y evalúa cada expresión aquí.  Usa ‘C-u C-x C-e’
para evaluar la expresión ‘(print-elements-recursively animals)’ así que
los resultado se imprimen en el búffer; de otro modo el intérprete Lisp
intentará presionar los resultados dentro de una línea del área echo.

   También, posiciona tu cursor inmediatamente después del último
paréntesis que cierra la función ‘print-elements-recursively’, antes del
comentario.  De otro modo, el intérprete Lisp intentará evaluar el
comentario.

     (setq animales '(gacela jirafa leon tigre))

     (defun print-elements-recursively (list)
       "Imprime cada elemento de la LISTA de la línea en
       sí. Usa recursión."
       (when list                            ; do-again-test
             (print (car list))              ; body
             (print-elements-recursively     ; recursive call
              (cdr list))))                  ; next-step-expression

     (print-elements-recursively animales)

   La función ‘print-elements-recursively’ primero chequea si hay
cualquier contenido en la lista; si lo hay, la función imprime el primer
elemento de la lista, el CAR de la lista.  Entonces la función se
'invoca en sí', pero da a sí mismo como su argumento, no la lista
completa, pero el segundo y subsiguientes elementos de la lista, el CDR
de la lista.

   Pon otro camino, si la lista no está vacía, la función invoca otra
instancia de código que es similar al código inicial, pero es un hilo
diferente de ejecución, con diferentes argumentos a la primera
instancia.

   Veamos una manera más, si la lista no está vacía, el primer robot
ensambla un segundo robot que cuenta qué hacer; el segundo robot es un
individuo diferente desde el principio, pero es el mismo modelo.

   Cuando la segunda evaluación ocurre, la expresión ‘when’ se evalúa y
si es verdad, se imprime el primer elemento de la lista que recibe como
su argumento (que es el segundo elemento de la lista original).
Entonces la función 'llamarse a sí mismo' con la CDR del CDR de la lista
original.

   Note que aunque nosotros decimos que la función 'se llama a sí
misma', lo que significa es que el intérprete Lisp ensambla e instruye
una nueva instancia del programa.  La nueva instancia es un clon del
primero, pero es un individuo separado.

   Cada vez que la función 'se invoca a sí misma', se invoca a sí misma
en una versión de la lista original.  Eso crea una nueva instancia que
funciona como una lista ordenada.

   Finalmente, la función se invoca a sí misma en una lista vacía.  Eso
crea una nueva instancia cuyo argumento es ‘nil’.  La expresión
condicional chequea el valor de ‘lista’.  Desde el valor de ‘lista’ a
‘nil’, la expresión ‘when’ devuelve falso así la then-part no está
evaluada.  La función es como un todo que entonces devuelve ‘nil’.

   Cuando se evalúa la expresión ‘(print-elements-recursively animals)’
en el búffer ‘*scratch*’, se verá este resultado:

     gacela

     jirafa

     leon

     tigre
     nil


File: emacs-lisp-intro-es.info,  Node: Función recursiva triángulo,  Next: Recursión con cond,  Prev: Recursión con lista,  Up: Recursión

11.3.4 Recursión en lugar de un contador
----------------------------------------

La función ‘triangle’ describe en una sección previa si puede ser
escrita recursivamente.  Se ve así:

     (defun triangle-recursively (number)
       "Return the sum of the numbers 1 through NUMBER inclusive.
     Uses recursion."
       (if (= number 1)                    ; do-again-test
           1                               ; then-part
         (+ number                         ; else-part
            (triangle-recursively          ; recursive call
             (1- number)))))               ; next-step-expression

     (triangle-recursively 7)

Se puede instalar esta función evaluando y entonces se intenta evaluar
‘(triangle-recursively 7)’.  (Recuerda poner tu cursor inmediatamente
después de los últimos paréntesis de la definición de la función, antes
del comentario.)  La función se evalúa a 28.

   Para comprender cómo funciona la función, hay que considerar qué
ocurre en varios casos cuando la función se le pasa 1, 2, 3, o 4 como el
valor a su argumento.

* Menu:

* Ejemplo recursivo y argumento con valor 1 o 2::  Ejemplo recursivo y
                                                     argumento con valor 1 o 2
* Ejemplo Recursivo de 3 o 4 argumentos::  Ejemplo Recursivo de 3 o 4
                                             argumentos


File: emacs-lisp-intro-es.info,  Node: Ejemplo recursivo y argumento con valor 1 o 2,  Next: Ejemplo Recursivo de 3 o 4 argumentos,  Up: Función recursiva triángulo

Un argumento de 1 o 2
.....................

Primero, veamos qué ocurre si el valor del argumento es 1.

   La función tiene una expresión ‘if’ después de la cadena de
documentación.  Esto chequea si el valor de ‘number’ es igual a 1; si es
así, Emacs evalúa la then-part de la expresión ‘if’, que devuelve el
número 1 como el valor de la función.  (Un triángulo con una fila tiene
un asterisco dentro.)

   Supón, sin embargo, que el valor del argumento es 2.  En este caso,
Emacs evalúa la parte else de la expresión ‘if’.

   La parte else consiste de una adición, la llamada recursiva para
‘triangle-recursively’ y una acción de decremento; y se ve así:

     (+ number (triangle-recursively (1- number)))

   Cuando Emacs evalúa esta expresión, la expresión interna es evaluada
primero; entonces las otras partes en secuencia.  Aquí están los pasos
en detalle:

Paso 1   Evalúa la expresión interna.

     La expresión interna es ‘(1- number)’ así Emacs decrementa el valor
     de ‘number’ desde 2 a 1.

Paso 2   Evalúa la función ‘triangle-recursively’.

     El intérprete Lisp crea una instancia individual de
     ‘triangle-recursively’.  Eso no importa que esta función está
     contenida con sí misma.  Emacs pasa el resultado Paso 1 como el
     argumento usado por esta instancia de la función
     ‘triangle-recursively’

     En este caso, Emacs evalúa ‘triangle-recursively’ con un argumento
     de 1.  Esto significa que esta evaluación de ‘triangle-recursively’
     devuelve 1.

Paso 3   Evalúa el valor de ‘number’.

     La variable ‘number’ es el segundo elemento de la lista que empieza
     con ‘+’; su valor es 2.

Paso 4   Evalúa la expresión ‘+’.

     La expresión ‘+’ recibe dos argumentos, el primero desde la
     evaluación de ‘number’ (Paso 3) y el segundo desde la evaluación de
     ‘triangle-recursively’ (Paso 2).

     El resultado de la adición es la suma de 2 + 1, y el número 3 es
     devuelto, que es correcto.  Un triángulo con dos filas tiene tres
     asteriscos ahí.


File: emacs-lisp-intro-es.info,  Node: Ejemplo Recursivo de 3 o 4 argumentos,  Prev: Ejemplo recursivo y argumento con valor 1 o 2,  Up: Función recursiva triángulo

Un argumento de 3 o 4
.....................

Supón que ‘triangle-recursively’ es llamado con un argumento de 3.

Paso 1   Evalúa la do-again-test.

     La expresión ‘if’ se evalúa primero.  Esto es el test do-again y
     devuelve falso, así la parte else de la expresión ‘if’ es evaluada.
     (Note que en este ejemplo, el do-again-test causa la función para
     llamarse a sí misma cuando eso se chequea como falso, no cuando eso
     se chequea como verdadero.)

Paso 2   Evalúa la expresión propia de la parte else.

     La expresión propia de la parte que es evaluada, decrementa 3 a 2.
     Esta la next-step-expression.

Paso 3   Evalúa la función ‘triangle-recursively’.

     El número 2 es pasado a la función ‘triangle-recursively’.

     Nosotros ya sabemos qué ocurre cuando Emacs evalúa
     ‘triangle-recursively’ con un argumento de 2.  Después de ir a
     través de la secuencia de acciones descritas temprano, eso devuelve
     un valor de 3.  Así que es lo que ocurrirá aquí.

Paso 4   Evalúa la adición.

     3 será pasado como un argumento para la adición y será añadido al
     número con el que la función se llamó, que es 3.

El valor devuelto por la función como un todo será 6.

   Ahora que sabemos qué ocurrirá cuando ‘triangle-recursively’ llama
con un argumento 3, es evidente lo que ocurrirá si se llama con el
argumento 4:

     En la llamada recursiva, la evaluación de

          (triangle-recursively (1- 4))

     devuelve el valor de evaluar

          (triangle-recursively 3)

     que es 6 este valor será añadido a 4 por la adición en la tercera
     línea.

El valor devuelto por la función como un todo será 10.

   Cada vez que ‘triangle-recursively’ se evalúa, se interpreta una
versión de sí misma -- una instancia diferente en sí -- con un pequeño
argumento, hasta que el argumento es suficientemente pequeño así que no
se evalúa en sí.

   Note que este particular diseño para una función recursiva requiere
que las operaciones sean diferidas.

   Antes de que ‘(triangle-recursively 7)’ pueda calcular su respuesta,
debe llamarse a ‘(triangle-recursively 6)’; y antes a
‘(triangle-recursively 5)’; y así.  Esto es decir, que el cálculo de
‘(triangle-recursively 7)’ a crear debe ser diferido hasta que
‘(triangle-recursively 6)’ haga su cálculo; y ‘(triangle-recursively 5)’
lo complete; y así.

   Si cada una de estas instancias de ‘triangle-recursively’ son
pensadas como diferentes robots, el primer robot debe esperar por el
segundo para completar su trabajo, que debe esperar hasta los terceros
completos, y así.

   Hay un camino alrededor de este tipo de espera, que se discutirá en
*note Recursión sin Defermentos.: Sin Aplazar.


File: emacs-lisp-intro-es.info,  Node: Recursión con cond,  Next: Patrones recursivos,  Prev: Función recursiva triángulo,  Up: Recursión

11.3.5 Ejemplo de recursión usando ‘cond’
-----------------------------------------

La versión de ‘triangle-recursively’ antes descrita se escribió con la
forma especial ‘if’.  Eso puede también ser escrita usando otra forma
especial llamada ‘cond’.  El nombre de la forma especial ‘cond’ es una
abreviación de la palabra ‘conditional’.

   Aunque la forma especial ‘cond’ no se usa con frecuencia en las
fuentes de Emacs como ‘if’, se usa con suficiente frecuencia para
justificarse explicando.

   La plantilla para una expresión ‘cond’ se parece a:

     (cond
      BODY...)

donde el BODY es una serie de listas.

   Escrito de manera más completa, la plantilla se parece a esto:

     (cond
      (FIRST-TRUE-OR-FALSE-TEST FIRST-CONSEQUENT)
      (SECOND-TRUE-OR-FALSE-TEST SECOND-CONSEQUENT)
      (THIRD-TRUE-OR-FALSE-TEST THIRD-CONSEQUENT)
       ...)

   Cuando el intérprete Lisp evalúa la expresión ‘cond’, evalúa el
primer elemento (el CAR o true-or-false-test) de la primera expresión en
una serie de expresiones con el cuerpo del ‘cond’.

   Si el true-or-false-test devuelve ‘nil’ el resto de esta expresión,
el consecuente, se descarta y el true-or-false-test de la siguiente
expresión se evalúa.  Cuando una expresión encuentra un
true-or-false-test cuyo valor no es ‘nil’, el consecuente de esta
expresión se evalúa.  El consecuente puede ser una o más expresiones.
Si el consecuente consiste de más de una expresión, las expresiones son
evaluadas en secuencia y el valor del último se devuelve.  Si la
expresión no tiene un consecuente, se devuelve el valor del
true-or-false-test.

   Si ninguno del test true-or-false-tests es cierto, la expresión
‘cond’ devuelve ‘nil’.

   Escrito usando ‘cond’, la función ‘triangle’ se parece a esto:

     (defun triangle-using-cond (number)
       (cond ((<= number 0) 0)
             ((= number 1) 1)
             ((> number 1)
              (+ number (triangle-using-cond (1- number))))))

En este ejemplo, el ‘cond’ devuelve 0 si el número es menor o igual a 0,
eso devuelve 1 si el número es 1 y eso evalúa ‘(+ number
(triangle-using-cond (1- number)))’ si el número es más grandes que 1.


File: emacs-lisp-intro-es.info,  Node: Patrones recursivos,  Next: Sin Aplazar,  Prev: Recursión con cond,  Up: Recursión

11.3.6 Patrones recursivos
--------------------------

Aquí hay tres patrones recursivos.  Cada uno involucra una lista.  La
recursión no se necesita para involucrar listas, pero Lisp se diseña
para listas y esto provee un sentido de sus capacidades primarias.

* Menu:

* Cada::                     Cada
* Acumular::                 Acumular
* Guardar::                  Guardar


File: emacs-lisp-intro-es.info,  Node: Cada,  Next: Acumular,  Up: Patrones recursivos

Patrón recursivo: _every_
.........................

En el patrón recursivo ‘every’, se desarrolla una acción por cada
elemento de una lista.

   El patrón básico es:

   • Si una lista es vacía, devuelve ‘nil’.
   • Else, act on the beginning of the list (the CAR of the list)
        − through a recursive call by the function on the rest (the CDR)
          of the list,
        − and, optionally, combine the acted-on element, using ‘cons’,
          with the results of acting on the rest.

   Aquí está el ejemplo:

     (defun square-each (numbers-list)
       "El cuadrado de cada LISTA DE NUMEROS, recursivamente."
       (if (not numbers-list)                ; test-hazlo-de-nuevo
           nil
         (cons
          (* (car numbers-list) (car numbers-list))
          (square-each (cdr numbers-list))))) ; expresion-siguiente-paso

     (square-each '(1 2 3))
         ⇒ (1 4 9)

Si ‘numbers-list’ está vacío, no hay que hacer nada.  Pero si tiene
contenido, se construye una lista combinando el cuadrado del primer
número en la lista con el resultado de la llamada recursiva.

   (El ejemplo sigue el patrón exactamente: se devuelve ‘nil’ si la
lista de números es vacía.  En la práctica, se escribiría el
condicional, así se ejecuta la acción cuando la lista de números no es
vacía.)

   La función ‘print-elements-recursively’ (*note Recursión con una
Lista: Recursión con lista.) es otro ejemplo de un patrón ‘every’,
excepto en este caso, en vez de traer los resultados juntos usando
‘cons’, se imprime cada elemento de salida.

   La función ‘print-elements-recursively’ se parece a esto:

     (setq animales '(gacela jirafa leon tigre))

     (defun print-elements-recursively (list)
       "Imprime cada elemento de la LISTA de la línea en
       sí. Usa recursión."
       (when list                            ; do-again-test
             (print (car list))              ; body
             (print-elements-recursively     ; recursive call
              (cdr list))))                  ; next-step-expression

     (print-elements-recursively animales)

   El patrón para ‘print-elements-recursively’ es:

   • Cuando la lista está vacía, no hacer nada.
   • But when the list has at least one element,
        − act on the beginning of the list (the CAR of the list),
        − and make a recursive call on the rest (the CDR) of the list.


File: emacs-lisp-intro-es.info,  Node: Acumular,  Next: Guardar,  Prev: Cada,  Up: Patrones recursivos

Patrón recursivo: _accumulate_
..............................

Otro patrón recursivo es llamado el patrón ‘accumulate’.  En el patrón
recursivo ‘accumulate’, se realiza una acción en cada elemento de una
lista y el resultado de esta acción se acumula con los resultados de
desarrollar la acción en otros elementos.

   Esto es como 'cada' patrón usando ‘cons’, excepto que este ‘cons’ no
se esté usando, pero que algún otro combine.

   El patrón es:

   • Si una lista está vacía, devuelve cero o alguna otra constante.
   • Else, act on the beginning of the list (the CAR of the list),
        − and combine that acted-on element, using ‘+’ or some other
          combining function, with
        − a recursive call by the function on the rest (the CDR) of the
          list.

   Aquí hay un ejemplo:

     (defun add-elements (numbers-list)
       "Añade los elementos de NUMBERS-LIST juntos."
       (if (not numbers-list)
           0
         (+ (car numbers-list) (add-elements (cdr numbers-list)))))

     (add-elements '(1 2 3 4))
         ⇒ 10

   *Note Creando una lista de ficheros: Listar ficheros, para un ejemplo
del patrón acumulado.


File: emacs-lisp-intro-es.info,  Node: Guardar,  Prev: Acumular,  Up: Patrones recursivos

Patrón recursivo: _keep_
........................

Un tercer patrón es llamado el patrón ‘keep’.  En el patrón recursivo
‘keep’, se chequea cada elemento de una lista; se actúa en el elemento y
los resultados se guardan solo si el elemento encuentra un criterio.

   De nuevo, esto se parece al patrón 'every', excepto que el elemento
se descarta a menos que se encuentre un criterio.

   El patrón tiene tres partes:

   • Si una lista es vacía, devuelve ‘nil’.
   • Else, if the beginning of the list (the CAR of the list) passes a
     test
        − act on that element and combine it, using ‘cons’ with
        − a recursive call by the function on the rest (the CDR) of the
          list.
   • Otherwise, if the beginning of the list (the CAR of the list) fails
     the test
        − skip on that element,
        − and, recursively call the function on the rest (the CDR) of
          the list.

   Aquí hay un ejemplo que usa ‘cond’:

     (defun manten-tres-letras (lista-palabras)
       "Guarda 3 palabras en WORD-LIST."
       (cond
        ;; Primero do-again-test: stop-condition
        ((not lista-palabras) nil)

        ;; Segundo do-again-test: cuando actuar
        ((eq 3 (length (symbol-name (car lista-palabras))))
         ;; combina el elemento que actúa con la llamada recursiva en la
         ;; lista ordenada
         (cons (car lista-palabras) (manten-tres-letras (cdr lista-palabras))))

        ;; Tercero do-again-test: cuando se descarte el elemento;
        ;; llama recursivamente a la lista ordenada con la next-step expression
        (t (manten-tres-letras (cdr lista-palabras)))))

     (manten-tres-letras '(uno dos tres cuatro cinco seis))
         ⇒ (uno dos)

   Eso va sin decir que no se necesita usar ‘nil’ como si el test para
cuando para; y se puede, de acuerdo, combinar estos patrones.


File: emacs-lisp-intro-es.info,  Node: Sin Aplazar,  Next: No aplazar la solución,  Prev: Patrones recursivos,  Up: Recursión

11.3.7 Recursión sin diferir
----------------------------

Permita considerar de nuevo qué ocurre con la función
‘triangle-recursively’.  Nosotros encontraremos que los cálculos
difieran hasta que todo pueda ser hecho.

   Aquí está la definición de función:

     (defun triangle-recursively (number)
       "Devuelve la suma de los números 1 a través de NUMBER inclusive
     Usa recursión."
       (if (= number 1)                    ; do-again-test
           1                               ; then-part
         (+ number                         ; else-part
            (triangle-recursively          ; recursive call
             (1- number)))))               ; next-step-expression

   ¿Qué ocurre cuando se llama a esta función con un argumento de 7?

   La primera instancia de la función ‘triangle-recursively’ añade el
número 7 al valor devuelto por una segunda instancia de
‘triangle-recursively’, una instancia que ha pasado un argumento de 6.
Así, el primer cálculo es:

     (+ 7 (triangle-recursively 6))

La primera instancia de ‘triangle-recursively’ -- se puede querer pensar
como un pequeño robot -- no puede completar su trabajo.  Eso debe
manejar el cálculo para ‘(triangle-recursively 6)’ a una segunda
instancia del programa, a un segundo robot.  Este segundo individuo es
completamente diferente desde el primero; eso es, en la jerga, una
'diferente instanciación'.  O, poner otro camino, eso es un diferente
robot.  Eso es el mismo modelo como el primero; eso calcula números de
triángulo recursivamente; pero eso tiene un número de serie diferente.

   ¿Y qué hace ‘(triangle-recursively 6)’ devuelve?  Eso devuelve el
número 6 añadido al valor devuelto para evaluar ‘triangle-recursively’
con un argumento de 5.  Usando la metáfora del robot, eso cuestiona
todavía otro robot para ayudarle.

   Ahora el total es:

     (+ 7 6 (triangle-recursively 5))

   ¿Y qué ocurre después?

     (+ 7 6 5 (triangle-recursively 4))

   Cada vez que ‘triangle-recursively’ es llamado, excepto por la última
vez, eso crea otra instancia del programa -- otro robot -- y pregunta
para crear un cálculo.

   Finalmente, la adición completa es de la siguiente manera:

     (+ 7 6 5 4 3 2 1)

   Este diseño para la función difiere el cálculo del primer paso hasta
el segundo puede ser hecho, y difiere esto hasta que el tercero puede
ser hecho, y así.  Cada defermento significa el ordenador debe recordar
que está siendo esperado dentro.  Esto no es un problema cuando hay solo
unos pocos pasos, como en este ejemplo.  Pero eso puede ser un problema
cuando hay más pasos.


File: emacs-lisp-intro-es.info,  Node: No aplazar la solución,  Prev: Sin Aplazar,  Up: Recursión

11.3.8 No hay solución pospuesta
--------------------------------

La solución al problema de operaciones pospuestas es para escribir en
una manera que no posponga operaciones(1).  Esto requiere escribir a un
patrón diferente, con frecuencia uno que involucra escribiendo dos
definiciones de función, una función de 'inicialización' y una función
'ayuda'.

   La función 'inicializacion' configura el trabajo; la función
'ayudante' hace el trabajo.

   Aquí hay dos definiciones para añadir números.  Son así de simple,
aunque se encuentre duro de comprender.

     (defun triangle-initialization (number)
       "Devuelve la suma de los números 1 a través de NUMBER inclusive.
     Este es el componente de `inicialización' de una función dúo que
     usa recursión"
       (triangle-recursive-helper 0 0 number))

     (defun triangle-recursive-helper (sum counter number)
       "Devuelve SUM, usando COUNTER, a través de NUMBER inclusive.
     Este es el componente `helper' de unas dos funciones
     que usan recursión."
       (if (> counter number)
           sum
         (triangle-recursive-helper (+ sum counter)  ; suma
                                    (1+ counter)     ; contador
                                    number)))        ; número

   Instalar ambas definiciones de función por evaluarlo, entonces llama
a ‘triangle-initialization’ con 2 filas:

     (triangle-initialization 2)
         ⇒ 3

   La función 'inicialización' llama la primera instancia de la función
'ayudante' con tres argumentos: cero, cero, y un número que es el número
de filas en el triángulo.

   Los primeros dos argumentos pasaron a la función 'ayuda' son valores
de inicialización.  Estos valores son cambiados cuando
‘triangle-recursive-helper’ invocan nuevas instancias.(2)

   Permítase ver que ocurre cuando tenemos un triángulo que tiene una
fila.  (¡Este triángulo tendrá un asterisco dentro!)

   ‘triangle-initialization’ llamará su ayudante con los argumentos
‘0 0 1’.  Esta función ejecutará el test condicional si ‘(> counter
number)’:

     (> 0 1)

y encuentra que el resultado es falso, así invocará la else-part de la
claúsula ‘if’:

         (triangle-recursive-helper
          (+ sum counter)  ; sum más counter ⇒ sum
          (1+ counter)     ; incrementa counter ⇒ counter
          number)          ; number parece lo mismo

que computará primero:

     (triangle-recursive-helper (+ 0 0)  ; sum
                                (1+ 0)   ; counter
                                1)       ; number
que es:

     (triangle-recursive-helper 0 1 1)

   De nuevo, ‘(> counter number)’ será falso, así de nuevo, el
intérprete Lisp evaluará ‘triangle-recursive-helper’, creando una nueva
instancia con nuevos argumentos.

   Esta nueva instancia será;

         (triangle-recursive-helper
          (+ sum counter)  ; suma más contador ⇒ sum
          (1+ counter)     ; incrementar contador ⇒ contador
          number)          ; número empieza lo mismo

que es:

     (triangle-recursive-helper 1 2 1)

   En este caso, el test ‘(> counter number)’ ¡será cierto!  Así la
instancia devolverá el valor de la suma, que será 1, como se espera.

   Ahora, permite pasar ‘triangle-initialization’ un argumento de 2,
para encontrar cuántos asterisco hay en un triángulo con dos filas.

   Esta función llama ‘(triangle-recursive-helper 0 0 2)’.

   En fases, las instancias llamadas serán:

                               suma contador número
     (triangle-recursive-helper 0    1       2)

     (triangle-recursive-helper 1    2       2)

     (triangle-recursive-helper 3    3       2)

   Cuando la última instancia se llama, el ‘(> counter number)’ se
chequea si será cierto, así la instancia devolverá el valor de ‘sum’,
que será 3.

   Este tipo de patrón ayuda cuando estás escribiendo funciones que
puede usar recursos en un ordenador.

   ---------- Footnotes ----------

   (1) La frase “cola recursiva” es usado para describir tal proceso,
uno que usa 'espacio constante'.

   (2) La jerga es medianamente confusa: ‘triangle-recursive-helper’ usa
un proceso que es iterativo en un procedimiento que es recursivo.  El
proceso se llama iterativo porque el ordenador necesita solo grabar los
tres valores, ‘suma’, ‘contador’, y ‘número’: el procedimiento es
recursivo porque la función 'llama a sí mismo'.  Por otro lado, ambos el
proceso y el procedimiento usado por ‘triangle-recursively’ son llamados
recursivos.  La palabra 'recursivo' tiene diferentes significados en los
dos contextos.


File: emacs-lisp-intro-es.info,  Node: Ejercicio de Bucle,  Prev: Recursión,  Up: Bucles y recursión

11.4 Ejercicio de bucles
========================

   • Escribe una función similar a ‘triangle’ en el que cada fila tiene
     un valor que es la raíz del número de la fila.  Usa un bucle
     ‘while’.

   • Escribe una función similar para ‘triangle’ que multiplique en vez
     de añadir los valores.

   • Reescribe estas dos funciones recursivamente.  Reescribe estas
     funciones usando ‘cond’.

   • Escribe una función para el modo Texinfo que crea una entrada
     índice al principio de un párrafo para cada ‘@dfn’ con el párrafo.
     (En un fichero Texinfo, ‘@dfn’ marca una definición.  El libro es
     escrito en Texinfo.)

     Muchas de las funciones necesitarán ser descritas en dos de los
     capítulos, *note Cortando y almacenando texto: Cortando y
     almacenando texto. y *note Pegando texto: Pegando.  Si usas
     ‘forward-paragraph’ para poner la entrada índice al principio del
     párrafo, tendrá que usar ‘C-h f’ (‘describe-function’) para
     encontrar cómo conseguir que el comando vaya hacia atrás.

     Para más información, ver *note texinfo: Indicando Definiciones.


File: emacs-lisp-intro-es.info,  Node: Buscar regexp,  Next: Contando palabras,  Prev: Bucles y recursión,  Up: Top

12 Búsquedas de expresiones regulares
*************************************

Las búsquedas expresiones regulares son usadas extensivamente en GNU
Emacs.  Las dos funciones ‘forward-sentence’ y ‘forward-paragraph’,
ilustran estas búsquedas bien.  Usan expresiones regulares para
encontrar donde mover el punto.  La frase 'expresión regular' es con
frecuencia escrita como 'regexp'.

   Las búsquedas de expresiones regulares son descritas en *note
Búsqueda de Expresión Regular: (emacs)Búsqueda de Regexp, tan bien como
en *note (elisp)Expresiones Regulares::.  Escribiendo este capítulo,
estoy presuponiendo que tiene al menos una familiaridad con esto.  El
mayor punto para recordar es que las expresiones regulares te permiten
buscar patrones tan bien como para cadenas literales de caracteres.  Por
ejemplo, el código en ‘forward-sentence’ busca para el patrón de
posibles caracteres que podrían marcar el fin de una frase, y mueve el
punto al otro lado.

   Antes de mirar en el código la función ‘forward-sentence’, es
valorable considerar que el patrón que marca el fin de una frase debe
estar.  El patrón se discute en la siguiente sección; siguiendo que es
una descripción de la expresión regular de búsqueda,
‘re-search-forward’.  La función ‘forward-sentence’ es descrito en la
sección siguiente.  Finalmente, la función ‘forward-paragraph’ es
descrito en la última sección de este capítulo.  ‘forward-paragraph’ es
una función compleja que introduce varias funcionalidades.

* Menu:

* sentence-end::             La expresión regular para
                               ‘sentence-end’.
* re-search-forward::        Muy similar a ‘search-forward’.
* forward-sentence::         Un ejemplo sencillo de búsqueda con
                               expresiones regulares.
* forward-paragraph::        Un ejemplo complejo de alguna cosa.
* etags::                    Cómo crear tu propia tabla ‘TAGS’.
* Revisar regexp::           Revisar regexp
* Ejercicios re-search::     Ejercicios re-search


File: emacs-lisp-intro-es.info,  Node: sentence-end,  Next: re-search-forward,  Up: Buscar regexp

12.1 La expresión regular para ‘sentence-end’
=============================================

El símbolo ‘sentence-end’ se asocia al patrón que marca el fin de una
frase.  ¿Cuál sería esta expresión regular?

   Claramente, una frase puede ser finalizada por un periodo, una marca
de inicio de interrogación, o una marca de exclamación.  Puesto que
viene del inglés, solo las claúsulas que finalizan con uno de estos tres
caracteres deberían ser consideradas al fin de una frase.  Esto
significa que el patrón incluiría el conjunto de caracteres:

     [.?!]

   Sin embargo, no queremos que ‘forward-sentence’ salte a un periodo,
una marca de pregunta, o una marca de exclamación, porque tal carácter
podría ser usado en el medio de una frase.  Un periodo, por ejemplo, se
usa después de abreviaciones.  Así, otra información es necesaria.

   De acuerdo a la convención, escribe dos espacios después de cada
frase, pero solo un espacio después de un periodo, una marca de
pregunta, o una marca de exclamación seguida por dos espacios es un buen
indicador de un fin de frase.  Sin embargo, en un fichero, los dos
espacios pueden ser un tabulador o el fin de una línea.  Esto significa
que la expresión regular incluiría estos tres ítems como alternativas.

   Este grupo de alternativas se parece a esto:

     \\($\\| \\|  \\)
            ^   ^^
           TAB  SPC

Aquí, ‘$’ indica el fin de la línea, y yo he apuntado donde el tab y dos
espacios están insertados en la expresión.  Ambos están insertados
poniendo los caracteres actuales dentro de la expresión.

   Dos barras invertidas, ‘\\’, se requiere antes de los paréntesis y
barras verticales: la primera barra invertida cita la siguiente barra
invertida en Emacs; y el segundo indica que el siguiente caracter, el
paréntesis o la barra vertical, es especial.

   También, una frase puede ser seguida por uno o más retornos de carro,
como este:

     [
     ]*

Como en los tabuladores y espacios, un retorno de carro se inserta
dentro de una expresión regular insertándolo literalmente.  El asterisco
indica que el <RET> se repite cero o más veces.

   Pero una frase no consiste solo en un periodo, una marca de pregunta
o una marca de exclamación seguida por espacios apropiados: una marca de
cerrar comillas o cerrar un paréntesis de algún tipo puede preceder el
espacio.  En realidad más de una marca o paréntesis pueden preceder el
espacio.  Estas requieren una expresión que se parezca a:

     []\"')}]*

   En esta expresión, el primer ‘]’ es el primer caracter en la
expresión; el segundo caracter es ‘"’, que está precedido por un ‘\’
para contar Emacs el ‘"’ _no_ es especial.  Los últimos tres caracteres
son ‘'’, ‘)’, y ‘}’.

   Todo esto sugiere que el patrón de la expresión regular para asociar
el fin de una frase sería; y, profundamente, si se evalúa ‘sentence-end’
y encuentra que se devuelve el valor siguiente:

     sentence-end
          ⇒ "[.?!][]\"')}]*\\($\\|     \\|  \\)[
     ]*"

(Bien, no en GNU Emacs 22; porque es un esfuerzo crear el proceso simple
y manejar más símbolos y lenguajes.  Cuando el valor de ‘sentence-end’
es ‘nil’, entonces usa el valor definido por la función ‘sentence-end’
es ‘nil’, entonces usa el valor definido por la función ‘sentence-end’.
(Aquí se usa la diferencia entre un valor y una función en Emacs Lisp.)
La función devuelve un valor construido desde las variables
‘sentence-end-base’, ‘sentence-end-double-space’,
‘sentence-end-without-period’, y ‘sentence-end-without-space’.  La
variable crítica es ‘sentence-end-base’; su valor global es similar a
uno descrito debajo pero también contiene marcas de cita adicionales.
Estas tienen diferentes grados de curvas.  La variable
‘sentence-end-without-period’, cuando es verdad, dice a Emacs que una
frase puede finalizar sin un periodo tal como texto en Thai.)


File: emacs-lisp-intro-es.info,  Node: re-search-forward,  Next: forward-sentence,  Prev: sentence-end,  Up: Buscar regexp

12.2 La función ‘re-search-forward’
===================================

La función ‘re-search-forward’ es similar a la función ‘search-forward’.
(*Note La Función ‘search-forward’: search-forward.)

   ‘re-search-forward’ busca una expresión regular.  Si la búsqueda es
exitosa, deja el punto inmediatamente después del último caracter en el
objetivo.  Si la búsqueda es hacia atrás, deja el punto antes del primer
caracter en el objetivo.  Se puede contar ‘re-search-forward’ para
devolver ‘t’ a cierto.  (Moviendo el punto es por ello un 'efecto
lateral'.)

   Como ‘search-forward’, la función ‘re-search-forward’ toma cuatro
argumentos:

  1. El primer argumento es la expresión regular que la función busca.
     La expresión regular será una cadena entre comillas.

  2. El segundo argumento opcional limita cómo la función busca; es un
     emparejamiento, que se especifica como una posición en el búffer.

  3. El tercer argumento opcional especifica cómo la función responde al
     fallo: ‘nil’ como tercer argumento que causa la función para
     señalar un error (e imprime un mensaje) cuando la búsqueda falla;
     cualquier otro valor causa devolver ‘nil’ si la búsqueda falla y
     ‘t’ si la búsqueda tiene éxito.

  4. El cuarto argumento opcional es el contaje repetido.  Un contaje
     negativo repetido causa ‘re-search-forward’ para buscar hacia
     atrás.

   La plantilla para ‘re-search-forward’ se parece a esto:

     (re-search-forward "REGULAR-EXPRESSION"
                     LIMIT-OF-SEARCH
                     WHAT-TO-DO-IF-SEARCH-FAILS
                     REPEAT-COUNT)

   El segundo, tercer, y cuarto argumentos son opcionales.  Sin embargo,
si se quiere pasar un valor a uno o ambos de los últimos dos argumentos,
se debe también pasar un valor a todos los argumentos precedentes.  De
otro modo, el intérprete Lisp errará a qué argumento estás pasando el
valor.

   En la función ‘forward-sentence’, la expresión regular será el valor
de la variable ‘sentence-end’.  En forma simple, esto es:

     "[.?!][]\"')}]*\\($\\|  \\|  \\)[
     ]*"

El límite de la búsqueda será el fin del párrafo (desde una frase no
puede ir bajo un párrafo).  Si la búsqueda falla, la función devuelve
‘nil’, y el contaje repite será provisto por el argumento para la
función ‘forward-sentence’.


File: emacs-lisp-intro-es.info,  Node: forward-sentence,  Next: forward-paragraph,  Prev: re-search-forward,  Up: Buscar regexp

12.3 ‘forward-sentence’
=======================

El comando mueve el cursor hacia adelante una frase es una ilustración
honesta de cómo usar búsquedas de expresiones regulares en Emacs Lisp.
En realidad, la función parece más larga y más complicada de lo que es;
esto es porque la función está diseñada para ir hacia atrás tan bien
como hacia adelante; y, opcionalmente, a través de una frase.  La
función está normalmente asociada al comando ‘M-e’.

* Menu:

* Completa forward-sentence::  Completa forward-sentence
* Bucles while fwd-sentence::  Dos bucles ‘while’.
* Volver a buscar la frase en sentido directo::  Una búsqueda de
                                                   expresión regular.


File: emacs-lisp-intro-es.info,  Node: Completa forward-sentence,  Next: Bucles while fwd-sentence,  Up: forward-sentence

Completa la definición ‘forward-sentence’
-----------------------------------------

Aquí está la código para ‘forward-sentence’:

     (defun forward-sentence (&optional arg)
       "Ve al siguiente `sentence-end'. Con el argumento, repite.
     Con el argumento negativo, mueve atrás repetidamente a `sentence-beginning'.
     La variable `sentence-end' es una expresión regular que empareja el
     fin de frases. También, cada párrafo asociado termina las frases
     bien.
       (interactive "p")
       (or arg (setq arg 1))
       (let ((opoint (point))
             (sentence-end (sentence-end)))
         (while (< arg 0)
           (let ((pos (point))
                 (par-beg (save-excursion (start-of-paragraph-text) (point))))
            (if (and (re-search-backward sentence-end par-beg t)
                     (or (< (match-end 0) pos)
                         (re-search-backward sentence-end par-beg t)))
                (goto-char (match-end 0))
              (goto-char par-beg)))
           (setq arg (1+ arg)))
         (while (> arg 0)
           (let ((par-end (save-excursion (end-of-paragraph-text) (point))))
            (if (re-search-forward sentence-end par-end t)
                (skip-chars-backward " \t\n")
              (goto-char par-end)))
           (setq arg (1- arg)))
         (constrain-to-field nil opoint t)))

   La función se ve larga a primera vista y es mejor mirar primero el
esqueleto, y entonces su músculo.  El camino para ver el esqueleto es
mirar en las expresiones que empiezan las columnas más a la izquierda:

     (defun forward-sentence (&optional arg)
       "DOCUMENTATION..."
       (interactive "p")
       (or arg (setq arg 1))
       (let ((opoint (point)) (sentence-end (sentence-end)))
         (while (< arg 0)
           (let ((pos (point))
                 (par-beg (save-excursion (start-of-paragraph-text) (point))))
            REST-OF-BODY-OF-WHILE-LOOP-WHEN-GOING-BACKWARDS
         (while (> arg 0)
           (let ((par-end (save-excursion (end-of-paragraph-text) (point))))
            REST-OF-BODY-OF-WHILE-LOOP-WHEN-GOING-FORWARDS
         HANDLE-FORMS-AND-EQUIVALENT

   ¡Esto parece bastante simple!  La definición de la función consiste
de documentación una expresión ‘interactive’, una expresión ‘or’, una
expresión ‘let’, y bucles ‘while’.

   Permite mirar cada una de estas partes.

   Notamos que la documentación es profunda y comprensible.

   La función tiene una declaración ‘interactive "p"’.  Esto signifca
que el argumento prefijo, si cualquiera es pasado a la función como su
argumento.  (Esto será un número.)  Si la función no pasa un argumento
(eso es opcional) entonces el argumento ‘arg’ será asociado a 1.

   Cuando ‘forward-sentence’ se llama no interactivamente sin un
argumento, ‘arg’ está asignado ‘nil’.  La expresión ‘or’ maneja esto.
Lo que hace es dejar el valor de ‘arg’ como eso es, pero solo si ‘arg’
está asignado a un valor; o eso asigna el valor de ‘arg’ a 1, en el caso
de ‘arg’ está asignado a ‘nil’.

   Lo siguiente es un ‘let’.  Que especifica los valores de dos
variables locales ‘point’ y ‘sentence-end’.  El valor local de punto,
desde antes de la búsqueda, es usada en la función ‘constrain-to-field’
que maneja formularios y equivalentes.  La variable ‘sentence-end’ está
asignada por la función ‘sentence-end’.


File: emacs-lisp-intro-es.info,  Node: Bucles while fwd-sentence,  Next: Volver a buscar la frase en sentido directo,  Prev: Completa forward-sentence,  Up: forward-sentence

Los bucles ‘while’
------------------

Sigue dos bucles ‘while’.  El primer ‘while’ tiene un true-or-false-test
que chequea cierto si el argumento prefijo para ‘forward-sentence’ es un
número negativo.  Esto es para volver hacia atrás.  El cuerpo de este
bucle es similar al cuerpo de la segunda cláusula ‘while’, pero eso no
es exactamente el mismo.  Se obviará este bucle ‘while’ y concentra en
el segundo bucle ‘while’.

   El segundo bucle ‘while’ está moviendo el punto hacia adelante.  Su
esqueleto se parece a esto:

     (while (> arg 0)            ; true-or-false-test
       (let VARLIST
         (if (TRUE-OR-FALSE-TEST)
             THEN-PART
           ELSE-PART
       (setq arg (1- arg))))     ; while loop decrementer

   El bucle ‘while’ es el tipo de decremento.  (*Note Un Bucle con un
Contador de Decremento: Bucle que se decrementa.)  Eso tiene un
true-or-false-test que chequea cierto tan largo con el contador (en este
caso, la variable ‘arg’) es mayor que cero; y eso tiene un decremento
que elimina 1 desde el valor del contador cada vez que el bucle se
repite.

   Si ningún argumento prefijo es dado para ‘forward-sentece’, que es el
camino más común es usado, este bucle ‘while’ ejecutará una vez, desde
que el valor de ‘arg’ será 1.

   El cuerpo del cuerpo ‘while’ consite de una expresión ‘let’, que crea
y asocia una variable local, y tiene, su cuerpo, una expresión ‘if’.

   El cuerpo del bucle ‘while’ se parece a esto:

     (let ((par-end
            (save-excursion (end-of-paragraph-text) (point))))
       (if (re-search-forward sentence-end par-end t)
           (skip-chars-backward " \t\n")
         (goto-char par-end)))

   La expresión ‘let’ crea y asocia la variable local ‘par-end’.  Como
se ve, esta variable local está diseñada para proporcionar una
asociación o límite para la búsqueda de la expresión regular.  Si la
búsqueda falla para encontrar una frase apropiada finalizando en el
párrafo, eso se parará logrando el fin del párrafo.

   Pero primero, permítenos examinar cómo ‘par-end’ se asocia a la
variable del fin del párrafo.  Lo que ocurre es que el ‘let’ asigna el
valor de ‘par-end’ al valor devuelto cuando el intérprete evalúa la
expresión.

     (save-excursion (end-of-paragraph-text) (point))

En esta expresión, ‘(end-of-paragraph-text)’ mueve el punto al fin del
párrafo, ‘(point)’ devuelve el valor del punto, y entonces
‘save-excursion’ restaura el punto a su posición original.  De este
modo, el ‘let’ asocia ‘par-end’ al valor devuelto por la expresión
‘save-excursion’, que es la posición del fin del párrafo.  (La función
‘end-of-paragraph-text’ usa ‘forward-paragraph’, que se discutirá
pronto.)

   Emacs evalúa el cuerpo del ‘let’, que es una expresión ‘if’ que se
parece a esto:

     (if (re-search-forward sentence-end par-end t) ; if-part
         (skip-chars-backward " \t\n")              ; then-part
       (goto-char par-end)))                        ; else-part

   El test ‘if’ si su primer argumento es cierto y si así, evalúa su
parte then; de otro modo, el intérprete Emacs Lisp evalúa la parte else.
El true-or-false-test de la expresión ‘if’ es la búsqueda de la
expresión regular.

   Puede estar mal tener que mirar como el 'trabajo real' de la función
‘forward-sentence’ es vista aquí, pero esto es un camino común de este
tipo de operación traida en Lisp.


File: emacs-lisp-intro-es.info,  Node: Volver a buscar la frase en sentido directo,  Prev: Bucles while fwd-sentence,  Up: forward-sentence

La búsqueda de expresiones regulares
------------------------------------

La función ‘re-search-forward’ busca el fin de la frase, que es, para el
patrón definido por la expresión regular ‘sentence-end’.  Si el patrón
es encontrado -- si el fin de la frase se encuentra -- entonces la
función ‘re-search-forward’ hace dos cosas:

  1. La función ‘re-search-forward’ trae un efecto lateral, que es mover
     el punto al final de la ocurrencia encontrada.

  2. La función ‘re-search-forward’ devuelve un valor de verdad.  Esto
     es el valor recibido por el ‘if’, y significa que la búsqueda fué
     exitosa.

El efecto lateral, el movimiento del punto se completa antes de la
función ‘if’ y es manejado por el valor devuelto por la exitosa
conclusión de la búsqueda.

   Cuando la función ‘if’ recibe el valor de verdad desde una llamada
exitosa a ‘re-search-forward’, el ‘if’ evalúa la parte then que es la
expresión ‘(skip-chars-backward "\t\n")’.  Esta expresión se mueve atrás
a través de espacios en blanco, los tabuladores o retornos de carro
hasta un caracter impreso es encontrado y entonces deja el punto
correcto después del caracter impreso cerrado de la frase, que es
normalmente un periodo.

   Por otro lado, si la función ‘re-search-forward’ falla para encontrar
un patrón marcando el fin de la frase, la función devuelve falso.  Lo
falso causa el ‘if’ para evaluar su tercer argumento, que es ‘(goto-char
par-end)’: eso mueve el punto al final del párrafo.

   (Y si el texto está en una forma o equivalente, y apunta a que no
puede moverse completamente entonces la función ‘constrain-to-field’
empieza a funcionar.)

   Las búsquedas de expresiones regulares son excepcionalmente útiles y
el patrón ilustrado por ‘re-search-forward’, en el que la búsqueda es el
test de una expresión ‘if’, es manejable.  Se verá o escribirá código
incorporando este patrón con frecuencia.


File: emacs-lisp-intro-es.info,  Node: forward-paragraph,  Next: etags,  Prev: forward-sentence,  Up: Buscar regexp

12.4 ‘forward-paragraph’: una mina de oro de funciones
======================================================

La función ‘forward-paragraph’ mueve el punto al fin del párrafo.  Eso
está normalmente asociado a ‘M-}’ y hace uso de un número de funciones
que son importantes en sí, incluyendo ‘let*’, ‘match-beginning’, y
‘looking-at’.

   La definición de función para ‘forward-paragraph’ es
considerablemente mayor que la definición de función para
‘forward-sentence’ porque eso funciona como un párrafo, cada línea puede
empezar con un prefijo de relleno _fill prefix_.

   Un prefijo de relleno _fill prefix_ consiste en una cadena de
caracteres que se repite al principio de cada línea.  Por ejemplo, en
código Lisp, es una convención para empezar cada línea de un comentario
de párrafo largo con ‘;;; ’.  En modo Texto, cuatro espacios en blanco
crean otro prefijo de relleno _fill prefix_ común, creando un párrafo
indentado.  (*Note (emacs)Fill Prefix:: para más información acerca de
prefijos de relleno _fill prefix_.)

   La existencia de un prefijo de relleno significa que además de ser
capaz de encontrar el fin de un párrafo cuyas líneas empiezan más a la
izquierda, la función ‘forward-paragraph’ debe ser capaz de encontrar el
fin de un párrafo cuando todas o muchas de las líneas en el búffer
empiezan con el prefijo de relleno _fill prefix_.

   Más allá, es algunas veces práctico ignorar un prefijo de relleno
_fill prefix_ que existe, especialmente cuando las líneas en blanco
separen párrafos.  Esto es una complicación añadida.

* Menu:

* forward-paragraph en breve::  Partes clave de la definición de la
                                  función.
* fwd-para let::             La expresión ‘let*’.
* fwd-para while::           El bucle ‘while’ con modo hacia adelante.


File: emacs-lisp-intro-es.info,  Node: forward-paragraph en breve,  Next: fwd-para let,  Up: forward-paragraph

Definición de función ‘forward-paragraph’
-----------------------------------------

En vez de imprimir toda la función ‘forward-paragraph’, nosotros solo
imprimiremos partes de la misma.  ¡Lee sin preparación, la función puede
estar para desanimar!

   En esquema, la función se parece a esto:

     (defun forward-paragraph (&optional arg)
       "DOCUMENTATION..."
       (interactive "p")
       (or arg (setq arg 1))
       (let*
           VARLIST
         (while (and (< arg 0) (not (bobp)))     ; backward-moving-code
           ...
         (while (and (> arg 0) (not (eobp)))     ; forward-moving-code
           ...

   Las primeras partes de la función son rutinas: la función lista
argumentos que consisten de un argumento opcional.  La documentación
sigue.

   La letra minúscula ‘p’ en la declaración ‘interactive’ significa que
el argumento prefijo se procesa, si se pasa a la función.  Eso será un
número, y es el contaje repetido de cuántos párrafos se moverá.  La
expresión ‘or’ en la siguiente línea maneja el caso común cuando no hay
argumentos que se pasan a la función, esto ocurre si la función se llama
desde otro código en vez de interactivamente.  Este caso se describe
pronto.  (*Note La función ‘forward-sentence’: forward-sentence.)  Ahora
se logra el fin de la parte familiar de esta función.


File: emacs-lisp-intro-es.info,  Node: fwd-para let,  Next: fwd-para while,  Prev: forward-paragraph en breve,  Up: forward-paragraph

La expresión ‘let*’
-------------------

La siguiente línea de la función ‘forward-paragraph’ empieza una
expresión ‘let*’.  Esto es tan diferente como ‘let’.  El símbolo es
‘let*’ no ‘let’.

   La forma especial ‘let*’ es como ‘let’ excepto que Emacs asigna cada
variable en secuencia, una después de otra, y las variables en la última
parte de la varlist hacen uso de los valores para los que Emacs asignó
variable al principio la varlist.

   (*note ‘save-excursion’ en ‘append-to-buffer’: append
save-excursion.)

   En la expresión ‘let*’ en esta función, Emacs asigna un total de
siete variables: ‘opoint’, ‘fill-prefix-regexp’, ‘parstart’, ‘parsep’,
‘sp-parstart’, ‘start’, y ‘found-start’.

   La variable ‘parsep’ aparece dos veces, primero, para borrar
instancias de ‘^’, y segundo, para manejar prefijos rellenos.

   La variable ‘opoint’ es solo el valor de ‘point’.  Como se puede
adivinar, eso se usa en una expresión ‘constrain-to-field’, solo como en
‘forward-sentence’.

   La variable ‘fill-prefix-regexp’ se asigna al valor devuelto para
evaluar la siguiente lista:

     (and fill-prefix
          (not (equal fill-prefix ""))
          (not paragraph-ignore-fill-prefix)
          (regexp-quote fill-prefix))

Esta es una expresión cuyo primer elemento es la forma especial ‘and’.

   Como se aprendió antes la (*note La función ‘kill-new’: Función
kill-new.), la forma especial ‘and’ evalúa cada uno de sus argumentos
hasta uno de los argumentos y devuelve un valor de ‘nil’ en el que el
caso de la expresión ‘and’ devuelve ‘nil’; sin embargo, si ninguno de
los argumentos devuelve un valor de ‘nil’, el valor resultante de
evaluar el último argumento es devuelto.  (Puesto que tal valor no es
‘nil’, eso es considerado verdad en Lisp.)  En otras palabras, una
expresión ‘and’ devuelve un valor de verdad solo si todos sus argumentos
son verdad.

   En este caso, la variable ‘fill-prefix-regexp’ está asociado a un
valor no ‘nil’ solo si el las siguientes cuatro expresiones producen un
valor true (por ej., un no ‘nil’) cuando son evaluados; de otro modo,
‘fill-prefix-regexp’ está asociado a ‘nil’.

‘fill-prefix’
     Cuando esta variable se evalúa, el valor del prefijo de relleno
     _fill prefix_, si cualquiera, está devuelto.  Si no hay prefijo
     relleno, la variable devuelve ‘nil’.

‘(not (equal fill-prefix "")’
     Esta expresión chequea si un prefijo lleno es una cadena vacía, que
     es, una cadena sin caracteres en eso.  Una cadena vacía no es útil
     un prefijo relleno _fill prefix_.

‘(not paragraph-ignore-fill-prefix)’
     Esta expresión devuelve ‘nil’ si la variable
     ‘paragraph-ignore-fill-prefix’ ha sido cambiado siendo asignado un
     valor de verdad tal como ‘t’.

‘(regexp-quote fill-prefix)’
     Este es el último argumento para la forma especial ‘and’.  Si todos
     los argumentos de ‘and’ son verdaderos, el valor resultante de
     evaluar esta expresión será devuelto por la expresión ‘and’ y
     asociado a la variable ‘fill-prefix-regexp’,

El resultado de evaluar esta expresión ‘and’ con éxito es que
‘fill-prefix-regexp’ se asociará al valor de ‘fill-prefix’ como fué
modificado por la función ‘regexp-quote’.  Lo que ‘regexp-quote’ hace es
leer una cadena y devolver la expresión regular que asociará exactamente
la cadena y nada más.  Esto significa que ‘fill-prefix-regexp’ será
asignada a un valor que asociará el prefijo si el prefijo existe.  De
otro modo, la variable será asignada a ‘nil’.

   Las dos variables locales siguientes en la expresión ‘let*’ están
diseñadas para eliminar instancias de ‘^’ desde ‘parstart’ y ‘parsep’,
las variables locales indican que el párrafo empieza como separador de
párrafo.  La siguiente expresión asigna ‘parsep’ de nuevo.  Esto es
manejar prefijos rellenos.

   Esta es la configuración que requiere la llamada de la definición
‘let*’ en vez de ‘let’.  El true-or-false-test para el ‘if’ depende de
si la variable ‘fill-prefix-regexp’ evalúa a ‘nil’ o algún otro valor.

   Si ‘fill-prefix-regexp’ no tiene un valor, Emacs evalúa la parte else
de la expresión ‘if’ y asocia ‘parsep’ a su valor local.  (‘parsep’ es
una expresión regular que asocia lo que los párrafos separan.)

   Pero si ‘fill-prefix-regexp’ tiene un valor, Emacs evalúa la parte
then de la expresión ‘if’ y asocia ‘parsep’ a una expresión regular que
incluye el ‘fill-prefix-regexp’ como parte del patrón.

   Específicamente, ‘parsep’ está asignado al valor original del párrafo
que separa la expresión regular concatenada con una expresión
alternativa que consiste del ‘fill-prefix-regexp’ seguido por espacios
en blanco opcionales para el fin de la línea.  El espacio en blanco está
definido por ‘"[ \t]*$"’.)  El ‘\\|’ define esta porción del regexp como
una alternativa a ‘parsep’.

   De acuerdo a un comentario en el código, la siguiente variable local,
‘sp-parstart’, se usa para buscar, y entonces los dos finales, ‘start’ y
‘found-start’, se asignan a ‘nil’.

   Ahora tenemos dentro el cuerpo del ‘let*’.  La primera parte del
cuerpo del ‘let*’ trata con el caso cuando la función es dada a un
argumento negativo y consiguientemente moviéndose hacia atrás.  Nosotros
saldremos de esta sección yendo hacia atrás.


File: emacs-lisp-intro-es.info,  Node: fwd-para while,  Prev: fwd-para let,  Up: forward-paragraph

El bucle ‘while’ hacia adelante
-------------------------------

La segunda parte del cuerpo del ‘let*’ trata con el proceso hacia
adelante.  Eso es un bucle ‘while’ que se repite si el valor de ‘arg’ es
mayor que cero.  En el uso más común de la función el valor del
argumento es 1, así el cuerpo del bucle ‘while’ se evalúa exactamente
una vez, y el cursor se mueve hacia adelante un párrafo.

   Esta parte maneja tres situaciones: cuando el punto está entre
párrafos, cuando hay un prefijo de relleno y cuando no hay prefijo de
relleno _fill prefix_.

   El bucle ‘while’ se parece a esto:

     ;; yendo hacia adelante y no al fin del búffer
     (while (and (> arg 0) (not (eobp)))

       ;; entre párrafos
       ;; Mueve hacia adelante a través de líneas de
       ;; separación...
       (while (and (not (eobp))
                   (progn (move-to-left-margin) (not (eobp)))
                   (looking-at parsep))
         (forward-line 1))
       ;;  Esto decremento el bucle
       (unless (eobp) (setq arg (1- arg)))
       ;; ... y una línea más
       (forward-line 1)

       (if fill-prefix-regexp
           ;; Hay un prefijo lleno; que sobreescribe parstart;
           ;; vamos adelante línea por línea
           (while (and (not (eobp))
                       (progn (move-to-left-margin) (not (eobp)))
                       (not (looking-at parsep))
                       (looking-at fill-prefix-regexp))
             (forward-line 1))

         ;; No hay prefijo;
         ;; vamos hacia adelante caracter por caracter
         (while (and (re-search-forward sp-parstart nil 1)
                     (progn (setq start (match-beginning 0))
                            (goto-char start)
                            (not (eobp)))
                     (progn (move-to-left-margin)
                            (not (looking-at parsep)))
                     (or (not (looking-at parstart))
                         (and use-hard-newlines
                              (not (get-text-property (1- start) 'hard)))))
           (forward-char 1))

         ;; y si no hay prefijo y si no estamos al final
         ;; ir a lo que fué encontrado en la búsqueda de expresiones regulares
         ;; para sp-parstart
         (if (< (point) (point-max))
             (goto-char start))))

   Se puede ver que esto es un contador de decremento ‘while’, usando la
expresión ‘(setq arg (1- arg))’ como lo que se decrementa.  Esta
expresión no está lejos desde el ‘while’, pero está oculta en otra macro
Lisp, una macro ‘unless’.  A menos que estemos al final del búffer --
esto es lo que la función ‘eobp’ determina; eso es una abreviación de
‘Fin del Buffer P’ -- nosotros decrementamos el valor de ‘arg’ por uno.

   (Si estamos al fin del búffer, no podemos ir más hacia adelante y el
siguiente bucle de la expresión ‘while’ chequeará falso desde que el
test es un ‘and’ con ‘(not (eobp))’.  La función ‘not’ significa
exactamente como se esperaba; eso es otro nombre de ‘null’, una función
que devuelve cierto cuando su argumento es falso.)

   De manera interesante, el bucle cuenta que no se decrementa hasta que
deje el espacio entre párrafos, a menos que vuelva al fin del búffer o
pare viendo el valor local del separador del párrafo.

   El segundo ‘while’ también tiene una expresión
‘(move-to-left-margin)’.  La función es autoexplicativa.  Eso está
dentro de una expresión ‘progn’ y no el último elemento de su cuerpo,
así es solo invocado para su efecto lateral, que es mover el punto al
margen izquierdo de la línea actual.

   La función ‘looking-at’ es también auto-explicativa; eso devuelve
cierto si el texto después del punto asocia la expresión regular dada
como su argumento.

   El resto del cuerpo del bucle se ve compleja al principio, pero tiene
sentido cuando se comprende.

   Primero considera que ocurre si hay un prefijo de relleno _fill
prefix_:

       (if fill-prefix-regexp
           ;; Hay un prefijo lleno; que sobreescribe parstart;
           ;; vamos adelante línea por línea
           (while (and (not (eobp))
                       (progn (move-to-left-margin) (not (eobp)))
                       (not (looking-at parsep))
                       (looking-at fill-prefix-regexp))
             (forward-line 1))

Esta expresión mueve el punto hacia adelante línea por línea tan lejos
como que las cuatro condiciones son ciertas:

  1. Punto no está al final del búffer.

  2. Podemos mover al margen izquierdo del texto y no estar al fin del
     búffer.

  3. El siguiente punto no separa párrafos.

  4. El patrón que sigue el punto es la expresión regular prefija
     rellena.

   La última condición puede ser un puzzle, hasta que se recuerde qué
punto fué movido al principio de la línea temprana en la función
‘forward-paragraph’.  Esto significa que si el texto tiene el prefijo
relleno, la función ‘looking-at’ se verá.

   Considera qué ocurre cuando no hay un prefijo lleno.

         (while (and (re-search-forward sp-parstart nil 1)
                     (progn (setq start (match-beginning 0))
                            (goto-char start)
                            (not (eobp)))
                     (progn (move-to-left-margin)
                            (not (looking-at parsep)))
                     (or (not (looking-at parstart))
                         (and use-hard-newlines
                              (not (get-text-property (1- start) 'hard)))))
           (forward-char 1))

El bucle ‘while’ nos tiene buscando hacia adelante para ‘sp-parstart’,
que es la combinación de posibles espacios en blanco con un valor local
del comienzo de un párrafo o de un párrafo separador.  (Las últimas dos
son con una expresión empezando con ‘(?:)’ así que no están
referenciadas por la función ‘match-beginning’.)

   Las dos expresiones,

     (setq start (match-beginning 0))
     (goto-char start)

significa ir al comienzo del siguiente texto localizado por la expresión
regular.

   La expresión ‘(match-beginning 0)’ es nueva.  Eso devuelve un número
especificando la posición del comienzo del texto fuese asociado a la
última búsqueda.

   La función ‘match-beginning’ es usado aquí porque una característica
de una búsqueda hacia adelante: una búsqueda hacia adelante, sin
dignidad si eso es una búsqueda plana o una expresión regular, mueve el
punto al fin del texto que es encontrado.  En este caso, una búsqueda
exitosa mueve el punto al fin del patrón para ‘sp-parstart’.

   Sin embargo, se quiere poner el punto al fin del actual párrafo, no
en algún lugar más.  En vez de eso, desde que la búsqueda posiblemente
incluye el separador del párrafo, el punto puede finalizar al principio
de lo siguiente a menos que se use una expresión que incluya
‘match-beginning’.

   Cuando un argumento de 0, ‘match-beginning’ devuelve la posición que
es el comienzo del texto asociado por la búsqueda más reciente.  En este
caso, la búsqueda más reciente parece ‘sp-parstart’.  La expresión
‘(match-beginning 0)’ devuelve la posición del comienzo de este patrón,
en vez de la posición final de este patrón.

   (Incidentalmente, cuando se pasa un número positivo como un
argumento, la función ‘match-beginning’ devuelve la localización de
punto en el que la expresión con paréntesis en la última búsqueda a
menos que la expresión con paréntesis empiece con ‘\(?:’.  No sé porque
‘\(?:’ aparece aquí desde que el argumento es 0.)

   La última expresión cuando no hay prefijos es

     (if (< (point) (point-max))
         (goto-char start))))

Esto dice que si no hay prefijo lleno y no estamos al punto final que se
movería al principio de lo que fué encontrado por la búsqueda de la
expresión regular para ‘sp-parstart’.

   La definición completa para la función ‘forward-paragraph’ no solo
incluye código para avanzar, también código para retroceder.

   Si está leyendo esto dentro de GNU Emacs y quieres ver la función
completa, se puede escribir ‘C-h f’ (‘describe-function’) y el nombre de
la función.  Esto da la documentación de función y el nombre de la
librería conteniendo las fuentes de la función.  Posiciona el punto a
través del nombre de la librería y presionar la tecla RET; será tomado
directamente a las fuentes.  (¡Asegúrate de instalar las fuentes!  ¡Sin
eso, estarás como una persona que intenta conducir un coche con los ojos
cerrados!)


File: emacs-lisp-intro-es.info,  Node: etags,  Next: Revisar regexp,  Prev: forward-paragraph,  Up: Buscar regexp

12.5 Crea tu propio fichero ‘TAGS’
==================================

Bajo ‘C-h f’ (‘describe-function’), otro camino para ver la fuente de
una función es escribir ‘M-.’ (‘find-tag’) y el nombre de la función se
asigna para eso.  Esto es un buen hábito para obtenerlo.  El comando
‘M-.’ (‘find-tag’) toma directamente a las fuentes de una función,
variable, o nodo.  La función depende de tablas de etiquetas para saber
donde ir.

   Si la función ‘find-tag’ pregunta primero por el nombre de una tabla
‘TAGS’, dado el nombre de un fichero ‘TAGS’ tal como
‘/usr/local/src/emacs/src/TAGS’.  (La ruta exacta a tu fichero ‘TAGS’
depende de cómo tu copia de Emacs fué instalada.  Yo te cuento la
localización que provee tanto mi C y mis fuentes de Emacs Lisp.)

   Se puede también crear tu propio fichero ‘TAGS’ para los directorios
que faltan.

   Con frecuencia se necesita construir e instalar etiquetas de tablas
por uno mismo.  Esas no son construidas automáticamente.  Una tabla de
etiquetas llama a un fichero ‘TAGS’; el nombre es letras mayúsculas.

   Se puede crear un fichero ‘TAGS’ llamando el programa ‘etags’ que
viene como parte de la distribución Emacs.  Normalmente, ‘etags’ está
compilado e instalado cuando Emacs se construye.  (‘etags’ no es una
función Lisp o una parte de Emacs; eso es un programa C.)

   Para crear el fichero ‘TAGS’, primero cambia el directorio en el que
se quiere crear el fichero.  En Emacs se puede hacer esto con el comando
‘M-x cd’, o visitando un fichero en el directorio, o listando el
directorio ‘etags *.el’ como el comando a ejecutar

     M-x compile RET etags *.el RET

crear un fichero de ‘TAGS’ para Emacs Lisp.

   Por ejemplo, si se tiene un gran número de ficheros en el directorio
‘~/emacs’, como se hace -- Yo tengo 137 ‘.el’ dentro, de que se carguen
12 -- se puede crear un fichero ‘TAGS’ para los ficheros Emacs Lisp en
este directorio.

   El programa ‘etags’ toma en toda la consola usual 'comodines'.  Por
ejemplo, si tienes dos directorios para el que quieres un fichero ‘TAGS’
simple, escribe ‘etags *.el ../elisp/*.el’, donde ‘../elisp/’ es el
segundo directorio:

     M-x compile RET etags *.el ../elisp/*.el RET

   Tipo

     M-x compile RET etags --help RET

para ver una lista de las opciones aceptadas por ‘etags’ tan bien como
una lista de lenguajes soportados.

   El programa ‘etags’ maneja más de 20 lenguajes, incluyendo Emacs
Lisp, Common Lisp, Scheme, C, C++, Ada, Fortran, HTML, Java, LaTeX,
Pascal, Perl, Postscript, Python, TeX, Texinfo, makefiles, y la mayoría
de ensambladores.  El programa no cambia para especificar el lenguaje;
eso reconoce el lenguaje como una entrada de fichero de acuerdo a su
nombre de fichero y contenidos.

   ‘etags’ es muy útil cuando se escribe código por tí mismo y quiere
referirse a funciones que ya se han escrito.  Ahora ejecuta ‘etags’ de
nuevo en intervalos como se escriben nuevas funciones, así llegan a ser
parte del fichero ‘TAGS’.

   Si piensa que un fichero ‘TAGS’ apropiado que ya existe para lo que
quieres, pero no conoces donde está, se puede usar el programa ‘locate’
para intentar encontrarlo.

   Escribe ‘M-x locate <RET> TAGS <RET>’ y Emacs listará para ti las
rutas nombres completas de todos tus ficheros ‘TAGS’.  En mi sistema,
este comando lista 34 fichero ‘TAGS’.  Por otro lado, un sistema
'vanilla plano' que recientemente no contenía fichero ‘TAGS’.

   Si la tabla de etiquetas que se quiere ha sido creada, se puede usar
el comando ‘M-x visit-tags-table’ para especificarlo.  De otro modo, se
necesitará la tabla de etiquetas por tí mismo y entonces usar ‘M-x
visit-tags-table’.

Construyendo Etiquetas en las fuentes Emacs
...........................................

Las fuentes GNU Emacs vienen con un ‘Makefile’ que contiene un comando
sofisticado ‘etags’ que crea, recoge, y asocia tablas de etiquetas de
todas las fuentes de Emacs y pone la información dentro de un fichero
‘TAGS’ en el directorio ‘src/’.  (El directorio ‘src/’ está debajo del
alto nivel de tu directorio Emacs.)

   Para construir este fichero ‘TAGS’, se puede ir al alto nivel de
directorio de fuentes Emacs y ejecutar el comando de compilar ‘make
tags’:

     M-x compile RET make tags RET

(El comando ‘make tags’ trabaja bien con las fuentes de GNU Emacs, tan
bien como con otros paquetes fuentes.)

   Para más información, mira *note Tablas de Etiquetas:
(emacs)Etiquetas.


File: emacs-lisp-intro-es.info,  Node: Revisar regexp,  Next: Ejercicios re-search,  Prev: etags,  Up: Buscar regexp

12.6 Revisar
============

Aquí hay un breve resumen de algunas funciones introducidas
recientemente.

‘while’
     Repetidamente evalúa el cuerpo de la expresión tan larga como el
     primer elemento del cuerpo chequea cierto.  Entonces devuelve
     ‘nil’.  (La expresión es evaluado solo por sus efectos laterales.)

     Por ejemplo:

          (let ((foo 2))
            (while (> foo 0)
              (insert (format "foo is %d.\n" foo))
              (setq foo (1- foo))))

               ⇒      foo is 2.
                       foo is 1.
                       nil

     (La función ‘insert’ inserta sus argumentos en el punto; la función
     ‘format’ devuelve una cadena formateada desde sus argumentos el
     camino ‘message’ formatea sus argumentos; ‘\n’ produce una nueva
     línea.)

‘re-search-forward’
     Busca un patrón, y si el patrón se encuentra, mueve el punto al
     resto solo después de eso.

     Toma cuatro argumentos, como ‘search-forward’:

       1. Una expresión regular que especifica el patrón para buscarlo.
          (¡Recuerda por marcas de comillas alrededor de este
          argumento!)

       2. Opcionalmente, el límite de la búsqueda.

       3. Opcionalmente, que haces si la búsqueda falla, devuelve ‘nil’
          o un mensaje de error.

       4. Opcionalmente, cuántas veces se puede repetir la búsqueda; si
          es negativa, la búsqueda va hacia atrás.

‘let*’
     Asocia algunas variables localmente a valores particulares, y
     entonces evalúa los argumentos que permanencen, devolviendo el
     valor del último.  Mientras se asocian las variables locales, se
     usan los valores locales de variables asociadas pronto, si acaso.

     Por ejemplo:

          (let* ((foo 7)
                (bar (* 3 foo)))
            (message "`bar' is %d." bar))
               ⇒ `bar' is 21.

‘match-beginning’
     Devuelve la posición del principio del texto encontrado por la
     última búsqueda de la expresión regular.

‘looking-at’
     Devuelve ‘t’ para verdadero si el texto después del punto se asocia
     al argumento, que debería ser una expresión.

‘eobp’
     Devuelve ‘t’ para cierto si el punto está en el fin de la parte
     accesible de un búffer.  El fin de la parte accesible es el fin del
     búffer no está encogido; eso es el fin de la parte encogida si el
     búffer está encogido.


File: emacs-lisp-intro-es.info,  Node: Ejercicios re-search,  Prev: Revisar regexp,  Up: Buscar regexp

12.7 Ejercicios con ‘re-search-forward’
=======================================

   • Escribe una función para buscar para una expresión que detecte dos
     o más líneas blancas en secuencia.

   • Escribe una función para buscar palabras duplicadas, tales como 'el
     el'.  *Note Sintaxis para Expresiones Regulares: (emacs)Regexps,
     para información de cómo escribir un regexp (una expresión regular)
     para asociar una cadena que se compone de dos mitades idénticas.
     Se puede disponer de varios regexps; algunos son mejores que otros.
     La función que se usa es descrito en un apéndice, a lo largo de
     varios regexps.  *Note Función de Palabras Duplicadas ‘the-the’:
     the-the.


File: emacs-lisp-intro-es.info,  Node: Contando palabras,  Next: Palabras en una función,  Prev: Buscar regexp,  Up: Top

13 Contando: repetición y regexps
*********************************

La repetición y búsqueda de expresiones regulares son herramientas
poderosas que con frecuencia se usan cuando se escribe código en Emacs
Lisp.  Este capítulo ilustra el uso de búsqueda de expresiones regulares
a través de la construcción de comandos de contaje de palabras usando
bucles ‘while’ y recursión.

* Menu:

* Por qué Contar Palabras::  Por qué Contar Palabras
* count-words-example::      Usa un regexp, pero encuentra un problema.
* recursive-count-words::    Empezar en caso de que no haya palabras en la
                               región.
* Ejercicio de Contar::      Ejercicio de Contar


File: emacs-lisp-intro-es.info,  Node: Por qué Contar Palabras,  Next: count-words-example,  Up: Contando palabras

Contando palabras
=================

La distribución de Emacs estándar contiene una función para contar el
número de líneas en una región.

   Hay cierto tipo de pregunta escrita para contar palabras.  De este
modo, si se escribe un ensayo, puede limitarse a 800 palabras; si se
escribe una novela, te puedes disciplinar a ti mismo a escribir 1000
palabras al día.  Parece raro, pero durante mucho tiempo, a Emacs le
faltó un comando para contar palabras.  Quizás la gente usaba Emacs
mayoritariamente para codificar o documentar cosas que no requieren
contar palabras, o quizás se restringían al sistema operativo el comando
de contar palabras, ‘wc’.  De manera alternativa, la gente puede seguir
la convención de las editoriales y computaban un contaje de palabras
dividiendo el número de caracteres en un documento por cinco.

   Hay mucho caminos para implementar un comando para contar palabras.
Aquí hay algunos ejemplos, que pueden desear compararse con el comando
de Emacs estándar, ‘count-words-region’.


File: emacs-lisp-intro-es.info,  Node: count-words-example,  Next: recursive-count-words,  Prev: Por qué Contar Palabras,  Up: Contando palabras

13.1 La función ‘count-words-example’
=====================================

Un comando de contar palabras podría contar palabras en una línea,
párrafo, región, o búffer.  ¿Qué comando funcionaría?  Se podría diseñar
el comando para contar el número de palabras en un búffer completo.  Sin
embargo, la tradición Emacs anima a la flexibilidad -- se puede querer
contar palabras solo en una sección, en vez de en todo un búffer.  Así,
tiene más sentido diseñar el comando para contar el número de palabras
en una región.  Una vez tienes un comando ‘count-words-region’, se
puede, si desea, contar palabras en un búffer completo marcándolo con
‘C-x h’ (‘mark-whole-buffer’).

   Claramente, contar palabras es un acto repetitivo: empezando desde el
principio de la región, se cuenta la primera palabra, entonces la
segunda palabra, entonces la tercera palabra, y así, hasta que logres el
fin de la región.  Esto significa que contar palabras se ajusta
idealmente a recursión o a un bucle ‘while’.

* Menu:

* Diseñar count-words-example::  La definición usando un bucle
                                     ‘while’.
* Error de espacio en blanco::  El error de espacio en blanco en
                                  ‘count-words-example’.


File: emacs-lisp-intro-es.info,  Node: Diseñar count-words-example,  Next: Error de espacio en blanco,  Up: count-words-example

Diseñando ‘count-words-example’
-------------------------------

Primero, implementaremos el comando de contar palabras con un bucle
‘while’, entonces con la recursión.  El comando, de acuerdo, será
interactivo.

   La plantilla para una definición de función interactiva es, como
siempre:

     (defun NAME-OF-FUNCTION (ARGUMENT-LIST)
       "DOCUMENTATION..."
       (INTERACTIVE-EXPRESSION...)
       BODY...)

   Lo que necesitamos hacer es rellenar los slots.

   El nombre de la función sería auto-explicativo y similar al nombre
del ‘count-lines-region’ existente.  Esto hace que el nombre sea fácil
de recordar.  ‘count-words-region’ es una buena elección.  Puesto que el
nombre se usa ahora para el comando de Emacs estándar para contar
palabras, nosotros nombraremos nuestra implementación como
‘count-words-example’.

   La función cuenta palabras con una región.  Esto significa que el
argumento lista debe contener símbolos que son asociados a las dos
posiciones, el principio y fin de la región.  Estas dos posiciones puede
ser llamadas ‘beginning’ y ‘end’ respectivamente.  La primera línea de
la documentación sería una frase simple, desde que esto es todo lo que
está impreso como documentación por un comando tal como ‘apropos’.  La
expresión interactiva será de la forma ‘(interactive "r")’, puesto que
causará que Emacs pase al principio y fin de la región a la lista de
argumentos de función.  Todo esto es rutina.

   El cuerpo de la función necesita ser escrita para hacer tres tareas:
primero, configurar condiciones bajo las que el bucle ‘while’ pueda
contar palabras, segundo, ejecutar el bucle ‘while’, y tercero, enviar
un mensaje al usuario.

   Cuando un usuario llama a ‘count-words-example’, apunta a que puede
estar al principio o fin de la región.  Sin embargo, el proceso de
conteo debe empezar al principio de la región.  Esto significa que
querremos poner el punto que hay si eso no está allí.  Ejecutando
‘(goto-char beginning)’ asegura esto.  De acuerdo, querremos devolver el
punto a su posición esperada cuando la función finalice su trabajo.  Por
esta razón, el cuerpo debe ser encerrado en una expresión
‘save-excursion’.

   La parte central del cuerpo de la función consiste en un bucle
‘while’ en el que una expresión salta el punto hacia delante palabra por
palabra, y otra expresión cuenta estos saltos.  Si el
test-verdadero-o-falso del bucle ‘while’ es verdadero, el punto saltaría
hacia adelante, y si es falso el punto estaría al fin de la región.

   Nosotros podríamos usar ‘(forward-word 1)’ como la expresión para
mover el punto hacia adelante palabra por palabra, pero eso es fácil de
ver que Emacs identifica como una 'palabra' si se usa una búsqueda de
expresión regular.

   Una expresión regular busca lo que encuentra el patrón que se está
buscando deja el punto después del último carácter emparejado.  Esto
significa que una sucesión de palabras exitosas busquen que moverá el
punto adelante palabra por palabra.

   Como materia práctica, se quiere que la expresión regular se busque
para saltar a través de un espacio en blanco y puntúe entre palabras tan
bien a través de las palabras en sí.  Una expresión regexp que rechaza
para saltar a través de espacios en blanco entre palabras ¡nunca
saltaría más de una palabra!.  Esto significa que el regexp incluiría el
espacio en blanco y la puntuación sigue a una palabra cualquiera, como
la palabra en sí.  (Una palabra puede finalizar un búffer y no tiene
cualquier espacio en blanco o puntuación, así esta parte del regexp debe
ser opcional.)

   De este modo, queremos para el regexp es un patrón definiendo una o
más palabras de caracteres que constituyen caracteres seguidos,
opcionalmente, por uno o más caracteres que no son palabras
constituyentes.  La expresión regular para esto es:

     \w+\W*

La tabla de sintaxis del búffer determina qué caracteres son y no son
palabras constituyentes.  Para más información acerca de sintaxis, *note
Tablas de Sintaxis: (elisp)Tablas de Sintaxis.

   La expresión se parece a esto:

     (re-search-forward "\\w+\\W*")

(Note que las barras invertidas que preceden el ‘w’ y ‘W’.  Una barra
invertida tiene significado especial al intérprete Emacs Lisp.  Eso
indica que el caracter siguiente es interpretado de manera diferente que
la normal.  Por ejemplo, los dos caracteres, ‘\n’, son una ‘nueva
línea’, en vez de una barra invertida seguida por ‘\n’.  Dos barras
invertidas en una fila para una 'barra invertida no especial', así Emacs
Lisp interpreta el fin de mirar una barra invertida simple seguida por
una letra.  Así descubre la letra que es especial.)

   Se necesita un contador para contar cuántas palabras hay; esta
variables debe primero ser asignado a 0 y entonces incrementados cada
vez que Emacs va alrededor del bucle ‘while’.  La expresión de
incremento es simple:

     (setq count (1+ count))

   Finalmente, se quiere contar al usuario cuántas palabras hay en la
región.  La función ‘message’ presenta este tipo de información al
usuario.  El mensaje tiene que ser fraseado de manera que se lea
apropiadamente sin cuidado de cuantas palabras hay en la región: no se
quiere decir que "hay una palabra en la región".  El conflicto entre
singular y plural no es gramatical.  Se puede resolver este problema
usando una expresión condicional que evalúa diferentes mensajes
dependiendo en el número de palabras en la región.  Hay tres
posibilidades: no palabras en la región, una palabra en la región, y más
de una palabra.  Esto significa que la forma especial ‘cond’ es
apropiada.

   Todo esto lidera a la siguiente definición de función:

     ;;; ¡La Primera versión; tiene errores!
     (defun count-words-region (beginning end)
       "Imprime el número de palabras en la región.
     Las palabras están definidas al menos una palabra
     constituida de caracteres seguido por al menos un
     caracter que no constituye palabra. La tabla de
     sintaxis del búffer determina qué caracteres hay."
       (interactive "r")
       (message "Contando palaras en la región ... ")

     ;;; 1. Configurar condiciones apropiadas.
       (save-excursion
         (goto-char beginning)
         (let ((count 0))

     ;;; 2. Ejecutar el bucle while.
           (while (< (point) end)
             (re-search-forward "\\w+\\W*")
             (setq count (1+ count)))

     ;;; 3. Enviar un mensaje al usuario.
           (cond ((zerop count)
                  (message
                   "La región no tiene palabras."))
                 ((= 1 count)
                  (message
                   "La región tiene 1 palabra."))
                 (t
                  (message
                   "La región tiene %d palabras." count))))))

Como se escribe, la función funciona, pero no en todas las
circunstancias.


File: emacs-lisp-intro-es.info,  Node: Error de espacio en blanco,  Prev: Diseñar count-words-example,  Up: count-words-example

13.1.1 El error de espacio en blanco en ‘count-words-example’
-------------------------------------------------------------

El comando ‘count-words-example’ descrito en la sección precedente tiene
dos errores, o incluso, un error con dos manifestaciones.  Primero, si
se marca una región conteniendo solo espacio en blanco en el medio de
algún texto el comando ¡‘count-words-example’ cuenta que la región
contiene una palabra!.  Segundo, si se marca una región conteniendo solo
espacios en blanco al final del búffer o la porción accesible de un
búffer encogido, el comando muestra un mensaje de error que se parece a
esto:

     Búsqueda fallida: "\\w+\\W*"

   Si está leyendo esto en Info en GNU Emacs, se puede testear para
estos errores por sí mismo.

   Primero, evalúa la función de la manera usual para instalarlo.  Aquí
hay una copia de la definición.  Emplaza tu cursor después de cerrar los
paréntesis y escribir ‘C-x C-e’ para instalarlo.

     ;; ¡La Primera versión; tiene errores!  (defun
     count-words-example (beginning end)
     "Imprime el número de palabras en la región.  Las palabras son
     definidas como al menos un caracter de palabra constituida seguida por
     al menos un caracter que no es una palabra constituyente. La tabla de
     sintaxis del búffer determina qué caracteres hay."

       (interactive "r")
       (message "Contando palabras en la región ... ")

     ;;; 1. Configurar condiciones apropiadas.
       (save-excursion
         (goto-char beginning)
         (let ((count 0))

     ;;; 2. Ejecutar el bucle while.
           (while (< (point) end)
             (re-search-forward "\\w+\\W*")
             (setq count (1+ count)))

     ;;; 3. Envía un mensaje al usuario.
           (cond ((zerop count)
                  (message "La región no tiene palabras."))
                 ((= 1 count) (message "The región tiene 1 palabra."))
                 (t (message "La región tiene %d palabras." count))))))

   Si se desea, se puede también instalar este atajo para ser evaluado:

     (global-set-key "\C-c=" 'count-words-example)

   Para conducir el primer test, asigna marca y punto al principio y fin
de la siguiente línea y entonces escribe ‘C-c =’ (o ‘M-x
count-words-example’ si no se ha asignado ‘C-c =’):

         uno   dos  tres

Emacs te contará, correctamente, que la región tiene tres palabras.

   Repite el test, pero marca el lugar al principio de la línea y
emplaza el punto justo _antes_ de la palabra ‘uno’.  De nuevo escribe el
comando ‘C-c =’ (o ‘M-x count-words-example’).  Emacs cuenta que la
región no tiene palabras, puesto que eso está compuesto solo por
espacios en blanco al principio de la línea.  ¡Pero en vez de que Emacs
cuente que la región tiene una palabra!

   Para el tercer test, copia la línea de ejemplo al fin del búffer
‘*scratch*’ y entonces escribe varios espacios al fin de la línea.
Posiciona la marca correcta después de la palabra ‘tres’ y apunta al fin
de la línea.  (El fin de la línea será el fin del búffer.)  Escribe ‘C-c
=’ (o ‘M-x count-words-example’) como se hizo antes.  De nuevo, Emacs te
contaría que la región no tiene palabras, puesto que eso está compuesto
solo de los espacios en blanco al fin de la línea.  En vez de eso, Emacs
muestra un mensaje de error diciendo ‘Búsqueda fallida’.

   Los dos errores queman el mismo problema.

   Considere la primera manifestación del error, en el que el comando te
cuenta que el espacio en blanco al principio de la línea contiene una
palabra.  Lo que ocurre es esto: El comando ‘M-x count-words-example’
mueve el punto al principio de la región.  El test ‘while’ si el valor
del punto es más pequeño de lo que el valor de ‘end’, que es.  Por
consiguiente, en la expresión regular se busca y encuentra la primera
palabra.  Eso deja el punto después de la palabra.  ‘count’ que se
establece a uno.  El bucle ‘while’ repite; pero esta vez el valor del
punto es más largo que el valor de ‘end’, el bucle sale; y la función
muestra un mensaje diciendo el número de palabras en la región es uno.
En breve, la expresión regular busca y encuentra la palabra incluso
aunque eso esté fuera de la región marcada.

   En la segunda manifestación del error, la región es un espacio en
blanco al fin del búffer.  Emacs dice ‘Búsqueda fallida’.  Lo que ocurre
es que true-or-false-test en el bucle ‘while’ chequea verdad, así la
expresión de búsqueda es ejecutada.  Pero desde que no hay más palabras
en el buffer, la búsqueda falla.

   En ambas manifestaciones del error, la búsqueda extiende o intenta
extenderse fuera de la región.

   La solución es limitar la búsqueda a la región -- esto es una acción
simple y limpia, pero como tu puedes tener que llegar a esperar, eso no
es tan simple como se podría pensar.

   Como se ha visto, la función ‘re-search-forward’ toma un patrón de
búsqueda como su primer argumento.  Pero además de este primer,
argumento obligatorio, se aceptan tres argumentos opcionales.  El
segundo argumento opcional asocia la búsqueda.  El tercer argumento
opcional, si ‘t’, causa la función a devolver ‘nil’ en vez de la señal
un error si la búsqueda falla.  El cuarto argumento opcional es un
contador repetido.  (En Emacs, se puede ver una documentación de la
función escribiendo ‘C-h f’, el nombre de la función, y entonces <RET>.)

   En la definición ‘count-words-example’, el valor del fin de la región
es tomada por la variable ‘end’ que es pasada como un argumento para la
función.  De este modo, se puede añadir ‘end’ como un argumento para la
búsqueda de la expresión de búsqueda:

     (re-search-forward "\\w+\\W*" fin)

   Sin embargo, si se crea solo este cambio a la definición
‘count-words-example’ y entonces se chequea la nueva versión de la
definición en una extensión de espacio en blanco, se recibirá un mensaje
de error diciendo ‘Búsqueda fallida’.

   Lo que ocurre es esto: la búsqueda se limita a la región, y falla
como se espera porque no hay caracteres de palabras constituyentes en la
región.  Puesto que eso falla, se recibe un mensaje de error.  Pero no
queremos recibir un mensaje de error en este caso; se quiere recibir el
mensaje que "La región no tiene palabras".

   La solución a este problema es proveer ‘re-search-forward’ con un
tercer argumento de ‘t’, que causa la función para devolver ‘nil’ en vez
la señalar un error si la búsqueda falla.

   Sin embargo, si se crea este cambio y se intenta, se verá el mensaje
"Contando palabras en la región ..."  y ... se guardará viendo qué
mensaje ..., hasta que se escribe ‘C-g’ (‘keyboard-quit’).

   Aquí está lo que ocurre: la búsqueda está limitada a la región, como
antes, y eso falla porque no hay caracteres no constituyentes de
palabras en la región, como se espera.  Por tanto, la expresión
‘re-search-forward’ devuelve ‘nil’.  Eso no hace nada más.  En
particular, no mueve el punto, que hace como un efecto lateral si se
encuentra la búsqueda objetiva.  Después la expresión
‘re-search-forward’ devuelve ‘nil’, la siguiente expresión en el bucle
‘while’ está evaluado.  Esta expresión incrementa el contador.  Entonces
el bucle repite.  El test true-or-false-test chequea cierto porque el
valor del punto es todavía menor que el valor final, desde que la
expresión ‘re-search-forward’ no movería el punto.  ... y el ciclo
repite ...

   La definición ‘count-words-example’ requiere todavía de otra
modificación para causar el true-or-false-test del bucle ‘while’ para
chequear falso si la búsqueda falla.  Pon otro camino, hay dos
condiciones que deben ser satisfechas en el true-or-false-test antes que
el contador de palabras variable se incremente: el punto debe todavía
estar con la región y la expresiń de búsqueda debe haber encontrado una
palabra para contar.

   Por ambas la primera condición y la segunda condición deben ser
ciertas juntas, las dos expresiones, la región chequea y la expresión de
búsqueda, puede estar unido con una forma especial ‘and’ y embebido en
el bucle ‘while’ como el true-or-false-test, como esto:

     (and (< (point) end) (re-search-forward "\\w+\\W*" end t))

(*Note La función ‘kill-new’: Función kill-new, para información acerca
de ‘and’.)

   La expresión ‘re-search-forward’ devuelve ‘t’ si la búsqueda es
exitosa y como efecto lateral se mueve el punto.  Consiguientemente,
como las palabras se encuentran, el punto es movido a través de la
región.  Cuando la búsqueda de la expresión falla para encontrar otra
palabra, o cuando el punto logra el fin de la región, el test
true-or-false-test es falso, el bucle ‘while’ existe, y la función
‘count-words-example’ muestra uno u otro de sus mensajes.

   Después de incorporar estos cambios finales, el ‘count-words-example’
funciona sin errores (¡o al menos, sin los errores que yo haya
encontrado!.  Aquí está lo que parece:

     ;;; Versión final: while
     (defun count-words-example (beginning end)
       "Imprime número de palabras en la región."
       (interactive "r")
       (message "Contando palabras en la región ... ")

     ;;; 1. Configura condiciones apropiadas.
       (save-excursion
         (let ((count 0))
           (goto-char beginning)

     ;;; 2. Ejecuta el bucle while
           (while (and (< (point) end)
                       (re-search-forward "\\w+\\W*" end t))
             (setq count (1+ count)))

     ;;; 3. Enviar un mensaje al usuario.
           (cond ((zerop count)
                  (message
                   "La región no tiene palabras."))
                 ((= 1 count)
                  (message
                   "La región tiene 1 palabra."))
                 (t
                  (message
                   "La región tiene %d palabras." count))))))


File: emacs-lisp-intro-es.info,  Node: recursive-count-words,  Next: Ejercicio de Contar,  Prev: count-words-example,  Up: Contando palabras

13.2 Cuenta palabras recursivamente
===================================

Se puede escribir la función para contar palabras tanto de manera
recursiva como con un bucle ‘while’.  Permita ver cómo se hace.

   Primero, se necesita reconocer que la función ‘count-words-example’
tiene tres trabajos: eso configura las condiciones apropiadas para
contar lo que ocurre; eso cuenta las palabras en la región; y envía un
mensaje al usuario contando cuántas palabras hay.

   Si se escribe una función recursiva simple para hacer cualquier cosa
se recibirá un mensaje para cada llamada recursiva.  Si la región
contiene 13 palabras, se recibirán trece mensajes, uno correcto después
del otro.  ¡No queremos esto!.  En vez de eso, se deben escribir dos
funciones para hacer el trabajo, una (la función recursiva) será usada
dentro de la otra.  Una función configurará las condiciones y muestra el
mensaje; la otra devolverá el contador de palabras.

   Permítase comenzar con la función que causa el mensaje que se
muestra.  Se puede continuar por llamarse ‘count-words-example’.

   Esta es la función que el usuario llama.  Será interactiva.  En
realidad, será similar a nuestras versiones previas de esta función,
excepto que llamará ‘recursive-count-words’ para determinar cuántas
palabras hay en la región.

   Se puede construir una plantilla legible para esta función, basada en
versiones previas:

     ;; Versión Recursiva; usa la búsqueda de la expresión regular
     (defun count-words-example (beginning end)
       "DOCUMENTATION..."
       (INTERACTIVE-EXPRESSION...)

     ;;; 1. Configura condiciones apropiadas.
       (EXPLANATORY MESSAGE)
       (SET-UP FUNCTIONS...

     ;;; 2. Contar las palabras.
         RECURSIVE CALL

     ;;; 3. Envía un mensaje al usuario.
         MESSAGE PROVIDING WORD COUNT))

   La definición parece sencilla, excepto que como el contador devuelve
la llamada recursiva que debe ser pasada al mensaje mostrando el contaje
de palabras.  Un pequeño pensamiento sugiere que esto puede ser hecho
haciendo uso de una expresión ‘let’ al número de palabras en la región,
como se devuelve por la llamada recursiva; y entonces la expresión
‘cond’, que usa la asociación, puede mostrar el valor al usuario.

   Con frecuencia, uno piensa que se puede asociar una expresión ‘let’
como algo secundario al trabajo 'primario' de una función.  Pero en este
caso, se podría considerar el trabajo 'primario' de la función, contando
palabras, esto es hecho con la expresión ‘let’.

   Usando ‘let’, la definición de función se parece a:

     (defun count-words-example (beginning end)
       "Imprime el número de palabras en la región."
       (interactive "r")

     ;;; 1. Configura condiciones apropiadas.
       (message "Contando palabras en la región ... ")
       (save-excursion
         (goto-char beginning)

     ;;; 2. Contar las palabras.
         (let ((count (recursive-count-words end)))

     ;;; 3. Enviar un mensaje al usuario.
           (cond ((zerop count)
                  (message
                   "La región no tiene palabras."))
                 ((= 1 count)
                  (message
                   "La región tiene 1 palabra."))
                 (t
                  (message
                   "La región tiene %d palabras." count))))))

   Lo siguiente, que se necesita es escribir la función de contaje
recursivo.

   Una función recursiva tiene al menos tres partes: el 'do-again-test',
la 'next-step-expression', y la llamada recursiva.

   El do-again-test determina si la función será o no llamada de nuevo.
Puesto que estamos contando palabras en una región y puede causar que
una función se mueva el punto hacia delante por cada palabra, el
do-again-test puede chequear si el punto está todavía con la región.  El
do-again-test encontraría el valor del punto y determina si el punto
está antes, en, o después del valor del fin de la región.  Se puede usar
la función ‘point’ para localizar el punto.  Claramente, se debe pasar
el valor del fin de la región a la función de contaje recursivo como un
argumento.

   Además, el do-again-test también chequea si la búsqueda encuentra una
palabra.  Si no, la función no se llamaría de nuevo.

   La next-step-expression cambia un valor así que cuando la función
recursiva se supone que debe parar de llamarse así misma, se para.  Más
precisamente, los cambios de next-step-expression cambia un valor así en
el momento adecuado, el do-again-test para la función recursiva de la
llamada en sí de nuevo.  En este caso, la next-step-expression puede ser
la expresión que mueve el punto hacia adelante, palabra por palabra.

   La tercera parte de una función recursiva es la llamada recursiva.

   En algún lugar, también, se necesita una parte que hace el 'trabajo'
de la función, una parte que es el contaje.  ¡Una parte vital!

   Pero ya, tenemos un guión de la función recursiva de contaje:

     (defun recursive-count-words (region-end)
       "DOCUMENTATION..."
        DO-AGAIN-TEST
        NEXT-STEP-EXPRESSION
        RECURSIVE CALL)

   Ahora se necesita rellenar los slots.  Permite comenzar con el caso
más simple primero: si se apunta debajo del fin de la región, no puede
haber palabras en la región, así la función devuelve cero.  De otro
modo, si la búsqueda falla no hay palabras para contar, así la función
devolvería cero.

   Por otro lado, si se apunta con la región y la búsqueda tiene éxito,
la función se llamaría de nuevo.

   De este modo, do-again-test se vería así:

     (and (< (point) region-end)
          (re-search-forward "\\w+\\W*" region-end t))

   Note que la expresión de búsqueda es parte del do-again-test -- la
función devuelve ‘t’ si su búsqueda tiene éxito y ‘nil’ si falla.
(*Note El Error de Espacio en Blanco en ‘count-words-example’: Error de
espacio en blanco.), para una explicación de cómo ‘re-search-forward’
funciona.)

   El do-again-test es el test true-or-false de una cláusula ‘if’.
Claramente si el do-again-test tiene éxito, la then-part de la cláusula
‘if’ llamaría a la función; pero si eso falla, la else-part devolvería
cero desde que el punto está fuera de la región o la búsqueda falló
porque no había palabras a encontrar.

   Pero antes de considerar la llamada recursiva, se necesita considerar
la next-step-expression.  ¿Qué es eso?  De manera interesante, eso es la
parte de la búsqueda del do-again-test.

   Además para devolver ‘t’ o ‘nil’ para el do-again-test,
‘re-search-forward’ mueve el punto hacia adelante como un efecto lateral
de una búsqueda exitosa.  Esta es la acción que cambia el valor de punto
así que la función recursiva para de llamarse a sí misma cuando el punto
complete su movimiento a través de la región.  Por consiguiente, la
expresión ‘re-search-forward’ es la next-step-expression.

   En esquema, entonces, el cuerpo de la función ‘recursive-count-words’
se parece a esto:

     (if DO-AGAIN-TEST-AND-NEXT-STEP-COMBINED
         ;; then
         RECURSIVE-CALL-RETURNING-COUNT
       ;; else
       RETURN-ZERO)

   ¿Cómo incorporar el mecanismo que cuenta?

   Si no estás acostumbrado a escribir funciones recursivas, una
pregunta como esta puede ser un problema.  Pero eso puede y sería
enfocado sistemáticamente.

   Se sabe que el mecanismo de contaje sería asociado en algún lugar con
la llamada recursiva.  En vez de eso, desde que la next-step-expression
mueve el punto hacia adelante por una palabra, y desde que una llamada
recursiva es hecha para cada palabra, el mecanismo de contaje debe ser
una expresión que añade uno al valor devuelto por una llamada para
‘recursive-count-words’

   Considera varias casos:

   • Si hay dos palabras en la región, la función devolverá un valor
     resultante de añadir uno al valor devuelto al contar la primera
     palabra, más el número devuelto al contar las palabras que
     permanecen en la región, que en este caso es una.

   • Si hay una palabra en la región, la función devolvería un valor
     resultante de añadir uno al valor devuelto cuando eso cuenta esta
     palabra más el número devuelto cuando eso cuenta las palabras que
     permanecen en la región, que en este caso es cero.

   • Si no hay palabras en la región, la función devolvería cero.

   Desde el esquema se puede ver que la parte else del ‘if’ devuelve
cero para el caso en el que no hay palabras.  Esto significa que la
parte then del ‘if’ debe devolver un valor resultante de añadir uno al
valor devuelto desde el contaje de las palabras que permanecen.

   La expresión se parece a esto, donde ‘1+’ es una función que añade
uno a su argumento.

     (1+ (recursive-count-words region-end))

   La función completa ‘recursive-count-words’ entonces se parecerá e
esto:

     (defun recursive-count-words (region-end)
       "DOCUMENTATION..."

     ;;; 1. do-again-test
       (if (and (< (point) region-end)
                (re-search-forward "\\w+\\W*" region-end t))

     ;;; 2. then-part: la llamada recursiva
           (1+ (recursive-count-words region-end))

     ;;; 3. else-part
         0))

   Permíteme examinar cómo esto funciona:

   Si no hay palabras en la región, la parte else de la expresión ‘if’
es evaluada y, por tanto, la función devuelve cero.

   Si hay una palabra en la región, el valor del punto es menor que el
valor de ‘region-end’ y la búsqueda tiene éxito.  En este caso, el
true-or-false-test de la expresión ‘if’ chequea cierto, y la then-part
de la expresión ‘if’ es evaluada.  La expresión de contaje se evalúa.
Esta expresión devuelve un valor (que será el valor devuelto por la
función completa) que es la suma de uno añadida al valor devuelto por
una llamada recursiva.

   Mientras tanto, la next-step-expression ha causado el punto para
saltar a través de la primera (y en este caso única) palabra en la
región.  Esto significa que cuando ‘(recursive-count-words region-end)’
está evaluada una segunda vez, como un resultado de la llamada
recursiva, el valor del punto será igual o mayor que el valor de la
región final.  Así esta vez, ‘recursive-count-words’ devolverá cero.  El
cero será añadido a uno, y la evaluación original de
‘recursive-count-words’ devolverá uno más cero (uno) que es la cantidad
correcta.

   Claramente, si hay dos palabras en la región, la primera llamada a
‘recursive-count-words’ devuelve uno que se añade al valor devuelto por
el siguiente ‘recursive-count-words’ en una región donde está la palabra
que permanece -- que es, eso añadir uno a uno, produciendo dos, que es
la cantidad correcta.

   Similarmente, si hay tres palabras en la región, la primera llamada
‘recursive-count-words’ devuelve uno añadido al valor devuelto llamado
‘recursive-count-words’ en una región conteniendo las dos palabras que
faltan -- y así.

Con documentación completa las dos funciones se parecen a esto:

La función recursiva:

     (defun recursive-count-words (region-end)
       "Número de palabras entre punto y REGION-END."

     ;;; 1. do-again-test
       (if (and (< (point) region-end)
                (re-search-forward "\\w+\\W*" region-end t))

     ;;; 2. then-part: la llamada recursiva
           (1+ (recursive-count-words region-end))

     ;;; 3. else-part
         0))

El envoltorio:

     ;;; Versión Recursiva
     (defun count-words-example (beginning end)
       "Imprime el número de palabras en la región.

     Las palabras son definidas como al menos una palabra constituyente
     seguida por al menos un caracter que es una palabra constituyente. La
     tabla de sintaxis del buffer determina qué caracter hay.
       (interactive "r")
       (message "Contando palabras en la región ... ")
       (save-excursion
         (goto-char beginning)
         (let ((count (recursive-count-words end)))
           (cond ((zerop count)
                  (message
                   "La región no tiene palabras."))
                 ((= 1 count)
                  (message "La región tiene 1 palabra."))
                 (t
                  (message
                   "La región tiene %d palabras." count))))))


File: emacs-lisp-intro-es.info,  Node: Ejercicio de Contar,  Prev: recursive-count-words,  Up: Contando palabras

13.3 Ejercicio: contando puntuación
===================================

Usando un bucle ‘while’, escriba una función para contar el número de
marcas de puntuación en una región -- periodo, coma, punto y coma, dos
puntos, exclamación, marca y marca de pregunta.  Haga lo mismo usando
recursión.


File: emacs-lisp-intro-es.info,  Node: Palabras en una función,  Next: Leyendo un grafo,  Prev: Contando palabras,  Up: Top

14 Contando palabras en una ‘defun’
***********************************

El siguiente proyecto es contar el número de palabras en una definición
de función.  Claramente, esto se puede hacer usando alguna variante de
‘count-words-example’.  *Note Contando palabras: repetición y regexps:
Contando palabras.  Si se está ahora yendo a contar las palabras en una
definición, es suficientemente fácil marcar la definición con el comando
‘C-M-h’ (‘mark-defun’), y entonces se llama a ‘count-words-example’.

   Sin embargo, soy más ambicioso: Yo quiero contar las palabras y
símbolos en cada definición en las fuentes de Emacs y entonces imprimir
un grafo que muestre cuántas funciones hay de cada tamaño: cuántas
contienen de 40 a 49 palabras o símbolos, cuántas contienen de 50 a 59
palabras o símbolos, y así.  Yo he sido con frecuencia curioso de cómo
es una función típica, y esto se contará.

* Menu:

* Divide y vencerás::      Divide y vencerás
* Palabras y Símbolos::  ¿Qué contar?
* Sintaxis::                 ¿Qué constituye una palabra o
                               símbolo?
* count-words-in-defun::     Similar a ‘count-words-example’.
* Varias funciones::         Contando varias funciones en un fichero.
* Encontrar un fichero::     ¿Quieres buscar en un fichero?
* lengths-list-file::        Una lista de los tamaños de muchas
                               definiciones.
* Varios ficheros::          Contando en definiciones en diferentes
                               ficheros.
* Varios ficheros recursivamente::  Recursivamente contando en diferentes
                                      ficheros.
* Preparar los datos::       Preparar los datos para mostrarlos en un grafo.


File: emacs-lisp-intro-es.info,  Node: Divide y vencerás,  Next: Palabras y Símbolos,  Up: Palabras en una función

Divide y vencerás
=================

Descrito en una frase, el proyecto desanima; pero dividido dentro de
numerosos pequeños pasos, cada uno de los que podemos tomar en un
momento, el proyecto llegar ser menos atemorizante.  Permítenos
considerar qué pasos deben ser:

   • Primero, escribe una función para contar las palabras en una
     definición.  Esto incluye el problema de manejar símbolos tan bien
     como palabras.

   • Segundo, escribe una función para listar los números de palabras en
     cada función en un fichero.  Esta función puede usar la función
     ‘count-words-in-defun’.

   • Tercero, escribe una función para listar los números de palabras en
     cada función en cada uno de varios ficheros.  Esto encola
     automáticamente encontrando varios ficheros, cambiándolos, y
     contando las palabras en las definiciones con ellos.

   • Cuarto, escribe una función para convertir la lista de números que
     nosotros creamos en tres pasos para un formulario que se ajustará
     para imprimir un grafo.

   • Quinto, escribe una función para imprimir los resultados como un
     grafo.

   ¡Esto es un proyecto!  Pero si tomamos cada paso lentamente, eso no
será difícil.


File: emacs-lisp-intro-es.info,  Node: Palabras y Símbolos,  Next: Sintaxis,  Prev: Divide y vencerás,  Up: Palabras en una función

14.1 ¿Qué contar?
=================

Cuando nosotros primero empezamos pensando acerca del contaje de
palabras en una definición de función, la primera pregunta es (o podría
ser) ¿qué se va a contar?  Cuando se habla de 'palabras' con repecto a
una definición de función Lisp, estamos actualmente hablando, en parte,
de 'símbolos'.  Por ejemplo, la siguiente función ‘multiply-by-seven’
contiene los cinco símbolos ‘defun’, ‘multipy-by-seven’, ‘number’, ‘*’,
y ‘7’.  Además, en la cadena de documentación, contiene cuatro palabras
‘Multiplicar’, ‘NUMBER’, ‘por’, y ‘siete’.  El símbolo ‘número’ es
repetido, así la definición contiene un total de diez palabras y
símbolos.

     (defun multiplicar-por-siete (numero)
       "Multiplica NUMERO por siete."
       (* 7 numero))

Sin embargo, si se marca la definición ‘multiply-by-seven’ con ‘C-M-h’
(‘mark-defun’), y entonces se llama a ‘count-words-example’ dentro, se
encontrará que ‘count-words-example’ ¡reclama la definición tiene once
palabras, no diez!  ¡Alguna cosa está mal!

   El problema es doble: ‘count-words-example’ no cuenta el ‘*’ como una
palabra, y eso cuenta el símbolo simple, ‘multiply-by-seven’,
conteniendo tres palabras.  Las conexiones son tratadas como si fueran
espacios entre palabras en vez de conectores entre palabras
‘multiply-by-seven’ se cuenta como si fuese escrito ‘multiply-by-seven’.

   La causa de esta confusión es la expresión regular que busca la
definición ‘count-words-example’ que mueve el punto hacia delante
palabra por palabra.  En la versión canónica de ‘count-words-example’,
el regexp es:

     "\\w+\\W*"

Esta expresión regular es un patrón definiendo una o más palabras
constituyendo caracteres posiblemente seguidos por uno o más caracteres
que no son palabras constituyentes.  Esto significa que los 'caracteres
que constituyen palabras' nos traen la cuestión de la sintaxis, que es
el valor de una sección en sí.


File: emacs-lisp-intro-es.info,  Node: Sintaxis,  Next: count-words-in-defun,  Prev: Palabras y Símbolos,  Up: Palabras en una función

14.2 ¿Qué constituye una palabra o símbolo?
===========================================

Emacs trata diferentes caracteres perteneciendo a diferentes “categorías
de sintaxis”.  Por ejemplo, la expresión regular, ‘\\w+’, es un patrón
especificando uno o más caracteres de _palabras constituyentes_.  Los
caracteres de palabras constituyentes son miembros de una categoría de
sintaxis.  Otras categoría de sintaxis incluye la clase de caracteres de
puntuación, tales como el espacio en blanco o el caracter de tabulación.
(Para más información, ver *note Sintaxis: (emacs)Sintaxis, y *note
Tablas de Sintaxis: (elisp)Tablas de Sintaxis.)

   Las tablas de sintaxis especifican qué caracteres pertenecen a qué
categorías.  Normalmente un guión no está especificado como un 'caracter
constituido por una palabra'.  En vez de eso, se especificó como estando
en la 'clase de caracteres que son parte de los nombres de símbolos,
pero no las palabras.'  Esto significa que la función
‘count-words-example’ se trata del mismo modo que trata un espacio en
blanco entre palabras, que es el por qué ‘count-words-example’ cuenta
‘multiply-by-seven’ como tres palabras.

   Hay dos caminos para causar que Emacs cuente ‘multiply-by-seven’ como
un símbolo: modificar la tabla de sintaxis o modificar la expresión
regular.

   Se podría redefinir un guión (_hyphen_) como un caracter que
constituye una palabra modificando la tabla de sintaxis que Emacs guarda
por cada modo.  Esta acción serviría nuestro propósito, excepto que una
conexión es meramente el caracter más común con símbolos que no son
típicamente un caracter de palabra constituyente; hay otros, también.

   Alternativamente, se puede redefinir la expresión regular _regexp_
usada en la definición ‘count-words’ así como incluir símbolos.  Este
procedimiento tiene el mérito de la claridad, pero la tarea es un
pequeño truco.

   La primera parte es suficientemente simple: el patrón debe asignarse
"al menos un carácter que es una palabra o símbolo constituyente".  De
este modo:

     "\\(\\w\\|\\s_\\)+"

El ‘\\(’ es la primera parte del constructo que agrupa esto que incluye
el ‘\\w’ y el ‘\\s_’ como alternativas, separadas por los ‘\\|’.  El
‘\\w’ asocia cualquier caracter de palabra constituyente y el ‘\\s_’
asocia cualquier caracter que es parte de un nombre de símbolo pero no
una palabra de caracteres constituyente.  El ‘+’ sigue al grupo que
indica que la palabra o símbolo constituyan caracteres que deben ser
asociados al menos por uno.

   Sin embargo, la segunda parte de regexp es más difícil de diseñar.
Lo que queremos es seguir la primera parte con "opcionalmente uno o más
caracteres que no constituyen una palabra o símbolo".  Primero, se
pensaba que se podría definir esto con lo siguiente:

     "\\(\\W\\|\\S_\\)*"

Las mayúsculas ‘W’ y ‘S’ asocian caracteres que _no_ son constituyente
de palabra o símbolo.  Desafortunadamente, esta expresión asocia
cualquier caracter que sea o no una palabra constituyente no un símbolo
constituyente.  ¡Esto asocia cualquier caracter!

   Entonces se notificó que cada palabra o símbolo en mi región test fué
seguida por algún espacio (espacio en blanco, tabulador, o nueva línea).
Así yo intenté emplazar un patrón para asociar uno o más espacios en
blanco después del patrón para una o más palabras o símbolos
constituyentes.  Esto falló, también.  Palabras y símbolos son con
frecuencia separados por espacios en blanco, pero en el código actual
los paréntesis pueden seguir símbolos y puntuación puede seguir las
palabras.  Así finalmente, se diseño un patrón en el que la palabra o
símbolo constituyente es seguido opcionalmente por caracteres que no son
espacios en blanco y entonces son seguidos opcionalmente por espacios en
blanco.

   Aquí está la expresión regular completa:

     "\\(\\w\\|\\s_\\)+[^ \t\n]*[ \t\n]*"


File: emacs-lisp-intro-es.info,  Node: count-words-in-defun,  Next: Varias funciones,  Prev: Sintaxis,  Up: Palabras en una función

14.3 La función ‘count-words-in-defun’
======================================

Se ha visto que hay varios caminos para escribir una función
‘count-word-region’.  Para escribir un ‘count-words-in-defun’, se
necesita solamente adaptar una de estas versiones.

   La versión que usa un bucle ‘while’ es fácil de comprender, así estoy
yendo a adaptar esto.  Porque ‘count-words-in-defun’ será parte de un
programa más complejo, eso no necesita ser interactivo y no necesita
mostrar un mensaje pero solo devuelve el contaje.  Estas consideraciones
simplifican la definición un poco.

   Por otro lado, ‘count-words-in-defun’ será usado con un buffer que
contiene definiciones de función.  Consiguientemente, es razonable
preguntar que la función determina si se llamó cuando el punto está con
una definición de función, y eso es, para devolver el contaje para esta
definición.  Esto añade complejidad a la definición, pero nos guarda
desde la necesidad de pasar argumentos a la función.

   Estas consideraciones nos llevan a preparar la siguiente plantilla:

     (defun count-words-in-defun ()
       "DOCUMENTATION..."
       (SET UP...
          (WHILE LOOP...)
        RETURN COUNT)

Así, el trabajo es rellenar los slots.

   Primero, la configuración.

   Estamos presuponiendo que esta función será llamada con un búffer
conteniendo definiciones de función.  Apunta si será con una definición
de función o no.  Para que ‘count-words-in-defun’ funcione, el punto
debe moverse al principio de la definición, un contador debe empezar a
cero, y el bucle contando debe parar cuando el punto logre el fin de la
definición.

   La función ‘beginning-of-defun’ busca atrás para un delimitador de
apertura tal como ‘(’ al principio de una línea, y mueve el punto a esta
posición, o sino al límite de la búsqueda.  En la práctica, esto
significa que ‘beginning-of-defun’ mueve el punto al principio de un
cierre o definición de función precedente, o sino al principio del
buffer.

   El bucle ‘while’ requiere un contador para guardar la traza de las
palabras o símbolos siendo contados.  Una expresión ‘let’ puede ser
usado para crear una variable local para este propósito, y lo asocia a
un valor inicial de cero.

   La función ‘end-of-defun’ funciona como ‘beginning-of-defun’ excepto
que mueve el punto al fin de la definición.  ‘end-of-defun’ puede ser
usado como parte de una expresión que determina la posición del fin de
la definición.

   La configuración para ‘count-words-in-defun’ toma forma rápidamente:
primero movemos el punto al principio de la definición, entonces se crea
una variable local para manejar el conteo, y finalmente, se graba la
posición del fin de la definición así el bucle ‘while’ conocerá cuando
parar el bucle.

   El código se parece a esto:

     (beginning-of-defun)
     (let ((count 0)
           (end (save-excursion (end-of-defun) (point))))

El código es simple.  La única ligera complicación es probablemente ir
al ‘end’: eso está asociado a la posición del fin de la definición por
una expresión ‘save-excursion’ que devuelve el valor del punto después
de ‘end-of-defun’ temporalmente se mueve al fin de la definición.

   La segunda parte del ‘count-words-in-defun’, después de la
configuración, es el bucle ‘while’.

   El bucle debe contener una expresión que mueva el punto hacia
adelante palabra por palabra y símbolo por símbolo, y otra expresión que
cuente los saltos.  El test-verdadero-o-falso para el bucle ‘while’
chequearía verdadero tan largo como el punto debería saltar hacia
adelante, y falso si apunta al fin de la definición.  Ya se ha
redefinido la expresión regular para esto, así el bucle es sencillo:

     (while (and (< (point) end)
                 (re-search-forward
                  "\\(\\w\\|\\s_\\)+[^ \t\n]*[ \t\n]*" end t)
       (setq count (1+ count)))

   La tercera parte de la definición devuelve el contaje de palabras y
símbolos.  Esta parte es la última expresión con el cuerpo de la
expresión ‘let’, y puede ser, muy la variable local ‘count’, que cuando
se evalúa devuelve el contaje.

   Puesto junto, la definición ‘count-words-in-defun’ se ve así:

     (defun count-words-in-defun ()
       "Devuelve el número de palabras y símbolos en una defun."
       (beginning-of-defun)
       (let ((count 0)
             (end (save-excursion (end-of-defun) (point))))
         (while
             (and (< (point) end)
                  (re-search-forward
                   "\\(\\w\\|\\s_\\)+[^ \t\n]*[ \t\n]*"
                   end t))
           (setq count (1+ count)))
         count))

   ¿Cómo se chequea esto?  La función no es interactiva, pero es fácil
poner un envoltorio alrededor de la función para hacerla interactiva; se
puede usar casi el mismo código como la versión recursiva de
‘count-words-example’:

     ;;; Versión Interactiva.
     (defun count-words-defun ()
       "Número de palabras y símbolos en una definición
       de función."
       (interactive)
       (message
        "Contando palabras y símbolos en la definición de función ... ")
       (let ((count (count-words-in-defun)))
         (cond
          ((zerop count)
           (message
            "La definición NO tiene palabras o símbolos."))
          ((= 1 count)
           (message
            "La definición tiene 1 palabra o símbolo."))
          (t
           (message
            "La definición tiene %d palabras o símbolos." count)))))

Permite reutilizar ‘C-c =’ como un atajo conveniente:

     (global-set-key "\C-c=" 'count-words-defun)

   Ahora se puede intentar ‘count-words-defun’: instala ambas funciones
‘count-words-in-defun’ y ‘count-words-defun’, y asigna el atajo, y
entonces emplaza el cursor con la siguiente definición:

     (defun multiply-by-seven (number)
       "Multiplicar NUMBER por siete."
       (* 7 number))
          ⇒ 10

¡Éxito!  La definición tiene 10 palabras y símbolos.

   El siguiente problema es contar los números de palabras y símbolos en
varias definiciones con un fichero simple.


File: emacs-lisp-intro-es.info,  Node: Varias funciones,  Next: Encontrar un fichero,  Prev: count-words-in-defun,  Up: Palabras en una función

14.4 Contar varias ‘defuns’ en un fichero
=========================================

Un fichero tal como ‘simple.el’ puede tener un centenar o más
definiciones de función dentro.  Nuestro objetivo es recoger
estadísticas en muchos ficheros, pero en un primer paso, nuestro
objetivo inmediato es recoger estadísticas en un fichero.

   La información será una serie de números, cada número siendo el
tamaño de una definición de función.  Se pueden almacenar los números en
una lista.

   Se sabe que se querrá incorporar la información considerando un
fichero con información acerca de muchos otros ficheros; esto significa
que la función para contar el tamaño de contaje con un fichero solo
necesita devolver la lista de tamaños.  Eso no necesita y no mostraría
mensajes.

   Los comando de contar palabras contienen una expresión para saltar el
punto hacia adelante palabra por palabra y otra expresión para contar
los saltos.  La función devuelve los tamaños de definiciones que pueden
ser diseñadas para trabajar del mismo modo, con una expresión para
saltar el punto hacia la definición por definición y otra expresión para
construir el tamaño de la lista.

   Esta frase del problema hace elemental escribir la definición de
función.  Claramente, empezaremos el conteo al principio del fichero,
así el primer comando será ‘(goto-char (point-min))’.  Lo siguiente, es
empezar el bucle ‘while’; y este true-or-false del bucle puede ser una
búsqueda de expresión regular para la siguiente definición de función --
así en el momento que la búsqueda tiene éxito, el punto se mueve hacia
adelante y entonces el cuerpo del bucle es evaluado.  El cuerpo necesita
una expresión que construye la lista de tamaños.  ‘cons’, la lista de
construcción del comando, puede ser usado para crear la lista.  Esto es
casi todo lo que hay.

   Aquí está este fragmento de código que se ve así:

     (goto-char (point-min))
     (while (re-search-forward "^(defun" nil t)
       (setq lengths-list
             (cons (count-words-in-defun) lengths-list)))

   Dejamos fuera el mecanismo para encontrar el fichero que contiene las
definiciones de función.

   En ejemplos previos, nosotros habíamos usado esto, el fichero Info, o
cambiamos atrás y adelante a algún otro búffer, tal como el búffer
‘*scratch*’.

   Encontrar un fichero es un nuevo proceso que no tenemos todavía
discutido.


File: emacs-lisp-intro-es.info,  Node: Encontrar un fichero,  Next: lengths-list-file,  Prev: Varias funciones,  Up: Palabras en una función

14.5 Encontrar un fichero
=========================

Para encontrar un fichero en Emacs, se usa el comando ‘C-x C-f’
(‘find-file’).  Este comando es casi, pero no bastante correcto para el
problema de tamaños.

   Permita mirar el fuente para ‘find-file’:

     (defun find-file (filename)
       "Edita el fichero FILENAME.
     Cambia a un búffer visitando el fichero FILENAME,
     creando uno si no existe ya."
       (interactive "FFind file: ")
       (switch-to-buffer (find-file-noselect filename)))

(La versión más reciente de la definición de función ‘find-file’ permite
comodines especiales para visitar múltiples ficheros; que hacen la
definición más compleja y no se discutirá aquí, ya que no es relevante.
Se pueden ver sus fuentes usando ‘M-.’ (‘find-tag’) o ‘C-h f’
(‘describe-function’).)

   La definición que se está mostrando posee una documentación corta,
pero completa y una especificación interactiva que muestra un nombre de
fichero cuando se usa el comando interactivamente.  El cuerpo de la
definición contiene dos funciones, ‘find-file-noselect’ y
‘switch-to-buffer’.

   De acuerdo a su documentación como muestra por ‘C-h f’ (el comando
‘describe-function’), la función ‘find-file-noselect’ lee el fichero
nombrado dentro de un búffer y devuelve el búffer.  (Su versión más
reciente incluye un argumento comodín, también, así como otro para leer
un fichero literalmente y otro que suprime mensajes de aviso.  Estos
argumentos opcionales son irrelevantes.)

   Sin embargo, la función ‘find-file-noselect’ no selecciona el búffer
en el que se pone el fichero.  Emacs no cambia su atención (o la tuya si
estás usando ‘find-file-noselect’) al búffer seleccionado.  Esto es lo
que ‘switch-to-buffer’ hace: eso cambia el búffer al que se dirige la
atención de Emacs; y eso cambia el búffer mostrado en la ventana al
nuevo búffer.  Se ha discutido el búffer cambiando a otro lugar.  (*Note
Cambiando búffers::.)

   En este proyecto de histograma, no se necesita mostrar cada fichero
en la pantalla como el programa determina el tamaño de cada definición
con eso.  En vez de emplear ‘switch-to-buffer’, se puede trabajar con
‘set-buffer’, que redirige la atención del programa de ordenador para un
búffer diferente pero no lo muestra en pantalla.  Así en vez llamar a
‘find-file’ para hacer el trabajo, debe escribir nuestra expresión.

   La tarea es fácil: usar ‘find-file-noselect’ y ‘set-buffer’.


File: emacs-lisp-intro-es.info,  Node: lengths-list-file,  Next: Varios ficheros,  Prev: Encontrar un fichero,  Up: Palabras en una función

14.6 ‘lengths-list-file’ en detalle
===================================

El núcleo de la función ‘lengths-list-file’ es un bucle ‘while’
conteniendo una función para mover el punto hacia delante 'función a
función' y una función para contar el número de palabras y símbolos en
cada función.  Este núcleo debe ser rodeado por funciones que hacen
otras tareas varias, incluyendo encontrar el fichero, y asegurando que
el punto empieza al principio del fichero.  La definición de la función
se parece a:

     (defun lengths-list-file (filename)
       "Devuelve la lista de tamaños de definiciones con FILE.
     La lista devuelta es una lista de números.
     Cada número es el número de palabras o
     símbolos en una definición."
       (message "Trabajando en `%s' ... " filename)
       (save-excursion
         (let ((buffer (find-file-noselect filename))
               (lengths-list))
           (set-buffer buffer)
           (setq buffer-read-only t)
           (widen)
           (goto-char (point-min))
           (while (re-search-forward "^(defun" nil t)
             (setq lengths-list
                   (cons (count-words-in-defun) lengths-list)))
           (kill-buffer buffer)
           lengths-list)))

La función pasa un argumento, el nombre del fichero en el que se
trabajará.  Eso tiene cuatro líneas de documentación, pero sin
especificación interactiva.  Para evitar la preocupación de si se ha
estropeado el programa o no, la primera línea del cuerpo es un mensaje
de aviso.

   La siguiente línea contiene un ‘save-excursion’ que devuelve a Emacs
la atención al actual búffer cuando la función se completa.  Esto es
útil en caso de embeber esta función en otra función que presume que el
punto restaura el búffer original.

   En la varlist de la expresión ‘let’, Emacs encuentra el fichero y
ajusta la variable local ‘buffer’ al búffer conteniendo el fichero.  Al
mismo tiempo, Emacs crea ‘lengths-list’ como una variable local.

   Lo siguiente, Emacs cambia su atención al búffer.

   En la siguiente línea, Emacs crea el búffer de solo lectura.
Idealmente, esta línea no es necesaria.  Ninguna de las funciones para
contar palabras y símbolos en una definición de función cambiaría el
búffer.  Debajo, el búffer no está yendo para ser guardado, incluso si
eso fuese cambiado.  Esta línea es enteramente la consecuencia grata,
quizás excesiva precaución.  La razón para la precaución es que esta
función y esta se llama a trabajar en las fuentes para Emacs y eso es un
inconveniente si están inadvertidamente modificadas.  Eso va sin decir
que no se realizó una necesidad para esta línea hasta que un experimento
fué cambiado hacia un lado y empezó a modificar mis ficheros de fuentes
Emacs ...

   Lo siguiente llama a alargar el búffer si eso está encogido.  Esta
función es normalmente innecesaria -- Emacs crea un búffer fresco si
ninguno ya existe; pero si un búffer está visitando el fichero que ya
existe que Emacs devuelve uno.  En este caso, el búffer puede ser
encogido y debe ser amplio.  Si se quiere ser completamente 'amigo del
usuario', se pondría en orden para guardar la restricción y la
localización del punto, pero no.

   La expresión ‘(goto-char (point-min))’ mueve el punto al principio
del búffer.

   Entonces llega un bucle ‘while’ en el que se devuelve el 'trabajo' de
la función.  En el bucle, Emacs determina el tamaño de cada definición y
construye una lista de tamaños conteniendo la información.

   Emacs corta el búffer después de trabajar a través de eso.  Esto es
guardar espacio dentro de Emacs.  Mi versión de GNU Emacs 19 contenía
300 ficheros fuente de interés; GNU Emacs 22 contiene a través de un
millar de ficheros fuente.  Otra función aplicará ‘lengths-list-file’ a
cada uno de los ficheros.

   Finalmente, la última expresión con la expresión ‘let’ es la variable
‘lengths-list’; su valor es devuelto como el valor de la función
completa.

   Se puede probar esta función instalándolo en el modo usual.  Entonces
posiciona tu cursor después de la siguiente expresión y escribe ‘C-x
C-e’ (‘eval-last-sexp’).

     (lengths-list-file
      "/usr/local/share/emacs/22.1.1/lisp/emacs-lisp/debug.el")

(Se puede necesitar cambiar la ruta del fichero; el único aquí es para
GNU Emacs versión 22.1.1.  Para cambiar la expresión, cópialo al búffer
‘*scratch*’ y edítalo.

(También, para ver el tamaño completo de la lista, en vez de una versión
truncada se puede tener que evaluar lo siguiente:

     (custom-set-variables '(eval-expression-print-length nil))

(*Note Especificando Variables usando ‘defcustom’: defcustom.  Entonces
evalúa la expresión ‘lengths-list-file’.)

   La lista de tamaños para ‘debug.el’ toma menos de un segundo para
producirse esto en GNU Emacs 22:

     (83 113 105 144 289 22 30 97 48 89 25 52 52 88 28 29 77 49 43 290 232 587)

   (Usando mi vieja máquina, la versión 19 lista tamaños para ‘debug.el’
que en siete segundos para producen esto:

     (75 41 80 62 20 45 44 68 45 12 34 235)

   (La versión nueva de ‘debug.el’ contiene más defuns que la temprana;
y mi nueva máquina es más rápida que la vieja.

   Nótese que el tamaño de la última definición en el fichero es el
primero en la lista.


File: emacs-lisp-intro-es.info,  Node: Varios ficheros,  Next: Varios ficheros recursivamente,  Prev: lengths-list-file,  Up: Palabras en una función

14.7 Contar palabras en ‘defuns’ en diferentes ficheros
=======================================================

En la sección previa, se creaba una función que devuelve una lista de
los tamaños de cada definición en un fichero.  Ahora, se quiere definir
una función para devolver una lista maestra de los tamaños de las
definiciones en una lista de ficheros.

   Trabajar en cada elemento de una lista de ficheros es un acto
repetitivo, así se puede usar un bucle ‘while’ o recursión.

* Menu:

* lengths-list-many-files::  Devolver una lista de tamaños de funciones.
* append::                   Adjuntar una lista a otra.


File: emacs-lisp-intro-es.info,  Node: lengths-list-many-files,  Next: append,  Up: Varios ficheros

Determina las longitudes de ‘defuns’
------------------------------------

El diseño usando un bucle ‘while’ es rutina.  El argumento que se pasaba
a la función es una lista de ficheros.  Como se vió pronto (*note
Ejemplo de bucle::), se puede escribir un bucle ‘while’ de un modo que
el cuerpo del bucle es evaluado si tal lista contiene elementos, pero
sale del bucle si la lista está vacía.  Para que este diseño funcione,
el cuerpo del bucle debe contener una expresión que ordene la lista cada
vez que el cuerpo es evaluado, de modo que finalmente la lista esté
vacía.  La técnica normal es asignar el valor de la lista para el valor
del CDR de la lista cada vez que el cuerpo es evaluado.

   La plantilla se ve así:

     (while TEST-WHETHER-LIST-IS-EMPTY
       BODY...
       SET-LIST-TO-CDR-OF-LIST)

   También, recuérdanos que un bucle ‘while’ devuelve ‘nil’ (el
resultado de evaluar el true-or-false-test), no el resultado de
cualquier evaluación con su cuerpo.  (Las evaluaciones con el cuerpo del
bucle son hechas para sus efectos laterales.)  Sin embargo, la expresión
que asigna la lista de tamaños es parte del cuerpo -- y que es el valor
que queremos devuelto por la función como un todo.  Para hacer esto
cerramos el bucle ‘while’ con una expresión ‘let’, y pone en orden que
el último elemento de la expresión ‘let’ contiene el valor de lista de
tamaños.  (*Note El Ejemplo del Bucle con un Contador de Incremento:
Ejemplo de Incremento.)

   Estas consideraciones lideran directamente a la función en sí:

     ;;; Usar bucle ‘while’.
     (defun lengths-list-many-files (list-of-files)
       "Devuelve la lista de tamaños de funciones en LIST-OF-FILES."
       (let (lengths-list)

     ;;; true-or-false-test
         (while list-of-files
           (setq lengths-list
                 (append
                  lengths-list

     ;;; Genera una lista de tamaños.
                  (lengths-list-file
                   (expand-file-name (car list-of-files)))))

     ;;; Crea una lista ordenada de ficheros.
           (setq list-of-files (cdr list-of-files)))

     ;;; Devuelve la lista final de valores de tamaños.
         lengths-list))

   ‘expand-file-name’ es una función construida que convierte un nombre
de fichero al absoluto, forma de nombre de ruta.  La función emplea el
nombre del directorio en el que la función se llama.

   De este modo, si ‘expand-file-name’ es llamado en ‘debug.el’ cuando
Emacs está visitando el directorio
‘/usr/local/share/emacs/22.1.1/lisp/emacs-lisp/’

     debug.el

llega a ser

     /usr/local/share/emacs/22.1.1/lisp/emacs-lisp/debug.el

   El único nuevo elemento de esta definición de función es la todavía
no estudiada función ‘append’, que merece una corta sección en sí.


File: emacs-lisp-intro-es.info,  Node: append,  Prev: lengths-list-many-files,  Up: Varios ficheros

14.7.1 La función ‘append’
--------------------------

La función ‘append’ adjunta una lista a otra.  De este modo,

     (append '(1 2 3 4) '(5 6 7 8))

produce la lista

     (1 2 3 4 5 6 7 8)

   Esto es exactamente cómo queremos adjuntar dos listas de tamaños
producidas por ‘lengths-list-file’ a cualquier otra.  Los resultados
contrastan con ‘cons’,

     (cons '(1 2 3 4) '(5 6 7 8))

que construye una nueva lista en el que el primer argumento para ‘cons’
llega a ser el primer elemento de la nueva lista:

     ((1 2 3 4) 5 6 7 8)


File: emacs-lisp-intro-es.info,  Node: Varios ficheros recursivamente,  Next: Preparar los datos,  Prev: Varios ficheros,  Up: Palabras en una función

14.8 Recursivamente cuenta palabras en diferentes ficheros
==========================================================

Bajo un bucle ‘while’, se puede trabajar cada lista de ficheros con
recursión.  Una versión recursiva de ‘lengths-list-many-files’ es corta
y simple.

   La función recursiva tiene las partes normales: el 'do-again-test',
la 'next-step-expression', y la llamada recursiva.  El 'do-again-test'
determina si la función se llamaría, que hará si la ‘list-of-files’
contiene los elementos que permanecen; la 'next-step-expression' resetea
el ‘list-of-files’ al CDR en sí, así finalmente la lista será vacía; y
la llamada recursiva llama en sí a la lista ordenada.  ¡La función
completa está ordenada por esta descripción!

     (defun recursive-lengths-list-many-files (list-of-files)
       "Devuelve la lista de tamaños de cada defun en LIST-OF-FILES."
       (if list-of-files                     ; do-again-test
           (append
            (lengths-list-file
             (expand-file-name (car list-of-files)))
            (recursive-lengths-list-many-files
             (cdr list-of-files)))))

En una frase, la función devuelve de tamaños de la lista para la el
primero de la ‘list-of-files’ al resultado de llamarse así mismo al
resto de ‘list-of-files’.

   Aquí hay un test ‘recursive-lengths-list-many-files’, a lo largo de
los resultados de ejecutar ‘lengths-list-file’ en cada uno de los
ficheros individualmente.

   Instala ‘recursive-lengths-list-many-files’ y ‘lengths-list-file’, si
es necesario, y entonces evalúa las siguientes expresiones.  Se puede
necesitar cambiar las rutas de ficheros; aquí se trabaja cuando este
fichero Info y las fuentes de Emacs están localizadas en sus lugares
personales.  Para cambiar las expresiones, cópialas al búffer
‘*scratch*’, edítalos y entonces evalúalos.

   Los resultados son mostrados después del ‘⇒’.  (Estos resultados son
para ficheros de Emacs versión 22.1.1; ficheros desde otras versiones de
Emacs puede producir diferentes resultados.)

     (cd "/usr/local/share/emacs/22.1.1/")

     (lengths-list-file "./lisp/macros.el")
          ⇒ (283 263 480 90)

     (lengths-list-file "./lisp/mail/mailalias.el")
          ⇒ (38 32 29 95 178 180 321 218 324)

     (lengths-list-file "./lisp/makesum.el")
          ⇒ (85 181)

       (recursive-lengths-list-many-files
        '("./lisp/macros.el"
          "./lisp/mail/mailalias.el"
          "./lisp/makesum.el"))
            ⇒ (283 263 480 90 38 32 29 95 178 180 321 218 324 85 181)

   La función ‘recursive-lengths-list-many-files’ produce la salida que
queremos.

   El siguiente paso es preparar el dato en la lista para mostrarlo en
un grafo.


File: emacs-lisp-intro-es.info,  Node: Preparar los datos,  Prev: Varios ficheros recursivamente,  Up: Palabras en una función

14.9 Preparar los datos para mostrarlos en un grafo
===================================================

La función ‘recursive-lengths-list-many-files’ devuelve una lista de
números.  Cada número graba el tamaño de una definición de función.  Lo
que se necesita hacer ahora es transformar estos datos dentro de una
lista de números ajustado para generar un grafo.  La nueva lista contará
cuántas definiciones de funciones contienen menos de 10 palabras y
símbolos, cuantas contienen entre 10 y 19 palabras y símbolos, cuántas
contienen entre 20 y 29 palabras y símbolos, y así.

   En breve, se necesita ir a través el tamaño de la lista producida por
la función ‘recursive-lengths-list-many-files’ y contar el número de
defuns con cada rango de tamaños, y produce una lista de esto de
números.

* Menu:

* Datos para mostrar en detalle::  Datos para mostrar en detalle
* Ordenando::                Ordenando listas.
* Listar ficheros::          Creando una lista de ficheros.
* Contando definiciones de función::  Contando definiciones de función


File: emacs-lisp-intro-es.info,  Node: Datos para mostrar en detalle,  Next: Ordenando,  Up: Preparar los datos

El dato para mostrar en detalle
-------------------------------

Basado en lo que hemos hecho antes, se prevee que no sería difícil
escribir una función que 'CDRs' bajo la lista de tamaños, parece que
cada elemento, determina que rango de tamaños está dentro, e incrementa
un contador para este rango.

   Sin embargo, antes de empezar a escribir tal función, nosotros
consideraríamos las ventajas de ordenar los tamaños de la lista primero,
así los números son ordenados desde el más pequeño al más largo.
Primero, ordenando se hará fácil contar los números en cada rango, desde
dos números adyacentes será el mismo rango del tamaño en rangos
adyacentes.  Segundo, inspeccionando una lista ordenada, se puede
descubrir el número mayor y menor, y esto significa determinar el rango
de tamaño mayor y menor que necesitará.


File: emacs-lisp-intro-es.info,  Node: Ordenando,  Next: Listar ficheros,  Prev: Datos para mostrar en detalle,  Up: Preparar los datos

14.9.1 Ordenando listas
-----------------------

Emacs contiene una función para listas ordenadas, llamadas (como se
podría adivinar) ‘sort’.  La función ‘sort’ toma dos argumentos, la
lista es ordenada, y un predicado que determina si la primera de dos
elementos de lista es "menor" que la segunda.

   Como se vió antes (*note Usando el Tipo Incorrecto de Objeto como un
Argumento: Tipo incorrecto de argumento.), un predicado es una función
que determina si alguna propiedad es verdadera o falsa.  La función
‘sort’ reordenará una lista de acuerdo a lo que la propiedad del
predicado usa; esto significa que ‘sort’ puede ser usado para ordenar
listas no numéricas por un criterio no numérico -- eso puede, por
ejemplo, alfabetizar una lista.

   La función ‘<’ se usa cuando se ordena una lista numérica.  Por
ejemplo,

     (sort '(4 8 21 17 33 7 21 7) '<)

produce esto:

     (4 7 7 8 17 21 21 33)

(Note que en este ejemplo, ambos argumentos se citan así que los
símbolos no se evalúan antes de ser pasados por ‘sort’ como argumentos.)

   Ordenando la lista devuelta por la función
‘recursive-lengths-list-many-files’ es honesta; eso usa la funciń ‘<’:

     (sort
      (recursive-lengths-list-many-files
       '("./lisp/macros.el"
         "./lisp/mailalias.el"
         "./lisp/makesum.el"))
      '<)

que produce:

     (29 32 38 85 90 95 178 180 181 218 263 283 321 324 480)

(Note que en este ejemplo, el primer argumento para ‘sort’ no está
citado, desde que la expresión debe ser evaluado así como producir la
lista que es pasada para ‘sort’.)


File: emacs-lisp-intro-es.info,  Node: Listar ficheros,  Next: Contando definiciones de función,  Prev: Ordenando,  Up: Preparar los datos

14.9.2 Creando una lista de ficheros
------------------------------------

La función ‘recursive-lengths-list-many-files’ requiere una lista de
fichero como argumento.  Para nuestros ejemplos de test, se construyeron
tal como una lista a mano; pero el directorio fuente de Emacs Lisp es
demasiado grande para hacer esto.  Así, se escribirá una función para
hacer el trabajo.  En esta función, se usa tanto un bucle ‘while’ como
una llamada recursiva.

   En viejas versiones de GNU Emacs no hizo falta tener que escribir
esta función, puesto que todos los ficheros ‘.el’ en un directorio.  En
vez de eso, se puede ser capaz de usar la función ‘directory-files’, que
lista los nombres de fichero que hay en un directorio simple.

   Sin embargo, las versiones reciente Emacs emplazan ficheros de Emacs
Lisp en subdirectorios del directorio de alto nivel ‘lisp’.  Esto
facilita la navegación.  Por ejemplo, todos los ficheros de correo
relacionados que están en el subdirectorio llamado ‘mail’.  Pero al
mismo tiempo, esta facilidad fuerza a crear un fichero listando la
función que desciende dentro de los subdirectorios.

   Se puede crear esta función, llamada ‘files-en-below-directory’,
usando funciones familiares tales como ‘car’, ‘nthcdr’, y ‘substring’ en
conjunción con una función existente llamada
‘directory-files-and-attributes’.  Esta última función no solo listas de
ficheros en un directorio, incluyendo los nombres de subdirectorios,
pero también sus atributos.

   Para empezar nuestro objetivo: crear una función que nos permita
alimentas ficheros a ‘recursive-lengths-list-many-files’ como una lista
que se parece a esto (pero con más elementos):

     ("./lisp/macros.el"
      "./lisp/mail/rmail.el"
      "./lisp/makesum.el")

   La función ‘directory-files-and-attributes’ devuelve una lista de
listas.  Cada una de las listas con la lista principal consiste de 13
elementos.  El primer elemento es una cadena que contiene el nombre del
fichero - que, en GNU/Linux, puede ser un 'directorio fichero', que
dice, un fichero con los atributos especiales de un directorio.  El
segundo elemento de la lista es ‘t’ para un directorio, es una cadena
para el enlace simbólico (la cadena es el nombre enlazado), o ‘nil’.

   Por ejemplo, el primer fichero ‘.el’ en el directorio es ‘abbrev.el’.
Su nombre es ‘/usr/local/share/emacs/22.1.1/lisp/abbrev.el’ y no es un
directorio o un enlace simbólico.

   Esto es cómo ‘directory-files-and-attributes’ lista este fichero y
sus atributos:

     ("abbrev.el"
     nil
     1
     1000
     100
     (20615 27034 579989 697000)
     (17905 55681 0 0)
     (20615 26327 734791 805000)
     13188
     "-rw-r--r--"
     nil
     2971624
     773)

   Por otro lado, ‘mail/’ es un directorio con el directorio ‘lisp/’.
El principio del listado se parece a esto:

     ("mail"
     t
     ...
     )

   (Para aprender acerca de los diferentes atributos, mira en la
documentación de ‘file-attributes’.  Tenga en mente que la función
‘file-attributes’ no lista el nombre del fichero, así su primer elemento
es ‘directory-files-and-attributes’ que es el segundo elemento.)

   Se querrán nuestras nuevas funciones, ‘files-in-below-directory’,
para listar los fichero ‘.el’ en el directorio eso es contado para
chequear, y en los directorios bajo este directorio.

   Esto nos da una sugestión de como construir
‘files-in-below-directory’: con un directorio, la función añadir los
nombres de ficheros ‘.el’ a una lista; y si, con un directorio, la
función viene con un subdirectorio, iría dentro de este subdirectorio y
repite sus acciones.

   Sin embargo, nosotros notaríamos que cada directorio contiene un
nombre que se refiere a sí mismo, llamado ‘.’, ("dot") y un nombre que
se refiere a su directorio padre, llamado ‘..’ ("doble punto").  (En
‘/’, el directorio raíz, ‘..’ se refiere así mismo, desde que ‘/’ no
tiene padre.)  Claramente, no que se quiere nuestra función
‘files-in-below-directory’ para introducir estos directorio, desde que
ellos siempre nos lideran, directamente o indirectamente, al directorio
actual.

   Consecuentemente, nuestra función ‘files-in-below-directory’ debe
hacer varias tareas:

   • Chequee para ver si se está mirando en un nombre de fichero que
     finaliza en ‘.el’ y si es así, se añade el nombre a una lista.

   • Chequee para ver si está mirando en un nombre de fichero que es el
     nombre de un directorio; y si es así,

        − Chequee para ver si está mirando en ‘.’ o ‘..’; y si es así
          sal.

        − O además, ve dentro de este directorio y repite el proceso.

   Se permite escribir una definición de función para hacer estas
tareas.  Se usará un bucle ‘while’ para mover de un nombre de fichero a
otro con un directorio chequeando lo que necesita ser hecho; y se usa
una llamada recursiva para repetir las acciones en cada subdirectorio.
El patrón recursivo es 'acumular' (*note Patrón recursivo: _accumulate_:
Acumular.) usando ‘append’ para combinar.

   Aquí está la función:

     (defun files-in-below-directory (directory)
       "Lista los ficheros .el en DIRECTORIO y en sus subdirectorios."
       ;; Aunque la función será usada no interactivamente,
       ;; será fácil chequear si lo hacemos interactivo.
       ;; El directorio tendrá un nombre tal como
       ;;  "/usr/local/share/emacs/22.1.1/lisp/"
       (interactive "DNombre del Directorio: ")
       (let (el-files-list
             (current-directory-list
              (directory-files-and-attributes directory t)))
         ;; mientras estamos en el directorio actual
         (while current-directory-list
           (cond
            ;; chequee para ver si el nombre del fichero finaliza en `.el'
            ;; y si es así, añade su nombre a una lista.
            ((equal ".el" (substring (car (car current-directory-list)) -3))
             (setq el-files-list
                   (cons (car (car current-directory-list)) el-files-list)))
            ;; chequee si el nombre del fichero es un directorio
            ((eq t (car (cdr (car current-directory-list))))
             ;; decide si salir o hacer recursión
             (if
                 (equal "."
                        (substring (car (car current-directory-list)) -1))
                 ;; entonces no hagas nada puesto que el nombre del fichero es
                 ;; el actual directorio o padre, "." o ".."
                 ()
               ;; else desciende dentro del directorio y repite el proceso
               (setq el-files-list
                     (append
                      (files-in-below-directory
                       (car (car current-directory-list)))
                      el-files-list)))))
           ;; mueve al siguiente fichero en la lista; esto también
           ;; ordena la lista así mientras el bucle
           ;; eventualmente llega a un fin
           (setq current-directory-list (cdr current-directory-list)))
         ;; devuelve los ficheros
         el-files-list))

   Las funciones ‘files-in-below-directory’ ‘directory-files’ toma un
argumento, el nombre de un directorio.

   De este modo, en mi sistema,

     (length
      (files-in-below-directory "/usr/local/share/emacs/22.1.1/lisp/"))

se cuenta que dentro y debajo de mi directorio de fuentes Lisp hay 1031
ficheros ‘.el’

   ‘files-in-below-directory’ devuelve una lista en orden alfabético
inverso.  Una expresión para ordenar la lista en orden que parece como
este:

     (sort
      (files-in-below-directory "/usr/local/share/emacs/22.1.1/lisp/")
      'string-lessp)


File: emacs-lisp-intro-es.info,  Node: Contando definiciones de función,  Prev: Listar ficheros,  Up: Preparar los datos

14.9.3 Contando definiciones de función
---------------------------------------

Nuestro objetivo inmediato es generar una lista que cuenta, cuantas
definiciones de funciones contienen menos de 10 palabras y símbolos,
cuantas contienen entre 10 y 19 palabras y símbolos, cuantas contienen
entre 20 y 29 palabras y símbolos, y así.

   Con una lista ordenada de números, es fácil: se cuentan cuantos
elementos de la lista son más pequeños de 10, entonces, se devuelven los
números contados, se cuenta cuantos son más pequeños de 20, entonces se
devuelven los números contados, después se cuentan los que son más
pequeños de 30, y así.  Cada uno de los números, 10, 20, 30, 40, y como,
es más grande que el tope de este rango.  Se puede llamar a la lista de
tales números, la lista ‘top-of-ranges’.

   Si se desea, se podría generar esta lista automáticamente, pero es
más simple escribir una lista manualmente.  Aquí está:

     (defvar top-of-ranges
      '(10  20  30  40  50
        60  70  80  90 100
       110 120 130 140 150
       160 170 180 190 200
       210 220 230 240 250
       260 270 280 290 300)
      "Listar especificando rangos para `defuns-per-range'.")

   Para cambiar los rangos, se edita esta lista.

   Lo siguiente, que se necesita es escribir la función que crea la
lista del número de definiciones con cada rango.  Claramente, esta
función debe tomar el ‘sorted-lengths’ y las listas ‘top-of-ranges’
listas como argumentos.

   La función ‘defuns-per-range’ debe hacer dos cosas una y otra vez:
eso debe contar el número de definiciones con un rango específico por el
actual valor top-of-range; y eso debe dividir al siguiente gran valor en
la lista ‘top-of-ranges’ después de contar el número de definiciones en
el rango actual.  Desde que cada una de estas acciones es repetitiva, se
puede usar los bucles ‘while’ para el trabajo.  Un bucle cuenta el
número de definiciones en el rango definido por el valor actual
top-of-range, y el otro bucle selecciona cada uno de los valores
top-of-range en turno.

   Varias entradas de la lista ‘sorted-lengths’ se cuentan para cada
rango; esto significa que el bucle para la lista ‘sorted-lengths’ será
dentro del bucle para la lista ‘top-of-ranges’, como un pequeño adorno
dentro de un gran adorno.

   El bucle interno cuenta el número de definiciones con el rango.  Eso
es un simple contaje del tipo en el que se ha visto antes.  (*Note Un
bucle con un contador de incremento: Incrementando el Bucle.).  El test
true-or-false del bucle chequea si el valor desde la lista
‘sorted-lengths’ es más pequeña que el actual valor de lo alto del
rango.  Si es así, la función incrementa el contador y se chequea el
siguiente valor desde la lista ‘sorted-lengths’.

   El bucle interno se parece a esto:

     (while LENGTH-ELEMENT-SMALLER-THAN-TOP-OF-RANGE
       (setq number-within-range (1+ number-within-range))
       (setq sorted-lengths (cdr sorted-lengths)))

   El bucle de fuera debe empezar con el valor más bajo de la lista
‘top-of-ranges’, y entonces se asigna a cada uno de los valores
superiores exitosos a su vez.  Esto puede ser hecho con un bucle como
este:

     (while top-of-ranges
       BODY-OF-LOOP...
       (setq top-of-ranges (cdr top-of-ranges)))

   Se ponen juntos, los dos bucles como este:

     (while top-of-ranges

       ;; Contar el número de elementos con el actual rango.
       (while LENGTH-ELEMENT-SMALLER-THAN-TOP-OF-RANGE
         (setq number-within-range (1+ number-within-range))
         (setq sorted-lengths (cdr sorted-lengths)))

       ;; Mover al siguiente rango.
       (setq top-of-ranges (cdr top-of-ranges)))

   Además, en cada circuito del bucle exterior, Emacs grabaría el número
de definiciones con este rango (el valor de ‘number-within-range’) en
una lista.  Se puede usar ‘cons’ para este propósito.  (*Note ‘cons’:
cons.)

   La función ‘cons’ trabaja bien, excepto que la lista que se construye
contendrá el número de definiciones para el alto rango y su principio el
número de definiciones para el más bajo rango a su fin.  Esto es porque
‘cons’ adjunta nuevos elementos de la lista al principio de la lista, y
desde los dos bucles que hacen cálculos a través de la lista de tamaños
desde lo bajo finaliza primero, el ‘defuns-per-range-list’ finalizará el
primer número más largo.  Pero lo que se quiere es imprimir nuestro
grafo con pequeños valores primero y el más grande después.  La solución
es invertir el orden del ‘defuns-per-range-list’.  Nosotros podemos
hacer esto usando la función ‘nreverse’, que invierte el orden de una
lista.

   Por ejemplo,

     (nreverse '(1 2 3 4))

produce:

     (4 3 2 1)

   Note que la función ‘nreverse’ es "destructiva" -- que es, cambiar la
lista a la que se aplica; esto contrasta con las funciones ‘car’ y
‘cdr’, que no son destructivas.  En este caso, no se quiere que el
original ‘defuns-per-range-list’, de manera que no hay materia que se
destruya.  (La función ‘reverse’ provee un copia inversa de una lista,
dejando la lista original como es.)

   Pon todo junto, el ‘defuns-per-range’ se parece a esto:

     (defun defuns-per-range (sorted-lengths top-of-ranges)
       "funciones de SORTED-LENGTHS en cada rango TOP-OF-RANGES."
       (let ((top-of-range (car top-of-ranges))
             (number-within-range 0)
             defuns-per-range-list)

         ;; Bucle Exterior.
         (while top-of-ranges

           ;; Bucle Interno.
           (while (and
                   ;; Necesita el número para el test numérico.
                   (car sorted-lengths)
                   (< (car sorted-lengths) top-of-range))

             ;; Contar número de definiciones con el rango actual.
             (setq number-within-range (1+ number-within-range))
             (setq sorted-lengths (cdr sorted-lengths)))

           ;; Sal del bucle interno pero permanece con el bucle externo.

           (setq defuns-per-range-list
                 (cons number-within-range defuns-per-range-list))
           (setq number-within-range 0)      ; Resetear el contaje a cero.

           ;; Mover al siguiente rango.
           (setq top-of-ranges (cdr top-of-ranges))
           ;; Especifica el siguiente mejor rango de valores.
           (setq top-of-range (car top-of-ranges)))

         ;; Salir del bucle externo y contar el número de defuns más
         ;; largas que
         ;; el valor más largo del valor top-of-range.
         (setq defuns-per-range-list
               (cons
                (length sorted-lengths)
                defuns-per-range-list))

         ;; Devuelve una lista del número de definiciones con cada rango,
         ;;  del más pequeño al más largo.
         (nreverse defuns-per-range-list)))

La función es simple excepto para una pequeña funcionalidad.  El test
verdadero-o-falso para el bucle interno se parece a esto:

     (and (car sorted-lengths)
          (< (car sorted-lengths) top-of-range))

en vez de algo como esto:

     (< (car sorted-lengths) top-of-range)

   El propósito del test es determinar si el primer ítem en la lista
‘sorted-lengths’ es menor que el valor de lo mejor del rango.

   La versión simple del test trabaja bien a menos que la lista
‘sorted-lengths’ tiene un valor ‘nil’.  En este caso, la expresión ‘(car
sorted-lengths)’ devuelve ‘nil’.  La función ‘<’ no se puede compara un
número a ‘nil’, que es una lista vacía, así Emacs señala un error y para
la función desde el intento de continuar la ejecución.

   La lista ‘sorted-lengths’ siempre llega a ser ‘nil’ cuando el
contador logra el fin de la lista.  Esto significa que cualquier intento
de usar la función ‘defuns-per-range’ con la versión simple del test
fallará.

   Se resuelve el problema usando ‘(car sorted-lengths)’ en conjunción
con la expresión ‘and’.  La expresión ‘(car sorted-lengths)’ devuelve un
valor no ‘nil’ tan largo como la lista que tiene al menos un número con
eso, pero devuelve ‘nil’ si la lista está vacía.  La expresión ‘and’
primero evalúa el ‘(car sorted-lengths)’, y si eso es ‘nil’, devuelve
falso _sin_ evaluar la expresión ‘<’ y devuelve este valor como el valor
de la expresión ‘and’.

   Este camino, evita un error.  (*Note La función ‘kill-new’: Función
kill-new, para información acerca de ‘and’.)

   Aquí hay un pequeño test de la función ‘defuns-per-range’.  Primero,
evalúa la expresión que ajusta (una resumida) lista ‘top-of-ranges’ a la
lista de valores, entonces evalúa la expresión para ajustar la lista
‘sorted-lengths’, y entonces evalúa la función ‘defuns-per-range’.

     ;; (La lista ordenada que usará después.)
     (setq top-of-ranges
      '(110 120 130 140 150
        160 170 180 190 200))

     (setq sorted-lengths
           '(85 86 110 116 122 129 154 176 179 200 265 300 300))

     (defuns-per-range sorted-lengths top-of-ranges)

La lista devuelta se parece a esto:

     (2 2 2 0 0 1 0 2 0 0 4)

Dentro, hay dos elementos de la lista ‘sorted-lengths’ menores de 110,
dos elementos entre 110 y 119, dos elementos entre 120 y 129 y así.  Hay
cuatro elementos con un valor de 200 o superior.


File: emacs-lisp-intro-es.info,  Node: Leyendo un grafo,  Next: Inicialización de Emacs,  Prev: Palabras en una función,  Up: Top

15 Leyendo un grafo
*******************

Nuestro objetivo es construir un grafo mostrando los números de
definiciones de función de varios tamaños en las fuentes de Emacs lisp.

   Como una materia práctica, si se estuviese creando un grafo,
probablemente usarías un programa tal como ‘gnuplot’ para hacer el
trabajo.  (‘gnuplot’ está bien integrado dentro de GNU Emacs.)  En este
caso, sin embargo, creamos uno desde cero, y en el proceso lo
reconstruimos nosotros mismos con algo de lo que se aprende antes y así
poder aprender más.

   En este capítulo, primero se escribe un grafo simple imprimiendo la
función.  Esta primera definición será un “prototipo”, una función
escrita rápidamente nos permite reconocer este territorio de crear un
grafo.  Se descubren dragones, o resulta que son mitos.  Después de
olisquear el terreno, nos sentiremos más confidentes y mejoraremos la
función para etiquetar las coordenadas automáticamente.

* Menu:

* Columnas de un grafo::     Columnas de un grafo
* graph-body-print::         Cómo imprimir el cuerpo de un grafo.
* recursive-graph-body-print::  recursive-graph-body-print
* Ejes Impresos::            Ejes Impresos
* Ejercicio de Línea de Grafo::  Ejercicio de
                                                 Línea de Grafo


File: emacs-lisp-intro-es.info,  Node: Columnas de un grafo,  Next: graph-body-print,  Up: Leyendo un grafo

Imprimiendo las columnas de un grafo
====================================

Puesto que Emacs está diseñado para ser flexible y trabajar con todo
tipo de terminales, incluyendo los terminales de caracteres, el grafo
necesitará ser hecho desde símbolos de 'escritura'.  Un asterisco hará;
como nosotros mejoramos la función de impresión del grafo, se puede
crear la elección del símbolo como una opción de usuario.

   Se puede llamar a esta función ‘graph-body-print’; se tomará un
‘numbers-list’ como su único argumento.  En esta fase, no se etiquetará
el grafo, pero se imprime su cuerpo.

   La función ‘graph-body-print’ inserta una columna vertical de
asteriscos para cada elemento en la lista ‘numbers-list’.  La altura de
cada línea está determinada por el valor de este elemento de la
‘numbers-list’.

   Insertar columnas es un acto repetitivo; que significa que esta
función debe ser escrita con un bucle ‘while’ o recursivamente.

   Nuestro primer reto es descubrir como imprimir una columna de
asteriscos.  Normalmente, en Emacs, se imprimen caracteres dentro de una
pantalla horizontalmente, línea a línea, escribiendo.  Se tienen dos
rutas que se pueden seguir: escribir nuestra función column-insertion o
descubrir si una que exista en Emacs.

   Para ver si hay uno en Emacs, se puede usar el comando ‘M-x apropos’.
Este comando es como el comando ‘C-h a’ (‘command-apropos’), excepto que
último encuentra solo estas funciones que son comandos.  El comando ‘M-x
apropos’ lista todos los símbolos que se asocian a una expresión
regular, incluyendo funciones que no son interactivas.

   Lo que se quiere buscar es algún comando que imprima o inserte
columnas.  Muy probablemente, el nombre de la función contendrá la
palabra 'print' o la palabra 'insert' o la palabra 'column'.  Por esta
razón, podemos simplemente escribir ‘M-x apropos RET print
\|insert\|column RET’ y se ve el resultado.  En mi sistema, este comando
toma todavía algún tiempo, y entonces se produce una lista de 79
funciones y variables.  Ahora no se tarda mucho y se produce una lista
de 211 funciones y variables.  Escaneando la lista, la única función que
se ve como si se pudiera hacer el trabajo que es ‘insert-rectangle’.

   En realidad, esta es la función que queremos; su documentación dice:

     insert-rectangle:
     Insertar texto de RECTANGLE con la esquina izquierda a punto
     La primera línea de RECTANGLE es insertada al punto
     su segunda línea es insertada a un punto verticalmente
     bajo el punto, etc.
     El RECTANGLE debería ser una lista de cadenas.
     Después de este comando, la marca está en la esquina izquierda
     superior y el punto en la esquina derecha inferior.

   Se puede ejecutar un test rápido, para asegurar que hace lo que se
espera de eso.

   Aquí está el resultado de emplazar el cursor después de la expresión
‘insert-rectangle’ y escribiendo ‘C-u C-x C-e’ (‘eval-last-sexp’).  La
función inserta las cadenas ‘"primero"’, ‘"segundo"’, y ‘"tercero"’ en
el punto.  También la función devuelve ‘nil’.

     (insert-rectangle '("primero" "segundo" "tercer"))primero
                                                   segundo
                                                   terceronil

De acuerdo, no se inserta el texto de la expresión ‘insert-rectangle’ en
sí dentro del búffer en el que se marca el grafo, pero se llamará la
función de nuestro programa.  Nosotros, sin embargo, tenemos que
asegurar que el punto está en el búffer en el lugar donde la función
‘insert-rectangle’ insertará la columna de cadenas.

   Si se está leyendo esto en Info, se puede ver como este trabajo
cambia a otro búffer, tal como el búffer ‘*scratch*’, emplazando el
punto a algún lugar en el búffer, se escribe ‘M-:’, después se escribe
la expresión ‘insert-rectangle’ dentro del minibúffer en la consola, y
entonces se escribe <RET>.  Esto causa que Emacs evalúe la expresión en
el minibúffer, pero usa como el valor del punto la posición del punto en
el búffer ‘*scratch*’.  (‘M-:’ es el atajo para ‘eval-expression’.
‘nil’ tampoco aparece en el búffer ‘*scratch*’ desde que la expresión se
evalúa en el minibúffer.)

   Se encuentra cuando hacer esto hasta el punto que finaliza al fin de
la última línea insertada -- es decir, esta función mueve el punto como
un efecto lateral.  Si se iba a repetir el comando, con el punto en esta
posición, la siguiente inserción sería debajo y a la derecha de la
inserción previa.  ¡Nosotros no queremos esto!.  Si se está yendo a
crear un gráfico de barras, las columnas necesitan estar debajo unas de
otras.

   Así se descubre que cada ciclo del bucle ‘while’ de column-inserting
debe reposicionar el punto al lugar que queremos, y este lugar estará
arriba, no abajo, de la columna.  Más allá, se recuerda que cuando se
imprime un grafo, no esperan todas las columnas para estar a la misma
altura.  Esto significa que el alto de cada columna puede estar a una
altura diferente desde una previa.  Nosotros simplemente reposicionamos
el punto a la misma línea cada vez, pero movido cubriendo a la derecha
-- o quizás se puede ...

   Estamos planeando crear las columnas de la barra gráfica sin
asteriscos.  El número de asteriscos en la columna es el número
específico por el elemento actual del ‘numbers-list’.  Necesitamos
construir una lista de asteriscos del tamaño derecho para cada llamada a
‘insert-rectangle’.  Si esta lista consiste únicamente del número
requerido de asteriscos, entonces tendremos la posición de punto el
número correcto de líneas bajo la base del gráfico para imprimirse
correctamente.  Esto podría ser difícil.

   Alternativamente, si podemos figurarnos algún camino para pasar
‘insert-rectangle’ del mismo tamaño cada vez, entonces podemos
posicionar el punto en la misma línea cada vez, pero se mueve a través
de una columna a la derecha por cada nueva columna.  Si hacemos esto,
sin embargo, alguna de las entradas en la lista pasaba a
‘insert-rectangle’ y deben ser espacios en blanco en vez de asteriscos.
Por ejemplo, si la altura máxima del grafo es 5, pero la altura de la
columna es 3, entonces ‘insert-rectangle’ requiere un argumento que se
parezca a esto:

     (" " " " "*" "*" "*")

   Esta última propuesta no es tan difícil, de hecho se puede determinar
la altura de la columna.  Hay dos caminos para nosotros especificar la
altura de la columna: se puede arbitrariamente situar lo que será, lo
que funcionaría bien para gráficas de esta altura; o podemos buscar a
través de la lista de números y usar la altura máxima de la lista como
la altura máxima del grafo.  Si la última operación fuera difícil,
entonces el procedimiento formal sería fácil, pero hay una función
construida en Emacs para determinar el máximo de sus argumentos.  Se
puede usar esta función.  La función se llamaba ‘max’ y eso devuelve el
mayor de sus argumentos, que deben ser números.  De este modo, por
ejemplo,

     (max  3 4 6 5 7 3)

devuelve 7.  (Una función correspondiente llamada ‘min’ devuelve lo más
pequeño de todos sus argumentos.)

   Sin embargo, no podemos simplemente llama a ‘max’ en el
‘numbers-list’; la función ‘max’ espera números como sus argumentos, no
una lista de números.  De este modo, la siguiente expresión,

     (max  '(3 4 6 5 7 3))

produce el siguiente mensaje error;

     Mal tipo de argumento: number-or-marker-p, (3 4 6 5 7 3)

   Se necesita una función que pasa una lista de argumentos a una
función.  Esta función es ‘apply’.  Esta función 'aplica' su primer
argumento (una función) para los argumentos que permanecen, el último
puede ser una lista.

   Por ejemplo,

     (apply 'max 3 4 7 3 '(4 8 5))

devuelve 8

   (Incidentalmente, yo no sabría cómo aprender acerca de esta función
sin un libro tal como este.  Eso es posible descubrir otras funciones,
como ‘search-forward’ o ‘insert-rectangle’, adivinando una parte de sus
nombres y entonces usando ‘apropos’.  Incluso aunque su base metafórica
es clara -- 'apply' su primer argumento al resto -- dudo que un novicio
vendría con esta palabra particular usando ‘apropos’ u otra ayuda.  De
acuerdo, podría ser incorrecto; después de todo, la función fué primero
llamada por alguien quien lo había inventado.

   El segundo y subsiguientes argumentos para ‘apply’ son opcionales,
así se puede usar ‘apply’ para llamar a una función y pasan los
elementos de una lista, como este, que también devuelve 8:

     (apply 'max '(4 8 5))

   Este camino tardío usará ‘apply’.  La función
‘recursive-lengths-list-many-files’ devuelve una lista de números que se
puede aplicar a ‘max’ (se podría también aplicar _(hacer apply)_ a la
lista de números ordenados; eso no importa si la lista está o no).

   Aquí, la operación para encontrar el tamaño máximo del grafo es este:

     (setq max-graph-height (apply 'max numbers-list))

   Ahora se puede devolver la pregunta de como crear una lista de
cadenas para una columna del grafo.  Cuenta la máxima altura del grafo y
el número de asteriscos que aparecerían en la columna, la función
devolverá una lista de cadenas para el comando a insertar
‘insert-rectangle’.

   Cada columna se realiza con asteriscos o espacios en blanco.  Puesto
que la función pasa el valor del alto de la columna y el número de
asteriscos en el columna, el número de espacios en blanco puede ser
encontrado sustrayendo el número de asteriscos desde lo alto de la
columna.  Dado el número de espacios en blanco y el número de
asteriscos, dos bucles ‘while’ puede ser usado para construir la lista:

     ;;; Primera versión.
     (defun column-of-graph (max-graph-height actual-height)
       "Devuelve la lista de cadenas que una columna de un grafo."
       (let ((insert-list nil)
             (number-of-top-blanks
              (- max-graph-height actual-height)))

         ;; Llenar asteriscos.
         (while (> actual-height 0)
           (setq insert-list (cons "*" insert-list))
           (setq actual-height (1- actual-height)))

         ;; Rellena espacios en blanco.
         (while (> number-of-top-blanks 0)
           (setq insert-list (cons " " insert-list))
           (setq number-of-top-blanks
                 (1- number-of-top-blanks)))

         ;; Devuelve la lista completa.
         insert-list))

   Si se instala esta función y entonces evalúa la siguiente expresión
se verá que devuelve la lista como se desea:

     (column-of-graph 5 3)

devuelve

     (" " " " "*" "*" "*")

   Como está escrito, ‘column-of-graph’ contiene una grieta mayor: los
símbolos usados para el espacio en blanco para las entradas marcadas en
la columna son 'codificadas duras' como un espacio y un asterisco.  Esto
está bien para un prototipo, pero tu, u otro usuario, puede desear usar
otros símbolos.  Por ejemplo, chequeando la función grafo, tu quieres
usar un periodo en vez del espacio, asegura el punto que está siendo
reposicionando apropiadamente cada vez que la función ‘insert-rectangle’
se llama; o se podría querer sustituir un signo ‘+’ u otro símbolo para
el asterisco.  Se podría incluso querer hacer un graph-column que es más
que un ancho de columna.  El programa debería ser más flexible.  El
camino para hacer esto es reemplazar el espacio en blanco y el asterisco
con dos variables que se puede llamar ‘graph-blank’ y ‘graph-symbol’ y
define estas variables separadamente.

   También la documentación no está escrita.  Estas consideraciones nos
llevan también a la segunda versión de la función:

     (defvar graph-symbol "*"
       "Cadena usada como símbolo en grafo, normalmente un asterisco.")

     (defvar graph-blank " "
       "La cadena como un espacio en blanco en grafo, normalmente un
       espacio en blanco.
     graph-blank debe ser el mismo número de columnas amplio como graph-symbol.")

(Para una explicación de ‘defvar’, ver *note Inicializando una Variable
con ‘defvar’: defvar.)

     ;;; Segunda versión.
     (defun column-of-graph (max-graph-height actual-height)
       "Devuelve cadenas MAX-GRAPH-HEIGHT; ACTUAL-HEIGHT son
       símbolos de grafos.

     Los graph-symbols son entradas contiguo al fin de la lista.
     La lista será insertado como una columna de un grafo.
     Las cadenas son tanto graph-blank o graph-symbol.

       (let ((insert-list nil)
             (number-of-top-blanks
              (- max-graph-height actual-height)))

         ;; Rellenar en ‘graph-symbols’.
         (while (> actual-height 0)
           (setq insert-list (cons graph-symbol insert-list))
           (setq actual-height (1- actual-height)))

         ;; Rellenar en ‘graph-blanks’.
         (while (> number-of-top-blanks 0)
           (setq insert-list (cons graph-blank insert-list))
           (setq number-of-top-blanks
                 (1- number-of-top-blanks)))

         ;; Devuelve la lista completa.
         insert-list))

   Si se desea, podríamos reescribir ‘column-of-graph’ una tercera vez
para proporcionar opcionalmente un gráfico de líneas, como gráfico de
barras.  Esto no sería duro de hacer.  Un camino para pensar en un grafo
de líneas es que no es más que un grafo de barras en el que la parte de
cada barra que está debajo del alto es blanco.  Para construir una
columna para gráfico de líneas, la función primero construyen una lista
de espacios en blanco que es una más ordenada que el valor, entonces usa
‘cons’ para adjuntar un símbolo gráfico a la lista; entonces eso usa
‘cons’ de nuevo para adjuntar el 'alto de espacios en blanco' a la
lista.

   Es fácil ver como escribir tal función, pero puesto que no se
necesita eso, no se hará.  Pero el trabajo podría ser hecho, y si eso se
hiciera, se haría con ‘column-of-graph’.  Incluso más importante, no se
valora nada más que pocos cambios que tendrían que ser hechos de
cualquier otra manera.  La mejora, que se desea hacer, es simple.

   Ahora, finalmente, volvemos a nuestra primera función de grafo
impresa.  Esto imprime el cuerpo de un grafo, no las etiquetas para los
ejes horizontal y vertical, así se puede llamar este ‘graph-body-print’.


File: emacs-lisp-intro-es.info,  Node: graph-body-print,  Next: recursive-graph-body-print,  Prev: Columnas de un grafo,  Up: Leyendo un grafo

15.1 La función ‘graph-body-print’
==================================

Después de nuestra preparación en la sección precedente, la función
‘graph-body-print’ es simple.  La función imprimirá la columna después
de la columna de asteriscos y espacios en blanco, usando los elementos
de la lista de números para especificar el número de asteriscos en cada
columna.  Esto es un acto repetitivo, que significa que se puede usar un
bucle ‘while’ que decrementa o una función recursiva para el trabajo.
En esta sección, se escribirá la definición usando un bucle ‘while’.

   La función ‘column-of-graph’ requiere el alto del grafo como un
argumento, así se asigna y guarda esto como una variable local.

   Esto lidera a la siguiente plantilla para el bucle ‘while’ versión de
esta función:

     (defun graph-body-print (numbers-list)
       "DOCUMENTATION..."
       (let ((height  ...
              ...))

         (while numbers-list
           INSERT-COLUMNS-AND-REPOSITION-POINT
           (setq numbers-list (cdr numbers-list)))))

Necesitamos rellenar los slots de la plantilla.

   Claramente, se puede usar la expresión ‘(apply 'max numbers-list)’
para determinar el alto del grafo.

   El bucle ‘while’ iterará a través de ‘numbers-list’ un elemento a la
vez.  Como eso está ordenado por la expresión ‘(setq numbers-list (cdr
numbers-list))’, el CAR de cada instancia de la lista es el valor del
argumento para ‘column-of-graph’.

   En cada ciclo del bucle ‘while’, la función ‘insert-rectangle’
inserta la lista devuelta por ‘column-of-graph’.  Desde que la función
‘insert-rectangle’, se necesita guardar la localización de punto al
tiempo que el rectángulo se inserta, mueve atrás a esta posición después
de que el rectángulo es insertado, y entonces se mueve horizontalmente
al siguiente lugar desde el que ‘insert-rectangle’ se llama.

   Si las columnas se insertan en un carácter amplio, será si los
espacios en blanco y asteriscos se usan, el comando de reposición es
simple ‘(forward-char 1)’; sin embargo, el ancho de una columna puede
ser más grande que uno.  Esto significa que el comando de
reposicionamiento sería escrito ‘(forward-char symbol-width)’.  El mejor
lugar para asociar la variable ‘symbol-width’ al valor del width de la
columna grafo está en la varlist de la expresión ‘let’.

   Estas consideraciones lideran a la siguiente definición de función:

     (defun graph-body-print (numbers-list)
       "Imprime un gráfico de barras de la NUMBERS-LIST.
     La numbers-list consiste en los valores del eje Y."

       (let ((height (apply 'max numbers-list))
             (symbol-width (length graph-blank))
             from-position)

         (while numbers-list
           (setq from-position (point))
           (insert-rectangle
            (column-of-graph height (car numbers-list)))
           (goto-char from-position)
           (forward-char symbol-width)
           ;; Dibuja la columna del grafo por columna.
           (sit-for 0)
           (setq numbers-list (cdr numbers-list)))
         ;; Emplaza el punto para etiquetas de ejes X.
         (forward-line height)
         (insert "\n")
     ))

La expresión inesperada en esta función es la expresión ‘(sit-for 0)’ en
el bucle ‘while’.  Esta expresión hace que el grafo imprima la operación
más interesante para vigilar lo que sería de otro modo.  La expresión
causa que Emacs pare (sit-for 0) para un momento cero y entonces
redibuje la pantalla.  Puesto aquí, eso causa que Emacs redibuje la
pantalla columna por columna.  Sin eso, Emacs no redibujaría la pantalla
hasta que la función exista.

   Se puede chequear ‘graph-body-print’ con una pequeña lista de
números.

  1. Instala ‘graph-symbol’, ‘graph-blank’, ‘column-of-graph’, que están
     en *note Columnas de un grafo::, and ‘graph-body-print’.

  2. Copia la siguiente expresión:

          (graph-body-print '(1 2 3 4 6 4 3 5 7 6 5 2 3))

  3. Cambia al búffer ‘*scratch*’ y emplaza el cursor donde quiere que
     el grafo empiece.

  4. Escribe ‘M-:’ (‘eval-expression’).

  5. Pega la expresión ‘graph-body-print’ dentro del minibúffer con
     ‘C-y’ (‘yank’).

  6. Presiona <RET> para evaluar la expresión ‘graph-body-print’

   Emacs imprimirá un grafo como este:

                         *
                     *   **
                     *  ****
                    *** ****
                   ********* *
                  ************
                 *************


File: emacs-lisp-intro-es.info,  Node: recursive-graph-body-print,  Next: Ejes Impresos,  Prev: graph-body-print,  Up: Leyendo un grafo

15.2 La función ‘recursive-graph-body-print’
============================================

La función ‘graph-body-print’ puede también ser escrito recursivamente.
La solución recursiva es dividida dentro de dos partes: una fuera
'wrapper' _envoltorio_ que usa una expresión ‘let’ para determinar los
valores varias variables que solo necesitan ser encontradas una vez, tal
como la máxima altura del grafo, y una función dentro que es llamada
recursivamente para imprimir el grafo.

   El 'envoltorio' no es complicado:

     (defun recursive-graph-body-print (numbers-list)
       "Imprime un gráfico de barras del NUMBERS-LIST.
     El numbers-list consiste en los valores del eje Y."
       (let ((height (apply 'max numbers-list))
             (symbol-width (length graph-blank))
             from-position)
         (recursive-graph-body-print-internal
          numbers-list
          height
          symbol-width)))

   La función recursiva es un poco más difícil.  Eso tiene cuatro
partes: el 'do-again-test', el código impreso, la llamada recursiva, y
la 'next-step-expression'.  El 'do-again-test' es una expresión ‘when’
determina si la ‘numbers-list’ contiene cualquier elemento que
permanece; si hace eso, la función imprime una columna del grafo usando
el código impreso y se llama así mismo de nuevo.  La función se llama
así misma de nuevo de acuerdo al valor producido por la
'next-step-expression' que causa para llamar a actuar en una versión
ordenada de la ‘numbers-list’.

     (defun recursive-graph-body-print-internal
       (numbers-list height symbol-width)
       "Imprime un gráfico de barras.
     Usado con la función recursive-graph-body-print."

       (when numbers-list
             (setq from-position (point))
             (insert-rectangle
              (column-of-graph height (car numbers-list)))
             (goto-char from-position)
             (forward-char symbol-width)
             (sit-for 0)     ; Dibuja un gráfico columna por columna.
             (recursive-graph-body-print-internal
              (cdr numbers-list) height symbol-width)))

   Después de la siguiente instalación, esta expresión puede ser
chequeada; aquí hay un ejemplo:

     (recursive-graph-body-print '(3 2 5 6 7 5 3 4 6 4 3 2 1))

   Aquí está lo que ‘recursive-graph-body-print’ produce:

                     *
                    **   *
                   ****  *
                   **** ***
                 * *********
                 ************
                 *************

   Cada una de estas dos funciones, ‘graph-body-print’ o
‘recursive-graph-body-print’, crea el cuerpo de un grafo.


File: emacs-lisp-intro-es.info,  Node: Ejes Impresos,  Next: Ejercicio de Línea de Grafo,  Prev: recursive-graph-body-print,  Up: Leyendo un grafo

15.3 Necesidad para ejes impresos
=================================

Un grafo necesita ejes impresos, así se puede orientar a tí mismo.  Para
un proyecto do-once, eso puede ser razonable dibujar los ejes a mano
usando el modo de emacs Picture, pero un grafo dibuja la función que
puede ser usada más de una vez.

   Por esta razón, se han escrito mejoras a la función básica
‘print-graph-body’ que automáticamente imprime etiquetas para los ejes
horizontal y vertical.  Puesto que la etiqueta de imprimir funciones no
contiene mucho material nuevo, se ha emplazado su descripción en un
apéndice *Note Un Grafo con Ejes Etiquetados: Grafo completo.


File: emacs-lisp-intro-es.info,  Node: Ejercicio de Línea de Grafo,  Prev: Ejes Impresos,  Up: Leyendo un grafo

15.4 Ejercicio
==============

Escribe una versión de línea de grafo de la funciones de impresión del
grafo.


File: emacs-lisp-intro-es.info,  Node: Inicialización de Emacs,  Next: Depurando,  Prev: Leyendo un grafo,  Up: Top

16 Tu fichero ‘.emacs’
**********************

"No te tiene que gustar Emacs para lo que te gusta" -- esto que parece
una frase paradójica es el secreto de GNU Emacs.  En realidad, Emacs es
una herramienta genérica.  La mayoría de la gente que usa Emacs, lo
personaliza para ajustarlo a sus necesidades.

   GNU Emacs está mayoritariamente escrito en Emacs Lisp; esto significa
que escribiendo expresiones en Emacs Lisp se puede modificar o extender
Emacs.

* Menu:

* Configuración por defecto::  Configuración por defecto
* Site-wide Init::           Se puede escribir site-wide ficheros init.
* defcustom::                Emacs escribirá código para ti.
* Empezando un fichero .emacs::  Cómo escribir un ‘fichero .emacs’.
* Texto y Autorelleno::      Corta líneas automáticamente.
* Alias de correo::          Usar abreviaciones para direcciones de correo
                               electrónico.
* Indentar modo de tabulaciones::  No usar tabulaciones con TeX
* Atajos de teclado::        Crear algunos atajos de teclado personales.
* Mapas de teclado::         Más acerca de atajos de teclado.
* Cargando ficheros::        Cargar (por ej. evaluar) ficheros
                               automáticamente.
* Autocarga::                Crear funciones disponibles.
* Extensión simple::       Definir una función; enlazarla a una tecla.
* Colores X11::              Colores en X.
* Miscelánea::             Miscelánea
* Mode Line::                Cómo personalizar tu mode line.


File: emacs-lisp-intro-es.info,  Node: Configuración por defecto,  Next: Site-wide Init,  Up: Inicialización de Emacs

Configuración por defecto de Emacs
==================================

Hay quien aprecia la configuración por defecto de Emacs.  Después de
todo, Emacs empieza en modo C cuando se edita un fichero C, empieza en
modo Fortran cuando se edita un fichero Fortran, y empieza en modo
Fundamental cuando se edita un fichero no adornado.  Esto tiene sentido,
si no sabes quien está yendo a usar Emacs.  ¿Quién sabe lo que una
persona espera hacer con un fichero no adornado?  El modo fundamental es
el modo correcto por defecto para tal fichero, tal como el modo C es lo
correcto para editar código C. (Suficientes lenguajes de programación
tienen sintaxis que permiten compartir funcionalidades, tal como el modo
C es ahora proporcionado por el modo CC, la 'Colección C'.)

   Pero cuando se conoce quien está yendo a usar Emacs -- tu, tu mismo -
entonces eso tiene sentido para personalizar Emacs.

   Por ejemplo, yo raramente quiero el modo Fundamental cuando edito un
fichero de otro modo no distinguido; yo quiero el modo Texto.  Esto es
por lo que yo personalizo Emacs: así eso se ajusta a mí.

   Se puede personalizar y extender Emacs escribiendo o adaptando un
fichero ‘~/.emacs’.  Esto es un fichero de inicialización personal; sus
contenidos, escritos en Emacs Lisp, cuentan a Emacs qué hacer.(1)

   Un fichero ‘~/.emacs’ contiene código Emacs Lisp.  Se puede escribir
este código por uno mismo; o se puede usar la funcionalidad ‘customize’
para escribir el código para ti.  Se puede combinar tus propias
expresiones y expresiones auto-escritas personalizadas en tu fichero
‘.emacs’.

   (Yo prefiero por mí mismo escribir mis propias expresiones, excepto
para estas, fuentes particularmente, que se encuentran fáciles de
manipular usando el comando ‘customize’.  Yo combino los dos métodos.)

   La mayoría de este capítulo es acerca de escribir expresiones por uno
mismo.  Eso describe un fichero ‘.emacs’ simple; para más información,
mira *note El Fichero de Inicio: (emacs)Fichero de Inicio, y la *note El
Fichero de Inicio: (elisp)Fichero de Inicio.

   ---------- Footnotes ----------

   (1) Tu puedes también añadir ‘.el’ para ‘~/.emacs’ y llama a un
fichero ‘~/.emacs’.  En el pasado, fué prohibido escribir los atajos de
teclado extra que el nombre ‘~/.emacs.el’ requiere, pero ahora puedes.
El nuevo formato es consistente con las conveniciones de nombre del
fichero Emacs Lisp; el viejo formato guarda la escritura.


File: emacs-lisp-intro-es.info,  Node: Site-wide Init,  Next: defcustom,  Prev: Configuración por defecto,  Up: Inicialización de Emacs

16.1 Fichero de inicialización site-wide
========================================

Además de tu fichero de inicialización personal, Emacs automáticamente
carga varios ficheros de inicialización amplios, si existen.  Tienen la
misma forma que tu fichero ‘.emacs’, pero se cargan por cualquiera.

   Dos ficheros de incialización, ‘site-load.el’ y ‘site-init.el’, están
cargados dentro de Emacs y volcados _dumped_ sin una versión dumped de
Emacs se creó, como es más común.  (Las copias dumped de Emacs cargan
más rápidamente.  Sin embargo, puesto que un fichero se carga y compila,
un cambio no llega a ser un cambio en Emacs a menos que se cargue por
uno mismo o se recompile Emacs.  *Note Construyendo Emacs:
(elisp)Construyendo Emacs, y el fichero ‘INSTALL’)

   Los otros tres ficheros de inicialización se cargan automáticamente
cada vez que se inicia Emacs, si existen.  Son ‘site-start.el’, que se
carga _antes_ que tu fichero ‘.emacs’, y ‘default.el’, y el tipo de
fichero terminal, que se cargan _después_ de tu fichero ‘.emacs’.

   Las configuraciones y definiciones en tu fichero ‘.emacs’
sobreescribirán las configuraciones en conflicto y definiciones en un
fichero ‘site-start.el’, si eso existe; pero las configuraciones y
definiciones en un ‘default.el’ o el tipo de fichero terminal
sobreescribirá estos en tu fichero ‘.emacs’.  (Se pueden prevenir
interferencias desde un tipo de fichero terminal configurando
‘term-file-prefix’ para ‘nil’.  *Note Una extensión simple: Extensión
simple.)

   El fichero ‘INSTALL’ que viene en la distribución contiene
descripciones de los fichero ‘site-init.el’ y ‘site-load.el’.

   Los ficheros ‘loadup.el’, ‘startup.el’, y ‘loaddefs.el’ controlan la
carga.  Estos ficheros están en el directorio ‘lisp’ de la distribución
Emacs y tiene valor de uso.

   El fichero ‘loaddefs.el’ contiene buenas sugerencias como las que
poner dentro de tu propio fichero ‘.emacs’, o dentro de un fichero de
inicialización amplio.


File: emacs-lisp-intro-es.info,  Node: defcustom,  Next: Empezando un fichero .emacs,  Prev: Site-wide Init,  Up: Inicialización de Emacs

16.2 Especificar variables usando ‘defcustom’
=============================================

Se pueden especificar variables usando ‘defcustom’ así que la gente
pueda usar la funcionalidad de Emacs ‘customize’ para asignar sus
valores.  (No se puede usar ‘customize’ para escribir definiciones de
función; pero se pueden escribir ‘defuns’ en tu fichero ‘.emacs’.  En
vez de eso, se puede escribir cualquier expresión Lisp en tu fichero
‘.emacs’).

   La funcionalidad ‘customize’ depende de la forma especial
‘defcustom’.  Aunque se puede usar ‘defvar’ o ‘setq’ para las variables
que los usuarios asignan, la forma especial ‘defcustom’ está diseñada
para el trabajo.

   Se puede usar tu conocimiento de ‘defvar’ para escribir los primeros
tres argumentos para ‘defcustom’.  El primer argumento para ‘defcustom’
es el nombre de la variable.  El segundo argumento es el valor inicial
de la variable, cualquiera; y este valor es asignado solo si el valor no
ha sido ya asignado.  El tercer argumento es la documentación.

   El cuarto y subsiguientes argumentos para ‘defcustom’ especifican los
tipos y opciones; estos no son funcionales en ‘defvar’.  (Estos
argumentos son opcionales.)

   Cada uno de estos argumentos consiste de una palabra seguido de una
palabra por un valor.  Cada palabra clave empieza con los dos puntos
‘:’.

   Por ejemplo, la variable de opciones personalizable ‘text-mode-hook’
se parece a esto:

     (defcustom text-mode-hook nil
       "El hook normal se ejecuta cuando se introduce en modo texto y
       muchos modos relacionados."
       :type 'hook
       :options '(turn-on-auto-fill flyspell-mode)
       :group 'data)

El nombre de la variable es ‘text-mode-hook’; no tiene valor por
defecto; y su cadena de documentación cuenta lo que hace.

   La palabra clave ‘:type’ le cuenta a Emacs el tipo de datos para los
que ‘text-mode-hook’ sería asignado y como muestra el valor en un búffer
de Personalización.

   La palabra clave ‘:options’ especifica una lista sugerida de valores
para la variable.  Normalmente, ‘:options’ se asocia a un gancho
(_hook_.  La lista es solo una sugerencia; esa no es exclusiva; una
persona quien asigna la variable puede asignarse a otros valores; la
lista mostrada siguiendo la palabra clave ‘:options’ se pretende ofrecer
elecciones convenientes a un usuario.

   Finalmente, la palabra clave ‘:group’ cuenta el comando de
Personalización de Emacs en el que el grupo de la variable está
localizado.  Esto cuenta dónde encontralo.

   La función ‘defcustom’ reconoce más de una docena de palabras clave.
Para más información, mire *note Escribiendo las Definiciones de
Personalización: (elisp)Personalización.

   Considere ‘text-mode-hook’ como un ejemplo.

   Hay dos caminos para personalizar esta variable.  Se puede usar el
comando de personalización o escribir las expresiones apropiadas por uno
mismo.

   Usando el comando de personalización, se puede escribir:

     M-x customize

y encuentre que el grupo para editar ficheros de datos se llama 'datos'.
Introduzca este grupo.  El Hook _Disparador_ es el primer miembro.  Se
puede hacer click en sus opciones varias, tal como ‘turn-on-auto-fill’,
para asignar los valores.  Después de hacer click en el botón.

     Guárdalo para Futuras Sesiones

Emacs escribirá una expresión en tu fichero ‘.emacs’.  Se parecerá a
esto:

     (custom-set-variables
       ;; custom-set-variables fué añadido por Custom.
       ;; Si se edita a mano, tu podrías liarte,
       ;; así que ten cuidado.
       ;; Tu fichero init contendría solo esta instancia.
       ;; Si hay más de uno, ellos no quieren trabajar.
      '(text-mode-hook (quote (turn-on-auto-fill text-mode-hook-identify))))

(La función ‘text-mode-hook-identify’ cuenta
‘toggle-text-mode-auto-fill’ que buffers hay en modo Texto.  Eso viene
automáticamente)

   La función ‘custom-set-variables’ funciona de alguna manera diferente
más de un ‘setq’.  Mientras yo nunca he aprendido las diferencias, yo
modifico las expresiones ‘custom-set-variable’ en mi fichero ‘.emacs’ a
mano: yo creo los cambios en los que aparecen a mi para ser una manera
razonable y no tener problemas.  Otros prefieren usar el comando de
Personalización y permitir a Emacs hacer el trabajo para ellos.

   Otra función ‘custom-set-...’ es ‘custom-set-faces’.  Esta función
asigna varios tipos de fuentes.  A través del tiempo, yo he asignado un
considerable número de tipos.  Algo de tiempo, yo las reseteo usando
‘customize’; otras veces, simplemente edito la expresión
‘custom-set-faces’ en mi fichero ‘.emacs’ en sí.

   El segundo modo de personalizar tu ‘text-mode-hook’ es asignarte a tí
mismo en tu fichero ‘.emacs’ usando código que no tiene nada que hacer
con las funciones ‘custom-set-...’.

   Cuando se hace esto, y después usa ‘customize’, se verá un mensaje
que dice:

     CHANGED fuera de Personalizar; operando dentro aquí
     puede ser no confiable.

   Este mensaje es solo un aviso.  Si se puede cliquear en el botón a

     Guárdalo para Futuras Sesiones

Emacs escribirá una expresión ‘custom-set-...’ cerca del fin de tu
fichero ‘.emacs’ que será evaluado después de que tu expresión sea
escrita a mano.  Por esta razón, se sobreescribirá tu expresión escrita
a mano.  Ningún daño será hecho.  Cuando se haga esto, sin embargo, ten
cuidado para recordar que expresión está activa; si olvidas, puedes
confundirte por tí mismo.

   Tan largo como se recuerda donde los valores son configurados, no
habrá problemas.  En cualquier eventos, los valores son siempre
configurados en tu fichero de inicialización, que es normalmente llamado
‘.emacs’.

   Yo mismo hago un ‘customize’ para cualquier cosa.  Mayoritariamente,
escribo expresiones por mí mismo.

   Incidentalmente, para ser una definición concerniente más completa:
‘defsubst’ define una función inline.  La sintaxis es solo como esta de
‘defun’.  ‘defconst’ define un símbolo como una constante.  El intento
es que ningún programa o usuario cambiarían un valor asignado por
‘defconst’.  (Se puede cambiar; el valor asignado es una variable; pero
por favor no lo haga.)


File: emacs-lisp-intro-es.info,  Node: Empezando un fichero .emacs,  Next: Texto y Autorelleno,  Prev: defcustom,  Up: Inicialización de Emacs

16.3 Empieza por un fichero ‘.emacs’
====================================

Cuando se abre Emacs, se carga tu fichero ‘.emacs’ a menos que se cuente
que no se especifique ‘-q’ en la línea de comandos.  (El comando ‘emacs
-q’ tu da un Emacs plano, fuera.)

   Un fichero ‘.emacs’ contiene expresiones Lisp.  Con frecuencia, no
hay más expresiones para configura valores; algunas veces esas son
definiciones de funciones.

   *Note El Fichero de Inicio ‘~/.emacs’: (emacs)Fichero de Inicio, para
una corta descripción de fichero de inicialización.

   Este capítulo cubre algo del mismo suelo, pero es un paseo entre
extractos desde un completo, largamente usado fichero ‘.emacs’ -- por
mí.

   La primera parte del fichero consiste en comentario: me recuerdo a mí
mismo.  Por ahora, yo recuerdo estas cosas, pero cuando empecé, no.

     ;;;; fichero .emacs de Bob
     ; Robert J. Chassell
     ; 26 de Septiembre de 1985

¡Mira en esta fecha!  Yo empecé este fichero hace mucho tiempo.  Yo he
estado añadiendo cosas desde siempre.

     ; Cada sección en este fichero es introducido por una
     ; línea empezando con cuatro puntos y comas y cada
     ; entrada es introducida por una línea empezando con
     ; tres puntos y comas.

Esto describe las convenciones usuales para comentarios en Emacs Lisp.
Cada cosa en una línea que sigue un punto y coma es un comentario.  Dos,
tres, y cuatro puntos y coma son usados como subsección y marcas de
sección.  (*Note (elisp)Comentarios::, para más comentarios.)

     ;;;; La Tecla de Ayuda
     ; Control-h es la tecla de ayuda;
     ; después escribiendo control-h, escribe una letra a
     ; indica el asunto acerca del que quieres ayuda.
     ; Para una explicación de la facilidad de ayuda,
     ; escribe control-h dos veces en una fila.

Solo recuerda: escribe ‘C-h’ dos veces para ayudar.

     ; Para informarse acerca de cualquier modo, escribe control-h m
     ; mientras esté en este modo. Por ejemplo, para encontrar
     ; acerca del modo correo, introduce el modo correo y entonces
     ; escribe control-h m.

'Modo ayuda', como yo llamo a esto, es muy útil.  Usualmente, se cuenta
todo lo que se necesita saber.

   De acuerdo, no se necesitan incluir comentarios y ficheros como estos
‘.emacs’.  Yo los incluí en el mío porque se olvida el Modo ayuda o las
convenciones para comentarios -- pero era capaz de recordar ver aquí
recordármelo a mí mismo.


File: emacs-lisp-intro-es.info,  Node: Texto y Autorelleno,  Next: Alias de correo,  Prev: Empezando un fichero .emacs,  Up: Inicialización de Emacs

16.4 Modo texto y auto relleno
==============================

Ahora regresa a la parte que 'vuelve' al modo Texto y modo Auto Relleno.

     ;;; Modo texto modo Auto Fill
     ;; Las siguiente dos líneas puestas en Emacs dentro de
     ;; modo Texto y en el modo Auto Fill, son para escritores que
     ;; quieren empezar a escribir prosa en vez de código.
     (setq-default major-mode 'text-mode)
     (add-hook 'text-mode-hook 'turn-on-auto-fill)

   ¡Aquí está la primera parte de este fichero ‘.emacs’ que hace alguna
cosa bajo recuerdo de un humano olvidado!

   La primera de las dos líneas entre paréntesis cuentan a Emacs a
cambiar al modo Texto que se encuentra un fichero, _a menos que_ el
fichero iría dentro de algún otro modo, tal como el modo C.

   Cuando Emacs lee un fichero, eso parece la extensión al nombre del
fichero.  (La extensión es la parte que viene después de un ‘.’.)  Si el
fichero finaliza con una extensión ‘.c’ o ‘.h’ entonces Emacs cambia al
modo C. También, Emacs parece al principio una línea no blanca del
fichero; si la línea dice ‘-*- C -*-’, Emacs cambia al modo C. Emacs
posee una lista de extensiones y especificaciones que usa
automáticamente.  Además, Emacs se ve cerca de la última página por
buffer, "lista variables locales".

   *Note Como los Modos Mayores son Elegidos: (emacs)Eligiendo Modos.

   *Note Variables Locales en Ficheros: (emacs)Variables de Fichero.

   Ahora, regresa al fichero ‘.emacs’.

   Aquí está la línea de nuevo; ¿cómo funciona?

     (setq major-mode 'text-mode)

Esta línea es un resumen, pero completa la expresión Emacs Lisp.

   Ya estamos familiarizados con ‘setq’.  Eso asigna la siguiente
variable, ‘major-mode’, al subsiguiente valor, que es ‘text-mode’.  La
marca de cita simple antes de ‘text-mode’ cuenta a Emacs como tratar
directamente con el símbolo, no con cualquier cosa que pudiera existir.
*Note Configurando el Valor de una Variable: set y setq, por un recuerdo
de como ‘setq’ funciona.  El principal punto es que no hay diferencia
entre el procedimiento que se usa para asignar un valor en su fichero
‘.emacs’ y el procedimiento que se usa en cualquier lugar más en Emacs.

   Aquí está la siguiente línea:

     (add-hook 'text-mode-hook 'turn-on-auto-fill)

En esta línea, el comando ‘add-hook’ añade ‘turn-on-auto-fill’ para la
variable.

   ¡‘turn-on-auto-fill’ es el nombre de un programa, que se adivina!,
cambia al modo Auto Fill.

   Cada vez que Emacs cambia al modo texto, Emacs ejecuta el comando
'hooked' dentro de modo Texto.  Así que cada vez que Emacs cambia al
modo Texto, Emacs también cambia al modo de autoajuste.

   En breve, la primera línea causa a Emacs a entrar en modo Texto
cuando se edite un fichero, a menos que la extensión del nombre del
fichero, una línea no en blanco, variables locales para contar a Emacs
de otro modo.

   El modo texto entre otras acciones, asigna la tabla de sintaxis para
trabajar adecuadamente a escritores.  En modo texto, Emacs considera un
apóstrofe como parte de una palabra como una letra; pero Emacs no
considera un período o un espacio como parte de una palabra.  De este
modo, ‘M-f’ se mueve hacia tí a través de ‘eso’.  Por otro lado, en modo
C, ‘M-f’ para solo después del ‘t’ de ‘eso’.

   La segunda línea causa que Emacs active el modo Auto Fill cuando
cambia al modo Texto.  En modo Auto Fill, Emacs automáticamente rompe
una línea que es demasiado amplio y trae la parte excesivamente amplia
de la línea de debajo a la siguiente línea.  Emacs rompe líneas entre
palabras con ellas.

   Cuando el modo Auto Fill está desactivado, las líneas continúan a la
derecha como se escriben.  Dependiendo de como configuras el valor de
‘truncate-lines’, las palabras que se escribe si desaparecen al lado
derecho de la pantalla, o lo demás son mostradas, en un modo feo e
ilegible, como una línea de continuación en la pantalla.

   Además, en esta parte de mi fichero ‘.emacs’, yo cuento a Emacs el
ajuste de comandos para insertar dos espacios después de dos puntos:

     (setq colon-double-space t)


File: emacs-lisp-intro-es.info,  Node: Alias de correo,  Next: Indentar modo de tabulaciones,  Prev: Texto y Autorelleno,  Up: Inicialización de Emacs

16.5 Alias de correo
====================

Aquí hay un ‘setq’ que 'activa' el alias de correo, para más ocasiones.

     ;;; Modo Correo
     ; Para entrar en el modo correo, escribe `C-x m'
     ; Para introducir RMAIL (para leer el correo),
     ; escribe `M-x rmail'
     (setq mail-aliases t)

Este comando ‘setq’ asigna el valor de la variable ‘mail-aliases’ al
‘t’.  Desde que ‘t’ significa cierto, la línea dice, en efecto, "Sí uso
alias de correo."

   Los alias de correo son nombres cortos convenientes para largas
direcciones de correo o para listas de direcciones de correo.  El
fichero donde guardar tus 'aliases' es ‘~/.mailrc’.  Se escribe un alias
como este:

     alias geo george@foobar.wiz.edu

Cuando se escribe un mensaje a Jorge, la dirección a ‘geo’; el correo
automáticamente expandirá ‘geo’ a la dirección completa.


File: emacs-lisp-intro-es.info,  Node: Indentar modo de tabulaciones,  Next: Atajos de teclado,  Prev: Alias de correo,  Up: Inicialización de Emacs

16.6 Indentar modo de tabulaciones
==================================

Por defecto, Emacs inserta tabulaciones en lugar en múltiples espacios
cuando se formatea una región.  (Por ejemplo, se podrían indentar muchas
líneas de texto todo a la vez con el comando ‘indent-region’.)  Los
tabuladores se ven bien en un terminal o con impresión ordinaria, pero
ellos producen mala salida de indentación cuando se usa TeX o Texinfo
puesto que TeX ignora tabuladores.

   Lo siguiente desactiva el modo de Indentar Tabulaciones:

     ;;; Prevenir Tabulaciones Extrañas
     (setq-default indent-tabs-mode nil)

   Note que esta línea usa ‘setq-default’ en vez de el comando ‘setq’
que hemos visto antes.  El comando ‘setq-default’ asigna valores solo en
búffers que no tienen sus propios valores locales para la variable.

   *Note Tabuladores versus Espacios: (El Manual de GNU Emacs)Solo
Espacios.

   *Note Variables Locales en Ficheros: (emacs)Variables de Fichero.


File: emacs-lisp-intro-es.info,  Node: Atajos de teclado,  Next: Mapas de teclado,  Prev: Indentar modo de tabulaciones,  Up: Inicialización de Emacs

16.7 Algunos atajos
===================

Ahora para algunos atajos personales:

     ;;; Compara ventanas
     (global-set-key "\C-cw" 'compare-windows)

   ‘compare-windows’ es un comando excelente que compara el texto en tu
ventana actual con texto de la siguiente ventana.  Eso hace la
comparación empezando al punto en cada ventana, moviendo a través del
texto en cada ventana tan lejos como ellos asocian.  Yo uso este comando
todo el tiempo.

   Esto también muestra como configurar una tecla globalmente, para todo
los modos

   El comando es ‘global-set-key’.  Es seguido por el atajo.  En un
fichero ‘.emacs’, el atajo es escrito como se ve: ‘\C-c’ que se asocia a
'control-c', que significa 'presionar la tecla de control y la tecla <c>
al mismo tiempo'.  La ‘w’ significa 'presionar la tecla <w>'.  El atajo
es rodeado por dobles comillas.  En la documentación, se escribiría esto
como ‘C-c w’.  (Si estuviera asociando una tecla <META>, tal como ‘M-c’,
en vez de una tecla de <CTRL>, se escribiría ‘\M-c’ en su fichero
‘.emacs’.  *Note Reasociando Teclas en Su Fichero Init:
(emacs)Reasociando Init, para más detalles.)

   El comando invocado por las teclas es ‘compare-windows’.  Note que
‘compare-windows’ es precedido por una comilla simple; de otro modo,
Emacs primero intentaría evaluar el símbolo para determinar su valor.

   Estas tres cosas, las marcas de dobles comillas, la barra invertida
antes de la ‘C’, y la marca de comilla simple son partes necesarias de
atajos de teclado que tiendo a olvidar.  Afortunadamente, he llegado a
recordar que miraría mi fichero ‘.emacs’ existente, y lo adaptaría a lo
que hay.

   Como para el atajo en sí: ‘C-c w’, combina la tecla prefija, ‘C-c’,
con un caracter simple, en este caso, ‘w’.  Este conjunto de teclas,
‘C-c’ seguido por un caracter simple, es estrictamente reservado para un
uso propio individual.  (Esto se llama teclas 'propias', puesto que
estas son para su propio uso).  Siempre sería capaz de crear tal atajo
para el uso propio sin pisar fuerte en algún atajo más.  Si siempre se
escribe una extensión a Emacs, por favor, evite tomar cualquiera de
estas teclas para uso público.  Se cree que una tecla como ‘C-c C-w’ en
vez de eso.  De otra manera, ejecutará sin sus 'propias' teclas.

   Aquí hay otro atajo, con un comentario:

     ;;; Atajo para `occur'
     ; Yo uso mucho occur, así permite asignarlo a una tecla:
     (global-set-key "\C-co" 'occur)

   El comando ‘occur’ muestra todas las líneas en el buffer actual que
contiene un emparejamiento para una expresión regular.  Asociar las
líneas que se muestran en un búffer llamado ‘*Occur*’.  Este buffer
sirve como un menu para saltar a ocurrencias.

   Aquí se muestra como desasignar una tecla, así no funciona:

     ;;; Desasociar `C-x f'
     (global-unset-key "\C-xf")

   Hay una razón para esta no asociación: Yo encontré inadvertidamente
escrito ‘C-x f’ cuando significó escribir ‘C-x C-f’.  En vez de
encontrar un fichero, como se pretende, accidentalmente asigna el ancho
para el fichero lleno, casi siempre a un tamaño que no quería.  Puesto
que duramente se reseteó mi ancho por defecto, yo simplemente disocié la
tecla.

   Lo siguiente reasocia una tecla existente:

     ;;; Reasocia `C-x C-b' al `buffer-menu'
     (global-set-key "\C-x\C-b" 'buffer-menu)

   Por defecto, ‘C-x C-b’ ejecute el comando ‘list-buffers’.  Este
comando lista sus buffers en _otra_ ventana.  Desde que casi siempre se
quiere hacer alguna cosa en esta ventana, se prefiere el comando
‘buffer-menu’, que no solo lista los buffers, pero mueve el punto dentro
de esta ventana.


File: emacs-lisp-intro-es.info,  Node: Mapas de teclado,  Next: Cargando ficheros,  Prev: Atajos de teclado,  Up: Inicialización de Emacs

16.8 Mapas de teclado
=====================

Emacs usa “keymaps” para grabar qué teclas llaman a qué comandos.
Cuando se use ‘global-set-key’ para asignar los atajos de teclados a un
simple comando en todo ‘current-global-map’.

   Modos específicos, tales como modo C o modo Texto, tiene sus propios
mapas de teclado; mapas de teclado de modo específico sobreescribe el
mapa global que es compartido por todos los buffers.

   La función ‘global-set-key’ asocia, o reasocia, el mapa de teclado
global.  Por ejemplo, las siguientes asociaciones la tecla ‘C-x C-b’ a
la función ‘buffer-menu’:

     (global-set-key "\C-x\C-b" 'buffer-menu)

   Mapas de teclado específico de modo son asociados usando la función
‘define-key’, que toma un mapa de teclado específico como un argumento,
tan bien como la tecla y el comando.  Por ejemplo, mi fichero ‘.emacs’
contiene la siguiente expresión asociada al comando
‘texinfo-insert-@group’ comando a ‘C-c C-c g’:

     (define-key texinfo-mode-map "\C-c\C-cg" 'texinfo-insert-@group)

La función ‘texinfo-insert-@group’ en sí es una pequeña extensión del
modo Texinfo que inserta ‘@group’ dentro de un fichero Texinfo.  Se usa
este comando todo el tiempo y se prefieren escribir los tres atajos ‘C-c
C-c g’ en vez de los seis atajos ‘@ g r o u p’.  (‘@group’ y su
asociación ‘@end group’ son comandos que guarda todo el texto cerrado
junto a una página; muchos ejemplos multi-línea en este libro están
rodeados por ‘@group ... @end group’.)

   Aquí está la definición de función ‘texinfo-insert-@group’:

     (defun texinfo-insert-@group ()
       "Inserta la cadena @group en un búffer Texinfo."
       (interactive)
       (beginning-of-line)
       (insert "@group\n"))

   (De acuerdo, podría haber usado el modo Abbrev para dejar de
escribir, en vez de escribir una función para insertar una palabra; pero
prefiero atajos de teclado consitentes con otro modo Texinfo para atajos
de teclado.)

   Verá numerosas expresiones ‘define-key’ en ‘loaddefs.el’ tan bien
como en varios modos de librerías, tal como ‘cc-mode.el’ y
‘lisp-mode.el’.

   *Note Personalizando Atajos de Teclado: (emacs)Atajos de Teclado, y
*note Mapas de Teclado: (elisp)Mapas de Teclado, para más información
acerca de mapas de teclado.


File: emacs-lisp-intro-es.info,  Node: Cargando ficheros,  Next: Autocarga,  Prev: Mapas de teclado,  Up: Inicialización de Emacs

16.9 Cargando ficheros
======================

Muchas personas en la comunidad de GNU Emacs han escrito extensiones a
Emacs.  Hace tiempo, que estas extensiones son con frecuencia incluidas
en las nuevas entregas _releases_.  Por ejemplo, los paquetes Calendario
y Diario son ahora parte del estándar GNU Emacs, como es Calc.

   Se puede usar un comando ‘load’ para evaluar un fichero completo que
significa instalar todas las funciones y variables en el fichero Emacs.
Por ejemplo:

     (load "~/emacs/slowsplit")

   Esto evalúa, por ej. carga, el fichero ‘slowsplit.el’ o si eso
existe, lo más rápido, el fichero compilado ‘slowsplit.elc’ desde el
subdirectorio ‘emacs’ del directorio home.  El fichero contiene la
función ‘split-window-quietly’, que John Robinson escribió en 1989.

   La función ‘split-window-quietly’ divide una ventana con el mínimo de
redisplay.  Yo lo instalé en 1989 porque trabajó bien con los terminales
de 1200 baudios que entonces estaba usando.  Ahora, ocasionalmente vengo
a través de una conexión lenta, pero continúa usando la función porque
me gusta el camino que deja arriba del búffer en el bajo de las nuevas
ventanas y arriba en la ventana superior.

   Para reemplazar el atajo de teclado por defecto
‘split-window-vertically’, se debe también desasignar esta tecla y
asociar las teclas a ‘split-window-quietly’, como este:

     (global-unset-key "\C-x2")
     (global-set-key "\C-x2" 'split-window-quietly)

   Si se cargan muchas extensiones, como yo hago, entonces en vez de
especificar la posición exacta del fichero, como se muestra arriba, se
puede especificar que directorio como parte del ‘load-path’ de Emacs.
Entonces, cuando Emacs carga un fichero, buscará que directorio tan bien
como su lista por defecto de directorios.  (La lista por defecto es
especificada en ‘paths.h’ cuando Emacs se construye.)

   El comando siguiente añade tu directorio ‘~/emacs’ a la ruta
existente:

     ;;; Ruta Emacs
     (setq load-path (cons "~/emacs" load-path))

   Incidentalmente, ‘load-library’ es un interfaz interactivo a la
función ‘load’.  La función se parece a esto:

     (defun load-library (library)
       "Carga la librería llamada LIBRARY.
     Esto es una interfaz a la función `load'."
       (interactive
        (list (completing-read "Carga la librería: "
                               (apply-partially 'locate-file-completion-table
                                                load-path
                                                (get-load-suffixes)))))
       (load library))

   El nombre de la función, ‘load-libray’, viene desde el uso de
'library' como un sinónimo para 'file'.  La fuente para el comando
‘load-library’ está en la librería ‘files.el’.

   Otro comando interactivo que hace un trabajo ligeramente diferente es
‘load-file’.  *Note Librerías de Código Lisp para Emacs:
(emacs)Librerías Lisp, para información en la distinción entre
‘load-library’ y este comando.


File: emacs-lisp-intro-es.info,  Node: Autocarga,  Next: Extensión simple,  Prev: Cargando ficheros,  Up: Inicialización de Emacs

16.10 Autoloading
=================

En vez de instalar una función cargando el fichero que lo contiene, o
evaluando la definición de función, se puede hacer la función disponible
pero actualmente no se instala hasta la primera vez llamada.  Este
proceso se llama “autocarga” (_autoloading_).

   Cuando se ejecuta una función de autocarga, Emacs automáticamente
evalúa el fichero que contiene la definición, y entonces llama a la
función.

   Emacs empieza rápido con funciones de autocarga, puesto que sus
librerías no se cargan bien; pero si necesita esperar un momento cuando
su primer uso tal como una función, mientras que el fichero que lo
contiene se evalúa.

   Raramente las funciones usadas son frecuentemente autocargadas.  La
librería ‘loaddefs.el’ coniene cientos de funciones autocargadas, desde
‘bookmark-set’ a ‘wordstar-mode’.  Si se usa una función 'rara'
frecuentemente, se debería cargar este fichero de función con una
expresión de ‘load’ en tu fichero ‘.emacs’.

   En mi fichero ‘.emacs’, se cargan 14 librerías que contienen
funciones que de otro modo serían autocargadas.  (Actualmente, eso
habría sido mejor para incluir estos ficheros en mi Emacs 'volcado',
pero se olvida.  *Note Construyendo Emacs: (elisp)Construyendo Emacs, y
el fichero ‘INSTALL’ para más acerca de volcados.)

   Se puede también querer incluir expresiones autocargadas en tu
fichero ‘.emacs’.  ‘autoload’ es una función construida que toma cinco
argumento, los tres finales de los que son opcionales.  El primer
argumento es el nombre de la función para ser autocargada.  El segundo
es el nombre del fichero para ser cargado.  El tercer argumento es
documentación para la función, y el cuarto cuenta si la función puede
ser llamada interactivmente.  El quinto argumento cuenta que tipo de
objeto -- ‘autoload’ puede manejar un mapa de teclado o macro tan bien
como una función (por defecto es una función).

   Aquí hay un ejemplo típico:

     (autoload 'html-helper-mode
       "html-helper-mode" "Editar documentos HTML" t)

(‘html-helper-mode’ es una vieja alternativa a ‘html-mode’, que es una
parte estándar de la distribución.)

Esta expresión autocarga la función ‘html-helper-mode’.  Esto se toma
desde el fichero ‘html-helper-mode-el’ (o desde la versión compilada
‘html-helper-mode.elc’, si eso existe).  El fichero debe ser localizado
en un directorio específico por ‘load-path’.  La documentación dice que
esto es un modo para ayudar a editar documentos escritos en Lenguaje de
Marcas de Hiper Texto.  Se puede llamar este modo interactivamente
escribiendo ‘M-x html-helper-mode’.  (Se necesitan duplicar las
funciones regulares de documentación en la expresión de autocarga porque
la función regular no está todavía cargada, así su documentación no está
disponible.)

   *Note Autocarga: (elisp)Autocarga, para más información.


File: emacs-lisp-intro-es.info,  Node: Extensión simple,  Next: Colores X11,  Prev: Autocarga,  Up: Inicialización de Emacs

16.11 Una extensión simple: ‘line-to-top-of-window’
===================================================

Aquí hay una simple extensión a Emacs que mueve el punto de línea arriba
de la ventana.  Yo uso esto todo el tiempo, para hacer fácil de leer el
texto.

   Se puede poner el siguiente código dentro de un fichero separado y
entonce cargarlo desde tu fichero ‘.emacs’, o se puede incluir con tu
fichero ‘.emacs’.

   Aquí está la definición

     ;;; Línea a lo alto de la ventana;
     ;;; reemplaza tres secuencias de atajos de teclado  C-u 0 C-l
     (defun line-to-top-of-window ()
       "Mueve la línea que apunta a lo alto de la ventana."
       (interactive)
       (recenter 0))

   Ahora el atajo.

   En estos días, las teclas de función así como los eventos del ratón y
caracteres no ASCII son escritos con corchetes, sin marcas de citas.
(En Emacs versión 18 y anteriores, se tenía que escribir diferentes
teclas de función asignadas por cada diferente creación del terminal.)

   Se puede asociar ‘line-to-top-of-window’ a la tecla de función <F6>
así:

     (global-set-key [f6] 'line-to-top-of-window)

   Para más información, mira *note Reasociando Teclas en tu fichero
init: (emacs)Reasociando el Init.

   Si ejecutas dos versiones de GNU Emacs, tal como las versiones 22 y
23, y usas un fichero ‘.emacs’, se puede seleccionar qué código evalúa
el siguiente condicional:

     (cond
      ((= 22 emacs-major-version)
       ;; evalúa la version 22
       ( ... ))
      ((= 23 emacs-major-version)
       ;; evalúa la version 23
       ( ... )))

   Por ejemplo, en versiones más recientes se ocultan los cursores por
defecto.  Si se odia tal ocultación se escribe lo siguiente en mi
fichero ‘.emacs’(1):

     (when (>= emacs-major-version 21)
       (blink-cursor-mode 0)
       ;; Inserta la nueva línea cuando se presiona `C-n' (next-line)
       ;; al fin del búffer
       (setq next-line-add-newlines t)
       ;; Cambia la imagen viendo
       (auto-image-file-mode t)
       ;; Activa la barra de menu (esta barra tiene texto)
       ;; (Usa un argumento numérico para activarlo)
       (menu-bar-mode 1)
        ;; Desactiva la barra de herramientas (esta barra tiene iconos)
        ;; (Usa argumentos numéricos para activarlo)
        (tool-bar-mode nil)
       ;; Desactiva el modo tooltip para la tool bar
       ;; (Este modo causa explicaciones de iconos al pop up)
       ;; (Usa el argumento numérico para activarlo)
       (tooltip-mode nil)
       ;; Si los tooltips activados, crea consejos aparecen en el prompt
       (setq tooltip-delay 0.1)  ; por defecto es de 0.7 segundos
        )

   ---------- Footnotes ----------

   (1) Cuando se empiezan las instancias de Emacs que no cargan mi
fichero ‘.emacs’ o cualquier fichero, también se puede deshabilitar la
ocultación:
     emacs -q --no-site-file -eval '(blink-cursor-mode nil)'
O ahora,
     usando un conjunto más sofisticado de opciones, emacs -Q - D


File: emacs-lisp-intro-es.info,  Node: Colores X11,  Next: Miscelánea,  Prev: Extensión simple,  Up: Inicialización de Emacs

16.12 Colores X11
=================

Se pueden especificar colores cuando se usa Emacs con el Sistema de
Ventanas X del MIT.

   Si disgustan los colores por defecto y especifica unos propios.

   Aquí están las expresiones en un fichero ‘.emacs’ que establecen los
valores:

     ;; Asigna el color del cursor
     (set-cursor-color "white")

     ;; Asigna el color del ratón
     (set-mouse-color "white")

     ;; Asigna foreground y background
     (set-foreground-color "white")
     (set-background-color "darkblue")

     ;;; Asigna colores para isearch y drag
     (set-face-foreground 'highlight "white")
     (set-face-background 'highlight "blue")

     (set-face-foreground 'region "cyan")
     (set-face-background 'region "blue")

     (set-face-foreground 'secondary-selection "skyblue")
     (set-face-background 'secondary-selection "darkblue")

     ;; Asigna colores al calendario
     (setq calendar-load-hook
           '(lambda ()
              (set-face-foreground 'diary-face   "skyblue")
              (set-face-background 'holiday-face "slate blue")
              (set-face-foreground 'holiday-face "white")))

   Las varias sombras de azul disparan mi ojo y me preveen de ver la
ventana desplegada.

   Alternativamente, se podrían haber configurado mis especificaciones
en varios ficheros inicialización de X. Por ejemplo, se podría asignar
el foreground, background, cursor y puntero (por ej., ratón) colores en
mi fichero ‘~/.Xresources’ como esto:

     Emacs*foreground:   white
     Emacs*background:   darkblue
     Emacs*cursorColor:  white
     Emacs*pointerColor: white

   En cualquier evento que no es parte de Emacs, se asigna el color raíz
de mi ventana X en mi fichero ‘~/.xinitrc’, como este(1)

     xsetroot -solid Navy -fg white &

   ---------- Footnotes ----------

   (1) también se ejecutan gestores de ventanas más modernos, tales como
Enlightenment, Gnome, o KDE; en estos casos, con frecuencia se
especifica una imagen en vez de un color plano.


File: emacs-lisp-intro-es.info,  Node: Miscelánea,  Next: Mode Line,  Prev: Colores X11,  Up: Inicialización de Emacs

16.13 Configuraciones misceláneas para un fichero ‘.emacs’
==========================================================

Aquí hay unas pocas configuraciones misceláneas:

   − Asigna la forma y color del ratón del cursor:

          ; Formas de Cursor están definidas en
          ; `/usr/include/X11/cursorfont.h';
          ; por ejemplo, el cursor `objetivo' es número 128;
          ; el cursor `top_left_arrow' es el número 132.

          (let ((mpointer (x-get-resource "*mpointer"
                                          "*emacs*mpointer")))
            ;; Si no se ha asignado tu puntero de ratón
            ;; entonces asignalo, de otro modo, déjalo así:
            (if (eq mpointer nil)
                (setq mpointer "132")) ; top_left_arrow
            (setq x-pointer-shape (string-to-int mpointer))
            (set-mouse-color "white"))

   − O se pueden asignar los valores de una variedad de funcionalidades
     en una alist, como esta:

          (setq-default
           default-frame-alist
           '((cursor-color . "white")
             (mouse-color . "white")
             (foreground-color . "white")
             (background-color . "DodgerBlue4")
             ;; (cursor-type . bar)
             (cursor-type . box)
             (tool-bar-lines . 0)
             (menu-bar-lines . 1)
             (width . 80)
             (height . 58)
             (font .
                   "-Misc-Fixed-Medium-R-Normal--20-200-75-75-C-100-ISO8859-1")
             ))

   − Convierte ‘<CTRL>-h’ dentro <DEL> y <DEL> dentro de ‘<CTRL>-h’.
     (Algunos viejos teclados lo necesitan, aunque yo no he visto el
     problema recientemente.)

          ;; Traducir `C-h' a <DEL>.
          ; (keyboard-translate ?\C-h ?\C-?)

          ;; Traducir <DEL> a `C-h'.
          (keyboard-translate ?\C-? ?\C-h)

   − ¡Desactiva un cursor oculto!

          (if (fboundp 'blink-cursor-mode)
              (blink-cursor-mode -1))

     o empieza GNU Emacs con el comando ‘emacs -nbc’.

   − Cuando se usa 'grep'
     ‘-i’  Ignore distinciones de letras
     ‘-n’  El prefijo de cada línea de la salida con el número de líneas
     ‘-H’  Imprime el nombre de fichero para cada cadena encontrada.
     ‘-e’  Protege patrones empezando con un caracter de guión, ‘-’

          (setq grep-command "grep -i -nH -e ")

   − Encuentra un búffer existente, incluso si eso tiene un nombre
     diferente
     Esto evita problemas con enlaces simbólicos.

          (setq find-file-existing-other-name t)

   − Configura tu entorno de lenguaje y el método de entrada por defecto

          (set-language-environment "latin-1")
          ;; Recuerda que se puede habilitar o deshabilitar el texto de lenguaje
          ;; multilingüe con el comando toggle-input-method' (C-\)
          (setq default-input-method "latin-1-prefix")

     Si se quiere escribir con el caracter Chino 'GB', asigna esto:

          (set-language-environment "Chinese-GB")
          (setq default-input-method "chinese-tonepy")

Arreglando Atajos de Teclados
.............................

Algunos sistemas asocian teclas de maneras no agradables.  Algunas
veces, por ejemplo, la tecla <CTRL> en un modo perverso en vez de la
lejanía a la izquierda de la fila.

   Normalmente, cuando las personas arreglan estos atajos de teclado, no
se cambia su fichero ‘~/.emacs’.  En vez de eso, se asocian las teclas
apropiadas en sus consolas con los comandos ‘loadkeys’ o
‘install-keymap’ en su script de inicio y entonces incluyen comandos
‘xmodmap’ en su fichero ‘.xinitrc’ o ‘.Xsession’ para X Windows.

Para un script de inicio:

     loadkeys /usr/share/keymaps/i386/qwerty/emacs2.kmap.gz
or
     install-keymap emacs2

Para un fichero ‘.xinitrc’ o un fichero ‘.Xsession’ cuando la tecla
<Caps Lock> es que tan lejos de la fila del home:

     # Asocia la tecla etiquetada `Caps Lock' a `Control'
     # (Tal como un interfaz de usuario roto sugiere que el teclado hecho
     # piensa que los ordenadores son máquinas de escribir desde 1885.)

     xmodmap -e "clear Lock"
     xmodmap -e "add Control = Caps_Lock"

En un ‘.xinitrc’ o ‘.Xsession’, para convertir una tecla <ALT> a una
tecla <META>:

     # Algunos teclados mal diseñados tienen una tecla etiquetada ALT y no Meta
     xmodmap -e "keysym Alt_L = Meta_L Alt_L"


File: emacs-lisp-intro-es.info,  Node: Mode Line,  Prev: Miscelánea,  Up: Inicialización de Emacs

16.14 Una línea modificada
==========================

Finalmente, una funcionalidad que realmente me gusta: un mode line
modificado.

   Cuando se trabaja a través de una red, se olvida que máquina se está
usando.  También, se tiende a perder la traza de donde se está, y a qué
línea se apunta.

   Así se resetea mi mode line para que se parezca a esto:

     -:-- foo.texi   rattlesnake:/home/bob/  Line 1  (Texinfo Fill) Top

   Estoy visitando un fichero llamado ‘foo.texi’, en mi máquina
‘rattlesnake’ en mi búffer ‘/home/bob’.  Yo estoy en la línea 1, en modo
Texinfo, y estoy arriba del búffer.

   Mi fichero ‘.emacs’ tiene una sección que se parece a esto:

     ;; Asigna un Mode Line que nos cuente que máquina, que directorio,
     ;; y que línea estoy on, más la información de client.
     (setq-default mode-line-format
      (quote
       (#("-" 0 1
          (help-echo
           "mouse-1: select window, mouse-2: delete others ..."))
        mode-line-mule-info
        mode-line-modified
        mode-line-frame-identification
        "    "
        mode-line-buffer-identification
        "    "
        (:eval (substring
                (system-name) 0 (string-match "\\..+" (system-name))))
        ":"
        default-directory
        #(" " 0 1
          (help-echo
           "mouse-1: select window, mouse-2: delete others ..."))
        (line-number-mode " Line %l ")
        global-mode-string
        #("   %[(" 0 6
          (help-echo
           "mouse-1: select window, mouse-2: delete others ..."))
        (:eval (mode-line-mode-name))
        mode-line-process
        minor-mode-alist
        #("%n" 0 2 (help-echo "mouse-2: widen" local-map (keymap ...)))
        ")%] "
        (-3 . "%P")
        ;;   "-%-"
        )))

Aquí, se redefine el mode line por defecto.  La mayoría de las partes
son desde el original; pero yo creo unos pocos cambios.  Yo asigno el
formato de mode line _default_ así como permitir varios modos, tales
como Info, para sobreescribirlo.

   Muchos elementos en la lista son auto-explicativos:
‘mode-line-modified’ es una variable que cuenta si el búffer ha sido
modificado, ‘mode-name’ cuenta el nombre del modo, y así.  Sin embargo,
el formato parece complicado porque las dos funcionalidades no han sido
discutidas.

   The first string in the mode line is a dash or hyphen, ‘-’.  In the
old days, it would have been specified simply as ‘"-"’.  But nowadays,
Emacs can add properties to a string, such as highlighting or, as in
this case, a help feature.  If you place your mouse cursor over the
hyphen, some help information appears (By default, you must wait
seven-tenths of a second before the information appears.  You can change
that timing by changing the value of ‘tooltip-delay’.)

   La nueva cadena de formato tiene una sintaxis especial:

     #("-" 0 1 (help-echo "mouse-1: select window, ..."))

El ‘#(’ empieza una lista.  El primer elemento de la lista es la cadena
en sí, solo un ‘-’.  El segundo y tercer elemento especifica el rango a
través del cuarto elemento aplicado.  Un rango empieza _después_ un
carácter, así un cero significa el rango que empieza solo después del
primer caracter; un 1 significa que el rango finaliza solo después del
primer caracter.  El tercer elemento es la propiedad para el rango.  Eso
consiste en una lista de propiedades, un nombre de propiedad, en este
caso, ‘help-echo’, seguido por un valor, en este caso, una cadena.  El
segundo, tercer y cuarto elemento de este nuevo formato de cadena puede
ser repetido.

   *Note Propiedades de Texto: (elisp)Propiedades de Texto, y ver *note
Formato Mode Line: (elisp)Formato Mode Line, para más información.

   ‘mode-line-buffer-identification’ muestra el nombre del buffer.  Eso
es una lista empezando por ‘(#("%12b" 0 4 ...’.  El ‘#(’ empieza la
lista.

   El ‘"%12b"’ muestra el nombre del actual búffer, usando la función
‘buffer-name’ con la que estamos familiarizados; el '12' especifica el
número máximo de caracteres que serán mostrados.  Cuando un nombre tiene
pocos caracteres, el espacio en blanco se añade para rellenar este
número.  (Los nombres del búffer puede y con frecuencia serán más largos
de 12 caracteres; esta longitud funciona bien en la típica ventana de 80
columnas de ancho.)

   ‘:eval’ dice evaluar la siguiente forma y usa el resultado como una
cadena para mostrarse.  En este caso, la expresión muestra el primer
componente del sistema completo.  El fin del primer componente es un ‘.’
('periodo'), así se usa la función ‘string-match’ para contar el tamaño
del primer componente.  La subcadena desde el caracter cero a este
tamaño del primer componente.  La subcadena desde el caracter cero a
este tamaño es el nombre de la máquina.

   Esta es la expresión:

     (:eval (substring
             (system-name) 0 (string-match "\\..+" (system-name))))

   ‘%[’ y ‘%]’ causa un par de corchetes que aparezcan por cada edición
nivel de edición recursiva editando el nivel.  ‘%n’ dice 'Encoger'
cuando esto puede hacerse.  ‘%P’ te cuenta el porcentaje del búffer que
está debajo de la ventana, o 'arriba', 'abajo', o 'todo'.  (Una
minúscula ‘p’ cuenta el porcentaje bajo el alto de la ventana.)  ‘%-’
inserta suficientes guiones para rellenar la línea.

   Recuerda, "No tiene que gustarte Emacs para que le gustes" -- Emacs
puede tener diferentes colores, diferentes comandos, y diferentes teclas
que un Emacs por defecto.

   Por otro lado, si se quiere traer un plano 'fuera de la caja' Emacs,
sin personalización, escribe:

     emacs -q

Esto inicializará un Emacs que _no_ cargue tu ‘~/.emacs’ fichero de
inicialización.  Uno plano, el que trae Emacs por defecto.  Nada más.


File: emacs-lisp-intro-es.info,  Node: Depurando,  Next: Conclusión,  Prev: Inicialización de Emacs,  Up: Top

17 Depurando
************

GNU Emacs tiene dos depuradores, ‘debug’ y ‘edebug’.  El primero es
construido dentro de las tripas de Emacs y está siempre contigo; el
segundo requiere que exista una función antes de que se pueda usar.

   Ambos depuradores son descritos extensivamente en *note Depurando
Programas Lisp: (elisp)Depurando.  En este capítulo, se explicará un
breve ejemplo de esto.

* Menu:

* depurar::                  Cómo usar el depurador construido.
* debug-on-entry::           Empezar depurando cuando se llama a una
                               función.
* debug-on-quit::            Empezar depurando cuando se sale con ‘C-g’.
* edebug::                   Cómo usar Edebug, un depurador a nivel de
                               fuentes.
* Ejercicios de depuración::  Ejercicios de depuración


File: emacs-lisp-intro-es.info,  Node: depurar,  Next: debug-on-entry,  Up: Depurando

17.1 ‘depurar’
==============

Supón que se ha escrito una definición de función que se pretende
devolver la suma de los números 1 a través de un número dado.  (Esta es
la función ‘triangle’ discutida pronto.  *Note Ejemplo con Contador de
Decremento: Ejemplo de Decremento, para una discusión.)

   Sin embargo, tu definición de función tiene un error.  Se ha
malescrito ‘1=’ por ‘1-’.  Aquí está la definición rota:

     (defun triangle-bugged (number)
       "Devuelve suma de números 1 a través de NUMBER inclusive."
       (let ((total 0))
         (while (> number 0)
           (setq total (+ total number))
           (setq number (1= number)))      ; Error aquí.
         total))

   Si se está leyendo esto en Info, se puede evaluar esta definición en
el modo normal.  Se verá que ‘triangle-bugged’ aparece en el área echo.

   Ahora evalúa la función ‘triangle-bugged’ con un argumento de 4:

     (triangle-bugged 4)

En un GNU Emacs reciente, se creará e introducirá un búffer
‘*Backtrace*’ que dice:

     ---------- Buffer: *Backtrace* ----------
     Debugger entered--Lisp error: (void-function 1=)
       (1= number)
       (setq number (1= number))
       (while (> number 0) (setq total (+ total number))
             (setq number (1= number)))
       (let ((total 0)) (while (> number 0) (setq total ...)
         (setq number ...)) total)
       triangle-bugged(4)
       eval((triangle-bugged 4))
       eval-last-sexp-1(nil)
       eval-last-sexp(nil)
       call-interactively(eval-last-sexp)
     ---------- Buffer: *Backtrace* ----------

(Se ha reformateado este ejemplo ligeramente; el depurador no contiene
muchas líneas.  Así, se puede salir del depurador escribiendo ‘q’ en el
buffer ‘*Backtrace*’.)

   En la práctica, debido a un error tan simple como este, la línea de
'error Lisp' explica lo que se necesita saber para corregir la
definición.  La función ‘1=’ está 'vacía'.

   Sin embargo, si no se conoce con bastante certeza lo que está
pasando, se puede leer la traza completa.

   En este caso, se necesita ejecutar una versión reciente de GNU Emacs,
que automáticamente empieza el depurador que pone en el búffer
‘*Backtrace*’; o además, se necesita para empezar el depurador
manualmente como se describe debajo.

   Lee el búffer ‘*Backtrace*’ de abajo a arriba; eso cuenta lo que le
hizo a Emacs tener un error.  Emacs hace una llamada interactiva a ‘C-x
C-e’ (‘eval-last-sexp’), que lleva a la evaluación de la expresión
‘triangle-bugged’.  Cada línea de debajo cuenta lo que el intérprete
Lisp evaluó.

   La tercera línea desde lo alto del búffer es

     (setq number (1= number))

Emacs intentó evaluar esta expresión; para hacerlo así, se intentó
evaluar la expresión interna para ser mostrada en la segunda línea desde
arriba:

     (1= number)

Aquí es donde el error ocurre; como se dice en la línea de arriba:

     Debugger entered--Lisp error: (void-function 1=)

Se puede corregir el error, reevalúa la definición de función, y
entonces se puede testear de nuevo.


File: emacs-lisp-intro-es.info,  Node: debug-on-entry,  Next: debug-on-quit,  Prev: depurar,  Up: Depurando

17.2 ‘debug-on-entry’
=====================

Un GNU Emacs actual abre el depurador automáticamente cuando la función
tiene un error.

   Incidentalmente, se puede empezar el depurador manualmente para todas
las versiones de Emacs; la ventaja es que el depurador se ejecuta
incluso si no se tiene un error en su código.  Algunas veces, ¡su código
estará libre de errores!

   Se puede introducir el depurador cuando se llama a la función
llamando ‘debug-on-entry’.

Tipo:

     M-x debug-on-entry RET triangle-bugged RET

Ahora, evalúa lo siguiente:

     (triangle-bugged 5)

Todas las versiones de Emacs crearán un búffer ‘*Backtrace*’ y cuenta tu
que eso es el principio para evaluar la función ‘triangle-bugged’:

     ---------- Buffer: *Backtrace* ----------
     Debugger entered--entering a function:
     * triangle-bugged(5)
       eval((triangle-bugged 5))
       eval-last-sexp-1(nil)
       eval-last-sexp(nil)
       call-interactively(eval-last-sexp)
     ---------- Buffer: *Backtrace* ----------

   En el búffer ‘*Backtrace*’, escribe ‘d’.  Emacs evaluará la primera
expresión en ‘triangle-bugged’; el búffer se parece a esto:

     ---------- Buffer: *Backtrace* ----------
     Debugger entered--beginning evaluation of function call form:
     * (let ((total 0)) (while (> number 0) (setq total ...)
             (setq number ...)) total)
     * triangle-bugged(5)
       eval((triangle-bugged 5))
       eval-last-sexp-1(nil)
       eval-last-sexp(nil)
       call-interactively(eval-last-sexp)
     ---------- Buffer: *Backtrace* ----------

Ahora, escribe ‘d’ de nuevo, ocho veces, lentamente.  Cada vez que se
escribe ‘d’ Emacs evaluará otra expresión en la definición de función.

   Eventualmente, el búffer se parece a esto:

     ---------- Buffer: *Backtrace* ----------
     Debugger entered--beginning evaluation of function call form:
     * (setq number (1= number))
     * (while (> number 0) (setq total (+ total number))
             (setq number (1= number)))
     * (let ((total 0)) (while (> number 0) (setq total ...)
             (setq number ...)) total)
     * triangle-bugged(5)
       eval((triangle-bugged 5))
       eval-last-sexp-1(nil)
       eval-last-sexp(nil)
       call-interactively(eval-last-sexp)
     ---------- Buffer: *Backtrace* ----------

Finalmente, después se escribe ‘d’ dos veces más, Emacs logrará el error
y las dos líneas superiores del buffer ‘*Backtrace*’ se ve así:

     ---------- Buffer: *Backtrace* ----------
     Debugger entered--Lisp error: (void-function 1=)
     * (1= number)
     ...
     ---------- Buffer: *Backtrace* ----------

   Escribiendo ‘d’, sería capaz de pasear a través de la función.

   Se puede salir de un buffer ‘*Backtrace*’ escribiendo ‘q’; esto se
sale de la traza, pero no cancela ‘debug-on-entry’.

   Para cancelar el efecto de ‘debug-on-entry’, llama a
‘cancel-debug-on-entry’ y el nombre de la función, como esto:

     M-x cancel-debug-on-entry RET triangle-bugged RET

(Si está leyendo esto en Info, cancela ‘debug-on-entry’ ahora.)


File: emacs-lisp-intro-es.info,  Node: debug-on-quit,  Next: edebug,  Prev: debug-on-entry,  Up: Depurando

17.3 ‘debug-on-quit’ y ‘(debug)’
================================

Adición a la configuración ‘debug-on-error’ o llamando ‘debug-on-entry’,
hay otros dos caminos para empezar ‘debug’.

   Se puede empezar ‘debug’ siempre y cuando se escribe ‘C-g’
(‘keyboard-quit’) se configura la variable ‘debug-on-quit’ para ‘t’.
Esto es útil para depurar bucles infinitos.

   O, se puede insertar un línea que dice ‘(debug)’ dentro de tu código
donde se quiere que el depurador empiece, así:

     (defun triangle-bugged (number)
       "Devuelve suma de números 1 a través de NUMERO inclusive."
       (let ((total 0))
         (while (> number 0)
           (setq total (+ total number))
           (debug)                         ; Empieza el depurador.
           (setq number (1= number)))      ; Error aquí.
         total))

   La función ‘debug’ se describe en detalle en *note El Depurador Lisp:
(elisp)Depurador.


File: emacs-lisp-intro-es.info,  Node: edebug,  Next: Ejercicios de depuración,  Prev: debug-on-quit,  Up: Depurando

17.4 El depurador de nivel de fuentes ‘edebug’
==============================================

Edebug es un depurador a nivel de fuentes Edebug que normalmente muestra
las fuentes del código que se está depurando, con una flecha a la
izquierda que muestra que línea se está actualmente ejecutando.

   Se puede pasear a través de la ejecución de una función, línea a
línea, o ejecutarse rápidamente hasta lograr un “punto de ruptura” donde
la ejecución pare.

   Edebug se describe en *note Edebug: (elisp)edebug.

   Aquí hay una función con errores para ‘triangle-recursively’.  *Note
Recursión en lugar de un contador: Función recursiva triángulo, para una
revisión de eso.

     (defun triangle-recursively-bugged (number)
       "Devuelve la suma of números 1 a través de NUMBER inclusive.
     Usa recursión."
       (if (= number 1)
           1
         (+ number
            (triangle-recursively-bugged
             (1= number)))))               ; Error aquí.

Normalmente, se instalaría esta definición posicionando su cursor
después de la función cerrando paréntesis y escribiendo ‘C-x C-e’
(‘eval-last-sexp’) o lo demás posicionando tu cursor con la definición y
escribiendo ‘C-M-x’ (‘eval-defun’).  (Por defecto, el comando
‘eval-defun’ funciona solo en modo Emacs Lisp o en el modo de
interacción de Lisp.)

   Sin embargo, para preparar esta definición de función para Edebug, se
debe primero “instrumentar” el código usando un comando diferente.  Se
puede hacer esto posicionando el cursor dentro o después de la
definición y escribiendo

     M-x edebug-defun RET

Esto causará que Emacs cargue Edebug automáticamente si eso no está ya
cargado y, apropiadamente prepara la función.

   Después de preparar la función, emplaza tu cursor después de la
siguiente expresión y escribe ‘C-x C-e’ (‘eval-last-sexp’):

     (triangle-recursively-bugged 3)

Se vuelve a las fuentes de ‘triangle-recursively-bugged’ y el cursor se
posiciona al principio del ‘if’ de la línea de la función.  También, se
verá una flecha en la mano izquierda al lado de esta línea donde la
función se está ejecutando.  (En los siguientes ejemplos, se muestra la
flecha con ‘=>’; en un sistema de ventanas, se puede ver la flecha como
un triángulo sólido en el 'borde' de la ventana.)

     =>⋆(if (= number 1)

En el ejemplo, la localización del punto es mostrado como ‘⋆’ (en un
libro impreso, eso es mostrado con una estrella apuntada).

   Si ahora se presiona <SPC>, el punto se moverá a la siguiente
expresión para ejecutarse; la línea se parece a esto:

     =>(if ⋆(= number 1)

Como se continua presionando <SPC>, el puntero se moverá desde la
expresión a la expresión.  Al mismo tiempo, siempre y cuando una
expresión devuelva un valor, este valor será mostrado en el área echo.
Por ejemplo, después de mover el punto pasado ‘number’, se verá lo
siguiente:

     Resultado: 3 (#o3, #x3, ?\C-c)

Esto significa el valor de ‘number’ es 3, que son tres octales, tres
hexadecimales, y ASCII 'control-c' (la tercera letra del alfabeto, en
caso de que se necesite conocer esta información).

   Uno puede continuar moviéndose a través del código hasta que logre la
línea con el error.  Antes de la evaluación, esta línea se parece a
esto:

     =>        ⋆(1= number)))))               ; Error aquí.

Cuando se presiona <SPC> una vez de nuevo, se producirá un mensaje de
error que dice:

     La definición de la función está vacío: 1=

Este es el error.

   Presiona ‘q’ para salir de Edebug.

   Para eliminar la instrumentación desde una definición de función,
simplemente se reevalúa con un comando que no lo instrumente.  Por
ejemplo, se podría posicionar su cursor después de la definición
cerrando paréntesis y escribiendo ‘C-x C-e’.

   Edebug hace un gran trato antes de entrar en una función.  Se puede
dirigir así mismo, parando solo en un error o en puntos específicos, se
puede causar para mostrar los valores cambiantes de varias expresiones;
se puede encontrar cuantas veces una función se llama, y más.

   Edebug se describe en *note Edebug: (elisp)edebug.


File: emacs-lisp-intro-es.info,  Node: Ejercicios de depuración,  Prev: edebug,  Up: Depurando

17.5 Ejercicios de depuración
=============================

   • Instale la función ‘count-words-example’ y provoque que se
     introduzca el depurador construido cuando se llame.  Ejecute el
     comando en una región conteniendo dos palabras.  Se necesitará
     presionar ‘d’ un número remarcable de veces.  En el sistema, es un
     'hook' llamado después que el comando se finaliza.  (Para
     información sobre hooks, mira *note Resumen del Comando Bucle:
     (elisp)Resumen de Comandos.)

   • Copie ‘count-words-example’ dentro del búffer ‘*scratch*’,
     instrumente la función para Edebug, y navegue a través de su
     ejecución.  La función no necesita tener un error, aunque se puede
     introducir uno si se desea.  Si a la función le falta un error, el
     paseo se completa sin problemas.

   • Mientras se ejecuta Edebug, escriba ‘?’ para ver una lista de todos
     los comandos Edebug.  (El ‘global-edebug-prefix’ normalmente es
     ‘C-x X’, por ej ‘<CTRL>-x’ seguido por una tecla mayúscula ‘X’; use
     este prefijo para comandos hechos fuera del búffer de depuración
     Edebug.)

   • En el búffer de depuración Edebug, usa el comando ‘p’
     (‘edebug-bounce-point’) para ver si ‘count-words-example’ está
     funcionando.

   • Mueve el punto a algún sitio debajo de la función y entonces
     escribe el comando ‘h’ (‘edebug-goto-here’) para saltar a esta
     localización.

   • Usa el comando ‘t’ (‘edebug-trace-mode’) para causar que Edebug
     pasee a través de la función en sí; usa una letra mayúscula ‘T’
     para ‘edebug-Trace-fast-mode’.

   • Asigna un punto de ruptura, entonces ejecuta Edebug en modo Traza
     hasta que se logre el punto de parada.


File: emacs-lisp-intro-es.info,  Node: Conclusión,  Next: the-the,  Prev: Depurando,  Up: Top

18 Conclusión
*************

Ahora se ha llegado al fin de esta Introducción.  Se ha aprendido lo
suficiente acerca de programación en Emacs Lisp para asignar valores,
para escribir ficheros ‘.emacs’ para tí mismo y tus amigos, y escribir
personalizaciones simples y extensiones a Emacs.

   Este es un lugar para parar.  O, si se desea, se puede ir adelante, y
aprender más por uno mismo.

   Se han aprendido algunas bases de programación.  Pero solo algunas.
Todavía hay muchas cosas que son fáciles de usar que no se han tocado.

   Otra idea para seguir es leer las fuentes de Emacs o *note El Manual
de Referencia de GNU Emacs Lisp: (El Manual de Referencia de GNU Emacs
Lisp)Arriba.

   Las fuentes de Emacs Lisp son una aventura.  Cuando se leen las
fuentes vienen a través de una función o expresión que nos es familiar,
se necesita imaginar o encontrar qué se hace.

   Ir al Manual de Referencia.  Eso está a través del completo, limpio y
fácil de leer descripción de Emacs Lisp.  Está escrito no solo para
expertos, pero sí para gente que conoce lo que usted conoce.  (El
‘Manual de Referencia’ viene con la distribución de GNU Emacs.  Como
esta introducción, viene como un fichero fuente Texinfo, así se puede
leer on-line como un libro impreso.)

   Ir a otra ayuda on-line que sea parte de GNU Emacs: la documentación
on-line para todas las funciones y variables, y ‘find-tag’, el programa
que va a las fuentes.

   Aquí hay un ejemplo de cómo explorar las fuentes.  Porque su nombre,
‘simple.el’ es el fichero que se vió primero, hace tiempo.  Como eso
ocurre alguna de las funciones en ‘simple.el’ son complicadas, o al
menos parece complicado a primera vista.  La función ‘open-line’, por
ejemplo, parece complicada.

   Se puede querer pasear a través de esta función lentamente, como
nosotros hicimos la función ‘forward-sentence’.  (*Note La función
‘forward-sentence’: forward-sentence.)  O se puede querer salir de esta
función y mirar en otra, tal como ‘split-line’.  No se necesita leer
todas las funciones.  De acuerdo a ‘count-words-in-defun’, la función
‘split-line’ contiene 102 palabras y símbolos.

   Incluso aunque sean pocas, ‘split-line’ contiene expresiones que no
se han estudiado: ‘skip-chars-forward’, ‘indent-to’, ‘current-column’ y
‘insert-and-inherit’.

   Considera la función ‘skip-chars-forward’.  (Eso es parte de la
definición de función para ‘back-to-indentation’, que muestra la *note
Revisar: Revisar.)

   En GNU Emacs, se puede encontrar más acerca de ‘skip-chars-forward’
escribiendo ‘C-h f’ (‘describe-function’) y el nombre de la función.
Esto te da la documentación de función.

   Se puede ser capaz de adivinar que se hace por una función bien
llamada tal como ‘indent-to’; o se puede buscar, también.
Incidentalmente, la función ‘describe-function’ en sí está en ‘help.el’;
esta es una de estas largas, pero descifrables funciones.  ¡Se puede
buscar ‘describe-function’ usando el comando ‘C-h f’!

   En esta instancia, desde el código es Lisp, el búffer ‘*Help*’
contiene el nombre de la librería conteniendo las fuentes de la función.
Se puede poner el punto a través del nombre de la librería y presiona la
tecla RET, que está en esta situación está asociado a ‘help-follow’, y
se toma directamente de las fuentes, en el mismo camino que ‘M-.’
(‘find-tag’).

   La definición para ‘describe-function’ ilustra como personalizar las
expresiones ‘interactive’ sin usar los códigos de caracter estándar y
eso muestra como crear un búffer temporal.

   (La función ‘indent-to’ es escrita en C en vez de Emacs Lisp; eso es
una función 'construida'.  ‘help-follow’ toma su fuente como ‘find-tag’,
cuando se configura apropiadamente.)

   Se puede mirar en las fuentes de la función usando ‘find-tag’, que
está asociado a ‘M-.’.  Finalmente, se puede encontrar que el Manual de
Referencia tiene que decir visitando el manual en Info, y escribiendo
‘i’ (‘Info-index’) y el nombre de la función, o buscando la función en
el índice a una copia impresa del manual.

   Similarmente, se puede encontrar que significa por
‘insert-and-inherit’.

   Otros ficheros fuente interesantes incluyen ‘paragraphs.el’,
‘loaddefs.el’ y ‘loadup.el’.  El fichero ‘paragraphs.el’ incluye
ordenar, funciones fácilmente comprendidas tan bien como las largas.  El
fichero ‘loaddefs.el’ contiene muchos autoloads estándar y muchos mapas
de teclado.  Nunca se ha buscado en todo; solo en las partes.
‘loadup.el’ es el fichero que carga las partes estándar de Emacs; eso
cuenta un gran trato acerca de cómo Emacs está construido.  (*Note
Construyendo Emacs: (elisp)Construyendo Emacs, para más acerca de
construcción.)

   Como dije, se han aprendido algunas cosas; sin embargo, y de manera
muy importante, se han tocado fuertes aspectos de la programación; no se
ha dicho nada acerca de como ordenar la información, excepto para usar
la función predefinida ‘sort’; no se ha dicho nada acerca de cómo
almacenar la información, excepto para usar variables y listas; no se ha
dicho nada acerca de como escribir programas que escriben programas.
Esto son asuntos para otro tipo diferente de libro, un diferente tipo de
aprendizaje.

   Lo que se ha hecho es aprender lo suficiente para hacer mucho trabajo
práctico con GNU Emacs.  Lo que se ha hecho es comenzar.  Este es el fin
del principio de una gran amistad.


File: emacs-lisp-intro-es.info,  Node: the-the,  Next: Kill Ring,  Prev: Conclusión,  Up: Top

Apéndice A La función ‘the-the’
*******************************

Algunas veces cuando se se escribe texto, se duplican palabras -- como
con "se se" cerca del principio de esta frase.  Se encuentra que lo más
frecuente, es duplicar "el"; aquí, se llama a la función para detectar
las palabras duplicadas, ‘the-the’.

   Como primer paso, se podrían usar las siguientes expresiones
regulares para buscar duplicados:

     \\(\\w+[ \t\n]+\\)\\1

Este regexp asocia uno o más caracteres que constituyen palabras
seguidas por uno o más espacios, tabuladores, o nuevas líneas.  Sin
embargo, eso no detecta palabras duplicadas en diferentes líneas, desde
la finalización de la primera palabra, el fin de la línea, es diferente
desde el fin de la segunda palabra, un espacio.  (Para más información
acerca de expresiones regulares, mira el *note Búsquedas de Expresiones
Regulares: Buscar regexp, tan bien como la *note Sintaxis de Expresiones
Regulares: (emacs)Regexps, y la *note Expresiones Regulares:
(elisp)Expresiones Regulares.)

   Se podrían intentar buscar caracteres duplicados pero no si el patrón
detecta dobles tales como las dos ocurrencias de 'th' en 'with the'.

   Otro posible regexp busca caracteres constituyentes de palabras
seguidos por caracteres de no palabras constituyentes, reduplicadas.
Aquí, ‘\\w+’ asocia a una o más caracteres de palabras constituyente y
‘\\W*’ asocia cero o más caracteres que no constituyen palabras.

     \\(\\(\\w+\\)\\W*\\)\\1

De nuevo, no útil.

   Aquí está el patrón que uso.  No es perfecto, pero suficientemente
bueno.  ‘\\b’ asocia la cadena vacía provista al principio o fin de una
palabra; ‘[^@ \n\t]+’ asocia una o más ocurrencias de qué caracteres que
_no_ son un @-signo, espacio, nueva línea, o tabulador.

     \\b\\([^@ \n\t]+\\)[ \n\t]+\\1\\b

   Uno puede escribir expresiones más complicadas, pero esta expresión
es suficientemente buena así.

   Aquí está la función ‘the-the’, como se incluye en mi fichero
‘.emacs’, a lo largo de un atajo global manejable:

     (defun the-the ()
       "Busca hacia adelante para una palabra duplicada."
       (interactive)
       (message "Buscando palabras duplicadas ...")
       (push-mark)
       ;; Este regexp no es perfecto
       ;; pero es limpiamente bueno a pesar de todo:
       (if (re-search-forward
            "\\b\\([^@ \n\t]+\\)[ \n\t]+\\1\\b" nil 'move)
           (message "Palabra encontrada duplicada.")
         (message "Fin de búffer")))

     ;; Asocia `the-the' a  C-c \
     (global-set-key "\C-c\\" 'the-the)


   Aquí está el test del texto:

     uno dos tres cuatro cinco
     cinco seis siete

   Se pueden sustituir las otras expresiones regulares mostradas debajo
en la definición de función y se prueba cada una de ellas en esta lista.


File: emacs-lisp-intro-es.info,  Node: Kill Ring,  Next: Grafo completo,  Prev: the-the,  Up: Top

Apéndice B Manejando el anillo de la muerte
*******************************************

El anillo de la muerte es una lista que es transformada dentro de un
anillo que trabaja con la función ‘current-kill’.  Los comandos ‘yank’ y
‘yank-pop’ usan la función ‘current-kill’.

   Este apéndice describe la función ‘current-kill’ y los comandos
‘yank’ y ‘yank-pop’, pero primero, considere los trabajo del kill ring.

* Menu:

* Qué hace el anillo de la muerte::  Qué hace el anillo de la muerte
* current-kill::             current-kill
* pegar::                    Pegar una copia de un elemento ya cortado.
* yank-pop::                 Insertar elemento apuntado.
* fichero anillo::           fichero anillo


File: emacs-lisp-intro-es.info,  Node: Qué hace el anillo de la muerte,  Next: current-kill,  Up: Kill Ring

Qué hace el anillo de la muerte
===============================

El anillo de la muerte _kill ring_ tiene el tamaño máximo de sesenta
elementos; hacer una explicación con este número máximo quedaría
demasiado larga.  En vez de eso, pensemos qué ocurre si se asígna a
cuatro.  Por favor, evalúe lo siguiente:

     (setq old-kill-ring-max kill-ring-max)
     (setq kill-ring-max 4)

Entonces, por favor, copie cada línea del siguiente ejemplo indentado
dentro del anillo de la muerte _kill ring_.  Se puede cortar cada línea
con ‘C-k’ o marcarla y copiarla con ‘M-w’.

(En un búffer de solo lectura, tal como el búffer ‘*info*’, el comando
kill, ‘C-k’ (‘kill-line’), no eliminará el texto, solamente lo mueve al
anillo de la muerte _kill ring_.  Sin embargo, el ordenador puede avisar
con un beep.  Alternativamente, para silenciar, se puede copiar la
región de cada línea con el comando ‘M-w’ (‘kill-ring-save’).  Se debe
marcar cada línea de este comando para tener éxito, pero no importa si
al final se posiciona en el punto o la marca).

Por favor, invoque las llamadas en orden, de modo que los cinco
elementos rellenen el anillo de la muerte _kill ring_.

     primero algo de texto
     segunda pieza de texto
     tercera línea
     cuarta línea de texto
     quinto bit de texto

Entonces encuentra el valor de ‘kill-ring’ evaluando

     kill-ring

Eso es:

     ("quinto bit de texto" "cuarta línea de texto"
     "tercera línea" "segunda pieza de texto")

El primer elemento, ‘primero algo de texto’, fué borrado.

   Para devolver el viejo valor para el tamaño del kill ring, evalúe:

     (setq kill-ring-max old-kill-ring-max)


File: emacs-lisp-intro-es.info,  Node: current-kill,  Next: pegar,  Prev: Qué hace el anillo de la muerte,  Up: Kill Ring

B.1 La función ‘current-kill’
=============================

La función ‘current-kill’ cambia el elemento en el anillo de la muerte
_kill ring_ para el que el ‘kill-ring-yank-pointer’ apunta.  (También,
la función ‘kill-new’ asigna ‘kill-ring-yank-pointer’ para apuntar al
último elemento del anillo de la muerte _kill ring_.  La función
‘kill-new’ se usa directamente o indirectamente por ‘kill-append’,
‘copy-region-as-kill’, ‘kill-ring-save’, ‘kill-line’, y ‘kill-region’.)

* Menu:

* Código para current-kill::  Código para current-kill
* Comprendiendo current-kill::  Comprendiendo current-kill


File: emacs-lisp-intro-es.info,  Node: Código para current-kill,  Next: Comprendiendo current-kill,  Up: current-kill

El código ‘current-kill’
------------------------

La función ‘current-kill’ es usada por ‘yank’ y por ‘yank-pop’.  Aquí
está el código para ‘current-kill’:

     (defun current-kill (n &optional do-not-move)
     "Rota el punto de pegue por N lugares, y entonces devuelve lo cortado.
     Si N es cero, `interprogram-paste-function' se asigna, y si se llama
     devuelve una cadena, entonces esta cadena se añade al frente del
     anillo de la muerte _kill ring_ y devuelve el último corte.
     Si el argumento opcional DO-NOT-MOVE es no nulo, entonces no muevas el
     punto de pegue; solo devuelve el Nth corte hacia adelante.
        (let ((interprogram-paste (and (= n 0)
                                       interprogram-paste-function
                                       (funcall interprogram-paste-function)))))
         (if interprogram-paste
             (progn
               ;; Deshabilita el programa de la función de corte cuando se
               ;; añade el nuevo texto al anillo de la muerte _kill ring_,
               ;; así Emacs no intenta poseer la selección
               ;; con idéntico texto.
               (let ((interprogram-cut-function nil))
                 (kill-new interprogram-paste))
               interprogram-paste)
           (or kill-ring (error "Kill ring is empty"))
           (let ((ARGth-kill-element
                  (nthcdr (mod (- n (length kill-ring-yank-pointer))
                               (length kill-ring))
                          kill-ring)))
             (or do-not-move
                 (setq kill-ring-yank-pointer ARGth-kill-element))
             (car ARGth-kill-element)))))

   Recuerde también que la función ‘kill-new’ asigna
‘kill-ring-yank-pointer’ al último elemento del anillo de la muerte
_kill ring_, que significa que todas las funciones lo llaman y asigna el
valor de manera indirecta: ‘kill-append’, ‘copy-region-as-kill’,
‘kill-ring-save’, ‘kill-line’ y ‘kill-region’.

   Aquí está la línea en ‘kill-new’, que se explica en la *note La
función ‘kill-new’: Función kill-new.

     (setq kill-ring-yank-pointer kill-ring)


File: emacs-lisp-intro-es.info,  Node: Comprendiendo current-kill,  Prev: Código para current-kill,  Up: current-kill

‘current-kill’ en outline
-------------------------

La función ‘current-kill’ parece compleja, pero usual, eso puede ser
comprendido tomándolo aparte pieza por pieza.  Primero míralo en la
forma esquelética:

     (defun current-kill (n &optional do-not-move)
       "Rota el punto a pegar por N lugares, y entonces devuelve el texto cortado."
       (let VARLIST
         BODY...)

   Esta función tiene dos argumentos, uno es opcional.  Hay una cadena
de documentación.  _No_ es una función interactiva.

* Menu:

* Cuerpo de current-kill::   Cuerpo de current-kill
* Disgresión concerniente de error::  Cómo confundir humanos, pero no
                                          ordenadores.
* Determinando el elemento::  Determinando el elemento


File: emacs-lisp-intro-es.info,  Node: Cuerpo de current-kill,  Next: Disgresión concerniente de error,  Up: Comprendiendo current-kill

El cuerpo de ‘current-kill’
...........................

El cuerpo de la definición de función es una expresión ‘let’, que por sí
misma tiene tanto un cuerpo como una VARLIST.

   La expresión ‘let’ declara una variable que será solo usable con las
asociaciones de esta función.  Esta variable se llama
‘interprogram-paste’ y se copia a otro programa.  No se copia con esta
instancia de GNU Emacs.  La mayoría de los sistemas de ventanas proveen
una facilidad para pegar el interprograma.  Tristemente, esta facilidad
normalmente provee solo el último elemento.  La mayoría de los sistemas
de ventanas no han adoptado un anillo de muchas posibilidades, incluso
aunque Emacs haya provisto esto durante décadas.

   La expresión ‘if’ tiene dos partes, una si existe
‘interprogram-paste’ y otra si no.

   Permítenos considerar el 'si no' o la parte else de la función
‘current-kill’.  (La parte then usa la función ‘kill-new’, que ya hemos
descrito.  *Note La función ‘kill-new’.: Función kill-new.)

     (or kill-ring (error "El Kill ring está vacío"))
     (let ((ARGth-kill-element
            (nthcdr (mod (- n (length kill-ring-yank-pointer))
                         (length kill-ring))
                    kill-ring)))
       (or do-not-move
           (setq kill-ring-yank-pointer ARGth-kill-element))
       (car ARGth-kill-element))

El código primero chequea si el kill ring _anillo de la muerte_ tiene
contenido; de otro modo señala un error.

   Note que la expresión ‘or’ es muy similar para testear el tamaño con
un ‘if’:

     (if (zerop (length kill-ring))          ; parte-si
         (error "Anillo de la muerte vacío"))       ; parte-entonces
       ;; No hay parte-resto

Si no hay nada en el kill ring _anillo de la muerte_, su tamaño debe ser
cero y un mensaje de error se envía al usuario: ‘El kill ring está
vacío’.  La función ‘current-kill’ usa una expresión ‘or’ que es simple.
Pero una expresión ‘if’ recuerda lo que lleva.

   Esta expresión ‘if’ usa la función ‘zerop’ que devuelve cierto si el
valor que se chequea es cero.  Cuando ‘zerop’ chequea cierto, la parte
then del ‘if’ se evalúa.  La parte then es una lista empezando con la
función ‘error’, que es una función que es similar a la función
‘message’ (*note La Función ‘message’: message.) que imprime un mensaje
de una línea en el área echo.  Sin embargo, además de imprimir un
mensaje, ‘error’ también evalúa la función que está embebida.  Esto
significa que el resto de la función no será evaluada si el tamaño del
anillo de la muerte _kill ring_ es cero.

   Entonces la función ‘current-kill’ selecciona el elemento a devolver.
La selección depende del número de lugares que ‘current-kill’ rota y
donde ‘kill-ring-yank-pointer’ apunta.

   Lo siguiente, si el argumento ‘do-not-move’ opcional es verdadero o
el actual valor de ‘kill-ring-yank-pointer’ se establece al punto de la
lista.  Finalmente, otra expresión devuelve el primer elemento de la
lista incluso si el argumento ‘do-not-move’ es verdadero.


File: emacs-lisp-intro-es.info,  Node: Disgresión concerniente de error,  Next: Determinando el elemento,  Prev: Cuerpo de current-kill,  Up: Comprendiendo current-kill

Disgresión acerca de la palabra 'error'
.......................................

En mi opinión, es ligeramente erróneo, al menos para humanos, usar el
término 'error' como el nombre de la función ‘error’.  Un término mejor
sería 'cancelar'.  Estrictamente hablando, de acuerdo, no se puede
apuntar, mucho menos rotar un puntero a una lista que no tiene tamaño,
así desde el punto de vista del ordenador, la palabra 'error' es
correcta.  Pero un humano espera intentar algo, si solo si se encuentra
el anillo de la muerte _kill ring_ esté lleno o vacío.  Esto es un acto
de exploración.

   Desde el punto de vista humano, el acto de exploración y
descubrimiento no es necesariamente un error, y por esta razón no sería
etiquetado como tal, incluso las vocales de un ordenador.  Como tal, el
código en Emacs implica que un humano que está actuando virtuosamente,
explorando su entorno, está teniendo un error.  Esto está mal.  Incluso
aunque el ordenador tome los mismos pasos como cuando hay 'error', un
término tal como 'cancelar' tendría una clara connotación.


File: emacs-lisp-intro-es.info,  Node: Determinando el elemento,  Prev: Disgresión concerniente de error,  Up: Comprendiendo current-kill

Determinando el elemento
........................

Entre otras acciones, la else-part de la expresión ‘if’ asigna el valor
de ‘kill-ring-yank-pointer’ a ‘ARGth-kill-element’ cuando el kill ring
_anillo de la muerte_ tiene alguna cosa dentro y el valor de
‘do-not-move’ es ‘nil’.

   El código se parece a esto:

     (nthcdr (mod (- n (length kill-ring-yank-pointer))
                  (length kill-ring))
             kill-ring)))

   Esto necesita algún examen.  A menos que no se suponga mover el
puntero, la función ‘current-kill’ cambia donde ‘kill-ring-yank-pointer’
apunta.  Esto es lo que la expresión
‘(setq kill-ring-yank-pointer ARGth-kill-element)’ hace.  También,
claramente, ‘ARGth-kill-element’ está siendo asignado para ser igual a
algún CDR del anillo de la muerte _kill ring_, usando la función
‘nthcdr’ que está descrita en una sección temprana.  (*Note
copy-region-as-kill::.)  ¿Cómo se hace?

   Como se ha visto antes (*note nthcdr::), la función ‘nthcdr’ funciona
repetidamente tomando el CDR de una lista -- eso toma el CDR, del CDR,
del CDR, ...

   Las siguientes dos expresiones producen el mismo resultado:

     (setq kill-ring-yank-pointer (cdr kill-ring))

     (setq kill-ring-yank-pointer (nthcdr 1 kill-ring))

   Sin embargo, la expresión ‘nthcdr’ es más complicada.  Usa la función
‘mod’ para determinar que CDR para seleccionar.

   (Se recordará buscar funciones propias primero, en vez de esto,
tendremos que ir dentro del ‘mod’.)

   La función ‘mod’ devuelve el valor de su primer argumento módulo el
segundo; que es decir, eso devuelve el resto después de dividir el
primer argumento por el segundo.  El valor devuelto tiene el mismo signo
que el segundo argumento.

   De este modo,

     (mod 12 4)
       ⇒ 0  ;; porque no hay resto
     (mod 13 4)
       ⇒ 1

   En este caso, el primer argumento es con frecuencia pequeño que el
segundo.  Que está bien.

     (mod 0 4)
       ⇒ 0
     (mod 1 4)
       ⇒ 1

   Se puede adivinar lo que la función ‘-’ hace.  Eso es como ‘+’ pero
sustrae en vez de añadir; la función ‘-’ sustrae su segundo argumento
desde el primero.  También, ya se sabe que la función ‘length’ hace
(*note length::).  Eso devuelve el tamaño de una lista.

   Y ‘n’ es el nombre del argumento requerido a la función
‘current-kill’.

   Así cuando el primer argumento a ‘nthcdr’ es cero, la expresión
‘nthcdr’ devuelve la lista entera, como se puede ver evaluando lo
siguiente:

     ;; kill-ring-yank-pointer and kill-ring tener un tamaño de cuatro
     ;; and (mod (- 0 4) 4) ⇒ 0
     (nthcdr (mod (- 0 4) 4)
             '("cuarta línea de texto"
               "tercera línea"
               "segunda pieza de texto"
               "primero algo de texto"))

   Cuando el primer argumento a la función ‘current-kill’ es uno, la
expresión ‘nthcdr’ devuelve la lista sin su primer elemento.

     (nthcdr (mod (- 1 4) 4)
             '("cuarta línea de texto"
               "tercera línea"
               "segunda pieza de texto"
               "primero algo de texto"))

   Incidentalmente, tanto ‘kill-ring’ y ‘kill-ring-yank-pointer’ son
“variables globales”.  Esto significa que cualquier expresión en Emacs
Lisp puede acceder a ellas.  Ellas no son como las variables locales
asignadas por ‘let’ o como los símbolos en una lista de argumentos.  Las
variables locales pueden solo ser accedidas con el ‘let’ que los define
o la función que los especifica en una lista de argumentos (y con
expresiones llamadas por ellos).


File: emacs-lisp-intro-es.info,  Node: pegar,  Next: yank-pop,  Prev: current-kill,  Up: Kill Ring

B.2 ‘pegar’
===========

Después de aprender acerca de ‘current-kill’, el código para la función
‘yank’ es casi fácil.

   La función ‘yank’ no usa la variable ‘kill-ring-yank-pointer’
directamente.  Eso llama a ‘insert-for-yank’ que llama a ‘current-kill’
que asigna la variable ‘kill-ring-yank-pointer’.

   El código se parece a esto:

     (defun yank (&optional arg)
       "Reinserta (\"pega\") el último logro del texto cortado.
     Más precisamente, reinserta el texto cortado más recientemente.
     Pon el punto al final, y asigna la marca al principio.
     Solo con \\[universal-argument] como argumento, lo mismo pero pon el
     punto al principio (y la marca al final). Con el argumento N, reinserta
     el N más recientemente cortado.
     Cuando este comando inserta texto cortado dentro del búffer, eso
     honra a `yank-excluded-properties' y `yank-handler' como se describe
     la cadena de documentación para `insert-for-yank-1', que se ve.

     Ver también el comando \\[yank-pop]."
       (interactive "*P")
       (setq yank-window-start (window-start))
       ;; Si no tenemos todo el camino a través, crea last-command que
       ;; indique esto para el siguiente comando.
       (setq this-command t)
       (push-mark (point))
       (insert-for-yank (current-kill (cond
                                       ((listp arg) 0)
                                       ((eq arg '-) -2)
                                       (t (1- arg)))))
       (if (consp arg)
           ;; Esto es como like exchange-point-and-mark,
           ;;     pero no activa la marca.
           ;; Es limpio evitar la activación, incluso aunque el comando
           ;; loop would desactivaría la marca porque se
           ;; insertara el texto.
           (goto-char (prog1 (mark t)
                        (set-marker (mark-marker) (point) (current-buffer)))))
       ;; Si tenemos todo el camino, haz que this-command lo indique.
       (if (eq this-command t)
           (setq this-command 'yank))
       nil)

   La expresión clave es ‘insert-for-yank’, que inserta la cadena
devuelta por ‘current-kill’, pero elimina algo de propiedades de texto
desde eso.

   Sin embargo, antes de tener esta expresión, la función asigna el
valor de ‘yank-window-start’ a la posición devuelta por la expresión
‘(window-start)’, la posición que muestra lo que actualmente empieza.
La función ‘yank’ también asigna ‘this-command’ y empuja la marca.

   Después de pegar el elemento apropiado, si el argumento opcional es
un CONS en vez de un número o nada, se pone el punto al principio del
texto pegado y se marca al final.

   (La función ‘prog1’ es como ‘progn’ pero devuelve el valor de su
primer argumento en vez del valor de su último argumento.  Su primer
argumento fuerza devolver la marca del búffer como un entero.  Se puede
ver la documentación para estas funciones emplazando el punto a través
de ellas en este búffer y entonces escribiendo ‘C-h f’
(‘describe-function’) seguido por un ‘RET’; por defecto es la función.)

   La última parte de la función cuenta que hacer cuando eso sucede.


File: emacs-lisp-intro-es.info,  Node: yank-pop,  Next: fichero anillo,  Prev: pegar,  Up: Kill Ring

B.3 ‘yank-pop’
==============

Después de comprender ‘yank’ y ‘current-kill’, se conoce como enfocar la
función ‘yank-pop’.  Dejando fuera la documentación para guardar el
espacio, se parece a esto:

     (defun yank-pop (&optional arg)
       "..."
       (interactive "*p")
       (if (not (eq last-command 'yank))
           (error "El comando previo no fué un corte"))
       (setq this-command 'yank)
       (unless arg (setq arg 1))
       (let ((inhibit-read-only t)
             (before (< (point) (mark t))))
         (if before
             (funcall (or yank-undo-function 'delete-region) (point) (mark t))
           (funcall (or yank-undo-function 'delete-region) (mark t) (point)))
         (setq yank-undo-function nil)
         (set-marker (mark-marker) (point) (current-buffer))
         (insert-for-yank (current-kill arg))
         ;; Asigna la ventana a volver donde estaba el comando yank,
         ;; si es posible
         (set-window-start (selected-window) yank-window-start t)
         (if before
             ;; Esto es como exchange-point-and-mark,
             ;; pero no activa la marca.
             ;; Es limpio evitar la activación, incluso aunque el comando
             ;; desactivase la marca porque se insertara el texto.
             (goto-char (prog1 (mark t)
                          (set-marker (mark-marker)
                                      (point)
                                      (current-buffer))))))
       nil)

   La función es interactive con una pequeña ‘p’ así el argumento
prefijo es procesado y pasado a la función.  El comando puede solo ser
usado después del yank previo; de otro modo un mensaje de error se
envía.  Este chequeo usa la variable ‘last-command’ que se asigna por
‘yank’ y discutida de algún modo.  (*Note copy-region-as-kill::.)

   La cláusula ‘let’ asigna la variable ‘before’ a cierto o falso
dependiendo de si el punto está antes o después de la marca y entonce la
región entre punto y marca se borra.  Esta es la región que fué
insertada por el yank previo y eso es este texto que será reemplazado.

   ‘funcall’ llama a su primer argumento como una función, pasando los
argumentos que permanecen.  El primer argumento es el que la expresión
‘or’ devuelve.  Los dos argumentos que permanecen son las posiciones de
punto y marca asignadas por el comando ‘yank’ precedente.

   Hay más, pero esta es la parte más dura.


File: emacs-lisp-intro-es.info,  Node: fichero anillo,  Prev: yank-pop,  Up: Kill Ring

B.4 El fichero ‘ring.el’
========================

De manera interesante, GNU Emacs posee un fichero llamado ‘ring.el’ que
provee muchas de las funcionalidades que ahora se discuten.  Pero las
funciones tales como ‘kill-ring-yank-pointer’ no usan esta librería,
posiblemente porque fueron escritas pronto.


File: emacs-lisp-intro-es.info,  Node: Grafo completo,  Next: Software Libre y Manuales Libres,  Prev: Kill Ring,  Up: Top

Apéndice C Un grafo con ejes etiquetados
****************************************

Los ejes impresos ayudan a comprender un grafo.  Para crear escalas.  En
un capítulo anterior (*note Leyendo un grafo: Leyendo un grafo.), se
escribió el código para imprimir el cuerpo de un grafo.  Aquí se escribe
el código para imprimir y etiquetar ejes horizontales y verticales, a lo
largo del cuerpo en sí.

* Menu:

* Ejemplo etiquetado::       Ejemplo etiquetado
* print-graph Varlist::      Expresión ‘let’ en ‘print-graph’.
* print-Y-axis::             Imprimir una etiqueta para los ejes verticales.
* print-X-axis::             Imprimir una etiqueta horizontal.
* Imprimir Grafo Entero::    La función para imprimir un grafo completo.


File: emacs-lisp-intro-es.info,  Node: Ejemplo etiquetado,  Next: print-graph Varlist,  Up: Grafo completo

Grafo de ejemplo etiquetado
===========================

Puesto que las inserciones rellenan un búffer a la derecha y debajo del
punto, el nuevo grafo imprime la función que primero imprimiría el eje
vertical Y, después el cuerpo del grafo, y finalmente el eje horizontal
X.  Esta secuencia nos da los contenidos de la función:

  1. Configura código.

  2. Imprime el eje Y.

  3. Imprime el cuerpo del grafo.

  4. Imprime el eje X.

   Aquí hay un ejemplo de como se ve un grafo finalizado:

         10 -
                       *
                       *  *
                       *  **
                       *  ***
          5 -      *   *******
                 * *** *******
                 *************
               ***************
          1 - ****************
              |   |    |    |
              1   5   10   15

En este grafo, en ambos ejes vertical y horizontal se etiquetan con
números.  Sin embargo, en algunos grafos, el eje horizontal es tiempo y
estaría mejor etiquetarlo con meses, así:

          5 -      *
                 * ** *
                 *******
               ********** **
          1 - **************
              |    ^      |
            Enero Junio Enero

   Dentro, con un pequeño pensamiento, se puede fácilmente venir con una
variedad de esquemas de etiquetado verticales y horizontales.  Nuestra
tarea podría llegar a ser complicada.  Pero las complicaciones generan
confusión.  En vez de permitir esto, es mejor elegir un simple esquema
de etiquetado para nuestro primer esfuerzo, y modificarlo o reemplazarlo
después.

   Estas consideraciones sugieren el siguiente outline para la función
‘print-graph’:

     (defun print-graph (numbers-list)
       "DOCUMENTATION..."
       (let ((height  ...
             ...))
         (print-Y-axis height ... )
         (graph-body-print numbers-list)
         (print-X-axis ... )))

   Nosotros podemos trabajar en cada parte de la definición de función
‘print-graph’.


File: emacs-lisp-intro-es.info,  Node: print-graph Varlist,  Next: print-Y-axis,  Prev: Ejemplo etiquetado,  Up: Grafo completo

C.1 La varlist ‘print-graph’
============================

Para escribir la función ‘print-graph’, la primera tarea es escribir la
varlist en la expresión ‘let’.  (Nosotros dejaremos por ahora cualquier
pensamiento acerca de hacer la función interactive o acerca de los
contenidos de su cadena de documentación.)

   La varlist asignaría varios valores.  Claramente, la etiqueta
superior del eje vertical debe ser al menos la altura del grafo, que
significa que debe obtener esta información aquí.  Note que la función
‘print-graph-body’ también requiere esta información.  No hay razón para
calcular la altura del grafo en dos lugares diferentes, así cambiaría
‘print-graph-body’ desde el camino que definimos pronto para tomar
ventaja del cálculo.

   De manera similar, tanto la función para imprimir la etiqueta del eje
X y la función ‘print-graph-body’ se necesita aprender el valor del
ancho de cada símbolo.  Se puede desarrollar el cálculo aquí y cambiar
la definición para ‘print-graph-body’ desde el camino que se definió en
el capítulo previo.

   El tamaño de la etiqueta para el eje horizontal debe ser al menos tan
largo como el grafo.  Sin embargo, esta información es usada solo en la
función que imprime el eje horizontal, así no necesita calcularse aquí.

   Estos pensamientos nos llevan directamente a la siguiente forma para
la varlist en el ‘let’ para ‘print-graph’:

     (let ((height (apply 'max numbers-list)) ; Primera versión.
           (symbol-width (length graph-blank)))

Como se verá, esta expresión no es bastante correcta.


File: emacs-lisp-intro-es.info,  Node: print-Y-axis,  Next: print-X-axis,  Prev: print-graph Varlist,  Up: Grafo completo

C.2 La función ‘print-Y-axis’
=============================

El trabajo de la función ‘print-Y-axis’ es imprimir una etiqueta para el
eje vertical que se parece a esto:

         10 -




          5 -



          1 -

La función se pasaría a lo alto del grafo, y así construyen e insertan
los números y marcas apropiados.

* Menu:

* print-Y-axis en Detalle::  print-Y-axis en Detalle
* Altura de etiqueta::       ¿Qué altura para el eje Y?
* Calcular un resto::        Cómo calcular el resto de una división.
* Elemento del Eje Y::       Construir una línea para el eje
                               Y.
* Y-axis-column::            Generar una lista de etiquetas del eje Y.
* Penúltimo print-Y-axis::  Una versión no muy final.


File: emacs-lisp-intro-es.info,  Node: print-Y-axis en Detalle,  Next: Altura de etiqueta,  Up: print-Y-axis

La función ‘print-Y-axis’ en detalle
------------------------------------

Es suficientemente fácil ver en la figura que la etiqueta del eje Y pero
se puede decir en palabras, y entonces escribir una definición de
función para hacer el trabajo es otra materia.  No es bastante verdad
decir que se quiere un número y un tic cada cinco líneas: solo hay tres
líneas entre el ‘1’ y el ‘5’ (líneas 2, 3 y 4), pero cuatro líneas entre
el ‘5’ y el ‘10’ (líneas 6, 7, 8 y 9).  Es mejor decir que se quiere un
número y un tic en la quinta línea desde abajo a cada línea que es un
múltiplo de cinco.


File: emacs-lisp-intro-es.info,  Node: Altura de etiqueta,  Next: Calcular un resto,  Prev: print-Y-axis en Detalle,  Up: print-Y-axis

¿A qué altura se debería etiquetar?
-----------------------------------

La siguiente cuestión es a que altura se etiquetaría.  Supón que la
máxima altura de la columna mayor del grafo es siete.  La etiqueta
superior en el eje Y sería ‘5 -’, ¿y el grafo se pegaría debajo de la
etiqueta?, ¿o la etiqueta superior sería ‘7 -’, y marcar la vertical del
grafo?  ¿o sería la etiqueta superior ‘10 -’, que es múltiplo de cinco,
y es superior al valor más alto del grafo?

   La última forma es preferida.  La mayoría de los grafos son
rectángulos cuyos lados son un número integral de pasos a lo largo -- 5,
10, 15, y así para un paso a distancia de cinco.  Pero tan pronto se
decide usar un paso alto para el eje vertical, se descubre que la
expresión simple en la varlist para la altura de la computación es
errónea.  La expresión es ‘(apply 'max numbers-list)’.  Esto devuelve la
altura precisa, no la altura máxima más de lo que es necesario para
redondear el múltiplo de cinco.  Una expresión más compleja es
requerida.

   Como es normal en casos como este, un problema complejo llega a ser
simple si está dividido en varios problemas pequeños.

   Primero, considere el caso cuando el valor superior del grafo es un
múltiplo integral de cinco -- cuando eso es 5, 10, 15, o algún múltiplo
de cinco.  Se puede usar este valor como la altura del eje Y.

   Un camino simple y limpio para determinar si un número es múltiplo de
cinco se divide por cinco y mira si la división devuelve resto.  Si no
hay resto, el número es un múltiplo de cinco.  De este modo, siete
dividido tiene un resto de dos, y siete no es un entero múltiplo de
cinco.  Dicho de otra manera, recordando la escuela, cinco entre siete
es uno y me llevo dos.  Sin embargo, diez entre dos, no tiene resto:
diez es un múltiplo entero de cinco.


File: emacs-lisp-intro-es.info,  Node: Calcular un resto,  Next: Elemento del Eje Y,  Prev: Altura de etiqueta,  Up: print-Y-axis

C.2.1 Viaje lateral: Calcula un resto
-------------------------------------

En Lisp, la función para calcular un resto es ‘%’.  La función devuelve
el resto de su primer argumento dividido por su segundo argumento.  Como
ocurre, ‘%’ es una función en Emacs Lisp que no se puede implementar
usando ‘apropos’: no se puede encontrar nada si se escribe ‘M-x apropos
<RET> resto <RET>’.  El único camino para aprender la existencia de ‘%’
es leer acerca de eso en un libro tal como este o en las fuentes de
Emacs Lisp.

   Se puede probar la función ‘%’ evaluando las siguientes dos
expresiones:

     (% 7 5)

     (% 10 5)

La primera expresión devuelve 2 y la segunda expresión devuelve 0.

   Para chequear si el valor devuelto es cero o algún otro número, se
puede usar la función ‘zerop’.  Esta función devuelve ‘t’ si su
argumento debe ser un número, es cero.

     (zerop (% 7 5))
          ⇒ nil

     (zerop (% 10 5))
          ⇒ t

   De este modo, la siguiente expresión devolverá ‘t’ si la altura del
grafo es divisible por cinco:

     (zerop (% height 5))

(El valor de ‘height’, de acuerdo, puede ser encontrado desde ‘(apply
'max numbers-list)’.)

   Por otro lado, si el valor de ‘height’ no es un múltiplo de cinco,
nosotros queremos resetear el valor al siguiente múltiplo de cinco.
Esta es la aritmética sencilla usando funciones con las que ya se está
familiarizado.  Primero, se divide el valor de ‘height’ por cinco para
determinar cuantas veces cinco va dentro del número.  De este modo,
cinco va dentro doce veces.  Si se añade uno a este cociente y se
multiplica por cinco, obtendremos el valor del siguiente múltiplo de
cinco que es más largo que el mayor.  Cinco va dentro de doce dos veces.
Añade uno a dos, y multiplica por cinco; el resultado es quince, que es
el siguiente múltiplo de cinco que es mayor de doce.  La expresión Lisp
para esto es:

     (* (1+ (/ height 5)) 5)

Por ejemplo, si se evalúa lo siguiente, el resultado es 15:

     (* (1+ (/ 12 5)) 5)

   Todo a través de esta discusión, se ha estado usando 'cinco' como el
valor para las etiquetas espaciadas en el eje Y; pero se puede querer
usar algún otro valor.  Generalmente, reemplazaría 'cinco' con una
variable a la que poder asignar un valor.  El mejor nombre que puedo
pensar para esta variable es ‘Y-axis-label-spacing’.

   Usando este término, y una expresión ‘if’, se produce lo siguiente:

     (if (zerop (% height Y-axis-label-spacing))
         height
       ;; else
       (* (1+ (/ height Y-axis-label-spacing))
          Y-axis-label-spacing))

Esta expresión devuelve el valor de ‘height’ en sí si la altura es
incluso un múltiplo del valor del ‘Y-axis-label-spacing’ o lo demás
computa y devuelve un valor de ‘height’ que es igual al siguiente
múltiplo mayor del valor del ‘Y-axis-label-spacing’.

   Se puede ahora incluir esta expresión en la expresión ‘let’ de la
función ‘print-graph’ (después de la primera configuración del valor de
‘Y-axis-label-spacing’):

     (defvar Y-axis-label-spacing 5
       "Número de líneas desde una etiqueta del eje Y al siguiente.")

     ...
     (let* ((height (apply 'max numbers-list))
            (height-of-top-line
             (if (zerop (% height Y-axis-label-spacing))
                 height
               ;; else
               (* (1+ (/ height Y-axis-label-spacing))
                  Y-axis-label-spacing)))
            (symbol-width (length graph-blank))))
     ...

(Note que el uso de la función ‘let*’: el valor inicial de la altura es
calculada una vez por la expresión ‘(apply 'max numbers-list)’ y
entonces el valor resultado de ‘height’ es usado para computar su valor
final.  *Note La expresión ‘let*’: fwd-para let, para más acerca de
‘let*’.)


File: emacs-lisp-intro-es.info,  Node: Elemento del Eje Y,  Next: Y-axis-column,  Prev: Calcular un resto,  Up: print-Y-axis

C.2.2 Construye un elemento del eje Y
-------------------------------------

Cuando se imprime el eje vertical, se quieren insertar cadenas tales
como ‘5 -’ y ‘10 - ’ cada cinco líneas.  Más allá, se quieren los
números agitados para alinear, así pocos números deben ser acuñados con
espacios de guía.  Si alguna de las cadenas usan dos dígitos, las
cadenas con un simple dígito deben incluir una guía en blanco antes del
número.

   Para figurarse el tamaño del número, se usa la función ‘length’.
Pero la función ‘length’ funciona solo con una cadena, no con un número.
Así el número tiene que ser convertido desde un número a una cadena.
Esto se hace con la función ‘number-to-string’.  Por ejemplo,

     (length (number-to-string 35))
          ⇒ 2

     (length (number-to-string 100))
          ⇒ 3

(‘number-to-string’ se llama ‘int-to-string’; se verá este nombre
alternativo en varias fuentes.)

   Además, en cada etiqueta, cada número es seguido por una cadena tal
como ‘ - ’, que llamará al marcador ‘Y-axis-tic’.  Esta variable está
definida con ‘defvar’:

     (defvar Y-axis-tic " - "
        "La Cadena que sigue el número en una etiqueta del eje Y.")

   El tamaño de la etiqueta Y es la suma del tamaño del eje Y y el
tamaño del número del alto del grafo.

     (length (concat (number-to-string height) Y-axis-tic)))

   Este valor será calculado por la función ‘print-graph’ en su varlist
como ‘full-Y-label-width’ y se pasa dentro.  (Note que no se pensaba en
incluir esto en el varlist cuando se propuso.)

   Para crear un eje vertical completo, una marca de tic es concatenada
con un número; y los dos juntos pueden ser precedidos por uno o más
espacios dependiendo de cómo de largo es el número.  La etiqueta
consiste de tres partes: los espacios que se lideran (opcional), el
número, y la marca tic.  La función se pasa al valor del número para la
fila específica, y el valor del ancho de la línea de arriba, que es
calculada (solo una vez) por ‘print-graph’.

     (defun Y-axis-element (number full-Y-label-width)
       "Construye una etiqueta NUMERADA
     Un elemento numerado se parece a esto ` 5 - ',
     y está tan acuñado como se necesita así todo se
     alinea con el elemento para el número mayor."
       (let* ((leading-spaces
              (- full-Y-label-width
                 (length
                  (concat (number-to-string number)
                          Y-axis-tic)))))
         (concat
          (make-string leading-spaces ? )
          (number-to-string number)
          Y-axis-tic)))

   La función ‘Y-axis-element’ concatena junto los espacios que se
lideran si cualquiera; el número, como una cadena; y la marca tic.

   Para imaginarnos cuantos espacios guía la etiqueta necesita, la
función sustrae el tamaño de la etiqueta -- el tamaño del número más el
tamaño de la marca tic -- desde el ancho de la etiqueta deseada.

   Los espacios en blanco se insertan usando la función ‘make-string’.
Esta función tiene dos argumentos: lo primero cuenta como de larga será
a cadena y el segundo es un símbolo para el caracter a insertar, en un
formato espcial.  El formato es una marca de pregunta seguida por un
espacio en blanco, como este, ‘?’.  *Note Tipo de Caracter: (elisp)Tipo
de Caracter, para una descripción de la sintaxis para caracteres.  (De
acuerdo, se podría querer reemplazar el espacio en blanco por algún otro
caracter ....  Tu sabes qué hacer.)

   La función ‘number-to-string’ es usada en la expresión de
concatenación, para convertir el número a una cadena que es concatenada
con los espacios que se lideran y la marca de tic.


File: emacs-lisp-intro-es.info,  Node: Y-axis-column,  Next: Penúltimo print-Y-axis,  Prev: Elemento del Eje Y,  Up: print-Y-axis

C.2.3 Crea un eje de la columna Y
---------------------------------

Las funciones precedentes proporcionan todas las herramientas necesarias
para construir una función que genera una lista de cadenas enumeradas y
en blanco para inserta como la etiqueta para el eje vertical:

     (defun Y-axis-column (height width-of-label)
       "Construye la lista de ejes Y etiquetadas y cadenas en blanco.
     Para height _la altura_ de la línea de debajo y width-of-label."
       (let (Y-axis)
         (while (> height 1)
           (if (zerop (% height Y-axis-label-spacing))
               ;; Insertar etiqueta.
               (setq Y-axis
                     (cons
                      (Y-axis-element height width-of-label)
                      Y-axis))
             ;; Else, insertar blancos.
             (setq Y-axis
                   (cons
                    (make-string width-of-label ? )
                    Y-axis)))
           (setq height (1- height)))
         ;; Insertar la línea base.
         (setq Y-axis
               (cons (Y-axis-element 1 width-of-label) Y-axis))
         (nreverse Y-axis)))

   En esta función, nosotros empezamos con el valor de ‘height’ y
repetitivamente sustrae uno desde su valor.  Después de cada sustración,
se chequea para ver si el valor es una integral múltiple del
‘Y-axis-label-spacing’.  Si eso es, se construye una etiqueta numerada
usando la función ‘Y-axis-element’; si no, se construye una etiqueta
blanca usando la función ‘make-string’.  La línea base consiste del
número uno seguido por una marca tic.


File: emacs-lisp-intro-es.info,  Node: Penúltimo print-Y-axis,  Prev: Y-axis-column,  Up: print-Y-axis

C.2.4 La versión no demasiado final de ‘print-Y-axis’
-----------------------------------------------------

La lista construida por la función ‘Y-axis-column’ está pasada a la
función ‘print-Y-axis’, que inserta la lista como una columna.

     (defun print-Y-axis (height full-Y-label-width)
       "Inserta el eje Y usando HEIGHT y FULL-Y-LABEL-WIDTH.
     La altura debe ser la máxima altura del grafo.
     El ancho completo es el ancho del mayor elemento de la
     etiqueta"
     ;; El valor del alto y full-Y-label-width
     ;; son pasadas por `print-graph'.
       (let ((start (point)))
         (insert-rectangle
          (Y-axis-column height full-Y-label-width))
         ;; Posiciona el punto listo para inserta el grafo.
         (goto-char start)
         ;; Mueve el punto hacia adelante por valor de full-Y-label-width
         (forward-char full-Y-label-width)))

   El ‘print-Y-axis’ usa la función ‘insert-rectangle’ para inserta el
eje Y creado por la función ‘Y-axis-column’.  Además, eso emplaza el
punto en la posición correcta para imprimir el cuerpo del grafo.

   Se puede chequear ‘print-Y-axis’:

  1. Instalar

          Y-axis-label-spacing
          Y-axis-tic
          Y-axis-element
          Y-axis-column
          print-Y-axis

  2. Copia la siguiente expresión:

          (print-Y-axis 12 5)

  3. Cambia al búffer ‘*scratch*’ y emplaza el cursor donde se quiere el
     eje etiquetado para empezar.

  4. Escribe ‘M-:’ (‘eval-expression’).

  5. Pega la expresión ‘graph-body-print’ dentro del minibúffer con
     ‘C-y’ (‘yank’).

  6. Presiona <RET> para evaluar la expresión

   Emacs imprimirá etiquetas verticalmente, el primero siendo ‘10 - ’.
(La función ‘print-graph’ pasará el valor de ‘height-of-top-line’, que
en este caso finalizará en 15, por esto lo que se obtiene podría
aparecer como un error.)


File: emacs-lisp-intro-es.info,  Node: print-X-axis,  Next: Imprimir Grafo Entero,  Prev: print-Y-axis,  Up: Grafo completo

C.3 La función ‘print-X-axis’
=============================

Las etiquetas del eje X son como las etiquetas del eje Y, excepto que
los ticks son un línea debajo de los números.  Las etiquetas se parece
como esto:

         |   |    |    |
         1   5   10   15

   El primer tic está bajo la primera columna del grafo y está precedido
por varios espacios en blanco.  Estos espacios proporcionan la
habitación en filas de debajo para las etiquetas del eje Y. El segundo,
tercer, cuarto, y subsiguientes ticks son todos espaciados igualmente,
de acuerdo al valor de ‘X-axis-label-spacing’.

   La segunda fila del eje X consiste de números, precedidos por varios
espacios en blanco y también separado de acuerdo al valor de la variable
‘X-axis-label-spacing’.

   El valor de la variable ‘X-axis-label-spacing’ sería medido en
unidades de ‘symbol-width’, puesto que se puede querer cambiar el ancho
de los símbolos que estás usando para imprimir el cuerpo del grafo sin
cambiar los caminos del grafo que está etiquetado.

* Menu:

* Diferencias similares::    Mucho como ‘print-Y-axis’, pero no
                               exactamente.
* Eje X marca tic::          Crear marcas de tic para los ejes horizontales.


File: emacs-lisp-intro-es.info,  Node: Diferencias similares,  Next: Eje X marca tic,  Up: print-X-axis

Similaridades y diferencias
---------------------------

La función ‘print-X-axis’ está construida más o menos del mismo modo
como que la función ‘print-Y-axis’ excepto que tiene dos líneas: la
línea de marcas tic y los números.  Nosotros escribiremos una función
separado a imprimir cada línea y entonces combinarlo con la función
‘print-X-axis’.

   Esto es un proceso de tres pasos:

  1. Escribe una función para imprimir el eje X marca tic,
     ‘print-X-axis-tic-line’.

  2. Escribe una función imprime los números X,
     ‘print-X-axis-numbered-line’.

  3. Escribe una función para imprimir ambas líneas, la función
     ‘print-X-axis’, usando ‘print-X-axis-tic-line’ y
     ‘print-X-axis-numbered-line’.


File: emacs-lisp-intro-es.info,  Node: Eje X marca tic,  Prev: Diferencias similares,  Up: print-X-axis

C.3.1 Eje X marca tic
---------------------

La primera función imprimiría las marcas de tic del eje X. Se deben
especificar las marcas en sí y su espacio:

     (defvar X-axis-label-spacing
       (if (boundp 'graph-blank)
           (* 5 (length graph-blank)) 5)
       "Números de unidades desde un eje X al siguiente.")

(Note que el valor de ‘graph-blank’ est'a asignado por otro ‘defvar’.
El predicado ‘boundp’ chequea si ya ha sido asignado; ‘boundp’ devuelve
‘nil’ si no lo tiene.  Si ‘graph-blank’ fuera disociado y no usara esta
construcción condicional, en un GNU Emacs reciente, se introduciría el
depurador y mirará un mensaje de error diciendo
‘Debugger entered--Lisp error: (void-variable graph-blank)’

   Aquí está el ‘defvar’ para ‘X-axis-tic-symbol’:

     (defvar X-axis-tic-symbol "|"
       "Cadena para insertar para apuntar a una columna en el eje X.")

   El objetivo es crear una línea que se parece a esto:

            |   |    |    |

   El primer tic es indentado así que está bajo la primera columna, que
es indentado para proveer espacio para las etiquetas del eje Y.

   Un elemento tic consiste en espacios en blanco que se extienden desde
un tic al siguiente más un símbolo tic.  El número de espacios en blanco
se determinan por el ancho del símbolo tic y el ‘X-axis-label-spacing’.

   El código se parece a esto:

     ;;; X-axis-tic-element
     ...
     (concat
      (make-string
       ;; Crea una cadena de blancos.
       (-  (* symbol-width X-axis-label-spacing)
           (length X-axis-tic-symbol))
       ? )
      ;; Concatena blancos con símbolos.
      X-axis-tic-symbol)
     ...

   Lo siguiente, determina cuantos espacios en blanco son necesarios
para indentar la primera marca tic a la primera del grafo.  Esto usa el
valor de ‘full-Y-label-width’ pasaba por la función ‘print-graph’.

   El código para crear ‘X-axis-leading-spaces’ se parece a esto:

     ;; X-axis-leading-spaces
     ...
     (make-string full-Y-label-width ? )
     ...

   También necesita determinar el tamaño del eje horizontal, que es el
tamaño de la lista de números, y el número de ticks en el eje
horizontal:

     ;; X-length
     ...
     (length numbers-list)

     ;; tic-width
     ...
     (* symbol-width X-axis-label-spacing)

     ;; number-of-X-ticks
     (if (zerop (% (X-length tic-width)))
         (/ (X-length tic-width))
       (1+ (/ (X-length tic-width))))

   Todo esto lidera directamente a la función para imprimir el eje X:

     (defun print-X-axis-tic-line
       (number-of-X-tics X-axis-leading-spaces X-axis-tic-element)
       "Imprime ticks para el eje X."
         (insert X-axis-leading-spaces)
         (insert X-axis-tic-symbol)  ; En la primera columna.
         ;; Inserta el segundo tic en el lugar adecuado.
         (insert (concat
                  (make-string
                   (-  (* symbol-width X-axis-label-spacing)
                       ;; Inserta el espacio en blanco al segundo símbolo tic.
                       (* 2 (length X-axis-tic-symbol)))
                   ? )
                  X-axis-tic-symbol))
         ;; Inserta los ticks que permanecen.
         (while (> number-of-X-tics 1)
           (insert X-axis-tic-element)
           (setq number-of-X-tics (1- number-of-X-tics))))

   La línea de números es igualmente simple:

   Primero, creamos un elemento numerado con espacios en blanco antes de
cada número:

     (defun X-axis-element (number)
       "Construye un elemento del eje X numerado."
       (let ((leading-spaces
              (-  (* symbol-width X-axis-label-spacing)
                  (length (number-to-string number)))))
         (concat (make-string leading-spaces ? )
                 (number-to-string number))))

   Lo siguiente, se crea la función para imprimir la línea numerada,
empezando con el número "1" para la primera columna:

     (defun print-X-axis-numbered-line
       (number-of-X-tics X-axis-leading-spaces)
       "Imprime la líneas de números del eje X"
       (let ((number X-axis-label-spacing))
         (insert X-axis-leading-spaces)
         (insert "1")
         (insert (concat
                  (make-string
                   ;; Inserta espacios en blanco al siguiente número.
                   (-  (* symbol-width X-axis-label-spacing) 2)
                   ? )
                  (number-to-string number)))
         ;; Insertar números.
         (setq number (+ number X-axis-label-spacing))
         (while (> number-of-X-tics 1)
           (insert (X-axis-element number))
           (setq number (+ number X-axis-label-spacing))
           (setq number-of-X-tics (1- number-of-X-tics)))))

   Finalmente, se necesita escribir lo que ‘print-X-axis’ que usa
‘print-X-axis-tic-line’ y ‘print-X-axis-numbered-line’.

   La función debe determinar los valores locales de las variables
usadas por ‘print-X-axis-tic-line’ y ‘print-X-axis-numbered-line’, y
entonces eso debe llamarlas.  También, debe imprimir el retorno de carro
que separe las dos líneas.

   La función consiste de una varlist que especifica cinco variables
locales, y llama cada una de las dos líneas imprimiendo funciones:

     (defun print-X-axis (numbers-list)
       "Imprime el eje X etique al tamaño de NUMBERS-LIST."
       (let* ((leading-spaces
               (make-string full-Y-label-width ? ))
            ;; symbol-width se provee por graph-body-print
            (tic-width (* symbol-width X-axis-label-spacing))
            (X-length (length numbers-list))
            (X-tic
             (concat
              (make-string
               ;; Crea una cadena de espacios en blanco.
               (-  (* symbol-width X-axis-label-spacing)
                   (length X-axis-tic-symbol))
               ? )
              ;; Concatena espacio en blanco con símbolos
              tic.
              X-axis-tic-symbol))
            (tic-number
             (if (zerop (% X-length tic-width))
                 (/ X-length tic-width)
               (1+ (/ X-length tic-width)))))
         (print-X-axis-tic-line tic-number leading-spaces X-tic)
         (insert "\n")
         (print-X-axis-numbered-line tic-number leading-spaces)))

   Se puede testear ‘print-X-axis’:

  1. Instale ‘X-axis-tic-symbol’, ‘X-axis-label-spacing’,
     ‘print-X-axis-tic-line’, tanto como ‘X-axis-element’,
     ‘print-X-axis-numbered-line’, y ‘print-X-axis’.

  2. Copia la siguiente expresión:

          (progn
           (let ((full-Y-label-width 5)
                 (symbol-width 1))
             (print-X-axis
              '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16))))

  3. Cambia al búffer ‘*scratch*’ y emplaza el cursor donde se quiere el
     eje etiquetado para empezar.

  4. Escribe ‘M-:’ (‘eval-expression’).

  5. Pegue la expresión de test dentro del minibuffer con ‘C-y’
     (‘yank’).

  6. Presiona <RET> para evaluar la expresión

   Emacs imprimirá el eje horizontal así

          |   |    |    |    |
          1   5   10   15   20


File: emacs-lisp-intro-es.info,  Node: Imprimir Grafo Entero,  Prev: print-X-axis,  Up: Grafo completo

C.4 Imprimiendo el grafo completo
=================================

Ahora estamos listos para imprimir el grafo completo.

   La función para imprimir el grafo con las etiquetas apropiadas sigue
el esquema que creamos antes (*note Un Grafo con Ejes Etiquetados: Grafo
completo.), pero con adiciones.

   Aquí está el esquema:

     (defun print-graph (numbers-list)
       "DOCUMENTATION..."
       (let ((height  ...
             ...))
         (print-Y-axis height ... )
         (graph-body-print numbers-list)
         (print-X-axis ... )))

* Menu:

* La versión final::       Unos pocos cambios
* Testear print-graph::      Ejecutar un rápido test.
* Graficar palabras en funciones::  Ejecutando el código final.
* lambda::                   Cómo escribir una función anónima.
* mapcar::                   Aplicar una función a elementos de una lista.
* Otro Error::               Todavía otro error ... más
                               insidioso.
* Grafo impreso final::      ¡El grafo en sí!


File: emacs-lisp-intro-es.info,  Node: La versión final,  Next: Testear print-graph,  Up: Imprimir Grafo Entero

Cambios para la versión final
-----------------------------

La versión final es diferente desde que se planea en dos caminos:
primero, contiene los valores adicionales calculadas una vez que en la
varlist; segundo, eso trae una opción para específicar las etiquetas se
incrementa la fila.  Esta última funcionalidad cambia a ser esencial; de
otro modo, un grafo puede tener más filas que ajustarse en una muestra o
en una hoja de papel.

   Esta nueva funcionalidad requiere un cambio a la función
‘Y-axis-column’, para añadir ‘vertical-step’ para eso.  Esta función es
parece a esto:

     ;;; Versión Final.
     (defun Y-axis-column
       (height width-of-label &optional vertical-step)
       "Construye una lista de etiquetas para el eje Y.
     HEIGHT es la máxima altura del grafo.
     WIDTH-OF-LABEL es el máximo ancho de la etiqueta.
     VERTICAL-STEP, una opción, es un entero positivo
     que especifica cuanto una etiqueta de eje Y incrementa
     cada línea. Por ejemplo, un paso de 5
     significa que cada línea es cinco unidades
     del grafo."
       (let (Y-axis
             (number-per-line (or vertical-step 1)))
         (while (> height 1)
           (if (zerop (% height Y-axis-label-spacing))
               ;; Inserta etiqueta.
               (setq Y-axis
                     (cons
                      (Y-axis-element
                       (* height number-per-line)
                       width-of-label)
                      Y-axis))
             ;; Else, inserta espacios en blanco.
             (setq Y-axis
                   (cons
                    (make-string width-of-label ? )
                    Y-axis)))
           (setq height (1- height)))
         ;; Inserta línea base.
         (setq Y-axis (cons (Y-axis-element
                             (or vertical-step 1)
                             width-of-label)
                            Y-axis))
         (nreverse Y-axis)))

   Los valores para la máxima altura del grafo y el ancho de un símbolo
se computan por ‘print-graph’ es su expresión ‘let’; así
‘graph-body-print’ debe ser cambiado para aceptarlos.

     ;;; Versión Final.
     (defun graph-body-print (numbers-list height symbol-width)
       "Imprime una gráfica de barras del NUMBERS-LIST.
     El numbers-list consiste en los valores del eje Y.
     HEIGHT es la máxisma altura del grafo.
     SYMBOL-WIDTH es el número de cada columna."
       (let (from-position)
         (while numbers-list
           (setq from-position (point))
           (insert-rectangle
            (column-of-graph height (car numbers-list)))
           (goto-char from-position)
           (forward-char symbol-width)
           ;; Dibuja el grafo columna por columna.
           (sit-for 0)
           (setq numbers-list (cdr numbers-list)))
         ;; Posiciona el punto para las etiquetas del eje X.
         (forward-line height)
         (insert "\n")))

   Finalmente, el código para la función ‘print-graph’:

     ;;; Versión Final.
     (defun print-graph
       (numbers-list &optional vertical-step)
       "El gráfico de barras etiquetadas del NUMBERS-LIST.
     El numbers-list consiste en los valores de eje Y.

     Opcionalmente, VERTICAL-STEP, un entero positivo, especifica cuanto el
     eje Y incrementa cada línea. Por ejemplo, un paso de 5
     significa que cada fila es de cinco unidades.
       (let* ((symbol-width (length graph-blank))
              ;; height en ambos es el número más largo
              ;; y el número con la mayoría de los digitos.
              (height (apply 'max numbers-list))
              (height-of-top-line
               (if (zerop (% height Y-axis-label-spacing))
                   height
                 ;; else
                 (* (1+ (/ height Y-axis-label-spacing))
                    Y-axis-label-spacing)))
              (vertical-step (or vertical-step 1))
              (full-Y-label-width
               (length
                (concat
                 (number-to-string
                  (* height-of-top-line vertical-step))
                 Y-axis-tic))))

         (print-Y-axis
          height-of-top-line full-Y-label-width vertical-step)
         (graph-body-print
          numbers-list height-of-top-line symbol-width)
         (print-X-axis numbers-list)))


File: emacs-lisp-intro-es.info,  Node: Testear print-graph,  Next: Graficar palabras en funciones,  Prev: La versión final,  Up: Imprimir Grafo Entero

C.4.1 Testeando ‘print-graph’
-----------------------------

Se puede chequear la función ‘print-graph’ con una lista ordenada de
números:

  1. Instala las versiones finales de ‘Y-axis-column’,
     ‘graph-body-print’, y ‘print-graph’ (además del resto del código.)

  2. Copia la siguiente expresión:

          (print-graph '(3 2 5 6 7 5 3 4 6 4 3 2 1))

  3. Cambia al búffer ‘*scratch*’ y emplaza el cursor donde se quiere el
     eje etiquetado para empezar.

  4. Escribe ‘M-:’ (‘eval-expression’).

  5. Pegue la expresión de test dentro del minibuffer con ‘C-y’
     (‘yank’).

  6. Presiona <RET> para evaluar la expresión

   Emacs imprimirá un grafo que se parece a:

     10 -


              *
             **   *
      5 -   ****  *
            **** ***
          * *********
          ************
      1 - *************

          |   |    |    |
          1   5   10   15

   Por otro lado, si se pasa a ‘print-graph’ un ‘vertical-step’ valor de
2, evaluando esta expresión:

     (print-graph '(3 2 5 6 7 5 3 4 6 4 3 2 1) 2)

El grafo se parece a esto:

     20 -


              *
             **   *
     10 -   ****  *
            **** ***
          * *********
          ************
      2 - *************

          |   |    |    |
          1   5   10   15

(Una pregunta: ¿es el '2' debajo del eje vertical un error o una
funcionalidad?  Si se piensa que es un error, y sería un '1', (o incluso
un '0'), se pueden modificar las fuentes.)


File: emacs-lisp-intro-es.info,  Node: Graficar palabras en funciones,  Next: lambda,  Prev: Testear print-graph,  Up: Imprimir Grafo Entero

C.4.2 Creando gráficas de números de palabras y símbolos
--------------------------------------------------------

Ahora para el gráfico para el que todo este código fué escrito: un
gráfico que muestra cuantas definiciones de función contienen unas pocas
10 palabras y símbolos, cuantas contienen entre 10 y 19 palabras y
símbolos, cuantos contienen entre 20 y 29 palabras y símbolos, y así.

   Esto es un proceso de múltiples pasos.  Primero asegúrate que has
cargado todo el requisito del código.

   Eso es una buena idea para eliminar el valor de ‘top-of-ranges’ en
caso de que has asignado a algún valor diferente.  Se puede evaluar lo
siguiente:

     (setq top-of-ranges
      '(10  20  30  40  50
        60  70  80  90 100
       110 120 130 140 150
       160 170 180 190 200
       210 220 230 240 250
       260 270 280 290 300)

Lo siguiente crea una lista del número de palabras y símbolos en cada
rango.

Evalúa lo siguiente:

     (setq list-for-graph
            (defuns-per-range
              (sort
               (recursive-lengths-list-many-files
                (directory-files "/usr/local/emacs/lisp"
                                 t ".+el$"))
               '<)
              top-of-ranges))

En mi vieja máquina, esto lleva como una hora.  Se parece a 303 ficheros
Lisp en mi copia de Emacs version 19.23.  Después de toda esta
computación, el ‘list-for-graph’ tenía este valor:

     (537 1027 955 785 594 483 349 292 224 199 166 120 116 99
     90 80 67 48 52 45 41 33 28 26 25 20 12 28 11 13 220)

Esto significa que mi copia de Emacs tiene 537 definiciones de funciones
con poco menos de 10 palabras o símbolos en sí, 1027 definiciones de
función con 10 a 19 palabras o símbolos dentro, 955 definiciones de
función con 20 a 29 palabras o símbolos dentro, y así.

   Claramente, solo buscando esta lista se puede ver que la mayoría de
definiciones de función contienen de diez a treinta palabras y símbolos.

   Ahora para imprimir.  Nosotros _no_ queremos imprimir un grafo que es
de 1030 líneas de alto ....  En vez de eso, imprimiría un grafo que es
mejor que venticinco líneas de alto.  Un grafo cuya altura puede ser
mostrada en casi cualquier monitor, y fácilmente impreso en una hoja de
papel.

   Esto significa que cada valor en ‘list-for-graph’ debe ser reducido a
un quinceavo de su valor presente.

   Aquí hay una corta función para hacer esto, usando dos funciones que
no se han visto todavía, ‘mapcar’ y ‘lambda’.

     (defun one-fiftieth (full-range)
       "Devuelve la lista, con el cincuenteavo de cada elemento."
      (mapcar '(lambda (arg) (/ arg 50)) full-range))


File: emacs-lisp-intro-es.info,  Node: lambda,  Next: mapcar,  Prev: Graficar palabras en funciones,  Up: Imprimir Grafo Entero

C.4.3 Una expresión ‘lambda’: Anonimicidad útil
-----------------------------------------------

‘lambda’ es el símbolo para una función anónima, una función sin un
nombre.  Cada vez que se use una función anónima, se necesita incluir su
cuerpo completo.

De este modo,

     (lambda (arg) (/ arg 50))

es una definición de función que dice 'devuelve el valor resultante de
dividir cualquier cosa que es pasada como ‘arg’ por 50'.

   Pronto, por ejemplo, se tenía una función ‘multiply-by-seven’; se
multiplica su argumento por 7.  Esta función es similar, excepto que
divide su argumento por 50; y, no tiene nombre.  El equivalente anónimo
de ‘multiply-by-seven’ es:

     (lambda (number) (* 7 number))

(*Note La forma especial ‘defun’: defun.)

Si queremos multiplicar 3 por 7, podemos escribir:

     (multiply-by-seven 3)
      \_______________/ ^
              |         |
           función  argumento


Esta expresión devuelve 21.

De manera similar, se puede escribir:

     ((lambda (number) (* 7 number)) 3)
      \____________________________/ ^
                    |                |
           función anónima     argumento


Si queremos dividir 100 por 50, se puede escribir:

     ((lambda (arg) (/ arg 50)) 100)
      \______________________/  \_/
                  |              |
          función anónima   argumento


Esta expresión devuelve 2.  El 100 es pasado para la función, que divide
este número por 50.

   *Note Expresiones Lambda: (elisp)Expresiones Lambda, para más acerca
de ‘lambda’.  Lisp y expresiones Lambda se derivan del Cálculo Lambda.


File: emacs-lisp-intro-es.info,  Node: mapcar,  Next: Otro Error,  Prev: lambda,  Up: Imprimir Grafo Entero

C.4.4 La función ‘mapcar’
-------------------------

‘mapcar’ es una función que llama a su primer argumento con cada
elemento de su segundo argumento.  El segundo argumento debe ser una
secuencia.

   La parte ‘map’ del nombre viene de la frase matemática, 'mapeando a
través de un dominio', significa hace apply a una función a cada uno de
los elementos en un dominio.  La frase matemática está basada en la
metáfora de un superviviente paseando, un paso en un momento, a través
de un área él está mapeando.  Y ‘car’, de acuerdo, viene desde la noción
Lisp del primero de una lista.

Por ejemplo,

     (mapcar '1+ '(2 4 6))
          ⇒ (3 5 7)

La función ‘1+’ añade uno a su argumento, es ejecutada en _each_ de la
lista, y una nueva lista es devuelta.

   En contraste con esto ‘apply’, se aplica su primer argumento a todo
lo que permanece.  (*Note Leyendo un grafo: Leyendo un grafo, para una
explicación de ‘apply’.)

   En la definición de ‘one-fiftieth’, el primer argumento es la función
anónima:

     (lambda (arg) (/ arg 50))

y el segundo argumento es ‘full-range’, que será asociado para
‘list-for-graph’.

   La expresión completa se parece a esto:

     (mapcar (lambda (arg) (/ arg 50)) full-range))

   *Note Mapeando Funciones: (elisp)Funciones de Mapeo, para más acerca
de ‘mapcar’.

   Usando la función ‘one-fiftieth’, se puede generar una lista en el
que cada elemento es un cincuenteavo del tamaño del correspondiente
elemento en ‘list-for-graph’.

     (setq fiftieth-list-for-graph
           (one-fiftieth list-for-graph))

   La lista resultante se parece a esto:

     (10 20 19 15 11 9 6 5 4 3 3 2 2
     1 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 4)

Así, ¡ya estamos casi listos para imprimir!  (También se notifica la
pérdida de información: muchos de los rangos superiores son 0, esto
significa que menos de 50 funciones tenían muchas palabras o símbolos --
pero no necesariamente significando que niguna tenía muchas palabras o
símbolos.)


File: emacs-lisp-intro-es.info,  Node: Otro Error,  Next: Grafo impreso final,  Prev: mapcar,  Up: Imprimir Grafo Entero

C.4.5 Otro error ... más insidioso
----------------------------------

¡Se dijo 'casi listo para imprimir'!  De acuerdo, hay un error en la
función ‘print-graph’ ....  Esta tiene una opción ‘vertical-step’, pero
no una opción ‘horizontal-step’.  La escala ‘top-of-range’ va desde 10 a
300 por decenas.  Pero la función ‘print-graph’ imprimirá solo uno por
uno.

   Esto es un ejemplo clásico de lo que algunos consideramos el tipo más
insidioso de error, el error de omisión.  Este no es el tipo de error
que se puede encontrar estudiando el código, para eso no es el código;
es una funcionalidad omitida.  Tus mejores acciones son probar tu
programa pronto y con frecuencia; e intentar poner en orden, tanto como
se pueda, escribir código que sea fácil de comprender y fácil de
cambiar.  Intenta ser consciente, siempre y cuando se pueda, esto es
siempre que tengas que escribir, _será_ reescrito, si no pronto,
eventualmente.  Un máximo duro de seguir.

   Esta es la función ‘print-X-axis-numbered-line’ que necesita el
trabajo; y entonces el ‘print-X-axis’ y la función ‘print-graph’
necesita ser adaptada.  No se necesita mucho para ser hecho; hay uno
simpático: los números podrían alinearse con marcas de tic.  Esto toma
un pequeño pensamiento.

   Aquí está el ‘print-X-axis-numbered-line’ corregido:

     (defun print-X-axis-numbered-line
       (number-of-X-tics X-axis-leading-spaces
        &optional horizontal-step)
       "Imprime la líneas de números X-axis"
       (let ((number X-axis-label-spacing)
             (horizontal-step (or horizontal-step 1)))
         (insert X-axis-leading-spaces)
         ;; Elimina espacios extra de guía.
         (delete-char
          (- (1-
              (length (number-to-string horizontal-step)))))
         (insert (concat
                  (make-string
                   ;; Inserta espacio en blanco.
                   (-  (* symbol-width
                          X-axis-label-spacing)
                       (1-
                        (length
                         (number-to-string horizontal-step)))
                       2)
                   ? )
                  (number-to-string
                   (* number horizontal-step))))
         ;; Insertar los números que permanecen.
         (setq number (+ number X-axis-label-spacing))
         (while (> number-of-X-tics 1)
           (insert (X-axis-element
                    (* number horizontal-step)))
           (setq number (+ number X-axis-label-spacing))
           (setq number-of-X-tics (1- number-of-X-tics)))))

   Si se está leyendo esto en Info, se pueden ver las nuevas versiones
‘print-X-axis’ y ‘print-graph’ y los evaluarlas.  Si se está leyendo
esto en un libro impreso, se pueden ver las líneas cambiadas aquí (el
texto completo es mucho para imprimir).

     (defun print-X-axis (numbers-list horizontal-step)
       "Imprime etiquetas del eje X a la longitud de NUMBERS-LIST.
     Opcionalmente, HORIZONTAL-STEP, un entero positivo,
     especifica cuanto una etiqueta del eje X incrementa
     cada columna."
     ;; Valor del símbolo symbol-width and full-Y-label-width
     ;; se pasan por `print-graph'.
       (let* ((leading-spaces
               (make-string full-Y-label-width ? ))
            ;; symbol-width is provided by graph-body-print
            (tic-width (* symbol-width X-axis-label-spacing))
            (X-length (length numbers-list))
            (X-tic
             (concat
              (make-string
               ;; Crea una cadena de espacios en blanco.
               (-  (* symbol-width X-axis-label-spacing)
                   (length X-axis-tic-symbol))
               ? )
              ;; Concatena espacios en blanco con el
              símbolo tic.
              X-axis-tic-symbol))
            (tic-number
             (if (zerop (% X-length tic-width))
                 (/ X-length tic-width)
               (1+ (/ X-length tic-width)))))

         (print-X-axis-tic-line
          tic-number leading-spaces X-tic)
         (insert "\n")
         (print-X-axis-numbered-line
          tic-number leading-spaces horizontal-step)))

     (defun print-graph
       (numbers-list &optional vertical-step horizontal-step)
       "Imprime el gráfico de barras etiquetada de los NUMBERS-LIST.
     Los numbers-list consisten en los valores del eje Y."

     Opcionalmente, VERTICAL-STEP, un entero positivo, especifica cuanto un
     eje Y se incrementa por cada línea. Por ejemplo, un paso
     de 5 significa que cada fila es de cinco unidades.

     Opcionalmente, HORIZONTAL-STEP, un entero positivo,
     especifica cuanto se incrementa en un eje X cada columna."
       (let* ((symbol-width (length graph-blank))
              ;; height es ambos el número más largo
              ;; y el número con la mayoría de los dígitos.
              (height (apply 'max numbers-list))
              (height-of-top-line
               (if (zerop (% height Y-axis-label-spacing))
                   height
                 ;; else
                 (* (1+ (/ height Y-axis-label-spacing))
                    Y-axis-label-spacing)))
              (vertical-step (or vertical-step 1))
              (full-Y-label-width
               (length
                (concat
                 (number-to-string
                  (* height-of-top-line vertical-step))
                 Y-axis-tic))))
         (print-Y-axis
          height-of-top-line full-Y-label-width vertical-step)
         (graph-body-print
             numbers-list height-of-top-line symbol-width)
         (print-X-axis numbers-list horizontal-step)))


File: emacs-lisp-intro-es.info,  Node: Grafo impreso final,  Prev: Otro Error,  Up: Imprimir Grafo Entero

C.4.6 El gráfico impreso
------------------------

Cuando esté hecho e instalado, se puede llamar al comando ‘print-graph’
como esto:

     (print-graph fiftieth-list-for-graph 50 10)

Aquí está el gráfico:


     1000 -  *
             **
             **
             **
             **
      750 -  ***
             ***
             ***
             ***
             ****
      500 - *****
            ******
            ******
            ******
            *******
      250 - ********
            *********                     *
            ***********                   *
            *************                 *
       50 - ***************** *           *
            |   |    |    |    |    |    |    |
           10  50  100  150  200  250  300  350



El grupo largo de funciones contienen de 10 a 19 palabras y símbolos.


File: emacs-lisp-intro-es.info,  Node: Software Libre y Manuales Libres,  Next: GNU Free Documentation License,  Prev: Grafo completo,  Up: Top

Apéndice D Software Libre y Manuales Libres
*******************************************

*por Richard M. Stallman*

   La mayor deficiencia en sistemas operativos libres no está en el
software -- es la falta de buenos manuales libres que se puedan incluir
en estos sistemas.  Muchos de nuestros programas más importantes no
vienen con manuales completos.  La documentación es una parte esencial
de cualquier paquete de software; cuando un paquete de software libre no
viene con un manual libre, es una brecha mayor.  Nosotros tenemos muchas
brechas hoy.

   Érase una vez, hace muchos años, se piensa que aprendería Perl.  Se
tiene una copia de un manual libre, pero se encontró difícil de leer.
Cuando pregunto a los usuarios de Perl acerca de alternativas, me
contaron que serían mejor los manuales introductorios -- pero estos no
eran libres.

   ¿Por qué era esto?  Los autores de los buenos manuales los habían
escrito para O'Reilly Associates, que los publicaron con términos
restrictivos -- no copiando, no modificando, los ficheros fuentes están
disponibles -- que los excluyen desde la comunidad de software libre.

   No era la primera vez que esto ocurría, y (para nuestra comunidad es
una gran pérdida) eso está lejos desde el último.  Las editoriales de
manuales privativos han logrado que muchos autores restrinjan sus
manuales desde entonces.  Muchas veces se ha oido que un usuario de GNU
hábil me cuente que un manual que está escribiendo, con el que él espera
ayudar al proyecto GNU -- y entonces tenía mis esperanzas frustradas,
como se ha procedió a explicar que él tenía que haber firmado un
contrato con una editorial que restringiría eso, así que no puede
usarlo.

   Debido a que escribir buen inglés es una habilidad rara entre
programadores, se pueden perder manuales por este motivo.

   La documentación, como el software, es una cuestión de libertad, no
de precio.  El problema con estos manuales no eran que O'Reilly
Associates impusiera un precio por las copias impresas -- que en sí
estaban bien.  La Free Software Foundation _Fundación por el Software
Libre_ vende copias impresas (http://shop.fsf.org) de manuales libres de
GNU (http://www.gnu.org/doc/doc.html), también.  Pero los manuales de
GNU están disponibles en forma de código fuente, mientras que estos
manuales están disponibles solo en papel.  Los manuales de GNU vienen
con permiso para copiar y modificar; los manuales de Perl no.  Estas
restricciones son un problema.

   El criterio para un manual libre es parecido al del software libre:
es una cuestión de dar a todos los usuarios ciertas libertades.  La
redistribución (incluyendo redistribución comercial) debe ser permitida,
así el manual puede acompañar cada copia del programa, en líne o en
papel.  El permiso para modificar es crucial también.

   Como regla general, no se cree que sea esencial para la gente tener
permisos para modificar todas las partes de artículos y libro.  Las
cuestiones para escritos no son necesariamente las mismas como estas
para el software.  Por ejemplo, no se sabe si se está obligado a dar
permisos para modificar artículos como este, que describen nuestras
acciones y nuestras vistas.

   Pero hay una razón particular de por qué la libertad de modificar es
crucial para la documentación de software libre.  Cuando las personas
ejercita su derecho a modificar el software, y añadir o cambiar sus
funcionalidades, si son consciente ellos cambiarán el manual también --
así se puede proveer documentación usable y cuidada con el programa
modificado.  Un manual que prohibe a los programadores ser consciente y
finalizar el trabajo, o más precisamente requiere escribir un nuevo
manual desde cero si ellos cambian el programa, no se ajusta a las
necesidades de nuestra comunidad.

   Mientras una serie de prohibiciones en la modificación es
inaceptable, algunos tipos de límites en el método de modificar no tiene
tanto problema.  Por ejemplo, los requisitos para preservar la noticia
de autores del copyright, los términos de distribución, o la lista de
autores, estén ok.  Eso es también no da problemas para requerir
versiones modificadas para incluir notificar que fueron modificadas,
incluso tienen secciones enteras que puede no ser eliminadas o
cambiadas, tan largo como estas secciones tratan con asuntos no
técnicos.  (Algunos manuales de GNU los tienen).

   Estos tipos de restricciones no son un problema porque, como materia
práctica, no para al programador consciente desde la adaptación del
manual para ajustar el programa modificado.  En otras palabras, no se
bloquea la comunidad del software libre haciendo el uso completo del
manual.

   Sin embargo, debe ser posible modificar todo el contenido técnico del
manual, y entonces se distribuye el resultado en todos los medios
usuales, a través de todos los canales usuales; de otro modo, las
restricciones bloquean la comunidad, el manual no es libre, y así no se
necesita otro manual.

   Desafortunadamente, con frecuencia es duro encontrar a alguien a
escribir otro manual cuando un manual privativo.  El obstáculo es que
muchos usuario piensan que un manual privativo es suficientemente bueno
-- así ellos no ven la necesidad de escribir un manual libre.  Ellos no
ven que el sistema operativo tiene un gazapo que necesita se rellenado.

   ¿Por qué los usuarios piensan que los manuales privativos son
suficientemente buenos?  Algunos no han considerado la cuestión.  Espero
que este artículo hará alguna cosa para cambiar esto.

   Otros usuarios considera manuales privativos aceptables para la misma
razón así muchas personas software privativo aceptable: ellos judgan en
términos puramente prácticos, no usando la liberta como un criterio.
Estas personas son tituladas a sus opiniones, pero desde que estas
opciones crezcan desde valores que no incluyen libertad, ellas no están
guiadas por esto quienes valoran la libertad.

   Por favor, populariza esta cuestión.  Se continúa a perder manuales
para publicación privativa.  Si se populariza que los manuales
privativos no son suficientes, quizás la siguiente persona que quiere
ayudar a GNU escribiendo documentación realizará, antes de que sea
demasiado tarde, lo que él debe que todo sea libre.

   Se puede también animar editoriales comerciales a vender manuales
libres o con copyleft en vez de uno privativo.  Un camino que se puede
ayudar esto chequea los términos de la distribución de un manual antes
de que se compre, y preferimos manuales copyleft a los no copyleft.



Note: La Fundación para el Software Libre mantiene una página en su
sitio Web que liste libros libres disponibles desde otras editoriales:
<http://www.gnu.org/doc/other-free-books.html>


File: emacs-lisp-intro-es.info,  Node: GNU Free Documentation License,  Next: Índice,  Prev: Software Libre y Manuales Libres,  Up: Top

Apéndice E GNU Free Documentation License
*****************************************

                     Version 1.3, 3 November 2008

     Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
     <http://fsf.org/>

     Everyone is permitted to copy and distribute verbatim copies
     of this license document, but changing it is not allowed.

  0. PREAMBLE

     The purpose of this License is to make a manual, textbook, or other
     functional and useful document “free” in the sense of freedom: to
     assure everyone the effective freedom to copy and redistribute it,
     with or without modifying it, either commercially or
     noncommercially.  Secondarily, this License preserves for the
     author and publisher a way to get credit for their work, while not
     being considered responsible for modifications made by others.

     This License is a kind of "copyleft", which means that derivative
     works of the document must themselves be free in the same sense.
     It complements the GNU General Public License, which is a copyleft
     license designed for free software.

     We have designed this License in order to use it for manuals for
     free software, because free software needs free documentation: a
     free program should come with manuals providing the same freedoms
     that the software does.  But this License is not limited to
     software manuals; it can be used for any textual work, regardless
     of subject matter or whether it is published as a printed book.  We
     recommend this License principally for works whose purpose is
     instruction or reference.

  1. APPLICABILITY AND DEFINITIONS

     This License applies to any manual or other work, in any medium,
     that contains a notice placed by the copyright holder saying it can
     be distributed under the terms of this License.  Such a notice
     grants a world-wide, royalty-free license, unlimited in duration,
     to use that work under the conditions stated herein.  The
     "Document", below, refers to any such manual or work.  Any member
     of the public is a licensee, and is addressed as "you".  You accept
     the license if you copy, modify or distribute the work in a way
     requiring permission under copyright law.

     A "Modified Version" of the Document means any work containing the
     Document or a portion of it, either copied verbatim, or with
     modifications and/or translated into another language.

     A "Secondary Section" is a named appendix or a front-matter section
     of the Document that deals exclusively with the relationship of the
     publishers or authors of the Document to the Document's overall
     subject (or to related matters) and contains nothing that could
     fall directly within that overall subject.  (Thus, if the Document
     is in part a textbook of mathematics, a Secondary Section may not
     explain any mathematics.)  The relationship could be a matter of
     historical connection with the subject or with related matters, or
     of legal, commercial, philosophical, ethical or political position
     regarding them.

     The "Invariant Sections" are certain Secondary Sections whose
     titles are designated, as being those of Invariant Sections, in the
     notice that says that the Document is released under this License.
     If a section does not fit the above definition of Secondary then it
     is not allowed to be designated as Invariant.  The Document may
     contain zero Invariant Sections.  If the Document does not identify
     any Invariant Sections then there are none.

     The "Cover Texts" are certain short passages of text that are
     listed, as Front-Cover Texts or Back-Cover Texts, in the notice
     that says that the Document is released under this License.  A
     Front-Cover Text may be at most 5 words, and a Back-Cover Text may
     be at most 25 words.

     A "Transparent" copy of the Document means a machine-readable copy,
     represented in a format whose specification is available to the
     general public, that is suitable for revising the document
     straightforwardly with generic text editors or (for images composed
     of pixels) generic paint programs or (for drawings) some widely
     available drawing editor, and that is suitable for input to text
     formatters or for automatic translation to a variety of formats
     suitable for input to text formatters.  A copy made in an otherwise
     Transparent file format whose markup, or absence of markup, has
     been arranged to thwart or discourage subsequent modification by
     readers is not Transparent.  An image format is not Transparent if
     used for any substantial amount of text.  A copy that is not
     "Transparent" is called "Opaque".

     Examples of suitable formats for Transparent copies include plain
     ASCII without markup, Texinfo input format, LaTeX input format,
     SGML or XML using a publicly available DTD, and standard-conforming
     simple HTML, PostScript or PDF designed for human modification.
     Examples of transparent image formats include PNG, XCF and JPG.
     Opaque formats include proprietary formats that can be read and
     edited only by proprietary word processors, SGML or XML for which
     the DTD and/or processing tools are not generally available, and
     the machine-generated HTML, PostScript or PDF produced by some word
     processors for output purposes only.

     The "Title Page" means, for a printed book, the title page itself,
     plus such following pages as are needed to hold, legibly, the
     material this License requires to appear in the title page.  For
     works in formats which do not have any title page as such, "Title
     Page" means the text near the most prominent appearance of the
     work's title, preceding the beginning of the body of the text.

     The "publisher" means any person or entity that distributes copies
     of the Document to the public.

     A section "Entitled XYZ" means a named subunit of the Document
     whose title either is precisely XYZ or contains XYZ in parentheses
     following text that translates XYZ in another language.  (Here XYZ
     stands for a specific section name mentioned below, such as
     "Acknowledgements", "Dedications", "Endorsements", or "History".)
     To "Preserve the Title" of such a section when you modify the
     Document means that it remains a section "Entitled XYZ" according
     to this definition.

     The Document may include Warranty Disclaimers next to the notice
     which states that this License applies to the Document.  These
     Warranty Disclaimers are considered to be included by reference in
     this License, but only as regards disclaiming warranties: any other
     implication that these Warranty Disclaimers may have is void and
     has no effect on the meaning of this License.

  2. VERBATIM COPYING

     You may copy and distribute the Document in any medium, either
     commercially or noncommercially, provided that this License, the
     copyright notices, and the license notice saying this License
     applies to the Document are reproduced in all copies, and that you
     add no other conditions whatsoever to those of this License.  You
     may not use technical measures to obstruct or control the reading
     or further copying of the copies you make or distribute.  However,
     you may accept compensation in exchange for copies.  If you
     distribute a large enough number of copies you must also follow the
     conditions in section 3.

     You may also lend copies, under the same conditions stated above,
     and you may publicly display copies.

  3. COPYING IN QUANTITY

     If you publish printed copies (or copies in media that commonly
     have printed covers) of the Document, numbering more than 100, and
     the Document's license notice requires Cover Texts, you must
     enclose the copies in covers that carry, clearly and legibly, all
     these Cover Texts: Front-Cover Texts on the front cover, and
     Back-Cover Texts on the back cover.  Both covers must also clearly
     and legibly identify you as the publisher of these copies.  The
     front cover must present the full title with all words of the title
     equally prominent and visible.  You may add other material on the
     covers in addition.  Copying with changes limited to the covers, as
     long as they preserve the title of the Document and satisfy these
     conditions, can be treated as verbatim copying in other respects.

     If the required texts for either cover are too voluminous to fit
     legibly, you should put the first ones listed (as many as fit
     reasonably) on the actual cover, and continue the rest onto
     adjacent pages.

     If you publish or distribute Opaque copies of the Document
     numbering more than 100, you must either include a machine-readable
     Transparent copy along with each Opaque copy, or state in or with
     each Opaque copy a computer-network location from which the general
     network-using public has access to download using public-standard
     network protocols a complete Transparent copy of the Document, free
     of added material.  If you use the latter option, you must take
     reasonably prudent steps, when you begin distribution of Opaque
     copies in quantity, to ensure that this Transparent copy will
     remain thus accessible at the stated location until at least one
     year after the last time you distribute an Opaque copy (directly or
     through your agents or retailers) of that edition to the public.

     It is requested, but not required, that you contact the authors of
     the Document well before redistributing any large number of copies,
     to give them a chance to provide you with an updated version of the
     Document.

  4. MODIFICATIONS

     You may copy and distribute a Modified Version of the Document
     under the conditions of sections 2 and 3 above, provided that you
     release the Modified Version under precisely this License, with the
     Modified Version filling the role of the Document, thus licensing
     distribution and modification of the Modified Version to whoever
     possesses a copy of it.  In addition, you must do these things in
     the Modified Version:

       A. Use in the Title Page (and on the covers, if any) a title
          distinct from that of the Document, and from those of previous
          versions (which should, if there were any, be listed in the
          History section of the Document).  You may use the same title
          as a previous version if the original publisher of that
          version gives permission.

       B. List on the Title Page, as authors, one or more persons or
          entities responsible for authorship of the modifications in
          the Modified Version, together with at least five of the
          principal authors of the Document (all of its principal
          authors, if it has fewer than five), unless they release you
          from this requirement.

       C. State on the Title page the name of the publisher of the
          Modified Version, as the publisher.

       D. Preserve all the copyright notices of the Document.

       E. Add an appropriate copyright notice for your modifications
          adjacent to the other copyright notices.

       F. Include, immediately after the copyright notices, a license
          notice giving the public permission to use the Modified
          Version under the terms of this License, in the form shown in
          the Addendum below.

       G. Preserve in that license notice the full lists of Invariant
          Sections and required Cover Texts given in the Document's
          license notice.

       H. Include an unaltered copy of this License.

       I. Preserve the section Entitled "History", Preserve its Title,
          and add to it an item stating at least the title, year, new
          authors, and publisher of the Modified Version as given on the
          Title Page.  If there is no section Entitled "History" in the
          Document, create one stating the title, year, authors, and
          publisher of the Document as given on its Title Page, then add
          an item describing the Modified Version as stated in the
          previous sentence.

       J. Preserve the network location, if any, given in the Document
          for public access to a Transparent copy of the Document, and
          likewise the network locations given in the Document for
          previous versions it was based on.  These may be placed in the
          "History" section.  You may omit a network location for a work
          that was published at least four years before the Document
          itself, or if the original publisher of the version it refers
          to gives permission.

       K. For any section Entitled "Acknowledgements" or "Dedications",
          Preserve the Title of the section, and preserve in the section
          all the substance and tone of each of the contributor
          acknowledgements and/or dedications given therein.

       L. Preserve all the Invariant Sections of the Document, unaltered
          in their text and in their titles.  Section numbers or the
          equivalent are not considered part of the section titles.

       M. Delete any section Entitled "Endorsements".  Such a section
          may not be included in the Modified Version.

       N. Do not retitle any existing section to be Entitled
          "Endorsements" or to conflict in title with any Invariant
          Section.

       O. Preserve any Warranty Disclaimers.

     If the Modified Version includes new front-matter sections or
     appendices that qualify as Secondary Sections and contain no
     material copied from the Document, you may at your option designate
     some or all of these sections as invariant.  To do this, add their
     titles to the list of Invariant Sections in the Modified Version's
     license notice.  These titles must be distinct from any other
     section titles.

     You may add a section Entitled "Endorsements", provided it contains
     nothing but endorsements of your Modified Version by various
     parties--for example, statements of peer review or that the text
     has been approved by an organization as the authoritative
     definition of a standard.

     You may add a passage of up to five words as a Front-Cover Text,
     and a passage of up to 25 words as a Back-Cover Text, to the end of
     the list of Cover Texts in the Modified Version.  Only one passage
     of Front-Cover Text and one of Back-Cover Text may be added by (or
     through arrangements made by) any one entity.  If the Document
     already includes a cover text for the same cover, previously added
     by you or by arrangement made by the same entity you are acting on
     behalf of, you may not add another; but you may replace the old
     one, on explicit permission from the previous publisher that added
     the old one.

     The author(s) and publisher(s) of the Document do not by this
     License give permission to use their names for publicity for or to
     assert or imply endorsement of any Modified Version.

  5. COMBINING DOCUMENTS

     You may combine the Document with other documents released under
     this License, under the terms defined in section 4 above for
     modified versions, provided that you include in the combination all
     of the Invariant Sections of all of the original documents,
     unmodified, and list them all as Invariant Sections of your
     combined work in its license notice, and that you preserve all
     their Warranty Disclaimers.

     The combined work need only contain one copy of this License, and
     multiple identical Invariant Sections may be replaced with a single
     copy.  If there are multiple Invariant Sections with the same name
     but different contents, make the title of each such section unique
     by adding at the end of it, in parentheses, the name of the
     original author or publisher of that section if known, or else a
     unique number.  Make the same adjustment to the section titles in
     the list of Invariant Sections in the license notice of the
     combined work.

     In the combination, you must combine any sections Entitled
     "History" in the various original documents, forming one section
     Entitled "History"; likewise combine any sections Entitled
     "Acknowledgements", and any sections Entitled "Dedications".  You
     must delete all sections Entitled "Endorsements."

  6. COLLECTIONS OF DOCUMENTS

     You may make a collection consisting of the Document and other
     documents released under this License, and replace the individual
     copies of this License in the various documents with a single copy
     that is included in the collection, provided that you follow the
     rules of this License for verbatim copying of each of the documents
     in all other respects.

     You may extract a single document from such a collection, and
     distribute it individually under this License, provided you insert
     a copy of this License into the extracted document, and follow this
     License in all other respects regarding verbatim copying of that
     document.

  7. AGGREGATION WITH INDEPENDENT WORKS

     A compilation of the Document or its derivatives with other
     separate and independent documents or works, in or on a volume of a
     storage or distribution medium, is called an "aggregate" if the
     copyright resulting from the compilation is not used to limit the
     legal rights of the compilation's users beyond what the individual
     works permit.  When the Document is included in an aggregate, this
     License does not apply to the other works in the aggregate which
     are not themselves derivative works of the Document.

     If the Cover Text requirement of section 3 is applicable to these
     copies of the Document, then if the Document is less than one half
     of the entire aggregate, the Document's Cover Texts may be placed
     on covers that bracket the Document within the aggregate, or the
     electronic equivalent of covers if the Document is in electronic
     form.  Otherwise they must appear on printed covers that bracket
     the whole aggregate.

  8. TRANSLATION

     Translation is considered a kind of modification, so you may
     distribute translations of the Document under the terms of section
     4.  Replacing Invariant Sections with translations requires special
     permission from their copyright holders, but you may include
     translations of some or all Invariant Sections in addition to the
     original versions of these Invariant Sections.  You may include a
     translation of this License, and all the license notices in the
     Document, and any Warranty Disclaimers, provided that you also
     include the original English version of this License and the
     original versions of those notices and disclaimers.  In case of a
     disagreement between the translation and the original version of
     this License or a notice or disclaimer, the original version will
     prevail.

     If a section in the Document is Entitled "Acknowledgements",
     "Dedications", or "History", the requirement (section 4) to
     Preserve its Title (section 1) will typically require changing the
     actual title.

  9. TERMINATION

     You may not copy, modify, sublicense, or distribute the Document
     except as expressly provided under this License.  Any attempt
     otherwise to copy, modify, sublicense, or distribute it is void,
     and will automatically terminate your rights under this License.

     However, if you cease all violation of this License, then your
     license from a particular copyright holder is reinstated (a)
     provisionally, unless and until the copyright holder explicitly and
     finally terminates your license, and (b) permanently, if the
     copyright holder fails to notify you of the violation by some
     reasonable means prior to 60 days after the cessation.

     Moreover, your license from a particular copyright holder is
     reinstated permanently if the copyright holder notifies you of the
     violation by some reasonable means, this is the first time you have
     received notice of violation of this License (for any work) from
     that copyright holder, and you cure the violation prior to 30 days
     after your receipt of the notice.

     Termination of your rights under this section does not terminate
     the licenses of parties who have received copies or rights from you
     under this License.  If your rights have been terminated and not
     permanently reinstated, receipt of a copy of some or all of the
     same material does not give you any rights to use it.

  10. FUTURE REVISIONS OF THIS LICENSE

     The Free Software Foundation may publish new, revised versions of
     the GNU Free Documentation License from time to time.  Such new
     versions will be similar in spirit to the present version, but may
     differ in detail to address new problems or concerns.  See
     <http://www.gnu.org/copyleft/>.

     Each version of the License is given a distinguishing version
     number.  If the Document specifies that a particular numbered
     version of this License "or any later version" applies to it, you
     have the option of following the terms and conditions either of
     that specified version or of any later version that has been
     published (not as a draft) by the Free Software Foundation.  If the
     Document does not specify a version number of this License, you may
     choose any version ever published (not as a draft) by the Free
     Software Foundation.  If the Document specifies that a proxy can
     decide which future versions of this License can be used, that
     proxy's public statement of acceptance of a version permanently
     authorizes you to choose that version for the Document.

  11. RELICENSING

     "Massive Multiauthor Collaboration Site" (or "MMC Site") means any
     World Wide Web server that publishes copyrightable works and also
     provides prominent facilities for anybody to edit those works.  A
     public wiki that anybody can edit is an example of such a server.
     A "Massive Multiauthor Collaboration" (or "MMC") contained in the
     site means any set of copyrightable works thus published on the MMC
     site.

     "CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0
     license published by Creative Commons Corporation, a not-for-profit
     corporation with a principal place of business in San Francisco,
     California, as well as future copyleft versions of that license
     published by that same organization.

     "Incorporate" means to publish or republish a Document, in whole or
     in part, as part of another Document.

     An MMC is "eligible for relicensing" if it is licensed under this
     License, and if all works that were first published under this
     License somewhere other than this MMC, and subsequently
     incorporated in whole or in part into the MMC, (1) had no cover
     texts or invariant sections, and (2) were thus incorporated prior
     to November 1, 2008.

     The operator of an MMC Site may republish an MMC contained in the
     site under CC-BY-SA on the same site at any time before August 1,
     2009, provided the MMC is eligible for relicensing.

ADDENDUM: How to use this License for your documents
====================================================

To use this License in a document you have written, include a copy of
the License in the document and put the following copyright and license
notices just after the title page:

       Copyright (C)  YEAR  YOUR NAME.
       Permission is granted to copy, distribute and/or modify this document
       under the terms of the GNU Free Documentation License, Version 1.3
       or any later version published by the Free Software Foundation;
       with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
       Texts.  A copy of the license is included in the section entitled ``GNU
       Free Documentation License''.

   If you have Invariant Sections, Front-Cover Texts and Back-Cover
Texts, replace the "with...Texts."  line with this:

         with the Invariant Sections being LIST THEIR TITLES, with
         the Front-Cover Texts being LIST, and with the Back-Cover Texts
         being LIST.

   If you have Invariant Sections without Cover Texts, or some other
combination of the three, merge those two alternatives to suit the
situation.

   If your document contains nontrivial examples of program code, we
recommend releasing these examples in parallel under your choice of free
software license, such as the GNU General Public License, to permit
their use in free software.


File: emacs-lisp-intro-es.info,  Node: Índice,  Next: Acerca del Autor,  Prev: GNU Free Documentation License,  Up: Top

Índice
******

[index]
* Menu:

* (debug) en código:                     debug-on-quit.       (line  13)
* * (multiplicación):                    defun.               (line 104)
* * para buffer solo lectura:            Búffer solo lectura. (line   6)
* *scratch* buffer:                      print-elements-of-list.
                                                              (line   9)
* / (division):                          El caso del buffer largo.
                                                              (line  37)
* % (función resto):                     Calcular un resto.   (line   6)
* <= (menos que igual):                  Partes Inc de Ejemplo.
                                                              (line  48)
* > (mayor que):                         if en más detalle.   (line  32)
* Acumular, tipo de patrón recursivo:    Acumular.            (line   6)
* add-hook:                              Texto y Autorelleno. (line  54)
* Alias de correo:                       Alias de correo.     (line  14)
* Almacenando y cortando texto:          Cortando y almacenando texto.
                                                              (line   6)
* Ampliando:                             Encogiendo y extendiendo.
                                                              (line   6)
* and:                                   Función kill-new.    (line 224)
* and <1>:                               fwd-para let.        (line  47)
* Anillo, creando un lista como un:      Kill Ring.           (line   6)
* append-to-buffer:                      append-to-buffer.    (line   6)
* apply:                                 Columnas de un grafo.
                                                              (line 150)
* apropos:                               Columnas de un grafo.
                                                              (line  34)
* Argumento como variable local:         Ejemplo Dec junto.   (line  27)
* argumento definido:                    Argumentos.          (line  15)
* Argumento, tipo incorrecto de:         Tipo incorrecto de argumento.
                                                              (line   6)
* Argumentos:                            Argumentos.          (line   6)
* Argumentos Opcionales:                 Argumentos opcionales.
                                                              (line  11)
* Argumentos, número variable de:        Número de variables de argumentos.
                                                              (line   6)
* Asignando tecla globalmente:           Atajos de teclado.   (line  20)
* Asignando valor de variable:           set y setq.          (line   6)
* Asignar tecla global:                  Atajos de teclado.   (line  20)
* Asociaciones, teclas, arreglando:      Miscelánea.          (line  89)
* Asterisco para búffer de solo lectura: Búffer solo lectura. (line   6)
* Atajos de Teclado, arreglando:         Miscelánea.          (line  89)
* Átomos Lisp:                           Átomos Lisp.         (line   6)
* autoload:                              Autocarga.           (line   6)
* Ayuda escribiendo listas:              Escribiendo listas.  (line   6)
* beginning-of-buffer:                   beginning-of-buffer. (line   6)
* bind se definió:                       set y setq.          (line   6)
* Borrando texto:                        Cortando y almacenando texto.
                                                              (line   6)
* Borrando texto <1>:                    Cortando y almacenando texto.
                                                              (line   6)
* Bucles:                                while.               (line   6)
* Bucles y recursión:                    Bucles y recursión.  (line   6)
* Búffer solo lectura:                   Búffer solo lectura. (line   6)
* buffer-file-name:                      Nombres de búffer.   (line   6)
* buffer-menu, asociado a tecla:         Atajos de teclado.   (line  73)
* buffer-name:                           Nombres de búffer.   (line   6)
* Buffer, historia de palabra:           Nombres de búffer.   (line  70)
* Búsquedas de expresiones regulares:    Buscar regexp.       (line   6)
* Búsquedas, ilustrando:                 Buscar regexp.       (line   6)
* C, una disgresión dentro:              Disgresión dentro de C.
                                                              (line   6)
* cadena definida:                       Átomos Lisp.         (line  68)
* cadena vacía definida:                 Revisar.             (line 141)
* Caja con cajones, metáfora para su símbolo: Símbolos como cajas.
                                                              (line   6)
* Cajones, Caja de, metáfora para un símbolo: Símbolos como cajas.
                                                              (line   6)
* Cambiando a un búffer:                 Cambiando búffers.   (line   6)
* Cambiando una definición de función:   Cambiar un defun.    (line   6)
* cancel-debug-on-entry:                 debug-on-entry.      (line  84)
* car, introducido:                      Car cdr y cons.      (line   6)
* Cargando ficheros:                     Cargando ficheros.   (line   6)
* Categorías de sintaxis y tablas:       Sintaxis.            (line   6)
* cdr, introducido:                      Car cdr y cons.      (line   6)
* Código de instalación:                 Instalación Permanente.
                                                              (line   6)
* Código Permanente de Instalación:      Instalación Permanente.
                                                              (line   6)
* comando definido:                      Cómo evaluar.        (line  11)
* Comentarios en Código Lisp:            Cambiar un defun.    (line  23)
* Common Lisp:                           Historia de Lisp.    (line  11)
* compare-windows:                       Atajos de teclado.   (line  11)
* Compilando Byte:                       Compilación de bytes.
                                                              (line   6)
* concatenar:                            Tipos de datos.      (line  11)
* cond:                                  Recursión con cond.  (line   6)
* Condicional con if:                    if.                  (line   6)
* Condicional marcarán estas dos versiones de Emacs: Extensión simple.
                                                              (line  38)
* condition-case:                        condition-case.      (line   6)
* Configurando una tecla globalmente:    Atajos de teclado.   (line  20)
* cons, introducido:                     cons.                (line   6)
* Construyendo Etiquetas en las fuentes Emacs: etags.         (line  88)
* Construyendo robots:                   Construyendo robots. (line   6)
* Contando:                              Contando.            (line   6)
* Contando las palabras en un defun:     Palabras en una función.
                                                              (line   6)
* Contando palabras en un defun:         Palabras en una función.
                                                              (line   6)
* Contando palabras en un defun <1>:     count-words-in-defun.
                                                              (line   6)
* Convención formateando:                append save-excursion.
                                                              (line  16)
* Copiando texto:                        Cortando y almacenando texto.
                                                              (line   6)
* copy-region-as-kill:                   copy-region-as-kill. (line   6)
* copy-to-buffer:                        copy-to-buffer.      (line   6)
* Cortando texto:                        Cortando y almacenando texto.
                                                              (line   6)
* Cortando y almacenando texto:          Cortando y almacenando texto.
                                                              (line   6)
* count-words-example:                   count-words-example. (line   6)
* count-words-in-defun:                  count-words-in-defun.
                                                              (line  98)
* crear etiquetas:                       etags.               (line  88)
* Cuenta palabras recursivamente:        recursive-count-words.
                                                              (line   6)
* Cuerpo de grafo:                       Leyendo un grafo.    (line   6)
* cuerpo definido:                       defun.               (line  40)
* current-buffer:                        Obteniendo búffers.  (line   6)
* current-kill:                          current-kill.        (line   6)
* debug-on-entry:                        debug-on-entry.      (line   6)
* debug-on-quit:                         debug-on-quit.       (line   9)
* defconst:                              defcustom.           (line 138)
* defcustom:                             defcustom.           (line   6)
* Definición de Función, como cambiar:   Cambiar un defun.    (line   6)
* Definición de la instalación:          Instalar.            (line   6)
* Definición de la Instalación de Función: Instalar.          (line   6)
* definición de punto:                   Tamaño de búffer y localizaciones.
                                                              (line  20)
* definición función definida:           defun.               (line   6)
* Definición, cómo cambiar:              Cambiar un defun.    (line   6)
* defsubst:                              defcustom.           (line 138)
* defun:                                 defun.               (line   6)
* defvar:                                defvar.              (line   6)
* defvar con un asterisco:               defvar y asterisk.   (line   6)
* defvar para una variable personalizable: defvar y asterisk. (line   6)
* delete-and-extract-region:             Disgresión dentro de C.
                                                              (line   6)
* Depurador de nivel de código:          edebug.              (line   6)
* depurando:                             Depurando.           (line   6)
* depurar:                               depurar.             (line   6)
* Desasociar Tecla a Comando:            Atajos de teclado.   (line  61)
* describe-function:                     simplified-beginning-of-buffer.
                                                              (line  79)
* describe-function, introducido:        Encontrando más.     (line   6)
* Diferir en recursión:                  Sin Aplazar.         (line   6)
* directory-files:                       Listar ficheros.     (line  13)
* Disgresión dentro de C:                Disgresión dentro de C.
                                                              (line   6)
* Disociando la tecla:                   Atajos de teclado.   (line  61)
* División:                              El caso del buffer largo.
                                                              (line  37)
* dolist:                                dolist.              (line   6)
* dotimes:                               dotimes.             (line   6)
* edebug:                                edebug.              (line   6)
* efecto lateral definido:               Cómo el intérprete actúa.
                                                              (line  16)
* Ejecuta un programa:                   Ejecutar un programa.
                                                              (line   6)
* Ejemplo de Expresión let:              Ejemplo de expresión let.
                                                              (line   6)
* Ejes, imprime horizontal:              print-X-axis.        (line   6)
* Ejes, imprimir vertical:               print-Y-axis.        (line   6)
* Else:                                  else.                (line   6)
* Encogiendo:                            Encogiendo y extendiendo.
                                                              (line   6)
* Encontrar documentación de la función: Encontrando más.     (line   6)
* Encontrar la fuente de la función:     Encontrando más.     (line  14)
* Encontrar un fichero:                  Encontrar un fichero.
                                                              (line   6)
* eobp:                                  fwd-para while.      (line  61)
* eq:                                    Revisar.             (line 126)
* eq (ejemplo de uso):                   last-command & this-command.
                                                              (line  36)
* equal:                                 Revisar.             (line 126)
* error:                                 Cuerpo de current-kill.
                                                              (line  40)
* Error para símbolo sin función:        Función vacía.       (line   6)
* Error para símbolo sin valor:          Variable vacía.      (line   6)
* Error, del tipo más insidioso:         Otro Error.          (line   6)
* Escribiendo la Definición:             Escribiendo funciones.
                                                              (line   6)
* Escribiendo la Definición de Función:  Escribiendo funciones.
                                                              (line   6)
* Escribiendo una definición función:    Escribiendo funciones.
                                                              (line   6)
* Espacio en blanco en listas:           Espacios en blanco en listas.
                                                              (line   6)
* etags:                                 etags.               (line   6)
* Etiquetas en las fuentes Emacs:        etags.               (line  88)
* Evaluación:                            Evaluación.          (line   6)
* Evaluación de listas internas:         Evaluando listas propias.
                                                              (line   6)
* Evaluación práctica:                   Practicando evaluación.
                                                              (line   6)
* Evaluando listas internas:             Evaluando listas propias.
                                                              (line   6)
* Every, tipo de patrón recursivo:       Cada.                (line   6)
* expresión definida:                    Átomos Lisp.         (line  26)
* expresión let, partes de:              Partes de la expresión let.
                                                              (line   6)
* expresión simple let:                  Ejemplo de expresión let.
                                                              (line   6)
* Expresiones regulares para contar palabras: Contando palabras.
                                                              (line   6)
* Expresiones simbólicas, introducidas:  Átomos Lisp.         (line  26)
* Extendiendo, ejemplo de:               what-line.           (line   6)
* Extensión simple en fichero .emacs:    Extensión simple.    (line   6)
* Falsedad y verdad en Emacs Lisp:       Verdad y falsedad.   (line   6)
* FDL, GNU Free Documentation License:   GNU Free Documentation License.
                                                              (line   6)
* fichero .emacs:                        Inicialización de Emacs.
                                                              (line   6)
* fichero .emacs, empezando:             Empezando un fichero .emacs.
                                                              (line   6)
* fichero de inicio default.el:          Site-wide Init.      (line   6)
* fichero de TAGS, crea el propio:       etags.               (line   6)
* Fichero inicialización:                Inicialización de Emacs.
                                                              (line   6)
* fichero inicio site-init.el:           Site-wide Init.      (line   6)
* fichero ring.el:                       fichero anillo.      (line   6)
* fichero site-load.el:                  Site-wide Init.      (line   6)
* files-in-below-directory:              Listar ficheros.     (line  25)
* fill-column, una variable de ejemplo:  Ejemplo de rellenar columna.
                                                              (line   6)
* filter-buffer-substring:               last-command & this-command.
                                                              (line  29)
* find-tag:                              Encontrando más.     (line  40)
* Flores en un campo:                    Listas Lisp.         (line  18)
* Focalizando atención (encogiendo):     Encogiendo y extendiendo.
                                                              (line   6)
* forma definida:                        Átomos Lisp.         (line  26)
* Forma Especial:                        Complicaciones.      (line  12)
* Forma Especial de defun:               defun.               (line   6)
* Formateando ayuda:                     Escribiendo listas.  (line   6)
* Formato de Modo Línea:                 Mode Line.           (line   6)
* forward-paragraph:                     forward-paragraph.   (line   6)
* forward-sentence:                      forward-sentence.    (line   6)
* Frases, movimiento por:                Buscar regexp.       (line   6)
* Función Anónima:                       lambda.              (line   6)
* Función de palabras duplicadas:        the-the.             (line   6)
* función definida:                      Creando errores.     (line  49)
* función definida <1>:                  Creando errores.     (line  74)
* función interactiva definida:          Cómo evaluar.        (line  11)
* Función resto, %:                      Calcular un resto.   (line   6)
* Funciones Interactivas:                Interactive.         (line   6)
* Funciones primitivas:                  Funciones primitivas.
                                                              (line   6)
* Funciones, primitiva:                  Funciones primitivas.
                                                              (line   6)
* Genera un mensaje de error:            Creando errores.     (line   6)
* Generación de mensaje de Error:        Creando errores.     (line   6)
* global-set-key:                        Atajos de teclado.   (line  20)
* global-unset-key:                      Atajos de teclado.   (line  61)
* Grafo prototipo:                       Leyendo un grafo.    (line   6)
* Grafo, imprimiendo todo:               Imprimir Grafo Entero.
                                                              (line   6)
* graph-body-print:                      graph-body-print.    (line   6)
* graph-body-print Versión Final.:       La versión final.    (line  56)
* Historia de Lisp:                      Historia de Lisp.    (line   6)
* if:                                    if.                  (line   6)
* Imprime eje horizontal:                print-X-axis.        (line   6)
* Imprimiendo eje horizontal:            print-X-axis.        (line   6)
* imprimiendo eje X:                     print-X-axis.        (line   6)
* imprimiendo eje Y:                     print-Y-axis.        (line   6)
* Imprimiendo Ejes Verticales:           print-Y-axis.        (line   6)
* Imprimiendo el grafo entero:           Imprimir Grafo Entero.
                                                              (line   6)
* Imprimiendo el grafo entero <1>:       Imprimir Grafo Entero.
                                                              (line   6)
* Imprimir eje vertical:                 print-Y-axis.        (line   6)
* indent-tabs-mode:                      Indentar modo de tabulaciones.
                                                              (line   6)
* Indentaciń para formatear:             append save-excursion.
                                                              (line  16)
* Inicialización de Variable:            defvar.              (line   6)
* Inicializando una variable:            defvar.              (line   6)
* insert-buffer:                         insert-buffer.       (line   6)
* insert-buffer-substring:               resumen de append-to-buffer.
                                                              (line   6)
* insert-buffer, nueva versión del cuerpo: Nuevo insert-buffer.
                                                              (line   6)
* Insidioso tipo de error:               Otro Error.          (line   6)
* Instalar código permanentemente:       Instalación Permanente.
                                                              (line   6)
* Instalar una definición de función:    Instalar.            (line   6)
* interactive:                           Interactive.         (line   6)
* interactive, ejemplo de uso:           insert-buffer interactivo.
                                                              (line   6)
* Intérprete Lisp, explicada:            Ejecutar un programa.
                                                              (line  39)
* Intérprete Lisp, qué hace:             Interpréte Lisp.     (line   6)
* Intérprete, Lisp, explicado:           Ejecutar un programa.
                                                              (line  39)
* Intérprete, qué hace:                  Interpréte Lisp.     (line   6)
* Keep, el tipo de patrón recursivo:     Guardar.             (line   6)
* kill-append:                           Función kill-append. (line   6)
* kill-new:                              Función kill-new.    (line   6)
* kill-region:                           kill-region.         (line   6)
* lambda:                                lambda.              (line   6)
* length:                                length.              (line   6)
* lengths-list-file:                     lengths-list-file.   (line  12)
* lengths-list-many-files:               lengths-list-many-files.
                                                              (line  33)
* let:                                   let.                 (line   6)
* Leyendo un grafo:                      Leyendo un grafo.    (line   6)
* Librería, como término para 'fichero': Encontrando más.     (line  63)
* line-to-top-of-window:                 Extensión simple.    (line   6)
* list-buffers, reasociar:               Atajos de teclado.   (line  73)
* lista de argumentos definida:          defun.               (line  62)
* Lista de variables locales, por búffer,: Texto y Autorelleno.
                                                              (line  22)
* lista vacía definida:                  Átomos Lisp.         (line  18)
* Listas en un ordenador:                Implementación de listas.
                                                              (line   6)
* Listas Lisp:                           Listas Lisp.         (line   6)
* llamada definida:                      Cambiando búffers.   (line  54)
* load-library:                          Cargando ficheros.   (line  52)
* load-path:                             Cargando ficheros.   (line  36)
* Localización del Punto:                Tamaño de búffer y localizaciones.
                                                              (line   6)
* Localización del punto:                Tamaño de búffer y localizaciones.
                                                              (line   6)
* looking-at:                            fwd-para while.      (line  84)
* Maclisp:                               Historia de Lisp.    (line  11)
* Macro Lisp:                            Macro Lisp.          (line   6)
* Macro, lisp:                           Macro Lisp.          (line   6)
* make-string:                           Elemento del Eje Y.  (line  73)
* Manejando el anillo de la muerte:      Kill Ring.           (line   6)
* Manejando el anillo de la muerte <1>:  Kill Ring.           (line   6)
* Mapas de teclado:                      Mapas de teclado.    (line   6)
* mapcar:                                mapcar.              (line   6)
* marca:                                 save-excursion.      (line   6)
* mark-whole-buffer:                     mark-whole-buffer.   (line   6)
* match-beginning:                       fwd-para while.      (line 164)
* max:                                   Columnas de un grafo.
                                                              (line 138)
* message:                               message.             (line   6)
* min:                                   Columnas de un grafo.
                                                              (line 138)
* mode-line-format:                      Mode Line.           (line   6)
* Modo de autoajuste activado:           Texto y Autorelleno. (line  54)
* Modo de selección, automático:         Texto y Autorelleno. (line  22)
* Modo Texto activado:                   Texto y Autorelleno. (line  39)
* Mover frase y párrafo:                 Buscar regexp.       (line   6)
* narrowing definido:                    Tamaño de búffer y localizaciones.
                                                              (line  44)
* nil:                                   Verdad y falsedad.   (line   6)
* nil, historia de palabra:              Nombres de búffer.   (line  43)
* No aplazar la solución:                No aplazar la solución.
                                                              (line   6)
* Nombres de Símbolos:                   Nombres y definiciones.
                                                              (line   6)
* nreverse:                              Contando definiciones de función.
                                                              (line 103)
* nth:                                   nth.                 (line   6)
* nthcdr:                                nthcdr.              (line   6)
* nthcdr <1>:                            copy-region-as-kill. (line   6)
* nthcdr, ejemplo:                       Función kill-new.    (line 160)
* nueva versión cuerpo para insert-buffer: Nuevo insert-buffer.
                                                              (line   6)
* number-to-string:                      Elemento del Eje Y.  (line  13)
* Número variable de argumentos:         Número de variables de argumentos.
                                                              (line   6)
* occur:                                 Atajos de teclado.   (line  56)
* opcional:                              Argumentos opcionales.
                                                              (line  11)
* Opciones Interactive:                  Opciones de interactive..
                                                              (line   6)
* Opciones para interactive:             Opciones de interactive..
                                                              (line   6)
* or:                                    Insertar o.          (line  13)
* other-buffer:                          Obteniendo búffers.  (line   6)
* Palabra Clave:                         Argumentos opcionales.
                                                              (line  11)
* Palabras y símbolos en defun:          Palabras y Símbolos. (line   6)
* Palabras, contadas recursivamente:     recursive-count-words.
                                                              (line   6)
* Palabras, duplicadas:                  the-the.             (line   6)
* Párrafos, movimiento por:              Buscar regexp.       (line   6)
* parte-entonces definida:               if en más detalle.   (line   6)
* parte-si definida:                     if en más detalle.   (line   6)
* Partes de definición recursiva:        Partes de definición recursiva.
                                                              (line   6)
* Partes de la expresión let:            Partes de la expresión let.
                                                              (line   6)
* Partes de una Definición Recursiva:    Partes de definición recursiva.
                                                              (line   6)
* Pasando información para funciones:    Argumentos.          (line   6)
* Patrón recursivo: acumular:            Acumular.            (line   6)
* Patrón recursivo: every:               Cada.                (line   6)
* Patrón recursivo: keep:                Guardar.             (line   6)
* Patrones recursivos:                   Patrones recursivos. (line   6)
* Patrones, buscando por:                Buscar regexp.       (line   6)
* Pegando Texto:                         Pegando.             (line   6)
* pegar:                                 Pegando.             (line   6)
* pegar <1>:                             pegar.               (line   6)
* Personalizando tu fichero .emacs:      Inicialización de Emacs.
                                                              (line   6)
* Por búffer, lista de variables locales: Texto y Autorelleno.
                                                              (line  22)
* Practicando evaluación:                Practicando evaluación.
                                                              (line   6)
* Preservando punto, marca, y búffer:    save-excursion.      (line   6)
* Primitivas en lenguaje C:              Funciones primitivas.
                                                              (line   6)
* Primitivas escritas en C:              Funciones primitivas.
                                                              (line   6)
* print-elements-of-list:                print-elements-of-list.
                                                              (line   6)
* print-elements-recursively:            Recursión con lista. (line  23)
* print-graph varlist:                   print-graph Varlist. (line   6)
* print-graph Versión Final.:            La versión final.    (line  78)
* print-X-axis:                          Eje X marca tic.     (line 145)
* print-X-axis-numbered-line:            Eje X marca tic.     (line 115)
* print-X-axis-tic-line:                 Eje X marca tic.     (line  81)
* print-Y-axis:                          Penúltimo print-Y-axis.
                                                              (line   9)
* progn:                                 progn.               (line   6)
* Programa, ejecutando uno:              Ejecutar un programa.
                                                              (line   6)
* Propiedades, en el ejemplo del modo línea: Mode Line.       (line  68)
* Propiedades, mención de buffer-substring-no-properties: Ejercicio narrow.
                                                              (line  13)
* Prototipo de grafo:                    Leyendo un grafo.    (line   6)
* punto:                                 save-excursion.      (line   6)
* Punto, marca, preservación de búffer:  save-excursion.      (line   6)
* push, ejemplo:                         Función kill-new.    (line 125)
* re-search-forward:                     re-search-forward.   (line   6)
* Reasociando teclas:                    Mapas de teclado.    (line   6)
* Recuperando Texto:                     Pegando.             (line   6)
* Recuperar Texto:                       Pegando.             (line   6)
* Recursión:                             Recursión.           (line   6)
* Recursión sin diferir:                 Sin Aplazar.         (line   6)
* Recursión y bucles:                    Bucles y recursión.  (line   6)
* Recursivamente contando palabras:      recursive-count-words.
                                                              (line   6)
* recursive-count-words:                 recursive-count-words.
                                                              (line 261)
* recursive-graph-body-print:            recursive-graph-body-print.
                                                              (line   6)
* recursive-lengths-list-many-files:     Varios ficheros recursivamente.
                                                              (line  16)
* regexp-quote:                          fwd-para let.        (line  75)
* Región, qué es:                        save-excursion.      (line   6)
* Repetición (bucles):                   Bucles y recursión.  (line   6)
* Repetición para contar palabras:       Contando palabras.   (line   6)
* Resumen del Anillo de la Muerte _Kill ring_: Resumen del anillo de la muerte.
                                                              (line   6)
* reverse:                               Contando definiciones de función.
                                                              (line 118)
* Robots, construyendo:                  Construyendo robots. (line   6)
* save-excursion:                        save-excursion.      (line   6)
* save-restriction:                      save-restriction.    (line   6)
* se definió evaluate:                   Ejecutar un programa.
                                                              (line   6)
* search-forward:                        search-forward.      (line   6)
* Selección de modo automático:          Texto y Autorelleno. (line  22)
* sentence-end:                          sentence-end.        (line   6)
* set:                                   Usando set.          (line   6)
* set-buffer:                            Cambiando búffers.   (line   6)
* set-variable:                          defvar y asterisk.   (line  23)
* setcar:                                setcar.              (line   6)
* setcdr:                                setcdr.              (line   6)
* setcdr, ejemplo:                       Función kill-new.    (line 164)
* setq:                                  Usando setq.         (line   6)
* Símbolo sin función de error:          Función vacía.       (line   6)
* Símbolo sin valor de error:            Variable vacía.      (line   6)
* Símbolos como una caja con cajones:    Símbolos como cajas. (line   6)
* simplified-beginning-of-buffer:        simplified-beginning-of-buffer.
                                                              (line   6)
* Sin posponer la solución:              No aplazar la solución.
                                                              (line   6)
* Solución no pospuesta:                 No aplazar la solución.
                                                              (line   6)
* sort:                                  Ordenando.           (line   6)
* switch-to-buffer:                      Cambiando búffers.   (line   6)
* tabla TAGS, especificando:             Encontrando más.     (line  40)
* Tabuladores, previniendo:              Indentar modo de tabulaciones.
                                                              (line   6)
* Tamaño del búffer:                     Tamaño de búffer y localizaciones.
                                                              (line   6)
* Tamaño del Búffer:                     Tamaño de búffer y localizaciones.
                                                              (line   6)
* Teniendo un búffer:                    Obteniendo búffers.  (line   6)
* Texto entre comillas:                  Átomos Lisp.         (line  64)
* the-the:                               the-the.             (line   6)
* Tipo incorrecto de argumento:          Tipo incorrecto de argumento.
                                                              (line   6)
* Tipos de dato de los argumentos:       Tipos de datos.      (line   6)
* Tipos de datos:                        Tipos de datos.      (line   6)
* Tipos de datos <1>:                    Tipos de datos.      (line   6)
* top-of-ranges:                         Contando definiciones de función.
                                                              (line  20)
* triangle-bugged:                       depurar.             (line  14)
* triangle-recursively:                  Función recursiva triángulo.
                                                              (line   6)
* valor devuelto explicado:              Cómo el intérprete actúa.
                                                              (line   6)
* Variable de Ejemplo, fill-column:      Ejemplo de rellenar columna.
                                                              (line   6)
* variable global definida:              Determinando el elemento.
                                                              (line  91)
* variable local definida:               Prevenir confusión.  (line   6)
* Variable, asignando valor:             set y setq.          (line   6)
* Variable, ejemplo de, fill-column:     Ejemplo de rellenar columna.
                                                              (line   6)
* variable, global, definida:            Determinando el elemento.
                                                              (line  91)
* variable, local, definida:             Prevenir confusión.  (line   6)
* Variables:                             Variables.           (line   6)
* Variables let no inicializadas:        Variables let inicializadas.
                                                              (line   6)
* Variables let no inicializadas <1>:    Variables let inicializadas.
                                                              (line   6)
* varlist definida:                      Partes de la expresión let.
                                                              (line   6)
* Verdad y mentira en Emacs Lisp:        Verdad y falsedad.   (line   6)
* Versión de Emacs, eligiendo:           Extensión simple.    (line  38)
* Versión de Emacs, eligiendo <1>:       Extensión simple.    (line  38)
* what-line:                             what-line.           (line   6)
* while:                                 while.               (line   6)
* X-axis-element:                        Eje X marca tic.     (line 104)
* Y-axis-column:                         Y-axis-column.       (line  10)
* Y-axis-column Versión Final.:          La versión final.    (line  17)
* Y-axis-label-spacing:                  Calcular un resto.   (line  80)
* Y-axis-tic:                            Elemento del Eje Y.  (line  31)
* yank-pop:                              yank-pop.            (line   6)
* zap-to-char:                           zap-to-char.         (line   6)
* zerop:                                 Cuerpo de current-kill.
                                                              (line  40)


File: emacs-lisp-intro-es.info,  Node: Acerca del Autor,  Prev: Índice,  Up: Top

Acerca del Autor
****************

     Robert J. Chassell ha trabajado con GNU Emacs desde 1985.  Él
     escribe, edita y enseña Emacs y Emacs Lisp, y habla alrededor del
     mundo acerca de la libertad del software.  Chassell es Director
     fundador y Tesorero de la Fundación por el Software Libre (FSF). Él
     se graduó la Universidad de Cambridge, en Inglaterra.  Él tiene un
     interés contínuo en historia económica y social y vuela su propio
     aeroplano


Tag Table:
Node: Top1230
Node: Prefacio24976
Node: Por qué26438
Node: Leyendo este texto27150
Node: Quien eres29501
Node: Historia de Lisp32440
Node: Nota para principiantes33283
Node: Se agradece36006
Node: Procesamiento de listas36598
Ref: Procesamiento de listas-Footnote-138221
Node: Listas Lisp38430
Node: Listas de números39357
Node: Átomos Lisp40567
Node: Espacios en blanco en listas44631
Node: Escribiendo listas46025
Node: Ejecutar un programa47304
Node: Creando errores49922
Node: Nombres y definiciones55198
Node: Interpréte Lisp57294
Node: Complicaciones58401
Node: Compilación de bytes60014
Node: Evaluación61240
Node: Cómo el intérprete actúa61913
Node: Evaluando listas propias63316
Node: Variables66016
Node: Ejemplo de rellenar columna67686
Node: Función vacía69340
Node: Variable vacía70528
Node: Argumentos72362
Ref: Argumentos-Footnote-174123
Node: Tipos de datos74967
Node: Argumentos como variables o listas77056
Node: Número de variables de argumentos78739
Node: Tipo incorrecto de argumento79681
Ref: Tipo incorrecto de argumento-Footnote-183340
Node: message83416
Ref: message-Footnote-187399
Node: set y setq87608
Node: Usando set88370
Node: Usando setq90758
Node: Contando93126
Node: Resumen95176
Node: Ejercicios de mensajes de error97170
Node: Practicando evaluación97721
Node: Cómo evaluar99096
Node: Nombres de búffer100678
Node: Obteniendo búffers106869
Ref: Obteniendo búffers-Footnote-1109532
Node: Cambiando búffers109756
Ref: Cambiando búffers-Footnote-1113256
Ref: Cambiando búffers-Footnote-2113566
Node: Tamaño de búffer y localizaciones114224
Node: Ejercicio de evaluación116469
Node: Escribiendo funciones116799
Node: Funciones primitivas118314
Node: defun119577
Node: Instalar126620
Node: Efecto de instalación128101
Node: Cambiar un defun128962
Node: Interactive130873
Node: multiply-by-seven interactivo132007
Node: multiply-by-seven en detalle134037
Node: Opciones de interactive.136868
Node: Instalación Permanente140158
Node: let142400
Node: Prevenir confusión143863
Node: Partes de la expresión let145932
Node: Ejemplo de expresión let147639
Ref: Ejemplo de expresión let-Footnote-1149474
Node: Variables let inicializadas149749
Node: if151455
Node: if en más detalle152431
Node: tipo-de-animal en detalle155325
Node: else157959
Node: Verdad y falsedad161054
Node: nil explicado162036
Node: save-excursion164192
Node: Punto y marca165020
Node: Plantilla para save-excursion168171
Node: Revisar169499
Node: Ejercicios defun177724
Node: Un paseo a través de los búffers178182
Node: Encontrando más179427
Node: simplified-beginning-of-buffer183566
Node: mark-whole-buffer188256
Node: resumen de mark-whole-buffer189145
Node: Cuerpo de mark-whole-buffer190580
Node: append-to-buffer193884
Node: resumen de append-to-buffer194639
Node: append interactivo197456
Node: cuerpo append-to-buffer200028
Node: append save-excursion202236
Node: Revisa lo relacionado con el búffer207376
Node: Ejercicios de búffer209551
Node: Más complejidad210076
Node: copy-to-buffer211208
Node: insert-buffer214016
Node: código insert-buffer215394
Node: insert-buffer interactivo216442
Node: Búffer solo lectura216990
Node: b para interactivo217630
Node: cuerpo insert-buffer218795
Node: si y o220053
Node: Insertar o223270
Node: Insertar let225671
Node: Nuevo insert-buffer229538
Node: beginning-of-buffer230794
Node: Argumentos opcionales232449
Node: beginning-of-buffer opt arg235902
Node: Desenmarañar beginning-of-buffer236908
Node: El caso del buffer largo238210
Node: Pequeño caso de búffer240809
Node: Completo beginning-of-buffer242535
Node: Revisar el segundo búffer relacionado245662
Node: Ejercicio opcional247507
Node: Encogiendo y extendiendo248010
Node: Ventajas de encoger248713
Node: save-restriction250731
Node: what-line252774
Node: Ejercicio narrow257175
Node: Car cdr y cons258265
Node: Nombres extraños259441
Node: car y cdr260466
Node: cons265049
Node: Construir una lista266122
Ref: Construir una lista-Footnote-1267816
Node: length268033
Node: nthcdr269667
Node: nth272571
Node: setcar273997
Node: setcdr276387
Node: Ejercicio cons277998
Node: Cortando y almacenando texto278402
Node: Almacenando Texto279960
Node: zap-to-char282112
Node: Completar zap-to-char283272
Node: zap-to-char interactivo285389
Node: cuerpo zap-to-char286948
Node: search-forward288553
Node: progn291747
Node: Resumiendo zap-to-char293580
Node: kill-region294753
Node: Completa kill-region295791
Node: condition-case300507
Node: Macro Lisp303294
Node: copy-region-as-kill305818
Node: Completar copy-region-as-kill306778
Node: cuerpo copy-region-as-kill309837
Node: last-command & this-command310994
Node: Función kill-append313345
Node: Función kill-new317560
Node: Disgresión dentro de C329139
Ref: Disgresión dentro de C-Footnote-1334651
Node: defvar334844
Node: Mira el valor actual de la variable336519
Node: defvar y asterisk338540
Node: Revisión de cons y search-fwd340522
Node: Buscar ejercicios343702
Node: Implementación de listas344537
Node: Listas diagramadas345717
Node: Símbolos como cajas352171
Node: Ejercicio Lista354307
Node: Pegando354686
Node: Resumen del anillo de la muerte356213
Node: kill-ring-yank-pointer358184
Node: pegar Ejercicio nthcdr360855
Node: Bucles y recursión361766
Ref: Bucles y recursión-Footnote-1362989
Node: while363567
Node: Bucles while365105
Node: Ejemplo de bucle366939
Node: print-elements-of-list370507
Node: Incrementando el Bucle373207
Node: Incrementando los detalles de los bucles373830
Node: Ejemplo de Incremento375342
Node: Partes Inc de Ejemplo377822
Node: Ejemplo Inc junto381989
Node: Bucle que se decrementa385721
Node: Ejemplo de Decremento387171
Node: Partes de Ejemplo Dec388768
Node: Ejemplo Dec junto390857
Node: Dolist y dotimes393239
Node: dolist394120
Node: dotimes397345
Node: Recursión398993
Node: Construyendo robots400270
Node: Partes de definición recursiva402209
Node: Recursión con lista404720
Node: Función recursiva triángulo408430
Node: Ejemplo recursivo y argumento con valor 1 o 2409952
Node: Ejemplo Recursivo de 3 o 4 argumentos412261
Node: Recursión con cond415246
Node: Patrones recursivos417653
Node: Cada418164
Node: Acumular420709
Node: Guardar422014
Node: Sin Aplazar423998
Node: No aplazar la solución426790
Ref: No aplazar la solución-Footnote-1430917
Ref: No aplazar la solución-Footnote-2431025
Node: Ejercicio de Bucle431564
Node: Buscar regexp432842
Node: sentence-end435037
Node: re-search-forward439136
Node: forward-sentence441699
Node: Completa forward-sentence442561
Node: Bucles while fwd-sentence446154
Node: Volver a buscar la frase en sentido directo449877
Node: forward-paragraph452020
Node: forward-paragraph en breve454018
Node: fwd-para let455507
Node: fwd-para while461288
Node: etags470035
Node: Revisar regexp474787
Node: Ejercicios re-search477373
Node: Contando palabras478210
Node: Por qué Contar Palabras479028
Node: count-words-example480184
Node: Diseñar count-words-example481626
Node: Error de espacio en blanco488763
Node: recursive-count-words498960
Node: Ejercicio de Contar511516
Node: Palabras en una función511939
Node: Divide y vencerás513819
Node: Palabras y Símbolos515181
Node: Sintaxis517372
Node: count-words-in-defun521508
Node: Varias funciones527885
Node: Encontrar un fichero530484
Node: lengths-list-file533182
Node: Varios ficheros538723
Node: lengths-list-many-files539520
Node: append542466
Node: Varios ficheros recursivamente543134
Node: Preparar los datos546065
Node: Datos para mostrar en detalle547275
Node: Ordenando548236
Node: Listar ficheros549997
Node: Contando definiciones de función557938
Node: Leyendo un grafo567465
Node: Columnas de un grafo568910
Node: graph-body-print583505
Node: recursive-graph-body-print588291
Node: Ejes Impresos591120
Node: Ejercicio de Línea de Grafo591934
Node: Inicialización de Emacs592163
Node: Configuración por defecto593795
Ref: Configuración por defecto-Footnote-1596064
Node: Site-wide Init596420
Node: defcustom598646
Node: Empezando un fichero .emacs605183
Node: Texto y Autorelleno607809
Node: Alias de correo612170
Node: Indentar modo de tabulaciones613207
Node: Atajos de teclado614348
Node: Mapas de teclado618247
Node: Cargando ficheros620761
Node: Autocarga623955
Node: Extensión simple627055
Ref: Extensión simple-Footnote-1629913
Node: Colores X11630207
Ref: Colores X11-Footnote-1632173
Node: Miscelánea632360
Node: Mode Line636891
Node: Depurando642837
Node: depurar643789
Node: debug-on-entry647018
Node: debug-on-quit650278
Node: edebug651358
Node: Ejercicios de depuración655719
Node: Conclusión657634
Node: the-the663339
Node: Kill Ring666286
Node: Qué hace el anillo de la muerte667131
Node: current-kill668947
Node: Código para current-kill669727
Node: Comprendiendo current-kill672039
Node: Cuerpo de current-kill672928
Node: Disgresión concerniente de error676238
Node: Determinando el elemento677501
Node: pegar681307
Node: yank-pop684623
Node: fichero anillo687201
Node: Grafo completo687611
Node: Ejemplo etiquetado688484
Node: print-graph Varlist690589
Node: print-Y-axis692345
Node: print-Y-axis en Detalle693224
Node: Altura de etiqueta693961
Node: Calcular un resto695967
Node: Elemento del Eje Y699983
Node: Y-axis-column703855
Node: Penúltimo print-Y-axis705582
Node: print-X-axis707627
Node: Diferencias similares709008
Node: Eje X marca tic709878
Node: Imprimir Grafo Entero717120
Node: La versión final718244
Node: Testear print-graph722707
Node: Graficar palabras en funciones724390
Node: lambda727215
Node: mapcar728979
Node: Otro Error731145
Node: Grafo impreso final736942
Node: Software Libre y Manuales Libres737897
Node: GNU Free Documentation License744820
Node: Índice770006
Node: Acerca del Autor808593

End Tag Table


Local Variables:
coding: utf-8
Info-documentlanguage: es
End:
