\input texinfo                                      @c -*-texinfo-*-
@c ===========================================================================
@c
@c This file was generated with po4a. Translate the source file.
@c
@c ===========================================================================

@comment %**start of header
@setfilename ../../info/eintr
@c setfilename emacs-lisp-intro.info
@c sethtmlfilename emacs-lisp-intro.html
@settitle Programaci@'on en Emacs Lisp
@syncodeindex vr cp
@syncodeindex fn cp
@documentencoding UTF-8
@documentlanguage es
@finalout

@c ---------
@c <<<< For hard copy printing, this file is now
@c      set for smallbook, which works for all sizes
@c      of paper, and with PostScript figures >>>>
@set smallbook
@ifset smallbook
@smallbook
@clear largebook
@end ifset
@set print-postscript-figures
@c set largebook
@c clear print-postscript-figures
@c ---------

@comment %**end of header

@c per rms and peterb, use 10pt fonts for the main text, mostly to
@c save on paper cost.
@c Do this inside @tex for now, so current makeinfo does not complain.
@tex
@ifset smallbook
@fonttextsize 10

@end ifset
\global\hbadness=6666 % don't worry about not-too-underfull boxes
@end tex

@set edition-number 3.10
@set update-date 28 October 2009

@ignore
 ## Summary of shell commands to create various output formats:

    pushd /usr/local/src/emacs/lispintro/
    ## pushd /u/intro/

    ## Info output
    makeinfo --paragraph-indent=0 --verbose emacs-lisp-intro.texi

      ## ;; (progn (when (bufferp (get-buffer "*info*")) (kill-buffer "*info*")) (info "/usr/local/src/emacs/info/eintr"))

    ## DVI output
    texi2dvi emacs-lisp-intro.texi

      ## xdvi -margins 24pt -topmargin 4pt -offsets 24pt -geometry 760x1140 -s 5 -useTeXpages -mousemode 1 emacs-lisp-intro.dvi &

    ## HTML output
    makeinfo --html --no-split --verbose emacs-lisp-intro.texi

      ## galeon emacs-lisp-intro.html

    ## Plain text output
    makeinfo --fill-column=70 --no-split --paragraph-indent=0 \
    --verbose --no-headers --output=emacs-lisp-intro.txt emacs-lisp-intro.texi

    popd

# as user `root'
# insert thumbdrive
  mtusb       #   mount -v -t ext3 /dev/sda /mnt
  cp -v /u/intro/emacs-lisp-intro.texi /mnt/backup/intro/emacs-lisp-intro.texi
  umtusb      #   umount -v /mnt
# remove thumbdrive

    ## Other shell commands

    pushd /usr/local/src/emacs/lispintro/
    ## pushd /u/intro/

    ## PDF
    texi2dvi --pdf emacs-lisp-intro.texi
       # xpdf emacs-lisp-intro.pdf &

    ## DocBook                    -- note file extension
    makeinfo --docbook --no-split --paragraph-indent=0 \
    --verbose --output=emacs-lisp-intro.docbook emacs-lisp-intro.texi

    ## XML with a Texinfo DTD     -- note file extension
    makeinfo --xml --no-split --paragraph-indent=0 \
    --verbose --output=emacs-lisp-intro.texinfoxml emacs-lisp-intro.texi

    ## PostScript (needs DVI)
        #     gv emacs-lisp-intro.ps &
        # Create DVI if we lack it
        # texi2dvi emacs-lisp-intro.texi
    dvips emacs-lisp-intro.dvi -o emacs-lisp-intro.ps

    ## RTF (needs HTML)
        # Use OpenOffice to view RTF
        # Create HTML if we lack it
        # makeinfo --no-split --html emacs-lisp-intro.texi
    /usr/local/src/html2rtf.pl emacs-lisp-intro.html

    ## LaTeX (needs RTF)
    /usr/bin/rtf2latex emacs-lisp-intro.rtf

    popd

@end ignore

@c ================ Included Figures ================

@c Set  print-postscript-figures  if you print PostScript figures.
@c If you clear this, the ten figures will be printed as ASCII diagrams.
@c (This is not relevant to Info, since Info only handles ASCII.)
@c Your site may require editing changes to print PostScript; in this
@c case, search for `print-postscript-figures' and make appropriate changes.

@c ================ How to Create an Info file ================

@c If you have `makeinfo' installed, run the following command

@c     makeinfo emacs-lisp-intro.texi

@c or, if you want a single, large Info file, and no paragraph indents:
@c     makeinfo --no-split --paragraph-indent=0 --verbose emacs-lisp-intro.texi

@c After creating the Info file, edit your Info `dir' file, if the
@c `dircategory' section below does not enable your system to
@c install the manual automatically.
@c (The `dir' file is often in the `/usr/local/share/info/' directory.)

@c ================ How to Create an HTML file ================

@c To convert to HTML format
@c     makeinfo --html --no-split --verbose emacs-lisp-intro.texi

@c ================ How to Print a Book in Various Sizes ================

@c This book can be printed in any of three different sizes.
@c In the above header, set @-commands appropriately.

@c     7 by 9.25 inches:
@c              @smallbook
@c              @clear largebook

@c     8.5 by 11 inches:
@c              @c smallbook
@c              @set largebook

@c     European A4 size paper:
@c              @c smallbook
@c              @afourpaper
@c              @set largebook

@c ================ How to Typeset and Print ================

@c If you do not include PostScript figures, run either of the
@c following command sequences, or similar commands suited to your
@c system:

@c     texi2dvi emacs-lisp-intro.texi
@c     lpr -d emacs-lisp-intro.dvi

@c or else:

@c     tex emacs-lisp-intro.texi
@c     texindex emacs-lisp-intro.??
@c     tex emacs-lisp-intro.texi
@c     lpr -d emacs-lisp-intro.dvi

@c If you include the PostScript figures, and you have old software,
@c you may need to convert the .dvi file to a .ps file before
@c printing.  Run either of the following command sequences, or one
@c similar:
@c
@c     dvips -f < emacs-lisp-intro.dvi > emacs-lisp-intro.ps
@c
@c or else:
@c
@c     postscript -p < emacs-lisp-intro.dvi > emacs-lisp-intro.ps
@c

@c (Note: if you edit the book so as to change the length of the
@c table of contents, you may have to change the value of `pageno' below.)

@c ================ End of Formatting Sections ================

@c For next or subsequent edition:
@c   create function using with-output-to-temp-buffer
@c   create a major mode, with keymaps
@c   run an asynchronous process, like grep or diff

@c For 8.5 by 11 inch format: do not use such a small amount of
@c whitespace between paragraphs as smallbook format
@ifset largebook
@tex
\global\parskip 6pt plus 1pt
@end tex
@end ifset

@c For all sized formats:  print within-book cross
@c reference with ``...''  rather than [...]

@c This works with the texinfo.tex file, version 2003-05-04.08,
@c in the Texinfo version 4.6 of the 2003 Jun 13 distribution.

@tex
\if \xrefprintnodename
 \global\def\xrefprintnodename#1{\unskip, ``#1''}
 \else
 \global\def\xrefprintnodename#1{ ``#1''}
\fi
% \global\def\xrefprintnodename#1{, ``#1''}
@end tex

@c ----------------------------------------------------

@dircategory GNU Emacs Lisp
@direntry
* Introducci@'on a Emacs Lisp: (eintr).  Una introducci@'on simple a la 
                                           programaci@'on a Emacs Lisp
@end direntry

@copying
Esto es una @cite{Introducci@'on a la Programaci@'on en Emacs Lisp},
para personas que no son programadoras.
@sp 1
Traducido desde la edici@'on @value{edition-number}.
@sp 1
Copyright @copyright{} 2015 Libremanuals.
@sp 1

@iftex
Publicado por:@*

Libremanuals,                     @hfill
@uref{http://www.libremanuals.net/}@*
Puede descargar una copia de las fuentes desde
https://savannah.nongnu.org/git/?group=elisp-es
@end iftex

@ifnottex
Publicado por el:

@example
Libremanuals,                     @hfill @uref{http://www.libremanuals.net/}@* 
@end example
@end ifnottex

@sp 1
@c Printed copies are available from @uref{http://shop.fsf.org/} for $35 each.@*
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.''
@end copying

@c half title; two lines here, so do not use `shorttitlepage'
@tex
{\begingroup%
    \hbox{}\vskip 1.5in \chaprm \centerline{Una Introducci@'on}%
        \endgroup}%
{\begingroup\hbox{}\vskip 0.25in \chaprm%
        \centerline{a la Programaci@'on en Emacs Lisp}%
        \endgroup\page\hbox{}\page}
@end tex

@titlepage
@sp 6
@center @titlefont{Una Introducci@'on a la}
@sp 2
@center @titlefont{Programaci@'on en Emacs Lisp}
@sp 2
@center Revisada la tercera edici@'on
@sp 4
@center Escrito por Robert J. Chassell. Traducido por David Arroyo Men@'endez.

@page
@vskip 0pt plus 1filll
@insertcopying
@end titlepage

@iftex
@headings off
@evenheading @thispage @| @| @thischapter
@oddheading @thissection @| @| @thispage
@end iftex

@ifnothtml
@c     Keep T.O.C. short by tightening up for largebook
@ifset largebook
@tex
\global\parskip 2pt plus 1pt
\global\advance\baselineskip by -1pt
@end tex
@end ifset
@end ifnothtml

@shortcontents
@contents

@ifnottex
@node Top
@top Una Introducci@'on a la Programaci@'on en Emacs Lisp

@insertcopying

Este men@'u maestro primero lista cada cap@'{@dotless{i}}tulo e
indexa; entonces lista cada nodo en cada cap@'{@dotless{i}}tulo.
@end ifnottex

@c >>>> Set pageno appropriately <<<<

@c The first page of the Preface is a roman numeral; it is the first
@c right handed page after the Table of Contents; hence the following
@c setting must be for an odd negative number.

@c iftex
@c global@pageno = -11
@c end iftex

@set COUNT-WORDS count-words-example
@c Length of variable name chosen so that things still line up when expanded.

@menu
* Prefacio::                 Qu@'e buscas
* Procesamiento de listas::  @questiondown{}Qu@'e es Lisp?
* Practicando evaluaci@'on::  Ejecutando varios programas.
* Escribiendo funciones::    C@'omo escribir definiciones de funciones.
* Un paseo a trav@'es de los b@'uffers::  Explorando unas pocas funciones 
                                            relacionadas con los b@'uffers.
* M@'as complejidad::        Unas pocas, incluso m@'as complejas funciones.
* Encogiendo y extendiendo::  Restringi@'endote a t@'i y a Emacs a una 
                                regi@'on.
* Car cdr y cons::           Funciones fundamentales en Lisp.
* Cortando y almacenando texto::  Eliminando texto y guard@'andolo.
* Implementaci@'on de listas::  C@'omo las listas se implementan en el 
                                  ordenador
* Pegando::                  Pegando texto almacenado.
* Bucles y recursi@'on::     C@'omo repetir un proceso.
* Buscar regexp::            B@'usquedas de expresiones regulares.
* Contando palabras::        Una revisi@'on de repetici@'on y regexps.
* Palabras en una funci@'on::  Contando palabras en una @code{defun}.
* Leyendo un grafo::         Un grafo prototipo imprimiendo una funci@'on.
* Inicializaci@'on de Emacs::  C@'omo escribir un fichero @file{.emacs}.
* Depurando::                C@'omo ejecutar los depuradores de Emacs Lisp.
* Conclusi@'on::             Ahora tienes las bases.
* the-the::                  Un ap@'endice: c@'omo encontrar palabras 
                               reduplicadas.
* Kill Ring::                Un ap@'endice: c@'omo el kill ring funciona.
* Grafo completo::           C@'omo crear un grafo con ejes etiquetados.
* Software Libre y Manuales Libres::  Software Libre y Manuales Libres
* GNU Free Documentation License::  GNU Free Documentation License
* @'Indice::                 @'Indice
* Acerca del Autor::         Acerca del Autor

@detailmenu
 --- El Listado Detallado de Nodos ---



Prefacio



* Por qu@'e::                @questiondown{}Por qu@'e aprender Emacs Lisp?
* Leyendo este texto::       Leer, ganar familiaridad, coger h@'abitos...
* 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::              @questiondown{}Qu@'e 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@'{@dotless{i}}mbolos y 
                               definiciones de funci@'on.
* Interpr@'ete Lisp::        Qu@'e hace el int@'erprete Lisp.
* Evaluaci@'on::             Ejecutando un programa.
* Variables::                Devolviendo un valor desde una variable.
* Argumentos::               Pasando informaci@'on a una funci@'on.
* 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@'umeros::      Lista tener n@'umeros, otras listas, en ellas.
* @'Atomos Lisp::            Entidades Elementales.
* Espacios en blanco en listas::  Formatenado listas para ser legibles.
* Escribiendo listas::       C@'omo GNU Emacs te ayuda a escribir listas.

El int@'erprete Lisp



* Complicaciones::           Variables, formas especiales, Listas.
* Compilaci@'on de bytes::   Especialmente procesando c@'odigo por la 
                               velocidad.

Evaluaci@'on



* C@'omo el int@'erprete act@'ua::  Devolver y Efectos Colaterales...
* Evaluando listas propias::  Listas con listas...

Variables



* Ejemplo de rellenar columna::  Ejemplo de rellenar columna
* Funci@'on vac@'{@dotless{i}}a::  El mensaje de error para un 
                                     s@'{@dotless{i}}mbolo sin una funci@'on.
* Variable vac@'{@dotless{i}}a::  El mensaje de error para un 
                                    s@'{@dotless{i}}mbolo sin un valor.

Argumentos



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

Configurando el valor de una variable



* Usando set::               Configurando valores.
* Usando setq::              Configurando un valor citado.
* Contando::                 Usando @code{setq} para contar.

Practicando evaluaci@'on



* C@'omo evaluar::           Escribiendo comandos de edici@'on o con 
                               @kbd{C-x C-e}.
* Nombres de b@'uffer::      Buffers y ficheros son diferentes.
* Obteniendo b@'uffers::     Obteniendo un buffer por s@'{@dotless{i}} 
                               mismo, no solamente su nombre.
* Cambiando b@'uffers::      C@'omo cambiar a otro buffer.
* Tama@~no de b@'uffer y localizaciones::  D@'onde el punto est@'a 
                                             localizado y el tama@~no del 
                                             buffer.
* Ejercicio de evaluaci@'on::  Ejercicio de evaluaci@'on

C@'omo escribir definiciones de funciones



* Funciones primitivas::     Funciones primitivas
* defun::                    La forma especial @code{defun}.
* Instalar::                 Instalar una definici@'on de funci@'on.
* Interactive::              Creando una funci@'on interactive.
* Opciones de interactive.::  Diferentes opciones para @code{interactive}.
* Instalaci@'on Permanente::  Instalando c@'odigo permanentemente.
* let::                      Creando e inicializando variables locales.
* if::                       @questiondown{}Y qu@'e 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@'on de funci@'on



* Efecto de instalaci@'on::  Efecto de instalaci@'on
* Cambiar un defun::         C@'omo cambiar una definici@'on de funci@'on

Crear una funci@'on interactive



* multiply-by-seven interactivo::  Un resumen
* multiply-by-seven en detalle::  La versi@'on interactive.

@code{let}



* Prevenir confusi@'on::     Prevenir confusi@'on
* Partes de la expresi@'on let::  Partes de la expresi@'on let
* Ejemplo de expresi@'on let::  Ejemplo de expresi@'on let
* Variables let inicializadas::  Variables let inicializadas

La forma especial @code{if}



* if en m@'as detalle::      if en m@'as detalle
* tipo-de-animal en detalle::  Un ejemplo de una expresi@'on @code{if}.

Verdad y falsedad en Emacs Lisp



* nil explicado::            @code{nil} tiene dos significados.

@code{save-excursion}



* Punto y marca::            Una revisi@'on de varias localizaciones.
* Plantilla para save-excursion::  Plantilla para save-excursion

Unas pocas funciones de buffer relacionadas



* Encontrando m@'as::        C@'omo encontrar m@'as informaci@'on.
* simplified-beginning-of-buffer::  Muestra @code{goto-char}, 
                                      @code{point-min}, y @code{push-mark}.
* mark-whole-buffer::        Casi lo mismo que @code{beginning-of-buffer}.
* append-to-buffer::         Usa @code{save-excursion} y 
                               @code{insert-buffer-substring}.
* Revisa lo relacionado con el b@'uffer::  Revisa
* Ejercicios de b@'uffer::   Ejercicios de b@'uffer

La definici@'on de @code{mark-whole-buffer}



* resumen de mark-whole-buffer::  resumen de mark-whole-buffer
* Cuerpo de mark-whole-buffer::  Solo tres l@'{@dotless{i}}neas de c@'odigo.

La definici@'on de @code{append-to-buffer}



* resumen de append-to-buffer::  resumen de append-to-buffer
* append interactivo::       Una expresi@'on interactiva de dos partes.
* cuerpo append-to-buffer::  Incorpora una expresi@'on @code{let}.
* append save-excursion::    C@'omo @code{save-excursion} trabaja.

Unas pocas funciones m@'as complejas



* copy-to-buffer::           Con @code{set-buffer}, 
                               @code{get-buffer-create}.
* insert-buffer::            Solo lectura, y con @code{or}.
* beginning-of-buffer::      Muestra @code{goto-char}, @code{point-min}, y 
                               @code{push-mark}.
* Revisar el segundo b@'uffer relacionado::  Revisar el segundo b@'uffer 
                                               relacionado
* Ejercicio opcional::       Ejercicio opcional

La definici@'on de @code{insert-buffer}



* c@'odigo insert-buffer::   c@'odigo insert-buffer
* insert-buffer interactivo::  Cuando tu puedes leer, pero no escribir.
* cuerpo insert-buffer::     El cuerpo tiene un @code{or} y un @code{let}.
* si y o::                   Usando un @code{if} en vez de un @code{or}.
* Insertar o::               C@'omo la expresi@'on @code{or} funciona.
* Insertar let::             Dos expresiones @code{save-excursion}.
* Nuevo insert-buffer::      Nuevo insert-buffer

La expresi@'on interactiva en @code{insert-buffer}



* B@'uffer solo lectura::    Cuando un buffer no puede ser modificado.
* b para interactivo::       Un buffer existe o adem@'as su nombre.

Definici@'on completa de @code{beginning-of-buffer}



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

@code{beginning-of-buffer} con un argumento



* Desenmara@~nar beginning-of-buffer::  Desenmara@~nar beginning-of-buffer
* El caso del buffer largo::  El caso del buffer largo
* Peque@~no caso de b@'uffer::  Peque@~no caso de b@'uffer

Encogiendo y extendiendo



* Ventajas de encoger::      Las ventajas de encoger
* save-restriction::         La forma especial @code{save-restriction}.
* what-line::                El n@'umero de la l@'{@dotless{i}}nea que 
                               apunta est@'a activa.
* Ejercicio narrow::         Ejercicio narrow

@code{car}, @code{cdr}, @code{cons}: Funciones fundamentales



* Nombres extra@~nos::       Un lado hist@'orico: @questiondown{}por qu@'e 
                               los nombres extra@~nos?
* car y cdr::                Funciones para extraer parte de una lista.
* cons::                     Construyendo una lista.
* nthcdr::                   Llamando @code{cdr} repetidamente.
* nth::                      nth
* setcar::                   Cambiando el primer elemento de una lista.
* setcdr::                   Cambiando el resto de una lista.
* Ejercicio cons::           Ejercicio cons

@code{cons}



* Construir una lista::      Construir una lista
* length::                   C@'omo encontrar el tama@~no de una lista.

Cortando y almacenando texto



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

@code{zap-to-char}



* Completar zap-to-char::    La implementaci@'on completa.
* zap-to-char interactivo::  Una expresi@'on interactiva de tres partes.
* cuerpo zap-to-char::       Un resumen corto
* search-forward::           C@'omo buscar una cadena.
* progn::                    La forma especial @code{progn}.
* Resumiendo zap-to-char::   Usando @code{point} y @code{search-forward}.

@code{kill-region}



* Completa kill-region::     La definici@'on de funci@'on.
* condition-case::           Tratando con un problema.
* Macro Lisp::               Macro Lisp

@code{copy-region-as-kill}



* Completar copy-region-as-kill::  La definici@'on completa de funci@'on.
* cuerpo copy-region-as-kill::  El cuerpo de @code{copy-region-as-kill}.

El cuerpo de @code{copy-region-as-kill}



* last-command & this-command::  last-command & this-command
* Funci@'on kill-append::    Funci@'on kill-append
* Funci@'on kill-new::       Funci@'on kill-new

Inicializando una variable con @code{defvar}



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

C@'omo las listas se implementan



* Listas diagramadas::       Listas diagramadas
* S@'{@dotless{i}}mbolos como cajas::  Explorando una met@'afora 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 @code{kill-ring-yank-pointer}.

Bucles y recursi@'on



* while::                    Causando un cierto c@'odigo para repetir.
* Dolist y dotimes::         Dolist y dotimes
* Recursi@'on::              Causando que una funci@'on se llame a 
                               s@'{@dotless{i}} misma.
* Ejercicio de Bucle::       Ejercicio de Bucle

@code{while}



* Bucles while::             Repetir tantas veces como el test devuelva 
                               verdadero.
* Ejemplo de bucle::         Un bucle @code{while} que usa una lista.
* print-elements-of-list::   Usos @code{while}, @code{car}, @code{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@'angulo.
* Partes Inc de Ejemplo::    Las partes de la definici@'on de funci@'on.
* Ejemplo Inc junto::        Poniendo la definici@'on de funci@'on junta.

Bucle que decrementa



* Ejemplo de Decremento::    M@'as piedras en la playa.
* Partes de Ejemplo Dec::    Las partes de la definici@'on de funci@'on.
* Ejemplo Dec junto::        Poniendo la definici@'on de funci@'on junta.

Ahorra tiempo: @code{dolist} y @code{dotimes}



* dolist::                   dolist
* dotimes::                  dotimes

Recursi@'on



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

Recursi@'on 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@'usquedas de expresiones regulares



* sentence-end::             La expresi@'on regular para 
                               @code{sentence-end}.
* re-search-forward::        Muy similar a @code{search-forward}.
* forward-sentence::         Un ejemplo sencillo de b@'usqueda con 
                               expresiones regulares.
* forward-paragraph::        Un ejemplo complejo de alguna cosa.
* etags::                    C@'omo crear tu propia tabla @file{TAGS}.
* Revisar regexp::           Revisar regexp
* Ejercicios re-search::     Ejercicios re-search

@code{forward-sentence}



* Completa forward-sentence::  Completa forward-sentence
* Bucles while fwd-sentence::  Dos bucles @code{while}.
* Volver a buscar la frase en sentido directo::  Una b@'usqueda de 
                                                   expresi@'on regular.

@code{forward-paragraph}: una mina de oro de funciones



* forward-paragraph en breve::  Partes clave de la definici@'on de la 
                                  funci@'on.
* fwd-para let::             La expresi@'on @code{let*}.
* fwd-para while::           El bucle @code{while} con modo hacia adelante.

Contando: repetici@'on y regexps



* Por qu@'e Contar Palabras::  Por qu@'e Contar Palabras
* @value{COUNT-WORDS}::      Usa un regexp, pero encuentra un problema.
* recursive-count-words::    Empezar en caso de que no haya palabras en la 
                               regi@'on.
* Ejercicio de Contar::      Ejercicio de Contar

La funci@'on @code{@value{COUNT-WORDS}}



* Dise@~nar @value{COUNT-WORDS}::  La definici@'on usando un bucle 
                                     @code{while}.
* Error de espacio en blanco::  El error de espacio en blanco en 
                                  @code{@value{COUNT-WORDS}}.

Contando palabras en una @code{defun}



* Divide y vencer@'as::      Divide y vencer@'as
* Palabras y S@'{@dotless{i}}mbolos::  @questiondown{}Qu@'e contar?
* Sintaxis::                 @questiondown{}Qu@'e constituye una palabra o 
                               s@'{@dotless{i}}mbolo?
* count-words-in-defun::     Similar a @code{@value{COUNT-WORDS}}.
* Varias funciones::         Contando varias funciones en un fichero.
* Encontrar un fichero::     @questiondown{}Quieres buscar en un fichero?
* lengths-list-file::        Una lista de los tama@~nos 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 @code{defuns} en diferentes ficheros



* lengths-list-many-files::  Devolver una lista de tama@~nos 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@'on::  Contando definiciones de funci@'on

Leyendo un grafo



* Columnas de un grafo::     Columnas de un grafo
* graph-body-print::         C@'omo imprimir el cuerpo de un grafo.
* recursive-graph-body-print::  recursive-graph-body-print
* Ejes Impresos::            Ejes Impresos
* Ejercicio de L@'{@dotless{i}}nea de Grafo::  Ejercicio de 
                                                 L@'{@dotless{i}}nea de Grafo

Tu fichero @file{.emacs}



* Configuraci@'on por defecto::  Configuraci@'on por defecto
* Site-wide Init::           Se puede escribir site-wide ficheros init.
* defcustom::                Emacs escribir@'a c@'odigo para ti.
* Empezando un fichero .emacs::  C@'omo escribir un @code{fichero .emacs}.
* Texto y Autorelleno::      Corta l@'{@dotless{i}}neas autom@'aticamente.
* Alias de correo::          Usar abreviaciones para direcciones de correo 
                               electr@'onico.
* Indentar modo de tabulaciones::  No usar tabulaciones con @TeX{}
* Atajos de teclado::        Crear algunos atajos de teclado personales.
* Mapas de teclado::         M@'as acerca de atajos de teclado.
* Cargando ficheros::        Cargar (por ej. evaluar) ficheros 
                               autom@'aticamente.
* Autocarga::                Crear funciones disponibles.
* Extensi@'on simple::       Definir una funci@'on; enlazarla a una tecla.
* Colores X11::              Colores en X.
* Miscel@'anea::             Miscel@'anea
* Mode Line::                C@'omo personalizar tu mode line.

Depurando



* depurar::                  C@'omo usar el depurador construido.
* debug-on-entry::           Empezar depurando cuando se llama a una 
                               funci@'on.
* debug-on-quit::            Empezar depurando cuando se sale con @kbd{C-g}.
* edebug::                   C@'omo usar Edebug, un depurador a nivel de 
                               fuentes.
* Ejercicios de depuraci@'on::  Ejercicios de depuraci@'on

Manejando el anillo de la muerte



* Qu@'e hace el anillo de la muerte::  Qu@'e 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@'on @code{current-kill}



* C@'odigo para current-kill::  C@'odigo para current-kill
* Comprendiendo current-kill::  Comprendiendo current-kill

@code{current-kill} en outline



* Cuerpo de current-kill::   Cuerpo de current-kill
* Disgresi@'on concerniente de error::  C@'omo confundir humanos, pero no 
                                          ordenadores.
* Determinando el elemento::  Determinando el elemento

Un grafo con ejes etiquetados



* Ejemplo etiquetado::       Ejemplo etiquetado
* print-graph Varlist::      Expresi@'on @code{let} en @code{print-graph}.
* print-Y-axis::             Imprimir una etiqueta para los ejes verticales.
* print-X-axis::             Imprimir una etiqueta horizontal.
* Imprimir Grafo Entero::    La funci@'on para imprimir un grafo completo.

La funci@'on @code{print-Y-axis}



* print-Y-axis en Detalle::  print-Y-axis en Detalle
* Altura de etiqueta::       @questiondown{}Qu@'e altura para el eje Y?
* Calcular un resto::        C@'omo calcular el resto de una divisi@'on.
* Elemento del Eje Y::       Construir una l@'{@dotless{i}}nea para el eje 
                               Y.
* Y-axis-column::            Generar una lista de etiquetas del eje Y.
* Pen@'ultimo print-Y-axis::  Una versi@'on no muy final.

La funci@'on @code{print-X-axis}



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

Imprimiendo el grafo completo



* La versi@'on final::       Unos pocos cambios
* Testear print-graph::      Ejecutar un r@'apido test.
* Graficar palabras en funciones::  Ejecutando el c@'odigo final.
* lambda::                   C@'omo escribir una funci@'on an@'onima.
* mapcar::                   Aplicar una funci@'on a elementos de una lista.
* Otro Error::               Todav@'{@dotless{i}}a otro error @dots{} m@'as 
                               insidioso.
* Grafo impreso final::      @exclamdown{}El grafo en s@'{@dotless{i}}!

@end detailmenu
@end menu

@node Prefacio
@unnumbered Prefacio

La mayor@'{@dotless{i}}a del entorno integrado GNU Emacs est@'a
escrito en el lenguaje de programaci@'on llamado Emacs Lisp. El
c@'odigo escrito en este lenguaje de programaci@'on es el
software---el conjunto de instrucciones---que cuenta al ordenador qu@'e
hacer cuando tu le das comandos. Emacs est@'a dise@~nado
de forma que se puede escribir nuevo c@'odigo en Emacs Lisp
y f@'acilmente instalarlo como una extensi@'on al editor.

(GNU Emacs se define muchas veces como un ``editor extensible'', pero
hace mucho m@'as que proporcionar capacidad de edici@'on. Es mejor
referirse a Emacs como un ``entorno de computaci@'on extensible''. Sin
embargo, esta frase es un poco pretenciosa. Es m@'as f@'acil 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@'odigo, administrar ficheros, leer cartas,
escribir libros---todas estas actividades son maneras de editar en un
sentido amplio de la palabra.)

@menu
* Por qu@'e::                @questiondown{}Por qu@'e aprender Emacs Lisp?
* Leyendo este texto::       Leer, ganar familiaridad, coger h@'abitos...
* 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
@end menu

@ifnottex
@node Por qu@'e
@unnumberedsec @questiondown{}Por qu@'e estudiar Emacs Lisp?
@end ifnottex

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

Quiz@'as se quiere comprender la programaci@'on; quiz@'as se quiere
extender Emacs; o quiz@'as se quiere llegar a ser un programador. Esta
introducci@'on a Emacs Lisp est@'a dise@~nada para ayudar a empezar en
todo esto: para guiarse en el aprendizaje de los fundamentos de
programaci@'on, y de manera m@'as importante, para ense@~nar como uno
mismo puede ir m@'as all@'a.

@node Leyendo este texto
@unnumberedsec Leyendo este texto

A trav@'es de este libro, se ver@'an peque@~nos 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@'acil de hacer y se explica cuando los ejemplos
se presentan). Alternativamente, se puede leer esta introducci@'on
como un libro impreso mientras se est@'a sentando con un ordenador
ejecutando Emacs. (Esto es lo que me gusta hacer; me gustan los libros
impresos.) Si no se est@'a ejecutando Emacs, todav@'{@dotless{i}}a se
puede leer este libro, pero en este caso, lo mejor es tratarlo como
una novela, o como una gu@'{@dotless{i}}a de v@'{i}aje a un pa@'{i}s a@'{u}n
no visitado: interesante, pero no es lo mismo
que estar all@'{@dotless{i}}.

Gran parte de esta introducci@'on se dedica a paseos guiados de
c@'odigo usado en GNU Emacs. Estos paseos est@'an dise@~nados para dos
prop@'ositos: primero, familiarizarse con c@'odigo real que funciona
(c@'odigo que se usa cada d@'{@dotless{i}}a); y, segundo,
familiarizarse con c@'omo funciona Emacs. Es interesante ver c@'omo se
implementa un entorno completamente operativo. Tambi@'en, espero que
se adquiera el h@'abito de navegar a trav@'es del c@'odigo fuente. Se
puede aprender mucho comparando c@'odigo de otros con el propio,
ganando nuevas ideas. Tener GNU Emacs es como tener la cueva del
drag@'on de los tesoros.

Adem@'as de aprender acerca de Emacs como editor y Emacs Lisp como
lenguaje de programaci@'on, los ejemplos y visitas guiadas le
dar@'an una oportunidad para familiarizarse con Emacs como un
entorno de programaci@'on Lisp. GNU Emacs soporta programaci@'on y
provee herramientas que llegar@'an a usarse c@'omodamente,
como @kbd{M-.} (la clave que invoca el comando
@code{find-tag}). Tambi@'en aprendera sobre b@'uffers y otros
objetos que forman parte del entorno. Aprender estas funcionalidades de
Emacs es como aprender nuevas rutas alrededor de tu hogar.

@ignore
In addition, I have written several programs as extended examples.
Although these are examples, the programs are real.  I use them.
Other people use them.  You may use them.  Beyond the fragments of
programs used for illustrations, there is very little in here that is
`just for teaching purposes'; what you see is used.  This is a great
advantage of Emacs Lisp: it is easy to learn to use it for work.
@end ignore

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

@node Quien eres
@unnumberedsec Para quien est@'a esto escrito

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

Un programador experto que revis@'o este texto me dijo:

@quotation
@i{Prefiero aprender desde manuales de referencia. Yo ``me sumerjo'' en
cada p@'arrafo y ``subo a por aire'' entre p@'arrafos.}

@i{Cuando llego al fin de un p@'arrafo, asumo que este asunto est@'a
hecho, finalizado, que conozco cada cosa que necesito (con la posible
excepci@'on del caso en el que el siguiente p@'arrafo empiece hablando
acerca de eso mismo en m@'as detalle). Yo espero que un manual de
referencia bien escrito no tendr@'a un mont@'on de redundancia, y
tendr@'a excelentes punteros a (un) lugar donde est@'a la
informaci@'on que quiero.}
@end quotation

@exclamdown{}Esta introducci@'on no est@'a 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@'on acerca de un asunto
en un mismo lugar, ni mucho menos en un p@'arrafo. 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@~na informaci@'on extra,
para que no haya sorpresas m@'as tarde cuando la informaci@'on
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@'an alerta
de lo que es importante y concentrarse en ellos.

Es necesario ``sumergirse'' en algunos p@'arrafos; no hay otro modo de
leerlos. Pero yo he intentado guardar el n@'umero de tales
p@'arrafos. Este libro pretende ser como una colina asequible, en vez
de una monta@~na abrumadora.

Esta introducci@'on de @cite{Programaci@'on en Emacs Lisp} viene
acompa@~nada de un documento complementario.
@iftex
@cite{El Manual de Referencia de GNU Emacs}.
@end iftex
@ifnottex
@ref{Arriba, , El Manual de Referencia de GNU Emacs Lisp, El Manual de
Referencia de GNU Emacs Lisp}.
@end ifnottex
El manual de referencia tiene m@'as detalles que esta
introducci@'on. En el manual de referencia, toda la informaci@'on
sobre un asunto est@'a concentrada en un lugar. Se debe cambiar si es
como el programador citado arriba. Y, por supuesto, despu@'es de haber
leido esta @cite{Introducci@'on}, ser@'a muy @'util consultar el
@cite{Manual de Referencia} al escribir programas propios.

@node Historia de Lisp
@unnumberedsec Historia de Lisp
@cindex Historia de Lisp

Lisp fu@'e originariamente desarrollado en los 50 en el Instituto
Tecnol@'ogico de Massachusetts para investigar en inteligencia
artificial. El gran poder del lenguaje Lisp lo hace superior para
otros prop@'ositos tambi@'en, tal como escribir comandos de edici@'on y
entornos integrados.

@cindex Maclisp
@cindex Common Lisp
GNU Emacs Lisp est@'a fuertemente inspirado en Maclisp, que est@'a
escrito en el MIT en los sesenta. Est@'a en cierto modo inspirado en
Common Lisp, que llega a ser un est@'andar en los 80. Sin embargo,
Emacs Lisp es mucho m@'as simple que Common Lisp. (La distribuci@'on
est@'andar de Emacs contiene un fichero de extensiones opcional,
@file{cl.el}, que a@~nade muchas funcionalidades a Emacs Lisp.)

@node Nota para principiantes
@unnumberedsec Una nota para principiantes

Aunque no se conozca GNU Emacs, este documento puede resultar
@'util. Sin embargo, es mejor aprender Emacs, al menos aprender a
moverse alrededor de la pantalla del ordenador. Uno puede aprender de
manera autodidacta c@'omo usar Emacs con el tutorial on-line. Para
usarlo, se debe escribir @kbd{C-h t}. (Esto significa que se presione
la tecla @key{CTRL} y la @kbd{h} al mismo tiempo, y despu@'es se
presiona @kbd{t}).

Con frecuencia, tambi@'en aludo a uno de los comandos de Emacs
est@'andar listando las teclas que se presionan para invocar el
comando y, luego dar el nombre del comando entre par@'entesis,
asi: @kbd{M-C-\} (@code{indent-region}). Esto significa invocar el
comando @code{indent-region} presionando @kbd{M-C-\}.(Si lo desea, se pueden
cambiar las teclas que son escritas para invocar el comando; esto se
llama @dfn{rebinding}. @xref{Mapas de teclado, , Mapas de Teclado}.)
La abreviaci@'on @kbd{M-C-\} significa que se presiona la tecla
@key{META}, @key{CTRL}, y @key{\} todo al mismo tiempo. (En muchos
teclados modernos la tecla @key{META} es etiquetada con @key{ALT}.)
Algunas veces una combinaci@'on como esta se llama @emph{keychord},
puesto que es similar a tocar un acorde en un piano. Si el teclado no
tiene una tecla @key{META}, en su lugar se usa la tecla @key{ESC}
como prefijo. En este caso @kbd{M-C-\} significa que se presiona y libera
@key{ESC}
y luego presiona la tecla @key{CTRL} y la tecla @key{\} al mismo
tiempo. Pero
normalmente @kbd{M-C-\} significa presionar la tecla @key{CTRL} junto
a la tecla que est@'a etiquetada @key{ALT} y, al mismo tiempo,
presionar la tecla @key{\}.

Adem@'as de pulsar una sola combinaci@'on de teclas, se puede
prefijar lo que se escribe con @kbd{C-u}, que es llamado el `argumento
universal'. El atajo @kbd{C-u} pasa a ser un argumento para el comando
subsiguiente. De este modo, para indentar una regi@'on de texto plano
a 6 espacios, se marca la regi@'on, y entonces se presiona @w{@kbd{C-u
6 M-C-\}}. (Si no se especifica un n@'umero, Emacs pasa el n@'umero 4
al comando o de otra manera ejecuta el comando de manera
diferente). @xref{Argumentos, , Argumentos Num@'ericos, emacs, El
Manual de GNU Emacs}.

Si se est@'a leyendo esto en Info usando GNU Emacs, se puede avanzar a
trav@'es de este documento completo solo presionando la barra de espacio,
@key{SPC}. (Para aprender acerca de Info, presiona @kbd{C-h i} y
luego selecciona Info.)

Una nota en terminolog@'{@dotless{i}}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.

@node Se agradece
@unnumberedsec Se agradece

Estoy agradecido a todas las personas que me ayudaron con este
libro. Especialmente agradecido a @r{Jim Blandy}, @r{Noah Friedman},
@w{Jim Kingdon}, @r{Roland McGrath}, @w{Frank Ritter}, @w{Randy
Smith}, @w{Richard M.  Stallman}, y @w{Melissa Weisshaus}. Gracias
tambi@'en a @w{Philip Johnson} y @w{David Stampe} por su @'animo
paciente. Mis errores son m@'{@dotless{i}}os.

@flushright
Robert J. Chassell
@email{bob@@gnu.org}
@end flushright

@c ================ Beginning of main text ================

@c Start main text on right-hand (verso) page

@tex
\par\vfill\supereject
\headings off
\ifodd\pageno
    \par\vfill\supereject
\else
    \par\vfill\supereject
    \page\hbox{}\page
    \par\vfill\supereject
\fi
@end tex

@c Note: this resetting of the page number back to 1 causes TeX to gripe
@c about already having seen page numbers 1-4 before (in the preface):
@c   pdfTeX warning (ext4): destination with the same identifier (name{1})
@c   has been already used, duplicate ignored
@c I guess that is harmless (what happens if a later part of the text
@c makes a link to something in the first 4 pages though?).
@c E.g., note that the Emacs manual has a preface, but does not bother
@c resetting the page numbers back to 1 after that.
@iftex
@headings off
@evenheading @thispage @| @| @thischapter
@oddheading @thissection @| @| @thispage
@global@pageno = 1
@end iftex

@node Procesamiento de listas
@chapter Procesamiento de listas

Para el ojo inexperto, Lisp es un lenguaje de
programaci@'on extra@~no. En c@'odigo Lisp hay par@'entesis por todas
partes. Algunas personas incluso reclaman que el nombre signfica `Lots
of Isolated Silly Parentheses' (`Montones de Par@'entesis Aislados
Est@'upidos'). Pero la protesta no tiene fundamento. Lisp es para
procesamiento de listas, y el lenguaje de programaci@'on maneja
@emph{listas} (y listas de listas) poni@'endolas entre
par@'entesis. Los par@'entesis marcan los l@'{@dotless{i}}mites de la
lista. Algunas veces una lista va precedida por un ap@'ostrofe simple
o una marca de cita, @samp{'}@footnote{El ap@'ostrofo o comilla
es una abreviaci@'on para la funci@'on @code{quote};
no necesitas pensar acerca de funciones ahora; las funciones se
definen en @ref{Creando errores, , Generar un mensaje de error}.}
Las listas son el fundamento de Lisp.

@menu
* Listas Lisp::              @questiondown{}Qu@'e 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@'{@dotless{i}}mbolos y 
                               definiciones de funci@'on.
* Interpr@'ete Lisp::        Qu@'e hace el int@'erprete Lisp.
* Evaluaci@'on::             Ejecutando un programa.
* Variables::                Devolviendo un valor desde una variable.
* Argumentos::               Pasando informaci@'on a una funci@'on.
* set y setq::               Configurando el valor de una variable.
* Resumen::                  Los mayores puntos.
* Ejercicios de mensajes de error::  Ejercicios de mensajes de error
@end menu

@node Listas Lisp
@section Listas Lisp
@cindex Listas Lisp

En Lisp, una lista como esta: @code{'(rosa violeta margarita
bot@'ondeoro)}. Esta lista es precedida por una comilla.
Bien, podr@'{@dotless{i}}a estar escrita de la siguente manera, que se
parece
m@'as al tipo de lista con la que se est@'a familiarizado:

@smallexample
@group
'(rosa
  violeta
  margarita
  bot@'ondeoro)
@end group
@end smallexample

@noindent
Los elementos de esta lista son los nombres de 4 flores diferentes,
separados por espacios en blanco y rodeados de par@'entesis, como
flores en un campo con un muro de piedras alrededor de ellas.
@cindex Flores en un campo

@menu
* Listas de n@'umeros::      Lista tener n@'umeros, otras listas, en ellas.
* @'Atomos Lisp::            Entidades Elementales.
* Espacios en blanco en listas::  Formatenado listas para ser legibles.
* Escribiendo listas::       C@'omo GNU Emacs te ayuda a escribir listas.
@end menu

@ifnottex
@node Listas de n@'umeros
@unnumberedsubsec N@'umeros, listas dentro de listas
@end ifnottex

Las listas pueden tambi@'en tener n@'umeros dentro, como en esta lista:
@code{(+ 2 2)}. Esta lista tiene un signo m@'as, @samp{+}, seguido por
dos @samp{2}, cada uno separado por espacios en blanco.

En Lisp, tanto datos como programas est@'an representados de la misma
manera; es decir, s@'on a la vez listas de palabras, n@'umeros, u otras
listas,
separadas por espacios en blanco y rodeadas de par@'entesis. (Puesto
que un programa son datos, un programa puede f@'acilmente servir datos
a otros programas; esta es una funcionalidad muy poderosa de Lisp.)
(Incidentalmente, estas dos marcas de par@'entesis @emph{no} son
listas Lisp, porque contienen @samp{;} y @samp{.} como marcas
de puntuaci@'on.) 

@need 1200
Aqu@'{@dotless{i}} hay otra lista, esta vez con una lista dentro:

@smallexample
'(esta lista tiene (una lista dentro de ella))
@end smallexample

Los componentes de esta lista son las palabras @samp{esta},
@samp{lista}, @samp{tiene}, y la lista @samp{(una lista dentro de
ella)}. La lista interior se construye con las palabras @samp{una},
@samp{lista}, @samp{dentro}, @samp{de}, @samp{ella}.

@node @'Atomos Lisp
@subsection @'Atomos Lisp
@cindex @'Atomos Lisp

En Lisp, lo que hemos estado llamando palabras son en realidad
@dfn{@'atomos}. Este t@'ermino viene del significado hist@'orico de la
palabra
@'atomo, que significa `indivisible'. En lo que a Lisp concierne, las
palabras
que hemos estado usando en las listas no pueden ser divididas en
peque@~nas partes, sin perder su significado dentro del programa; lo
mismo ocurre con n@'umeros y s@'{@dotless{i}}mbolos de un caracterer
como @samp{+}. Por otro lado, a diferencia de un @'atomo, una
lista puede ser dividida en peque@~nas partes. Ver @ref{Car cdr y
cons, , @code{car}, @code{cdr} y @code{cons}, Funciones
Fundamentales}.

En una lista, los @'atomos se separan unos de otros por espacios en
blanco. Pueden ir pegados a un par@'entesis.

@cindex @samp{lista vac@'{@dotless{i}}a} definida
T@'ecnicamente hablando, una lista en Lisp consiste de par@'entesis
alrededor de @'atomos separados por espacios en blanco o alrededor de
otras lista o alrededor de ambos @'atomos u otras listas. Una lista
puede tener solo un @'atomo o no tener absolutamente nada en
ella.  Una lista con nada dentro se ve as@'{@dotless{i}}: @code{()}, y
se llama @dfn{lista vac@'{@dotless{i}}a}. A diferencia de cualquier
otra cosa, una lista vac@'{@dotless{i}}a es tanto un @'atomo, como una
lista al mismo tiempo.

@cindex Expresiones simb@'olicas, introducidas
@cindex @samp{expresi@'on} definida
@cindex @samp{forma} definida
La representaci@'on impresa de @'atomos y listas se llama
@dfn{expresiones simb@'olicas} o, m@'as concisamente,
@dfn{s-expresiones}. La palabra @dfn{expresi@'on} por s@'{@dotless{i}}
misma puede referir o bien a la representaci@'on impresa, o al @'atomo
o a la lista como se maneja internamente en el ordenador. Con
frecuencia, las personas usan el t@'ermino @dfn{expresi@'on}
indiscriminadamente. (Tambi@'en, en muchos textos, la palabra
@dfn{forma} se usa como un sin@'onimo para la expresi@'on.)

Por cierto, los @'atomos que componen nuestro universo fueron nombrados
as@'i
cuando se pensaba que eran indivisibles; pero
pero se ha encontrado que los @'atomos fisicos no son
indivisibles. Las partes pueden dividir un @'atomo o puede fisionarse
en 2 partes de igual tama@~no. Los @'atomos f@'{@dotless{i}}sicos
se nombraron prematuramente, antes de que su verdadera naturaleza
fuese encontrada. En Lisp, ciertos tipos de @'atomos, 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 @'atomos de una lista
son indivisibles.

Como en español, el significado de las letras que componen un @'atomo Lisp
difiere del significado de las letras compuestas como una palabra.
Por ejemplo, la expresi@'on @samp{ay}, es
completamente diferente de las dos palabras @samp{a}, e @samp{y}.

Hay muchos tipos de @'atomos en la naturaleza, pero solo unos pocos en Lisp:
por ejemplo, @dfn{n@'umeros}, tales como 37, 511, o 1729, y
@dfn{s@'{@dotless{i}}mbolos}, tales como @samp{+}, @samp{foo}, o
@samp{forward-line}. Las palabras que hemos listado en los ejemplos
anteriores son todos s@'{@dotless{i}}mbolos. En una conversaci@'on cotidiana
de
Lisp, la palabra ``@'atomo'' no se usa con frecuencia,
porque los programadores normalmente intentan ser m@'as
espec@'{@dotless{i}}ficos acerca de que tipo de @'atomo est@'an
tratando. La programaci@'on Lisp es sobre todo de
s@'{@dotless{i}}mbolos (y algunas veces n@'umeros) con
listas. (De ese modo, tres palabras rodeadas de par@'entesis son una
apropiada lista en Lisp, ya que consiste de @'atomos, que en
este caso son s@'{@dotless{i}}mbolos, separados por espacios en blanco
y cerrados por par@'entesis, sin ninguna puntuaci@'on no Lisp.)

@need 1250
Texto entre comillas---incluso frases o p@'arrafos---son
tambi@'en un @'atomo. Aqu@'{@dotless{i}} hay un ejemplo:
@cindex Texto entre comillas

@smallexample
'(esta lista incluye "texto entre comillas.")
@end smallexample

@cindex @samp{cadena} definida
@noindent
En Lisp, todo el texto citado incluyendo la marca de puntuaci@'on y
los espacios en blanco son un solo @'atomo. Este tipo de @'atomo es
llamado @dfn{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 @'atomo diferente a los
n@'umeros, o s@'{@dotless{i}}mbolos y se usan de manera diferente.

@node Espacios en blanco en listas
@subsection Espacios en blanco en listas
@cindex Espacio en blanco en listas

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

@smallexample
@group
'(esta lista
   parece esto)
@end group
@end smallexample

@need 800
@noindent
es exactamente lo mismo que esto:

@smallexample
'(esta lista parece esto)
@end smallexample

Ambos ejemplos muestran que en Lisp es la misma lista, la lista hecha de
los s@'{@dotless{i}}mbolos @samp{esta}, @samp{lista}, @samp{parece},
y @samp{esto} en este orden.

Los espacios en blanco adicionales y los saltos de l@'inea est@'an
dise@~nados
para crear una lista m@'as legible por humanos. Cuando Lisp lee la
expresi@'on, asimila los espacios en blanco extra (pero necesita tener
al menos un espacio entre @'atomos 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@'as o menos
igual a uno
de estos ejemplos, excepto que la lista puede ser m@'as larga y m@'as
compleja. En resumen, una lista est@'a entre par@'entesis, una cadena
est@'a entre comillas, un s@'{@dotless{i}}mbolo parece como una
palabra, y un n@'umero parece un n@'umero. (Para ciertas situaciones,
corchetes, puntos y otros caracteres especiales pueden ser usados; sin
embargo; iremos bastante lejos sin ellos.)

@node Escribiendo listas
@subsection GNU Emacs te ayuda a escribir listas
@cindex Ayuda escribiendo listas
@cindex Formateando ayuda

Cuando se escribe una expresi@'on Lisp en GNU Emacs usando bien el
modo de Interacci@'on Lisp o el modo Emacs Lisp, est@'an disponibles
varios comandos para formatear la expresi@'on Lisp, de modo que sea
f@'acil de leer. Por ejemplo, presionando la tecla @key{TAB}
autom@'aticamente se indenta la l@'{@dotless{i}}nea donde se encuetra el
cursor
a la cantidad correcta. Un comando para indentar
apropiadamente el c@'odigo en una regi@'on est@'a asociado a
@kbd{M-C-\}. La indentaci@'on est@'a dise@~nada de modo que se pueda ver qué
elementos percecen a cada lista---los
elementos de una sublista est@'an m@'as indentados que los elementos
de una lista cerrada.

Adem@'as, cuando se escribe un par@'entesis de cierre, Emacs
moment@'aneamente salta el cursor atr@'as para hacer el matching
(emparejamiento) con el par@'entesis de apertura, para ver cu@'al
es. Esto es muy @'util, ya que cada lista que se escribe en Lisp debe
tener sus par@'entesis emparejados con sus par@'entesis de
apertura. (Ver @ref{Modos Mayores, Modos Mayores, emacs, El Manual de
GNU Emacs}, para m@'as informaci@'on acerca de modos de Emacs.)

@node Ejecutar un programa
@section Ejecutar un programa
@cindex Ejecuta un programa
@cindex Programa, ejecutando uno

@cindex se defini@'o @samp{evaluate}
Una lista en Lisp ---cualquier lista--- es un programa listo para ser
ejecutado. Si lo ejecutas (lo que la jerga Lisp llama @dfn{evaluar}),
el ordenador har@'a una de tres cosas: nada excepto devolverte la
lista misma; enviar un mensaje de error; o, tomar el primer
s@'{@dotless{i}}mbolo en la lista como un comando para hacer alguna
cosa. (@exclamdown{}Normalmente, es lo @'ultimo de estas tres cosas de
lo que realmente se quiere!). 

@c use code for the single apostrophe, not samp.
El ap@'ostrofe, @code{'}, que se pone enfrente de alg@'unos ejemplos de
lista en secciones anteriores se llama @dfn{quote}; (citar);
cuando precede a una lista, se informa a Lisp no hacer nada con la lista,
mas que la tomarla tal como est@'a escrita. Pero si no hay una cita
precediendo la lista, el primer @'{@dotless{i}}tem de la lista es
especial: es un comando para que el ordenador obedezca. (En Lisp,
estos comandos son llamados @emph{funciones}.) A continuación se muestra la
lista no citada @code{(+ 2 2)}, por lo que Lisp comprende que
@code{+} es una instrucci@'on para hacer alguna cosa con
el resto de la lista: suma los n@'umeros que siguen.

@need 1250
Si est@'as leyendo esto dentro de GNU Emacs en Info,
aqu@'{@dotless{i}} est@'a como puedes evaluar una lista: coloca tu cursor
justo después del paréntesis derecho de la siguiente lista y presiona
@kbd{C-x C-e}:

@smallexample
(+ 2 2)
@end smallexample

@c use code for the number four, not samp.
@noindent
Ver@'as que el n@'umero @code{4} aparece en el @'area echo. (En la jerga, lo
que acabas de hacer es ``evaluar la lista.'' El @'area echo es la
l@'{@dotless{i}}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@'es de la siguiente
lista y presiona @kbd{C-x C-e}:

@smallexample
'(esto es una lista con comillas)
@end smallexample

@noindent
Se ver@'a aparecer @code{(esto es una lista con comillas)} en el @'area
echo.

@cindex Int@'erprete Lisp, explicada
@cindex Int@'erprete, Lisp, explicado
En ambos casos, lo que est@'as haciendo es dar un comando al programa
dentro de GNU Emacs llamado @dfn{int@'erprete Lisp} --- dando al
int@'erprete un comando para evaluar la expresi@'on. El nombre del
int@'erprete Lisp viene de la palabra para la tarea hecha por un
humano que viene con el significado de una expresi@'on --- quien lo
``interpreta''.

Tambi@'en se puede evaluar un @'atomo que no es parte de una lista ---
uno que no est@'a rodeado por par@'entesis; de nuevo, el int@'erprete
Lisp traduce desde la expresi@'on humanamente legible al lenguaje del
ordenador. Pero antes de discutir esto (ver @ref{Variables}), vamos a
discutir lo que el int@'erprete de Lisp hace cuando tu creas el
error.

@node Creando errores
@section Generar un mensaje de error
@cindex Genera un mensaje de error
@cindex Generaci@'on de mensaje de Error

No se preocupe si genera un mensaje de error de manera accidental, ahora
daremos un comando al int@'erprete 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@'{@dotless{i}}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@'odigo
incorporado dentro de GNU Emacs. As@'{@dotless{i}} se `entra al
depurador'. Se puede salir del depurador pulsando @code{q}.

Lo que se hace es evaluar una lista que no est@'a citada y no tiene un
comando con significado como su primer elemento. Aqu@'{@dotless{i}}
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 @kbd{C-x C-e}:

@smallexample
(esto es una lista sin cita)
@end smallexample

@ignore
@noindent
What you see depends on which version of Emacs you are running.  GNU
Emacs version 22 provides more information than version 20 and before.
First, the more recent result of generating an error; then the
earlier, version 20 result.

@need 1250
@noindent
In GNU Emacs version 22, a @file{*Backtrace*} window will open up and
you will see the following in it:
@end ignore

Se abrir@'a una ventana @file{*Backtrace*} y se ver@'a lo siguiente:

@smallexample
@group
---------- 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* ----------
@end group
@end smallexample

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

@smallexample
q
@end smallexample

@noindent
Por favor, ahora pulsa @kbd{q}, as@'{@dotless{i}} se comprueba que se
puede salir del depurador. A continuacion, presione "@kbd{C-x C-e} una
vez m@'as para re-entrar.

@cindex @samp{funci@'on} definida
Sobre la base de lo que ya sabemos, casi podemos leer este mensaje de error.

Leer el b@'uffer @file{*Backtrace*} de abajo hacia arriba; informa lo que
Emacs ha hecho. Cuando se presiona @kbd{C-x C-e}, se hace una llamada
interactiva a el comando @code{eval-last-sexp}. @code{eval} es una
abreviatura para `evaluar' y @code{sexp} es una abreviatura para
`expresi@'on simb@'olica'. El comando significa `eval@'ua la
@'ultima expresi@'on simb@'olica', que es la expresi@'on justo antes
de tu cursor.

Cada l@'{@dotless{i}}nea anterior a esta cuenta lo que el int@'erprete de
Lisp evaluo despu@'es. La acci@'on m@'as reciente est@'a en la parte
superior. El
b@'uffer es llamado @file{*Backtrace*} ya que permite realizar un
seguimiento
de Emacs hacia atr@'as.

@need 800
En la parte superior del b@'uffer @file{*Backtrace*}, ver@'a la
l@'{@dotless{i}}nea:

@smallexample
Debugger entered--Lisp error: (void-function esto)
@end smallexample

@noindent
El int@'erprete Lisp intent@'o evaluar el primer @'atomo de la lista,
la palabra @samp{esto}. Esta es la acci@'on que gener@'o el mensaje de error
@samp{void-function esto}.

El mensaje contiene las palabras @samp{void-function} y @samp{esto}.

@cindex @samp{funci@'on} definida
La palabra @samp{function} fu@'e mencionada antes. Es una palabra muy
importante. Para nuestros prop@'ositos, podemos definirla diciendo
que una @dfn{funci@'on} (@emph{function}) es un conjunto de
instrucciones para decirle al ordenador que haga alguna cosa.

Ahora podemos empezar a comprender el mensaje de error:
@samp{void-function this}. La funci@'on (que es, la palabra
@samp{this}) no tiene la definici@'on de ningun conjunto de
instrucciones que el ordenador pueda realizar.

La palabra ligeramente extra@~na, @samp{void-function}, est@'a dise@~nada
para
cubrir la forma en que Emacs Lisp lo implementa, que es cuando un s@'imbolo
no tiene una definici@'on de funci@'on atribuido, el sitio que contiene la
instrucci@'on esta `vac@'io' (@samp{void}).

Por otro lado, ya que fuimos capaces de a@~nadir 2 m@'as 2 de
manera exitosa, evaluando @code{(+ 2 2)}, se puede inferir que el
s@'{@dotless{i}}mbolo @code{+} debe tener un conjunto de instrucciones
que el ordenador ejecuta y estas instrucciones deben sumar
los n@'umeros despues del @code{+}.

Es posible evitar que Emacs entre en el depurador en casos como
este. No se explicar@'a c@'omo hacer esto aqu@'{@dotless{i}}, pero se
mencionar@'a un resultado asi, porque se puede encontrar una
situaci@'on similar si hay un error en alg@'un c@'odigo de Emacs que
este usando. En tales casos, ver@'a solo una l@'{@dotless{i}}nea del
mensaje de error; aparecer en el @'area echo con el siguente aspecto

@smallexample
Symbol's function definition is void:@: esto
@end smallexample

@noindent
@ignore
(Also, your terminal may beep at you---some do, some don't; and others
blink.  This is just a device to get your attention.)
@end ignore
El mensaje aparece tan pronto se presiono una tecla, aunque sólo sea para
mover el cursor.

Conocemos el significado de la palabra
@samp{S@'{@dotless{i}}mbolo}. Se refiere al primer @'atomo de la
lista, la palabra @samp{este}. La palabra @samp{funci@'on} se refiere
a las instrucciones que dicen al ordenador que
hacer. (T@'ecnicamente, el s@'{@dotless{i}}mbolo indica al ordenador
donde encontrar las instrucciones, pero esta es una complicaci@'on que
podemos ignorar por el momento.)

El mensaje de error puede ser comprendido: @samp{La definici@'on del
s@'{@dotless{i}}mbolo est@'a vac@'{@dotless{i}}a: este}. El
s@'{@dotless{i}}mbolo (que es, la palabra @samp{este}) carece de
instrucciones que el ordenador realize.

@node Nombres y definiciones
@section Nombres de s@'{@dotless{i}}mbolos y definiciones de funciones
@cindex Nombres de S@'{@dotless{i}}mbolos

Se puede articular otra caracter@'{@dotless{i}}stica de Lisp basada en
lo que se discuti@'o hace tiempo---una caracter@'{@dotless{i}}stica
importante: un s@'{@dotless{i}}mbolo, como @code{+}, no es en
s@'{@dotless{i}} mismo el conjunto de instrucciones que el ordenador
realiza. En su lugar, el s@'{@dotless{i}}mbolo es usado,
quiz@'as temporalmente, como una manera de localizar la definici@'on 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 @samp{Bob}; sin embargo, no soy las letras @samp{B}, @samp{o}, @samp{b}
pero soy, o
o fu@'{@dotless{i}}, 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@~nadir
n@'umeros pueden ser enlazados al s@'{@dotless{i}}mbolo @code{m@'as}
tan bien como el s@'{@dotless{i}}mbolo @code{+} (y se encuantran en algunos
dialectos de Lisp). Entre humanos, puede referirse a @samp{Robert} tan
bien como @samp{Bob} y en otras palabras tambi@'en.

Por otra parte, un s@'{@dotless{i}}mbolo puede estar ligado solo con una
funci@'on
a la vez. De lo contrario, el ordenador
estar@'{@dotless{i}}a confundido acerca de qu@'e definici@'on usar. Si
este fuera el caso, solo una persona en el mundo podr@'{@dotless{i}}a
llamarse @samp{Bob}. Sin embargo, la definici@'on de funci@'on a la
que el nombre hace referencia puede cambiarse f@'acilmente.
(Ver @ref{Instalar, , Instalar una Definici@'on de Funci@'on}.)

Ya que Emacs Lisp es extenso, se acostumbra nombrar los
s@'{@dotless{i}}mbolos de un modo que pueda establecerse a que parte de
Emacs
pertenece la funci@'on. En consecuencia, todos los nombres de
funciones relacionadas con Texinfo empiezan con @samp{texinfo-} y aquellas
relaciondas con la lectura de correo empiezan con
@samp{rmail-}.

@node Interpr@'ete Lisp
@section El int@'erprete Lisp
@cindex Int@'erprete Lisp, qu@'e hace
@cindex Int@'erprete, qu@'e hace

Basado en lo que se ha visto, ahora podemos empezar a entender lo que
el int@'eprete Lisp hace cuando mandamos a evaluar una
lista. Primero, examina si hay un s@'{@dotless{i}}mbolo cita
antes de la lista; si lo hay, el int@'erprete nos da la lista. Por otro
lado, si no hay cita, el int@'eprete mira si el primer elemento en la
lista tiene una definici@'on de funci@'on. Si no, el
int@'erprete imprime un mensaje de error.

As@'{@dotless{i}} es como Lisp trabaja. Simple. Hay complicaciones
a@~nadidas que veremos en un minuto, pero estos son
los fundamentos. Claro est@'a, para escribir programas Lisp, se necesita
conocer como escribir definiciones de funci@'on y vincularlas a
nombres, y como hacer esto sin confundirnos a nosotros mismos o al
ordenador.

@menu
* Complicaciones::           Variables, formas especiales, Listas.
* Compilaci@'on de bytes::   Especialmente procesando c@'odigo por la 
                               velocidad.
@end menu

@ifnottex
@node Complicaciones
@unnumberedsubsec Complicaciones
@end ifnottex

Ahora, una primera complicaci@'on. Adem@'as de las listas, el
int@'erprete Lisp puede evaluar un s@'{@dotless{i}}mbolo no
citado que no tiene par@'entesis
en torno a el. El int@'erprete Lisp intentar@'a determinar el valor del
s@'{@dotless{i}}mbolo como una @dfn{variable}. Esta situaci@'on es
descrita en el apartado de las variablesla. (Ver @ref{Variables}.)

@cindex Forma Especial
La segunda complicaci@'on ocurre debido a que algunas funciones son
inusuales y no funcionan de la manera habitual. Estas son llamadas
@dfn{formas especiales}. Son usadas para trabajos especiales, como
definir una funci@'on, y no son muchas de ellas. En los siguientes
cap@'{@dotless{i}}tulos, se introducir@'an varias de las
formas especiales m@'as importantes.

La tercera y final complicaci@'on es la siguiente: si la funci@'on que
el int@'erprete Lisp est@'a buscando no es una forma especial, y si
es parte de una lista, el int@'erprete Lisp mira si la lista
tiene una lista dentro de ella. Si hay una lista dentro, el int@'erprete
Lisp
primero descubre qu@'e hacer con la lista interior, y luego trabaja en la
lista exterior. Si a@'un hay otra lista embebida
dentro de la lista interna, trabaja en esta primero, y
as@'{@dotless{i}}. Siempre se trabaja en la lista m@'as interna primero. El
int@'erprete trabaja en la lista más interana primero, para evaluar el
resultado de esta lista. El resultado puede ser usado por la
expresi@'on entre par@'entesis.

Por lo dem@'as, el int@'erprete trabaja de izquierda a derecha, desde
una expresi@'on a la siguiente.

@node Compilaci@'on de bytes
@subsection Compilaci@'on de bytes
@cindex Compilando Byte

Otro aspecto de interpretaci@'on: el int@'erprete Lisp es capaz de
interpretar dos tipos de entidad: c@'odigo humanamente legible, en el
que nos centraremos exclusivamente, y c@'odigo especialmente procesado,
llamado @dfn{byte compilado}, que no es humanamente legible. El
c@'odigo m@'aquina compilado se ejecuta m@'as r@'apido que el c@'odigo
humanamente legible.

Tu puedes transformar c@'odigo legible por humanos en c@'odigo compilado
ejecutando uno de los comandos de compilacion como
@code{byte-compile-file}. El c@'odigo compilado es normalmente
almacenado en un fichero que finaliza con una extensi@'on @file{.elc}
en vez de una extensi@'on @file{.el}. Ver@'as ambos tipos de ficheros
en el directorio @file{emacs/lisp}; los ficheros para leer estos
tienen la extensi@'on @file{.el}.

Como una cuesti@'on pr@'actica, para hacer la mayor@'{@dotless{i}}a de las
cosas como personalizar o extender Emacs, no
necesitas compilar byte; y no comentare el asunto
aqu@'{@dotless{i}}. Ver @ref{Compilaci@'on de Byte, , Compilaci@'on de
Byte, elisp, El Manual de Referencia de GNU Emacs}, para una completa
descripci@'on sobre compilar c@'odigo.

@node Evaluaci@'on
@section Evaluaci@'on
@cindex Evaluaci@'on

Cuando el int@'erprete Lisp trabaja en una expresi@'on, el t@'ermino
para la actividad es llamada @dfn{evaluaci@'on}. Decimos que el
int@'erprete `eval@'ua la expresi@'on'. Yo he usado este t@'ermino
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 @cite{Webster's New Collegiate Dictionary}.

@menu
* C@'omo el int@'erprete act@'ua::  Devolver y Efectos Colaterales...
* Evaluando listas propias::  Listas con listas...
@end menu

@ifnottex
@node C@'omo el int@'erprete act@'ua
@unnumberedsubsec C@'omo el int@'erprete act@'ua
@end ifnottex

@cindex @samp{valor devuelto} explicado
Despu@'es de evaluar una expresi@'on, el int@'erprete Lisp normalmente
@dfn{devuelve} el valor que el ordenador produce al llevar a cabo
las instrucciones encontradas en la definici@'on de la funci@'on, o
quiz@'as dar@'a esta funci@'on y producir@'a un mensaje de error. (El
int@'erprete puede tambi@'en quedarse colgado, por as@'{@dotless{i}}
decirlo, a una funci@'on diferente o puede intentar repetir
continuamente lo que est@'a haciendo y para siempre en lo que
se llama un `bucle infinito'. Estas acciones son menos
comunes; y pueden ignorarse). M@'as frecuentemente, el int@'erprete
devuelve un valor.

@cindex @samp{efecto lateral} definido
Al mismo tiempo el int@'erprete devuelve un valor, puede hacer
cualquier cosa m@'as tambi@'en, tal como mover un cursor o copiar un
fichero; este otro tipo de acci@'on es llamado @dfn{efecto
secundario}. Acciones que los humanos creen que son importantes tales
como imprimir resultados, con frecuencia son, ``efectos secundarios'' del
int@'erprete Lisp. La jerga puede sonar peculiar, pero resulta que es
bastante f@'acil aprender a utilazar los efectos secundarios.

En resumen, evaluar una expresi@'on simb@'olica normalmente
causa que el int@'erprete devuelva un valor y tal vez llevar a cabo un
efecto
secundario; o al menos produce un error.

@node Evaluando listas propias
@subsection Evaluando listas propias
@cindex Evaluaci@'on de listas internas
@cindex Evaluando listas internas

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

@need 1250
Nosotros podemos investigar este proceso evaluando otro ejemplo
adicional. Coloca tu cursor despu@'es de la siguiente expresi@'on y
presiona @kbd{C-x C-e}:

@smallexample
(+ 2 (+ 3 3))
@end smallexample

@noindent
El n@'umero 8 aparecer@'a en el @'area echo.

Lo que ocurre es que el int@'erprete Lisp primero eval@'ua la
expresi@'on interna, @code{(+ 3 3)}, para que el valor 6 se devuelva;
a continuaci@'on eval@'ua la expresi@'on externa como si fuera escrita
@code{(+ 2 6)}, que devuelve el valor 8. Puesto que no hay m@'as
expresiones entre parentesis a evaluar el int@'erprete imprime este valor
en el @'area echo.

Ahora es f@'acil comprender el nombre del comando invocado por
el atajo @kbd{C-x C-e}: el nombre es @code{eval-last-sexp}. Las letras
@code{sexp} son una abreviaci@'on para `expresi@'on simb@'olica', y
@code{eval} es una abreviaci@'on para `evaluar'. El comando significa
`evaluar la @'ultima expresi@'on simb@'olica'.

Como un experimento, puedes intentar evaluar la expresi@'on
poniendo el cursor al principio de la siguiente l@'{@dotless{i}}nea
inmediatamente despu@'es de la expresi@'on, o dentro de la expresi@'on.

@need 800
Aqu@'{@dotless{i}} hay otra copia de la expresi@'on:

@smallexample
(+ 2 (+ 3 3))
@end smallexample

@noindent
Si se posiciona el cursor al principio de la l@'{@dotless{i}}nea en
blanco que sigue inmediatamente a la expresi@'on y presionas @kbd{C-x
C-e}, todav@'{@dotless{i}}a se obtendr@'a el valor 8 impreso en el
@'area echo. Ahora intenta poner el cursor dentro de la
expresi@'on. Si lo coloca justo despu@'es del penultimo
par@'entesis (dara la impresi@'on de situarse sobre el
@'ultimo par@'entesis), @exclamdown{}obtendr@'a un 6 impreso en
el @'area echo!  Esto es porque el comando eval@'ua la expresi@'on
@code{(+ 3 3)}.

Ahora coloque el cursor inmediatamente despu@'es de un
n@'umero. Presiona @kbd{C-x C-e} y obtendr@'a el n@'umero en
s@'{@dotless{i}}. En Lisp, si eval@'uas un n@'umero, obtienes el
n@'umero en s@'{@dotless{i}}---as@'i es c@'omo los n@'umeros difieren
de los s@'{@dotless{i}}mbolos. Si se eval@'ua una lista que inicia con
un s@'{@dotless{i}}mbolo como @code{+}, tendr@'as un valor devuelto
que es el resultado del ordenador tras ejecutar las instrucciones que
aparecen
en la definici@'on de la funci@'on adjunta a este nombre. Si un
s@'{@dotless{i}}mbolo por s@'{@dotless{i}} mismo es evaluado, algo
diferente sucede, como veremos en la siguiente secci@'on.

@node Variables
@section Variables
@cindex Variables

En Emacs Lisp, un s@'{@dotless{i}}mbolo puede estar ligado a un valor
como a una definici@'on de funci@'on. Las dos son
diferentes. La definici@'on de funci@'on es un conjunto de
instrucciones que el ordenador ejecuta. Un valor, por otro lado, es
algo, como un n@'umero o un nombre, que puede variar (es por ello, que
tal s@'{@dotless{i}}mbolo es llamado variable). El valor
de un s@'{@dotless{i}}mbolo puede ser cualquier expresi@'on en Lisp, por
ejemplo un s@'{@dotless{i}}mbolo, n@'umero, lista, o cadena. Un
s@'{@dotless{i}}mbolo que tiene un valor es con frecuencia llamado una
@dfn{variable}.

Un s@'{@dotless{i}}mbolo puede tener ambos, una definici@'on de
funci@'on 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@'on ligada al nombre, por ejemplo, un ``gran
centro de programaci@'on''.

@ignore
(Incidentally, in Emacs Lisp, a symbol can have two
other things attached to it, too: a property list and a documentation
string; these are discussed later.)
@end ignore

Otra forma de pensar en esto es imaginar un s@'imbolo como un mueble con
cajones. La definici@'on de funci@'on se pone en un caj@'on, 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@'on que almacena la
definici@'on de funci@'on, y viceversa.

@menu
* Ejemplo de rellenar columna::  Ejemplo de rellenar columna
* Funci@'on vac@'{@dotless{i}}a::  El mensaje de error para un 
                                     s@'{@dotless{i}}mbolo sin una funci@'on.
* Variable vac@'{@dotless{i}}a::  El mensaje de error para un 
                                    s@'{@dotless{i}}mbolo sin un valor.
@end menu

@ifnottex
@node Ejemplo de rellenar columna
@unnumberedsubsec @code{fill-column}, un ejemplo de variable
@end ifnottex

@findex fill-column, @r{una variable de ejemplo}
@cindex Variable de Ejemplo, @code{fill-column}
@cindex Variable, ejemplo de, @code{fill-column}
La variable @code{fill-column} ilustra un s@'{@dotless{i}}mbolo con un
valor adjunto: en cada buffer de GNU Emacs, este s@'{@dotless{i}}mbolo
se establece a alg@'un valor, normalmente 72 o 70, pero algunas veces
a alg@'un otro valor. Para encontrar el valor de este
s@'{@dotless{i}}mbolo, eval@'ualo por s@'{@dotless{i}} mismo. Si est@'a
leyendo esto en Info dentro de GNU Emacs, puedes hacer esto
poniendo el cursor despu@'es del s@'{@dotless{i}}mbolo y pulsar
@kbd{C-x C-e}:

@smallexample
fill-column
@end smallexample

@noindent
Despu@'es de presionar @kbd{C-x C-e}, Emacs imprimi@'o el
n@'umero 72 en mi @'area echo. Este es el valor que he establecido para
@code{fill-column} mientras escribo esto. Puede
ser diferente para ti en tu b@'uffer Info. Observe que el valor devuelto
como una variable es impreso exactamente de la misma forma que el
valor devuelto por una funci@'on tras ejecutar sus instrucciones. Desde
el punto de vista del int@'erprete Lisp, un valor devuelto es un valor
devuelto. Que
tipo de expresi@'on sea, deja de importar una vez que el valor
se conoce.

Un s@'{@dotless{i}}mbolo puede tener cualquier valor ligado a él o,
siendo tecnicos, se puede @dfn{bind} (asociar) la variable a un valor: a
un n@'umero, por ejemplo 72; a una cadena, @code{\"como esta\"}; a
una lista, como @code{(abeto pino roble)}; podemos incluso asociar
una variable a una definici@'on de funci@'on.

Un s@'{@dotless{i}}mbolo puede vincularse a un valor de varias
maneras. Ver @ref{set y setq, , Configurando el valor de una variable},
para obtener informaci@'on sobre una manera de hacer esto.

@node Funci@'on vac@'{@dotless{i}}a
@subsection Mensaje de error de un s@'{@dotless{i}}mbolo sin una funci@'on
@cindex S@'{@dotless{i}}mbolo sin funci@'on de error
@cindex Error para s@'{@dotless{i}}mbolo sin funci@'on

Cuando se eval@'ua @code{fill-column} para encontrar el valor de una
variable, no se ponen par@'entesis alrededor de la palabra. Esto es
porque no pretendemos usarlos como un nombre de funci@'on.

Si @code{fill-column} fuese el primer o @'unico elemento de una lista,
el int@'erprete de Lisp intentar@'{@dotless{i}}a encontrar la
definici@'on de funci@'on adjunta. Pero @code{fill-column} no tiene
una definici@'on de funci@'on. Prueba evaluando esto:

@smallexample
(fill-column)
@end smallexample

@need 1250
@noindent
Se crear@'a un buffer @file{*Backtrace*} que dice:

@smallexample
@group
---------- 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* ----------
@end group
@end smallexample

@noindent
(Recuerda, para salir del depurador y hacer que la ventana del depurador
desaparezca, presiona @kbd{q} en el buffer @file{*Backtrace*}.)

@ignore
@need 800
In GNU Emacs 20 and before, you will produce an error message that says:

@smallexample
La definici@'on de s@'{@dotless{i}}mbolos de funci@'on:@: fill-column
@end smallexample

@noindent
(The message will go away as soon as you move the cursor or type
another key.)
@end ignore

@node Variable vac@'{@dotless{i}}a
@subsection Mensaje de error de un s@'{@dotless{i}}mbolo sin un valor
@cindex S@'{@dotless{i}}mbolo sin valor de error
@cindex Error para s@'{@dotless{i}}mbolo sin valor

Si se intenta evaluar un s@'{@dotless{i}}mbolo que no tiene un valor
asociado, recibir@'a un mensaje de error. Esto se puede ver
experimentando con nuestra suma 2 m@'as 2. En la siguiente
expresi@'on, pon el cursor correcto despu@'es del @code{+}, antes del
primer n@'umero 2, presiona @kbd{C-x C-e}:

@smallexample
(+ 2 2)
@end smallexample

@need 1500
@noindent
En GNU Emacs 24, se crear@'a un buffer @file{*Backtrace*} que dice:

@smallexample
@group
---------- 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* ----------
@end group
@end smallexample

@noindent
(De nuevo, se puede salir del depurador pulsando @kbd{q} en el
b@'uffer @file{*Backtrace*}.)

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

En este experimento con el @code{+}, lo que se hizo fu@'e causar
que el int@'erprete Lisp eval@'ue el @code{+} y busque el valor de la
variable en vez de la definici@'on de la funci@'on. Hicimos
esto colocando el cursor justo despu@'es del s@'{@dotless{i}}mbolo en
lugar de ponerlo al final de los par@'entesis que cierran la lista como
hicimos
antes. Como consecuencia, el int@'erprete Lisp evalu@'o la
s-expresi@'on anterior, que en este caso fu@'e el @code{+} en
s@'{@dotless{i}}.

Ya que @code{+} no tiene un valor asociado, solo la definici@'on de
funci@'on, el mensaje de error informa que el valor del
s@'{@dotless{i}}mbolo como una variable estaba vac@'{@dotless{i}}o.

@ignore
@need 800
In GNU Emacs version 20 and before, your error message will say:

@example
El valor de s@'{@dotless{i}}mbolo como variable est@'a
vac@'{@dotless{i}}o:@: +
@end example

@noindent
The meaning is the same as in GNU Emacs 22.
@end ignore

@node Argumentos
@section Argumentos
@cindex Argumentos
@cindex Pasando informaci@'on para funciones

Para ver c@'omo la informaci@'on se pasa a las funciones, veamos
de nuevo a nuestro viejo recurso, la adici@'on de dos m@'as dos. En
Lisp, esto se escribe como sigue:

@smallexample
(+ 2 2)
@end smallexample

Si se eval@'ua esta expresi@'on, el n@'umero 4 aparecer@'a en tu @'area
echo. Lo que el int@'erprete de Lisp hace es sumar los n@'umeros despues
del @code{+}.

@cindex @samp{argumento} definido
Los n@'umeros sumados por @code{+} son llamados @dfn{argumentos} de
la funci@'on @code{+}. Estos n@'umeros son la informaci@'on que se
da o @dfn{pasa} a la funci@'on.

La palabra `argumento' viene del @'ambito de las matem@'aticas y no se
refiere a una disputa entre 2 personas, sino que se refiere a la
informaci@'on presentada a la funci@'on, en este caso, al @code{+}. En
Lisp, los argumentos de una funci@'on son los @'atomos o listas que
siguen a la funci@'on. Los valores devueltos por la evaluaci@'on de
estos @'atomos o listas son pasados a la funci@'on. Funciones
diferentes requieren diferentes n@'umeros de argumentos; algunas
funciones no requieren ninguno en absoluto.@footnote{Es curioso trazar la
ruta por la cual la palabra `argumento' llego a tener dos
significados distintos, uno en matem@'aticas y el otro en el ingl@'es
cotidiano. De acuerdo al @cite{Oxford English
Dictionary}, la palabra deriva del Lat@'{@dotless{i}}n para
@samp{dejar claro, probar}, por lo tanto, paso a significar, por un hilo de
derivaci@'on, `la evidencia ofrecida como prueba', es decir `la
informaci@'on
que se ofrece', que conduce a su significado en Lisp.
Pero en el otro hilo de derivaci@'on, 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@'otese aqu@'{@dotless{i}} que la
palabra Ingl@'esa tiene dos definiciones diferentes adjuntas al mismo
tiempo. En contraste, en Emacs Lisp, un s@'{@dotless{i}}mbolo no puede
tener dos definiciones de funci@'on diferentes al mismo tiempo.)}

@menu
* Tipos de datos::           Tipos de datos pasados a una funci@'on.
* Argumentos como variables o listas::  Un argumento puede ser el valor de 
                                          una variable o lista.
* N@'umero de variables de argumentos::  Algunas funciones pueden tomar un 
                                           n@'umero variable de argumentos.
* Tipo incorrecto de argumento::  Pasando un argumento del tipo incorrecto a 
                                    una funci@'on.
* message::                  Una funci@'on @'util para enviar mensajes.
@end menu

@node Tipos de datos
@subsection Tipos de argumentos de datos
@cindex Tipos de datos
@cindex Tipos de datos
@cindex Tipos de dato de los argumentos

Los tipos de datos que deber@'{@dotless{i}}an ser pasados a una
funci@'on dependen de que tipo de informaci@'on usan. Los argumentos de
una funci@'on como @code{+} deben tener valores que son
n@'umeros, puesto que @code{+} a@~nade n@'umeros. Otras funciones usan
diferentes tipos de datos para sus argumentos.

@need 1250
@findex concatenar
Por ejemplo, la funci@'on @code{concat} concatena o une dos o m@'as
cadenas de texto para producir una cadena. Los argumentos son
cadenas. La concatenaci@'on de los dos caracteres de cadenas
@code{abc}, @code{def} produce una cadena @code{abcdef}. Esto
puede ser visto evaluando lo siguiente:

@smallexample
(concat "abc" "def")
@end smallexample

@noindent
El valor producido para evaluar esta expresi@'on es @code{"abcdef"}.

Una funci@'on tal como @code{substring} usa como argumento tanto una
cadena como n@'umeros. La funci@'on devuelve una parte de la cadena,
una subcadena del primer argumento. Esta funci@'on toma tres
argumentos. Su primer argumento es la cadena de caracteres, el segundo
y tercer argumento son n@'umeros que indican el principio y el fin de la
subcadena. Los n@'umeros son un conteo del n@'umero de caracteres
(incluyendo espacios y puntuaciones) desde el principio de la cadena.

@need 800
Por ejemplo, si eval@'ua lo siguiente:

@smallexample
(substring "El r@'apido zorro marr@'on salt@'o." 10 15)
@end smallexample

@noindent
se ver@'a @code{"zorro"} en el @'area echo. Los argumentos son la cadena
y los dos n@'umeros.

N@'otese que la cadena pasada a @code{substring} es un solo @'atomo
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@'on
@code{substring} como un tipo de `acelerador de particulas' ya que toma
un @'atomo indivisible y extrae una parte. Sin embargo,
@code{substring} solo es capaz de extraer una subcadena desde un
argumento que es una cadena, no otro tipo de @'atomo tal como un
n@'umero o s@'{@dotless{i}}mbolo.

@node Argumentos como variables o listas
@subsection Un argumento como el valor de una variable o lista

Un argumento puede ser un s@'{@dotless{i}}mbolo que devuelva un valor
cuando es evaluado. Por ejemplo, evaluar el s@'{@dotless{i}}mbolo
@code{fill-column} en si, devuelve un
n@'umero. Este n@'umero puede ser usado en una adici@'on.

@need 1250
Posicionar el cursor despu@'es de la siguiente expresi@'on y presiona
@kbd{C-x C-e}:

@smallexample
(+ 2 fill-column)
@end smallexample

@noindent
El valor ser@'a dos m@'as el n@'umero que se obtiene al evaluar solamente
@code{fill-column}. En m@'{@dotless{i}} caso, este es 74, porque mi
valor de @code{fill-column} es 72.

Como acabamos de ver, un argumento puede ser un s@'{@dotless{i}}mbolo que
devuelve un valor cuando se eval@'ua. Adem@'as, un argumento puede
ser una lista que devuelve un valor cuando es evaluada. Por ejemplo,
en la siguiente expresi@'on, los argumentos de la funci@'on
@code{concat} son las cadenas @w{@code{"Los"}} y @w{@code{" zorros
rojos."}} y la lista @code{(number-to-string (+ 2 fill-column))}.

@c For GNU Emacs 22, need number-to-string
@smallexample
(concat "Los " (number-to-string (+ 2 fill-column)) " zorros rojos.")
@end smallexample

@noindent
Si se eval@'ua esta expresi@'on---y si, como con mi Emacs,
@code{fill-column} se eval@'ua a 72---aparecer@'a @code{"Los 74
zorros rojos."} en el @'area echo. (N@'otese que se debe poner espacio
despu@'es de la palabra @samp{Los} y antes de la palabra @samp{rojos}
y as@'{@dotless{i}} es como aparecer@'a en la cadena final. La
funci@'on @code{number-to-string} convierte el entero que devuelve la
funci@'on de adici@'on a una cadena. @code{number-to-string}
tambi@'en se conoce como @code{int-to-string}.)

@node N@'umero de variables de argumentos
@subsection N@'umero de variables de argumentos
@cindex N@'umero variable de argumentos
@cindex Argumentos, n@'umero variable de

Algunas funciones, como @code{concat}, @code{+}, o @code{*},
toman cualquier n@'umero de argumentos. (El @code{*} es el
s@'{@dotless{i}}mbolo para multiplicar.) Esto puede ser visto
evaluando cada una de las siguientes expresiones de la forma
habitual. Lo que ver@'as en el @'area echo se imprime en este texto
despu@'es de @samp{@result{}}, que se puede leer como `evaluar a'.

@need 1250
En el primer conjunto, las funciones no tienen argumentos:

@smallexample
@group
(+)       @result{} 0

(*)       @result{} 1
@end group
@end smallexample

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

@smallexample
@group
(+ 3)     @result{} 3

(* 3)     @result{} 3
@end group
@end smallexample

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

@smallexample
@group
(+ 3 4 5) @result{} 12

(* 3 4 5) @result{} 60
@end group
@end smallexample

@node Tipo incorrecto de argumento
@subsection Usando el tipo incorrecto de objeto como un argumento
@cindex Tipo incorrecto de argumento
@cindex Argumento, tipo incorrecto de

Cuando a una funci@'on se le pasa un argumento del tipo incorrecto, el
interpr@'ete Lisp produce un mensaje de error. Por ejemplo, la
funci@'on @code{+} espera que los valores de sus argumentos sean
n@'umeros. Como un experimento podemos pasar el
s@'{@dotless{i}}mbolo citado @code{hola} en vez de un
n@'umero. Coloca el cursor despu@'es de la siguiente expresi@'on y
presiona @kbd{C-x C-e}:

@smallexample
(+ 2 'hola)
@end smallexample

@noindent
Al hacer esto se generar@'a un mensaje de error. Lo qu@'e ha
ocurrido es que @code{+} ha intentado a@~nadir el 2 al valor
devuelto por @code{'hola}, pero el valor devuelto por @code{'hola}
es el s@'{@dotless{i}}mbolo @code{hola}, no un n@'umero. Solo los
n@'umeros pueden ser a@~nadidos. Por tanto @code{+}
no pudo llevar a cabo su adici@'on.

@need 1250
Se crear@'a e introducir@'a un b@'uffer @file{*Backtrace*} que dice:

@noindent
@smallexample
@group
---------- 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* ----------
@end group
@end smallexample

@need 1250
Como de costumbre, el mensaje de error intenta ser @'util y tiene sentido
despu@'es de aprender c@'omo leerlo.@footnote{@code{(quote
hola)} es una expansi@'on de la abreviatura @code{'hola}.}

La primera parte del mensaje de error es sencilla; dice @samp{wrong
type argument} (tipo de argumento incorrecto). A continuación viene la
misteriosa palabra tecnica @w{@samp{number-or-marker-p}}. Esta
palabra est@'a intentando decirte qu@'e tipo de argumento espera @code{+}.

El s@'{@dotless{i}}mbolo @code{number-or-marker-p} dice que el
int@'erprete Lisp est@'a intentando determinar si la informaci@'on
presentada (el valor del argumento) es un n@'umero o una marca (un
objeto especial que representa una posici@'on de buffer). Lo que hace
es probar si se le estan dando numeros a sumar a @code{+}.
Tambi@'en chequea si el argumento es algo llamado
un marcador, que es una caracteristica espec@'{@dotless{i}}fica de
Emacs Lisp. (En Emacs, las ubicaciones en un b@'uffer se registran
como marcadores. Cuando se establece la marca con el comando
@kbd{C-@@} o @kbd{C-@key{SPC}}, su posici@'on se guarda como un
marcador. La marca puede ser considerada como un n@'umero---el n@'umero de
caracteres es la localizaci@'on desde el principio del b@'uffer.)
En Emacs Lisp, @code{+} se puede utilizar para a@~nadir el valor
num@'erico de los marcadores como n@'umeros.

La @samp{p} de @code{number-or-marker-p} es la encarnaci@'on de una
pr@'actica iniciada en los primeros d@'{@dotless{i}}as de la
programaci@'on Lisp. La @samp{p} significa `predicado'. En la jerga
usada por los primeros investigadores de Lisp, un predicado se refiere
a una funci@'on para determinar si alguna propiedad es verdadera o
falsa. As@'{@dotless{i}} la @samp{p} nos dice que
@code{number-or-marker-p} es el nombre de una funci@'on que determina
si el argumento dado es un n@'umero o una marca. Otros
s@'{@dotless{i}}mbolos Lisp que finalizan en @samp{p} incluyen
@code{zerop}, una funci@'on que chequea si su argumento tienen el
valor de cero, y @code{listp}, una funci@'on que prueba si su
argumento es una lista.

Finalmente, la @'ultima parte del mensaje de error es el
s@'{@dotless{i}}mbolo @code{hola}. Este es el valor del argumento
dado a @code{+}. Si a la adici@'on se le hubiese pasado el
tipo correcto de objeto, el valor habr@'{@dotless{i}}a sido un
n@'umero, como 37, en lugar de un s@'{@dotless{i}}mbolo como
@code{hola}. Pero entonces no habr@'{@dotless{i}}as obtenido el
mensaje de error.

@ignore
@need 1250
In GNU Emacs version 20 and before, the echo area displays an error
message that says:

@smallexample
Mal tipo de argumento:@: number-or-marker-p, hello
@end smallexample

This says, in different words, the same as the top line of the
@file{*Backtrace*} buffer.
@end ignore

@node message
@subsection La funci@'on @code{message}
@findex message

Al igual que @code{+}, la funci@'on @code{message} toma un n@'umero variable
de argumentos. Se utiliza para enviar mensajes al usuario y es
tan @'util que vamos a describirla.

@need 1250
Se impre un mensaje en el @'area echo. Por ejemplo, puede
imprimir un mensaje en su @'area echo evaluando la siguiente lista:

@smallexample
(message "@exclamdown{}Este mensaje aparece en el @'area echo!")
@end smallexample

Toda la cadena entre comillas dobles es un unico argumento y se
imprime @i{en su totalidad}. (N@'otese que en este ejemplo, el mensaje en
s@'{@dotless{i}} aparece en el @'area echo entre comillas
dobles; esto se debe a que ves el valor devuelto por la funci@'on
@code{message}. En la mayor@'{@dotless{i}}a de programas que escribiras,
el texto ser@'a impreso en
el @'area echo como un efecto secundario de @code{message}, sin las
comillas. Ver @ref{multiply-by-seven en detalle, ,
@code{multiply-by-seven} en detalle}, para un ejemplo de esto.)

Sin embargo, si hay un @samp{%s} en la cadena de caracteres citada, la
funci@'on @code{message} no imprime el @samp{%s} como tal, pero mira
el siguente argumento a continuaci@'on de la cadena. Se eval@'ua el segundo
argumento e
imprime el valor en la ubicaci@'on de la cadena donde est@'a el @samp{%s} .

@need 1250
Puede ver esto colocando el cursor despu@'es de la siguiente
expresi@'on y presionar @kbd{C-x C-e}:

@smallexample
(message "El nombre de este b@'uffer es: %s." (buffer-name))
@end smallexample

@noindent
En Info, @code{"El nombre de este b@'uffer es: *info*."} aparecer@'a
en el @'area echo. La funci@'on @code{buffer-name} devuelve el nombre
del b@'uffer como una cadena, que la funci@'on @code{message} inserta
en lugar de @code{%s}.

Para imprimir un valor como un entero, utiliza @samp{%d} de la misma forma
que @samp{%s}. Por ejemplo, para imprimir un mensaje en el
@'area echo que indique el valor de @code{fill-column}, eval@'ua lo
siguiente:

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

@noindent
En mi sistema, cuando eval@'uo esta lista, @code{"El valor de
fill-column es 72"} aparece en mi @'area echo@footnote{Actualmente,
puede usar @code{%s} para imprimir un n@'umero. Es no
espec@'{@dotless{i}}fico. @code{%d} imprime solo la parte de un
n@'umero a la izquierda del punto decimal, y no cualquier cosa que
no es un n@'umero.}

Si hay m@'as de un @samp{%s} en la cadena citada, el valor del primer
argumento despu@'es de la cadena citada se imprime en la posici@'on del
primer @samp{%s} y el valor del segundo argunmento se imprime en la
posici@'on del segundo @samp{%s}, y as@'{@dotless{i}} sucesivamente.

@need 1250
Por ejemplo, si se eval@'ua lo siguiente,

@smallexample
@group
(message "@exclamdown{}Hay %d %s en la oficina!"
         (- fill-column 14) "elefantes rosas")
@end group
@end smallexample

@noindent
un mensaje caracter@'{@dotless{i}}stico aparecer@'a en el @'area
echo. En mi sistema dice @code{"@exclamdown{}Hay 58 elefantes rosas en
la oficina!"}

Se evalua la expresi@'on @code{(- fill-column 14)} y el n@'umero
resultante se inserta en lugar del @samp{%d}; y la cadena entre
comillas dobles, @code{"elefantes rosas"}, se trata como un
solo argumento y se inserta en lugar del @samp{%s}. (Esto es decir,
una cadena entre comillas dobles se eval@'ua as@'{@dotless{i}} misma,
como un n@'umero.)

Finalmente, aqu@'{@dotless{i}} est@'a un ejemplo algo complejo que no
solo ilustra el c@'alculo de un n@'umero, tambi@'en muestra
como se puede usar una expresi@'on dentro de una expresi@'on para generar el
texto que
sustituira el @samp{%s}:

@smallexample
@group
(message "@'El vi@'o %d %s"
         (- fill-column 36)
         (concat (substring
                  "Los r@'apidos zorros marrones saltaron." 12 18)
                  " rojos trotando."))
@end group
@end smallexample

En este ejemplo, @code{message} tiene tres argumentos: la cadena,
@code{"@'El vi@'o %d %s"}, la expresi@'on, @code{(- fill-column 32)}, y la
expresi@'on a partir de
la funci@'on @code{concat}. El valor resultante desde la evaluaci@'on
de @code{(- fill-column 32)} se inserta en lugar del @samp{%d}; y
el valor devuelto por la expresi@'on que inicia con @code{concat} se
inserta en lugar del @samp{%s}.

Cuando @code{fill-column} es 70 y se eval@'ua la expresi@'on, aparecera el
mensaje @code{"@'El vi@'o 41 zorros rojos trotando."} en tu
@'area echo.

@node set y setq
@section Configurando el valor de una variable
@cindex Variable, asignando valor
@cindex Asignando valor de variable

@cindex @samp{bind} se defini@'o
Hay varias formas de asignar un valor a una variable. Una de
ellas es usar la funci@'on @code{set} o la funci@'on
@code{setq}. Otra forma es usar @code{let} (@pxref{let}). (La jerga
para este proceso es @dfn{bind} (ligar) una variable a un valor.)

Las siguientes secciones no solo describen c@'omo operan @code{set} y
@code{setq}, tambi@'en ilustran como se pasan los argumentos.

@menu
* Usando set::               Configurando valores.
* Usando setq::              Configurando un valor citado.
* Contando::                 Usando @code{setq} para contar.
@end menu

@node Usando set
@subsection Usando @code{set}
@findex set

Para establecer el valor del s@'{@dotless{i}}mbolo @code{flores} a la
lista @code{'(rosa violeta margarita bot@'ondeoro)}, eval@'ua la
siguiente expresi@'on colocando el cursor despu@'es de la
expresi@'on y presiona @kbd{C-x C-e}.

@smallexample
(set 'flores '(rosa violeta margarita bot@'ondeoro))
@end smallexample

@noindent
La lista @code{(rosa violeta margarita bot@'ondeoro)} aparecer@'a en el
@'area echo. Esto es @emph{devuelto} por la funci@'on
@code{set}. Como efecto secundario, el s@'{@dotless{i}}mbolo
@code{flores} est@'a ligado a la lista; es decir, el
s@'{@dotless{i}}mbolo @code{flores}, puede ser visto como una
variable, que entrega la lista como su valor. (Este proceso,
ilustra un efecto lateral al int@'erprete Lisp: asignando el valor,
que puede ser el efecto primario en el que los humanos
estamos interesados. Esto se debe a que cada funci@'on Lisp debe devolver
un valor si no se obtiene un error, pero solo tendr@'a un efecto
secundario si est@'a dise@~nado para tener uno.)

Despu@'es de evaluar la expresi@'on @code{set}, se puede evaluar el
s@'{@dotless{i}}mbolo @code{flores} y devolver@'a el valor
asignado. Aqu@'{@dotless{i}} est@'a el s@'{@dotless{i}}mbolo. Coloca
el cursor al final de este y presiona @kbd{C-x C-e}.

@smallexample
flores
@end smallexample

@noindent
Cuando se eval@'ua @code{flores}, la lista @code{(rosa violeta margarita
bot@'ondeoro)} aparece en el @'area echo.

Por cierto, si se eval@'ua @code{'flores}, la variable con una
comilla en frente, lo que ver@'a en el @'area echo es el
s@'{@dotless{i}}mbolo en s@'{@dotless{i}} mismo: @code{flores}.
Aqu@'{@dotless{i}} est@'a el s@'{@dotless{i}}mbolo citado,
para que pueda probar esto:

@smallexample
'flores
@end smallexample

N@'otese tambi@'en, que cuando se usa @code{set}, se necesitan citar
ambos argumentos de @code{set}, a menos que los quiera evaluar. Puesto
que nosotros no queremos evaluar, ni la variable
@code{flores}, ni la lista @code{(rosa violeta margarita
bot@'ondeoro)}, ambos se citan. (Cuando se usa @code{set} sin citar su
primer
argumento, el primer argumento se eval@'ua antes de realizar cualquier otra
cosa. Si hizo esto y @code{flores} no ten@'{@dotless{i}}a
ya un valor, se tendr@'{@dotless{i}}a un mensaje de error con el
@samp{Valor de s@'{@dotless{i}}mbolo como variable
vac@'{@dotless{i}}o}; por otro lado, si @code{flores} regreso un
valor despu@'es de ser evaluado, @code{set}
intentar@'{@dotless{i}}a establecer el valor que fue
devuelto. Hay situaciones donde esto el justo lo que la funci@'on
a de hacer, pero tales situaciones son poco frecuentes.)

@node Usando setq
@subsection Usando @code{setq}
@findex setq

Como una cuesti@'on pr@'actica, casi siempre se cita el primer argumento de
@code{set}. La combinaci@'on de @code{set} y un primer argumento citado
es tan com@'un que tiene nombre propio: la forma especial
@code{setq}. Esta forma especial es igual a @code{set} excepto que
el primer argumento se cita autom@'aticamente, por lo que no necesita
escribir la marca de cita. Tambi@'en, como
una conveniencia a@~nadida, @code{setq} permite asignar varias
variables diferentes a diferentes valores, todo en una expresi@'on.

Para establecer el valor de la variable @code{carn@'{@dotless{i}}voros} a
la lista @code{'(leon tigre leopardo)} usando @code{setq}, se utiliza la
siguiente
expresi@'on:

@smallexample
(setq carnivoros '(leon tigre leopardo))
@end smallexample

@noindent
Esto es exactamente lo mismo que usar @code{set} excepto que el primer
argumento se cita autom@'aticamente por @code{setq}. (La @samp{q} en
@code{setq} significa @code{quote}.)

@need 1250
Con @code{set}, la expresi@'on que se ver@'{@dotless{i}}a es:

@smallexample
(set 'carnivoros '(leon tigre leopardo))
@end smallexample

Adem@'as, @code{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@'{@dotless{i}} sucesivamente. Por ejemplo, se
podr@'{@dotless{i}}a usar lo siguiente para asignar una lista de
@'arboles al s@'{@dotless{i}}mbolo @code{arboles} y una lista
de herb@'{@dotless{i}}voros al s@'{@dotless{i}}mbolo @code{herbivoros}:

@smallexample
@group
(setq arboles '(pino abeto roble arce)
      herbivoros '(gacela antilope cebra))
@end group
@end smallexample

@noindent
(La expresi@'on podr@'{@dotless{i}}a tambi@'en haber estado en una
sola l@'{@dotless{i}}nea, pero podr@'{@dotless{i}}a no caber en
una p@'agina; y a los humanos les resulta m@'as f@'acil leer listas
con un formato agradable.)

Aunque he estado usando el t@'ermino `asignar', hay otra forma de
pensar respecto a el funcionamiento de @code{set} y @code{setq}; y consiste
en
decir que @code{set} y @code{setq} crean un s@'{@dotless{i}}mbolo
que @emph{apunta} a la lista. Esta ultima forma de pensar es muy
com@'un y en los cap@'{@dotless{i}}tulos siguientes deberiamos encontrar al
menos un s@'{@dotless{i}}mbolo con un `puntero' como parte de su nombre. El
nombre es elegido porque el s@'{@dotless{i}}mbolo tiene un valor,
espec@'{@dotless{i}}ficamente una lista, unida a el; o, expresado de otra
manera, el s@'{@dotless{i}}mbolo se ajusta para ``apuntar'' a la lista.

@node Contando
@subsection Contando
@cindex Contando

He aqu@'{@dotless{i}} un ejemplo que muestra c@'omo usar @code{setq}
en un contador. Se podr@'{@dotless{i}}a usar esto para contar cuantas
veces una parte de un programa se
repite. En primer lugar asigna una variable a cero; a continuaci@'on suma
uno al
n@'umero cada vez que el programa se
repita. Para ello, se necesita una variable que sirve como un
contador, y dos expresiones: una expresi@'on @code{setq} inicial que asigna
la
variable contador a cero; y una segunda expresi@'on @code{setq} que
incrementa el contador cada vez se evalua.

@smallexample
@group
(setq contador 0)                ; @r{Llamemos a esto el inicializador.}

(setq contador (+ contador 1))   ; @r{Este es el incremento.}

contador                         ; @r{Esste es el contador.}
@end group
@end smallexample

@noindent
(El texto que sigue al @samp{;} son los comentarios. Ver @xref{Cambiar un
defun, , Cambiar una definici@'on de funci@'on}.)

Si eval@'uas la primera de estas expresiones, el inicializador,
@code{(setq contador 0)}, y luego eval@'uas la tercera expresi@'on,
@code{contador}, el n@'umero @code{0} aparecer@'a en el @'area echo. Si
a continuaci@'on se eval@'ua la segunda expresi@'on, el incremento,
@code{(setq contador (+ contador 1))}, el contador tendr@'a el valor
1. As@'{@dotless{i}} que si eval@'uas de nuevo @code{contador}, el n@'umero
@code{1} aparecer@'a en el @'area echo. Cada vez que se eval@'ua la
segunda expresi@'on, el valor del contador ser@'a incrementado.

Al eval@'uar el incremento, @code{(setq contador (+ contador
1))}, el int@'erprete Lisp primero eval@'ua la lista interna; esta es
la adici@'on. Con el fin de evaluar esta lista, se debe evaluar la
variable @code{contador} y el n@'umero @code{1}. Cuando eval@'ua la
variable @code{contador}, se recibe su valor actual. Se pasa este valor y
el n@'umero @code{1} a @code{+} que los a@~nade. La suma
es devuelta como el valor de la list interior y pasa a @code{setq} que
asigna la variable @code{contador} a este nuevo valor. Por lo tanto, el
valor de la variable @code{contador}, cambia.

@node Resumen
@section Resumen

Aprender Lisp es como subir una colina en la que la primera parte
es la m@'as empinada. Ahora has subido la parte m@'as
dif@'{@dotless{i}}cil; lo que queda se vuelve m@'as f@'acil a medida que
avanzas hacia adelante.

@need 1000
En resumen,

@itemize @bullet

@item
Los programas Lisp se componen de expresiones, que son listas o @'atomos
individuales.

@item
La listas se componen de cero o m@'as @'atomos o listas internas,
separadas por espacios en blanco y rodeadas por par@'entesis. Una lista
puede estar vac@'{@dotless{i}}a.

@item
Los @'atomos son s@'{@dotless{i}}mbolos multi-car@'acter, como
@code{forward-paragraph}, s@'{@dotless{i}}mbolos de un solo caracterer
como @code{+}, cadenas de caracteres entre comillas dobles,
o n@'umeros.

@item
Un n@'umero se eval@'ua a s@'{@dotless{i}} mismo.

@item
Una cadena entre comillas dobles tambi@'en se eval@'ua a
s@'{@dotless{i}} mismo.

@item
Cuando se eval@'ua un s@'{@dotless{i}}mbolo a s@'{@dotless{i}} mismo,
su valor se devuelve.

@item
Cuando se eval@'ua una lista, el int@'erprete Lisp mira el primer
s@'{@dotless{i}}mbolo en la lista y luego la definici@'on de funci@'on
asociada a este s@'{@dotless{i}}mbolo. A continuaci@'on, las
instrucciones en la definici@'on de funci@'on se llevan a cabo.

@item
Una marca de cita,
@ifinfo
'
@end ifinfo
@ifnotinfo
@code{'}
@end ifnotinfo
, le indica al int@'erprete Lisp que devuelva la
siguiente expresi@'on como esta escrita, y no la eval@'ua como lo haria si
la cita
no estuviera alli. 

@item
Los argumentos son la informaci@'on que se pasa a una funci@'on. Los
argumentos a una funci@'on son computados evaluando el resto de los
elementos de la lista de la que la funci@'on es el primer elemento.

@item
Una funci@'on siempre devuelve un valor cuando se eval@'ua (a menos
que obtenga un error); adem@'as, tambi@'en se puede llevar a cabo algun tipo
de acci@'on
llamado ``efecto secundario''. En muchos casos, el prop@'osito principal
de una funci@'on es crear un efecto secundario.
@end itemize

@node Ejercicios de mensajes de error
@section Ejercicios

Unos ejercicios sencillos:

@itemize @bullet
@item
Generar un mensaje de error evaluando un s@'{@dotless{i}}mbolo
apropiado que no est@'a entre par@'entesis.

@item
Generar un mensaje de error evaluando un s@'{@dotless{i}}mbolo
apropiado que est@'a entre par@'entesis.

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

@item
Escribe una expresi@'on que imprima un mensaje en el @'area eco cuando es
evaluada.
@end itemize

@node Practicando evaluaci@'on
@chapter Practicando evaluaci@'on
@cindex Practicando evaluaci@'on
@cindex Evaluaci@'on pr@'actica

Antes de aprender como escribir una definici@'on de funci@'on en Emacs
Lisp, es @'util gastar un poco de tiempo evaluando varias expresiones
que ya han sido escritas. Estas expresiones ser@'an listas con
funciones como su primer (y con frecuencia @'unico) elemento. Dado que
algunas de las funciones asociadas con b@'uffers son a la vez simples e
interesantes, vamos a iniciar con estas. En esta secci@'on,
vamos a evaluar algunas de este tipo. En otra secci@'on, estudiaremos el
c@'odigo de varias otras funciones relacionadas con b@'uffers, para
ver la forma c@'omo fueron escritas.

@menu
* C@'omo evaluar::           Escribiendo comandos de edici@'on o con 
                               @kbd{C-x C-e}.
* Nombres de b@'uffer::      Buffers y ficheros son diferentes.
* Obteniendo b@'uffers::     Obteniendo un buffer por s@'{@dotless{i}} 
                               mismo, no solamente su nombre.
* Cambiando b@'uffers::      C@'omo cambiar a otro buffer.
* Tama@~no de b@'uffer y localizaciones::  D@'onde el punto est@'a 
                                             localizado y el tama@~no del 
                                             buffer.
* Ejercicio de evaluaci@'on::  Ejercicio de evaluaci@'on
@end menu

@ifnottex
@node C@'omo evaluar
@unnumberedsec C@'omo evaluar
@end ifnottex

@i{Siempre que proporciona un comando de edici@'on} a Emacs Lisp,
como el comando para mover el cursor o para desplazarse por la pantalla,
@i{se est@'a evaluando una expresi@'on,} de la cual el primer elemento es
una funci@'on. @i{As@'{@dotless{i}} es c@'omo funciona Emacs}.

@cindex @samp{funci@'on interactiva} definida
@cindex @samp{comando} definido
Al presionar las teclas, se causa que el int@'erprete Lisp eval@'ue
una expresi@'on que devuelve resultados. Incluso escribir texto
plano implica eval@'uar una funci@'on Emacs Lisp, en este caso,
se utiliza @code{self-insert-command}, que simplemente inserta el
caracter escrito. Las funciones que se eval@'uan presionando
atajos de teclado se llaman funciones @dfn{interactive}, o
@dfn{comandos}; como crear una funci@'on interactive ser@'a ilustrado
en el cap@'{@dotless{i}}tulo sobre c@'omo escribir definiciones de
funciones. Ver @ref{Interactive, , Creando una Funci@'on
Interactive}.

Adem@'as de presionar comandos de teclado, hemos visto una segunda
manera de evaluar una expresi@'on: colocar el cursor despu@'es de
una lista y presionar @kbd{C-x C-e}. Esto es lo que se har@'a
en el resto de esta secci@'on. Hay otras maneras de evaluar una
expresi@'on; que ser@'an descritas cuando llegemos a ellas.

Ademas de utilizarse para practicar la evaluaci@'on, las funciones mostradas
en
las siguientes secciones son importantes por derecho
propio. Un estudio de estas funciones deja claro la distinci@'on
entre b@'uffers y ficheros, c@'omo cambiar a un b@'uffer, y como
determinar una ubicaci@'on dentro de ella.

@node Nombres de b@'uffer
@section Nombres de b@'uffer
@findex buffer-name
@findex buffer-file-name

Las dos funciones, @code{buffer-name} y @code{buffer-file-name},
muestran la diferencia entre un fichero y un b@'uffer. Cuando
se eval@'ua la siguiente expresi@'on, @code{(buffer-name)}, el nombre
del buffer aparece en el area eco. Al evaluar @code{(buffer-file-name)}, el
nombre
del fichero al que se relaciona el b@'uffer aparece en el @'area
echo. Normalmente, el nombre devuelto por @code{(buffer-name)} es el
mismo que el nombre del fichero al que hace referencia, y el nombre
devuelto por @code{(buffer-file-name)} es la ruta completa del fichero.

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

@need 1250
Si est@'a leyendo esto en Info dentro de GNU Emacs, puede evaluar
cada una de las siguientes expresiones colocando el cursor
despu@'es de estas y pulsando @kbd{C-x C-e}.

@example
@group
(buffer-name)

(buffer-file-name)
@end group
@end example

@noindent
Cuando hago esto en Info, el valor devuelto para la evaluaci@'on de
@code{(buffer-name)} es @file{"*info*"}, y el valor devuelto por
evaluar @code{(buffer-file-name)} es @file{nil}.

Por otro lado, mientras escribo este documento, el valor
devuelto por la evaluaci@'on de @code{(buffer-name)} es
@file{"introduction.texinfo"}, y el valor devuelto por la evaluaci@'on de
@code{(buffer-file-name)} es @file{"/gnu/work/intro/introduction.texinfo"}.

@cindex @code{nil}, historia de palabra
El primero es el nombre del b@'uffer y el segundo es el nombre del
fichero. En Info, el nombre del b@'uffer es @file{"*info*"}. Info no
apunta a ning@'un fichero, por lo que el resultado de evaluar
@code{(buffer-file-name)}] es @file{nil}. El s@'{@dotless{i}}mbolo
@code{nil} proviene del Latin, significa `nada'; en este caso,
significa que el b@'uffer no est@'a asociado con ningun
fichero. (En Lisp, @code{nil} tambi@'en se usa con el significado de
`falso' y es sin@'omino para lista vac@'{@dotless{i}}a, @code{()}.)

Cuando estoy escribiendo, el nombre de mi b@'uffer es
@file{"introduction.texinfo"}. El nombre del fichero al que
se apunta es @file{"/gnu/work/intro/introduction.texinfo"}.

(En las expresiones, los par@'entesis hacen que el int@'erprete Lisp
trate a @w{@code{buffer-name}} y @w{@code{buffer-file-name}} como
funciones; sin los par@'entesis, el int@'erprete
intentar@'{@dotless{i}}a evaluar los s@'{@dotless{i}}mbolos como
variables. Ver @ref{Variables}.)

A pesar de la distinci@'on entre ficheros y b@'uffers, con frecuencia
encontrara que hay personas que se refieren a un fichero cuando quieren
un b@'uffer y vice-versa. En realidad, la mayor@'{@dotless{i}}a de la
gente dice, ``Estoy editando un fichero,'' en lugar de decir,
``Estoy editando un b@'uffer 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@'on en mente, ya que el ordenador no es
tan inteligente como una persona.

@cindex Buffer, historia de palabra
Por cierto, la palabra `b@'uffer', viene del significado de la
palabra como un coj@'in que amortigua la fuerza de una colisi@'on. En los
primeros ordenadores, un b@'uffer amortiguaba la interacci@'on 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@'uffer hizo posible
que
ambos trabajaran juntos de manera efectiva. Con el tiempo, el b@'uffer
pasó de ser un intermediario, a un lugar de almacenamiento temporal, donde
se
realiza el trabajo. Esta transformaci@'on se parace bastante a la de
un peque@~no puerto que se convierte en una gran ciudad:
una vez fu@'e 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@'uffers est@'an asociados con ficheros. Por ejemplo, el
b@'uffer @file{*scratch*} no visita ningun fichero. Del mismo modo, un
b@'uffer
@file{*Help*} no est@'a asociado a ningun fichero.

Anta@~no, cuando se carecia de un fichero @file{~/.emacs}
y se iniciava una sesi@'on Emacs escribiendo unicamente el comando
@code{emacs},
sin nombrar ningun fichero, Emacs iniciaba con el b@'uffer
@file{*scratch*} visible. Hoy en d@'{@dotless{i}}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@'uffer @file{*scratch*}.

Si cambia al b@'uffer @file{*scratch*}, escriba
@code{(buffer-name)}, coloque el cursor al final de la expresi@'on, y
presione
@kbd{C-x C-e} para evaluar la expresi@'on. El nombre
@code{*scratch*} ser@'a devuelto y aparecer@'a en el @'area
echo. @code{*scratch*} es el nombre del b@'uffer. Al escribir y eval@'uar
@code{(buffer-file-name)} en el b@'uffer @file{*scratch*},
@code{nil} aparecer@'a en el @'area echo, igual que cuando
eval@'ua @code{(buffer-file-name)} en Info.

Por cierto, si se encuentra en el b@'uffer @file{*scratch*} y
quiere que el valor devuelto por una expresi@'on aparesca en el
b@'uffer en s@'{@dotless{i}} y no en el @'area echo, presione @kbd{C-u C-x
C-e} en lugar de @kbd{C-x C-e}. Esto causa que el valor devuelto
aparezca despu@'es de la expresi@'on. El b@'uffer se ver@'a
as@'{@dotless{i}}:

@smallexample
(buffer-name)"*scratch*"
@end smallexample

@noindent
No se puede hacer esto en Info ya que Info es de solo lectura y no
se permitir@'a cambiar el contenido del b@'uffer. Pero puedes
hacer esto en cualquier b@'uffer que se puede editar; y cuando  se escribe
c@'odigo o documentaci@'on (como este libro), esta funcionalidad
es muy @'util.

@node Obteniendo b@'uffers
@section Obteniendo b@'uffers
@findex current-buffer
@findex other-buffer
@cindex Teniendo un b@'uffer

La funci@'on @code{buffer-name} devuelve el @emph{nombre} del b@'uffer;
para obtener el b@'uffer @emph{en s@'{@dotless{i}}}, una funci@'on
diferente es necesaria: la funci@'on @code{current-buffer}. Si usa
esta funci@'on en el c@'odigo, lo que se obtiene es el b@'uffer en
s@'{@dotless{i}}.

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 @samp{J}, @samp{o},
@samp{r}, @samp{g}, y @samp{e} escritas, podr@'{@dotless{i}}as divertirte,
pero no estar@'{@dotless{i}}as satisfecho. No quieres
hablar con el nombre, sino con la persona a la que el
nombre se refiere. Un b@'uffer es similar: el nombre del b@'uffer
scratch es @file{*scratch*}, pero el nombre no es el b@'uffer. Para
obtener un b@'uffer en s@'{@dotless{i}}, se necesita usar una
funci@'on como @code{current-buffer}.

Sin embargo, hay una ligera complicaci@'on: si eval@'uas
@code{current-buffer} en una expresi@'on por s@'{@dotless{i}} sola,
como haremos aqu@'{@dotless{i}}, lo que ves es una representaci@'on
impresa del nombre del b@'uffer sin los contenidos del b@'uffer. Emacs
funciona de esta forma por dos razones: el b@'uffer puede contener
miles de l@'{@dotless{i}}neas---demasiado largo para ser
mostrado convenientemente; y, otro b@'uffer puede tener los mismos
contenidos pero un nombre diferente, y es importante distinguir entre ellos.

@need 800
Aqu@'{@dotless{i}} hay una expresi@'on conteniendo la funci@'on:

@smallexample
(current-buffer)
@end smallexample

@noindent
Si eval@'ua esta expresi@'on en Info de la manera habitual,
@file{#<buffer *info*>} aparecer@'a en el @'area echo. El formato
especial indica que el b@'uffer en s@'{@dotless{i}} est@'a
siendo devuelto, en lugar de solo su nombre.

Por cierto, si bien puedes escribir un n@'umero o s@'{@dotless{i}}mbolo
en un programa, no se puede hacer esto con la representaci@'on impresa
del b@'uffer: la @'unica manera de obtener un b@'uffer
en s@'{@dotless{i}} mismo es con una funci@'on tal como
@code{current-buffer}.

Un funci@'on relacionada es @code{other-buffer}. Esta devuelve el
@'ultimo buffer seleccionado distino al que te encuentras
actualmente, no una representaci@'on impresa de su
nombre. Si recientemente has ido y vuelto del b@'uffer @file{*scratch*},
@code{other-buffer} devolver@'a este b@'uffer.

@need 800
Se puede ver esto evaluando la expresi@'on:

@smallexample
(other-buffer)
@end smallexample

@noindent
Ver@'as que @file{#<buffer *scratch*>} aparece en el @'area echo, o el
nombre de cualquier otro b@'uffer cambiado anteriormente a partir del m@'as
reciente@footnote{En realidad, por defecto, si el b@'uffer desde
el que has cambiado es visible por t@'{@dotless{i}} en otra
ventana, @code{other-buffer} elegir@'a el b@'uffer m@'as reciente que
no puedes ver; esto es una sutileza que a menudo olvido.}

@node Cambiando b@'uffers
@section Cambiando b@'uffers
@findex switch-to-buffer
@findex set-buffer
@cindex Cambiando a un b@'uffer

La funci@'on @code{other-buffer} realmente proporciona un b@'uffer
cuando se utiliza como argumento de una funci@'on que requiera
uno. Podemos ver esto usando @code{other-buffer} y
@code{switch-to-buffer} para cambiar a un b@'uffer diferente.

Pero primero, una breve introducci@'on a la funci@'on
@code{switch-to-buffer}. Cuando cambia de ida y vuelta de
Info al b@'uffer @file{*scratch*} para evaluar @code{(buffer-name)},
normalmente se
presiona @kbd{C-x b} y se pasa @file{*scratch*}@footnote{O
mejor, para evitar escribir, probablemente solo necesite pulsar @kbd{RET}
si @file{*scratch*} es el buffer por defecto, de ser diferente, solo
escriba parte del nombre, por ejemplo @code{*sc}, luego
presione la tecla @kbd{TAB} para hacer que se expanda el nombre completo, y
finalmente pulsa @kbd{RET}} en el minibuffer cuando se le solicita el nombre
del b@'uffer al que se quiere cambiar. El atajo, @kbd{C-x
b}, hace que el int@'erprete Lisp eval@'ue la funci@'on interactiva
@code{switch-to-buffer}. Como hemos dicho anteriormente,
as@'{@dotless{i}} es como funciona Emacs: diferentes atajos de teclado
llaman o ejecutan diferentes funciones. Por ejemplo, @kbd{C-f} llama a
@code{forward-char}, @kbd{M-e} llama a @code{forward-sentence},
etc'etera.

Escribiendo @code{switch-to-buffer} en una expresi@'on, y d@'andole un
b@'uffer para cambiar, se puede cambiar de b@'uffers tal y como hace
@kbd{C-x b}.

@smallexample
(switch-to-buffer (other-buffer))
@end smallexample

@noindent
@c noindent
El s@'{@dotless{i}}mbolo @code{switch-to-buffer} es el primer elemento
de la lista, por lo que el int@'erprete Lisp lo tratar@'a como
una funci@'on y llevara a cavo las instrucciones adjuntas al mismo. Pero
antes de
hacer esto, el int@'erprete observara que @code{other-buffer} est@'a
dentro de par@'entesis y trabaja en este s@'{@dotless{i}}mbolo
primero. @code{other-buffer} es el primer (y en este caso, el
@'unico) elemento de esta lista, por lo que el int@'erprete
Lisp llama o ejecuta la funci@'on. Esto devuelve un buffer distinto al
actual. A continuaci@'on, el int@'erprete ejecuta @code{switch-to-buffer},
pasando, como argumento, el b@'uffer devuelto, que es al que Emacs
cambia. Si est@'as leyendo esto en Info, prueba esto ahora. Eval@'ua
la expresi@'on. (Para volver, presiona @kbd{C-x b
@key{RET}}.)@footnote{Recuerda, esta expresi@'on te desplaza al
b@'uffer m@'as reciente que no puedas ver. Si
realmente quieres ir al ultimo b@'uffers seleccionado, incluso si
es visible, es necesario evaluar la siguiente expresi@'on m@'as
compleja:
@smallexample
(switch-to-buffer (other-buffer (current-buffer) t))
@end smallexample
En este caso, el primer argumento de @code{other-buffer} le dice a que
b@'uffer saltar ---el actual--- y el segundo argumento le indica a
@code{other-buffer} que esta BIEN cambiar a un b@'uffer visible. La utilidad
de @code{switch-to-buffer} es llevarte a una ventana invisible ya que
probablemente
usar@'{@dotless{i}}as @kbd{C-x o} (@code{other-window}) para ir a otro
b@'uffer visible}.

En los ejemplos de las secciones siguentes, veras con m@'as frecuencia  la
funci@'on @code{set-buffer} que @code{switch-to-buffer}. Esto es porque a
diferencia
de los programas de ordenador: los humanos tienen ojos y
esperan ver el b@'uffer en el que est@'an 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@'uffer, el b@'uffer no
necesita ser visible en la pantalla.

@code{switch-to-buffer} est@'a dise@~nado para los seres humanos y hace dos
cosas diferentes: cambia el b@'uffer a el que Emacs dirige la atenci@'on;
y cambia el b@'uffer mostrada en la ventana al
nuevo b@'uffer. @code{set-buffer}, por otro lado, solo hace una cosa:
cambia la atenci@'on del programa del ordenador a un b@'uffer diferente. El
b@'uffer en la pantalla permanece sin cambios (por supuesto, normalmente
no ocurre nada hasta que el comando termina de ejecutarse).

@cindex @samp{llamada} definida
Tambi@'en, acabamos introduciendo otro t@'ermino tecnico, la
palabra @dfn{llamada}. Cuando eval@'uas una lista en la que el
primer s@'{@dotless{i}}mbolo es una funci@'on, est@'as llamando
a esta funci@'on. El uso del t@'ermino viene de la noci@'on de la
funci@'on 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.

@node Tama@~no de b@'uffer y localizaciones
@section Tama@~no de b@'uffer y la ubicaci@'on del punto
@cindex Tama@~no del b@'uffer
@cindex Tama@~no del B@'uffer
@cindex Localizaci@'on del Punto
@cindex Localizaci@'on del punto

Por último, vamos a ver varias funciones bastante simples,
@code{buffer-size}, @code{point}, @code{point-min}, y
@code{point-max}. Estas entregan informaci@'on sobre el tama@~no de un
b@'uffer y la ubicaci@'on del punto dentro de este.

La funci@'on @code{buffer-size} te dice el tama@~no del b@'uffer
actual; es decir, la funci@'on devuelve un conteo del n@'umero de caracteres
en
el buffer.

@smallexample
(buffer-size)
@end smallexample

@noindent
Puedes evaluar esto de la forma habitual, coloca el cursor
despu@'es de la expresi@'on y presiona @kbd{C-x C-e}.

@cindex definici@'on de @samp{punto}
En Emacs, la posici@'on actual del cursor es llamada @dfn{punto}. La
expresi@'on @code{(point)} devuelve un n@'umero que informa donde est@'a
situado el cursor como un conteo del n@'umero de caracteres desde el
principio del b@'uffer hasta el punto.

@need 1250
Puedes ver el conteo de caracteres del punto para este b@'uffer
evaluando la siguiente expresi@'on de la forma habitual:

@smallexample
(point)
@end smallexample

@noindent
Mientras escribo esto, el valor de @code{point} es 65724. La funci@'on
@code{point} se utiliza con frecuencia en algunos de los ejemplos
mas adelante en este libro.

@need 1250
El valor del punto depende, por supuesto, de su posici@'on dentro del
b@'uffer. Si se eval@'ua el punto en este lugar, el n@'umero ser@'a
mayor:

@smallexample
(point)
@end smallexample

@noindent
Para m@'{@dotless{i}}, el valor del punto en esta posici@'on es 66043,
lo que significa que hay 319 caracteres (incluyendo espacios) entre
las dos expresiones. (Sin duda, se ver@'an diferentes n@'umeros, puesto
que se ha editado esto desde que se evalu@'o (point).)

@cindex @samp{narrowing} definido
La funci@'on @code{point-min} es similar a @code{point}, pero
devuelve el valor m@'{@dotless{i}}nimo permisible del punto en el
b@'uffer actual. Este es el n@'umero 1 a menos que @dfn{narrowing}
est@'e en efecto. (Narrowing, @emph{Encogiendo} es un mecanismo mediante el
cual
puedes restringirte a ti mismo, o un programa, a operar
solo en un parte de un b@'uffer. @ref{Encogiendo y extendiendo}.)
Del mismo modo, la funci@'on @code{point-max} devuelve el valor del
valor m@'aximo permisible del punto en el b@'uffer actual.

@node Ejercicio de evaluaci@'on
@section Ejercicio

Busca un fichero en el que trabajar y avanza hasta la
mitad. Encuentra el nombre de b@'uffer, el nombre del fichero,
su tama@~no, y la posici@'on en el fichero.

@node Escribiendo funciones
@chapter C@'omo escribir definiciones de funciones
@cindex Escribiendo la Definici@'on
@cindex Escribiendo la Definici@'on de Funci@'on
@cindex Escribiendo una definici@'on funci@'on

Cuando el int@'erprete eval@'ua una lista, mira si el primer
s@'{@dotless{i}}mbolo en la lista tiene una definici@'on adjunta; o, dicho
de otro
modo, si el s@'{@dotless{i}}mbolo apunta a una definici@'on de
funci@'on. Si lo hace, el ordenador lleva a cabo las instrucciones que
aparecen en la
definici@'on. Un s@'{@dotless{i}}mbolo que tiene una definici@'on de
funci@'on se llamada, simplemente, una funci@'on (aunque hablando con
propiedad, la definici@'on es la funci@'on y el s@'{@dotless{i}}mbolo
se refiere a ella.)

@menu
* Funciones primitivas::     Funciones primitivas
* defun::                    La forma especial @code{defun}.
* Instalar::                 Instalar una definici@'on de funci@'on.
* Interactive::              Creando una funci@'on interactive.
* Opciones de interactive.::  Diferentes opciones para @code{interactive}.
* Instalaci@'on Permanente::  Instalando c@'odigo permanentemente.
* let::                      Creando e inicializando variables locales.
* if::                       @questiondown{}Y qu@'e 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
@end menu

@ifnottex
@node Funciones primitivas
@unnumberedsec Una v@'{@dotless{i}}a acerca de funciones primitivas
@end ifnottex
@cindex Funciones primitivas
@cindex Funciones, primitiva

@cindex Primitivas en lenguaje C
@cindex Primitivas escritas en C
Todas las funciones se definen en t@'erminos de otras
funciones, a excepcion de algunas @dfn{primitivas} que estan
escritas en el lenguaje de programaci@'on C. Cuando escribas
definiciones de funciones, deben escribirse en Emacs Lisp y utilizar otras
funciones como bloques de construcci@'on. Algunas de las funciones
a utilizar estaran a su vez escritas en Emacs Lisp
(quiz@'as por t@'{@dotless{i}}) y algunas ser@'an primitivas escritas
en C. Las funciones primitivas se usan exactamente igual que las escritas en
Emacs Lisp y se
comportan de igual forma. Est@'an escritas en C para que podamos ejecutar
f@'acilmente
GNU Emacs en cualquier ordenador
que tenga la potencia suficiente y pueda ejecutar C.

Perm@'{@dotless{i}}teme volver a enfatizar esto: cuando se escribe c@'odigo
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@'e la distinci@'on solo porque es interesante
conocerla. De hecho, a menos de que investigues, no sabras si una
funci@'on previamente escrita esta en Emacs Lisp o en C.

@node defun
@section La forma especial @code{defun}
@findex defun
@cindex Forma Especial de @code{defun}

@cindex @samp{definici@'on funci@'on} definida
En Lisp, un s@'{@dotless{i}}mbolo como @code{mark-whole-buffer}
tiene c@'odigo unido a el que le dice al ordenador que hacer cuando se
invoca la
funci@'on. Este c@'odigo se denomina la @dfn{definici@'on de
funci@'on} y se crea mediante la evaluaci@'on de una expresi@'on Lisp que
comienza con
el s@'{@dotless{i}}mbolo @code{defun} (que es una abreviatura para
@emph{define function} (definir funci@'on)). Porque @code{defun} no eval@'ua
sus
argumentos en la forma habitual, eso se llama @dfn{forma especial}.

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

Una definici@'on de funci@'on tiene un m@'aximo de cinco partes despues de
la palabra @code{defun}:

@enumerate
@item
El nombre del s@'{@dotless{i}}mbolo al que la definici@'on de
funci@'on debe vincularse.

@item
Una lista de los argumentos que ser@'an pasados a la funci@'on. Si no
hay argumentos que pasar, tendremos una lista vac@'{@dotless{i}}a,
@code{()}.

@item
Documentaci@'on describiendo la funci@'on. (T@'ecnicamente opcional,
pero fuertemente recomendada.)

@item
Opcionalmente, una expresi@'on para hacer que la funci@'on interactive
pueda usarse presionando @kbd{M-x} seguido del
nombre de la funci@'on; o pulsando una tecla o atajo de teclado.

@cindex @samp{cuerpo} definido
@item
El c@'odigo que indica a el ordenador qu@'e hacer: el @dfn{cuerpo} de
la definici@'on de funci@'on.
@end enumerate

Es @'util pensar en las cinco partes de una definici@'on de funci@'on
siendo organizadas como una plantilla, con slots para cada parte:

@smallexample
@group
(defun @var{nombre-de-funci@'on} (@var{argumentos}@dots{})
  "@var{documentacion-opcional}@dots{}"
  (interactive @var{argument-passing-info})     ; @r{opcional}
  @var{cuerpo}@dots{})
@end group
@end smallexample

A modo de ejemplo, aqu@'{@dotless{i}} est@'a el c@'odigo de una
funci@'on que multiplica su argumento por 7. (Este ejemplo no es
interactivo. Ver @ref{Interactive, , Creando una Funci@'on Interactive},
para esta informaci@'on.)

@smallexample
@group
(defun multiplicar-por-siete (numero)
  "Multiplica NUMERO por siete."
  (* 7 numero))
@end group
@end smallexample

Esta definici@'on comienza con un par@'entesis y el
s@'{@dotless{i}}mbolo @code{defun} seguido por el nombre de la
funci@'on.

@cindex @samp{lista de argumentos} definida
El nombre de la funci@'on es seguido por una lista que contiene
los argumentos que ser@'an pasados a la funci@'on. Esta lista se
llama @dfn{lista de argumentos}. En este ejemplo, la lista
solo tiene un elemento, el s@'{@dotless{i}}mbolo @code{numero}. Cuando
se utiliza la funci@'on, el s@'{@dotless{i}}mbolo ser@'a asociado al
valor que se utiliza como argumento de la funci@'on

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

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

@ignore
Note also that we discuss the word `number' in two different ways: as a
symbol that appears in the code, and as the name of something that will
be replaced by a something else during the evaluation of the function.
In the first case, @code{number} is a symbol, not a number; it happens
that within the function, it is a variable who value is the number in
question, but our primary interest in it is as a symbol.  On the other
hand, when we are talking about the function, our interest is that we
will substitute a number for the word @var{number}.  To keep this
distinction clear, we use different typography for the two
circumstances.  When we talk about this function, or about how it works,
we refer to this number by writing @var{number}.  In the function
itself, we refer to it by writing @code{number}.
@end ignore

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

@findex * @r{(multiplicaci@'on)}
La tercera l@'{@dotless{i}}nea del ejemplo consiste en el cuerpo de la
definici@'on de funci@'on. (La mayor@'{@dotless{i}}a de las
definiciones de funci@'on, claro esta, son m@'as extensas que esta.) En
esta funci@'on, el cuerpo es la lista, @code{(* 7 numero)}, que indica
multiplicar el valor de @var{numero} por 7. (En Emacs Lisp, @code{*}
es la funci@'on para la multiplicaci@'on, al igual que @code{+} es la
funci@'on de la adici@'on.

Cuando se utiliza la funci@'on @code{multiplicar-por-siente}, el argumento
@code{numero} se eval@'ua al numero que desees
usar. He aqu@'{@dotless{i}} un ejemplo que muestra como
utilizar @code{multiplicar-por-siente}; pero @exclamdown{}no intentes
evaluar esto primero!.

@smallexample
(multiplicar-por-siente 3)
@end smallexample

@noindent
El s@'{@dotless{i}}mbolo @code{numero}, especificado en la
definici@'on de funci@'on en la siguiente secci@'on, se da o
``une a'' el valor 3 en el actual uso de la funci@'on. Note que
aunque @code{numero} estaba dentro de par@'entesis en la
definici@'on de funci@'on, el argumento pasado a la funci@'on
@code{multiplicar-por-siente} no est@'a entre par@'entesis. Los
par@'entesis se escriben en la definici@'on de funci@'on
para que el ordenador pueda averiguar donde termina la lista de
argumentos e inicia el resto de la definici@'on de funci@'on.

Si eval@'uas este ejemplo, es probable que obtengas un mensaje de
error. (@exclamdown{}adelante, intentalo!) Esto se debe a que hemos
escrito la definici@'on de funci@'on pero a@'un no se a comunicado
al ordenador la definici@'on --- no hemos
instalado (o `cargado') la definici@'on de funci@'on en
Emacs. Instalar una funci@'on es el proceso comunicar al
int@'erprete Lisp la definici@'on de la funci@'on. La instalaci@'on se
describe en la siguiente secci@'on.

@node Instalar
@section Instalar una definici@'on de funci@'on
@cindex Instalar una definici@'on de funci@'on
@cindex Definici@'on de la instalaci@'on
@cindex Definici@'on de la Instalaci@'on de Funci@'on

Si est@'as leyendo esto dentro de Info en Emacs, puedes probar la
funci@'on @code{multiply-by-seven} evaluando en primer ]ugar la definici@'on
de funci@'on y luego evaluar @code{(multiplicar-por-siente 3)}. Hay una
copia de la definici@'on a continuaci@'on. Coloca el cursor despu@'es del
@'ultimo par@'entesis de la definici@'on de funci@'on y presiona
@kbd{C-x C-e}. Al hacer esto, @code{multiplicar-por-siente}
aparecer@'a en el @'area echo. (Lo que significa es que cuando una
definici@'on de funci@'on se evalua, el valor devuelto es el nombre
de la funci@'on definida.) Al mismo tiempo, esta acci@'on instala la
definici@'on de funci@'on.

@smallexample
@group
(defun multiplicar-por-siete (numero)
  "Multiplica NUMERO por siete."
  (* 7 numero))
@end group
@end smallexample

@noindent
Al evaluar este @code{defun}, estas instanlado @code{multiply-by-seven}
en Emacs. La funci@'on es ahora solo una parte de Emacs como
@code{forward-word} o cualquier otra funci@'on de edici@'on que
utilices. (@code{multiplicar-por-siente} seguira instalado hasta que salgas
de
Emacs. Para volver a cargar el c@'odigo autom@'aticamente cada vez que
Emacs inicie, ver @ref{Instalaci@'on Permanente, , Instalar C@'odigo
Permanentemente}.)

@menu
* Efecto de instalaci@'on::  Efecto de instalaci@'on
* Cambiar un defun::         C@'omo cambiar una definici@'on de funci@'on
@end menu

@ifnottex
@node Efecto de instalaci@'on
@unnumberedsubsec El efecto de instalaci@'on
@end ifnottex

Puedes ver el efecto de instalar @code{multiplicar-por-siente} evaluando
el siguiente ejemplo. Coloca el cursor despu@'es de la siguiente
expresi@'on y presiona @kbd{C-x C-e}. El n@'umero 21 aparacer@'a en el
@'area echo.

@smallexample
(multiplicar-por-siente 3)
@end smallexample

Si lo deseas, puedes leer la documentaci@'on de la funci@'on
presiona @kbd{C-h f} (@code{describe-function}) y luego escribe el
nombre de la funci@'on, @code{multiplicar-por-siente}. Al hacer esto,
una ventana @file{*Help*} aparecer@'a en tu pantalla diciendo:

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

Multiplica NUMERO por siete.
@end group
@end smallexample

@noindent
(Para volver a una sola ventana en la pantalla, presiona @kbd{C-x 1}.)

@node Cambiar un defun
@subsection Cambiar una definici@'on de funci@'on
@cindex Cambiando una definici@'on de funci@'on
@cindex Definici@'on de Funci@'on, como cambiar
@cindex Definici@'on, c@'omo cambiar

Si deseas modificar al c@'odigo de @code{multiplicar-por-siente},
simplemente
reescr@'{@dotless{i}}belo. Para instalar la nueva versi@'on en lugar
de la vieja, eval@'ua la nueva definici@'on de la funci@'on.
Esta, es la forma de modificar el c@'odigo en
Emacs. Es muy simple,

A modo de ejemplo, puedes cambiar la funci@'on @code{multiplicar-por-siente}
para sumar el n@'umero a s@'{@dotless{i}} mismo siete veces en lugar de
multiplicar el n@'umero por siete. Esto produce el mismo resultado,
pero por una ruta diferente. Al mismo tiempo, a@~nadiremos un
comentario al codigo; un comentario es texto que el int@'erprete Lisp
ignora,
pero un lector humano puede encontrar @'util o esclarecedor. El
comentario es que esto es la ``segunda versi@'on''.

@smallexample
@group
(defun multiplicar-por-siente (numero)       ; @r{Segunda versi@'on.}
  "Multiplica NUMERO por siete."
  (+ numero numero numero numero numero numero numero))
@end group
@end smallexample

@cindex Comentarios en C@'odigo Lisp
El comentario sigue a un punto y coma, @samp{;}. En Lisp culquier cosa
en una l@'{@dotless{i}}nea despues de un punto y coma es un
comentario. El fin de la l@'{@dotless{i}}nea es el fin del
comentario. Para extender un comentario por dos o m@'as
l@'{@dotless{i}}neas, inicia cada l@'{@dotless{i}}nea con un punto y
coma.

@xref{Beginning a .emacs File, , Empezando un Fichero
@file{.emacs}}, y @ref{Comments, , Comentarios, elisp, El Manual de
Referencia de GNU Emacs Lisp}, para m@'as informacion sobre los comentarios.

Se puede instalar esta versi@'on de la funci@'on
@code{multiply-by-seven} evaluando esta de la misma forma en que se
evalu@'o la primer funci@'on: coloca el cursor despu@'es del
@'ultimo par@'entesis y presiona @kbd{C-x C-e}.

En resumen, esta es la forma en que puedes escribir c@'odigo en Emacs Lisp:
escribes una funci@'on; la instalas; la pruebas; luego haces
correciones y mejoras e inst@'alalas de nuevo.

@node Interactive
@section Crear una funci@'on interactive
@cindex Funciones Interactivas
@findex interactive

Haces a una funci@'on interactiva colocando una lista que inicia con
la clase especial @code{interactive} inmediatamente despu@'es de la
documentaci@'on. Un usuario puede invocar una funci@'on interactiva
con @kbd{M-x} seguido del nombre de la funci@'on; o
con un atajo de teclado ligado a esta, por ejemplo,
pulsa @kbd{C-n} para @code{next-line} o @kbd{C-x h} para
@code{mark-whole-buffer}.

Curiosamente, cuando se llama a una funci@'on interactiva
interactivamente, el valor devuelto no se muestra autom@'aticamente
en el @'area echo. Esto se bede a que a menudo se llama a
una funci@'on interactiva para sus efectos secundarios, tales como
avanzar hacia adelante por palabra o l@'{@dotless{i}}nea, y no
para el valor devuelto. Si el valor devuelto fuera mostrado en el
@'area echo cada vez que presionas una tecla,
distraer@'{@dotless{i}}a mucho

@menu
* multiply-by-seven interactivo::  Un resumen
* multiply-by-seven en detalle::  La versi@'on interactive.
@end menu

@ifnottex
@node multiply-by-seven interactivo
@unnumberedsubsec Un @code{multiply-by-seven} interactivo, Un resumen
@end ifnottex

Tanto el uso de la forma especial @code{interactive} y una forma de
mostrar un valor en el @'area echo pueden ilustrarse creando una
versi@'on interactiva de @code{multiplicar-por-siente}.

@need 1250
Aqu@'{@dotless{i}} est@'a el c@'odigo:

@smallexample
@group
(defun multiplicar-por-siente (numero)       ; @r{Versi@'on Interactiva.}
  "Multiplica NUMERO por siete."
  (interactive "p")
  (message "El resultado es %d" (* 7 numero)))
@end group
@end smallexample

@noindent
Para instalar este c@'odigo colaca el cursor despu@'es del ultimo parentesis
y
presiona @kbd{C-x C-e}. El nombre de la funci@'on aparecer@'a en el
@'area echo. Despues, puedes utilizar este c@'odigo al presionar
@kbd{C-u} seguido de un n@'umero, lugo @kbd{M-x
multiplicar-por-siente} y finalmente @key{RET}. La frase @samp{El
resultado es @dots{}} seguida por el producto aparecer@'a en el @'area
echo

Hablando en terminos mas generales, puedes invocar una funci@'on como
@'esta de dos maneras:

@enumerate
@item
Al escribir un argumento prefijo que contiene el n@'umero a pasar, y
a continuaci@'on presionar @kbd{M-x} y escribir el nombre de la funci@'on,
como ocurre con
@kbd{C-u 3 M-x forward-sentence}; o,

@item
Al escribir cualquier tecla o atajo de teclado ligado a la funcion a tratar,
como ocurre con @kbd{C-u 3 M-e}.
@end enumerate

@noindent
Ambos ejemplos operan de forma identica moviendo el punto
hacia adelantes tres frases. (Si @code{multiply-by-seven} no
estuviese ligado a una tecla, no podr@'{@dotless{i}}a ser usado
como ejemplo de enlace a tecla.

(@xref{Atajos de teclado, , Algunos Atajos de Teclas}, para aprender
como vincular un comando a una tecla.)

Un argumento prefijo se pasa a una funci@'on interactiva
pulsando la tecla @key{META} seguida por un n@'umero, por ejemplo,
@kbd{M-3 M-e}, o con @kbd{C-u} y luego un n@'umero, por
ejemplo, @kbd{C-u 3 M-e} (si presionas @kbd{C-u} sin ningun n@'umero, el
valor por
defecto es 4).

@node multiply-by-seven en detalle
@subsection @code{multiplicar-por-siente} interactivo

Veamos la clase especial @code{interactive} y
despues la funci@'on @code{message} en la versi@'on interactiva de
@code{multiplicar-por-siente}. Recordaras que la definici@'on de
funci@'on tiene el siguente aspecto:

@smallexample
@group
(defun multiplicar-por-siente (numero)       ; @r{Versi@'on Interactiva.}
  "Multiplica NUMERO por siete."
  (interactive "p")
  (message "El resultado es %d" (* 7 numero)))
@end group
@end smallexample

En esta funci@'on, la expresi@'on, @code{(interactive "p")}, es una
lista de dos elementos. La @code{"p"} le indica a Emacs que debe pasar el
argumento prefijo a la funci@'on y utilizar este valor para el argumento de
la funci@'on.

@need 1000
El argumento debe ser un n@'umero. Esto significa que el
s@'{@dotless{i}}mbolo @code{numero} estara asociado a un
n@'umero en la l@'{@dotless{i}}nea:

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

@need 1250
@noindent
Por ejemplo, si tu argumento prefijo es 5, el int@'erprete Lisp
evaluar@'a la l@'{@dotless{i}}nea como si fuera:

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

@noindent
(Si est@'as leyendo esto en GNU Emacs, puedes evaluar esta
expresi@'on por ti mismo.) Primera, el int@'erprete
evaluar@'a la lista interna, que es @code{(* 7 5)}. Esto devuelve un
valor de 35. A continuaci@'on, se evaluar@'a la lista externa, pasando los
valores del segundo y posteriores elementos de la lista a la
funci@'on @code{message}.

Como hemos visto, @code{message} es una funci@'on Emacs Lisp
especialmente dise@~nada para enviar un
mensaje de una l@'{@dotless{i}}nea al usuario. (@xref{message, , La
funci@'on @code{message}})
En resumen, la funci@'on @code{message} imprime su primer argumento en
el @'area echo tal cual, exceptuando las apariciones de @samp{%d}, o
@samp{%s} (y varias otras secuencias de control que no hemos
mencionado). Cuando aparece una secuencia de control, la funci@'on observa
al segundo o posteriores argumentos e imprime el valor del argumento
en la ubicaci@'on donde se encuentra la secuencia de control.

En la funci@'on interactiva @code{multiplicar-por-siente}, la cadena de
control es @samp{%d}, que requiere un n@'umero, y el valor devuelto
por la evaluaci@'on de @code{(* 7 5)} es el n@'umero 35. Por consiguiente,
el
n@'umero 35 se imprime en lugar de @samp{%d} y el mensaje es @samp{El
resultado es 35}.

(N@'otese que cuando llamas a la funci@'on @code{multiplicar-por-siente},
el mensaje se imprime sin comillas, pero cuando llamas a
@code{message}, el texto se impreme entre comillas. Esto se debe
a que el valor devuelto por @code{message} aparece en el @'area echo
cuando eval@'uas una expresi@'on cuyo primer elemento es
@code{message}; pero si se integra en una funci@'on,
@code{message} imprime el texto como un efecto secundario sin comillas.)

@node Opciones de interactive.
@section Diferentes opciones para @code{interactive}
@cindex Opciones para @code{interactive}
@cindex Opciones Interactive

En el ejemplo, @code{multiplicar-por-siente} usa @code{"p"} como el
argumento para @code{interactive}. Este argumento indica a Emacs que
interprete cualquier cosa que escriba despues de @kbd{C-u} o
del comando @key{META} como un n@'umero que sera el argumento a pasar
a la funci@'on. Emacs tiene m@'as de veinte
caracteres predefinidos para usar con @code{interactive}. En casi todos los
casos, una de estas opciones te permitira pasar la
informaci@'on adecuada interactivamente a una
funci@'on. (@xref{Interactive Codes, , Car@'acteres C@'odigo para
@code{interactive}, elisp, El Manual de Referencia GNU Emacs Lisp}).

@need 1250
Considera la funci@'on @code{zap-to-char}. Su expresi@'on interactiva es

@smallexample
(interactive "p\ncZap to char: ")
@end smallexample

La primer parte del argumento de @code{interactive} es @samp{p},
con el que ya est@'as familiarizado. Este argumento le indica a Emacs
intepretar un `prefijo', como un n@'umero que se pasa a la
funci@'on. Puedes especificar un prefijo plesionando @kbd{C-u}
seguido por un n@'umero o igualmente con @key{META} seguido por un
n@'umero. El prefijo es un n@'umero de caracteres especifico. De
este modo, si el prefijo es tres y el caracter
establecido es @samp{x}, entonces se borrar@'a todo el
texto incluido el tercer @samp{x} siguiente. Si no se establece un
prefijo, entonces borras todo el texto incluido el cuarto car@'acter
establecido, pero no m@'as.

La @samp{c} indica a la funci@'on el nombre del car@'acter que va a
eliminar.

M@'as formalmente, una funci@'on con dos o m@'as argumentos puede
tener informaci@'on que pasa a cada argumento a@~nadiendo partes en la
cadena viene despues de @code{interactive}. Cuando haces esto, la
informaci@'on se pasa a cada argumento en el mismo orden que se especifica
en la lista @code{interactive}. En la cadena, cada
parte est@'a separada de la siguiente parte por un @samp{\n}, que
significa nueva l@'{@dotless{i}}nea. Por ejemplo, a
@samp{p} puede continuar un @samp{\n} y un @samp{cZap to char:@:}. Esto hace
que
Emacs pase el valor del argumento prefijo (si lo hay) y el
car@'acter.

En este caso, la definici@'on de funci@'on se parace a la siguiente,
donde @code{arg} y @code{char} son los s@'{@dotless{i}}mbolos que
@code{interactive} vincula el argumento prefijo y el caracter especificado:

@smallexample
@group
(defun @var{nombre-de-funcion} (arg char)
  "@var{documentacion}@dots{}"
  (interactive "p\ncZap to char: ")
  @var{cuerpo-de-funcion}@dots{})
@end group
@end smallexample

@noindent
(El espacio despu@'es del punto y coma en pantalla hace que se vea
mejor. @xref{copy-to-buffer, , La Definici@'on de
@code{copy-to-buffer}}, para un ejemplo.)

Cuando una funci@'on no toma argumentos, @code{interactive} no
requiere ninguno. Una funci@'on asi contiene unicamente la expresi@'on
@code{(interactive)}. La funci@'on @code{mark-whole-buffer} es asi.

Alternativamente, si los c@'odigos de letras especiales no son adecuados
para tu
aplicaci@'on, puedes pasar tus propios argumentos a
@code{interactive} como una lista.

@xref{append-to-buffer, , La Definici@'on de @code{append-to-buffer}},
para un ejemplo. @xref{Using Interactive, , Usando
@code{interactive}, elisp, El Manual de GNU Emacs Lisp}, para una
explicaci@'on m@'as completa acerca de esta t@'ecnica.

@node Instalaci@'on Permanente
@section Instalar c@'odigo permanentemente
@cindex Instalar c@'odigo permanentemente
@cindex C@'odigo Permanente de Instalaci@'on
@cindex C@'odigo de instalaci@'on

Cuando instalas una definici@'on de funci@'on evaluada por ti,
permanecera instalada hasta que salgas de Emacs. La
proxima vez que inicies una nueva sesi@'on de Emacs, la
funci@'on no ser@'a instalada a menos que eval@'ues de nuevo la
definici@'on.

En alg@'un punto, podrias necesitar que el c@'odigo se instale
autom@'aticamente cada vez que inicies una nueva sesi@'on de
Emacs. Hay varias formas de hacer esto:

@itemize @bullet
@item
Si tienes c@'odigo solo para tu uso, puedes poner el
c@'odigo de la definici@'on de funci@'on en el fichero de
inicializaci@'on @file{.emacs}. Cuando se inicia Emacs, el fichero
@file{.emacs} se eval@'ua autom@'atica y se instalan todas sus definiciones
de
funci@'on. @xref{Inicializaci@'on de Emacs,
, Tu Fichero @file{.emacs}}.

@item
Como Alternativa, puedes poner las definiciones de funci@'on
en uno o m@'as ficheros y usar la funci@'on
@code{load} para hacer que Emacs evalue y con ello instale cada una de las
funciones en
los ficheros. @xref{Cargando ficheros, , Cargando ficheros}.

@item
En tercer lugar, si tienes c@'odigo que todo tu sitio va a utilizar, es
normal
ponerlo en un fichero llamado @file{site-init.el} que se carga
cuando se construye Emacs. Esto hace que el c@'odigo este disponible a
cualquiera que use tu m@'aquina. (Mira el fichero @file{INSTALL} que
forma parte de la distribuci@'on Emacs.)
@end itemize

Finalmente, si tienes c@'odigo 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@'odigo y su documentaci@'on bajo una licencia que permita a otras
personas ejecutar, copiar, estudiar, modificar, y redistribuir el
c@'odigo y te proteja de quien tome tu trabajo.) Si envias
una copia de tu c@'odigo a la Free Software Foundation, y lo proteges
apropiadamente de t@'{@dotless{i}} 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@'es de los
a@~nos, por donaciones.

@node let
@section @code{let}
@findex let

La expresi@'on @code{let} es una forma especial en Lisp que
tendras que utilizar en la mayor@'{@dotless{i}}a de las
definiciones de funci@'on.

@code{let} se utiliza para unir o enlazar un s@'{@dotless{i}}mbolo
a un valor de tal manera que el int@'erprete no confunda la
variable con otra variable del mismo nombre que no forma parte de la
funci@'on.

Para comprender por qu@'e la forma especial @code{let} es necesaria,
considera la situaci@'on 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@'on hace
referencia a `la casa', es probable que se refiera a
@emph{su} casa, no a la tuya, es decir, es una casa distinta.

Si tu amigo se refiere a su casa y tu crees que @'el se
est@'a refiri@'endo a tu casa, puedes tener cierta
confusi@'on. Lo mismo podria ocurrir en Lisp si una
variable que se utiliza dentro de una funci@'on tiene el mismo que una
variable usada dentro de otra funci@'on, y las dos no tienen la
intenci@'on de referirse al mismo valor. La forma especial @code{let}
previene este tipo de confusi@'on.

@menu
* Prevenir confusi@'on::     Prevenir confusi@'on
* Partes de la expresi@'on let::  Partes de la expresi@'on let
* Ejemplo de expresi@'on let::  Ejemplo de expresi@'on let
* Variables let inicializadas::  Variables let inicializadas
@end menu

@ifnottex
@node Prevenir confusi@'on
@unnumberedsubsec @code{let} evita confusiones
@end ifnottex

@cindex @samp{variable local} definida
@cindex @samp{variable, local}, definida
La forma especial @code{let} evita confusiones. @code{let} crea
un nombre para una @dfn{variable local} que eclipsa cualquier uso
del mismo nombre fuera de la expresi@'on @code{let}. Esto es como
entender que siempre que tu anfitri@'on se refiera a `la casa',
significa su casa, no la tuya. (Los s@'{@dotless{i}}mbolos usados en
las listas de argumentos funcionan de la misma manera. @xref{defun, , La
Forma Especial @code{defun}}.)

Las variable locales por una expresi@'on @code{let} conservan
su valor @emph{solo} dentro de la expresi@'on @code{let}
misma (y dentro de expresiones llamadas dentro de la expresi@'on
@code{let}); las variables locales no tiene efecto fuera de la
expresi@'on @code{let}.

Otra forma de pensar respecto a @code{let} es que es como un
@code{setq} que es temporal y local. Los valores establecidos por
@code{let} son autom@'aticamente deshechos cuando termina el @code{let}.
La configuraci@'on solo afecta a las expresiones que se encuentran
dentro de los limites de la expresi@'on @code{let}. En jerga
informatica, dir@'{@dotless{i}}amos ``la
union de un simbolo es visible solo en las
funciones llamadas en la forma @code{let}; en Emacs Lisp, el alcance
es din@'amico, no l@'exico.''

@code{let} puede crear m@'as de una variable a la vez. Ademas,
@code{let} da a cada variable que crea un valor inicial, ya sea un valor
especificado por t@'{@dotless{i}}, o @code{nil}. (En la jerga, eso se
llama `unir la variable al valor'.) Despu@'es que @code{let} ha creado
y unido las variables, ejecuta el c@'odigo en el cuerpo del
@code{let} y devuelve el valor de la @'ultima expresi@'on en el
cuerpo, como el valor de toda la expresi@'on @code{let}.
(`Ejecutar' es un t@'ermino tecnico que significa evaluar
una lista: proviene del significando de la palabra `llevar a la
pr@'actica' (@cite{Diccionario de Ingl@'es de Oxford}). Dado que
eval@'uas una expresi@'on para realizar una acci@'on, `ejecutar' ha
evolucionado como un sin@'onimo para `evaluar'.)

@node Partes de la expresi@'on let
@subsection Las partes de una expresi@'on @code{let}
@cindex expresi@'on @code{let}, partes de
@cindex Partes de la expresi@'on @code{let}

@cindex @samp{varlist} definida
Una expresi@'on @code{let} es una lista de tres partes. La primer
parte es el s@'{@dotless{i}}mbolo @code{let}. La segunda parte es una
lista, denominada @dfn{varlist} (lista de variables), cada uno de cuyos
elementos es un
s@'{@dotless{i}}mbolo por s@'{@dotless{i}} mismo o una lista de dos
elementos, el primer elemento es un s@'{@dotless{i}}mbolo. La
tercera parte de la expresi@'on @code{let} es el cuerpo del
@code{let}. El cuerpo normalmente consiste de una o m@'as listas.

@need 800
Una plantilla para una expresi@'on @code{let} se parece a esto:

@smallexample
(let @var{varlist} @var{body}@dots{})
@end smallexample

@noindent
Los s@'{@dotless{i}}mbolos en la varlist son las variables que dan
los valores iniciales para la forma especial @code{let}. Los
s@'{@dotless{i}}mbolos por s@'{@dotless{i}} solos reciven el
valor inicial de @code{nil}; y cada s@'{@dotless{i}}mbolo que es el
primer elemento de una lista de dos elementos es unido al valor
que el devuelto cuando el int@'erprete Lisp eval@'ua el segundo elemento.

De este modo, una varlist como:
@code{(thread (needles 3))}. En este caso, dentro una expresi@'on
@code{let}, Emacs une el s@'{@dotless{i}}mbolo @code{thread} a un
valor inicial de @code{nil}, y une el s@'{@dotless{i}}mbolo
@code{needles} a un valor inicial de 3.

Cuando escribes una expresi@'on @code{let}, lo que haces es poner las
expresiones apropiadas en los huecos de la plantilla de expresi@'on
@code{let}.

Si la varlist est@'a compuesta de listas de 2 elementos,
como suele ser el caso, la plantilla de la expresi@'on
@code{let} es la siguiente:

@smallexample
@group
(let ((@var{variable} @var{valor})
      (@var{variable} @var{valor})
      @dots{})
  @var{cuerpo}@dots{})
@end group
@end smallexample

@node Ejemplo de expresi@'on let
@subsection Ejemplo de Expresi@'on @code{let}
@cindex Ejemplo de Expresi@'on @code{let}
@cindex expresi@'on simple @code{let}

La siguiente expresi@'on crea y da valores iniciales a las
dos variables @code{cebra} y @code{tigre}. El cuerpo de la expresi@'on
@code{let} es una lista que llama a la funci@'on @code{message}.

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

Aqu@'{@dotless{i}}, la varlist es @code{((cebra 'rayas) (tigre
'fiero))}.

Las dos variables son @code{cebra} y @code{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 @code{cebra} al valor @code{rayas}@footnote{De
acuerdo con Jared Diamond en @cite{Guns, Germs, and Steel}, ``@dots{} las
cebras se vuelven increiblemente peligrosas a medida que envejecen'' pero la
demanda aqu@'{@dotless{i}} es que no llegan a ser fieras como un
tigre. (1997, W. W. Norton and Co., ISBN 0-393-03894-2, pagina 171)}, y
une la variable @code{tigre} al valor @code{fiero}. En este
ejemplo, ambos valores son s@'{@dotless{i}}mbolos precedidos por una
cita. Los valores podr@'{@dotless{i}}an muy bien haber sido otra
lista o una cadena. El cuerpo de @code{let} sigue despu@'es de la lista
que contiene las variables. En este ejemplo, el cuerpo es una lista que
usa la funci@'on @code{message} para imprimir una cadena en el @'area
echo.

@need 1500
Puedes evaluar el ejemplo de la forma habitual, coloca el cursor
despu@'es del @'ultimo par@'entesis y presiona @kbd{C-x
C-e}. Al hacer esto, aparecer@'a lo siguiente en el @'area echo:

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

Como hemos visto antes, la funci@'on @code{message} imprime su primer
argumento, excepto por @samp{%s}. En este ejemplo, el valor de la
variable @code{cebra} se imprime en la posici@'on del primer @samp{%s}
y el valor de la variable @code{tigre} se imprime en la posici@'on del
segundo @samp{%s}.

@node Variables let inicializadas
@subsection Variables sin inicializar en un sentencia @code{let}
@cindex Variables @code{let} no inicializadas
@cindex Variables @code{let} no inicializadas

Si no se une a las variables en una sentencia @code{let} con valores
iniciales espec@'{@dotless{i}}ficos, autom@'aticamente seran unidos
a un valor inicial de @code{nil}, como en la siguiente expresi@'on:

@smallexample
@group
(let ((abedul 3)
      pino
      abeto
      (roble 'algunos))
  (message
   "Aqu@'{@dotless{i}} est@'an %d variables con %s, %s, y el valor %s."
   abedul pino abeto roble))
@end group
@end smallexample

@noindent
Aqu@'{@dotless{i}}, la varlist es @code{((abedul 3) pino abeto (roble
'algunos))}.

@need 1250
Si eval@'uas esta expresi@'on de la forma habitual, aparecer@'a lo
siguiente en el @'area echo:

@smallexample
"Aqu@'i est@'an 3 variables con nil, nil, y el valor algunos."
@end smallexample

@noindent
En este ejemplo, Emacs une el s@'{@dotless{i}}mbolo @code{abedul}
al n@'umero 3, une los s@'{@dotless{i}}mbolos
@code{pino} y @code{abeto} a @code{nil}, y une el
s@'{@dotless{i}}mbolo @code{roble} al valor @code{algunos}.

Observe que en la primera parte de @code{let}, las variables @code{pino}
y @code{abeto} son unicamente @'atomos que no est@'an rodeados por
par@'entesis; esto se debe a que est@'an siendo unidos a @code{nil},
la lista vac@'{@dotless{i}}a. Pero @code{roble} se une a
@code{algunos} por ello es parte de la lista @code{(roble
'algunos)}. De manera similar, @code{abedul} se une al n@'umero 3 en
una lista con este n@'umero. (Ya que un
n@'umero se eval@'ua a s@'{@dotless{i}} mismo, el n@'umero no
necesita ser citado. Ademas, el n@'umero se imprime en el mensaje
usando un @samp{%d} en lugar de un @samp{%s}.) Las cuatro variables como un
grupo son puestas dentro de una lista para delimitarla de el
cuerpo de @code{let}.

@node if
@section La forma especial @code{if}
@findex if
@cindex Condicional con @code{if}

Adem@'as de @code{let} y @code{defun}, esta la forma especial
condicional @code{if}. Esta forma se utiliza para indicar al
computador que tome decisiones. Puedes escribir definiciones de
funci@'on sin necesidad de utilizar @code{if}, pero se usa con bastante
frecuencia, y es lo suficientemente importante como para incluirse
aqu@'{@dotless{i}}. Se utiliza, por ejemplo, en el c@'odigo para la
funci@'on @code{beginning-of-buffer}.

La idea b@'asica detras de @code{if}, es que ``@emph{if} (si) una prueba es
verdad
@emph{then} (entonces) se evalua la expresi@'on.'' Si la prueba no es
verdad, la
expresi@'on no se evalua. Por ejemplo, podr@'{@dotless{i}}a
tomar una decisi@'on como, ``@exclamdown{}si es c@'alido y
soleado, entonces ir a la playa!''

@menu
* if en m@'as detalle::      if en m@'as detalle
* tipo-de-animal en detalle::  Un ejemplo de una expresi@'on @code{if}.
@end menu

@ifnottex
@node if en m@'as detalle
@unnumberedsubsec @code{if} en m@'as detalle
@end ifnottex

@cindex @samp{parte-si} definida
@cindex @samp{parte-entonces} definida
Al escribir una expresi@'on @code{if} en Lisp no se utiliza la
palabra `then'; la prueba y la acci@'on son el segundo y tercer
elementos de la lista cuyo primer elemento es @code{if}.
No obstante, la parte de la prueba en una expresi@'on
@code{if} a menudo se llamada @dfn{if-part}
(@emph{parte-si}) y el segundo argumento a menudo se llamada
@dfn{then-part} (@emph{parte-entonces}).

Adembas, cuando se escribe una expresi@'on @code{if}, la
prueba-verdadero-o-falso normalmente se escribe en la misma
l@'{@dotless{i}}nea que el s@'{@dotless{i}}mbolo @code{if}, pero la
acci@'on a llevar a cabo si la prueba es verdadera, ``then-part''
(@emph{parte-entonces}), se escribe en la segunda y siguientes
l@'{@dotless{i}}neas. Esto hace que la expresi@'on @code{if}
sea mas f@'acil de leer.

@smallexample
@group
(if @var{prueba-verdadero-o-falso}
    @var{accion-a-realizar-si-el-test-es-cierto})
@end group
@end smallexample

@noindent
La prueba-verdadero-o-falso es una expresi@'on que evalua el
int@'erprete Lisp.

Aqu@'{@dotless{i}} hay un ejemplo que puedes evaluar.
La prueba consiste en si el n@'umero 5 es mayor que el n@'umero 4. Ya que es
as@'i,
se imprime el mensaje @samp{@exclamdown{}5 es mayor que 4!}.

@smallexample
@group
(if (> 5 4)                           ; @r{parte-si}
    (message "@exclamdown{}5 es mayor que 4!"))   ; @r{parte-entonces}
@end group
@end smallexample

@noindent
(La funci@'on @code{>} comprueba si su primer argumento es mayor que su
segundo argumento y devuelve verdadero si lo es.)
@findex > (mayor que)

Por supuesto, en un caso real, la prueba en una expresi@'on @code{if} no
ser@'a siempre la misma, como en la expresi@'on
@code{(> 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, @exclamdown{}no
necesitamos realizar la prueba!)

Por ejemplo, el valor puede estar unido a un argumento de una
definici@'on de funci@'on. En la siguiente definici@'on de funci@'on,
el tipo de animal es un valor que se pasa a la funci@'on. Si
el valor unido a @code{caracteristica} es
@code{fiero}, entonces se imprime el mensaje, @samp{@exclamdown{}Es un
tigre!};
de otro modo, se devolvera @code{nil}.

@smallexample
@group
(defun tipo-de-animal (caracteristica)
  "Imprime el mensaje en el @'area echo dependiendo de CARACTERISTICA.
Si la CARACTERISTICA es el s@'{@dotless{i}}mbolo `fiero',
entonces advierte que es un tigre."
  (if (equal caracteristica 'fiera)
      (message "@exclamdown{}Es un tigre!")))
@end group
@end smallexample

@need 1500
@noindent
Si est@'as leyendo esto dentro de GNU Emacs, puedes evaluar la
definici@'on de funci@'on de la forma habitual para instalarlo en Emacs, y
luego puedes evaluar las dos expresiones siguientes para ver los resultados:

@smallexample
@group
(tipo-de-animal 'fiero)
(tipo-de-animal 'cebra)

@end group
@end smallexample

@c Following sentences rewritten to prevent overfull hbox.
@noindent
Al evaluar @code{(tipo-de-animal 'fiero)}, veras el siguiente
mensaje impreso en el @'area echo: @code{"@exclamdown{}Es un tigre!"};
y cuando se eval@'ua @code{(tipo-de-animal 'cebra)} ver@'as @code{nil}
impreso en el @'area echo.

@node tipo-de-animal en detalle
@subsection La funci@'on @code{tipo-de-animal} en detalle

Veamos la funci@'on @code{tipo-de-animal} en detalle.

La definici@'on de funci@'on @code{tipo-de-animal} se escribio
llenando los espacios de dos plantillas, la primera para la definici@'on
de funci@'on como un todo, y la seguanda para una expresi@'on @code{if}.

@need 1250
La plantilla para cada funci@'on no interactiva es:

@smallexample
@group
(defun @var{nombre-de-funcion} (@var{lista-de-argumentos})
  "@var{documentacion}@dots{}"
  @var{cuerpo}@dots{})
@end group
@end smallexample

@need 800
Las partes de la funci@'on que encajan con esta plantilla se ven asi:

@smallexample
@group
(defun tipo-de-animal (caracteristica)
  "Imprime el mensaje en el @'area echo dependiendo de CARACTERISTICA.
Si la CARACTERISTICA es el s@'{@dotless{i}}mbolo `fiero',
entonces advierte que es un tigre."
  @var{cuerpo: la expresi@'on} @code{if})
@end group
@end smallexample

El nombre de funci@'on es @code{tipo-de-animal}; se pasa al valor de
un argumento. A la lista de argumentos se sigue una cadena de
documentaci@'on multi-l@'{@dotless{i}}nea. La cadena de
documentaci@'on se incluye en el ejemplo porque es un buen h@'abito
escribir la cadena de documentaci@'on para cada definici@'on de
funci@'on. El
cuerpo de la definici@'on de funci@'on consiste en la expresi@'on
@code{if}. 

@need 800
La plantilla para una expresi@'on @code{if} se ve as@'{@dotless{i}}:

@smallexample
@group
(if @var{prueba-verdadero-o-falso}
    @var{accion-a-realizar-si-la-prueba-devuelve-verdadero})
@end group
@end smallexample

@need 1250
En la funci@'on @code{tipo-de-animal}, el c@'odigo para @code{if}
se ve as@'{@dotless{i}}:

@smallexample
@group
(if (equal caracteristica 'fiero)
    (message "@exclamdown{}Es un tigre!")))
@end group
@end smallexample

@need 800
Aqu@'{@dotless{i}}, est@'a la expresi@'on prueba-verdadero-o-falso

@smallexample
(equal caracteristica 'fiero)
@end smallexample

@noindent
En Lisp, @code{equal} es una funci@'on que determina si su primer
argumento es igual a su segundo argumento. El segundo argumento es
el s@'{@dotless{i}}mbolo citado @code{'fiero} y el primer argumento es
el valor del s@'{@dotless{i}}mbolo @code{caracteristico}
--- en otras palabras, el argumento pasado a esta funci@'on.

En la primer prueba de @code{tipo-de-animal}, el argumento
@code{fiero} se pasa a @code{tipo-de-animal}. Ya que @code{fiero}
es igual a @code{fiero}, la expresi@'on, @code{(equal caracteristica
'fiero)}, devuelve el valor verdadero. Cuando esto sucede,
@code{if} eval@'ua el segundo argumento o la parte-entonces
del @code{if}: @code{(message "@exclamdown{}Es un tigre!")}.

Por otro lado, en la segunda prueba de @code{tipo-de-animal}, se
pasa el argumento @code{cebra} a @code{tipo-de-animal}. @code{cebra}
no es igual a @code{fiero}, por lo que la parte-entonces no
se evalua y se devuelve @code{nil} por la expresi@'on
@code{if} (@emph{si}).

@node else
@section Expresiones if--then--else
@cindex Else

Una expresi@'on @code{if} puede tener un tercer argumento
opcional, llamado la @dfn{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@'on @code{if}
global, @emph{no} se eval@'ua, pero el tercer argumento o la
parte-de_otro_modo
@emph{se} eval@'ua. Podr@'{@dotless{i}}a pensar en esto como la
alternativa del d@'{@dotless{i}}a nublado para la decisi@'on ``si es
c@'alido y soleado, entonces ir a la playa, de otro modo @exclamdown{}leer
un
libro!''

La palabra ``else'' (``de otro modo'') no se escribe en el c@'odigo
Lisp; la parte-de_otro_modo de una expresi@'on @code{if}
viene despu@'es de la parte-entonces. En Lisp,
la parte-de_otro_modo suele escribirse al inicio
de una nueva l@'{@dotless{i}}nea y se indenta menos
que la parte-entonces:

@smallexample
@group
(if @var{prueba-verdadero-o-falso}
    @var{accion-a-realizar-si-la-prueva-devuelve-verdadero}
  @var{accion-a-realizar-si-la-prueba-devuelve-falso})
@end group
@end smallexample

Por ejemplo, la siguiente expresi@'on @code{if} imprime el mensaje
@samp{@exclamdown{}4 no es mayor que 5!} al evaluarse en la forma
habitual:

@smallexample
@group
(if (> 4 5)                                   ; @r{parte-si}
    (message "@exclamdown{}4 falsamente es mayor que 5!") ; @r{parte-entonces}
  (message "@exclamdown{}4 no es mayor que 5!"))          ; @r{parte-resto}
@end group
@end smallexample

@noindent
N@'otese que los diferentes niveles de indentaci@'on hacen f@'acil
distinguir la parte then desde la parte resto. (GNU Emacs tiene varios
comandos que autom@'aticamente indenta expresiones correctamente
@code{if} @emph{si}. @xref{Escribiendo listas, , GNU Emacs te ayuda a
escribir listas}.)

Podemos extender la funci@'on @code{tipo-de-animal} para incluir una
parte else para simplemente incorporar una parte adicional para la
expresi@'on @code{if} @emph{si}.

@need 1500
Se puede ver las consecuencias de hacer esto si se eval@'ua la
siguiente versi@'on de la definici@'on de funci@'on
@code{type-of-animal} (@emph{tipo-de-animal}) para instalarlo y
entonces evaluar las dos expresiones subsiguientes para pasar
diferentes argumentos para la funci@'on. 

@smallexample
@group
(defun tipo-de-animal (caracteristica)  ; @r{Segunda versi@'on.}
  "Imprime el mensaje en el @'area echo dependiendo de CARACTERISTICA.
Si la CARACTERISTICA es el s@'{@dotless{i}}mbolo `fiera',
entonces avisa de un tigre; sino di que no es una fiera."
  (if (equal caracteristica 'fiera)
      (message "@exclamdown{}Es un tigre!")
    (message "@exclamdown{}No es una fiera!")))
@end group
@end smallexample
@sp 1

@smallexample
@group
(tipo-de-animal 'fiero)
(tipo-de-animal 'cebra)

@end group
@end smallexample

@c Following sentence rewritten to prevent overfull hbox.
@noindent
Cuando se eval@'ua @code{(tipo-de-animal 'fiera)}, se ver@'a el
siguiente mensaje impreso en el @'area echo: @code{"@exclamdown{}Eso
es un tigre!"}; pero cuando se eval@'ua @code{(tipo-de-animal
'cebra)}, se ver@'a @code{"@exclamdown{}No es una fiera!"}.

(De acuerdo, si la @var{caracter@'{@dotless{i}}stica} fuera
@code{feroz}, el mensaje @code{"@exclamdown{}No es una fiera!"}
ser@'{@dotless{i}}a impreso; @exclamdown{}y ser@'{@dotless{i}}a
err@'oneo!  Cuando se escribe c@'odigo, se necesita tener en cuenta la
posibilidad que algunos argumentos ser@'a probado por @code{if}
@emph{si} y escribir tu programa de acuerdo.

@node Verdad y falsedad
@section Verdad y falsedad en Emacs Lisp
@cindex Verdad y mentira en Emacs Lisp
@cindex Falsedad y verdad en Emacs Lisp
@findex nil

Hay un aspecto importante para el test de verdad en una expresi@'on
@code{if} (@emph{si}). As@'{@dotless{i}}, 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
@code{nil}. Cualquier otra es `verdadero'.

La expresi@'on chequea si verdad se interpreta como (@dfn{true})
@emph{verdadero} si el resultado de evaluarlo es un valor que no es
@code{nil}. En otras palabras, el resultado del test se considera
cierto si el valor devuelto es un n@'umero como 47, una cadena tal
como @code{"hola"}, o un s@'{@dotless{i}}mbolo (otro como @code{nil})
tal como @code{flores}, o una lista (tan larga como eso no est@'a
vac@'{@dotless{i}}a) @exclamdown{}o incluso un b@'uffer!

@menu
* nil explicado::            @code{nil} tiene dos significados.
@end menu

@ifnottex
@node nil explicado
@unnumberedsubsec Una explicaci@'on de @code{nil}
@end ifnottex

Antes de ilustrar un test para verdad, se necesita una explicaci@'on
de @code{nil}.

En Emacs Lisp, el s@'{@dotless{i}}mbolo @code{nil} tiene dos
significados. Primero, est@'a el significado de la lista
vac@'{@dotless{i}}a. Segundo, est@'a el valor de falso y es el valor
devuelto cuando el test test-verdadero-o-falso salga
falso. @code{nil}. Tan lejos como el int@'erprete Lisp es concebido,
@code{()} y @code{nil} son el mismo. Los humanos, sin embargo, tienden
a usar @code{nil} para falso y @code{()} para la lista
vac@'{@dotless{i}}a.

En Emacs Lisp, cualquier valor que no es @code{nil} --- no es una
lista vac@'{@dotless{i}}a --- es considerado verdad. Esto significa
que si una evaluaci@'on devuelve alguna cosa que no es una lista
vac@'{@dotless{i}}a, una expresi@'on @code{if} devuelve verdad. Por
ejemplo, si un n@'umero es puesto en el slot para el test, ser@'a
evaluado y devolver@'a por s@'{@dotless{i}} mismo, desde lo que hacen
los n@'umeros cuando se eval@'uan. En este condicional, la expresi@'on
@code{if} devuelve verdad. La expresi@'on se chequea como falso solo
cuando @code{nil}, una lista vac@'{@dotless{i}}a, es devuelta
evaluando la expresi@'on.

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

En el primer ejemplo, n@'umero 4 es evaluado como el test en la
expresi@'on @code{if} y se devuelve por s@'{@dotless{i}} mismo; por
consiguiente, la then-part de la expresi@'on es evaluada y devuelta:
@samp{true} aparece en el @'area echo. En el segundo ejemplo,
@code{nil} indica falso; por consiguiente, el else-part de la
expresi@'on es evaluada y devuelta: @samp{false} aparece en el @'area echo.

@smallexample
@group
(if 4
    'true
  'false)
@end group

@group
(if nil
    'true
  'false)
@end group
@end smallexample

@need 1250
Incidentalmente, si alg@'un otro valor @'util no est@'a disponible
para un test que devuelve cierto, entonces el int@'erprete Lisp
retornar@'a el s@'{@dotless{i}}mbolo @code{t} para cierto. Por
ejemplo, la expresi@'on @code{(> 5 4)} devuelve @code{t} cuando se
eval@'ua, como puedes ver evalu@'andolo en el camino usual:

@smallexample
(> 5 4)
@end smallexample

@need 1250
@noindent
Por otro lado, esta funci@'on devuelve @code{nil} si el test es falso.

@smallexample
(> 4 5)
@end smallexample

@node save-excursion
@section @code{save-excursion}
@findex save-excursion
@cindex Regi@'on, qu@'e es
@cindex Preservando punto, marca, y b@'uffer
@cindex Punto, marca, preservaci@'on de b@'uffer
@findex punto
@findex marca

La funci@'on @code{save-excursion} es la cuarta y @'ultima forma especial
que se discutir@'a en este cap@'{@dotless{i}}tulo.

En Emacs Lisp hay programas usados para edici@'on, la funci@'on
@code{save-excursion} es muy com@'un. Eso guarda la posici@'on de
punto y marca, ejecuta el cuerpo de la funci@'on, y entonces restaura
el punto y marca a sus posiciones previas si sus posiciones fueran
cambiadas. Su prop@'osito primario es guardar que el usuario sea
sorprendido y molesto por movimientos inesperados de punto y marca.

@menu
* Punto y marca::            Una revisi@'on de varias localizaciones.
* Plantilla para save-excursion::  Plantilla para save-excursion
@end menu

@ifnottex
@node Punto y marca
@unnumberedsubsec Punto y Marca
@end ifnottex

Antes de discutir @code{save-excursion}, sin embargo, puede ser @'util
primero revisar que punto y marca est@'an en GNU Emacs. @dfn{Punto} es
la posici@'on actual del cursor. En cualquier lugar que el cursor se
posicione hay un punto. De manera m@'as precisa, en terminales donde
el cursor parece estar en lo alto de un car@'acter, el punto est@'a
inmediatamente antes del car@'acter. En Emacs Lisp, punto es un
entero. El primer car@'acter en un b@'uffer es el n@'umero uno, el segundo
es el n@'umero dos, y as@'{@dotless{i}}. La funci@'on @code{punto}
devuelve la posici@'on actual del cursor como un n@'umero. Cada
b@'uffer tiene su propio valor para el punto.

La @dfn{marca} es otra posici@'on en el b@'uffer; su valor puede ser
asignado con un comando tal como @kbd{C-@key{SPC}}
(@code{set-mark-command}). Si una marca ha sido asignada, se puede
usar el comando @kbd{C-x C-x} (@code{exchange-point-and-mark}) para
hacer que el cursor salte a la marca y asignar la marca para la
posici@'on previa del punto. Adem@'as, si tu asignas otra marca, la
posici@'on puede ser guardada por este camino. Se puede saltar al
cursor para una marca guardada escribiendo @kbd{C-u C-@key{SPC}} una o
m@'as veces.

La parte del b@'uffer entre el punto y la marca es llamada @dfn{la
regi@'on}. Numerosos comandos trabajan en la regi@'on, incluyendo
@code{center-region}, @code{count-lines-region}, @code{kill-region} y
@code{print-region}.

La forma especial @code{save-excursion} salva las posiciones del punto
y la marca y restaura estas posiciones despu@'es del c@'odigo con el
cuerpo de la forma especial es evaluada por el int@'erprete Lisp. De
este modo, si el punto fuera en el principio de una pieza de texto y
alg@'un c@'odigo movido apunta al fin del b@'uffer, el
@code{save-excursion} no apuntar@'{@dotless{i}}a a donde fu@'e antes,
despu@'es las expresiones en el cuerpo de las que fueron evaluadas.

En Emacs, una funci@'on frecuentemente mueve el punto como parte de
sus trabajos internos incluso aunque un usuario no espere esto. Por
ejemplo, @code{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, @code{save-excursion} es con
frecuencia usado para punto y marca en la posici@'on esperada por el
usuario. El uso de @code{save-excursion} es un buen guarda casas.

Para estar seguro que la casa est@'a limpia, @code{save-excursion}
restaura los valores de punto y marca incluso si alguna cosa va mal en
el c@'odigo dentro de eso (o, para ser m@'as preciso y usar la jerga
apropiada, ``en caso de salida anormal''). Esta funcionalidad es muy
@'util.

Adem@'as grabando los valores de punto y marca, @code{save-excursion}
guarda la traza del actual buffer, y lo restaura, tambi@'en. Esto
significa que puedes escribir c@'odigo que cambiar@'a el buffer y
tener que @code{save-excursion} vuelva al buffer original. Esto es como
@code{save-excursion} es usado en
@code{append-to-buffer}. (@xref{append-to-buffer, , La Definici@'on de
@code{append-to-buffer}}.)

@node Plantilla para save-excursion
@subsection Plantilla para una expresi@'on @code{save-excursion}

@need 800
La plantilla para c@'odigo usando @code{save-excursion} es simple:

@smallexample
@group
(save-excursion
  @var{body}@dots{})
@end group
@end smallexample

@noindent
El cuerpo de la funci@'on es una o m@'as expresiones que ser@'an
evaluadas en secuencia por el int@'erprete Lisp. Si hay m@'as de una
expresi@'on en el cuerpo, el valor de la @'ultima ser@'a devuelto como
el valor de la funci@'on @code{save-excursion}. Las otras expresiones
en el cuerpo son evaluadas solo por sus efectos laterales; y
@code{save-excursion} en s@'{@dotless{i}} es usado solo por su efecto
lateral (que est@'a restaurando las posiciones de punto y marca).

@need 1250
Para m@'as detalles, la siguiente plantilla explica @code{save-excursion}

@smallexample
@group
(save-excursion
  @var{primera-expresion-en-el-cuerpo}
  @var{segunda-expresion-en-el-cuerpo}
  @var{tercera-expresion-en-el-cuerpo}
   @dots{}
  @var{ultima-expresion-en-el-cuerpo})
@end group
@end smallexample

@noindent
Una expresi@'on, de acuerdo, puede ser un s@'{@dotless{i}}mbolo por
s@'{@dotless{i}} mismo o una lista.

En c@'odigo Emacs Lisp, una expresi@'on @code{save-excursion} con
frecuencia ocurre el cuerpo de una expresi@'on @code{let}. Eso se ve
como esto:

@smallexample
@group
(let @var{varlist}
  (save-excursion
    @var{body}@dots{}))
@end group
@end smallexample

@node Revisar
@section Revisar

En los @'ultimos pocos cap@'{@dotless{i}}tulos se han introducido un
n@'umero limpio de funciones y formas especiales. Aqu@'{@dotless{i}}
se han descrito brevemente, con unas pocas funciones similares que no
han sido mencionadas todav@'{@dotless{i}}a.

@table @code
@item eval-last-sexp
Eval@'ua la @'ultima expresi@'on simb@'olica antes de la posici@'on
actual del punto. El valor es impreso en el @'area echo a menos
que la funci@'on sea invocada con un argumento; en este caso, la salida
es impresa en el actual b@'uffer. Este comando est@'a normalmente
asociado a @kbd{C-x C-e}.

@item defun
Definir funci@'on. Esta forma especial ha subido a cinco partes: el
nombre una plantilla para los argumentos que ser@'an pasados a la
documentaci@'on de la funci@'on, una declaraci@'on interactiva
opcional, y el cuerpo de la definici@'on.

@need 1250
Por ejemplo, en las primeras versiones de Emacs, la definici@'on de
funci@'on era como sigue. (Eso es ligeramente m@'as complejo ahora que
si busca el primer caracter de espacio no en blanco en vez del primer
caracter visible.)

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

@ignore
In GNU Emacs 22,

(defun backward-to-indentation (&optional arg)
  "Move backward ARG lines and position at first nonblank character."
  (interactive "p")
  (forward-line (- (or arg 1)))
  (skip-chars-forward " \t"))

(defun back-to-indentation ()
  "Move point to the first non-whitespace character on this line."
  (interactive)
  (beginning-of-line 1)
  (skip-syntax-forward " " (line-end-position))
  ;; Move back over chars that have whitespace syntax but have the p flag.
  (backward-prefix-chars))
@end ignore

@item interactive
Declara al int@'erprete que la funci@'on puede ser usada
interactivamente. Esta forma especial puede ser seguida por una cadena
con una o m@'as partes que pasan la informaci@'on a los argumentos de
la funci@'on, en secuencia. Estas partes pueden tambi@'en contar al
int@'erprete para mostrar la informaci@'on. Parte de las cadenas son
separadas por nuevas l@'{@dotless{i}}neas, @samp{\n}.

@need 1000
Caracteres de c@'odigo com@'un son:

@table @code
@item b
El nombre de un b@'uffer existente.

@item f
El nombre de un fichero existente

@item p
El argumento prefijo num@'erico. (N@'otese que esta `p' es min@'uscula.)

@item r
El Punto y la marca, como dos argumentos num@'ericos, el m@'as
peque@~no primero. Esta es la @'unica letra que especifica dos
argumentos sucesivos en vez de uno.
@end table

@xref{C@'odigos Interactivos, , Caracteres de C@'odigo para
@samp{interactive}, elisp, El Manual de Referencia de GNU Emacs Lisp},
para una lista de caracteres de c@'odigo.

@item let
Declara que una lista de variables es para usarla con el cuerpo del
@code{let} y darles un valor inicial, bien @code{nil} o un valor
espec@'{@dotless{i}}fico; entonces se evaluar@'an el resto de las
expresiones en el cuerpo del @code{let} y devolver el valor de la
@'ultima. Dentro del cuerpo del @code{let}, el int@'erprete Lisp no ve
los valores de las variables de los mismos nombres que son asociados
fuera del @code{let}.

@need 1250
Por ejemplo,

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

@item save-excursion
Graba los valores de punto y marca y el actual b@'uffer antes de evaluar
el cuerpo de esta forma especial. Restaura los valores de punto y
marca y el b@'uffer despu@'es de esto.

@need 1250
Por ejemplo,

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

@item if
Eval@'ua el primer argumento a la funci@'on; si es verdad, eval@'ua el
segundo argumento; lo dem@'as eval@'ua el tercer argumento, si hay uno.

La forma especial @code{if} es llamada @dfn{condicional}. Hay otros
condicionales en Emacs Lisp, pero @code{if} es quiz@'as lo m@'as
com@'unmente usado.

@need 1250
Por ejemplo,

@smallexample
@group
(if (= 22 version-de-emacs-mayor)
    (message "Esta es la versi@'on 22 de Emacs")
  (message "Esta no es la versi@'on 22 Emacs"))
@end group
@end smallexample

@need 1250
@item <
@itemx >
@itemx <=
@itemx >=
La funci@'on @code{<} chequea si su primer argumento es m@'as peque@~no
que su segundo argumento. Una funci@'on correspondiente, @code{>},
chequea si el primer argumento es mayor que el segundo. De otro modo,
@code{<=} chequea si el primer argumento es menor o igual al segundo y
@code{>=} chequea si el primer argumento es mayor o igual al
segundo. En todos los casos, ambos argumentos deben ser n@'umeros o
marcas (las marcas indican posiciones en b@'uffers).

@need 800
@item =
La funci@'on @code{=} chequea si dos argumentos, ambos n@'umeros o
marcadores, son iguales.

@need 1250
@item equal
@itemx eq
Chequea si dos objetos son el mismo. @code{equal} usa un signicado de
la palabra `mismo' y @code{eq} usa otro: @code{equal} devuelve cierto
si los dos objetos tienen una estructura y contenidos similares, tal
como dos copias del mismo libro. En una mano, @code{eq}, devuelve
cierto si ambos argumentos son actualmente el mismo objeto.
@findex equal
@findex eq

@need 1250
@item string<
@itemx string-lessp
@itemx string=
@itemx string-equal
La funci@'on @code{string-lessp} chequea si su primer argumento es
m@'as peque@~no que el segundo. En resumen, el nombre alternativo para
la misma funci@'on (un @code{defalias}) es @code{string}.

Los argumentos para @code{string-lessp} deben ser cadenas o
s@'{@dotless{i}}mbolos; la ordenaci@'on es lexicogr@'afica,
as@'{@dotless{i}} el caso es significativo. Los nombres impresos de
s@'{@dotless{i}}mbolos son usado en vez de s@'{@dotless{i}}mbolos por
s@'{@dotless{i}} mismos.

@cindex @samp{cadena vac@'{@dotless{i}}a} definida
Una cadena vac@'{@dotless{i}}a, @samp{"\"}, es una cadena sin caracteres
dentro, es m@'as peque@~na que cualquier cadena de caracteres.

@code{string-equal} provee el test correpondiente para igualdad. Su
corto nombre alternativo es @code{string=}. No hay funciones test que
correponden a @var{>}, @code{>=}.

@item message
Imprime un mensaje en el @'area echo. El primer argumento es una
cadena que puede contener, @samp{%s}, @samp{%d}, o @samp{%c} para
imprimir el valor de argumentos que siguen la cadena. El argumento
usado por @samp{%d} debe ser un n@'umero. El argumento usado por
@samp{%c} debe ser un n@'umero de c@'odigo @sc{ascii}; eso ser@'a
impreso como el caracter con este c@'odigo @sc{ascii}. (Otras varias
%-secuencias no han sido mencionadas.)

@item setq
@itemx set
La funci@'on @code{setq} asigna el valor de su primer argumento al
valor del segundo argumento. El primer argumento est@'a
autom@'aticamente citado por @code{setq}. Eso hace lo mismo para los
pares de argumentos. Otra funci@'on, @code{set}, toma solo dos
argumentos y eval@'ua ambos de ellos antes de configurar el valor
devuelto por su primer argumento al valor devuelto por su segundo argumento.

@item buffer-name
Sin un argumento, devuelve el nombre del b@'uffer, como una cadena.

@item buffer-file-name
Sin un argumento, devuelve el nombre del fichero si el b@'uffer lo est@'a
visitando.

@item current-buffer
Devuelve el b@'uffer en el que Emacs es activo; eso puede no ser el
b@'uffer que es visible en la pantalla.

@item other-buffer
Devuelve el b@'uffer seleccionado m@'as recientemente (otro que el
b@'uffer pasado a @code{other-buffer} como un argumento y otro en vez
de el b@'uffer actual).

@item switch-to-buffer
Selecciona un b@'uffer para que Emacs est@'e activo y lo muestre
en la ventana actual y as@'{@dotless{i}} los usuarios puedan
mirarlo. Normalmente se empareja a @kbd{C-x b}.

@item set-buffer
Cambia la atenci@'on de Emacs a un b@'uffer en el que los programas se
ejecutar@'an. No altera lo que la ventana est@'a mostrando.

@item buffer-size
Devuelve el n@'umero de caracteres en el b@'uffer actual.

@item punto
Devuelve el valor de la actual posici@'on del cursor, como un entero
contando el n@'umero de caracteres desde el principio del b@'uffer.

@item point-min
Devuelve el valor m@'{@dotless{i}}nimo permisible del punto en el
b@'uffer actual. Esto es 1, a menos que la contracci@'on est@'e en efecto

@item point-max
Devuelve el valor del m@'aximo valor permisible del punto en el
b@'uffer actual. Esto es el fin del b@'uffer, a menos que la
contracci@'on est@'e en efecto
@end table

@need 1500
@node Ejercicios defun
@section Ejercicios

@itemize @bullet
@item
Escribe una funci@'on no interactiva que doble el valor de su
argumento, un n@'umero. Luego haz la funci@'on interactiva.

@item
Escribe una funci@'on que chequee si el valor actual de
@code{fill-column} es m@'as grande que el argumento pasado a la
funci@'on, y si es as@'{@dotless{i}}, imprime un mensaje apropiado.
@end itemize

@node Un paseo a trav@'es de los b@'uffers
@chapter Unas pocas funciones de buffer relacionadas

En este cap@'{@dotless{i}}tulo estudiamos en detalle varias de las
funciones usadas en GNU Emacs. Esto se llama un ``paseo a
trav@'es''. Estas funciones son usadas como ejemplos de c@'odigo Lisp,
pero no son ejemplos imaginarios; con la excepci@'on del primero, la
definici@'on de funci@'on simplificada, esta funciones muestran el
actual c@'odigo usado en GNU Emacs. Se puede aprender mucho desde
estas definiciones. Las funciones descritas aqu@'{@dotless{i}} est@'an
todas relacionadas a b@'uffers. Despu@'es, estudiaremos otras
funciones.

@menu
* Encontrando m@'as::        C@'omo encontrar m@'as informaci@'on.
* simplified-beginning-of-buffer::  Muestra @code{goto-char}, 
                                      @code{point-min}, y @code{push-mark}.
* mark-whole-buffer::        Casi lo mismo que @code{beginning-of-buffer}.
* append-to-buffer::         Usa @code{save-excursion} y 
                               @code{insert-buffer-substring}.
* Revisa lo relacionado con el b@'uffer::  Revisa
* Ejercicios de b@'uffer::   Ejercicios de b@'uffer
@end menu

@node Encontrando m@'as
@section Encontrando m@'as informaci@'on

@findex describe-function, @r{introducido}
@cindex Encontrar documentaci@'on de la funci@'on
En este paseo, se describe cada nueva funci@'on como viene, algunas
veces en detalle y algunas veces brevemente. Si est@'a interesado, se
puede obtener la documentaci@'on completa de cualquier funci@'on Emacs
Lisp en cualquier momento escribiendo @kbd{C-h f} y entonces el
nombre de la funci@'on (y entonces @key{RET}. De manera similar, se
puede obtener la documentaci@'on completa para una variable
escribiendo @kbd{C-h v}, despu@'es el nombre de la variable (y
entonces @key{RET}).

@cindex Encontrar la fuente de la funci@'on
@c In version 22, tells location both of C and of Emacs Lisp
Tambi@'en, en @code{describe-function}, se encontrar@'a la localizaci@'on
de la definici@'on de la funci@'on.

Poner el punto dentro del nombre del fichero que contiene la funci@'on
y presiona la tecla @key{RET}. En este caso, @key{RET} significa
@code{push-button} en vez de `return' o `enter'. Emacs tomar@'a
directamente a la definici@'on de la funci@'on.

@ignore
Not In version 22

If you move point over the file name and press
the @key{RET} key, which in this case means @code{help-follow} rather
than `return' or `enter', Emacs will take you directly to the function
definition.
@end ignore

De manera m@'as general, si quieres ver una funci@'on en su fichero
fuente original, se puede usar la funci@'on @code{find-tag} para
saltar dentro. @code{find-tag} funciona con una amplia variedad de
lenguajes, no solo Lisp, y C, y funciona con texto de no
programaci@'on tambi@'en. Por ejemplo, @code{find-tag} saltar@'a a los
varios nodos en el fichero fuente Texinfo de este documento. La
funci@'on @code{find-tag} depende de `tablas de etiquetas' que graba
las localizaciones de las funciones, variables, y otros
@'{@dotless{i}}tems para los que @code{find-tag} salta.

Para usar el comando @code{find-tag}, escribe @kbd{M-.} (por ej.,
presionando la tecla @key{META}, o al menos escribe la tecla @key{ESC}
y entonces escribe la tecla punto), entonces, en la pantalla, se
escribe el nombre de la funci@'on cuyo c@'odigo fuente se quiere ver,
tal como @code{mark-whole-buffer}, y luego escribe @key{RET}. Emacs
cambiar@'a el b@'uffer y mostrar@'a el c@'odigo fuente para la
funci@'on en la pantalla. Para volver al b@'uffer actual, escribe
@kbd{C-x b @key{RET}}. (En algunos teclados, la tecla @key{META} es
etiquetada con @key{ALT}.)

@c !!! 22.1.1 tags table location in this paragraph
@cindex tabla TAGS, especificando
@findex find-tag
Dependiendo de c@'omo los valores iniciales por defecto de tu copia de
Emacs son asignados se puede tambi@'en necesitar especificar la
posici@'on de tu `tabla de tags', que es un fichero llamado
@file{TAGS}. Por ejemplo, si se est@'a interesado en fuentes de Emacs,
la tabla de tags que se desea, si ya ha sido creada para
t@'{@dotless{i}}, estar@'a en un subdirectorio del directorio
@file{/usr/local/share/emacs}; de este modo se usar@'{@dotless{i}}a el
comando @code{M-x visit-tags-table} y especifica una ruta tal como
@file{/usr/local/share/emacs/22.1.1/lisp/TAGS}. Si la tabla tags no ha
sido creada, tendr@'as que crearla por t@'{@dotless{i}} mismo. Ser@'a
un fichero tal como @file{/usr/local/src/emacs/src/TAGS}.

@need 1250
Para crear un fichero @file{TAGS} en un directorio
espec@'{@dotless{i}}fico, cambia a este directorio en Emacs usando
un comando @kbd{M-x cd}, o lista el directorio como @w{@code{etags
*.el}} como el comando para ejecutar:

@smallexample
M-x compile RET etags *.el RET
@end smallexample

Para m@'as informaci@'on, ver @ref{etags, , Crea tu propio fichero
@file{TAGS}}.

Despu@'es de llegar a estar m@'as familiarizado con Emacs Lisp,
se encontrar@'a frecuentemente usar @code{find-tag} para navegar tu
camino alrededor del c@'odigo fuente; y se crear@'an tus propias tablas
@file{TAGS}.

@cindex Librer@'{@dotless{i}}a, como t@'ermino para `fichero'
Incidentalmente, los ficheros que contienen c@'odigo Lisp son
convencionalmente llamadas @dfn{librer@'{@dotless{i}}as}. La
met@'afora se deriva que una librer@'{@dotless{i}}a, tal como
la librer@'{@dotless{i}}a de leyes o una librer@'{@dotless{i}}a de
ingenier@'{@dotless{i}}a, en vez de una librer@'{@dotless{i}}a
general. Cada librer@'{@dotless{i}}a, o fichero, contiene funciones
que se relacionan a un asunto particular o actividad, tal como
@file{abbrev.el} para manejar abreviaciones y otros atajos, y
@file{help.el} para la ayuda on-line. (Algunas veces varias
librer@'{@dotless{i}}as proporcionan c@'odigo para una actividad
simple, como varios @file{rmail@dots{}} ficheros proveen c@'odigo para
leer correos electr@'onicos.) En @cite{El Manual de GNU Emacs}, tu
ver@'as varias frases tales como ``El comando @kbd{C-h p} te permite
buscar el est@'andar de las librer@'{@dotless{i}}as Emacs Lisp por las
palabras claves.

@node simplified-beginning-of-buffer
@section Una definici@'on simplificada de @code{beginning-of-buffer}
@findex simplified-beginning-of-buffer

El comando @code{beginning-of-buffer} es una buena funci@'on para
empezar ya puedes tener cierta familiaridad con eso y es f@'acil de
comprender. Usado como un comando interactivo,
@code{beginning-of-buffer} mueve el cursor al principio del b@'uffer,
dejando la marca en la posici@'on previa. Eso es generalmente
asignados a @kbd{M-<}.

En esta secci@'on, se discutir@'a una versi@'on ordenada de la
funci@'on que muestra como eso es lo usado m@'as frecuentemente. Esta
funci@'on ordenada trabaja como se escribe, pero no contiene el
c@'odigo para una funci@'on compleja. En otra secci@'on, describiremos
la funci@'on entera. (@xref{beginning-of-buffer, Definici@'on Completa
de @code{beginnning-of-buffer}}.)

Antes de mirar en el c@'odigo, perm@'{@dotless{i}}tenos considerar que
la definici@'on de funci@'on tiene que contener: eso debe incluir una
expresi@'on que crea la funci@'on interactiva as@'{@dotless{i}} puede
ser llamado escribiendo @kbd{M-x beginning-of-buffer} o escribiendo
unos atajos tales como @kbd{M-<}; debe incluir c@'odigo para dejar una
marca en la posici@'on original en el b@'uffer; y debe incluir
c@'odigo el cursor al principio del b@'uffer.

@need 1250
Aqu@'{@dotless{i}} est@'a el texto completo la versi@'on ordenada de
la funci@'on:

@smallexample
@group
(defun simplified-beginning-of-buffer ()
  "Mover punto al principio del bufer; dejar marca en la posici@'on previa."
  (interactive)
  (push-mark)
  (goto-char (point-min)))
@end group
@end smallexample

Como todas las definiciones de funci@'on, esta definici@'on tiene
cinco partes siguiendo la forma especial @code{defun}:

@enumerate
@item
El nombre: en este ejemplo, @code{simplified-beginning-of-buffer}.

@item
Una lista de los argumentos: en este ejemplo, una lista
vac@'{@dotless{i}}a, @code{()},

@item
La cadena de documentaci@'on.

@item
La expresi@'on interactive.

@item
El cuerpo.
@end enumerate

@noindent
En esta definici@'on de funci@'on, la lista de argumentos est@'a
vac@'{@dotless{i}}a; esto significa que esta funci@'on no requiere
argumentos. (Cuando se busca la definici@'on para la funci@'on
completa, se ver@'a que puede pasarse un argumento opcional.)

La expresi@'on interactiva cuenta a Emacs que la funci@'on se pretende
ser usada interactivamente. En este ejemplo, @code{interactive} no
tiene un argumento porque @code{simplified-beginning-of-buffer} no se
requiere.

@need 800
El cuerpo de la funci@'on consiste de dos l@'{@dotless{i}}neas:

@smallexample
@group
(push-mark)
(goto-char (point-min))
@end group
@end smallexample

La primera de estas l@'{@dotless{i}}neas es la expresi@'on,
@code{(push-mark)}. Cuando esta expresi@'on es evaluado por el
int@'erprete Lisp, eso asigna una marca en la posici@'on actual del
cursor, siempre y cuando esto pueda ser. La posici@'on de esta marca
est@'a guardada en el anillo de marcas.

La siguiente l@'{@dotless{i}}nea es @code{(goto-char
(point-min))}. Esta expresi@'on salta el cursor al punto
m@'{@dotless{i}}nimo en el b@'uffer, esto es, para el comienzo del
b@'uffer (o al principio de la porci@'on accesible del b@'uffer si eso
est@'a encogido. @xref{Encogiendo y extendiendo, , Encogiendo y
extendiendo}.)

El comando @code{push-mark} estable una marca en el lugar donde el
cursor fu@'e localizado antes que fuera movido al principio del
b@'uffer por la expresi@'on @code{(goto-char
(point-min))}. Consiguientemente, puedes, si lo deseas, volver donde
estabas originalmente escribiendo @kbd{C-x C-x}.

@exclamdown{}Esto es todo lo que hay para la definici@'on de funci@'on!

@findex describe-function
Cuando se lee c@'odigo como este y vuelve a una funci@'on no familiar,
tal como @code{goto-char}, se puede encontrar que se hace usando el
comando @code{describe-function}. Para usar este comando, escribe
@kbd{C-h f} y entonces escribe en el nombre de la funci@'on y presiona
@key{RET}. El comando @code{describe-function} imprimir@'a la
documentaci@'n de la cadena de la  funci@'on en una ventana
@file{*Help*}. Por ejemplo, la documentaci@'on para @code{goto-char} es:

@smallexample
@group
Asignar punto a POSITION, un n@'umero o marca
Empezando el buffer es la posici@'on (point-min), y el final es
(point-max).
@end group
@end smallexample

@noindent
La funci@'on es un argumento es la posici@'on deseada.

@noindent
(La consola para @code{describe-function} te ofrecer@'a el
s@'{@dotless{i}}mbolo abajo o precediendo al cursor, as@'{@dotless{i}}
se puede guardar escribiendo al posicionar el cursor a la derecha o
despu@'es de la funci@'on y entonces escribir @kbd{C-h f @key{RET}}.)

La definici@'on de funci@'on @code{end-of-buffer} est@'a escrito en el
mismo modo que la definici@'on @code{beginnig-of-buffer} excepto que
el cuerpo de la funci@'on contenga la expresi@'on @code{(goto-char
(point-max))} en lugar de @code{(goto-char (point-min))}

@node mark-whole-buffer
@section La definici@'on de @code{mark-whole-buffer}
@findex mark-whole-buffer

La funci@'on @code{mark-whole-buffer} no es tan dif@'{@dotless{i}}cil de
comprender que la funci@'on @code{simplified-beginning-of-buffer}. En
este caso, sin embargo, se ver@'a la funci@'on completa, no una
versi@'on ordenada.

La funci@'on @code{mark-whole-buffer} no est@'a com@'unmente usada
como la funci@'on @code{beginning-of-buffer}, pero eso no es @'util:
eso marca un b@'uffer completo como una regi@'on poniendo el punto al
principio y una marca al fin del b@'uffer. Eso est@'a generalmente
asociado a @kbd{C-x h}.

@menu
* resumen de mark-whole-buffer::  resumen de mark-whole-buffer
* Cuerpo de mark-whole-buffer::  Solo tres l@'{@dotless{i}}neas de c@'odigo.
@end menu

@ifnottex
@node resumen de mark-whole-buffer
@unnumberedsubsec Un resumen de @code{mark-whole-buffer}
@end ifnottex

@need 1250
En GNU Emacs 22, el c@'odigo para la funci@'on completa se parece a:

@smallexample
@group
(defun mark-whole-buffer ()
  "Pon el punto al principio y marca el fin del b@'uffer. 
Probablemante no deber@'{@dotless{i}}as usar esta funci@'on en
  programas Lisp; normalmente un error para una funci@'on Lisp usa
  cualquier subrrutina que usa o asigna la marca."
  (interactive)
  (push-mark (point))
  (push-mark (point-max) nil t)
  (goto-char (point-min)))
@end group
@end smallexample

@need 1250
Como todas las otras funciones, la funci@'on @code{mark-whole-buffer}
se ajusta dentro de la plantilla para una definici@'on. La plantilla
se parece a esta:

@smallexample
@group
(defun @var{name-of-function} (@var{argument-list})
  "@var{documentation}@dots{}"
  (@var{interactive-expression}@dots{})
  @var{body}@dots{})
@end group
@end smallexample

Aqu@'{@dotless{i}} est@'a c@'omo la funci@'on trabaja: el nombre de la
funci@'on es @code{mark-whole-buffer}; eso es seguida por un argumento
de lista vac@'{@dotless{i}}a, @samp{()}, que significa que la
funci@'on no requiere argumentos. La documentaci@'on viene la siguiente.

La siguiente l@'{@dotless{i}}nea es una expresi@'on
@code{(interactive)} que cuenta a Emacs que la funci@'on ser@'a usada
interactivamente. Estos detalles son similares a la funci@'on
@code{simplified-beginning-of-buffer} descrita en la secci@'on previa

@need 1250
@node Cuerpo de mark-whole-buffer
@subsection Cuerpo de @code{mark-whole-buffer}

El cuerpo de la funci@'on @code{mark-whole-buffer} consiste en tres
l@'{@dotless{i}}neas de c@'odigo:

@c GNU Emacs 22
@smallexample
@group
(push-mark (point))
(push-mark (point-max) nil t)
(goto-char (point-min))
@end group
@end smallexample

El primero de estas l@'{@dotless{i}}neas es la expresi@'on,
@code{(push-mark (point))}.

Esta l@'{@dotless{i}}nea hace exactamente el mismo trabajo que la
primera l@'{@dotless{i}}nea del cuerpo de la funci@'on
@code{simplified-beginning-of-buffer}, que est@'a escrita
@code{(push-mark)}. En ambos casos, el int@'erprete Lisp asigna una
marca en la posici@'on actual del cursor.

No s@'e por qu@'e en la expresi@'on @code{mark-whole-buffer} est@'a
escrito @code{(push-mark (point))} y en la expresi@'on
@code{beginning-of-buffer} est@'a escrito @code{(push-mark)}. Quiz@'as
quien escribi@'o el c@'odigo no sab@'{@dotless{i}}a que los argumentos
para @code{push-mark} son opcionales y que si @code{push-mark} no se
pasa como argumento, la funci@'on autom@'aticamente asigna la marca en
la localizaci@'on del punto por defecto. O quiz@'as la expresi@'on
fu@'e escrita as@'{@dotless{i}} como para parelizar la estructura de
la siguiente l@'{@dotless{i}}nea. En cualquier caso, la
l@'{@dotless{i}}nea causa que Emacs determine la posici@'on del
punto y asigne una marca all@'{@dotless{i}}.

En las primeras versiones de GNU Emacs, la siguiente
l@'{@dotless{i}}nea de @code{mark-whole-buffer} fu@'e @code{(push-mark
(point-max))}. Esta expresi@'on asigna una marca en el punto en el
b@'uffer que tiene el n@'umero m@'as alto. Esto ser@'a el fin del
b@'uffer (o, si el b@'uffer es encogida, el fin de la porci@'on
accesible del b@'uffer. @xref{Encogiendo y extendiendo, , Encogiendo y
extendiendo}, para m@'as acerca de encoger). Despu@'es esta marca ha sido
asignada, la marca previa, uno asigna un punto, pero no se asigna largo,
pero Emacs recuerda su posici@'on, solo como todas las otras marcas
recientes son siempre recordadas. Esto significa que se puede, si lo
deseas, vuelve a esta posici@'on escribiendo @kbd{C-u C-@key{SPC}} dos
veces.

@need 1250
En GNU Emacs 22, el @code{(point-max)} es ligeramente m@'as
complicado. La l@'{@dotless{i}}nea lee

@smallexample
(push-mark (point-max) nil t)
@end smallexample

@noindent
La expresi@'on funciona cerca de lo mismo que antes. Eso asigna una marca
en el lugar numerado m@'as alto que se puede en el b@'uffer. Sin
embargo, en esta versi@'on, @code{push-mark} tiene dos argumentos
adicionales. El segundo argumento para @code{push-mark} es
@code{nil}. Esto cuenta la funci@'on que
@emph{mostrar@'{@dotless{i}}a} un mensaje que dice `Marca asignada'
cuando eso empuja la marca. El tercer argumento es @code{t}. Esto
cuenta @code{push-mark} para activar la marca cuando el modo Transient
Mark est@'a activado. Transient Mark mode ilumina la regi@'on de marca
activa. Con frecuencia desactivada

Finalmente, la @'ultima l@'{@dotless{i}}nea de la funci@'on es
@code{(goto-char (point-min))}. Esto es escrito exactamente el mismo
camino camino como est@'a escrito @code{beginning-of-buffer}. La
expresi@'on mueve el cursor al m@'{@dotless{i}}nimo punto en el
b@'uffer, que es, al principio del b@'ufferr (o para el principio de
la porci@'on accesible del b@'uffer). Como un resultado de esto, punto
est@'a emplazado al principio del b@'uffer y la marca est@'a asignada al
fin del b@'uffer. El b@'uffer completo es, m@'as all@'a, la regi@'on.

@node append-to-buffer
@section La definici@'on de @code{append-to-buffer}
@findex append-to-buffer

El comando @code{append-to-buffer} es m@'as complejo que el comando
@code{mark-whole-buffer}. Lo que hace es copiar la regi@'on (que es,
la parte del b@'uffer entre punto y marca) desde el buffer actual a un
b@'uffer espec@'{@dotless{i}}fico.

@menu
* resumen de append-to-buffer::  resumen de append-to-buffer
* append interactivo::       Una expresi@'on interactiva de dos partes.
* cuerpo append-to-buffer::  Incorpora una expresi@'on @code{let}.
* append save-excursion::    C@'omo @code{save-excursion} trabaja.
@end menu

@ifnottex
@node resumen de append-to-buffer
@unnumberedsubsec Un resumen de @code{append-to-buffer}
@end ifnottex

@findex insert-buffer-substring
El comando @code{append-to-buffer} usa la funci@'on
@code{insert-buffer-substring} para copiar la
regi@'on. @code{insert-buffer-substring} es descrita por su nombre:
eso toma una cadena de caracteres desde parte de un b@'uffer, una
``subcadena'', y las inserta dentro de otro b@'uffer.

La mayor@'{@dotless{i}}a de @code{append-to-buffer} se refiere con la
configuraci@'on de las condiciones para @code{insert-buffer-substring}
para trabajar: el c@'odigo debe especificar ambos el b@'uffer para el
que el texto ir@'a, la ventana viene y va, y la regi@'on que ser@'a copiada.

@need 1250
Aqu@'{@dotless{i}} est@'a el texto completo de la funci@'on:

@smallexample
@group
(defun append-to-buffer (buffer start end)
  "Introduce al b@'uffer espec@'{@dotless{i}}fico el texto de la
  regi@'on. Esto es insertado de este b@'uffer antes de su punto.
@end group

@group
Cuando se llama desde un programa, se dan tres argumentos:
BUFFER (o nombre del b@'uffer), START y END.
START y END especifica la porci@'on del b@'uffer actual para ser copiado."
  (interactive
   (list (read-buffer "Append to buffer: " (other-buffer
                                            (current-buffer) t))
         (region-beginning) (region-end)))
@end group
@group
  (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))))))))
@end group
@end smallexample

La funci@'on puede ser comprendida buscando como series de plantillas
rellenas

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

@smallexample
@group
(defun append-to-buffer (buffer start end)
  "@var{documentacion}@dots{}"
  (interactive @dots{})
  @var{cuerpo}@dots{})
@end group
@end smallexample

La primera l@'{@dotless{i}}nea de la funci@'on incluye su nombre y los
tres argumentos. Los argumentos son el @code{b@'uffer} que el texto
ser@'a copiado, y el @code{start} y @code{end} de la regi@'on en el
buffer actual que ser@'a copiado.

La siguiente parte de la funci@'on es la documentaci@'on, que es claro
y completo. Como es convencional, los tres argumentos son escritos en
may@'usculas as@'{@dotless{i}} se notificar@'an f@'acilmente. Incluso
mejor, son descritas en el mismo orden como en la lista de argumentos.

N@'otese que la documentaci@'on distingue entre un b@'uffer y su
nombre. (La funci@'on puede manejar otro.)

@node append interactivo
@subsection La expresi@'on interactiva @code{append-to-buffer}

Desde que la funci@'on @code{append-to-buffer} ser@'a usada
interactivamente, la funci@'on debe tener una expresi@'on
@code{interactive}. (Para una revisi@'on de @code{interactive}, ver
@ref{Interactive, , Creando una Funci@'on Interactive}.) La
expresi@'on se lee de la siguiente manera:

@smallexample
@group
(interactive
 (list (read-buffer
        "Agrega al buffer: "
        (other-buffer (current-buffer) t))
       (region-beginning)
       (region-end)))
@end group
@end smallexample

@noindent
Esta expresi@'on 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@'on para leer el nombre de
un b@'uffer y lo devuelve como una cadena. Esto es
@code{read-buffer}. La funci@'on requiere una consola como su primer
argumento, @samp{"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@'on conteniendo la
funci@'on @code{other-buffer}, una excepci@'on, y una @samp{t}, para verdad.

El primer argumento para @code{other-buffer}, la excepci@'on, es
todav@'{@dotless{i}}a otra funci@'on, @code{other-buffer}. Esto es no
yendo a ser devuelto. El segundo argumento es el s@'{@dotless{i}}mbolo
para verdad, @code{t}. Esto cuenta @code{other-buffer} que puede
mostrar b@'uffers visibles (excepto en este caso, eso no mostrar@'a el
b@'uffer actual, que tiene sentido).

@need 1250
La expresi@'on se ve como:

@smallexample
(other-buffer (current-buffer) t)
@end smallexample

El segundo y tercer argumento de la expresi@'on @code{list} son
@code{(region-beginning)} y @code{(region-end)}. Estas dos funciones
especifican el principio el y el final del texto que se adjunta.

@need 1250
Originalmente, el comando usaba las letras @samp{B} y @samp{r}. La
expresi@'on completa @code{interactive} es as@'{@dotless{i}}:

@smallexample
(interactive "BAsociar al buffer:@: \nr")
@end smallexample

@noindent
Pero cuando esto fu@'e hecho, el valor por defecto del b@'uffer cambi@'o
a ser invisible. Esto no se quer@'{@dotless{i}}a.

(La consola estaba separada del segundo argumento con una nueva
l@'{@dotless{i}}nea, @samp{\n}. Estaba seguido por un @samp{r} que
contaba a Emacs emparejar los dos argumentos que siguen el
s@'{@dotless{i}}mbolo @code{buffer} en la lista de argumentos de la
funci@'on (que es, @code{start} y @code{end}) para los valores de
punto y marca. Este argumento trabaj@'o bien.)

@node cuerpo append-to-buffer
@subsection El cuerpo de @code{append-to-buffer}

@ignore
in GNU Emacs 22   in    /usr/local/src/emacs/lisp/simple.el

(defun append-to-buffer (buffer start end)
  "Append to specified buffer the text of the region.
It is inserted into that buffer before its point.

When calling from a program, give three arguments:
BUFFER (or buffer name), START and END.
START and END specify the portion of the current buffer to be copied."
  (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))))))))
@end ignore

El cuerpo de la funci@'on @code{append-to-buffer} empieza con @code{let}.

Como se ha visto antes (@pxref{let, , @code{let}}), el prop@'osito de
una expresi@'on @code{let} es crear y dar valores iniciales a una o
m@'as variable que solo ser@'an usada con el cuerpo del
@code{let}. Esto significa que tal variable no ser@'a confuso con
cualquier variable del mismo nombre fuera de la expresi@'on @code{let}.

Podemos ver como la expresi@'on @code{let} se ajusta dentro de la
funci@'on como un todo mostrando una plantilla para
@code{append-to-buffer} con la expresi@'on @code{let} en
l@'{@dotless{i}}nea:

@smallexample
@group
(defun append-to-buffer (buffer start end)
  "@var{documentacion}@dots{}"
  (interactive @dots{})
  (let ((@var{variable} @var{valor}))
        @var{cuerpo}@dots{})
@end group
@end smallexample

La expresi@'on @code{let} tiene tres elementos:

@enumerate
@item
El s@'{@dotless{i}}mbolo @code{let};

@item
Una varlist conteniendo, en este caso, una lista simple de dos
elementos, @code{(@var{variable} @var{value})};

@item
El cuerpo de la expresi@'on @code{let}.
@end enumerate

@need 800
En la funci@'on @code{append-to-buffer}, la varlist se parece a esto:

@smallexample
(oldbuf (current-buffer))
@end smallexample

@noindent
En esta parte de la expresi@'on @code{let}, una variable,
@code{oldbuf} es emparejada al valor devuelto por la expresi@'on
@code{(current-buffer)}. La variable, @code{oldbuf}, es usada para
guardar la traza del b@'uffer en el que tu est@'as trabajando y desde
el que se copiar@'a.

El elemento o elementos de una varlist son rodeados por un conjunto de
par@'entesis as@'{@dotless{i}} el int@'erprete Lisp puede distinguir
la varlist desde el cuerpo del @code{let}. Como consecuencia, la lista
de dos elementos con la varlist est@'a rodeados por un circunscrito
conjunto de par@'entesis. Las l@'{@dotless{i}}neas se ven
as@'{@dotless{i}}:

@smallexample
@group
(let ((oldbuf (current-buffer)))
  @dots{} )
@end group
@end smallexample

@noindent
Los dos par@'entesis antes de @code{oldbuf} podr@'{@dotless{i}}an
sorprenderte si no fuera porque los primeros par@'entesis antes de
@code{oldbuf} marcan el l@'{@dotless{i}}mite de la varlist y el segundo
par@'entesis marca el principio de la lista de dos elementos,
@code{(oldbuf (current-buffer))}.

@node append save-excursion
@subsection @code{save-excursion} en @code{append-to-buffer}

El cuerpo de la expresi@'on @code{let} en @code{append-to-buffer}
consiste de una expresi@'on @code{save-excursion}.

La funci@'on @code{save-excursion} guarda las localizaciones de punto y
la marca, y las restaura a estas posiciones despu@'es de las expresiones
en el cuerpo de la ejecuci@'on completa
@code{save-excursion}. Adem@'as, @code{save-excursion} completa
la ejecuci@'on. Adem@'as, @code{save-excursion} guarda la traza del
b@'uffer original, y lo restaura. Esto es c@'omo @code{save-excursion}
que se usa en @code{append-to-buffer}.

@need 1500
@cindex Indentaci@'n para formatear
@cindex Convenci@'on formateando
Incidentalmente, no se valora nada aqu@'{@dotless{i}} que una
funci@'on Lisp es normalmente formateada as@'{@dotless{i}} que cada
cosa que es encerrada en conjunto multil@'{@dotless{i}}nea que es
indentada m@'as a la derecha que el primer s@'{@dotless{i}}mbolo. En
esta definici@'on de funci@'on, el @code{let} es indentado m@'as que
@code{defun}, y el @code{save-excursion} es indentado m@'as que el
@code{let}, como esto:

@smallexample
@group
(defun @dots{}
  @dots{}
  @dots{}
  (let@dots{}
    (save-excursion
      @dots{}
@end group
@end smallexample

@need 1500
@noindent
Esta convenci@'on formatea que sea f@'acil de ver que las
l@'{@dotless{i}}neas en el cuerpo de @code{save-excursion}, solo
como @code{save-excurion} por s@'{@dotless{i}} mismo est@'an
encerradas por los par@'entesis asociados con el @code{let}:

@smallexample
@group
(let ((oldbuf (current-buffer)))
  (save-excursion
    @dots{}
    (set-buffer @dots{})
    (insert-buffer-substring oldbuf start end)
    @dots{}))
@end group
@end smallexample

@need 1200
El uso de la funci@'on @code{save-excursion} puede ser vista como un
proceso de rellenar slots de una plantilla:

@smallexample
@group
(save-excursion
  @var{primera-expresion-en-cuerpo}
  @var{segunda-expresion-en-cuerpo}
   @dots{}
  @var{ultima-expresion-en-cuerpo})
@end group
@end smallexample

@need 1200
@noindent
En esta funci@'on, el cuerpo de @code{save-excursion} contiene solo
una expresi@'on, la expresi@'on @code{let*}. Se conoce una funci@'on
@code{let}. La funci@'on @code{let*} es diferente. Eso tiene un
@samp{*} en su nombre. Eso permite a Emacs asignar cada variable de su
varlist en secuencia, una despu@'es de otra.

Su funcionalidad cr@'{@dotless{i}}tica es que las variable despu@'es
en la varlist puedan hacer uso de los valores para los que Emacs asigna
variables pronto en la varlist. @xref{fwd-para let, La expresi@'on
@code{let*}}.

Se obviar@'an funciones como @code{let*} y se focalizar@'a en dos: la
funci@'on @code{set-buffer} y la funci@'on
@code{insert-buffer-substring}.

@need 1250
En anta@~no, la expresi@'on @code{set-buffer} era simple:

@smallexample
(set-buffer (get-buffer-create buffer))
@end smallexample

@need 1250
@noindent
pero ahora eso es

@smallexample
(set-buffer append-to)
@end smallexample

@noindent
@code{append-to} se asigna a @code{(get-buffer-create-buffer)} pronto
en la expresi@'on @code{let*}. Esta asociaci@'on extra no
ser@'{@dotless{i}}a necesaria excepto para este @code{append-to} es
usado despu@'es en la varlist como un argumento para
@code{get-buffer-window-list}.

@ignore
in GNU Emacs 22

  (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))))))))
@end ignore

La definici@'on de la funci@'on @code{append-to-buffer} inserta texto
desde el b@'uffer en el que est@'as actualmente a un buffer
nombrado. Eso sucede que @code{insert-buffer-substring} copia texto
desde otro b@'uffer al b@'uffer actual, solo el inverso --- que es
porque la definici@'on @code{append-to-buffer} empieza con un
@code{let} que asocia el s@'{@dotless{i}}mbolo local @code{oldbuf} al
valor devuelto por @code{current-buffer}.

@need 1250
La expresi@'on @code{insert-buffer-substring} se ve como esto:

@smallexample
(insert-buffer-substring oldbuf start end)
@end smallexample

@noindent
La funci@'on @code{insert-buffer-substring} copia una cadena
@emph{from} al b@'uffer especificado como su primer argumento e
inserta la cadena dentro del b@'uffer presente. En este caso, el
argumento para @code{insert-buffer-substring} es el valor de la
variable creada y asociada por el @code{let}, llama al valor de
@code{oldbuf}, que fu@'e el b@'uffer actual cuando tu diste el comando
@code{append-to-buffer}.

Despu@'es de que @code{insert-buffer-substring} ha hecho su trabajo,
@code{save-excursion} restaurar@'a la acci@'on al b@'uffer original y
@code{append-to-buffer} habr@'a hecho su trabajo.

@need 800
Escrito en forma esquel@'etica, los trabajos del cuerpo se ven como esto:

@smallexample
@group
(let (@var{bind-}@code{oldbuf}@var{-to-value-of-}@code{current-buffer})
  (save-excursion                       ; @r{Guarda la traza del b@'uffer.}
    @var{change-buffer}
    @var{insert-substring-from-}@code{oldbuf}@var{-into-buffer})

  @var{change-back-to-original-buffer-when-finished}
@var{let-the-local-meaning-of-}@code{oldbuf}@var{-disappear-when-finished}
@end group
@end smallexample

En resumen, @code{append-to-buffer} funciona como sigue: se guarda el
valor del b@'uffer actual en la variable llamada @code{oldbuf}. Se obtiene
el nuevo b@'uffer (creando uno si necesita ser) y cambia la atenci@'on
de Emacs a eso. Usando el valor de @code{oldbuf}, inserta la regi@'on
del texto desde el viejo b@'uffer dentro del nuevo b@'uffer; y entonces
usando @code{save-excursion}, trae atr@'as a tu b@'uffer original.

Buscando @code{append-to-buffer}, se ha explorado una funci@'on limpia
compleja. Eso muestra como usar @code{let} y @code{save-excursion}, y
como cambiar y volver desde otro buffer. Muchas definiciones de
funci@'on usan @code{let}, @code{save-excursion}, y @code{set-buffer}
de este modo.

@node Revisa lo relacionado con el b@'uffer
@section Revisar

Aqu@'{@dotless{i}} est@'a un breve resumen de varias funciones
discutidas en este cap@'{@dotless{i}}tulo.

@table @code
@item describe-function
@itemx describe-variable
Imprime la documentaci@'on para una funci@'on o
variable. Convencionalmente asociada a @kbd{C-h f} y @kbd{C-h v}.

@item find-tag
Encuentra el fichero que contiene la fuente para una funci@'on o
variable y cambia buffer a @'el, posicionando el punto al principio
del @'{@dotless{i}}tem. Convencionalmente emparejado a @kbd{M-.} (esto
es un per@'{@dotless{i}}odo seguiendo la tecla @key{META}).

@item save-excursion
Guarda la localizaci@'on de punto y marca y restaura sus valores
despu@'es de los argumentos para @code{save-excursion} y han sido
evaluados. Tambi@'en, recuerda el buffer actual y devu@'elvelo.

@item push-mark
Asigna la marca en una localizaci@'on y graba el valor de la marca
previa en el anillo de la marca. La marca es una localizaci@'on en el
b@'uffer que guarda su posici@'on relativa incluso si el texto es
a@~nadido o borrado desde el b@'uffer.

@item goto-char
Asigna punto a la localizaci@'on especificada por el valor del
argumento, que puede ser un n@'umero, una marca, o una expresi@'on que
devuelve el n@'umero de una posici@'on, tal como @code{(point-min)}.

@item insert-buffer-substring
Copia una regi@'on de texto desde un b@'uffer que es pasado a la
funci@'on como un argumento e inserta la regi@'on dentro del b@'uffer
actual.

@item mark-whole-buffer
Marca el b@'uffer completo como una regi@'on. Normalmente asignado a
@kbd{C-x h}.

@item set-buffer
Cambia la atenci@'on de Emacs a otro b@'uffer, pero no cambies la
ventana siendo mostrada. Usado cuando el programa en vez de un humano
trabaja en un b@'uffer diferente.

@item get-buffer-create
@itemx get-buffer
Encuentra un b@'uffer nombrado o crea uno si un b@'uffer de este
nombre no existe. La funci@'on @code{get-buffer} devuelve @code{nil}
si el nombre del b@'uffer no existe.
@end table

@need 1500
@node Ejercicios de b@'uffer
@section Ejercicios

@itemize @bullet
@item
Escribe tu propia definici@'on de funci@'on
@code{simplified-end-of-buffer}; entonces testea para ver si funciona.

@item
Usa @code{if} y @code{get-buffer} para escribir una funci@'on que
imprime un mensaje contando si un buffer existe.

@item
Usando @code{find-tag}, encuentra la fuente para la funci@'on
@code{copy-to-buffer}
@end itemize

@node M@'as complejidad
@chapter Unas pocas funciones m@'as complejas

En este cap@'{@dotless{i}}tulo, se construye lo que se aprendi@'o en
los cap@'{@dotless{i}}tulos previos mirando en funciones m@'as
complejas. La funci@'on @code{copy-to-buffer} ilustra el uso de
expresiones @code{save-excursion} en una definici@'on, mientras la
funci@'on @code{insert-buffer} ilustra el uso de un asterisco en una
expresi@'on @code{interactive}, uso de @code{o}, y la importante
distinci@'on entre un nombre y el objeto para el que el nombre se
refiere.

@menu
* copy-to-buffer::           Con @code{set-buffer}, 
                               @code{get-buffer-create}.
* insert-buffer::            Solo lectura, y con @code{or}.
* beginning-of-buffer::      Muestra @code{goto-char}, @code{point-min}, y 
                               @code{push-mark}.
* Revisar el segundo b@'uffer relacionado::  Revisar el segundo b@'uffer 
                                               relacionado
* Ejercicio opcional::       Ejercicio opcional
@end menu

@node copy-to-buffer
@section La definici@'on de @code{copy-to-buffer}
@findex copy-to-buffer

Despu@'es de comprender c@'omo se trabaja @code{append-to-buffer}, es
f@'acil para comprender @code{copy-to-buffer}. Esta funci@'on copia
texto dentro de un b@'uffer, pero en vez de a@~nadir al segundo
b@'uffer, se reemplaza a todo el texto previo en el segundo b@'uffer.

@need 800
El cuerpo de @code{copy-to-buffer} se ve como esto,

@smallexample
@group
@dots{}
(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)))))
@end group
@end smallexample

La funci@'on @code{copy-to-buffer} tiene una expresi@'on simple
@code{interactive} en vez de @code{append-to-buffer}.

@need 800
La definici@'on entonces dice:

@smallexample
(with-current-buffer (get-buffer-create buffer) @dots{}
@end smallexample

Primero, mira en la expresi@'on interna m@'as temprana; que es
evaluada primero. Esta expresi@'on empieza con @code{get-buffer-create
buffer}. La funci@'on cuenta al ordenador para usar el b@'uffer con el
nombre espec@'{@dotless{i}}ficado como uno para el que est@'as
copiando, o si tal b@'uffer no existe, cr@'ealo. Entonces, la funci@'on
@code{with-current-buffer} eval@'ua su cuerpo con este b@'uffer
temporalmente al actual.

(Esto demuestra otro camino para cambiar la atenci@'on del ordenador
pero no los usuarios. La funci@'on @code{append-to-buffer} muestra
como hacer lo mismo con @code{save-excursion} y
@code{set-buffer}. @code{with-current-buffer} es uno nuevo, y
argumentablemente f@'acil, mecanismo.)

La funci@'on @code{barf-if-buffer-read-only} env@'{@dotless{i}}a un
mensaje de error diciendo al b@'uffer es de solo lectura si no se
puede modificar.

La siguiente l@'{@dotless{i}}nea tiene la funci@'on
@code{erase-buffer} como sus @'unicos contenidos. Este funci@'on borra
el b@'uffer.

Finalmente, las @'ultimas dos l@'{@dotless{i}}neas contienen la
expresi@'on @code{save-excursion} con @code{insert-buffer-substring}
como su cuerpo. La expresi@'on @code{insert-buffer-substring} copia el
texto desde el b@'uffer en el que se est@'a (y no se ha visto el
ordenador puesta su atenci@'on, as@'{@dotless{i}} no se sabe que este
b@'uffer es ahora llamado @code{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.

@need 1250
El c@'odigo fuente, del cuerpo de @code{copy-to-buffer} se parece a
esto:

@smallexample
@group
(let (@var{bind-}@code{oldbuf}@var{-to-value-of-}@code{current-buffer})
    (@var{with-the-buffer-you-are-copying-to}
      (@var{but-do-not-erase-or-copy-to-a-read-only-buffer})
      (erase-buffer)
      (save-excursion
        @var{insert-substring-from-}@code{oldbuf}@var{-into-buffer})))
@end group
@end smallexample

@node insert-buffer
@section La definici@'on de @code{insert-buffer}
@findex insert-buffer

@code{insert-buffer} es todav@'{@dotless{i}}a una funci@'on
relacionada con el b@'uffer. Este comando copia otro b@'uffer
@emph{dentro} del b@'uffer actual. Es lo inverso de
@code{append-to-buffer} o @code{copy-to-buffer}, desde que se copia
una regi@'on de texto @emph{desde} el b@'uffer actual a otro
b@'uffer.

Aqu@'{@dotless{i}} hay una discusi@'on basada en el c@'odigo
original. El c@'odigo era simplificado en 2003 y es duro de comprender.

(@xref{Nuevo insert-buffer, , Nuevo Cuerpo para @code{insert-buffer}},
para ver una discusi@'on del nuevo cuerpo.)

Adem@'as, este c@'odigo ilustra el uso de @code{interactive} con un
b@'uffer que podr@'{@dotless{i}}a ser @dfn{read-only} y la
distinci@'on entre el nombre de un objeto y el objeto actualmente referido.

@menu
* c@'odigo insert-buffer::   c@'odigo insert-buffer
* insert-buffer interactivo::  Cuando tu puedes leer, pero no escribir.
* cuerpo insert-buffer::     El cuerpo tiene un @code{or} y un @code{let}.
* si y o::                   Usando un @code{if} en vez de un @code{or}.
* Insertar o::               C@'omo la expresi@'on @code{or} funciona.
* Insertar let::             Dos expresiones @code{save-excursion}.
* Nuevo insert-buffer::      Nuevo insert-buffer
@end menu

@ifnottex
@node c@'odigo insert-buffer
@unnumberedsubsec El c@'odigo para @code{insert-buffer}
@end ifnottex

@need 800
Aqu@'{@dotless{i}} est@'a el primer c@'odigo

@smallexample
@group
(defun insert-buffer (buffer)
  "Inserta despu@'es del punto los contenidos del BUFFER.
Pon la marca despu@'es del texto insertado.
El BUFFER puede ser un buffer un nombre de buffer."
  (interactive "*bInsert buffer:@: ")
@end group
@group
  (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)))
@end group
@group
      (insert-buffer-substring buffer start end)
      (setq newmark (point)))
    (push-mark newmark)))
@end group
@end smallexample

@need 1200
Como con otras definiciones de funci@'on, se puede usar una plantilla
para visi@'on de la funci@'on:

@smallexample
@group
(defun insert-buffer (buffer)
  "@var{documentation}@dots{}"
  (interactive "*bInsert buffer:@: ")
  @var{body}@dots{})
@end group
@end smallexample

@node insert-buffer interactivo
@subsection La expresi@'on interactiva en @code{insert-buffer}
@findex interactive, @r{ejemplo de uso}

En @code{insert-buffer}, el argumetno para la declaraci@'on
@code{interactive} tiene dos partes, un asterisco, @samp{*}, y
@samp{bInserta un buffer:@: }.

@menu
* B@'uffer solo lectura::    Cuando un buffer no puede ser modificado.
* b para interactivo::       Un buffer existe o adem@'as su nombre.
@end menu

@node B@'uffer solo lectura
@unnumberedsubsubsec Un b@'uffer de solo lectura
@cindex B@'uffer solo lectura
@cindex Asterisco para b@'uffer de solo lectura
@findex * @r{para buffer solo lectura}

El asterisco se utliza en la situaci@'on cuando el b@'uffer actual es un
b@'uffer de solo lectura --- un b@'uffer que no puede ser modificado. Si
@code{insert-buffer} es llamado cuando el b@'uffer actual es de solo
lectura, un mensaje a este efecto est@'a impreso en el @'area echo y
el terminal puede avisar; no se permite insertar cualquier cosa dentro
del b@'uffer. El asterisco no necesita ser seguido por una nueva
l@'{@dotless{i}}nea para separarse desde el siguiente argumento.

@node b para interactivo
@unnumberedsubsubsec @samp{b} en una expresi@'on interactiva

El siguiente argumento en la expresi@'on interactiva empieza con una
tecla min@'uscula @samp{b}. (Esto es diferente desde el c@'odigo para
@code{append-to-buffer}, que usa una may@'uscula
@samp{B}. @xref{append-to-buffer, , La Definici@'on de
@code{append-to-buffer}}.) La tecla min@'uscula cuenta al int@'erprete
Lisp que el argumento para @code{insert-buffer} ser@'{@dotless{i}}a un
buffer existente o sino su nombre. (La may@'uscula @samp{B} provee
para la posibilidad que el b@'uffer no existe.) Emacs te mostrar@'a en
pantalla el nombre del b@'uffer, ofreciendo un b@'uffer por defecto,
con la compleci@'on de nombre habilitado. Si el b@'uffer no existe, se
recibe un mensaje que dice ``No concuerda''; tu terminal te avisa tambi@'en.

El nuevo y simplificado c@'odigo genera una lista
@code{interactive}. Eso usa las funciones
@code{barf-if-buffer-read-only} y @code{read-buffer} con las que
estamos ya familiarizados y la forma especial @code{progn} con los que
no. (Eso ser@'a descrito despu@'es).

@node cuerpo insert-buffer
@subsection El cuerpo de la funci@'on @code{insert-buffer}

El cuerpo de la funci@'on @code{insert-buffer} tiene dos partes
principales: una expresi@'on @code{or} y una expresi@'on
@code{let}. El prop@'osito de la expresi@'on @code{or} es asegurar que
el argumento @code{buffer} es emparejado a un b@'uffer y no solo el
nombre de un b@'uffer. El cuerpo de la expresi@'on @code{let} contiene
el c@'odigo que copia los otros b@'uffers dentro del b@'uffer.

@need 1250
En el "outline" (esquema), las dos expresiones se ajustan dentro de la
funci@'on @code{insert-buffer} como esto:

@smallexample
@group
(defun insert-buffer (buffer)
  "@var{documentation}@dots{}"
  (interactive "*bInsertar buffer:@: ")
  (or @dots{}
      @dots{}
@end group
@group
  (let (@var{varlist})
      @var{body-of-}@code{let}@dots{} )
@end group
@end smallexample

Para comprender como la expresi@'on @code{or} asegura que el argumento
@code{buffer} es emparejado a un buffer y no al nombre de un b@'uffer,
es primero necesario comprender la funci@'on @code{or}.

Antes de hacer esto, perm@'{@dotless{i}}teme reescribir esta parte de
la funci@'on usando @code{if} as@'{@dotless{i}} puedes ver que es
hecho en una manera que ser@'a familiar.

@node si y o
@subsection @code{insert-buffer} con un @code{if} en vez de un @code{or}

El trabajo que debe ser hecho y asegura el valor de @code{buffer} es
un b@'uffer en s@'{@dotless{i}} mismo y no el nombre de un b@'uffer. Si
el valor es el nombre, entonces el b@'uffer en s@'{@dotless{i}} debe ser
obtenido.

Te puedes imaginar a t@'{@dotless{i}} mismo en una conferencia donde
un acomodador est@'a observando una lista con tu nombre dentro y
mir@'andote: el acomodador sabe ``asociar'' tu nombre, pero no a
t@'{@dotless{i}}; pero cuando el acomodador te encuentra y te toma el
brazo, el acomodador llega a ``asociarte'' a t@'{@dotless{i}}.

@need 800
En Lisp, se podr@'{@dotless{i}}a describir esta situaci@'on
as@'{@dotless{i}}:

@smallexample
@group
(if (not (holding-on-to-guest))
    (find-and-take-arm-of-guest))
@end group
@end smallexample

Se quiere hacer la misma cosa con un b@'uffer --- si no tenemos el
b@'uffer en s@'{@dotless{i}}, queremos tenerlo.

@need 1200
Usando un predicado llamado @code{bufferp} que nos cuenta si tenemos
un b@'uffer (en vez de su nombre), se puede escribir el c@'odigo como
este:

@smallexample
@group
(if (not (bufferp buffer))              ; @r{if-part}
    (setq buffer (get-buffer buffer)))  ; @r{then-part}
@end group
@end smallexample

@noindent
Aqu@'{@dotless{i}}, el true-or-false-test de la expresi@'on @code{if}
es @w{@code{(not (bufferp buffer))}}; y la then-part es la expresi@'on
@w{@code{(setq buffer (get-buffer buffer))}}.

En el test, la funci@'on @code{bufferp} devuelve cierto si su
argumento es un b@'uffer --- pero falso si su argumento es el nombre del
b@'uffer. (El @'ultimo car@'acter del nombre de la funci@'on
@code{bufferp} es el car@'acter @samp{p}; como se vi@'o antes, tal uso de
@samp{p} es una convenci@'on que indica que la funci@'on es un
predicado, que es un t@'ermino que significa que la funci@'on
determinar@'a si alguna propiedad es verdadera o falsa. @xref{Tipo
incorrecto de argumento, , Usando el objeto de tipo incorrecto como un
argumento}.)

@need 1200
La funci@'on @code{not} precede la expresi@'on @code{(bufferp
buffer)}, as@'{@dotless{i}} el true-or-false-test se ve como esto:

@smallexample
(not (bufferp buffer))
@end smallexample

@noindent
@code{no} es una funci@'on que devuelve cierto si su argumento es falso
y falso si su argumento es verdadero. As@'{@dotless{i}} si
@code{(bufferp buffer)} devuelve cierto, la expresi@'on @code{no}
devuelve falso y vice-versa: que es ``no cierto'' es falso que es ``no
falso'' es verdadero.

Usando este test, la expresi@'on @code{if} trabaja como sigue: cuando
el valor de la variable @code{buffer} est@'a actualmente en un
b@'uffer en vez de su nombre, el test true-or-false-test devuelve
false y la expresi@'on @code{if} no eval@'ua la parte then-part. Esto
est@'a bien, desde que no necesita para hacer cualquier cosa para la
variable @code{buffer} si es realmente un b@'uffer.

Por otro lado, cuando el valor de @code{buffer} no es un buffer en
s@'{@dotless{i}}, pero el nombre de un buffer, el true-or-false-test
devuelve cierto y la then-part de la expresi@'on es evaluada. En este
caso, la then-part es @code{(setq buffer (get-buffer buffer))}. Esta
expresi@'on usa la funci@'on @code{get-buffer} para devolver un buffer
actual en s@'{@dotless{i}}, dado su nombre. El @code{setq} entonces
asigna la variable @code{buffer} al valor del buffer en
s@'{@dotless{i}}, reemplazando su valor previo (que era el nombre del
buffer).

@node Insertar o
@subsection El @code{or} en el cuerpo

El prop@'osito de la expresi@'on @code{or} en la funci@'on
@code{insert-buffer} es asegurar que el argumento @code{buffer} est@'a
asociado a un b@'uffer y no solo al nombre de un b@'uffer. La secci@'on
previa muestra como el trabajo podr@'{@dotless{i}}a haber sido hecho
usando una expresi@'on @code{if}. Sin embargo, la funci@'on
@code{insert-buffer} actualmente usa @code{or}. Para comprender esto,
es necesario comprender como @code{or} trabaja.

@findex or
Una funci@'on @code{or} puede tener cualquier n@'umero de
argumentos. Eso eval@'ua cada argumento en turno y devuelve el valor
del primero de sus argumentos que no es @code{nil}. Tambi@'en, y esto
es una funcionalidad crucial de @code{or}, eso no eval@'ua cualquier
argumentos subsiguientes despu@'es devolviendo el primer valor
no-@code{nil}.

@need 800
La expresi@'on @code{or} se ve como esto:

@smallexample
@group
(or (bufferp buffer)
    (setq buffer (get-buffer buffer)))
@end group
@end smallexample

@noindent
El primer argumento a @code{or} es la expresi@'on @code{(bufferp
buffer)}. Esta expresi@'on devuelve cierto (un valor no-@code{nil}) si
el b@'uffer es actualmente un b@'uffer, y no solo el nombre de un
b@'uffer. En la expresi@'on @code{or}, si este es el caso, la
expresi@'on @code{or} devuelve esto el valor cierto y no eval@'ua la
siguiente expresi@'on --- y esto es bueno para nosotros, desde que
nosotros no queremos hacer cualquier cosa al valor de @code{buffer} si
eso es realmente un b@'uffer.

Por otro lado, si el valor de @code{(bufferp buffer)} es @code{nil},
que ser@'a si el valor de @code{buffer} es el nombre de un buffer, el
int@'erprete Lisp eval@'ua el siguiente elemento de la
expresi@'on. Esta es la expresi@'on @code{(setq buffer (get-buffer
buffer))}. Esta expresi@'on devuelve un valor no-@code{nil}, que es el
valor para el que asigna la variable @code{buffer} --- y este valor es
un b@'uffer en s@'{@dotless{i}}, no el nombre de un b@'uffer.

El resultado de todo esto es que el s@'{@dotless{i}}mbolo
@code{buffer} es siempre asociado a un b@'uffer en s@'{@dotless{i}} en
vez del nombre de un b@'uffer. Toda es necesario porque la funci@'on
@code{set-buffer} en una l@'{@dotless{i}}nea siguiente trabaja con un
buffer en s@'{@dotless{i}}, no con el nombre de un b@'uffer.

@need 1250
Incidentalmente, usando @code{or}, la situaci@'on con el acomodador se
ver@'{@dotless{i}}a as@'{@dotless{i}}:

@smallexample
(or (holding-on-to-guest) (find-and-take-arm-of-guest))
@end smallexample

@node Insertar let
@subsection La expresi@'on @code{let} en @code{insert-buffer}

Despu@'es asegurando que la variable @code{buffer} se refiere a un
buffer en s@'{@dotless{i}} y no solo al nombre de un buffer, la
funci@'on @code{insert-buffer} contin@'ua con una expresi@'on
@code{let}. Esto especifica tres variables locales, @code{start},
@code{end} y @code{newmark} y los asocia al valor inicial
@code{nil}. Estas variables son usadas dentro del resto de @code{let}
y temporalmente se oculta con cualquier otra ocurrencia de variables
del mismo nombre en Emacs hasta el fin del @code{let}.

@need 1200
El cuerpo del @code{let} contiene dos expresiones
@code{save-excursion}. Primero, miraremos la expresi@'on
@code{save-excursion} en detalle. La expresi@'on se parece a esto:

@smallexample
@group
(save-excursion
  (set-buffer buffer)
  (setq start (point-min) end (point-max)))
@end group
@end smallexample

@noindent
La expresi@'on @code{(set-buffer buffer)} cambia la atenci@'on de
Emacs desde el b@'uffer actual a uno desde el que el texto ser@'a
copiado. En este b@'uffer las variables @code{start} y @code{end} se
asignadan al principio y al fin del b@'uffer, usando los comandos
@code{point-min} y @code{point-max}. Note que tenemos
aqu@'{@dotless{i}} una ilustraci@'on de c@'omo @code{setq} es capaz de
asignar dos variables en la misma expresi@'on. El primer argumento de
@code{setq} es asignar al valor del segundo, y su tercer argumento
est@'a asignado al valor del cuarto.

Despu@'es el cuerpo del @code{save-excursion} propio es evaluado, el
@code{save-excursion} restaura el b@'uffer original, pero @code{start}
y @code{end} permanece asignado a los valores del principio y fin del
b@'uffer en el que el texto ser@'a copiado.

@need 1250
La expresi@'on por fuera @code{save-excursion} se ve como:

@smallexample
@group
(save-excursion
  (@var{inner-}@code{save-excursion}@var{-expression}
     (@var{go-to-new-buffer-and-set-}@code{start}@var{-and-}@code{end})
  (insert-buffer-substring buffer start end)
  (setq newmark (point)))
@end group
@end smallexample

@noindent
La funci@'on @code{insert-buffer-substring} copia el texto
@emph{dento} del b@'uffer @emph{desde} la regi@'on indicada por
@code{start} y @code{end} en el @code{b@'uffer}. Desde el total del
segundo b@'uffer cae entre @code{start} y @code{end}, el todo del
segundo b@'uffer es copiado dentro del b@'uffer que est@'as
editando. Lo siguiente, el valor del punto, que ser@'a al fin del
texto insertado, es grabado en la variable @code{newmark}.

Despu@'es el cuerpo de @code{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
@code{newmark} graba el fin del texto insertado. En la @'ultima
l@'{@dotless{i}}nea de la expresi@'on @code{let}, la expresi@'on de la
funci@'on @code{(push-mark newmark)} asigna una marca a esta
posici@'on. (La posici@'on previa de la marca est@'a
todav@'{@dotless{i}}a accesible; est@'a grabado en la marca del anillo
y se puede regresar a eso con @kbd{C-u C-@key{SPC}}.) Mientras tanto,
el punto est@'a localizado al principio del texto insertado, que
est@'a donde estaba antes de ser llamado la funci@'on que inserta, la
posici@'on de lo que estaba guardado por la primera @code{save-excursion}.

@need 1250
La expresi@'on @code{let} se parece a esto:

@smallexample
@group
(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))
@end group
@end smallexample

Como la funci@'on @code{append-to-buffer}, la funci@'on
@code{insert-buffer} usa @code{let}, @code{save-excursion} y
@code{set-buffer}. Adem@'as, la funci@'on ilustra un camino para usar
@code{o}. Toda estas funciones est@'an construyendo el bloque que
se encontrar@'an y usar@'an una y otra vez.

@node Nuevo insert-buffer
@subsection Nuevo cuerpo para @code{insert-buffer}
@findex insert-buffer, nueva versi@'on del cuerpo
@findex nueva versi@'on cuerpo para insert-buffer

El cuerpo en la versi@'on de GNU Emacs 22 es m@'as confuso que en el
original.

@need 1250
Consiste de dos expresiones

@smallexample
@group
  (push-mark
   (save-excursion
     (insert-buffer-substring (get-buffer buffer))
     (point)))

   nil
@end group
@end smallexample

@noindent
excepto, y esto es lo que los novicios confunden, un trabajo muy
importante es hecho dentro de la expresi@'on @code{push-mark}.

La funci@'on @code{get-buffer} devuelve un b@'uffer con el nombre
proporcionado. Se tomar@'a nota de que la funci@'on @emph{no} se
llama @code{get-buffer-create}; eso no crea un b@'uffer si uno no
existe ya. El b@'uffer devuelto por @code{get-buffer}, un b@'uffer
existente, es pasado a @code{insert-buffer-substring}, que inserta el
total del b@'uffer (desde que no se especific@'on ninguna cosa
m@'as).

La posici@'on dentro del buffer es insertado es grabado por
@code{push-mark}. Entonces la funci@'on devuelve @code{nil}, el valor
de su @'ultimo comando. Pon otro camino, la funci@'on
@code{insert-buffer} existe solo para producir un efecto lateral,
insertando otro buffer, no para devolver cualquier valor.

@node beginning-of-buffer
@section Definici@'on completa de @code{beginning-of-buffer}
@findex beginning-of-buffer

La estructura b@'asica de la funci@'on @code{beginning-of-buffer} ya
ha sido discutida. (@xref{simplified-beginning-of-buffer, , Una
Definici@'on Simplificada @code{beginning-of-buffer}}). Esta secci@'on
describe la parte compleja de la definici@'on.

Como se describe previamente, cuando se invoca sin un argumento,
@code{beginning-of-buffer} mueve el cursor al principio del b@'uffer
(en realidad, al principio de la porci@'on accesible del b@'uffer),
dejando la marca en la posici@'on previa. Sin embargo, cuando el
comando es invocado con un n@'umero entre uno y diez, la funci@'on
considera que n@'umero ser@'a una fracci@'on del tama@~no del
b@'uffer, medido en decenas, y Emacs mueve el cursor en esta
fracci@'on del camino desde el principio del b@'uffer. De este modo,
se puede o bien llamar a esta funci@'on con la tecla comando @kbd{M-<},
que mover@'a el cursor al principio del b@'uffer, o con una tecla tal
como @kbd{C-u 7 M-<} que mover@'a el cursor a un punto 70% del camino
a trav@'es del b@'uffer. Si un n@'umero m@'as grande de diez es usado
para el argumento que se mueve al final del b@'uffer.

La funci@'on @code{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
@end menu

@node Argumentos opcionales
@subsection Argumentos opcionales

A menos que se cuente de otro modo, Lisp espera que una funci@'on con
un argumento en su definici@'on de funci@'on se llame con un valor
para este argumento. Si esto no ocurre, se obtiene un error y un
mensaje que dice @samp{N@'umero de argumentos err@'oneo}.

@cindex Argumentos Opcionales
@cindex Palabra Clave
@findex opcional
Sin embargo, los argumentos opcionales son una funcionalidad de Lisp:
una @dfn{palabra clave} particular es usada para contar al
int@'erprete Lisp que un argumento es opcional. La palabra clave es
@code{&optional}. (El @samp{&} en frente de @samp{opcional} es parte
de la palabra clave.) En una definici@'on de funci@'on, si un
argumento sigue a la palabra clave @code{&optional}, ning@'un valor
necesita ser pasado a este argumento cuando la funci@'on se llama.

@need 1200
La primera l@'{@dotless{i}}nea de la definici@'on de funci@'on de
@code{beginning-of-buffer} tiene lo siguiente:

@smallexample
(defun beginning-of-buffer (&optional arg)
@end smallexample

@need 1250
En el "outline" (esquema), la funci@'on completa se parece a esto:

@smallexample
@group
(defun beginning-of-buffer (&optional arg)
  "@var{documentation}@dots{}"
  (interactive "P")
  (or (@var{is-the-argument-a-cons-cell} arg)
      (and @var{are-both-transient-mark-mode-and-mark-active-true})
      (push-mark))
  (let (@var{determine-size-and-set-it})
  (goto-char
    (@var{if-there-is-an-argument}
        @var{figure-out-where-to-go}
      @var{else-go-to}
      (point-min))))
   @var{do-nicety}
@end group
@end smallexample

La funci@'on es similar a la funci@'on
@code{simplified-beginning-of-buffer} excepto que la expresi@'on
@code{interactive} tiene @code{"P"} como un argumento y la funci@'on
@code{goto-char} es seguida por una expresi@'on 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@'{@dotless{i}}tulos, por favor, considere ignorar la funci@'on
@code{consp}. @ref{Implementaci@'on de listas, , C@'omo las Listas son
Implementadas}, y @ref{Tipo de Cons Cell, , Cons Cell y Tipos de
Listas, elisp, El Manual de Referencia GNU Emacs Lisp}).

El @code{"P"} en la expresi@'on @code{interactive} cuenta a Emacs
c@'omo pasar un argumento prefijo, si hay uno, a la funci@'on en forma
plana. Un argumento prefijo se crea escribiendo la tecla @key{META}
seguida por un n@'umero, o escribiendo @kbd{C-u} y entonces un
n@'umero. (Si no escribes un n@'umero, @kbd{C-u} por defecto a un cons
cell con un 4. Una min@'uscula @code{"p"} en la expresi@'on
@code{interactive} causa a la funci@'on convertir un argumento prefijo
a un n@'umero.)

El true-or-false-test de la expresi@'on @code{if} se ve compleja, pero
no lo es: se chequea si @code{arg} tiene un valor que no es @code{nil}
y si es un cons cell. (Esto es lo que @code{consp} hace; chequea si su
argumento es un cons cell.) Si @code{arg} tiene un valor que no es
@code{nil} (y no es un cons cell.), que ser@'a el caso si
@code{beginning-of-buffer} se llama con un argumento, entonces este
true-or-false-test devolver@'a cierto y la then-part de la expresi@'on
@code{if} falsa. Por otro lado, si @code{beginning-of-bufer} no se
llama con un argumento, el valor de @code{arg} ser@'a @code{nil} y la
else-part de la expresi@'on @code{if} se evaluar@'a. La else-part es
simple @code{point-min}, y esto es lo de fuera, la expresi@'on
@code{goto-char} es @code{(goto-char (point-min))}, que es c@'omo se
vi@'o la funci@'on @code{beginning-of-buffer} en su forma
simplificada.

@node beginning-of-buffer opt arg
@subsection @code{beginning-of-buffer} con un argumento

Cuando @code{beginning-of-buffer} se llama con un argumento, una
expresi@'on es evaluada que calcula que valor pasa a
@code{goto-char}. Esto es incluso complicado a primera vista. Eso
incluye una expresi@'on @code{if} propia y mucha aritm@'etica. Se ve
as@'{@dotless{i}}:

@smallexample
@group
(if (> (buffer-size) 10000)
    ;; @r{@exclamdown{}Evitar sobrecarga para grandes tama@~nos de b@'uffer!}
                          (* (prefix-numeric-value arg)
                             (/ size 10))
  (/
   (+ 10
      (*
       size (prefix-numeric-value arg))) 10)))
@end group
@end smallexample

@menu
* Desenmara@~nar beginning-of-buffer::  Desenmara@~nar beginning-of-buffer
* El caso del buffer largo::  El caso del buffer largo
* Peque@~no caso de b@'uffer::  Peque@~no caso de b@'uffer
@end menu

@ifnottex
@node Desenmara@~nar beginning-of-buffer
@unnumberedsubsubsec Desenmara@~nar @code{beginning-of-buffer}
@end ifnottex

Como otras expresiones que se ven complejas, la expresi@'on
condicional con @code{beginning-of-buffer} puede ser desenredada
mir@'andola por partes de una plantilla, en este caso, la plantilla
par una expresi@'on if-then-else. En forma esquel@'etica, la
expresi@'on se ve as@'{@dotless{i}}:

@smallexample
@group
(if (@var{buffer-is-large}
    @var{divide-buffer-size-by-10-and-multiply-by-arg}
  @var{else-use-alternate-calculation}
@end group
@end smallexample

El true-or-fase-test de esta expresi@'on @code{if} propia chequea el
tama@~no del buffer. La raz@'on para esto es que la versi@'on vieja de
Emacs 18 usaba n@'umeros que no son m@'as grandes que 8 millones o
as@'{@dotless{i}} y en la computaci@'on que segu@'{@dotless{i}}a, el
programador tem@'{@dotless{i}}a que Emacs podr@'{@dotless{i}}a
intentar usar a trav@'es de largos n@'umeros si el b@'uffer fuera
largo. El t@'ermino `sobrecarga', que se mencion@'o en el comentario,
significa que los n@'umeros son grandes. Las versiones m@'as recientes
de Emacs usan n@'umeros largos, pero este c@'odigo no ha sido tocado,
solo porque la gente ahora mira en b@'uffers que est@'an lejos, tan
lejos como antes.

Hay dos casos: si el b@'uffer es largo, o si no.

@node El caso del buffer largo
@unnumberedsubsubsec Qu@'e ocurre en un b@'uffer largo

En @code{beginning-of-buffer}, la expresi@'on propia @code{if} chequea
si el tama@~no del b@'uffer es mayor que 10000 caracteres. Para hacer
esto, se usa la funci@'on @code{>} y la computaci@'on de @code{size}
que viene desde la expresi@'on let.

Hace tiempo, se usaba la funci@'on @code{buffer-size}. No solo esta
funci@'on era llamada varias veces, eso daba el tama@~no del b@'uffer
completo, no la parte accesible. La computaci@'on tiene mucho m@'as
sentido cuando se maneja solo la parte accesible. (@xref{Encogiendo y
extendiendo, , Encogiendo y extendiendo}, para m@'as informaci@'on en
focalizar la atenci@'on para una parte `accesible'.)

@need 800
La l@'{@dotless{i}}nea se parece a esto:

@smallexample
(if (> size 10000)
@end smallexample

@need 1200
@noindent
Cuando el b@'uffer es largo, el then-part de la expresi@'on @code{if}
se eval@'ua. Eso se lee as@'{@dotless{i}} (despu@'es de ser formateado
para una f@'acil lectura):

@smallexample
@group
(*
  (prefix-numeric-value arg)
  (/ size 10))
@end group
@end smallexample

@noindent
Esta expresi@'on es una multiplicaci@'on, con dos argumentos para la
funci@'on @code{*}.

El primer argumento es @code{(prefix-numeric-value arg)}. Cuando
@code{"P"} se usa como argumento para @code{interactive}, el valor
pasado para la funci@'on como argumento es un ``argumento prefijo
crudo'', y no un n@'umero. (Es un n@'umero en una lista). Para
desarrollar la aritm@'etica, una conversi@'on es necesaria, y
@code{prefix-numeric-value} hace el trabajo.

@findex / @r{(division)}
@cindex Divisi@'on
El segundo argumento es @code{(/ size 10)}. Esta expresi@'on divide el
valor num@'erico por diez --- el valor num@'erico del tama@~no de la
porci@'on accesible del b@'uffer. Esto produce un n@'umero que cuenta
cu@'antos caracteres crean una decena del tama@~no del b@'uffer. (En Lisp,
@code{/} es usado para divisi@'on, solo como @code{*} es usado para
multiplicaci@'on.)

@need 1200
En la expresi@'on de la multiplicaci@'on como un todo, esta cantidad
se multiplica por el valor del argumento prefijo --- la
multiplicaci@'on se parece a:

@smallexample
@group
(* @var{numeric-value-of-prefix-arg}
   @var{number-of-characters-in-one-tenth-of-the-accessible-buffer})
@end group
@end smallexample

@noindent
Si, por ejemplo, el argumento prefijo es @samp{7}, el valor one-tenth
ser@'a multiplicado por 7 para dar una posici@'on del 70% del camino.

@need 1200
El resultado de todo esto es que si la porci@'on accesible del b@'uffer
es largo, la expresi@'on @code{goto-char} se lee esto:

@smallexample
@group
(goto-char (* (prefix-numeric-value arg)
              (/ size 10)))
@end group
@end smallexample

Esto pone el cursor donde se quiere.

@node Peque@~no caso de b@'uffer
@unnumberedsubsubsec Qu@'e ocurre en un b@'uffer peque@~no

Si el b@'uffer contiene poco m@'as de 10000 caracteres, una
computaci@'on ligeramente diferente es medida. Se podr@'{@dotless{i}}a
pensar que esto no es necesario, desde que la primera computaci@'on
podr@'{@dotless{i}}a hacer el trabajo. Sin embargo, en un b@'uffer
peque@~no, el primer m@'etodo puede no poner el cursor en la
l@'{@dotless{i}}nea exactamente deseada; el segundo m@'etodo hace un
trabajo mejor.

@need 800
El c@'odigo se parece a esto:

@c Keep this on one line.
@smallexample
(/ (+ 10 (* size (prefix-numeric-value arg))) 10))
@end smallexample

@need 1200
@noindent
Este es el c@'odigo en el que se ve qu@'e ocurre descubriendo como las
funciones se embeben entre par@'entesis. Eso es f@'acil de leer si se
reformatea con cada expresi@'on indentada m@'as profundamente que la
expresi@'on que encierra:

@smallexample
@group
  (/
   (+ 10
      (*
       size
       (prefix-numeric-value arg)))
   10))
@end group
@end smallexample

@need 1200
@noindent
Mirando los par@'entesis, se ve que la operaci@'on propia es
@code{(prefix-numeric-value arg)}, que convierte el argumento plano
para un n@'umero. En la siguiente expresi@'on, este n@'umero es
multiplicado por el tama@~no de la porci@'on accesible del b@'uffer:

@smallexample
(* size (prefix-numeric-value arg))
@end smallexample

@noindent
Esta multiplicaci@'on crea un n@'umero que puede ser m@'as largo que
el tama@~no del buffer --- siete veces m@'as larga si el argumento es
7, por ejemplo. Diez se a@~anade a @'este n@~umero y finalmente el
n@'umero es dividido por 10 para proporcionar un valor que es un
car@'acter m@'as largo que la posici@'on de porcentaje en el b@'uffer.

El n@'umero que resulta de todo esto se pasa a @code{goto-char} y
el cursor se mueve a este punto.

@need 1500
@node Completo beginning-of-buffer
@subsection El @code{beginning-of-buffer} completo

@need 1000
Aqu@'{@dotless{i}} est@'a el texto completo de la funci@'on
@code{beginning-of-buffer}:
@sp 1

@c In GNU Emacs 22
@smallexample
@group
(defun beginning-of-buffer (&optional arg)
  "Mueve el punto al principio del buffer;
deja marca en la posici@'on previa. 
Con prefijo \\[universal-argument], 
no se asigna una marca en la posici@'on previa.
Con el argumento num@'erico N, pon el 
punto N/10 del camino desde el principio.

Si el b@'uffer est@'a encogido
este comando usa el principio y tama@~no
de la parte accesible del b@'uffer.
@end group

@group
@exclamdown{}No use este comando en programas Lisp!
\(goto-char (point-min)) es r@'apido
y evita poseer la marca."
  (interactive "P")
  (or (consp arg)
      (and transient-mark-mode mark-active)
      (push-mark))
@end group
@group
  (let ((size (- (point-max) (point-min))))
    (goto-char (if (and arg (not (consp arg)))
                   (+ (point-min)
                      (if (> size 10000)
                          ;; @exclamdown{}Evita sobrecarga para grandes tama@~nos de b@'uffer!
                          (* (prefix-numeric-value arg)
                             (/ size 10))
                        (/ (+ 10 (* size (prefix-numeric-value arg)))
                           10)))
                 (point-min))))
  (if arg (forward-line 1)))
@end group
@end smallexample

@ignore
From before GNU Emacs 22
@smallexample
@group
(defun beginning-of-buffer (&optional arg)
  "Mueve el punto al principio del buffer;
deja la marca a la posici@'on previa.
Con el arg N, pon el punto N/10 del camino 
desde el comienzo real.
@end group
@group
@exclamdown{}No usar esto en programas Lisp!
\(goto-char (point-min)) es r@'apido 
y no asigna la marca."
  (interactive "P")
  (push-mark)
@end group
@group
  (goto-char
   (if arg
       (if (> (buffer-size) 10000)
           ;; @r{@exclamdown{}Evita overflow para tama@~nos de b@'uffer grandes!}
           (* (prefix-numeric-value arg)
              (/ (buffer-size) 10))
@end group
@group
         (/ (+ 10 (* (buffer-size)
                     (prefix-numeric-value arg)))
            10))
     (point-min)))
  (if arg (forward-line 1)))
@end group
@end smallexample
@end ignore

@noindent
Excepto por dos peque@~nos puntos, la discusi@'on previa muestra
c@'omo esta funci@'on trabaja. El primer punto trata un detalle en la
cadena de documentaci@'on, y el segundo concierne la @'ultima
l@'{@dotless{i}}nea de la funci@'on.

@need 800
En la cadena de documentaci@'on, hay referencia a una expresi@'on:

@smallexample
\\[universal-argument]
@end smallexample

@noindent
Un @samp{\\} es usado antes de la primera llave de esta
expresi@'on. Este @samp{\\} le cuenta al int@'erprete Lisp sustituir
qu@'e clave est@'a actualmente emparejada a los @samp{[@dots{}]}. En el
caso de @code{universal-argument}, que es normalmente @kbd{C-u}, pero
eso podr@'{@dotless{i}}a ser diferente. (@xref{Consejos de Documentaci@'on,
,
Consejos para Cadenas de Documentaci@'on, elisp, El Manual de
Referencia de GNU Emacs Lisp}, para m@'as informaci@'on.)

@need 1200
Finalmente, la @'ultima l@'{@dotless{i}}nea del comando
@code{beginning-of-buffer} dice mover el punto al principio de la
siguiente l@'{@dotless{i}}nea si el comando es invocado con un argumento:

@smallexample
(if arg (forward-line 1)))
@end smallexample

@noindent
Esto pone el cursor al principio de la primera l@'{@dotless{i}}nea
despu@'es de las apropiadas decenas de posiciones en el b@'uffer. Esto
significa que el cursor est@'a siempre localizado @emph{al menos} las
decenas solicitadas del camino a trav@'es del b@'uffer, que es un bien
que es, quiz@'as, no necesario, pero que, si no ocurri@'o,
estar@'{@dotless{i}}a seguro de dibujar rumores.

Por otro lado, eso significa que si se especifica el comando con un
@kbd{C-u}, sin un n@'umero, 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@'{@dotless{i}}nea @dots{} no s@'e si este se
pretende ning@'un trato con el c@'odigo para evitar que esto ocurre.

@node Revisar el segundo b@'uffer relacionado
@section Revisar

Aqu@'{@dotless{i}} hay un breve resumen de los asuntos cubierto en
este cap@'{@dotless{i}}tulo.

@table @code
@item or
Eval@'ua cada argumento en secuencia, y devuelve el valor del primer
argumento que no es @code{nil}, si ninguno devuelve un valor que no es
@code{nil}, devuelve @code{nil}. En breve, devuelve el primer valor de
verdad de los argumento; devuelve un valor cierto si un @emph{or}
cualquier de los otros son verdad.

@item and
Eval@'ua cada argumento en secuencia, y si cualquiera es @code{nil},
devuelve @code{nil}; si ninguno es @code{nil}, devuelve el valor del
@'ultimo argumento. En breve, devuelve un valor cierto solo si todos
los argumentos cierto; devuelve un valor cierto si un @emph{and} cada
uno de los otros son ciertos.

@item &optional
Una palabra clave usaba para indicar que un argumento a una
definici@'on de funci@'on es opcional; esto significa que la funci@'on
puede ser evaluado sin el argumento, si se desea.

@item prefix-numeric-value
Convierte el `argumento prefijo plano' producido por
@code{(interactive "P")} a un valor num@'erico.

@item forward-line
Mueve el punto hacia delante al principio de la siguiente
l@'{@dotless{i}}nea, o si el argumento es m@'as de uno, hacia delante
varias l@'{@dotless{i}}neas. Si eso no se puede mover tan lejos
hacia delante como se puede, @code{forward-line} va hacia delante tan
lejos como se puede y entonces devuelve un contaje del n@'umero de
l@'{@dotless{i}}neas adicionales que no pudo moverse.

@item erase-buffer
Borra todos los contenidos del b@'uffer actual.

@item bufferp
Devuelve @code{t} si su argumento es un b@'uffer; de otro modo
devuelve @code{nil}.
@end table

@node Ejercicio opcional
@section Ejercicio de argumento @code{opcional}

Escribe una funci@'on interactiva con un argumento opcional que
chequee si su argumento, un n@'umero, es mayor o igual, o al menos,
menos que el valor de @code{fill-column}, y lo escribe, en un
mensaje. Sin embargo, si no se pasa un argumento a la funci@'on, usa
56 como un valor por defecto.

@node Encogiendo y extendiendo
@chapter Encogiendo y extendiendo
@cindex Focalizando atenci@'on (encogiendo)
@cindex Encogiendo
@cindex Ampliando

Encoger es una funcionalidad de Emacs que hace posible focalizar en
una parte espec@'{@dotless{i}}fica de un b@'uffer, 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 @code{save-restriction}.
* what-line::                El n@'umero de la l@'{@dotless{i}}nea que 
                               apunta est@'a activa.
* Ejercicio narrow::         Ejercicio narrow
@end menu

@ifnottex
@node Ventajas de encoger
@unnumberedsec Las ventajas de encoger
@end ifnottex

Con encoger, el resto del b@'uffer se hace invisible, como si no
estuviera. Esto es una ventaja si, por ejemplo, se quiere reemplazar
una palabra en una parte del b@'uffer pero no otro: se encoge la parte
que se quiere y el reemplazo se trae solo en esta secci@'on, no en
el resto del b@'uffer. Las b@'usquedas solo funcionar@'an con una
regi@'on encogida, no fuera de una, as@'{@dotless{i}} si tu est@'as
arreglando una parte de un documento, se puede guardar en
s@'{@dotless{i}} desde encontrar partes accidentalmente que no
necesitas arreglar encongiendo solo la regi@'on que quieres. (La tecla
asociada a @code{narrow-to-region} es @kbd{C-x n n}.)

Sin embargo, encoger hace que el resto del b@'uffer sea invisible,
esto puede asustar a gente quien inadvertidamente invoca a encoger y
pensar que se ha borrado una parte de su fichero. M@'as all@'a, el
comando @code{undo} (que es normalmente emparejado a @kbd{C-x u}) no
se deja encoger, as@'{@dotless{i}} las personas pueden llegar a estar
bastante desesperadas si no conocen que ellas pueden volver al resto
de un b@'uffer para visibilizarlo con el comando @code{widen}. (El
emparejamiento de la tecla para @code{widen} es @kbd{C-x n w}.)

Encoger es tan @'util al int@'erprete Lisp como para las personas. Con
frecuencia, una funci@'on Emacs Lisp est@'a dise@~nada para trabajar
en solo parte de un b@'uffer; o de manera conversa, una funci@'on
Emacs Lisp necesita trabajar en todo un b@'uffer que ha sido
encogido. La funci@'on @code{what-line}, por ejemplo, borra el
encogimiento desde un b@'uffer, si eso tiene cualquier encogimiento y
cuando eso ha finalizado su trabajo, restaura el encogimiento
que haya. Por otro lado, la funci@'on @code{count-lines}, que es
llamada por @code{what-line}, usa el encogimiento para restringirse a
s@'{@dotless{i}} misma solo a la porci@'on del b@'uffer en el que
se est@'a interesado y entonces restaura la situaci@'on previa.

@node save-restriction
@section La forma especial @code{save-restriction}
@findex save-restriction

En Emacs Lisp, se puede usar la forma especial @code{save-restriction}
para guardar la traza siempre que el encogimiento est@'e en
efecto. Cuando el int@'erprete Lisp se encuentra con
@code{save-restriction}, eso ejecuta el c@'odigo en el cuerpo de la
expresi@'on @code{save-restriction}, y entonces deshace cualquier
cambio para encoger lo que el c@'odigo caus@'o. Si, por ejemplo, el
b@'uffer est@'a encogido y el c@'odigo que sigue al comando
@code{save-restriction} devuelve el b@'uffer para su regi@'on
encogida. En el comando @code{what-line}, cualquier encogimiento del
b@'uffer que se puede tener se deshace por el comando @code{widen} que
inmediatamente sigue el comando @code{save-restriction}. Cualquier
encogimiento original es restaurado solo antes de la compleci@'on de
la funci@'on.

@need 1250
La plantilla para una expresi@'on @code{save-restriction} es simple:

@smallexample
@group
(save-restriction
  @var{body}@dots{} )
@end group
@end smallexample

@noindent
El cuerpo del @code{save-restriction} es una o m@'as expresiones que
ser@'an evaluadas en secuencia por el int@'erprete Lisp.

Finalmente, un punto a anotar: cuando se usa tanto
@code{save-excursion} y @code{save-restriction}, uno correcto
despu@'es del otro, deber@'{@dotless{i}}as usar @code{save-excursion}
fuera. Si se escribe en el orden inverso, se podr@'{@dotless{i}}a
fallar para grabar el encogimiento en el b@'uffer para el que Emacs
cambia despu@'es de llamar a @code{save-excursion}. De este modo, cuando
se escribe junto a @code{save-excursion} y @code{save-restriction}
ser@'{@dotless{i}}a escrito as@'{@dotless{i}}:

@smallexample
@group
(save-excursion
  (save-restriction
    @var{body}@dots{}))
@end group
@end smallexample

En otras circunstancias, cuando no se escribe junto, las formas
especiales @code{save-excursion} y @code{save-restriction} deben ser
escritas en el orden apropiado para la funci@'on.

@need 1250
Por ejemplo,

@smallexample
@group
  (save-restriction
    (widen)
    (save-excursion
    @var{body}@dots{}))
@end group
@end smallexample

@ignore
Emacs 22
/usr/local/src/emacs/lisp/simple.el

(defun what-line ()
  "Print the current buffer line number and narrowed line number of point."
  (interactive)
  (let ((start (point-min))
        (n (line-number-at-pos)))
    (if (= start 1)
        (message "Line %d" n)
      (save-excursion
        (save-restriction
          (widen)
          (message "line %d (narrowed line %d)"
                   (+ n (line-number-at-pos start) -1) n))))))

(defun line-number-at-pos (&optional pos)
  "Return (narrowed) buffer line number at position POS.
If POS is nil, use current buffer location.
Counting starts at (point-min), so the value refers
to the contents of the accessible portion of the buffer."
  (let ((opoint (or pos (point))) start)
    (save-excursion
      (goto-char (point-min))
      (setq start (point))
      (goto-char opoint)
      (forward-line 0)
      (1+ (count-lines start (point))))))

(defun count-lines (start end)
  "Return number of lines between START and END.
This is usually the number of newlines between them,
but can be one more if START is not equal to END
and the greater of them is not at the start of a line."
  (save-excursion
    (save-restriction
      (narrow-to-region start end)
      (goto-char (point-min))
      (if (eq selective-display t)
          (save-match-data
            (let ((done 0))
              (while (re-search-forward "[\n\C-m]" nil t 40)
                (setq done (+ 40 done)))
              (while (re-search-forward "[\n\C-m]" nil t 1)
                (setq done (+ 1 done)))
              (goto-char (point-max))
              (if (and (/= start end)
                       (not (bolp)))
                  (1+ done)
                done)))
        (- (buffer-size) (forward-line (buffer-size)))))))
@end ignore

@node what-line
@section @code{what-line}
@findex what-line
@cindex Extendiendo, ejemplo de

El comando @code{what-line} cuenta el n@'umero de la
l@'{@dotless{i}}nea en la que el cursor se ha localizado. La
funci@'on ilustra el uso de los comandos @code{save-restriction} y
@code{save-excursion}. Aqu@'{@dotless{i}} est@'a el texto original de
la funci@'on:

@smallexample
@group
(defun what-line ()
  "Imprime el n@'umero de l@'{@dotless{i}}nea actual (en el b@'uffer)
  del punto."
  (interactive)
  (save-restriction
    (widen)
    (save-excursion
      (beginning-of-line)
      (message "L@'{@dotless{i}}nea %d"
               (1+ (count-lines 1 (point)))))))
@end group
@end smallexample

(En versiones recientes de GNU Emacs, la funci@'on @code{what-line} se
ha expandido para contar el n@'umero de l@'{@dotless{i}}neas en un
b@'uffer encogido tan bien como el n@'umero de l@'{@dotless{i}}neas en
un b@'uffer ampliado. La versi@'on reciente es m@'as compleja que la
versi@'on que se muestra. Alguien sinti@'endose venturoso,
podr@'{@dotless{i}}a querer mirarla despu@'es de entender como esta
versi@'on funciona. Probablemente se necesitar@'a usar @kbd{C-h f}
(@code{describe-function}). La versi@'on nueva usa un condicional para
determinar si el b@'uffer se ha encogido.

(Tambi@'en, eso usa @code{line-number-at-pos}, que otras expresiones
simples, tales como @code{(goto-char (point-min))}, mueve el punto al
principio de la l@'{@dotless{i}}nea actual con @code{(forward-line 0)}
en vez de @code{beginning-of-line}.)

La funci@'on @code{what-line} como se muestra aqu@'{@dotless{i}} tiene
una l@'{@dotless{i}}nea de documentaci@'on y es interactiva, como se
esperar@'{@dotless{i}}a. Las dos l@'{@dotless{i}}neas siguientes usan
las funciones @code{save-restriction} y @code{widen}.

La forma especial @code{save-restriction} nota que encogiendo es en
efecto, si cualquiera, en el buffer actual y restaura que encogiendo
despu@'es del c@'odigo en el cuerpo del @code{save-restriction} ha
sido evaluada.

La forma especial @code{save-restriction} es seguida por
@code{widen}. Esta funci@'on deshace cualquier distancia del actual
b@'uffer que puede haber tenido cuando @code{what-line} se llame. (La
distancia que hab@'{@dotless{i}}a es la distancia que
@code{save-restriction} recuerda.) Esta ampliaci@'on se hace posible
para la l@'{@dotless{i}}nea contando comandos a contar desde el
principio del b@'uffer. De otro modo, se habr@'{@dotless{i}}a
limitado para contar con la regi@'on accesible. Cualquier distancia
original se restaura solo antes de la compleci@'on de la funci@'on
por la forma especial @code{save-restriction}.

La llamada a @code{widen} es seguida por @code{save-excursion}, que
guarda la posici@'on del cursor (por ej., el punto) y de la marca, y
la restaura despu@'es el c@'odigo en el cuerpo del
@code{save-excursion} usa la funci@'on @code{beginning-of-line} para
mover el punto.

(N@'otese que la expresi@'on @code{(widen)} viene entre las formas
especiales @code{save-restriction} y @code{save-excursion}. Cuando se
escribe las dos expresiones @code{save- @dots{}} en secuencia, escribe
@code{save-excursion} finalmente.)

@need 1200
Las @'ultimas dos l@'{@dotless{i}}neas de la funci@'on
@code{what-line} son funciones para contar el n@'umero de
l@'{@dotless{i}}neas en el b@'uffer y entonces imprimir el n@'umero en
el @'area echo.

@smallexample
@group
(message "Line %d"
         (1+ (count-lines 1 (point)))))))
@end group
@end smallexample

La funci@'on @code{message} imprime un mensaje de una
l@'{@dotless{i}}nea abajo de la pantalla Emacs. El primer argumento
est@'a dentro de marcas de cita y est@'a impreso como una cadena de
caracteres. Sin embargo, se puede contener una expresi@'on @samp{%d}
para imprimir un argumento siguiente. @samp{%d} imprime el argumento
como un decimal, as@'{@dotless{i}} el mensaje dir@'a alguna cosa tal
como @samp{L@'{@dotless{i}}nea 243}.

@need 1200
El n@'umero que est@'a impreso en lugar de @samp{%d} est@'a computada
por la @'ultima l@'{@dotless{i}}nea de la funci@'on:

@smallexample
(1+ (count-lines 1 (point)))
@end smallexample

@ignore
GNU Emacs 22

(defun count-lines (start end)
  "Return number of lines between START and END.
This is usually the number of newlines between them,
but can be one more if START is not equal to END
and the greater of them is not at the start of a line."
  (save-excursion
    (save-restriction
      (narrow-to-region start end)
      (goto-char (point-min))
      (if (eq selective-display t)
          (save-match-data
            (let ((done 0))
              (while (re-search-forward "[\n\C-m]" nil t 40)
                (setq done (+ 40 done)))
              (while (re-search-forward "[\n\C-m]" nil t 1)
                (setq done (+ 1 done)))
              (goto-char (point-max))
              (if (and (/= start end)
                       (not (bolp)))
                  (1+ done)
                done)))
        (- (buffer-size) (forward-line (buffer-size)))))))
@end ignore

@noindent
Lo que esto hace es contar las l@'{@dotless{i}}neas entre la primera
posici@'on del b@'uffer indicada por el @code{1}, y el
@code{(point)}, y entonces se a@~nade uno a este n@'umero. (La funci@'on
@code{1+} a@~nade uno a su argumento.) Se a@~nade a eso porque
la l@'{@dotless{i}}nea 2 tiene solo una l@'{@dotless{i}}nea antes, y
@code{count-lines} cuenta solo las l@'{@dotless{i}}neas @emph{antes}
de la l@'{@dotless{i}}nea actual.

Despu@'es de que @code{count-lines} ha hecho su trabajo, y el mensaje
ha sido impreso en el @'area echo, la funci@'on @code{save-excursion}
restaura punto y marca a sus posiciones originales; y
@code{save-restriction} restaura la contracci@'on original, si la hay.

@node Ejercicio narrow
@section Ejercicio de encoger

Escribe una funci@'on que mostrar@'a los primeros 60 caracteres del
b@'uffer actual, incluso si se ha encogido el b@'uffer a su mitad
as@'{@dotless{i}} que la primera l@'{@dotless{i}}nea es
inaccesible. Restaura punto, marca y encogimiento. Para este
ejercicio, se necesita usa un popurri entero de funciones, incluyendo
@code{save-restriction}, @code{widen}, @code{goto-char},
@code{point-min}, @code{message}, y @code{buffer-substring}.

@cindex Propiedades, menci@'on de @code{buffer-substring-no-properties}
(@code{buffer-substring} es una funci@'on previamente no mencionada
que tendr@'a que investigarla cada cual por uno mismo; o quiz@'as
tendr@'a que usarse @code{buffer-substring-no-properties} o
@code{filter-buffer-substring} @dots{}, o todav@'{@dotless{i}}a otras
funciones. Las propiedades de texto son una funcionalidad que de otro
modo no ser@'{@dotless{i}}an discutidas aqu@'{@dotless{i}}.
@xref{Propiedades de Texto, , Propiedades de
Texto, elisp, El Manual de Referencia de Emacs Lisp}.)

Adem@'as, @questiondown{}realmente se necesita @code{goto-char} o
@code{point-min}?
@questiondown{}O se puede escribir la funci@'on sin ellos?

@node Car cdr y cons
@chapter @code{car}, @code{cdr}, @code{cons}: Funciones fundamentales
@findex car, @r{introducido}
@findex cdr, @r{introducido}

En Lisp, @code{car}, @code{cdr}, y @code{cons} son funciones
fundamentales. La funci@'on @code{cons} es usada para construir
listas, y las funciones @code{car} y @code{cdr} son usadas para
tomarlas aparte.

En el paseo guiado a trav@'es de la funci@'on
@code{copy-region-as-kill}, se ver@'a @code{cons} tan bien como dos
variantes de @code{cdr}, llamadas @code{setcdr} y
@code{nthcdr}. (@xref{copy-region-as-kill}.)

@menu
* Nombres extra@~nos::       Un lado hist@'orico: @questiondown{}por qu@'e 
                               los nombres extra@~nos?
* car y cdr::                Funciones para extraer parte de una lista.
* cons::                     Construyendo una lista.
* nthcdr::                   Llamando @code{cdr} repetidamente.
* nth::                      nth
* setcar::                   Cambiando el primer elemento de una lista.
* setcdr::                   Cambiando el resto de una lista.
* Ejercicio cons::           Ejercicio cons
@end menu

@ifnottex
@node Nombres extra@~nos
@unnumberedsec Nombres extra@~nos
@end ifnottex

El nombre de la funci@'on @code{cons} es razonable: es una
abreviaci@'on de la palabra `constructo'. Los or@'{@dotless{i}}genes
de los nombres @code{car} y @code{cdr}, por otro lado, son
esot@'ericos: @code{car} es un acr@'onimo de la frase `Contenidos de
la parte de la Direcci@'on del Registro'; y @code{cdr} (pronunciado
`could-er') es un acr@'onimo de la frase `Contenidos del Decremento
del Registro'. Estas frases se refieren a piezas
espec@'{@dotless{i}}ficas de hardware en el ordenador en el que el
Lisp original fu@'e desarrollado. El resto de frases han sido
completamente irrelevantes por m@'as de 25 a@~nos a cualquiera
pensando acerca de Lisp. Ninguno, excepto unos pocos acad@'emicos
valientes han empezado a usar nombres m@'as razonables para estas
funciones, los viejos t@'erminos est@'an todav@'{@dotless{i}}a en
uso. En particular, los t@'erminos usados en el c@'odigo fuente Emacs
Lisp, que usaremos en esta introducci@'on.

@node car y cdr
@section @code{car} y @code{cdr}

El @sc{car} de una lista es, bastante simple, el primer
@'{@dotless{i}}tem en la lista. De este modo, el @sc{car} de la lista
@code{(rosa violeta margarita bot@'ondeoro)} es @code{rosa}.

@need 1200
Si est@'a leyendo en Info y en GNU Emacs, se puede ver esto evaluando
lo siguiente:

@smallexample
(car '(rosa violeta margarita bot@'ondeoro))
@end smallexample

@noindent
Despu@'es de evaluar la expresi@'on, @code{rosa} aparecer@'a en el
@'area echo.

Claramente, un nombre m@'as razonable para la funci@'on @code{car}
ser@'{@dotless{i}}a @code{first} y esto es con frecuencia lo que se
sugiere.

@code{car} no elimina el primer @'{@dotless{i}}tem de la lista; solo
se informa de lo que hay. Despu@'es de que @code{car} se haya aplicado a
una lista, la lista es todav@'{@dotless{i}}a la misma que era. En la
jerga, @code{car} es `no-destructiva'. Esta funcionalidad deja de ser
importante.

El @sc{cdr} de una lista es el resto de la lista, que es, la funci@'on
@code{cdr} que devuelve la parte de la lista que sigue el primer
@'{@dotless{i}}tem. De este modo, mientras el @sc{car} de la lista
@code{'(rosa violeta margarita bot@'ondeoro)} es @code{rosa}, el resto
de la lista, el valor devuelto por la funci@'on @code{cdr}, es
@code{(violeta margarita bot@'ondeoro)}.

@need 800
Se puede ver esto evaluando lo siguiente del modo usual:

@smallexample
(cdr '(rosa violeta margarita bot@'ondeoro))
@end smallexample

@noindent
Cuando se eval@'ua esto, @code{(violeta margarita bot@'ondeoro)}
aparecer@'a en el @'area echo.

Al igual que @code{car}, @code{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@'erprete Lisp
intentar@'{@dotless{i}}a evaluar la lista llamando a @code{rosa} como
una funci@'on. En este ejemplo, no queremos hacer esto.

Claramente, un nombre m@'as razonable para @code{cdr}
ser@'{@dotless{i}}a @code{rest}.

(Hay una lecci@'on aqu@'{@dotless{i}}: cuando se nombran nuevas
funciones, considere muy cuidadosamente lo que se est@'a haciendo, ya
que puede estar pegadas con los nombres largos que se esperan. La
raz@'on es que este documento perpet@'ua estos nombres que el
c@'odigo fuente de Emacs Lisp usa, y si no los usaba, se
estar@'{@dotless{i}}a un duro rato leyendo el c@'odigo; pero, por
favor, se debe intentar evitar usar estos t@'erminos por uno
mismo. Las personas que vengan despu@'es se lo agradecer@'an.

Cuando @code{car} y @code{cdr} se aplica a una lista hecha de
s@'{@dotless{i}}mbolos, tal como la lista @code{(pino roble abeto
arce)}, el elemento de la lista devuelta por la funci@'on @code{car}
es el s@'{@dotless{i}}mbolo @code{pino} sin cualquier par@'entesis
alrededor. @code{pino} es el primer elemento en la lista. Sin embargo,
el @sc{cdr} de la lista es una lista por s@'{@dotless{i}} misma,
@code{(roble abeto arce)}, como se puede ver evaluando las siguientes
expresiones en el modo usual:

@smallexample
@group
(car '(pino roble abeto arce))

(cdr '(pino roble abeto arce))
@end group
@end smallexample

Por otro lado, en una lista de listas, el primer elemento es en
s@'{@dotless{i}} mismo una lista. @code{char} devuelve este primer
elemento como una lista. Por ejemplo, la siguiente lista contiene tres
sublistas, una lista de carn@'{@dotless{i}}voros, una lista de
herb@'{@dotless{i}}voros y una lista de mam@'{@dotless{i}}feros:

@smallexample
@group
(car '((leon tigre leopardo)
       (gacela antilope cebra)
       (ballena delfin foca)))
@end group
@end smallexample

@noindent
En este ejemplo, el primer elemento de @sc{car} de la lista es la
lista de carn@'{@dotless{i}}voros, @code{(leon tigre leopardo)}, y el
resto de la lista es @code{((gacela antilope cebra)
(ballena delfin foca))}.

@smallexample
@group
(cdr '((leon tigre leopardo)
       (gacela antilope cebra)
       (ballena delfin)))
@end group
@end smallexample

Es un valor decir de nuevo que @code{car} y @code{cdr} son no
destructivos --- esto es, no se modifican o cambian listas para las
que ser aplicados. Esto es muy importante por c@'omo son usados.

Tambi@'en, en el primer cap@'{@dotless{i}}tulo, en la discusi@'on
acerca de @'atomos, yo dije que en Lisp, ``ciertos tipos de @'atomos,
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 @'atomos de una lista son indivisibles.''
(@xref{@'Atomos Lisp}.) El @code{car} y el @code{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 @'atomo. De otro modo, la otra
funci@'on fundamental, @code{cons}, se puede poner cerca o construir
una lista, pero no un array. (Los arrays son manejados por funciones de
array espec@'{@dotless{i}}ficas. @xref{Arrays, , Arrays, elisp, El
Manual de Referencia de GNU Emacs Lisp}.)

@node cons
@section @code{cons}
@findex cons, @r{introducido}

La funci@'on @code{cons} construye listas; eso es lo inverso de
@code{car} y @code{cdr}. Por ejemplo, @code{cons} puede usarse para
crear una lista de cuatro elementos desde los tres elementos de la
lista, @code{(abeto roble arce)}:

@smallexample
(cons 'pino '(abeto roble arce))
@end smallexample

@need 800
@noindent
Despu@'es de evaluar esto, se ver@'a lo siguiente:

@smallexample
(pino abeto roble arce)
@end smallexample

@noindent
aparece en el @'area echo. @code{cons} causa la creaci@'on de una
nueva lista en el que el elemento es seguido por los elementos de la
lista original.

Con frecuencia decimos que `@code{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 @code{cons} no cambia
a una lista existente, pero crea una nueva.

Como @code{car} y @code{cdr}, @code{cons} es no destructivo.

@menu
* Construir una lista::      Construir una lista
* length::                   C@'omo encontrar el tama@~no de una lista.
@end menu

@ifnottex
@node Construir una lista
@unnumberedsubsec Construir una lista
@end ifnottex

@code{cons} debe tener una lista para adjuntar a@footnote{Actualmente,
se puede @code{cons} un elemento para un @'atomo para producir a para
punteado. Los pares punteados no se discuten aqu@'{@dotless{i}}; ver
@ref{Notaci@'on de Pares Punteados, , Notaci@'on de Para Punteado,
elisp, El Manual de Referencia de GNU Emacs Lisp}.} No se puede
empezar desde absolutamente nada. Si se est@'a construyendo una lista,
se necesita proveer al menos una lista vac@'{@dotless{i}}a al
principio. Aqu@'{@dotless{i}} hay una serie de expresiones @code{cons}
que construyen una lista de flores. Si est@'a 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@'es de @samp{@result{}},
que puede leer como `eval@'uas para'.

@smallexample
@group
(cons 'bot@'ondeoro ())
     @result{} (bot@'ondeoro)
@end group

@group
(cons 'margarita '(bot@'ondeoro))
     @result{} (margarita bot@'ondeoro)
@end group

@group
(cons 'violeta '(margarita bot@'ondeoro))
     @result{} (violeta margarita bot@'ondeoro)
@end group

@group
(cons 'rosa '(violeta margarita bot@'ondeoro))
     @result{} (rosa violeta margarita bot@'ondeoro)
@end group
@end smallexample

@noindent
En el primer ejemplo, la lista vac@'{@dotless{i}}a se muestra como
@code{()} y despu@'es se construye una lista de @code{bot@'ondeoro}
seguida por la lista vac@'{@dotless{i}}a. Como se puede ver, la lista
vac@'{@dotless{i}}a no se muestra en la lista que fu@'e
construida. Todo lo que se ve es @code{(bot@'ondeoro)}. La lista
vac@'{@dotless{i}}a no cuenta como un elemento de una lista porque
no hay nada en una lista vac@'{@dotless{i}}a. Generalmente hablando,
una lista vac@'{@dotless{i}}a es invisible.

El segundo ejemplo, @code{(cons 'margarita '(bot@'ondeoro))} construye
una nueva lista de dos elemento poniendo @code{margarita} en frente de
@code{bot@'ondeoro}; y el tercer ejemplo construye una lista de tres
elementos poniendo @code{violeta} en frente de @code{margarita} y
@code{bot@'ondeoro}.

@node length
@subsection Encuentra el tama@~no de una lista: @code{length}
@findex length

Se pueden encontrar cu@'antos elementos hay en una lista usando la
funci@'on Lisp @code{length}, como en los siguientes ejemplos:

@smallexample
@group
(length '(bot@'ondeoro))
     @result{} 1
@end group

@group
(length '(margarita bot@'ondeoro))
     @result{} 2
@end group

@group
(length (cons 'violeta '(margarita bot@'ondeoro)))
     @result{} 3
@end group
@end smallexample

@noindent
En el tercer ejemplo, la funci@'on @code{cons} es usada para construir
una lista de tres elementos que entonces se pasa a la funci@'on
@code{length} como su argumento.

@need 1200
Se puede tambi@'en usar @code{length} para contar el n@'umero de
elementos en una lista vac@'{@dotless{i}}a:

@smallexample
@group
(length ())
     @result{} 0
@end group
@end smallexample

@noindent
Como se esperar@'{@dotless{i}}a, el n@'umero de elementos en una lista
vac@'{@dotless{i}}a es cero.

Un experimento interesante es encontrar qu@'e ocurre si se intenta
encontrar el tama@~no de una no lista en todo; que es, si se intenta
llamar a @code{length} sin darle un argumento, incluso una lista no
vac@'{@dotless{i}}a:

@smallexample
(length )
@end smallexample

@need 800
@noindent
Lo que se ve, si se eval@'ua esto, es el mensaje de error

@smallexample
Lisp error: (wrong-number-of-arguments length 0)
@end smallexample

@noindent
Esto significa que la funci@'on recibe el n@'umero incorrecto de
argumentos, cero, cuando se espera alg@'un otro n@'umero de
argumentos. En este caso, se espera un argumento, el argumento de una
lista cuyo tama@~no de la funci@'on se est@'a midiendo. (N@'otese que
@emph{una} lista es @emph{un} argumento, incluso si la lista tiene
muchos elementos dentro.)

La parte del mensaje de error que dice @samp{length} es el nombre de la
funci@'on.

@ignore
@code{length} is still a subroutine, but you need C-h f to discover that.

In an earlier version:
    This is written with a special notation, @samp{#<subr},
    that indicates that the function @code{length} is one of the primitive
    functions written in C rather than in Emacs Lisp.  (@samp{subr} is an
    abbreviation for `subroutine'.)  @xref{What Is a Function, , What Is a
    Function?, elisp , The GNU Emacs Lisp Reference Manual}, for more
    about subroutines.
@end ignore

@node nthcdr
@section @code{nthcdr}
@findex nthcdr

La funci@'on @code{nthcdr} est@'a asociada con la funci@'on
@code{cdr}. Que lo que hace es tomar la @sc{cdr} de una lista repetidamente.

Si se toma el @sc{cdr} de la lista @code{(pino roble abeto arce)},
ser@'a devuelta la lista @code{(roble abeto arce)}. Si se repite esto en
lo que se devolvi@'o, se devolver@'a lista lista @code{(abeto
arce)}. (De acuerdo, se repite @sc{cdr} en la lista original solo se
dar@'a @sc{cdr} desde la funci@'on que no cambia la lista. Se necesita
evaluar el @sc{cdr} del @sc{cdr} y as@'{@dotless{i}}.) Si se conti@'ua
esto, finalmente ser@'a devuelta una lista vac@'{@dotless{i}}a, que en
este caso, en vez de ser mostrada como @code{()} es mostrado como
@code{nil}.

@need 1200
Para revisar, aqu@'{@dotless{i}} hay una serie de @sc{cdr}s repetidos,
el siguiente @samp{@result{}} muestra lo que se devuelve.

@smallexample
@group
(cdr '(pino roble abeto arce))
     @result{}(roble abeto arce)
@end group

@group
(cdr '(roble abeto arce))
     @result{} (abeto arce)
@end group

@group
(cdr '(abeto arce))
     @result{}(arce)
@end group

@group
(cdr '(arce))
     @result{} nil
@end group

@group
(cdr 'nil)
     @result{} nil
@end group

@group
(cdr ())
     @result{} nil
@end group
@end smallexample

@need 1200
Tambi@'en se pueden hacer varios @sc{cdr}s sin imprimir los valores
as@'{@dotless{i}}:

@smallexample
@group
(cdr (cdr '(pino roble abeto arce)))
     @result{} (abeto arce)
@end group
@end smallexample

@noindent
En este ejemplo, el int@'erprete Lisp eval@'ua la lista propia
dentro. La lista de dentro est@'a entre comillas, as@'{@dotless{i}} solo
pasa la lista del @code{cdr} m@'as interno. Este @code{cdr}
pasa una lista hecho del segundo y subsiguientes elementos de la lista
al @code{cdr} m@'as externo, que produce una lista compuesta del tercer y
subsiguientes elementos de la lista original. En este ejemplo, la
funci@'on @code{cdr} se repite y devuelve una lista que consiste de
la lista original sin sus primeros dos elementos.

La funci@'on @code{nthcdr} hace lo mismo que repitiendo la llamada a
@code{cdr}. En el siguiente ejemplo, el segundo argumento se pasa a la
funci@'on @code{nthcdr}, a trav@'es con la lista, y el valor devuelto
es la lista sin sus primeros dos @'{@dotless{i}}tems, que son
exactamente los mismos dos @code{cdr} en la lista:

@smallexample
@group
(nthcdr 2 '(pino roble abeto arce))
     @result{} (abeto arce)
@end group
@end smallexample

@need 1200
Usando la lista original de cuatro elementos, se puede ver qu@'e
ocurre cuando varios argumentos num@'ericos son pasados a @code{nthcdr},
incluyendo 0, 1, y 5:

@smallexample
@group
;; @r{Deja la lista como estaba.}
(nthcdr 0 '(pine fir oak maple))
     @result{} (pino roble abeto arce)
@end group

@group
;; @r{Devuelve una copia sin el primer elemento.}
(nthcdr 1 '(pine fir oak maple))
     @result{} (fir oak maple)
@end group

@group
;; @r{Devuelve una copia de la lista sin tres elementos.}
(nthcdr 3 '(pine fir oak maple))
     @result{} (maple)
@end group

@group
;; @r{Devuelve la lista faltando los cuatro elementos.}
(nthcdr 4 '(pine fir oak maple))
     @result{} nil
@end group

@group
;; @r{Devuelve una copia sin los elementos.}
(nthcdr 5 '(pine fir oak maple))
     @result{} nil
@end group
@end smallexample

@node nth
@section @code{nth}
@findex nth

La funci@'on @code{nthcdr} toma el @sc{cdr} de una lista
repetidamente. La funci@'on @code{nth} toma el @sc{car} del resultado
devuelto por @code{nthcdr}. Devuelve el elemento Nth de la lista.

@need 1500
De este modo, si no fuera definido en C para velocidad, la
definici@'on de @code{nth} ser@'{@dotless{i}}a:

@smallexample
@group
(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)))
@end group
@end smallexample

@noindent
(Originalmente, @code{nth} fu@'e definido en Emacs Lisp en
@file{subr.el}, pero su definici@'on fu@'e rehecha en C en los 1980s.)

La funci@'on @code{nth} devuelve un elemento simple de una lista. Esto
puede ser muy conveniente.

N@'otese que los elementos son numerados desde cero, no desde uno. Es
decir, el primer elemento de una lista, su @sc{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@'umero uno, eso es `basado en uno'.

@need 1250
Por ejemplo:

@smallexample
@group
(nth 0 '("uno" "dos" "tres"))
    @result{} "uno"

(nth 1 '("uno" "dos" "tres"))
    @result{} "dos"
@end group
@end smallexample

Es valorable mencionar que @code{nth}, como @code{nthcdr} y
@code{cdr}, no cambia la lista original --- la funci@'on no es
destructiva. En contraste con las funciones @code{setcar} y
@code{setcdr}.

@node setcar
@section @code{setcar}
@findex setcar

Como se podr@'{@dotless{i}}a adivinar desde sus nombres, las funciones
@code{setcar} y @code{setcdr} asignan el @sc{car} o la @sc{cdr} de una
lista a un nuevo valor. Ellos actualmente cambia la lista original, no
como @code{car} y @code{cdr} que deja la lista original como
estaba. Un camino para encontrar c@'omo esto funciona es
experimentar. Se comenzar@'a con la funci@'on @code{setcar}.

@need 1200
Primero, podemos crear una lista y entonces asignar el valor de una
variable a la lista usando la funci@'on
@code{setq}. Aqu@'{@dotless{i}} hay una lista de animales:

@smallexample
(setq animales '(antilope jirafa leon tigre))
@end smallexample

@noindent
Si est@'a leyendo esto en Info dentro de GNU Emacs, se puede evaluar
esta expresi@'on del modo usual, posicionando el cursor despu@'es de
la expresi@'on y escribiendo @kbd{C-x C-e}. Esto es una de las
ventajas de tener el int@'erprete construido dentro del entorno de
computaci@'on. Incidentalmente, cuando no hay nada en la
l@'{@dotless{i}}nea despu@'es del par@'entesis final, tal como un
comentario, el punto puede estar en la siguiente
l@'{@dotless{i}}nea. De este modo, si tu cursor est@'a en la primera
columna de la siguiente l@'{@dotless{i}}nea, no se necesita mover. En
realidad, Emacs permite cualquier cantidad de espacio en blanco
despu@'es del par@'entesis final.)

@need 1200
Cuando se eval@'ua la variable @code{animal}, vemos que est@'a
asociada a la lista @code{(antelope giraffer lion tiger)}:

@smallexample
@group
animales
     @result{} (antilope jirafa leon tigre)
@end group
@end smallexample

@noindent
Por otro lado, la variable @code{animales} apunta a la lista
@code{(antilope jirafa leon tigre)}.

Lo siguiente, es evaluar la funci@'on @code{setcar} mientras le pasa
dos argumentos, la variable @code{animales} y el s@'{@dotless{i}}mbolo
citado @code{hipopotamo}; esto se hace escribiendo la lista de tres
elementos @code{(setcar animales 'hipopotamo)} y entonces evaluando
en el modo usual:

@smallexample
(setcar animales 'hipopotamo)
@end smallexample

@need 1200
@noindent
Despu@'es de evaluar esta expresi@'on, eval@'ua la variable
@code{animales} de nuevo. Se puede ver que la lista de animales ha
cambiado:

@smallexample
@group
animales
     @result{} (hipop@'otamo jirafa leon tigre)
@end group
@end smallexample

@noindent
El primer elemento en la lista, @code{antilope} se reemplaza por
@code{hipopotamo}.

As@'{@dotless{i}} se puede ver que @code{setcar} no a@~nadi@'o un
nuevo elemento a la lista como @code{cons} tendr@'{@dotless{i}}a; eso
reemplaz@'o @code{ant@'{@dotless{i}}lope} con @code{hipop@'otamo}; eso
@emph{cambi@'o} la lista.

@node setcdr
@section @code{setcdr}
@findex setcdr

La funci@'on @code{setcdr} es similar a la funci@'on @code{setcar},
excepto que la funci@'on reemplaza el segundo y subsiguientes
elementos de una lista en vez del primer elemento.

(Para ver c@'omo se cambia el @'ultimo elemento de una lista, mira hacia
delante a la @ref{Funci@'on kill-new, , La funci@'on @code{kill-new}},
que usa las funciones @code{nthcdr} y @code{setcdr}.)

@need 1200
Para ver c@'omo esto funciona, asigna el valor de la variable a una
lista de animales domesticados evaluando la siguiente expresi@'on:

@smallexample
(setq animales-domesticos '(caballo vaca oveja cabra))
@end smallexample

@need 1200
@noindent
Si ahora se eval@'ua la lista, lo que se devuelve es @code{(caballo
vaca oveja cabra)}:

@smallexample
@group
animales-domesticos
     @result{} (caballo vaca oveja cabra)
@end group
@end smallexample

@need 1200
Lo siguiente, eval@'ua @code{setcdr} con dos argumentos, el nombre de la
variable que tiene una lista como su valor, y la lista para la que el
@sc{cdr} de la primera lista sea asignada;

@smallexample
(setcdr animales-domesticos '(gato perro))
@end smallexample

@noindent
Si se eval@'ua esta expresi@'on, la lista @code{(gato perro)} aparecer@'a
en el @'area echo. Este es el valor devuelto por la funci@'on. El
resultado en el que estamos interesados es el ``efecto lateral'', que
se puede ver evaluando la variable @code{domesticated-animals}:

@smallexample
@group
animales-domesticos
     @result{} (caballo gato perro)
@end group
@end smallexample

@noindent
En realidad, la lista es cambiada desde @code{(caballo vaca oveja cabra)}
a @code{(caballo gato perro)}. El @sc{cdr} de la lista es cambiada desde
@code{(vaca oveja cabra)} a @code{(gato perro)}.

@node Ejercicio cons
@section Ejercicio

Construye una lista de cuatro p@'ajaros evaluando varias expresiones
con @code{cons}. Encuentra que ocurre cuando @code{cons} una lista
dentro de s@'{@dotless{i}}. Reemplaza el primer elemento de la lista
de cuatro p@'ajaros con un pez. Reemplaza el resto de esta lista con
una lista de otro pez.

@node Cortando y almacenando texto
@chapter Cortando y almacenando texto
@cindex Cortando y almacenando texto
@cindex Almacenando y cortando texto
@cindex Cortando texto
@cindex Copiando texto
@cindex Borrando texto
@cindex Borrando texto

Siempre y cuando se corte o pegue texto de un b@'uffer con un comando
`kill' en GNU Emacs, se almacenar@'a dentro de una lista que se puede
traer con un comando `yank'.

(El uso de la palabra `kill' @emph{matar, cortar} en Emacs para
procesos que espec@'{@dotless{i}}ficamente @emph{no} destruyen los
valores de las entidades es un accidente hist@'orico desafortunado. Una
palabra mucho m@'as apropiada deber@'{@dotless{i}}a ser `clip'
@emph{cortar} puesto que es lo que los comandos de corte hacen; ellos
cortan texto fuera de un b@'uffer y lo ponen dentro del almacenamiento
desde el que puede traerse. Con frecuencia ha sido tentada de
reemplazar globalmente todas las ocurrencia de `kill' @emph{matar,
cortar} en las fuentes de Emacs con `clip' @emph{cortar} y todas las
ocurrencias de `killed' @emph{cortado, muerto} con `clipped'
@emph{cortado}.)

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

@ifnottex
@node Almacenando Texto
@unnumberedsec Almacenando texto en una lista
@end ifnottex

Cuando el texto se corta de un b@'uffer, es almacenado en una
lista. Piezas sucesivas de texto se almacenan en la lista
sucesivamente, as@'{@dotless{i}} la lista podr@'{@dotless{i}}a verse
as@'{@dotless{i}}:

@smallexample
("una pieza de texto" "pieza previa")
@end smallexample

@need 1200
@noindent
La funci@'on @code{cons} puede usarse para crear una nueva lista
desde una pieza de texto (un `@'atomo', para usar la jerga) y una
lista existente, como esta:

@smallexample
@group
(cons "otra pieza"
      '("una pieza de texto" "pieza previa"))
@end group
@end smallexample

@need 1200
@noindent
Si se eval@'ua esta expresi@'on, una lista de tres elementos
aparecer@'a en el @'area echo:

@smallexample
("otra pieza" "una pieza de texto" "pieza previa")
@end smallexample

Con las funciones @code{car} y @code{nthcdr}, se puede recuperar
siempre la pieza de texto que se quiere. Por ejemplo, en el siguiente
c@'odigo, @code{nthcdr 1 @dots{}} devuelve la lista con el primer
@'{@dotless{i}}tem eliminado; y el @code{car} devuelve el primer
elemento de este resto --- el segundo elemento de la lista
original:

@smallexample
@group
(car (nthcdr 1 '("otra pieza"
                 "una pieza de texto"
                 "pieza previa")))
     @result{} "una pieza de texto"
@end group
@end smallexample

Las funciones actuales en Emacs son m@'as complejas que esto, de
acuerdo. El c@'odigo para cortar y recuperar texto tiene que ser
escrito de modo que Emacs pueda ver qu@'e elemento en la lista se
quiere --- el primer, segundo, tercer o cualquier otro. Adem@'as,
cuando tiene el fin de la lista, Emacs dar@'{@dotless{i}}a el primer
elemento de la lista, en lugar de nada.

La lista que maneja las piezas de texto se llama @dfn{kill ring}
(anillo de la muerte). Este cap@'{@dotless{i}}tulo lidera una
descripci@'on del anillo de la muerte y como eso se usa por la
primera traza de c@'omo la funci@'on @code{zap-to-char} funciona. Esta
funci@'on usa (o `llama') a una funci@'on que invoca a otra funci@'on
que manipula el anillo de la muerte. De este modo, antes de lograr las
monta@~nas, se escalan las colinas.

Un cap@'{@dotless{i}}tulo subsiguiente describe c@'omo el texto que se
corta desde el b@'uffer se recupera. @xref{Pegando, , Pegando Texto}.

@node zap-to-char
@section @code{zap-to-char}
@findex zap-to-char

@c FIXME remove obsolete stuff
La funci@'on @code{zap-to-char} cambi@'o poco entre GNU Emacs
versi@'on 19 y GNU Emacs versi@'on 22. Sin embargo, @code{zap-to-char}
llama a otra funci@'on, @code{kill-region}, que se reescribi@'o m@'as.

La funci@'on @code{kill-region} en Emacs 19 es compleja, pero no usa
c@'odigo que es importante en este momento. Se obviar@'a.

La funci@'on @code{kill-region} en Emacs 22 es m@'as de f@'acil leer
que la misma funci@'on en Emacs 19 e introduce un concepto muy
importante, que el error maneja. Nosotros pasearemos a trav@'es de la
funci@'on.

Pero primero, d@'ejanos ver en la funci@'on interactive @code{zap-to-char}.

@menu
* Completar zap-to-char::    La implementaci@'on completa.
* zap-to-char interactivo::  Una expresi@'on interactiva de tres partes.
* cuerpo zap-to-char::       Un resumen corto
* search-forward::           C@'omo buscar una cadena.
* progn::                    La forma especial @code{progn}.
* Resumiendo zap-to-char::   Usando @code{point} y @code{search-forward}.
@end menu

@ifnottex
@node Completar zap-to-char
@unnumberedsubsec La implementaci@'on completa @code{zap-to-char}
@end ifnottex

La funci@'on @code{zap-to-char} elimina el texto en la regi@'on entre
la localizaci@'on del curso (por ej. punto) para incluir la siguiente
ocurrencia de un caracter espec@'{@dotless{i}}fico. El texto que
@code{zap-to-char} borra es puesto en el kill ring @emph{anillo de la
muerte}; y puede ser recuperado desde el kill ring @emph{anillo de la
muerte} escribiendo @kbd{C-y} (@code{yank}). Si el comando dado es un
argumento, eso borra texto a trav@'es de este n@'umero de
ocurrencias. De este modo, si el cursor estuviera al principio de esta
frase y el car@'acter fuera @samp{s}, @samp{De este modo}
ser@'{@dotless{i}}a borrado. Si el argumento fueran dos, @samp{De este
modo, si el cursor} se borrase, y incluir@'{@dotless{i}}a la @samp{s}
en el @samp{cursor}.

Si el car@'acter espec@'{@dotless{i}}fico no encuentra @code{zap-to-char}
dir@'a ``B@'usqueda fallida'', eso cuenta el car@'acter que se
escribi@'o, y no elimin@'o cualquier texto.

En orden para determinar cu@'anto texto eliminar @code{zap-to-char} usa
una funci@'on de b@'usqueda. Las b@'usquedas son usadas extensivamente
en el c@'odigo que manipula texto, y focalizar@'a la atenci@'on en
ellos tan bien como el comando de borrado.

@ignore
@c GNU Emacs version 19
(defun zap-to-char (arg char)  ; version 19 implementation
  "Kill up to and including ARG'th occurrence of CHAR.
Goes backward if ARG is negative; error if CHAR not found."
  (interactive "*p\ncZap to char: ")
  (kill-region (point)
               (progn
                 (search-forward
                  (char-to-string char) nil nil arg)
                 (point))))
@end ignore

@need 1250
Aqu@'{@dotless{i}} est@'a el texto completo de la versi@'on 22 de la
funci@'on:

@c GNU Emacs 22
@smallexample
@group
(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@'uffer actual.
Para ir atr@'as 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))))
@end group
@end smallexample

La documentaci@'on es en l@'{@dotless{i}}nea. Se necesita conocer el
significado de la jerga de la palabra `kill'.

@node zap-to-char interactivo
@subsection La expresi@'on @code{interactive}

@need 800
La expresi@'on interactiva en el comando @code{zap-to-char} se ve
as@'{@dotless{i}}:

@smallexample
(interactive "p\ncZap to char: ")
@end smallexample

La parte con comillas, @code{"p\ncZap to char:@: "} @emph{Cortar a
caracter}, especifica dos cosas diferentes. Primero, y m@'as simple es
el @samp{p}. Este parte se separa desde la siguiente parte por una
nueva l@'{@dotless{i}}nea, @samp{\n}. El @samp{p} significa que la
parte del primero argumento a la funci@'on ser@'a pasando el valor de
un `prefijo procesado'. El argumento prefijo es pasado escribiendo
@kbd{C-u} y un n@'umero, o @kbd{M-} y un n@'umero. Si la funci@'on es
llamada interactivamente sin un prefijo, el n@'umero que se pasa es 1.

La segunda parte de @code{"p\ncZap a caracter:@: "} es @samp{cZap a
car@'acter:@:}. En esta parte, la tecla baja @samp{c} indica que
@code{interactive} espera una consola que el argumento ser@'a un
caracter. La consola sigue el @samp{c} y es la cadena @samp{Zap a
caracter:@: } (con un espacio despu@'es del punto y coma para hacerlo
bien).

Todo lo que se hace es preparar los argumentos para @code{zap-to-char}
as@'{@dotless{i}} est@'an en el tipo correcto, y dan al usuario un
prompt.

En un b@'uffer de solo lectura, la funci@'on @code{zap-to-char} copia
el texto al anillo de la muerte, no se elimina. El @'area echo muestra
un mensaje diciendo que el b@'uffer es de solo lectura. Tambi@'en, la
terminal avisa con un pitido.

@node cuerpo zap-to-char
@subsection El cuerpo de @code{zap-to-char}

El cuerpo de la funci@'on @code{zap-to-char} contiene el c@'odigo que
mata (que se borra/corta) el texto en la regi@'on desde la posici@'on
actual del cursor e incluyendo el car@'acter especificado.

La primera parte del c@'odigo se ve como:

@smallexample
(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)))
@end smallexample

@noindent
@code{char-table-p} es una funci@'on prescrita no vista. Eso determina
si sus argumentos son una tabla de caracteres. As@'{@dotless{i}}, se
asigna el car@'acter pasado a @code{zap-to-char} a uno de ellos, si
este car@'acter existe, o al car@'acter en s@'{@dotless{i}}. (Esto
llega a ser importante para ciertos caracteres en lenguajes no
Europeos. La funci@'on @code{aref} extrae un elemento desde un
array. Eso es una funci@'on espec@'{@dotless{i}}fica de array que no
est@'a descrita en este documento. @xref{Array, , Arrays, elisp, El
Manual de Referencia de GNU Emacs Lisp}.)

@noindent
Lo que devuelve @code{(point)} es la posici@'on actual del cursor.

La siguiente parte del c@'odigo es una expresi@'on usando
@code{progn}. El cuerpo del @code{progn} se basa en llamadas a
@code{search-forward} y @code{point}.

Es f@'acil comprender c@'omo @code{progn} funciona despu@'es de aprender
acerca de @code{search-forward}, as@'{@dotless{i}} se ver@'a en
@code{search-forward} y entonces en @code{progn}.

@node search-forward
@subsection La funci@'on @code{search-forward}
@findex search-forward

La funci@'on @code{search-forward} se usa para localizar el
zapped-for-character en @code{zap-to-char}. Si la b@'usqueda es
exitosa, @code{search-forward} deja el punto inmediatamente despu@'es
del @'ultimo car@'acter en la cadena objetivo. (En @code{zap-to-char},
la cadena objetivo es solo un car@'acter largo. @code{zap-to-char} usa
la funci@'on @code{char-to-string} para asegurar que el ordenador
trata este car@'acter como una cadena). Si la b@'usqueda es hacia
atr@'as, @code{search-forward} deja el punto solo antes del primer
car@'acter en el objetivo. Tambi@'en, @code{search-forward} devuelve
@code{t} para verdad. (Moviendo el punto all@'{@dotless{i}} es un
`efecto lateral'.)

@need 1250
En @code{zap-to-char}, la funci@'on @code{search-forward} se ve
as@'{@dotless{i}}:

@smallexample
(search-forward (char-to-string char) nil nil arg)
@end smallexample

La funci@'on @code{search-forward} toma cuatro argumentos:

@enumerate
@item
El primer argumento es el objetivo, para el que es buscado. Esto debe
ser una cadena, tal como @samp{"z"}.

Cuando eso ocurre, el argumento pasado a @code{zap-to-char} es un
caracter simple. Debido a la forma en la que los ordenadores son
construidos, el int@'erprete Lisp puede tratar un caracter simple
siendo diferente desde una cadena de caracteres. Dentro del ordenador,
un caracter simple tiene un formato electr@'onico 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@'on @code{search-forward} busca una cadena, el caracter que la
funci@'on @code{zap-to-char} recibe como argumento debe ser
convertida dentro del ordenador de un formato a otro; de otro modo,
la funci@'on @code{search-forward} fallar@'a. La funci@'on
@code{char-to-string} es usada para hacer esta conversi@'on.

@item
El segundo argumento asocia la b@'usqueda; eso se especifica como
una posici@'on en el b@'uffer. En este caso, la b@'usqueda puede ir al
final del b@'uffer, as@'{@dotless{i}} no se asigna y el segundo
argumento es @code{nil}.

@item
El tercer argumento cuenta la funci@'on que har@'{@dotless{i}}a si la
b@'usqueda cae --- eso puede se@~nalar un error (e imprimir un
mensaje) o puede devolver @code{nil}. Un @code{nil} como tercer
argumento hace que la funci@'on se@~nale un error cuando la b@'usqueda
falla.

@item
El cuarto argumento @code{search-forward} es el contaje repetido ---
cu@'antas ocurrencias de la cadena para buscar. Este argumento es
opcional y si la funci@'on es llamada sin un contaje repetido, este
argumento pasa el valor 1. Si este argumento es negativo, la
b@'usqueda va hacia atr@'as.
@end enumerate

@need 800
En la forma de plantilla, una expresi@'on @code{search-forward} se ve
as@'{@dotless{i}}:

@smallexample
@group
(search-forward "@var{cadena-a-buscar}"
                @var{limite-de-busqueda}
                @var{que-hacer-si-la-busqueda-falla}
                @var{repetir-contaje})
@end group
@end smallexample

Lo siguiente es echar un vistazo a @code{progn}.

@node progn
@subsection La forma especial @code{progn}
@findex progn

@code{progn} es una forma especial que causa que cada uno de sus
argumentos puedan ser evaluados en secuencia y entonces devuelve el valor
del @'ultimo. Las expresiones precedentes son evaluadas solo por los
efectos laterales que ellos desarrollan. Los valores producidos por
ellos son descartados.

@need 800
La plantilla para una expresi@'on @code{progn} es muy simple:

@smallexample
@group
(progn
  @var{body}@dots{})
@end group
@end smallexample

En @code{zap-to-char}, la expresi@'on @code{progn} tiene que hacer dos
cosas: poner el punto en la posici@'on exacta; y devolver la
posici@'on del punto de modo que @code{kill-region} conoce c@'omo de
lejos se copia.

El primer argumento de @code{progn} es @code{search-forward}. Cuando
@code{search-forward} encuentra la cadena, la funci@'on deja el punto
inmediatamente despu@'es del @'ultimo caracter en la cadena
objetivo. (En este caso la cadena objetivo es solo un car@'acter
largo.) Si la b@'usqueda es hacia atr@'as, @code{search-forward} deja
el punto justo antes del primer car@'acter en el objetivo. El
movimiento del punto es un efecto lateral.

El segundo y @'ultimo argumento de @code{progn} es la expresi@'on
@code{(point)}. Esta expresi@'on devuelve el valor del punto, que en
este caso ser@'a la localizaci@'on para la que se ha movido por
@code{search-forward}. (En la fuente, una l@'{@dotless{i}}nea que
cuenta la funci@'on para ir al car@'acter previo, si se est@'a yendo
hacia delante, se coment@'o en 1999; yo no recuerdo si esta
funcionalidad o no funcionalidad era siempre parte de las fuentes
distribuidas.) El valor de @code{point} se devuelve por la expresi@'on
@code{progn} y se pasa a @code{kill-region} como el segundo argumento
de @code{kill-region} .

@node Resumiendo zap-to-char
@subsection Resumiendo @code{zap-to-char}

Ahora que se ha visto c@'omo @code{search-forward} y @code{progn}
trabajan, se puede ver c@'omo la funci@'on @code{zap-to-char}
funciona como un todo.

El primer argumento de @code{kill-region} es la posici@'on del cursor
cuando el comando @code{zap-to-char} da --- el valor del punto en este
momento. Con el @code{progn}, la b@'usqueda de la funci@'on mueve el
punto a solo despu@'es del zapped-to-character y @code{point} devuelve
el valor de localizaci@'on. La funci@'on @code{kill-region} pone junto
a estos dos valores de punto, el primero como el principio de la
regi@'on y el segundo como el fin de la regi@'on, y borra la
regi@'on.

La forma especial @code{progn} se necesita porque el comando
@code{kill-region} toma dos argumentos; y fallar@'{@dotless{i}}a si
@code{search-forward} y expresiones @code{point} fueran escritas en
secuencia como dos argumentos adicionales. La expresi@'on @code{progn}
es un argumento simple para @code{kill-region} y devuelve un valor
para que @code{kill-region} se necesite por su segundo argumento.

@node kill-region
@section @code{kill-region}
@findex kill-region

La funci@'on @code{zap-to-char} usa la funci@'on
@code{kill-region}. Esta funci@'on corta texto desde una regi@'on y
copia este texto al kill ring @emph{anillo de la muerte}, desde el que
puede ser recuperado.

@ignore
GNU Emacs 22:

(defun kill-region (beg end &optional yank-handler)
  "Kill (\"cut\") text between point and mark.
This deletes the text from the buffer and saves it in the kill ring.
The command \\[yank] can retrieve it from there.
\(If you want to kill and then yank immediately, use \\[kill-ring-save].)

If you want to append the killed region to the last killed text,
use \\[append-next-kill] before \\[kill-region].

If the buffer is read-only, Emacs will beep and refrain from deleting
the text, but put the text in the kill ring anyway.  This means that
you can use the killing commands to copy text from a read-only buffer.

This is the primitive for programs to kill text (as opposed to deleting it).
Supply two arguments, character positions indicating the stretch of text
 to be killed.
Any command that calls this function is a \"kill command\".
If the previous command was also a kill command,
the text killed this time appends to the text killed last time
to make one entry in the kill ring.

In Lisp code, optional third arg YANK-HANDLER, if non-nil,
specifies the yank-handler text property to be set on the killed
text.  See `insert-for-yank'."
  ;; Pass point first, then mark, because the order matters
  ;; when calling kill-append.
  (interactive (list (point) (mark)))
  (unless (and beg end)
    (error "The mark is not set now, so there is no region"))
  (condition-case nil
      (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)
              (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)
    ((buffer-read-only text-read-only)
     ;; The code above failed because the buffer, or some of the characters
     ;; in the region, are read-only.
     ;; We should beep, in case the user just isn't aware of this.
     ;; However, there's no harm in putting
     ;; the region's text in the kill ring, anyway.
     (copy-region-as-kill beg end)
     ;; Set this-command now, so it will be set even if we get an error.
     (setq this-command 'kill-region)
     ;; This should barf, if appropriate, and give us the correct error.
     (if kill-read-only-ok
         (progn (message "Read only text copied to kill ring") nil)
       ;; Signal an error if the buffer is read-only.
       (barf-if-buffer-read-only)
       ;; If the buffer isn't read-only, the text is.
       (signal 'text-read-only (list (current-buffer)))))))
@end ignore

Tanto la versi@'on de Emacs 22 de esta funci@'on usa
@code{condition-case} y @code{copy-region-as-kill}, ambas se
explicar@'an. @code{condition-case} es una forma especial importante.

En esencia, la funci@'on @code{kill-region} llama a
@code{condition-case}, que toma tres argumentos. En esta funci@'on, el
primer argumento no hace nada. El segundo argumento contiene el
c@'odigo hace el trabajo cuando todo va bien. El tercer argumento
contiene el c@'odigo que se llama en el evento de un error.

@menu
* Completa kill-region::     La definici@'on de funci@'on.
* condition-case::           Tratando con un problema.
* Macro Lisp::               Macro Lisp
@end menu

@ifnottex
@node Completa kill-region
@unnumberedsubsec La definici@'on completa @code{kill-region}
@end ifnottex

@need 1200
Ahora se puede volver a trav@'es del c@'odigo @code{condition-case} en
un momento. Primero, se echa un vistazo a la definici@'on de
@code{kill-region}, con comentarios a@~nadidos:

@c GNU Emacs 22:
@smallexample
@group
(defun kill-region (beg end)
  "Kill (\"corta\") texto entre punto y marca.
Esto borra el texto desde el b@'uffer y lo guarda en anillo de la
  muerte @emph{kill ring}.
El comando \\[yank] puede recuperarse desde all@'{@dotless{i}}. @dots{}
 "
@end group

@group
  ;; @bullet{} Desde materias de orden, pasa el punto primero.
  (interactive (list (point) (mark)))
  ;; @bullet{} Y cu@'entanos 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@'a asignada ahora, as@'{@dotless{i}} que
  no hay regi@'on"))
@end group

@group
  ;; @bullet{} `condition-case' toma tres argumentos
  ;;    Si el primer argumento es nulo, como aqu@'{@dotless{i}}
  ;;    la informaci@'on acerca del error no est@'a
  ;;    almacenada para ser usada por otra funci@'on
  (condition-case nil
@end group

@group
      ;; @bullet{} El segundo argumento a `condition-case' cuenta lo que el
      ;;    int@'erprete que hace cuando todo va bien.
@end group

@group
      ;;    Empieza con una funci@'on `let' que extrae la cadena
      ;;    y chequea si existe. Si es as@'{@dotless{i}} (esto es lo
      ;;    que `when' chequea), eso llama a una funci@'on `if' que
      ;;    determina si el comando previo que era otra llamada
      ;;    si el comando previo fu@'e otra llamada a `kill-region';
      ;;    si lo era, entonces el siguiente texto se a@~nade
      ;;    cuando se chequea), eso llama a una funci@'on `if' que
      ;;    determina si el comando previo era otra llamada a
      ;;    `kill-region'; si era eso, entonces el nuevo texto es
      ;;    a@~nadido al texto previo; si no, entonces una funci@'on 
      ;;    diferente, `kill-new' se llama.
@end group

@group
      ;;    La funci@'on `kill-append' concatena la nueva cadena y
      ;;    la vieja.  La funci@'on `kill-new' inserta texto dentro de
      ;;    @'{@dotless{i}}tem en el kill ring @emph{anillo de la muerte}.
@end group

@group
      ;;    `when' es un `if' sin una parte else.  El segundo `when'
      ;;    de nuevo chequea si la cadena actual existe; 
      ;;    por a@~nadidura, eso chequea si el comando previo fuese
      ;;    otra llamada a `kill-region'. Si una u otra condici@'on
      ;;    es verdadero, entonces eso configura el actual comando a 
      ;;    ser `kill-region'.
@end group
@group
      (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)
@end group
@group
              ;;    @minus{} `yank-handler' es un argumento opcional para
              ;;    `kill-region' que cuenta el `kill-append' y funciones
              ;;    `kill-new' como tratan con propiedades a@~nadidas
              ;;    al texto, tal como `negrilla' o `it@'alica'
              (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)
@end group

@group
    ;;  @bullet{} El tercer argumento a `condition-case' cuenta el int@'erprete
    ;;  qu@'e hacer con un error.
@end group
@group
    ;;    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@'uffer son de solo lectura)
    ;;    entonces el cuerpo es ejecutado.
@end group
@group
    ;;    La primera parte del tercer es el siguiente:
    ((buffer-read-only text-read-only) ;; parte if
     ;; @dots{}  parte then-part
     (copy-region-as-kill beg end)
@end group
@group
     ;;    Lo siguiente, tambi@'en como parte de la then-part, asigna this-command, as@'{@dotless{i}}
     ;;    ser@'a asignado en un error
     (setq this-command 'kill-region)
     ;;    Finalmente, en la then-part, env@'{@dotless{i}}a un mensaje
     ;;    si se puede copiar el texto al anillo de la muerte
     ;;    @emph{kill ring} sin se@~nalar un error, pero no si no se puede.

@end group
@group
     (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)))))
@end group
@end smallexample

@ignore
@c v 21
@smallexample
@group
(defun kill-region (beg end)
  "Corta entre punto y marca.
El texto es borrado, pero guardado en el kill ring."
  (interactive "r")
@end group

@group
  ;; 1. `condition-case' tiene tres argumentos.
  ;;    Si el primer argumento es nil, como est@'a aqu@'{@dotless{i}}
  ;;    la informaci@'on acerca de la se@~nal de error no es
  ;;    almacenada para usarse por otra funci@'on.
  (condition-case nil
@end group

@group
      ;; 2. El segundo argumento a `condition-case'
      ;;    cuenta al int@'eprete Lisp que hacer cuando todo va bien.
@end group

@group
      ;;    La funci@'on `delete-and-extract-region' normalmente hace
      ;;    el trabajo. Si el principio y final de la regi@'on son lo
      ;;    mismo, entonces la varible `string' estar@'a
      ;;    vac@'{@dotless{i}}a, o nula
      (let ((string (delete-and-extract-region beg end)))
@end group

@group
        ;; `cuando' es una cl@'ausula `if' que no puede tomar `else-part'.
        ;; Emacs normalmente asigna el valor del `last-command' al
        ;; comando previo.
@end group
@group
        ;; `kill-append' concatena la nueva cadena y la vieja.
        ;; `kill-new' inserta texto dentro de un nuevo
        ;; @'{@dotless{i}}tem dentro de un nuevo @'{@dotless{i}} en
        ;; kill ring.
        (when string
          (if (eq last-command 'kill-region)
              ;; si verdadero, concatena la cadena
              (kill-append string (< end beg))
            (kill-new string)))
        (setq this-command 'kill-region))
@end group

@group
    ;; 3. El tercer argumento para `condition-case' cuenta el int@'erprete
    ;;    que hacer con un error.
@end group
@group
    ;;    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@'uffer son de solo lectura)
    ;;    entonces el cuerpo es ejecutado.
@end group
@group
    ((buffer-read-only text-read-only) ;; esta el la parte if
     ;; entonces...
     (copy-region-as-kill beg end)
@end group
@group
     (if kill-read-only-ok            ;; normalmente esta variable es nula
         (message "Lee el texto copiado al kill ring")
       ;; o sino, se@~nala un error si el b@'uffer es de solo lectura;
       (barf-if-buffer-read-only)
       ;; y, en cualquier caso, se@~nala el texto de solo lectura.
       (signal 'text-read-only (list (current-buffer)))))))
@end group
@end smallexample
@end ignore

@node condition-case
@subsection @code{condition-case}
@findex condition-case

Como se ha visto antes (@pxref{Creando errores, , Genera un Mensaje de
Error}), cuando el int@'erprete Emacs Lisp tiene problemas evaluando
una expresi@'on, se provee de una ayuda; en jerga, se dice ``signaling an
error'' @emph{se@~nalando un error}. Normalmente, el ordenador para el
programa y te muestra un mensaje.

Sin embargo, algunos programas garantizan acciones complicadas. Eso no
parar@'{@dotless{i}}a en un error. En la funci@'on @code{kill-region},
la mayor@'{@dotless{i}}a parece un error que intentar@'a cortar texto
que es de solo lectura y no puede ser eliminado. As@'{@dotless{i}} la
funci@'on @code{kill-region} contiene c@'odigo para manejar esta
circunstancia. Este c@'odigo, hace que el cuerpo de la funci@'on
@code{kill-region}, est@'e dentro de una forma especial
@code{condition-case}.

@need 800
La plantilla para @code{condition-case} se parece a esto:

@smallexample
@group
(condition-case
  @var{var}
  @var{bodyform}
  @var{error-handler}@dots{})
@end group
@end smallexample

El segundo argumento, @var{bodyform} es sencillo. La forma especial
@code{condition-case} causa que el int@'erprete Lisp eval@'ue el
c@'odigo en @var{bodyform}. Si ning@'un error ocurre, la forma
especial devuelve el valor del c@'odigo y produce efectos laterales,
si hay.

En resumen, la parte @var{bodyform} de una expresi@'on
@code{condition-case} determina qu@'e ocurre cuando cualquier cosa
funciona correctamente.

Sin embargo, si un error ocurre, entre sus otras acciones, la
funci@'on genera la se@~nal de error que definir@'a uno o m@'as
errores de nombres de condici@'on.

Un manejador de errores es el tercer argumento para
@code{condition-case}. Un manejador de errores tiene dos partes, un
@var{condition-name} y un @var{body}. Si la parte @var{condition-name}
tiene un manejador de errores encuentra un nombre de condici@'on generado
por un error, entonces la parte del @var{body} del manejador de errores
se ejecuta.

Como se esperar@'{@dotless{i}}a, la parte @var{condition-name} de un
manejador de errores puede ser as@'{@dotless{i}}, un nombre de
condici@'on simple o una lista de nombres de condici@'on.

Tambi@'en, una expresi@'on completa @code{condition-case} puede
contener m@'as de un manejador de errores. Cuando un error ocurre, el
primer manejador aplicable se ejecuta.

Finalmente, el primer argumento a la expresi@'on
@code{condition-case}, es el argumento @var{var}, que es algunas veces
asignado a una variable que contiene informaci@'on acerca del
error. Sin embargo, si este argumento es nulo, como es el caso en
@code{kill-region}, esta informaci@'on se descarta.

@need 1200
En breve, en la funci@'on @code{kill-region}, el c@'odigo
@code{condition-case} funciona as@'{@dotless{i}}:

@smallexample
@group
@var{Si no hay errores}, @var{ejecuta solo este c@'odigo}
    @var{pero}, @var{si hay errores}, @var{ejecuta este otro c@'odigo}.
@end group
@end smallexample

@ignore
2006 Oct 24
In Emacs 22,
copy-region-as-kill is short, 12 lines, and uses
filter-buffer-substring, which is longer, 39 lines
and has delete-and-extract-region in it.
delete-and-extract-region is written in C.

see Initializing a Variable with @code{defvar}
this is line 8054
Initializing a Variable with @code{defvar} includes line 8350
@end ignore

@node Macro Lisp
@subsection Macro Lisp
@cindex Macro, lisp
@cindex Macro Lisp

La parte de la expresi@'on @code{condition-case} que se eval@'ua en la
expectativa de que todo va bien si tiene un @code{when}. El c@'odigo usa
@code{when} para determinar si la variable @code{string} (@emph{cadena})
apunta al texto que existe.

Una expresi@'on @code{when} es simplemente una conveniencia de
programadores. Eso es un @code{if} sin la posibilidad de una
cl@'ausula else. En tu mente, se puede reemplazar @code{when} con
@code{if} y comprender de que va. Esto es lo que el int@'erprete Lisp hace.

T@'ecnicamente hablando, @code{when} es una macro Lisp. Una
@dfn{macro} Lisp permite definir una nueva construcci@'on de control y
otras funcionalidades del lenguaje. Eso cuenta al int@'erprete c@'omo
computar otra expresi@'on Lisp que dejar@'a de computar el valor. En
este caso, la `otra expresi@'on' es una expresi@'on @code{if}.

La definici@'on de funci@'on tambi@'en tiene una macro @code{unless};
que acompa@~na a @code{when}. La macro @code{unless} es un
@code{if} sin una cl@'ausula then.

Para m@'as acerca de macros Lisp, ver @ref{Macros, , Macros, elisp, El
Manual de Referencia de Emacs Lisp}. El lenguaje de programaci@'on C
tambi@'en provee macros. Estos son diferentes, pero tambi@'en @'utiles.

@ignore
We will briefly look at C macros in
@ref{Digression into C}.
@end ignore

@need 1200
Guardando la macro @code{when}, en la expresi@'on
@code{condition-case}, cuando la cadena tiene contenido, entonces otra
expresi@'on condicional se ejecuta. Esto es un @code{if} tanto con una
then-part y como con una else-part.

@smallexample
@group
(if (eq last-command 'kill-region)
    (kill-append string (< end beg) yank-handler)
  (kill-new string nil yank-handler))
@end group
@end smallexample

La parte then (then-part) se eval@'ua si el comando previo fu@'e otra
llamada para @code{kill-region}; si no, se eval@'ua la parte else
(else-part)

@code{yank-handler} es un argumento opcional para @code{kill-region}
que cuenta c@'omo las funciones @code{kill-append} y @code{kill-new} se
tratan con propiedades a@~nadidas al texto, tal como `negrilla' o
`it@'alica'.  

@code{last-command} es una variable que viene con Emacs y que no se ha
visto antes. Normalmente, siempre y cuando una funci@'on se ejecute,
Emacs asigna el valor de @code{last-command} al comando previo. 

@need 1200
En este segmento de la definici@'on, la expresi@'on @code{if} chequea
si el comando previo era @code{kill-region}. Si era eso,

@smallexample
(kill-append string (< end beg) yank-handler)
@end smallexample

@noindent
Se concatena una copia del nuevo texto cortado al texto cortado
previamente en el kill ring @emph{anillo de la muerte}.

@node copy-region-as-kill
@section @code{copy-region-as-kill}
@findex copy-region-as-kill
@findex nthcdr

La funci@'on @code{copy-region-as-kill} copia una regi@'on de texto
desde un b@'uffer y (via @code{kill-append} o @code{kill-new}) lo
guarda en el @code{kill-ring}.

Si se llama a @code{copy-region-as-kill} inmediatamente despu@'es de
un comando @code{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@'on previa. Por
otro lado, si alg@'un otro comando precede la
@code{copy-region-as-kill}, la funci@'on copia el texto dentro de una
entrada separada el kill ring @emph{anillo de la muerte}.

@menu
* Completar copy-region-as-kill::  La definici@'on completa de funci@'on.
* cuerpo copy-region-as-kill::  El cuerpo de @code{copy-region-as-kill}.
@end menu

@ifnottex
@node Completar copy-region-as-kill
@unnumberedsubsec La definici@'on de la funci@'on completa @code{copy-region-as-kill}.
@end ifnottex

@need 1200
Aqu@'{@dotless{i}} est@'a el texto completo de la versi@'on 22
de la funci@'on @code{copy-region-as-kill}:

@smallexample
@group
(defun copy-region-as-kill (beg end)
  "Guarda la regi@'on como si estuviera cortada, pero no la cortes.
En el modo Marca de Tr@'ansito @emph{Transient Mark}, se desactiva la
  marca.
Si `interprogram-cut-function' es no nulo, tambi@'en se guarda el
  texto para una sistema de ventanas de cortar y pegar."
  (interactive "r")
@end group
@group
  (if (eq last-command 'kill-region)
      (kill-append (filter-buffer-substring beg end) (< end beg))
    (kill-new (filter-buffer-substring beg end)))
@end group
@group
  (if transient-mark-mode
      (setq deactivate-mark t))
  nil)
@end group
@end smallexample

@need 800
De normal, esta funci@'on puede ser dividida dentro sus componentes:

@smallexample
@group
(defun copy-region-as-kill (@var{argument-list})
  "@var{documentation}@dots{}"
  (interactive "r")
  @var{body}@dots{})
@end group
@end smallexample

Los argumentos son @code{beg} y @code{end} y la funci@'on es
interactiva con @code{"r"}, as@'{@dotless{i}} los dos argumentos deben
referirse al principio y al final de la regi@'on. Si ha estado
leyendo a trav@'es de este documento desde el principio, comprendiendo
estas partes de una funci@'on casi llegar@'{@dotless{i}}a a ser rutina.

La documentaci@'on es algo confusa a menos que se recuerde que la
palabra `kill' @emph{matar, cortar} tiene un significado diferente de la
usual. La `Marca Transitoria' y @code{interprogram-cut-function}
comenta explicar ciertos efectos laterales.

Despu@'es de que se ha asignado una marca, un b@'uffer siempre
contiene una regi@'on. Si se desea se puede usar el modo Marca
Transitoria para iluminar la regi@'on temporalmente. (Nadie quiere
iluminar la regi@'on todo el rato, as@'{@dotless{i}} el modo Marca
Transitoria subrraya solo en el momento apropiado. Muchas personas
desactivan el modo Marca Transitoria, as@'{@dotless{i}} la regi@'on
nunca se ilumina.)

Tambi@'en, un sistema de ventanas permite copiar, cortar y pegar entre
programas diferentes. En el sistema de X windows, por ejemplo, la
funci@'on @code{interprogram-cut-function} es @code{x-select-text},
que funciona con el sistema de ventanas equivalente del kill ring de
Emacs.

El cuerpo de la funci@'on @code{copy-region-as-kill} empieza con una
cl@'ausula @code{if}. Lo que esta cl@'ausula hace es distinguir entre
dos situaciones diferentes: si este comando se ejecuta o no
inmediatamente despu@'es de un comando previo @code{kill-region}. En
el primer caso, la nueva regi@'on se concatena al texto copiado
previamente. De otro modo, eso se inserta al principio del anillo de
la muerte @emph{kill ring} como una pieza separada de texto desde la
pieza previa.

Las dos l@'{@dotless{i}}neas de la funci@'on previene la regi@'on
desde la iluminaci@'on si el modo Transient Mark @emph{Marca
Transitoria} est@'a activado.

El cuerpo de @code{copy-region-as-kill} merece discusi@'on en detalle.

@node cuerpo copy-region-as-kill
@subsection El cuerpo de @code{copy-region-as-kill}

La funci@'on @code{copy-region-as-kil} funciona de un modo parecido a
la funci@'on @code{kill-region}. Ambas est@'an escritas
de un modo que dos o m@'as textos cortados en una fila combinan
su texto en una entrada simple. Si se pega el texto desde el
anillo de la muerte @emph{kill ring}, se tiene todo en una
pieza. M@'as all@'a, los cortes de textos que se cortan hacia adelante
desde la posici@'on actual del cursor se a@~naden al fin del texto
copiado previamente y comanda este texto copiado vaya hacia atr@'as al
principio del texto copiado previamente. De este modo, las palabras en
el texto est@'an en el orden apropiado.

Como @code{kill-region}, la funci@'on @code{copy-region-as-kill} hace
uso de la variable @code{last-command} que deja traza del comando de
Emacs previo.

@menu
* last-command & this-command::  last-command & this-command
* Funci@'on kill-append::    Funci@'on kill-append
* Funci@'on kill-new::       Funci@'on kill-new
@end menu

@ifnottex
@node last-command & this-command
@unnumberedsubsubsec @code{last-command} y @code{this-command}
@end ifnottex

Normalmente, siempre y cuando una funci@'on se ejecuta, Emacs asigna
el valor de @code{this-command} a la funci@'on que se ejecuta (que en
este caso ser@'{@dotless{i}}a @code{copy-region-as-kill}). Al mismo
tiempo, Emacs asigna el valor de @code{last-command} al valor previo
de @code{this-command}.

En la primera parte del cuerpo de la funci@'on
@code{copy-region-as-kill}, una expresi@'on @code{if} determina si el
valor de @code{last-command} es @code{kill-region}. Si es
as@'{@dotless{i}}, la then-part de la expresi@'on @code{if} se
eval@'ua; eso usa la funci@'on @code{kill-append} para concatenar el
texto copiado en esta llamada a la funci@'on con el texto ya en el
primer elemento (el @sc{car} del anillo de la muerte. Por otro lado,
si el valor de @code{last-command} no es @code{kill-region}, entonces
la funci@'on @code{copy-region-as-kill} adjunta un nuevo elemento al
anillo de la muerte @emph{kill ring} usando la funci@'on
@code{kill-new}.

@need 1250
La expresi@'on @code{or} se ve as@'{@dotless{i}}; usa @code{eq}:

@smallexample
@group
  (if (eq last-command 'kill-region)
      ;; @r{parte then}
      (kill-append  (filter-buffer-substring beg end) (< end beg))
    ;; @r{parte else}
    (kill-new  (filter-buffer-substring beg end)))
@end group
@end smallexample

@findex filter-buffer-substring
(La funci@'on @code{filter-buffer-substring} devuelve una subcadena
filtrada del b@'uffer, cualquiera. Opcionalmente --- los argumentos no
est@'an aqu@'{@dotless{i}}, as@'{@dotless{i}} nunca est@'a hecho ---
la funci@'on puede borrar el texto inicial o devolver el texto sin sus
propiedades; esta funci@'on es un reemplazo para la vieja funci@'on
@code{buffer-substring}, que viene antes que las propiedades del texto
fuesen implementadas.)

@findex eq @r{(ejemplo de uso)}
@noindent
La funci@'on @code{eq} chequea si su primer argumento es el mismo
objeto Lisp que su segundo argumento. La funci@'on @code{eq} es
similar a la funci@'on @code{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. @code{equal} determina si la estructura y
contenidos de dos expresiones son la misma.

Si el comando previo era @code{kill-region}, entonces el int@'erprete
Emacs Lisp llama a la funci@'on @code{kill-append}

@node Funci@'on kill-append
@unnumberedsubsubsec La funci@'on @code{kill-append}
@findex kill-append

@need 800
La funci@'on @code{kill-new} se ve como as@'{@dotless{i}}:

@c in GNU Emacs 22
@smallexample
@group
(defun kill-append (string before-p &optional yank-handler)
  "Inserta STRING al fin del @'ultimo corte en el anillo de la muerte @emph{kill ring}.
Si BEFORE-P es no nulo, inserta STRING.
@dots{} "
  (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)))
@end group
@end smallexample

@ignore
was:
(defun kill-append (string before-p)
  "Append STRING to the end of the latest kill in the kill ring.
If BEFORE-P is non-nil, prepend STRING to the kill.
If `interprogram-cut-function' is set, pass the resulting kill to
it."
  (kill-new (if before-p
                (concat string (car kill-ring))
              (concat (car kill-ring) string))
            t))
@end ignore

@noindent
La funci@'on @code{kill-append} es limpia. Usa la funci@'on
@code{kill-new}, que discutiremos en m@'as detalle en un momento.

(Tambi@'en, la funci@'on provee un argumento opcional llamado
@code{yank-handler}; cuando se invoque, este argumento cuenta a la
funci@'on c@'omo tratar con la propiedades a@~nadidas al texto, tales
como `negrilla' o `it@'alicas'.)

@c !!! bug in GNU Emacs 22 version of  kill-append ?
Eso tiene una funci@'on @code{let*} para asignar el valor del primer
elemento del kill ring a @code{cur}. (No se sabe por qu@'e la
funci@'on no usa @code{let}; solo un valor es asignado en la
expresi@'on. @questiondown{}Quiz@'as esto es un error que no produce
problemas?

Considera el condicional que es uno de los dos argumentos para
@code{kill-new}. Eso usa @code{concat} para concatenar el nuevo texto
al @sc{car} del anillo de la muerte @emph{kill ring}. Si eso se
concatena atr@'as o delante depende de los resultados de una
expresi@'on @code{if}:

@smallexample
@group
(if before-p                            ; @r{if-part}
    (concat string cur)                 ; @r{then-part}
  (concat cur string))                  ; @r{else-part}
@end group
@end smallexample

@noindent
Si la regi@'on cortada est@'a antes que la regi@'on que se cort@'o en
el @'ultimo comando, entonces deber@'{@dotless{i}}a ser puesto antes
que el material salvador en el anterior corte @emph{kill}; y de manera
contraria, si el texto cortado sigue lo que fu@'e cortado, eso
ser@'{@dotless{i}}a a@~nadido despu@'es del texto previo. La
expresi@'on @code{if} depende del predicado @code{before-p} para
decidir si el texto nuevamente salvado es puesto antes o despu@'es.

El s@'{@dotless{i}}mbolo @code{before-p} es el nombre de uno de los
argumentos a @code{kill-append}. Cuando la funci@'on
@code{kill-append} se eval@'ua, se asocia al valor devuelto evaluando
el argumento actual. En este caso, esta es la expresi@'on @code{(< end
beg)}. Esta expresi@'on no determina directamente si el texto cortado
en este comando se localiza antes o despu@'es del texto cortado del
@'ultimo comando; lo que hace es determinar si el valor de la variable
@code{end} es menor que el valor de la variable @code{beg}. Si es
as@'{@dotless{i}}, significa que el usuario se encara al principio del
b@'uffer. Tambi@'en, el resultado de evaluar la expresi@'on del
predicado. @code{(< end beg)}, ser@'a verdadero y el texto se
concatena antes del texto previo. Por otro lado, si el valor de la
variable @code{end} es mayor que el valor del la variable @code{beg},
el texto ser@'a concatenado despu@'es del texto previo.

@need 800
Cuando el texto nuevamente guardado se concatena, entonces la cadena
con el nuevo texto ser@'a concatenado antes del viejo texto:

@smallexample
(concat string cur)
@end smallexample

@need 1200
@noindent
Pero si el texto ser@'a a@~nadido, eso ser@'a concatenado despu@'es
del viejo texto:

@smallexample
(concat cur string))
@end smallexample

Para comprender c@'omo funciona esto, primero se necesita revisar la
funci@'on @code{concat}. La funci@'on @code{concat} enlaza junto o une
dos cadenas de texto. El resultado es una cadena. Por ejemplo:

@smallexample
@group
(concat "abc" "def")
     @result{} "abcdef"
@end group

@group
(concat "nuevo "
        (car '("primer elemento" "segundo elemento")))
     @result{} "nuevo primer elemento"

(concat (car
        '("primer elemento" "segundo elemento")) " modificado")
     @result{} "primer elemento modificado"
@end group
@end smallexample

Ahora puede tener sentido @code{kill-append}: eso modifica los
contenidos del anillo de la muerte @emph{kill ring}. El anillo de la
muerte @emph{kill ring} es una lista, en la que cada elemento es texto
guardado. La funci@'on @code{kill-append} usa la funci@'on
@code{kill-new} que usa la funci@'on @code{setcar}.

@node Funci@'on kill-new
@unnumberedsubsubsec La funci@'on @code{kill-new}
@findex kill-new

@c in GNU Emacs 22, additional documentation to kill-new:
@ignore
Optional third arguments YANK-HANDLER controls how the STRING is later
inserted into a buffer; see `insert-for-yank' for details.
When a yank handler is specified, STRING must be non-empty (the yank
handler, if non-nil, is stored as a `yank-handler' text property on STRING).

When the yank handler has a non-nil PARAM element, the original STRING
argument is not used by `insert-for-yank'.  However, since Lisp code
may access and use elements from the kill ring directly, the STRING
argument should still be a \"useful\" string for such uses."
@end ignore
@need 1200
La funci@'on @code{kill-new} se ve de esta manera:

@smallexample
@group
(defun kill-new (string &optional replace yank-handler)
  "Crea STRING el @'ultimo corte en el anillo de la muerte @emph{kill
  ring}.
Asigna `kill-ring-yank-pointer' para apuntarlo.

Si `interprogram-cut-function' es no nulo, apl@'{@dotless{i}}calo a su
 STRING.
Segundo argumento opcional REPLACE no-nulo significa que STRING
 reemplazar@'a el frente del kill ring, en vez de ser a@~andido a la lista.
@dots{}"
@end group
@group
  (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"))))
@end group
@group
  (if (fboundp 'menu-bar-update-yank-menu)
      (menu-bar-update-yank-menu string (and replace (car kill-ring))))
@end group
@group
  (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)))
@end group
@group
  (setq kill-ring-yank-pointer kill-ring)
  (if interprogram-cut-function
      (funcall interprogram-cut-function string (not replace))))
@end group
@end smallexample
@ignore
was:
(defun kill-new (string &optional replace)
  "Make STRING the latest kill in the kill ring.
Set the kill-ring-yank pointer to point to it.
If `interprogram-cut-function' is non-nil, apply it to STRING.
Optional second argument REPLACE non-nil means that STRING will replace
the front of the kill ring, rather than being added to the list."
  (and (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)
    (setq kill-ring (cons 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))))
@end ignore

(Vea que la funci@'on no es interactiva.)

Normalmente, se mira a esta funci@'on en partes.

La definici@'on de la funci@'on tiene un argumento opcional
@code{yank-handler}, que cuando se invoca cuenta la funci@'on de c@'omo
tratar con propiedades a@~nadidas al texto, tal como `negrilla' o
`it@'alica'. Nosotros evitaremos esto.

@need 1200
La primer l@'{@dotless{i}}nea de la documentaci@'on tiene sentido:

@smallexample
Crea la CADENA la @'ultima copia en el anillo de la muerte @emph{kill
ring}.
@end smallexample

@noindent
Permite saltarse el resto de la documentaci@'on por el momento.

@noindent
Tambi@'en, permite salir de la expresi@'on inicial @code{if} y estas
l@'{@dotless{i}}neas de c@'odigo involucrando
@code{menu-bar-update-yank-menu}. Nosotros explicaremos debajo.

@need 1200
Las l@'{@dotless{i}}neas cr@'{@dotless{i}}ticas son estas:

@smallexample
@group
  (if (and replace kill-ring)
      ;; @r{entonces}
      (setcar kill-ring string)
@end group
@group
    ;; @r{resto}
  (push string kill-ring)
@end group
@group
    (setq kill-ring (cons string kill-ring))
    (if (> (length kill-ring) kill-ring-max)
        ;; @r{avoid overly long kill ring}
        (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
@end group
@group
  (setq kill-ring-yank-pointer kill-ring)
  (if interprogram-cut-function
      (funcall interprogram-cut-function string (not replace))))
@end group
@end smallexample

El test condicional es @w{@code{(and replace kill-ring)}}. Esto ser@'a
verdad cuando dos condiciones se encuentran: el anillo de la muerte
@emph{kill ring} tiene alguna cosa dentro, y la variable
@code{replace} es verdad.

@need 1250
Cuando la funci@'on @code{kill-append} asigna @code{replace} para ser
cierto y cuando el anillo de la muerte @emph{kill ring} tiene al menos
un @'{@dotless{i}}tem en eso, la expresi@'on @code{setcar} es ejecutada.

@smallexample
(setcar kill-ring string)
@end smallexample

La funci@'on @code{setcar} actualemten cambia el primer elemento del
anillo de la muerte (@code{kill-ring} lista al valor de
@code{string}. Eso reemplaza el primer elemento.

@need 1250
Por otro lado, si el kill ring est@'a vac@'{@dotless{i}}o, o
reemplazar es falso, la else-part de la condici@'on est@'a ejecutado:

@smallexample
(push string kill-ring)
@end smallexample

@noindent
@need 1250
@code{push} pone su primer argumento dentro del segundo. Es similar al
viejo.

@smallexample
(setq kill-ring (cons string kill-ring))
@end smallexample

@noindent
@need 1250
o el nuevo

@smallexample
(add-to-list kill-ring string)
@end smallexample

@noindent
Cuando eso es falso, la expresi@'on primero construye una nueva
versi@'on del anillo de la muerte @emph{kill ring} a@~nadiendo
@code{string} al anillo de la muerte @emph{kill ring} como un nuevo
elemento (que es lo que @code{push} hace). Entonces ejecuta un segundo
@code{if} cl@'ausula. Este segundo @code{if} cl@'ausula guarada el
anillo de la muerte @emph{kill ring} desde el creciente demasiado largo.

D@'ejanos mirar estas dos expresiones en orden.

La l@'{@dotless{i}}nea @code{push} de la parte else asigna el nuevo
valor del kill ring @emph{anillo de la muerte} a que resultados
a@~naden la cadena siendo cortada al viejo anillo de la muerte
@emph{kill ring}

Nosotros podemos ver c@'omo esto funciona con un ejemplo.

@need 800
Primero,

@smallexample
(setq example-list '("aqui una clausula" "otra clausula"))
@end smallexample

@need 1200
@noindent
Despu@'es de evaluar esta expresi@'on con @kbd{C-x C-e}, se puede
evaluar @code{example-list} y mira lo que devuelve:

@smallexample
@group
example-list
     @result{} ("aqu@'{@dotless{i}} hay una cla@'usula" "otra cla@'usula")
@end group
@end smallexample

@need 1200
@noindent
Ahora, se puede a@~nadir un nuevo elemento en esta lista evaluando la
siguiente expresi@'on:
@findex push, @r{ejemplo}

@smallexample
(push "una tercera cl@'ausula" lista-de-ejemplo)
@end smallexample

@need 800
@noindent
Cuando se eval@'ua @code{example-list}, se encuentra su valor es:

@smallexample
@group
example-list
     @result{} ("una tercera cla@'usula" "aqu@'{@dotless{i}} hay una
     cla@'usula" "otra cla@'usula")
@end group
@end smallexample

@noindent
De este modo, la tercera cla@'usula se a@~nade a la lista con @code{push}.

@need 1200
Ahora para la segunda parte de la cla@'usula @code{if}. Esta
expresi@'on deja el kill ring desde lo creciente demasiado largo. Eso
se ve de la siguiente manera:

@smallexample
@group
(if (> (length kill-ring) kill-ring-max)
    (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))
@end group
@end smallexample

El c@'odigo chequea si el tama@~no del anillo de la muerte @emph{kill
ring} es m@'as grande que el m@'aximo tama@~no permitido. Este es el
valor de @code{kill-ring-max} (que es 60, por defecto). Si el tama@~no
del anillo de la muerte @emph{kill ring} es demasiado largo, entonces
este c@'odigo asigna el @'ultimo elemento del anillo de la muerte
@emph{kill ring} a @code{nil}. Eso hace esto usando dos funciones,
@code{nthcdr} y @code{setcdr}.

Nosotros vemos que @code{setcdr} temprano (@pxref{setcdr, ,
@code{setcdr}}). Eso asigna el @sc{cdr} de una lista, solo como
@code{setcar} asigna el @sc{car} de una lista. En este caso, sin
embargo, @code{setcdr} no estar@'a configurando el @sc{cdr} del kill
ring completo; la funci@'on @code{nthcdr} es usada para causarlo para
asignar el @sc{cdr} del siguiente al @'ultimo elemento del kill ring
--- esto significa que desde el @sc{cdr} del siguiente al @'ultimo
elemnto del kill ring @emph{anillo de la muerte}, eso asignar@'a el
@'ultimo elemento del kill ring @emph{anillo de la muerte}.

@findex nthcdr, @r{ejemplo}
La funci@'on @code{nthcdr} funciona repetidamente tomando el @sc{cdr}
de una lista --- eso toma el @sc{cdr} del @sc{cdr} del @sc{cdr}
@dots{}. Eso hace esto @var{N} veces y devuelve los
resultados. (@xref{nthcdr, , @code{nthcdr}}.)

@findex setcdr, @r{ejemplo}
De este modo, si teniamos una lista de cuatro elemento que era
supuestamente de tres elementos, se podr@'{@dotless{i}}a asignar el
@sc{cdr} del siguiente al @'ultimo elemento a @code{nil}, y por eso se
ordena la lista. (Si se asigna el @'ultimo elemento a alg@'un otro
valor a @code{nil}, que se podr@'{@dotless{i}}a hacer, entonces no
se habr@'{@dotless{i}}a ordenado la lista. @xref{setcdr, ,
@code{setcdr}}.)

Se puede ver ordenando la evaluaci@'on de las siguientes tres
expresiones en turno. Primero asigna el valor de @code{arboles} a
@code{(arce encina pino abedul)} entonces asigna el @sc{cdr} de su
segundo @sc{cdr} y entonces encuentra el valor de @code{arboles}.

@smallexample
@group
(setq arboles '(arce encina pino abedul))
     @result{} (arce encina pino abedul)
@end group

@group
(setcdr (nthcdr 2 arboles) nil)
     @result{} nil

@'arboles
     @result{} (arce encina pino)
@end group
@end smallexample

@noindent
(El valor devuelto por la expresi@'on @code{setcdr} es @code{nil}
desde que es que el @sc{cdr} es asignado.)

Para repetir, en @code{kill-new}, la funci@'on @code{nthcdr} toma el
@sc{cdr} un n@'umero de veces que es uno menos que el tama@~no
m@'aximo permitido del anillo de la muerte @emph{kill ring} y
@code{setcdr} asigna el @sc{cdr} de este elemento (que ser@'a el resto
de los elementos en el anillo muerte) para @code{nil}. Esto previene
el anillo de la muerte @emph{kill ring} desde lo que crece demasiado largo.

@need 800
De la siguiente a la @'ultima expresi@'on en la funci@'on
@code{kill-new} es

@smallexample
(setq kill-ring-yank-pointer kill-ring)
@end smallexample

El @code{kill-ring-yank-pointer} es una variable global que es
asignado para ser el @code{kill-ring}.

Incluso aunque el @code{kill-ring-yank-pointer} es llamado un
@samp{puntero}, eso es una variable solo como el anillo de la muerte
@emph{kill ring}. Sin embargo, el nombre que ha sido elegido para
ayudar a humanos a comprender c@'omo la variable se usa.

@need 1200
Ahora, para devolver r@'apido una expresi@'on en el cuerpo de la funci@'on:

@smallexample
@group
  (if (fboundp 'menu-bar-update-yank-menu)
       (menu-bar-update-yank-menu string (and replace (car kill-ring))))
@end group
@end smallexample

@noindent
Empieza con una expresi@'on @code{if}

En este caso, la expresi@'on chequea primero si
@code{menu-bar-update-yank-menu} existe como una funci@'on, y si
as@'{@dotless{i}}, se llama. La funci@'on @code{fboundp} devuelve
cierto si el s@'{@dotless{i}}mbolo que se chequea tiene una
definici@'on de funci@'on que `no es vac@'{@dotless{i}}a'. Si el
s@'{@dotless{i}}mbolo de la definici@'on de funci@'on fuera
vac@'{@dotless{i}}o, recibir@'{@dotless{i}}a un mensaje de error, como
se hizo cuando se crearon errores intencionalmente (@pxref{Creando
errores, , Genera un Mensaje de Error}).

@noindent
La then-part contiene una expresi@'on cuyo primer elemento es la
funci@'on @code{and}.

@findex and
La forma especial @code{and} eval@'ua cada uno de sus argumentos hasta
que uno de los argumentos devuelva un valor de @code{nil}, en cuyo caso
la expresi@'on @code{and} devuelve @code{nil}; sin embargo, si
ninguno de los argumentos devuelve una valor de @code{nil}, el valor
resultante desde la evaluaci@'on el @'ultimo argumento es
devuelto. (Desde que tal valor no es @code{nil}, eso es considerado
cierto en Emacs Lisp.) En otras palabras, una expresi@'on @code{and}
devuelve un valor cierto solo si todos sus argumentos son
verdaderos. (@xref{Revisar el segundo b@'uffer relacionado}.)

La expresi@'on determina si el segundo argumento
@code{menu-bar-update-yank-menu} es verdadero o no.
@ignore
    ;; If we're supposed to be extending an existing string, and that
    ;; string really is at the front of the menu, then update it in place.
@end ignore

@code{menu-bar-update-yank-menu} es una de la funciones que lo hace
posible para usar el menu `Seleccionar y Pegar' en el
@'{@dotless{i}}tem Editar de una barra de menu; usando un rat@'on, se
pueden mirar varias piezas de texto que se han guardado y se
selecciona una pieza para pegar.

La @'ultima expresi@'on en la funci@'on @code{kill-new} a@~nade 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@'on
@code{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.

@need 1200
La expresi@'on se ve como:

@smallexample
@group
  (if interprogram-cut-function
      (funcall interprogram-cut-function string (not replace))))
@end group
@end smallexample

Si @code{interprogram-cut-function} existe, entonces Emacs ejecuta
@code{funcall}, que en vez de llamar a su primer argumento como una
funci@'on, pasa los argumentos que permanecen en
eso. (Incidentalmente, tan lejos como se puede ver, esta expresi@'on
@code{if} podr@'{@dotless{i}}a ser reemplazado por una expresi@'on
@code{and} similar a uno en la primera parte de la funci@'on.)

Estamos yendo a discutir sistemas de ventanas y otros programas m@'as
all@'a pero meramente nota que este es un mecanismo que habilita GNU
Emacs a trabajar f@'acilmente y bien con otros programas.

Este c@'odigo para emplazar texot en el anillo de la muerte @emph{kill
ring}, concatenado con un elemento existente o como un nuevo elemento,
nos lidera al c@'odigo para traer texto que ha sido cortado del
b@'uffer --- los comandos de corte. Sin embargo, antes de discutir los
comandos de corte, es mejor aprender c@'omo las listas son implementadas
en un ordenador. Esto dejar@'a claro tales misterios como el uso del
t@'ermino `puntero'. Pero antes de esto, nos desviaremos a C.

@ignore
@c is this true in Emacs 22?   Does not seems to be

  (If the @w{@code{(< end beg))}}
expression is true, @code{kill-append} prepends the string to the just
previously clipped text.  For a detailed discussion, see
@ref{kill-append function, , The @code{kill-append} function}.)

If you then yank back the text, i.e., `paste' it, you get both
pieces of text at once.  That way, if you delete two words in a row,
and then yank them back, you get both words, in their proper order,
with one yank.  (The @w{@code{(< end beg))}} expression makes sure the
order is correct.)

On the other hand, if the previous command is not @code{kill-region},
then the @code{kill-new} function is called, which adds the text to
the kill ring as the latest item, and sets the
@code{kill-ring-yank-pointer} variable to point to it.
@end ignore
@ignore

@c Evidently, changed for Emacs 22. The zap-to-char command does not
@c use the delete-and-extract-region function

2006 Oct 26, the Digression into C is now OK but should come after
copy-region-as-kill and filter-buffer-substring

2006 Oct 24
In Emacs 22,
copy-region-as-kill is short, 12 lines, and uses
filter-buffer-substring, which is longer, 39 lines
and has delete-and-extract-region in it.
delete-and-extract-region is written in C.

see Initializing a Variable with @code{defvar}
@end ignore

@node Disgresi@'on dentro de C
@section Disgresi@'on dentro de C
@findex delete-and-extract-region
@cindex C, una disgresi@'on dentro
@cindex Disgresi@'on dentro de C

La funci@'on @code{copy-region-as-kill} (@pxref{copy-region-as-kill, ,
@code{copy-region-as-kill}}) usa la funci@'on
@code{filter-buffer-substring}, que en vez de eso usa la funci@'on
@code{delete-and-extract-region}. Eso elimina los contenidos de una
regi@'on y no se puede volverlos a tener.

Al contrario que el otro c@'odigo discutido aqu@'{@dotless{i}}, la
funci@'on @code{delete-and-extract-region} no est@'a escrita en Emacs
Lisp; eso est@'a escrito en C y es una de las primitivas del sistema
GNU Emacs. Puesto que es muy simple, se har@'a la disgresi@'on
brevemente desde el Lisp y se describe aqu@'{@dotless{i}}.

@c GNU Emacs 24  in src/editfns.c
@c the DEFUN for  delete-and-extract-region

@need 1500
Como muchas de las otras primitivas Emacs,
@code{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:

@smallexample
@group
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);
@}
@end group
@end smallexample

Sin ir dentro de los detalles de la macro que escribe el proceso, se
har@'a un apunte de esta macro que empieza con la palabra
@code{DEFUN}. La palabra @code{DEFUN} fu@'e elegida puesto que el
c@'odigo sirve para el mismo prop@'osito que @code{defun} hace en
Lisp. (La macro C @code{DEFUN} definida en @file{emacs/src/lisp.h}.)

El palabra @code{DEFUN} tiene siete partes dentro de los
par@'entesis:

@itemize @bullet
@item
La primera parte es el nombre dado a la funci@'on en Lisp,
@code{delete-and-extract-region}.

@item
La segunda parte es el nombre de la funci@'on en C,
@code{Fdelete_and_extract_region}. Por convenci@'on, eso empieza con
@samp{F}. Puesto que C no usa guiones en nombres, los guiones bajos son
usados a su vez.

@item
La tercera parte es el nombre para la estructura constante C que
registra informaci@'on en esta funci@'on para uso interno. Es el
nombre de la funci@'on en C pero empieza con una @samp{S} en vez de
una @samp{F}.

@item
Las partes cuarta y quinta especifican el n@'umero
m@'{@dotless{i}}nimo y m@'aximo de argumentos que la funci@'on puede
tener. Esta funci@'on demanda exactamente 2 argumentos.

@item
La sexta parte est@'a cerca del argumento que sigue la declaraci@'on
@code{interactive} en una funci@'on escrita en Lisp: una carta
seguida, quiz@'as, por una consola. La @'unica diferencia con Lisp es
que si la macro se llama sin argumentos. Entonces se escribe un @code{0}
(que es una `cadena nula'), como en esta macro.

Si se fueran a especificar argumentos, se emplazar@'{@dotless{i}}an
entre marcas de comillas. La macro C para @code{goto-char} incluye
@code{\"NGoto char \"} en esta posici@'on se indica que la funci@'on
espera un prefijo plano, en este caso, una localizaci@'on num@'erica
en un b@'uffer, y provee una consola.

@item
La s@'eptima parte es una cadena de documentaci@'on, solo como la
@'unica para una funci@'on escrita en Emacs Lisp. Esto es escrito como
un comentario C. (Cuando se escribe Emacs, el programa
@command{lib-src/make-docfile} extrae estos comentarios y los usa para
crear la documentaci@'on ``real''.)
@end itemize

@need 1200
En una macro C, los par@'ametros son los siguientes, con una frase de
este tipo de objeto se siguen por lo que podr@'{@dotless{i}}a ser
llamado el `cuerpo' de la macro. Para @code{delete-and-extract-region}
el `cuerpo' consiste de las siguientes cuatro l@'{@dotless{i}}neas:

@smallexample
@group
validate_region (&start, &end);
if (XINT (start) == XINT (end))
  return build_string ("");
return del_range_1 (XINT (start), XINT (end), 1, 1);
@end group
@end smallexample

La funci@'on @code{validate_region} chequea si los valores pasados
como el principio y fin de la regi@'on 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@'{@dotless{i}}a.

La funci@'on @code{del_range_1} actualmente borra el texto. Eso es una
funci@'on compleja que no miraremos. Eso actualiza el b@'uffer y hace
otras cosas. Sin embargo, es el valorable mirar los dos argumentos
pasados para @code{del_range}. Estos son @w{@code{XINT (start)}} y
@w{@code{XINT (end)}}.

Tan lejos como el lenguaje C es concebido, @code{start} y @code{end}
son dos enteros que marcan el principio y el fin de la regi@'on para
ser borrada@footnote{M@'as precisamente, y requiriendo conocimiento
m@'as experto para comprender, los dos enteros son del tipo
`Lisp_Object', que puede tambi@'en ser una uni@'on C en vez de un tipo
de entero.}.

En las primeras versiones de Emacs, estos dos n@'umeros fueron 32 bits
de longitud, pero el c@'odigo est@'a lentamente siendo generalizado
para manejar otras longitudes. Tres de los bits disponibles son usados
para especificar el tipo de informaci@'on; los bits permanecen ser
usados como `contenido'.

@samp{XINT} es una macro C que extrae los n@'umeros relevantes desde
la colecci@'on larga de bits; los otros tres bits se descartan.

@need 800
El comando en @code{delete-and-extract-region} se parece a esto:

@smallexample
del_range_1 (XINT (start), XINT (end), 1, 1);
@end smallexample

@noindent
Esto borra la regi@'on entre la posici@'on del principio,
@code{start}, y la posici@'on final, @code{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.

@node defvar
@section Inicializando una variable con @code{defvar}
@findex defvar
@cindex Inicializando una variable
@cindex Inicializaci@'on de Variable

@ignore
2006 Oct 24
In Emacs 22,
copy-region-as-kill is short, 12 lines, and uses
filter-buffer-substring, which is longer, 39 lines
and has delete-and-extract-region in it.
delete-and-extract-region is written in C.

see Initializing a Variable with @code{defvar}

@end ignore

La funci@'on @code{copy-region-as-kill} es escrita en Emacs Lisp. Dos
funciones con eso, @code{kill-append} y @code{kill-new}, copiar una
regi@'on en un b@'uffer y guardarlo en una variable llamada el
@code{kill-ring}. Esta secci@'on describe c@'omo la variable
@code{kill-ring} es creada e inicializada usando la forma especial
@code{defvar}.

(De nuevo se nota que el t@'ermino @code{kill-ring} es un sin
nombre. El texto que es cortado fuera del b@'uffer puede ser traido;
eso no es un corpus de anillo, pero un anillo de texto resucitable.)

En Emacs Lisp, una variable tal como @code{kill-ring} es creada y dada
por un valor inicial usando la forma especial @code{defvar}. El nombre
viene de ``definir variable''.

La forma especial @code{defvar} es similar a @code{setq} en este se
configura el valor de una variable. Eso no es @code{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, @code{defvar}
no sobreescribe el valor existente. Segundo, @code{defvar} tiene una
cadena de documentaci@'on.

(Otra forma especial, @code{defcustom}, est@'a dise@~nado para
variables que la gente personaliza. Eso tiene m@'as funcionalidades
que @code{defvar}. (@xref{defcustom, , Configurando Variables con
@code{defcustom}}.)

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

@ifnottex
@node Mira el valor actual de la variable
@unnumberedsubsec Mirando el actual valor de una variable
@end ifnottex

Se puede ver el actual valor de una variable, cualquier variable,
usando la funci@'on @code{describe-variable}, que es normalmente
invocado escribiendo @kbd{C-h v}. Si se escribe @kbd{C-h v} y
@code{kill-ring} (seguido por @key{RET}), se ver@'a que hay en tu
anillo de la muerte actual @emph{kill ring} al ser pulsado ---
@exclamdown{}esto puede ser bastante tranquilo! A la inversa, si no
has estado haciendo nada esta sesi@'on en Emacs, excepto leer este
documento, se puede no tener nada dentro. Tambi@'en, se ver@'a la
documentaci@'on para @code{kill-ring}:

@smallexample
@group
Documentaci@'on: 
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@'{@dotless{i}}a usar esta variable
@end group
@group
interact@'ua bin con `interprogram-cut-function' y
`interprogram-paste-function'. Las funciones `kill-new',
`kill-append', y `current-kill' se suponen para implementar esta
interacci@'on; se puede querer usarlo en vez de manipular en anillo de
la muerte @emph{kill ring} directamente.
@end group
@end smallexample

@need 800
El kill ring @emph{anillo de la muerte} est@'a definido por un
@code{defvar} del siguiente modo:

@smallexample
@group
(defvar kill-ring nil
  "Lista de secuencia de textos cortados.
@dots{}")
@end group
@end smallexample

@noindent
En esta definici@'on de variable, la variable es dada un valor inicial
de @code{nil}, que tiene sentido, desde que si no se ha guardado nada,
no se quiere nada si se da un comando @code{yank}. La cadena de
documentaci@'on es escrito solo como la cadena de documentaci@'on de
un @code{defun}. Como con la cadena de documentaci@'on
ser@'{@dotless{i}}a una frase completa, desde que algunos comandos,
como @code{apropos}, imprime solo la primera l@'{@dotless{i}}nea de
documentaci@'on. Las l@'{@dotless{i}}neas de exito no
ser@'{@dotless{i}}an indentadas; de otro modo se mira cuando se usa
@kbd{C-h v} (@code{describe-variable}).

@node defvar y asterisk
@subsection @code{defvar} y un asterisco
@findex defvar @r{para una variable personalizable}
@findex defvar @r{con un asterisco}

En el pasado, Emacs usaba la forma especial @code{defvar} tanto para
variables interna que no esperar@'{@dotless{i}}a que un usuario cambie
y para variables que espera un usuario cambie. Aunque se puede
todav@'{@dotless{i}}a usar @code{defvar} para variables
personalizadas, por favor, usa @code{defcustom} en vez, desde que la
forma especial provee una ruta dentro de los comando de
Personalizaci@'on. (@xref{defcustom, , Especificando Variables usando
@code{defcustom}}.)  

Cuando se especifica una variable usando la forma especial
@code{defvar}, se podr@'{@dotless{i}}a distinguir una variable que un
usuario podr@'{@dotless{i}}a querer cambiar desde otros escribiendo,
@samp{*}, en la primera columna de su cadena de documentaci@'on. Por
ejemplo:

@smallexample
@group
(defvar shell-command-default-error-buffer nil
  "*Nombre de buffer para `shell-command' @dots{} salir del error.
@dots{} ")
@end group
@end smallexample

@findex set-variable
@noindent
Tu podr@'{@dotless{i}}as (y todav@'{@dotless{i}}a puedes) usar el
comando @code{set-variable} para cambiar el valor de
@code{shell-command-default-error-buffer} temporalmente. Sin embargo,
las opciones configuradas usando @code{set-variable} no est@'an
asignadas solo por la duraci@'on de tu sesi@'on de edici@'on. Los
nuevos valores no est@'an guardados entre sesiones. Cada vez que Emacs
empieza, lee el valor original, a menos que tu cambia el valor con tu
fichero @file{.emacs}, si configur@'andolo manualmente o usando
@code{customize}. @xref{Inicializaci@'on de Emacs, , Tu Fichero
@file{.emacs}}.

Para m@'{@dotless{i}}, el mayor uso del comando @code{set-variable} es
sugerir variables que se podr@'{@dotless{i}}an querer asignar en mi
fichero @file{.emacs}. Ahora hay m@'as de 700 variables, demasiadas
para recordarlas f@'acilmente. Afortunadamente, se puede presionar
@key{TAB} despu@'es de llamar al comando @code{M-x set-variable} para
ver la lista de variables. (@xref{Examinando, , Examinando y
Configurando Variables, emacs, El Manual de GNU Emacs}.)

@need 1250
@node Revisi@'on de cons y search-fwd
@section Revisar

Aqu@'{@dotless{i}} hay un breve resumen de algunas funciones
introducidas recientemente.

@table @code
@item car
@itemx cdr
@code{car} devuelve el primer elemento de una lista; @code{cdr}
devuelve el segundo y subsiguientes elementos de una lista.

@need 1250
Por ejemplo:

@smallexample
@group
(car '(1 2 3 4 5 6 7))
     @result{} 1
(cdr '(1 2 3 4 5 6 7))
     @result{} (2 3 4 5 6 7)
@end group
@end smallexample

@item cons
@code{cons} construye una lista enlazando su primer argumento a su
segundo argumento.

@need 1250
Por ejemplo:

@smallexample
@group
(cons 1 '(2 3 4))
     @result{} (1 2 3 4)
@end group
@end smallexample

@item funcall
@code{funcall} eval@'ua su primer argumento como una
funci@'on. As@'{@dotless{i}} pasa los argumentos que permanecen a su
primer argumento.

@item nthcdr
Devuelve el resultado de tomar @sc{cdr} `n' veces en una lista.
@iftex
The
@tex
$n^{th}$
@end tex
@code{cdr}.
@end iftex
El `resto del resto', como estaba

@need 1250
Por ejemplo:

@smallexample
@group
(nthcdr 3 '(1 2 3 4 5 6 7))
     @result{} (4 5 6 7)
@end group
@end smallexample

@item setcar
@itemx setcdr
@code{setcar} cambia el primer elemento de una lista; @code{setcdr}
cambia el segundo y subsiguiente elementos de una lista.

@need 1250
Por ejemplo:

@smallexample
@group
(setq triple '(1 2 3))

(setcar triple '37)

triple
     @result{} (37 2 3)

(setcdr triple '("foo" "bar"))

triple
     @result{} (37 "foo" "bar")
@end group
@end smallexample

@item progn
Eval@'ua cada argumento en secuencia y entonces devuelve el valor del
@'ultimo.

@need 1250
Por ejemplo:

@smallexample
@group
(progn 1 2 3 4)
     @result{} 4
@end group
@end smallexample

@item save-restriction
Graba siempre que encoger est@'e en efecto en el b@'uffer, si
cualquiera, restaura este encogimiento despu@'es de evaluar los argumentos.

@item search-forward
Buscar una cadena, y si la cadena es encontrada, mueve el punto. Con
una expresi@'on regular, usa algo similar a
@code{re-search-forward}. (@xref{Buscar regexp, B@'usquedas de
Expresiones Regulares}, para una explicaci@'on de expresiones
regulares patrones y b@'usquedas.)

@need 1250
@noindent
@code{search-forward} y @code{re-search-forward} tiene cuatro argumentos:

@enumerate
@item
La cadena o la expresi@'on regular para buscar.

@item
Opcionalmente, el l@'{@dotless{i}}mite de la b@'usqueda.

@item
Opcionalmente, que haces si la b@'usqueda falla, devuelve @code{nil} o
un mensaje de error.

@item
Opcionalmente, cu@'antas veces se puede repetir la b@'usqueda; si es
negativa, la b@'usqueda va hacia atr@'as.
@end enumerate

@item kill-region
@itemx delete-and-extract-region
@itemx copy-region-as-kill

@code{kill-region} corta el texto entre punto y marca desde el
b@'uffer y almacena ese texto en el anillo de la muerte @emph{kill
ring}, as@'{@dotless{i}} se puede obtener peg@'andolo.

@code{copy-region-as-kill} copia el texto entre punto y marca dentro
del anillo de la muerte @emph{kill ring}, que se puede obtener
peg@'andolo. La funci@'on no corta o borra el texto desde el b@'uffer.
@end table

@code{delete-and-extract-region} elimina el texto entre el punto y
marca desde el b@'uffer y a trav@'es. No se puede volver. Esto no es
un comando interactivo.)

@need 1500
@node Buscar ejercicios
@section Buscando ejercicios

@itemize @bullet
@item
Escribe una funci@'on interactiva que busca una cadena. Si la
b@'usqueda encuentra la cadena, deja el punto despu@'es y muestra un
mensaje que dice ``@exclamdown{}Encontrado!''. (No use
@code{search-forward} como nombre de esta funci@'on; si se hace, se
sobreescribir@'a la versi@'on existente @code{search-forward} que
viene con Emacs. Use un nombre tal como @code{test-search} en vez de
eso.

@item
Escribe una funci@'on que imprime el tercer elemento del kill ring
@emph{anillo de la muerte} en el @'area echo, si cualquiera; si el
kill ring @emph{anillo de la muerte} no contiene un tercer elemento,
imprime un mensaje apropiado. 
@end itemize

@node Implementaci@'on de listas
@chapter C@'omo las listas se implementan
@cindex Listas en un ordenador

En Lisp, los @'atomos se graban de manera simple, si la
implementaci@'on no es sencilla en la pr@'actica, no es, nada sencilla
en la teor@'{@dotless{i}}a. El @'atomo @samp{rosa}, por ejemplo, se
graba como las cuatro letras contiguas @samp{r}, @samp{o}, @samp{s},
@samp{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 @'atomo o a
otra lista, y el segundo puntero en cada par al siguiente par, o al
s@'{@dotless{i}}mbolo @code{nil}, que marca el fin de la lista.

Un puntero por s@'{@dotless{i}} mismo es poco simple a la direcci@'on
electr@'onica de la que est@'a apuntada. Aqu@'{@dotless{i}}, una lista
se guarda como una serie de direcciones electr@'onicas.

@menu
* Listas diagramadas::       Listas diagramadas
* S@'{@dotless{i}}mbolos como cajas::  Explorando una met@'afora poderosa.
* Ejercicio Lista::          Ejercicio Lista
@end menu

@ifnottex
@node Listas diagramadas
@unnumberedsec Listas diagramadas
@end ifnottex

Por ejemplo, la lista @code{(rosa violeta bot@'ondeoro)} tiene tres
elementos, @samp{rosa}, @samp{violeta}, y @samp{bot@'ondeoro}. En el
ordenador, la direcci@'on electr@'onica de @samp{rosa} se graba en un
segmento de memoria del ordenador a trav@'es de la direcci@'on que da
la direcci@'on electr@'onica de donde el @'atomo @samp{violeta} est@'a
localizado; y esta direcci@'on (la que cuenta donde @samp{violeta}
est@'a se localiza) se guarda con una direcci@'on que cuenta donde la
direcci@'on para el @'atomo @samp{bot@'ondeoro} se localiza.

@need 1200
Esto parece m@'as complicado de lo que es y es m@'as f@'acil visto en
un diagrama:

@c clear print-postscript-figures
@c !!! cons-cell-diagram #1
@ifnottex
@smallexample
@group
    ___ ___      ___ ___      ___ ___
   |___|___|--> |___|___|--> |___|___|--> nil
     |            |            |
     |            |            |
     ---> rosa    ---> violeta ---> bot@'ondeoro
@end group
@end smallexample
@end ifnottex
@ifset print-postscript-figures
@sp 1
@tex
@center @image{cons-1}
%%%% old method of including an image
% \input /usr/local/lib/tex/inputs/psfig.tex
% \centerline{\psfig{figure=/usr/local/lib/emacs/man/cons-1.eps}}
% \catcode`\@=0 %
@end tex
@sp 1
@end ifset
@ifclear print-postscript-figures
@iftex
@smallexample
@group
    ___ ___      ___ ___      ___ ___
   |___|___|--> |___|___|--> |___|___|--> nil
     |            |            |
     |            |            |
     ---> rosa    ---> violeta ---> bot@'ondeoro
@end group
@end smallexample
@end iftex
@end ifclear

@noindent
En el diagrama, cada caja representa una palabra de memoria del
ordenador que maneja un objeto Lisp, normalmente en la forma de una
direcci@'on de memoria. Las cajas, por ej. las direcciones, est@'an en
pares. Cada flecha apunta a lo que la direcci@'on es la direcci@'on
de, si un @'atomo u otro par de direcciones. La primera caja es la
direcci@'on electr@'onica de @samp{rosa} y la flecha apunta a
@samp{rosa}; la segunda caja es la direcci@'on del siguiente par de
cajas, la primera parte de la que es la direcci@'on de @samp{violeta}
y la segunda parte es la direcci@'on del siguiente par. La @'ultima
caja apunta al s@'{@dotless{i}}mbolo @code{nil}, que marca el fin de
la lista.

@need 1200
Cuando una variable es configurado a una lista con una funci@'on tal
como @code{setq}, almacena la direcci@'on de la primera caja en la
variable. De este modo, la evaluaci@'on de la expresi@'on es:

@smallexample
(setq ramo '(rosa violeta bot@'ondeoro))
@end smallexample

@need 1250
@noindent
crea una situaci@'on como esta:

@c cons-cell-diagram #2
@ifnottex
@smallexample
@group
ramo
     |
     |     ___ ___      ___ ___      ___ ___
      --> |___|___|--> |___|___|--> |___|___|--> nil
            |            |            |
            |            |            |
             --> rosa     --> violeta   --> bot@'ondeoro
@end group
@end smallexample
@end ifnottex
@ifset print-postscript-figures
@sp 1
@tex
@center @image{cons-2}
%%%% old method of including an image
% \input /usr/local/lib/tex/inputs/psfig.tex
% \centerline{\psfig{figure=/usr/local/lib/emacs/man/cons-2.eps}}
% \catcode`\@=0 %
@end tex
@sp 1
@end ifset
@ifclear print-postscript-figures
@iftex
@smallexample
@group
ramo
     |
     |     ___ ___      ___ ___      ___ ___
      --> |___|___|--> |___|___|--> |___|___|--> nil
            |            |            |
            |            |            |
             --> rosa     --> violeta   --> bot@'ondeoro
@end group
@end smallexample
@end iftex
@end ifclear

@noindent
En este ejemplo, el s@'{@dotless{i}}mbolo @code{ramo} maneja la
direcci@'on del primer par de cajas.

@need 1200
Esta misma lista puede ser ilustrada en un modo diferente de
anotaci@'on de cajas como esta:

@c cons-cell-diagram #2a
@ifnottex
@smallexample
@group
ramo
 |
 |    --------------       ----------------       --------------------
 |   | car   | cdr  |     | car     | cdr  |     | car         | cdr  |
  -->| rosa  |   o------->| violeta |   o------->| bot@'ondeoro |  nil |
     |       |      |     |         |      |     |             |      |
      --------------       ----------------       --------------------
@end group
@end smallexample
@end ifnottex
@ifset print-postscript-figures
@sp 1
@tex
@center @image{cons-2a}
%%%% viejo m@'etodo de incluir una imagen
% \input /usr/local/lib/tex/inputs/psfig.tex
% \centerline{\psfig{figure=/usr/local/lib/emacs/man/cons-2a.eps}}
% \catcode`\@=0 %
@end tex
@sp 1
@end ifset
@ifclear print-postscript-figures
@iftex
@smallexample
@group
ramo
 |
 |    --------------       ----------------       --------------------
 |   | car   | cdr  |     | car     | cdr  |     | car         | cdr  |
  -->| rosa  |   o------->| violeta |   o------->| bot@'ondeoro |  nil |
     |       |      |     |         |      |     |             |      |
      --------------       ----------------       --------------------
@end group
@end smallexample
@end iftex
@end ifclear

(Los s@'{@dotless{i}}mbolos consisten de m@'as pares de direcciones,
pero la estructura de un s@'{@dotless{i}}mbolo es hecha de
direcciones. De manera profunda, el s@'{@dotless{i}}mbolo @code{ramo}
consiste de un grupo de cajas-de-direcciones, una que es la
direcci@'on de la palabra impresa @samp{ramo}, una segunda de la que
es la direcci@'on de una definici@'on de funci@'on adjunta al
s@'{@dotless{i}}mbolo, si cualquiera, un tercero del que es la
direcci@'on del primer par de cajas-de-direccion para la lista
@code{(rosa violeta bot@'ondeoro)}, y
as@'{@dotless{i}}. Aqu@'{@dotless{i}} se est@'a mostrando que la
tercera caja de direcci@'on del s@'{@dotless{i}}mbolo apunta al primer
par de cajas-de-direccion para la lista.)

Si un s@'{@dotless{i}}mbolo se asigna al @sc{cdr} de una lista, la
lista en s@'{@dotless{i}} no cambia; el s@'{@dotless{i}}mbolo
simplemente tiene una direcci@'on abajo de la lista. (En la jerga,
@sc{car} y @sc{cdr} son `no destructivos'.) De este modo, se eval@'ua
la siguiente expresi@'on

@smallexample
(setq flores (cdr ramo))
@end smallexample

@need 800
@noindent
produce esto:

@c cons-cell-diagram #3
@ifnottex
@sp 1
@smallexample
@group
ramo        flores
  |              |
  |     ___ ___  |     ___ ___      ___ ___
   --> |   |   |  --> |   |   |    |   |   |
       |___|___|----> |___|___|--> |___|___|--> nil
         |              |            |
         |              |            |
          --> rosa       --> violeta  --> bot@'ondeoro
@end group
@end smallexample
@sp 1
@end ifnottex
@ifset print-postscript-figures
@sp 1
@tex
@center @image{cons-3}
%%%% viejo m@'etodo de incluir una imagen
% \input /usr/local/lib/tex/inputs/psfig.tex
% \centerline{\psfig{figure=/usr/local/lib/emacs/man/cons-3.eps}}
% \catcode`\@=0 %
@end tex
@sp 1
@end ifset
@ifclear print-postscript-figures
@iftex
@sp 1
@smallexample
@group
ramo        flores
  |              |
  |     ___ ___  |     ___ ___      ___ ___
   --> |   |   |  --> |   |   |    |   |   |
       |___|___|----> |___|___|--> |___|___|--> nil
         |              |            |
         |              |            |
          --> rosa       --> violeta  --> bot@'ondeoro
@end group
@end smallexample
@sp 1
@end iftex
@end ifclear

@noindent
El valor de @code{flores} es @code{(violeta bot@'ondeoro)}, esto es
decir que el s@'{@dotless{i}}mbolo @code{flores} maneja la direcci@'on
del par address-boxes el primero que maneja la direcci@'on de
@code{violeta}, y el segundo que maneja la direcci@'on de
@code{bot@'ondeoro}.

Un par de cajas-de-direcciones se llama una @dfn{cons cell} o @dfn{par
de puntos}. @xref{Tipo de C@'elula Cons, , la C@'elula Cons y los
Tipos Lista, elisp, El Manual de Referencia de Emacs Lisp}, y
@ref{Notaci@'on de Pares de Puntos, , Notaci@'on de Pares de Puntos,
elisp, El Manual de Referencia de GNU Emacs Lisp}, para m@'as
informaci@'on acerca de c@'elulas cons y pares de puntos.

@need 1200
La funci@'on @code{cons} a@~nade un nuevo par de direcciones al frente
de una serie de direcciones como son mostradas debajo. Por ejemplo,
evaluando la expresi@'on

@smallexample
(setq ramo (cons 'lila ramo))
@end smallexample

@need 1500
@noindent
produce:

@c cons-cell-diagram #4
@ifnottex
@sp 1
@smallexample
@group
ramo                       flores
  |                             |
  |     ___ ___        ___ ___  |     ___ ___       ___ ___
   --> |   |   |      |   |   |  --> |   |   |     |   |   |
       |___|___|----> |___|___|----> |___|___|---->|___|___|--> nil
         |              |              |             |
         |              |              |             |
          --> lila      --> rosa       --> violeta    --> bot@'ondeoro
@end group
@end smallexample
@sp 1
@end ifnottex
@ifset print-postscript-figures
@sp 1
@tex
@center @image{cons-4}
%%%% viejo m@'etodo de incluir una imagen
% \input /usr/local/lib/tex/inputs/psfig.tex
% \centerline{\psfig{figure=/usr/local/lib/emacs/man/cons-4.eps}}
% \catcode`\@=0 %
@end tex
@sp 1
@end ifset
@ifclear print-postscript-figures
@iftex
@sp 1
@smallexample
@group
ramo                       flores
  |                             |
  |     ___ ___        ___ ___  |     ___ ___       ___ ___
   --> |   |   |      |   |   |  --> |   |   |     |   |   |
       |___|___|----> |___|___|----> |___|___|---->|___|___|--> nil
         |              |              |             |
         |              |              |             |
          --> lila      --> rosa       --> violeta    --> bot@'ondeoro
@end group
@end smallexample
@sp 1
@end iftex
@end ifclear

@need 1200
@noindent
Sin embargo, esto no cambia el valor del s@'{@dotless{i}}mbolo
@code{flores}, as@'{@dotless{i}} puedes ver evaluando lo siguiente,

@smallexample
(eq (cdr (cdr ramo)) flores)
@end smallexample

@noindent
que devuelve @code{t} para verdad.

Hasta que se resetea, @code{flores} todav@'{@dotless{i}}a tiene el
valor de @code{(violeta bot@'ondeoro)}; que es, eso tiene la
direcci@'on de la celula cons cuya primera direcci@'on es
@code{violeta}. Tambi@'en, esto no altera cualquier c@'elula
prexistente cons; ellas est@'a todav@'{@dotless{i}}a all@'{@dotless{i}}.

De este modo, en Lisp, tiene el @sc{cdr} de una lista, se obtiene la
direcci@'on del siguiente cons en las serie; para tener el @sc{car} de
una lista, se obtiene la direcci@'on del primer elemento de la lista;
para @code{cons} un nuevo elemento en una lista, se a@~nade una nueva
c@'elula cons al frente de la lista. @exclamdown{}Esto es todo lo que
hay as@'{@dotless{i}}! @exclamdown{}La estructura subyacente de Lisp
es brillantemente simple!

@questiondown{}Y qu@'e hace la @'ultima direcci@'on en una serie de
c@'elulas cons
se refieren? Eso es la direcci@'on de la lista vac@'{@dotless{i}}a, de
@code{nil}.

En resumen, cuando una variable Lisp es asignada a un valor, eso
provee con la direcci@'on de la lista a la que la variable se refiere.

@node S@'{@dotless{i}}mbolos como cajas
@section S@'{@dotless{i}}mbolos como una caja con cajones
@cindex S@'{@dotless{i}}mbolos como una caja con cajones
@cindex Caja con cajones, met@'afora para su s@'{@dotless{i}}mbolo
@cindex Cajones, Caja de, met@'afora para un s@'{@dotless{i}}mbolo

En una secci@'on temprana, se suger@'{@dotless{i}}a que se
podr@'{@dotless{i}}a imaginar un s@'{@dotless{i}}mbolo siendo una caja
con cajones. La definici@'on de funci@'on se pone en un caj@'on, el
valor en otro, y as@'{@dotless{i}}. Lo que se pone en el caj@'on
maneja el valor que puede cambiarse sin afectar a los contenidos del
caj@'on manejando la definici@'on de funci@'on, y viceversa.

Actualmente, lo que est@'a puesto en cada caj@'on es la direcci@'on
del valor o definici@'on de funci@'on. Eso es como si se encontrara un
viejo caj@'on en el @'atico, y en uno de sus cajones se encontrara un
mapa d@'andote direcciones a donde est@'a el tesoro escondido.

(Adem@'as de su nombre, la definici@'on del s@'{@dotless{i}}mbolo, y
un valor de la variable, un s@'{@dotless{i}}mbolo tiene un `caj@'on'
para una @dfn{lista de propiedades} que puede ser usada para grabar
otra informaci@'on. Las listas de propiedades no se discuten
aqu@'{@dotless{i}}; ver @ref{Listas de Propiedades, , Listas de
Propiedades, elisp, El Manual de Referencia de Emacs Lisp}.)

@need 1500
Aqu@'{@dotless{i}} hay una representaci@'on visionaria:

@c chest-of-drawers diagram
@ifnottex
@sp 1
@smallexample
@group
            Caja de Cajones            Contenidos de Cajones

            __   o0O0o   __
          /                 \
         ---------------------
        |    direcciones al   |            [mapeo a]
        | nombre del simbolo  |             ramo
        |                     |
        +---------------------+
        |  direcciones a la   |
        |  definici@'on del   |             [nunca]
        |    simbolo          |
        +---------------------+
        |    direcciones al   |            [mapeo a]
        |   valor de variable |       (rosa violeta bot@'ondeoro)
        |                     |
        +---------------------+
        |    direcciones a la |
        |lista de propiedades |             [no descrito aqu@'{@dotless{i}}]
        |                     |
        +---------------------+
        |/                   \|
@end group
@end smallexample
@sp 1
@end ifnottex
@ifset print-postscript-figures
@sp 1
@tex
@center @image{drawers}
%%%% viejo m@'etodo de incluir una imagen
% \input /usr/local/lib/tex/inputs/psfig.tex
% \centerline{\psfig{figure=/usr/local/lib/emacs/man/drawers.eps}}
% \catcode`\@=0 %
@end tex
@sp 1
@end ifset
@ifclear print-postscript-figures
@iftex
@sp 1
@smallexample
@group
            Caja de Cajones            Contenidos de Cajones

            __   o0O0o   __
          /                 \
         ---------------------
        |    direcciones al   |            [mapeo a]
        | nombre del simbolo  |             ramo
        |                     |
        +---------------------+
        |  direcciones a la   |
        |  definici@'on del   |             [nunca]
        |    simbolo          |
        +---------------------+
        |    direcciones al   |            [mapeo a]
        |   valor de variable |       (rosa violeta bot@'ondeoro)
        |                     |
        +---------------------+
        |    direcciones a la |
        |lista de propiedades |             [no descrito aqu@'{@dotless{i}}]
        |                     |
        +---------------------+
        |/                   \|
@end group
@end smallexample
@sp 1
@end iftex
@end ifclear

@node Ejercicio Lista
@section Ejercicio

Asignar @code{flores} a @code{violeta} y @code{bot@'ondeoro}. Asigna
dos flores m@'as en esta lista y asigna esta nueva lista a
@code{mas-flores}. Asigna el @sc{car} de @code{flores} a un
pez. @questiondown{}Qu@'e lista contiene ahora @code{mas-flores}?

@node Pegando
@chapter Pegando texto
@findex pegar
@cindex Recuperar Texto
@cindex Recuperando Texto
@cindex Pegando Texto

Siempre y cuando se corta texto fuera de un b@'uffer con un comando
`kill' en GNU Emacs, se puede traer con un comando `pegar'. El texto
cortado del b@'uffer es puesto en el anillo de la muerte y en los
comandos pegar, se insertan los contenidos apropiados del kill ring
detr@'as de un b@'uffer (no necesariamente el b@'uffer original).

Un simple comando @kbd{C-y} (@code{yank}) inserta el primer
@'{@dotless{i}}tem desde el anillo de la muerte @emph{kill ring}
dentro del actual b@'uffer. Si el comando @kbd{C-y} es seguido
inmediatamente para @kbd{M-y}, el primer elemento se reemplaza por el
segundo elemento. Los sucesivos comandos @kbd{M-y} reemplazan el
segundo elemento con el tercer, cuarto, o quinto elemento, y
as@'{@dotless{i}}. Cuando se llega al @'ultimo elemento en el anillo
de la muerte @emph{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. @xref{Qu@'e hace el anillo de
la muerte, , Manejando el anillo de la muerte @emph{kill ring}}, para
los detalles de c@'omo 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 @code{kill-ring-yank-pointer}.
@end menu

@node Resumen del anillo de la muerte
@section Resumen del anillo de la muerte
@cindex Resumen del Anillo de la Muerte @emph{Kill ring} 

El anillo de la muerte @emph{kill ring} es una lista de cadenas
textuales. Esto es lo que se ve:

@smallexample
("alg@'un texto" "una pieza diferente pieza de texto"
"todav@'{@dotless{i}}a m@'as texto")
@end smallexample

Si estos fueran los contenidos de mi anillo de la muerte @emph{kill
ring} y yo presionara @kbd{C-y}, la cadena de caracteres diciendo
@samp{alg@'un texto} ser@'{@dotless{i}}a insertado en este b@'uffer
donde mi cursor est@'a localizado. 

El comando @code{yank} @emph{pegar} es tambi@'en usado para duplicar
texto copi@'andolo. El texto copiado no es cortado desde el b@'uffer,
pero una copia de eso se pone en el anillo de la muerte @emph{kill
ring} y se inserta peg@'andolo.

Tres funciones se usan para atraer texto desde el anillo de la muerte
@emph{kill ring}: @code{yank} (@emph{pegar}), que normalmente se
asocian a @kbd{C-y}; @code{yank-pop}, que normalmente se asocia a
@kbd{M-y}; y @code{rotate-yank-pointer}, que se usa por las otras
dos funciones.

Estas funciones se refieren al kill ring @emph{anillo de la muerte} a
trav@'es de una variable llamada el @code{kill-ring-yank-pointer}. En
vez de eso, la inserci@'on del c@'odigo para ambos son las funciones
@code{yank} y @code{yank-pop}:

@smallexample
(insert (car kill-ring-yank-pointer))
@end smallexample

@noindent
(Bien, no m@'as. En GNU Emacs 22, la funci@'on se ha reemplazado por
@code{insert-for-yank} que llama a @code{insert-for-yank-1}
repetitivamente para cada segmento @code{yank-handler}. En vez de eso,
@code{insert-for-yank-1} destituye las propiedades de texto desde el
texto insertado de acuerdo a @code{yank-excluded-properties}. De otro
modo, eso es como @code{insert}. Nosotros lo pegamos con un @code{insert}
plano puesto que sea f@'acil de comprender.)

Para empezar a comprender c@'omo @code{yank} y @code{yank-pop}
funcionan, primero es necesario mirar en la variable
@code{kill-ring-yank-pointer}.

@node kill-ring-yank-pointer
@section La variable @code{kill-ring-yank-pointer}

@code{kill-ring-yank-pointer} es una variable, solo como
@code{kill-ring} es una variable. Eso apunta a alguna cosa siendo
asignada al valor de lo que apunta, como cualquier otra variable Lisp.

@need 1000
De este modo, si el valor del kill ring es:

@smallexample
("alg@'un texto" "una pieza diferente pieza de texto"
"todav@'{@dotless{i}}a m@'as texto")
@end smallexample

@need 1250
@noindent
y el @code{kill-ring-yank-pointer} apunta a la segunda cl@'ausula, el
valor de @code{kill-ring-yank-pointer} es:

@smallexample
("una pieza diferente de texto" "todav@'{@dotless{i}}a m@'as texto")
@end smallexample

Como se explica en el cap@'{@dotless{i}}tulo previo
(@xref{Implementaci@'on de listas}), el ordenador no guarda dos copias
diferentes del texto siendo apuntado por ambos el @code{kill-ring} (el
@emph{anillo de la muerte}) y el @code{kill-ring-yank-pointer} (el
@emph{puntero de pegar el anillo de la muerte}). Las
palabras ``una pieza diferente de texto'' y ``todav@'{@dotless{i}}a
m@'as texto'' no est@'an duplicadas. En vez de eso, las dos variables
Lisp apuntan a las mismas piezas de texto. Aqu@'{@dotless{i}} hay un
diagrama:

@c cons-cell-diagram #5
@ifnottex
@smallexample
@group
kill-ring     kill-ring-yank-pointer
    |               |
    |      ___ ___  |     ___ ___      ___ ___
     ---> |   |   |  --> |   |   |    |   |   |
          |___|___|----> |___|___|--> |___|___|--> nil
            |              |            |
            |              |            |
            |              |             --> "todav@'{@dotless{i}}a m@'as texto"
            |              |
            |               --> "una pieza diferente de texto"
            |
             --> "algo de texto"
@end group
@end smallexample
@sp 1
@end ifnottex
@ifset print-postscript-figures
@sp 1
@tex
@center @image{cons-5}
%%%% viejo m@'etodo de incluir una imagen
% \input /usr/local/lib/tex/inputs/psfig.tex
% \centerline{\psfig{figure=/usr/local/lib/emacs/man/cons-5.eps}}
% \catcode`\@=0 %
@end tex
@sp 1
@end ifset
@ifclear print-postscript-figures
@iftex
@smallexample
@group
kill-ring     kill-ring-yank-pointer
    |               |
    |      ___ ___  |     ___ ___      ___ ___
     ---> |   |   |  --> |   |   |    |   |   |
          |___|___|----> |___|___|--> |___|___|--> nil
            |              |            |
            |              |            |
            |              |             --> "todav@'{@dotless{i}}a m@'as texto"
            |              |
            |               --> "una pieza diferente de texto"
            |
             --> "algo de texto"
@end group
@end smallexample
@sp 1
@end iftex
@end ifclear

Tanto la variable @code{kill-ring} y la variable
@code{kill-ring-yank-pointer} son punteros. Pero el kill ring
@emph{anillo de la muerte} en s@'{@dotless{i}} es normalmente descrito
como si fuera actualmente de lo que est@'a compuesto. El
@code{kill-ring} se refiere a lo que es la lista en vez de lo que
apunta a la lista. Conversando, el @code{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
@emph{anillo de la muerte} es generalmente pensado como la estructura
completa de datos que manejan la informaci@'on de lo que se ha
cortado reci@'entemente de los b@'uffers de Emacs. El
@code{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 @sc{car}) ser@'a insertado.

@ignore
In GNU Emacs 22, the @code{kill-new} function calls

@code{(setq kill-ring-yank-pointer kill-ring)}

(defun rotate-yank-pointer (arg)
  "Rotate the yanking point in the kill ring.
With argument, rotate that many kills forward (or backward, if negative)."
  (interactive "p")
  (current-kill arg))

(defun current-kill (n &optional do-not-move)
  "Rotate the yanking point by N places, and then return that kill.
If N is zero, `interprogram-paste-function' is set, and calling it
returns a string, then that string is added to the front of the
kill ring and returned as the latest kill.
If optional arg DO-NOT-MOVE is non-nil, then don't actually move the
yanking point; just return the Nth kill forward."
  (let ((interprogram-paste (and (= n 0)
                                 interprogram-paste-function
                                 (funcall interprogram-paste-function))))
    (if interprogram-paste
        (progn
          ;; Disable the interprogram cut function when we add the new
          ;; text to the kill ring, so Emacs doesn't try to own the
          ;; selection, with identical text.
          (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)))))

@end ignore

@need 1500
@node pegar Ejercicio nthcdr
@section Ejercicios con @code{yank} y @code{nthcdr}

@itemize @bullet
@item
Usando @kbd{C-h v} (@code{describe-variable}), mira en el valor de tu
kill ring @emph{anillo de la muerte}. A@~nade varios
@'{@dotless{i}}tems a tu anillo de la muerte @emph{kill ring}; mira en
su valor de nuevo. Usando @kbd{M-y} (@code{yank-pop}, mueve todo el
camino alrededor del kill ring @emph{anillo de la
muerte}. @questiondown{}Cu@'antos @'{@dotless{i}}tems estaban en tu
kill ring @emph{anillo de la muerte}? Encuentra el valor de
@code{kill-ring-max}. @questiondown{}Estaba tu anillo de la muerte
@emph{kill ring} completo, o podr@'{@dotless{i}}as haber guardado
m@'as bloques de texto dentro?

@item
Usando @code{nthcrd} y @code{car}, construye una serie de expresiones
para devolver, el primer, segundo, tercer y cuarto elemento de una lista.
@end itemize

@node Bucles y recursi@'on
@chapter Bucles y recursi@'on
@cindex Bucles y recursi@'on
@cindex Recursi@'on y bucles
@cindex Repetici@'on (bucles)

Emacs Lisp tiene dos caminos primarios para causar una expresi@'on, o
una serie de expresiones, para ser evaluado repetidamente: uno usa un
bucle @code{while}, y el otro usa @dfn{recursi@'on}.

La repetici@'on puede ser valorable. Por ejemplo, para mover hacia
delante cuatro frases, tu solo necesitas escribir un programa que
mover@'a hacia delante una frase y entonces repite el proceso cuatro
veces. Ya que un ordenador no est@'a aburrido o cansado, tal acci@'on
repetitiva no tiene los efectos de borrado por equivocaci@'on o exceso
que pueden tener los humanos.

La gente mayoritariamente escribe funciones de Emacs Lisp usando
bucles @code{while}; pero se puede usar recursi@'on, que provee un
poderoso camino mental para resolver problemas@footnote{Se pueden
escribir funciones recursivas para ser frugal o basura mental o
recursos de ordenador; como eso ocurre, los m@'etodos que la gente
encuentra f@'aciles --- son frugales de `recursos mentales' ---
algunas veces usan recursos de ordenador considerables. Emacs fu@'e
dise@~nado para ejecutarse en m@'aquinas que ahora se consideran
limitadas y sus configuraciones por defecto son conservadoras. Se puede
querer incrementar los valores de @code{max-specdl-size} y
@code{max-lisp-eval-depth}. En mi fichero @file{.emacs}, yo los asigno
a 15 o 30 veces su valor por defecto.}.

@menu
* while::                    Causando un cierto c@'odigo para repetir.
* Dolist y dotimes::         Dolist y dotimes
* Recursi@'on::              Causando que una funci@'on se llame a 
                               s@'{@dotless{i}} misma.
* Ejercicio de Bucle::       Ejercicio de Bucle
@end menu

@node while
@section @code{while}
@cindex Bucles
@findex while

La forma especial @code{while} chequea si el valor devuelto para
evaluar el primer argumento es verdadero o falso. Esto es parecido a
lo que el int@'erprete Lisp hace con un @code{if}; el int@'erprete
hace lo siguiente, sin embargo, es diferente.

En una expresi@'on @code{while}, si el valor devuelto por evaluar el
primer argumento es falso, el int@'erprete Lisp descarta el resto de la
expresi@'on (el @dfn{cuerpo} de la expresi@'on) y no la eval@'ua. Sin
embargo, si el valor es cierto, el int@'erprete Lisp eval@'ua el
cuerpo de la expresi@'on y entonces de nuevo chequea si el primer
argumento para @code{while} es cierto o falso. Si el valor devuelto de
evaluar el primer argumento es cierto de nuevo, el int@'erprete Lisp
eval@'ua el cuerpo de la expresi@'on.

@need 1200
La plantilla para una expresi@'on @code{while} se ve as@'{@dotless{i}}:

@smallexample
@group
(while @var{test-verdadero-o-falso}
  @var{cuerpo}@dots{})
@end group
@end smallexample

@menu
* Bucles while::             Repetir tantas veces como el test devuelva 
                               verdadero.
* Ejemplo de bucle::         Un bucle @code{while} que usa una lista.
* print-elements-of-list::   Usos @code{while}, @code{car}, @code{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.
@end menu

@ifnottex
@node Bucles while
@unnumberedsubsec Bucles con @code{while}
@end ifnottex

En el momento en el que el true-or-false-test de la expresi@'on
@code{while} devuelve un valor cierto cuando eso se eval@'ua, el
cuerpo es repetidamente evaluado. Este proceso se llama bucle puesto
que el int@'erprete Lisp repite la misma cosa una y otra vez, como un
avi@'on haciendo un loop. Cuando el resultado de evaluar el
true-or-false-test es falso, el int@'erprete Lisp no eval@'ua el resto
de la expresi@'on @code{while} y `existe el bucle'.

Claramente, si el valor devuelto evaluando el primer argumento para
@code{while} es siempre cierto, el cuerpo siguiente ser@'a evaluado
una y otra vez @dots{} y @dots{} para
siempre. Rec@'{@dotless{i}}procamente, si el valor devuelto nunca es
cierto, las expresiones en el cuerpo nunca ser@'an evaluadas. La
fortaleza de escribir un bucle @code{while} consiste de elegir un
mecanismo tal que el true-or-false-test devuelva cierto solo el
n@'umero de veces que requieren las subsiguientes expresiones para
ser evaluadas, y entonces tener el test devuelto a falso.

El valor devuelto evaluando @code{while} es el valor del
true-or-false-test. Una consecuencia interesante de esto es que un
bucle @code{while} que eval@'ua sin errores devolver@'a @code{nil} o
falso sin dignidad de si eso ha girado 1 o 100 veces o
ninguna. @exclamdown{}Una expresi@'on @code{while} que se eval@'ua de
manera exitosa nunca devuelve un valor cierto! Lo que esto significa
es que @code{while} es siempre evaluado por sus efectos laterales, que
es decir, las consecuencias de evaluar las expresiones con el cuerpo
del bucle @code{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.

@node Ejemplo de bucle
@subsection Un bucle @code{while} y una lista

Un camino com@'un para controlar un bucle @code{while} es chequear si
una lista tiene cualquier elemento. Si eso se hace, el bucle se
repite; pero si no, la repetici@'on se finaliza. Puesto que esto es
una t@'ecnica importante, se crear@'a 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@'{@dotless{i}}a y devuelve la lista vac@'{@dotless{i}}a,
@code{()}, que es un sin@'onimo para @code{nil} o falso. Por otro
lado, una lista con elementos devolver@'a estos elementos cuando eso
se eval@'ua. Puesto que Emacs Lisp considera como cierto cualquier
valor que no es @code{nil}, una lista que devuelve elementos
chequear@'a cierto en un bucle @code{while}.

@need 1200
Por ejemplo, se puede asignar la variable @code{empty-list} a
@code{nil} para evaluar la siguiente expresi@'on @code{setq}:

@smallexample
(setq lista-vacia ())
@end smallexample

@noindent
Despu@'es de evaluar la expresi@'on @code{setq}, se puede evaluar la
variable @code{lista-vacia} es el camino normal, posicionando el cursor
despu@'es del s@'{@dotless{i}}mbolo y escribiendo @kbd{C-x C-e};
@code{nil} aparecer@'a en tu @'area echo:

@smallexample
lista-vacia
@end smallexample

Por otro lado, si se asigna una variable para ser una lista con
elementos, la lista aparecer@'a cuando se eval@'ue la variable, como
se puede ver evaluando las siguientes dos expresiones:

@smallexample
@group
(setq animales '(gacela jirafa leon tigre))

animales
@end group
@end smallexample

De este modo, para un bucle @code{while} que chequea si hay cualquier
@'{@dotless{i}}tem en la lista @code{animales}, la primera parte del
bucle ser@'a escrito as@'{@dotless{i}}:

@smallexample
@group
(while animales
       @dots{}
@end group
@end smallexample

@noindent
Cuando el @code{while} chequea su primer argumento, la variable
@code{animales} se eval@'ua. Eso devuelve una lista. Mientras la
lista tiene elementos, el @code{while} considera los resultados del
test para ser verdadero; pero cuando la lista es vac@'{@dotless{i}}a,
eso considera los resultados del test para ser falso.

Para prevenir que el bucle @code{while} se ejecute siempre, se
necesita proporcionar alg@'un mecanismo. Una t@'ecnica usada con
frecuencia es tener una de las subsiguientes formas en la expresi@'on
@code{while} que asigna el valor de la lista para ser el @sc{cdr} de
la lista. Cada vez que la funci@'on @code{cdr} se eval@'ua, se va
reduciendo, hasta que finalmente solo queda la lista
vac@'{@dotless{i}}a. En este punto, el test del bucle @code{while}
devolver@'a falso, y los argumentos para el @code{while} no se
evaluar@'an.

Por ejemplo, la lista de animales asociada a la variable
@code{animals} se puede asignar a ser el @sc{cdr} de la lista original
con la siguiente expresi@'on:

@smallexample
(setq animals (cdr animals))
@end smallexample

@noindent
Si se han evaluado las expresiones previas y entonces se eval@'ua esta
expresi@'on, se ver@'a @code{(jirafa leon tigre)} que aparecer@'a en
el @'area echo. Si se eval@'ua la expresi@'n de nuevo, @code{(leon
tigre)} aparecer@'a en el @'area echo. Si se eval@'ua de nuevo,
@code{(tigre)} y todav@'{@dotless{i}}a de nuevo aparecer@'a la lista
vac@'{@dotless{i}}a y se mostrar@'a como @code{nil}.

Una plantilla para un bucle @code{while} usa la funci@'on @code{cdr}
repetidamente para causar el true-or-false-test finalmente para
chequear la veracidad y se parece a esto:

@smallexample
@group
(while @var{test-whether-list-is-empty}
  @var{body}@dots{}
  @var{set-list-to-cdr-of-list})
@end group
@end smallexample

Este chequeo y uso de @code{cdr} puede ser puesto junto a una
funci@'on que va a trav@'es de una lista e imprime cada elemento de la
lista en una l@'{@dotless{i}}nea de s@'{@dotless{i}} misma.

@node print-elements-of-list
@subsection Un ejemplo: @code{imprimir-elementos-de-la-lista}
@findex print-elements-of-list

La funci@'on @code{imprimir-elementos-de-la-lista} ilustra un bucle
@code{while} con una lista.

@cindex @file{*scratch*} buffer
@c GNU Emacs 21, GNU Emacs 22, or a later version,
La funci@'on requiere varias l@'{@dotless{i}}neas por su salida. Si
est@'as leyendo esto en una instancia reciente de GNU Emacs, se puede
evaluar la siguiente expresi@'on dentro de Info, de normal.

Si se est@'a usando una versi@'on antigua de Emacs, es necesario
copiar las expresiones necesarias para el b@'uffer @file{*scratch*} y
evaluarlas all@'{@dotless{i}}. Esto es porque el @'area echo
ten@'{@dotless{i}}a solo una l@'{@dotless{i}}nea en las versiones
antiguas.

Se pueden copiar las expresiones marcando el principio de la regi@'on
con @kbd{C-@key{SPC}} (@code{set-mark-command}), moviendo el cursor al
fin de la regi@'on y entonces copiando la regi@'on usando @kbd{M-w}
(@code{kill-ring-save}, que llama a @code{copy-region-as-kill} y
entonces provee realimentaci@'on visual). En el b@'uffer
@file{*scratch*}, se pueden copiar las expresiones escribiendo
@kbd{C-y} (@code{yank}).

Despu@'es de haber copiado las expresiones al b@'uffer
@file{*scratch*}, se eval@'ua cada expresi@'on en orden. Aseg@'urese
de evaluar la @'ultima expresi@'on, @code{(imprimir-elementos-de-la-lista
animales)}, escribiendo @kbd{C-u C-x C-e}, que es, dando un argumento
para @code{eval-last-sexp}. Esto causar@'a el resultado de la
evaluaci@'on para ser impreso en el b@'uffer @file{*scratch*} en vez
de siendo impreso en el @'area echo. (De otro modo se ver@'a alguna
cosa como esto en tu @'area echo:
@code{^Jgacela^J^Jjirafa^J^Jleon^J^Jtigre^Jnulo}, en cada @samp{^J} se
estructura una `nueva l@'{@dotless{i}}nea'.)

@need 1500
En una instancia de GNU Emacs reciente, se pueden evaluar estas
expresiones directamente en el b@'uffer Info, y el @'area echo crecer@'a
para mostrar los resultados.

@smallexample
@group
(setq animales '(gacela jirafa leon tigre))

(defun imprimir-elementos-de-la-lista (list)
  "Imprime cada elemento de LIST en una l@'{@dotless{i}}nea."
  (while list
    (print (car list))
    (setq list (cdr list))))

(imprimir-elementos-de-la-lista animales)
@end group
@end smallexample

@need 1200
@noindent
Cuando se eval@'uan las tres expresiones en secuencia, se ver@'a esto:

@smallexample
@group
gacela

jirafa

leon

tigre
nil
@end group
@end smallexample

Cada elemento de la lista se imprime en una l@'{@dotless{i}}nea en
s@'{@dotless{i}} (que es lo que la funci@'on @code{print} hace) y
entonces el valor devuelto por la funci@'on se imprime. Desde que la
@'ultima expresi@'on en la funci@'on es el bucle @code{while}, y
desde que el bucle @code{while} siempre devuelve @code{nil}, un
@code{nil} se imprime despu@'es del @'ultimo elemento de la lista.

@node Incrementando el Bucle
@subsection Un bucle con un contaje incremental

Un bucle no es @'util a menos que pare cuando debe. Bajo el control de
un bucle con una lista, un camino com@'un de parar un bucle es
escribir el primer argumento como un test que devuelve falso cuando el
n@'umero correcto de repeticiones es completo. Esto significa que el
bucle debe tener un contador --- una expresi@'on que cuenta cu@'antas
veces el bucle se repite a s@'{@dotless{i}} mismo.

@ifnottex
@node Incrementando los detalles de los bucles
@unnumberedsubsec Detalles de un bucle que se incrementa
@end ifnottex

El test para un bucle con un contador de incremento puede ser una
expresi@'on tal como @code{(< contador numero-deseado)} que devuelve
@code{t} para verdad si el valor de @code{contador} es menor que el
@code{numero-deseado} de repeticiones y @code{nil} para falso si el
valor de @code{contador} es igual a o es mayor que el
@code{numero-deseado}. La expresi@'on que incrementa el contador puede
ser un simple @code{setq} tal como @code{(setq contador (1+ contador))},
donde @code{1+} es una funci@'on construida en Emacs Lisp que a@~nade
1 a su argumento. (La expresi@'on @w{@code{(1+ contador)}} tiene el mismo
resultado que @w{@code{(+ contador 1)}}, que es f@'acil de leer para un
humano.)

@need 1250
La plantilla para un bucle @code{while} controlado por un contador
que se incrementa se parece a esto:

@smallexample
@group
@var{asignar-contador-al-valor-inicial}
(while (< contador numero-deseado)         ; @r{true-or-false-test}
  @var{body}@dots{}
  (setq contador (1+ contador)))              ; @r{incremento}
@end group
@end smallexample

@noindent
Note que se necesita asignar el valor inicial de @code{contador};
normalmente asignado a 1.

@menu
* Ejemplo de Incremento::    Contando esquinas en un tri@'angulo.
* Partes Inc de Ejemplo::    Las partes de la definici@'on de funci@'on.
* Ejemplo Inc junto::        Poniendo la definici@'on de funci@'on junta.
@end menu

@node Ejemplo de Incremento
@unnumberedsubsubsec Ejemplo con contador incremental

Sup@'on que est@'as jugando en la playa y decides crear un tri@'angulo
de asteriscos, poniendo un asterisco en la primera fila, dos en la
segunda fila, tres en la tercera fila y as@'{@dotless{i}}:

@sp 1
@c pebble diagram
@ifnottex
@smallexample
@group
               *
              * *
             * * *
            * * * *
@end group
@end smallexample
@end ifnottex
@iftex
@smallexample
@group
               @bullet{}
              @bullet{} @bullet{}
             @bullet{} @bullet{} @bullet{}
            @bullet{} @bullet{} @bullet{} @bullet{}
@end group
@end smallexample
@end iftex
@sp 1

@noindent
(Hace 2500 a@~nos, Pit@'agoras y otras desarrollaron los principios de
la teor@'{@dotless{i}}a de n@'umeros considerando preguntas como esta.)

Sup@'on que quieres saber cu@'antos asteriscos necesitar@'as crear para un
tri@'angulo con 7 filas

Claramente, lo que necesitas hacer es a@~nadir los n@'umeros de 1 a
7. Hay dos caminos para hacer esto; se puede comenzar con los
n@'umeros m@'as peque@~nos, uno, y a@~nadir la lista en secuencia, 1,
2, 3, 4 y as@'{@dotless{i}}; o empieza con el n@'umero m@'as largo y
a@~nade la lista bajando: 7, 6, 5, 4 y as@'{@dotless{i}}. Porque ambos
mecanismos ilustran caminos comunes de escribir el bucle @code{while},
crearemos dos ejemplos, uno contando hacia arriba y el otro contando
hacia abajo. En este primer ejemplo, empezaremos con 1 y a@~nadimos 2,
3, 4 y as@'{@dotless{i}}.

Si se quiere sumar toda una lista de n@'umeros, el camino m@'as
f@'acil para hacer eso es sumar todos los n@'umeros a la vez. Sin
embargo, si no se sabe cu@'antos n@'umeros tendr@'a la lista, o si se
requiere estar preparado para una lista muy larga, entonces se
necesita dise@~nar la adici@'on, esto es, repetir un proceso simple
muchas veces en vez de hacer un proceso m@'as complejo.

Por ejemplo, en vez de a@~nadir todos los asteriscos a la vez, lo que
se puede hacer es a@~nadir el n@'umero de asteriscos en la primera
fila, 1, para el n@'umero en la segunda fila, 2, y entonces a@~nadir
el total de estas dos filas a la tercera fila, 3. Entonces se puede
a@~nadir el n@'umero en la cuarta fila, 4, al total de las primeras
tres filas; y as@'{@dotless{i}}.

La caracter@'{@dotless{i}}stica cr@'{@dotless{i}}tica del proceso es
que cada acci@'on repetitiva sea simple. En este caso, en cada paso
nosotros a@~nadimos solo dos n@'umeros, el n@'umero de asteriscos en
la fila y el total ya encontrado. Este proceso de a@~nadir dos
n@'umeros es repetido de nuevo y de nuevo hasta la @'ultima fila que
ha sido a@~nadida al total de todas las filas precedentes. En un
bucle m@'as complejo la acci@'on repetitiva podr@'{@dotless{i}}a no
ser tan simple, pero ser@'a tan simple como hacer todo a la vez.

@node Partes Inc de Ejemplo
@unnumberedsubsubsec Las partes de la definici@'on de funci@'on

El an@'alisis precedente nos da los bonos de nuestra definici@'on de
funci@'on: primero, necesitaremos una variable que podemos llamar
@code{total} que ser@'a el n@'umero total de asteriscos. Esto ser@'a
el valor devuelto por la funci@'on.

Segundo, sabemos que la funci@'on requerir@'a un argumento: este
argumento ser@'a el n@'umero de filas en el tri@'angulo. Eso puede
llamarse @code{number-of-rows}.

Finalmente, se necesita una variable para usarse como contador. Se
podr@'{@dotless{i}}a llamar a esta variable @code{counter}, pero un
nombre mejor es @code{row-number}. Debido a que lo que el contador hace
en esta funci@'on es contar filas, y un programa deber@'{@dotless{i}}a
escribirse para ser comprendido en la medida de lo posible.

Cuando el int@'erprete Lisp primero empieza evaluando las expresiones
de la funci@'on, el valor de @code{total} estar@'{@dotless{i}}a
asignado a cero, ya que no hemos a@~nadido cualquier cosa a
eso. Entonces la funci@'on a@~nadir@'{@dotless{i}}a el n@'umero de
asteriscos en la primera fila al total, y entonces a@~nade el n@'umero
de asteriscos en la segunda al total, y entonces a@~nade el n@'umero
de asteriscos a la tercera fila al total, y as@'{@dotless{i}}, hasta
que no hay m@'as filas a la izquierda para a@~nadir.

Ambos @code{total} y @code{row-number} se usan solo dentro de la
funci@'on, as@'{@dotless{i}} ellos pueden ser declarados como
variables locales con @code{let} y valores iniciales
dados. Claramente, el valor inicial para total ser@'{@dotless{i}}a
0. El valor inicial de @code{row-number} ser@'{@dotless{i}}a 1, desde
que se comienza con la primera fila. Esto significa que la frase
@code{let} se parece a esto:

@smallexample
@group
  (let ((total 0)
        (row-number 1))
    @var{body}@dots{})
@end group
@end smallexample

Despu@'es de que las variables internas se declaran y se asignan a
sus valores iniciales se podr@'{@dotless{i}}a empezar el bucle
@code{while}. La expresi@'on que sirve como el test
devolver@'{@dotless{i}}a un valor de @code{t} para la verdad tan
grande como el @code{row-number} que es menor o igual al
@code{number-of-rows}. (La expresi@'on devuelve cierto solo si el
n@'umero de fila es menor que el n@'umero de filas en el tri@'angulo,
la @'ultima fila nunca ser@'a a@~nadida al total; aqu@'{@dotless{i}}
el n@'umero de fila tiene que ser menor o igual el n@'umero de
filas.))

@need 1500
@findex <= @r{(menos que igual)}
Lisp provee la funci@'on @code{<=} 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@'{@dotless{i}} la expresi@'on que el
@code{while} evaluar@'a como si su test se ver@'{@dotless{i}}a como esto:

@smallexample
(<= row-number number-of-rows)
@end smallexample

El n@'umero de asteriscos puede encontrarse repetidamente a@~nadiendo
el n@'umero de asteriscos en una fila al total ya encontrado. Puesto
que el n@'umero de asteriscos en la fila es igual al n@'umero de la
fila, el total puede encontrarse a@~nadiendo el n@'umero de filas
al total. (Claramente, en una situaci@'on m@'as compleja, el n@'umero
de asteriscos en la fila podr@'{@dotless{i}}a ser relacionada al
n@'umero de la fila en un camino m@'as complicado; si este fuera el
caso, el n@'umero de fila ser@'{@dotless{i}}a reemplazado por la
expresi@'on apropiada.)

@smallexample
(setq total (+ total row-number))
@end smallexample

@noindent
Lo que esto hace es asignar el nuevo valor de @code{total} a ser igual a
la suma de a@~nadiendo el n@'umero de asteriscos en la fila al total previo.

Despu@'es de configurar el valor de @code{total}, las condiciones
deben ser establecidas para la siguiente repetici@'on del bucle,
si hay alguna. Esto se hace incrementando el valor de la variable
@code{row-number}, que sirve como un contador. Despu@'es que la
variable @code{row-number} ha sido incrementada, el true-or-false-test
al principio del bucle @code{while} chequea si su valor es
todav@'{@dotless{i}}a menor o igual al valor del @code{number-of-rows}
y si eso es, a@~nade el nuevo valor de la variable @code{row-number}
al @code{total} de la repetici@'on del bucle.

@need 1200
La funci@'on construida en Emacs Lisp @code{1+} a@~nade 1 a un
n@'umero, as@'{@dotless{i}} la variable @code{row-number} puede ser
incrementado con esta expresi@'on:

@smallexample
(setq row-number (1+ row-number))
@end smallexample

@node Ejemplo Inc junto
@unnumberedsubsubsec Poniendo la definici@'on de la funci@'on junta

Nosotros hemos creado las partes para la definici@'on de la funci@'on;
ahora necesitamos ponerlas juntas.

@need 800
Primero, los contenidos de la expresi@'on @code{while}:

@smallexample
@group
(while (<= row-number number-of-rows)   ; @r{true-or-false-test}
  (setq total (+ total row-number))
  (setq row-number (1+ row-number)))    ; @r{incremento}
@end group
@end smallexample

Tener la expresi@'on @code{let} de varlist, se acerca a completar el
cuerpo de la definici@'on de funci@'on. Sin embargo, eso requiere un
elemento final, la necesidad para la que es alguna cosa peque@~na.

El toque final es emplazar la variable @code{total} en una
l@'{@dotless{i}}nea por s@'{@dotless{i}} misma despu@'es de la
expresi@'on @code{while}. De otro modo, el valor devuelto por la
funci@'on completa es el valor de la @'ultima expresi@'on que es
evaluada en el cuerpo del @code{let}, y este es el valor devuelto por
el @code{while} que es siempre @code{nil}.

Esto puede no ser evidente a primera vista. Eso casi se ve como si la
expresi@'on de incremento es la @'ultima expresi@'on de la funci@'on
completa. Pero esta expresi@'on es parte del cuerpo del @code{while};
eso es el @'ultimo elemento de la lista que empieza con el
s@'{@dotless{i}}mbolo @code{while}. M@'as all@'a, el bucle
@code{while} completo es una lista con el cuerpo del @code{let}.

@need 1250
En l@'{@dotless{i}}nea (@emph{outline}), la funci@'on se parece a esto:

@smallexample
@group
(defun @var{name-of-function} (@var{argument-list})
  "@var{documentation}@dots{}"
  (let (@var{varlist})
    (while (@var{true-or-false-test})
      @var{body-of-while}@dots{} )
    @dots{} ))                    ; @r{Necesita la expresi@'on final aqu@'{@dotless{i}}.}
@end group
@end smallexample

El resultado de evaluar el @code{let} es que lo que est@'a yendo para
devolver el @code{defun} desde el @code{let} que no est@'a embebido
con cualquier lista que contiene, excepto para la @code{defun} como un
todo. Sin embargo, si el @code{while} es el @'ultimo elemento de la
expresi@'on @code{let}, la funci@'on siempre devolver@'a
@code{nil}. @exclamdown{}Esto no es lo que quiero! En vez de eso, lo
que queremos es el valor de la variable @code{total}. Eso devuelve
simplemente emplazando el s@'{@dotless{i}}mbolo como el @'ultimo
elemento de la lista empezando con @code{let}. Eso se eval@'ua
despu@'es de los elementos precedentes de la lista evaluada, que
significa que eso se evalu@'o despu@'es de haber sido asignado el
valor correcto para el total.

Eso puede ser f@'acil de ver imprimiendo la lista empezando con
@code{let} todo en una l@'{@dotless{i}}nea. Este formato hace evidente
que las expresiones @var{varlist} y @code{while} son el segundo el
tercer elementos de la lista empezando con @code{let}, y el
@code{total} es el @'ultimo elemento:

@smallexample
@group
(let (@var{varlist}) (while (@var{true-or-false-test}) 
@var{body-of-while}@dots{} ) total)
@end group
@end smallexample

@need 1200
Poniendo cualquier cosa junta, la definici@'on de funci@'on
@code{triangle} se parece a esto:

@smallexample
@group
(defun triangle (number-of-rows)    ; @r{Versi@'on con}
                                    ; @r{ contador de incremento.}
  "A@~nade el n@'umero de asteriscos en un tri@'angulo.
La primera fila tiene un asterisco, la segunda fila dos asteriscos,
la tercera fila tres asteriscos, y as@'{@dotless{i}}.
El argumento es NUMBER-OF-ROWS."
@end group
@group
  (let ((total 0)
        (row-number 1))
    (while (<= row-number number-of-rows)
      (setq total (+ total row-number))
      (setq row-number (1+ row-number)))
    total))
@end group
@end smallexample

@need 1200
Despu@'es de haber instalado @code{triangle} para evaluar la funci@'on,
se puede probar. Aqu@'{@dotless{i}} hay dos ejemplos:

@smallexample
@group
(triangle 4)

(triangle 7)
@end group
@end smallexample

@noindent
La suma del primero de cuatro n@'umeros es 10 y la suma de los primeros
siete n@'umeros es 28.

@node Bucle que se decrementa
@subsection Bucle que decrementa

Otro camino com@'un para escribir un bucle @code{while} es escribir el
test as@'{@dotless{i}} que determina si un contador es mayor que
cero. As@'{@dotless{i}} 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@'as peque@~no y peque@~no por una
forma que es evaluada repetidamente.

El test ser@'a una expresi@'on tal como @code{(> counter 0)} que
devuelve @code{t} @emph{cierto} si el valor de @code{counter} es mayor
que cero, y @code{nil} @emph{falso} si el valor de @code{counter} es
igual a o menor que cero. La expresi@'on hace que el n@'umero menor y
menor puede ser un simple @code{setq} tal como @code{(setq counter (1-
counter)}, donde @code{1-} es una funci@'on construida en Emacs Lisp
que sustrae 1 de su argumento.

@need 1250
La plantilla para decrementar el bucle @code{while} se ve
as@'{@dotless{i}}:

@smallexample
@group
(while (> counter 0)                    ; @r{test-verdadero-o-falso}
  @var{body}@dots{}
  (setq counter (1- counter)))          ; @r{decremento}
@end group
@end smallexample

@menu
* Ejemplo de Decremento::    M@'as piedras en la playa.
* Partes de Ejemplo Dec::    Las partes de la definici@'on de funci@'on.
* Ejemplo Dec junto::        Poniendo la definici@'on de funci@'on junta.
@end menu

@node Ejemplo de Decremento
@unnumberedsubsubsec Ejemplo con el contador que se decrementa

Para ilustrar un bucle con un contador de decremento, reescribir@'a la
funci@'on @code{triangle} as@'{@dotless{i}} como el contador se
decrementa a cero.

Esto es lo inverso de la versi@'on temprana de la funci@'on. En este
caso, para encontrar cu@'antos asteriscos son necesarios para crear un
tri@'angulo con 3 filas, a@~nade el n@'umero de asteriscos en la
tercera fila, 3, para el n@'umero en la fila precedente, 2, y entonces
a@~nade el total de estas dos filas a la fila que lo precede, 1.

M@'as all@'a, para encontrar el n@'umero de asteriscos en un
tri@'angulo con 7 filas, a@~nade el n@'umero de asteriscos en la fila
siete, 7, al n@'umero en la fila precedente, que es 6, y entonces
a@~nade el total de estas dos filas a la fila esta que lo precede,
que es 5, y as@'{@dotless{i}}. Como en el ejemplo previo, cada
adici@'on solo involucra la adici@'on de dos n@'umeros, el total de
las filas ya se a@~nadi@'o y el n@'umero de asteriscos en la fila que
est@'a siendo a@~nadida al total. Este proceso de a@~nadir dos
n@'umeros se repite de nuevo y de nuevo hasta que no haya m@'as
asteriscos que a@~nadir.

Sabemos con cu@'antos asteriscos empezar: el n@'umero de asteriscos en
la @'ultima fila es igual al n@'umero de filas. Si el tri@'angulo
tiene siete filas, el n@'umero de asteriscos en la @'ultima fila es
7. M@'as all@'a, sabemos cu@'antos asteriscos est@'an en la fila
precedente: eso es uno menos que el n@'umero en la fila.

@node Partes de Ejemplo Dec
@unnumberedsubsubsec Las partes de la definici@'on de funci@'on

Empezamos con tres variables: el n@'umero total de filas en el
tri@'angulo; el n@'umero de asteriscos en una fila; y el n@'umero
total de asteriscos, que es lo que queremos calcular. Estas variables
pueden llamarse @code{number-of-rows},
@code{number-of-pebbles-in-row}, y @code{total}, respectivamente.

Ambos @code{total} y @code{number-of-pebbles-in-row} se usan solo
dentro de la funci@'on y se declaran con @code{let}. El valor
inicial de @code{total} ser@'{@dotless{i}}a cero. Sin embargo, el
valor inicial de @code{number-of-pebbles-in-row} ser@'{@dotless{i}}a
igual al n@'umero de filas en el tri@'angulo, desde la adici@'on
empezar@'a con la fila m@'as larga.

@need 1250
Esto significa que el principio de la expresi@'on @code{let} se ver@'a
as@'{@dotless{i}}:

@smallexample
@group
(let ((total 0)
      (number-of-pebbles-in-row number-of-rows))
  @var{body}@dots{})
@end group
@end smallexample

El n@'umero total de asteriscos puede encontrarse repetidamente
a@~nadiendo el n@'umero de asteriscos en una fila para el total ya
encontrado, que, se eval@'ua repetidamente en la siguiente
expresi@'on:

@smallexample
(setq total (+ total number-of-pebbles-in-row))
@end smallexample

@noindent
Despu@'es el @code{number-of-pebbles-in-row} se a@~nade al
@code{total}, el @code{number-of-pebbles-in-row} ser@'{@dotless{i}}a
decrementado por uno, desde que la siguiente vez el bucle repite, la
fila precedente ser@'a a@~nadida al total.

El n@'umero de asteriscos en una fila precedente es uno menos que el
n@'umero de asteriscos en una fila, as@'{@dotless{i}} la funci@'on
Emacs Lisp construida @code{1-} puede usarse para computar el n@'umero
de asteriscos de la fila precedente. Esto puede ser hecho con la
siguiente expresi@'on:

@smallexample
@group
(setq number-of-pebbles-in-row
      (1- number-of-pebbles-in-row))
@end group
@end smallexample

Finalmente, sabemos que el bucle @code{while} parar@'{@dotless{i}}a
creando repetidas adiciones cuando no hay asteriscos en una
fila. As@'{@dotless{i}} el test para el bucle @code{while} es simple:

@smallexample
(while (> number-of-pebbles-in-row 0)
@end smallexample

@node Ejemplo Dec junto
@unnumberedsubsubsec Poniendo la definici@'on de la funci@'on junta

Se pueden poner estas expresiones juntas para crear una definici@'on de
funci@'on que funcione. Sin embargo, al examinarlas, encontraremos que
una de la variables locales @exclamdown{}es innecesaria!

@need 1250
La definici@'on de funci@'on se ve como esto:

@smallexample
@group
;;; @r{Primero la versi@'on substractiva.}
(defun triangle (number-of-rows)
  "A@~nade el n@'umero de asteriscos en un tri@'angulo."
  (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))
@end group
@end smallexample

Como se dijo, esta funci@'on funciona.

Sin embargo, no se necesita @code{number-of-pebbles-in-row}.

@cindex Argumento como variable local
Cuando la funci@'on @code{triangle} se eval@'ua, el
s@'{@dotless{i}}mbolo @code{number-of-rows} ser@'a asociado al
n@'umero, dando un valor inicial. Este n@'umero puede ser cambiado en
el cuerpo de la funci@'on si hubiera una variable local, sin miedo
de que tal cambio se efectuar@'a el valor de la variable fuera de la
funci@'on. Esto es una caracter@'{@dotless{i}}stica muy @'util de Lisp;
eso significa que la variable @code{number-of-rows} puede ser usada en
cualquier lugar en la funci@'on donde @code{number-of-pebbles-in-row}
se usa.

@need 800
Aqu@'{@dotless{i}} hay una segunda versi@'on de la funci@'on escrita un
poco m@'as limpiamente:

@smallexample
@group
(defun triangle (number)                ; @r{Segunda versi@'on.}
  "Devuelve la suma de n@'umeros 1 a trav@'es de NUMBER inclusive."
  (let ((total 0))
    (while (> number 0)
      (setq total (+ total number))
      (setq number (1- number)))
    total))
@end group
@end smallexample

En breve, un bucle @code{while} apropiadamente escrito consistir@'a de
tres partes:

@enumerate
@item
Un test que devuelva falso despu@'es de que el bucle ha repetido por
s@'{@dotless{i}} mismo el n@'umero de veces correcto.

@item
Una expresi@'on de la evaluaci@'on de que devolver@'a el valor deseado
despu@'es de ser repetidamente evaluado.

@item
Una expresi@'on para cambiar el valor pasado al true-or-false-test
as@'{@dotless{i}} el test devuelve falso despu@'es de que el bucle
se ha repetido por s@'{@dotless{i}} mismo el n@'umero de veces
correcto.
@end enumerate

@node Dolist y dotimes
@section Ahorra tiempo: @code{dolist} y @code{dotimes}

Adem@'as de @code{while}, tanto @code{dolist} como @code{dotimes}
proveen un bucle. Algunas veces estos son r@'apidos para escribir
el bucle equivalente @code{while}. Ambos son macros
Lisp. (@xref{Macros, , Macros, elisp, El Manual de Referencia GNU
Emacs Lisp}.)

@code{dolist} funciona como un bucle @code{while} con `@sc{cdr}s que
bajan la lista': @code{dolist} autom@'aticamente ordena la lista cada
vez que la lista hace bucles --- toma la @sc{cdr} de la lista --- y
asocia el @sc{car} de cada versi@'on ordenada de la lista al primero
de sus argumentos.

@code{dotimes} repite el bucle un n@'umero espec@'{@dotless{i}}fico de
veces: tu especificas el n@'umero.

@menu
* dolist::                   dolist
* dotimes::                  dotimes
@end menu

@node dolist
@unnumberedsubsec La macro @code{dolist}
@findex dolist

Sup@'on, por ejemplo, que quieres invertir una lista,
as@'{@dotless{i}} que ``primero'', ``segundo'', ``tercero'' llega a
ser ``tercero'', ``segundo'', ``primero''.

@need 1250
En la pr@'actica, usar@'{@dotless{i}}as la funci@'on @code{reverse},
como esta:

@smallexample
@group
(setq animales '(gacela jirafa leon tigre))

(reverse animales)
@end group
@end smallexample

@need 800
@noindent
Aqu@'{@dotless{i}} se ve c@'omo se podr@'{@dotless{i}}a invertir la
lista usando un bucle @code{while}:

@smallexample
@group
(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@'{@dotless{i}}a
    (while list
      (setq value (cons (car list) value))
      (setq list (cdr list)))
    value))

(reverse-list-with-while animales)
@end group
@end smallexample

@need 800
@noindent
Y aqu@'{@dotless{i}} se ve c@'omo podr@'{@dotless{i}}a usarse la macro
@code{dolist}:

@smallexample
@group
(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@'{@dotless{i}}a
    (dolist (element list value)
      (setq value (cons element value)))))

(reverse-list-with-dolist animals)
@end group
@end smallexample

@need 1250
@noindent
En Info, se puede localizar su cursor despu@'es de cerrar par@'entesis
de cada expresi@'on y escribir @kbd{C-x C-e}; en cada caso, se
ver@'{@dotless{i}}a

@smallexample
(tigre leon jirafa gacela)
@end smallexample

@noindent
en el @'area echo.

Para este ejemplo, la funci@'on @code{reverse} existente es obviamente
la mejor. El bucle @code{while} es solo como nuestro primer ejemplo
(@pxref{Ejemplo de bucle, , Un bucle @code{while} y una lista}). El
@code{while} primero chequea si la lista tiene elementos; si es
as@'{@dotless{i}}, eso construye una nueva lista a@~nadiendo el primer
elemento de la lista a la lista existente (que en la primera
iteraci@'on del bucle es @code{nil}). Puesto que el segundo elemento
est@'a asignado en frente del segundo elemento, la lista es inversa.

En la expresi@'on que usa el bucle @code{while}, la expresi@'on
@w{@code{(setq list (cdr list))}} ordena la lista, as@'{@dotless{i}}
el bucle @code{while} finalmente para. Adem@'as, se proporciona la
expresi@'on @code{cons} con un nuevo primer elemento creando una nueva
lista y se ordena en cada repetici@'on del bucle.

La expresi@'on @code{dolist} hace lo mismo que la expresi@'on
@code{while}, excepto que la macro @code{dolist} hace algo del trabajo
que se tiene que hacer cuando se escribe una expresi@'on @code{while}.

Al igual que el bucle @code{while}, tenemos el bucle @code{dolist}. Lo
que es diferente es que autom@'aticamente ordena la lista cada vez que
se repite --- eso es `recorrer los @sc{cdr}s de la lista' en
s@'{@dotless{i}} --- y eso autom@'aticamente asocia el @sc{car} de
cada versi@'on ordenada de la lista al primero de sus argumentos.

En el ejemplo, el @sc{car} de cada versi@'on ordenada de la lista se
refiere a usar el s@'{@dotless{i}}mbolo @samp{element}, la lista en
s@'{@dotless{i}} se llama @samp{list}, y el valor devuelto se llama
@samp{value}. El resto de la expresi@'on @code{dolist} es el cuerpo.

La expresi@'on @code{dolist} asocia el @sc{car} de cada versi@'on
ordenada de la lista al @code{element} y entonces eval@'ua el cuerpo
de la expresi@'on y repite el bucle. El resultado es devuelto en
@code{value}.

@node dotimes
@unnumberedsubsec La macro @code{dotimes}
@findex dotimes

La macro @code{dotimes} es similar a @code{dolist}, excepto que el
bucle se repite un n@'umero espec@'{@dotless{i}}fico de veces.

El primer argumento @code{dotimes} se asigna a los n@'umeros 0, 1, 2 y
as@'{@dotless{i}} vuelve al bucle, y el valor del tercer argumento se
devuelve. Se necesita proveer el valor del segundo argumento, que es
cu@'antas veces la macro hace el bucle.

@need 1250
Por ejemplo, lo siguiente asocia los n@'umeros de 0 en adelante, pero
no incluyendo, el n@'umero 3 al primer argumento, @var{n@'umero}, y
entonces construye una lista de los tres n@'umeros. (El primer
n@'umero es 0, el segundo n@'umero es 1, y el tercer n@'umero es 2;
esto crea un total de tres n@'umeros en todo, empezando con cero como
el primer n@'umero.)

@smallexample
@group
(let (value)      ; de otro modo un valor es una variable vac@'{@dotless{i}}a
  (dotimes (number 3 value)
    (setq value (cons number value))))

@result{} (2 1 0)
@end group
@end smallexample

@noindent
@code{dotimes} devuelve @code{value}, as@'{@dotless{i}} el camino para
usar @code{dotimes} es para operar en alguna expresi@'on el n@'umero
de veces @var{number} y entonces devolver el resultado, como una lista
o un @'atomo.

@need 1250
Aqu@'{@dotless{i}} hay un ejemplo de una @code{defun} que usa
@code{dotimes} para a@~nadir el n@'umero de asteriscos en un tri@'angulo.

@smallexample
@group
(defun triangle-using-dotimes (number-of-rows)
  "Usando dotimes, a@~nade el n@'umero de asteriscos en un tri@'angulo."
(let ((total 0))  ; de otro modo un total es una variable vac@'{@dotless{i}}a
  (dotimes (number number-of-rows total)
    (setq total (+ total (1+ number))))))

(triangle-using-dotimes 4)
@end group
@end smallexample

@node Recursi@'on
@section Recursi@'on
@cindex Recursi@'on

Una funci@'on recursiva contiene c@'odigo que hace que el int@'erprete
Lisp llame a un programa que ejecute el c@'odigo en s@'{@dotless{i}},
pero con argumentos ligeramente diferentes. El c@'odigo 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@'an.

@menu
* Construyendo robots::      Mismo modelo, diferente n@'umero serie ...
* Partes de definici@'on recursiva::  Paseo hasta que tu pares ...
* Recursi@'on con lista::    Usando una lista con el test si para recurso.
* Funci@'on recursiva tri@'angulo::  Funci@'on recursiva tri@'angulo
* Recursi@'on con cond::     Recursi@'on con cond
* Patrones recursivos::      Plantillas usadas con frecuencia.
* Sin Aplazar::              No almacenar trabajo ...
* No aplazar la soluci@'on::  No aplazar la soluci@'on
@end menu

@node Construyendo robots
@subsection Construyendo robots: Extendiendo la met@'afora
@cindex Construyendo robots
@cindex Robots, construyendo

Algunas veces es @'util pensar en un programa en ejecuci@'on como un
robot que hace un trabajo. Haciendo su trabajo, una funci@'on
recursiva llama a un segundo robot para que le ayude. El segundo robot es
id@'entico 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@'on recursiva, el segundo robot puede llamar a un
tercero; y el tercero puede llamar a un cuarto, y
as@'{@dotless{i}}. Cada una de estos es una entidad diferente; pero
todos son clones.

Desde que cada robot tiene instrucciones ligeramente diferentes ---
los argumentos diferir@'an desde un robot al siguiente --- el @'ultimo
robot conocer@'{@dotless{i}}a cuando pare.

Permite expandir la met@'afora en el que un programa de ordenador
es un robot.

Una definici@'on de funci@'on provee impresiones para un robot. Cuando
se instala una definici@'on de funci@'on, que es, cuando se eval@'ua
una forma especial @code{defun}, se instala el equipamiento para
construir robots. Eso es como si tu estuvieras en una f@'abrica,
configurando una l@'{@dotless{i}}nea de ensamblaje. Los robots con el
mismo nombre son construidos de acuerdo a las mismas
impresiones. As@'{@dotless{i}} ellos tienen, como estaban, el mismo
`n@'umero de modelo', pero un diferente `n@'umero de serie'.

Nosotros con frecuencia decimos que una funci@'on recursiva `se llama
as@'{@dotless{i}} misma'. Esto significa que las instrucciones en una
funci@'on recursiva causa que el int@'erprete de Lisp ejecute una
funci@'on 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@'a.

@node Partes de definici@'on recursiva
@subsection Las partes de una definici@'on recursiva
@cindex Partes de una Definici@'on Recursiva
@cindex Partes de definici@'on recursiva

Una funci@'on recursiva t@'{@dotless{i}}picamente contiene una
expresi@'on condicional que tiene tres partes:

@enumerate
@item
Un true-or-false-test que determina si la funci@'on se llama de
nuevo, aqu@'{@dotless{i}} se llama el @dfn{do-again-test}.

@item
El nombre de la funci@'on. Cuando este nombre se llama, es una nueva
instancia de la funci@'on --- un nuevo robot, as@'{@dotless{i}} --- se
crea y se dice qu@'e hacer.

@item
Una expresi@'on que devuelve un valor diferente cada vez que la
funci@'on se llama, aqu@'{@dotless{i}} llamada la
@dfn{next-step-expression}. Consecuentemente, el argumento (o
argumentos) pasados a la nueva instancia de la funci@'on ser@'an
diferentes puesto que se pasa a la instancia previa. Esto causa la
expresi@'on condicional, que el @dfn{do-again-test}, devuelva
falso despu@'es del n@'umero correcto de repeticiones.
@end enumerate

Las funciones recursivas pueden ser m@'as simples que cualquier otro
tipo de funciones. De manera profunda, cuando la gente empieza a
usarlas, con frecuencia se miran as@'{@dotless{i}} misteriosamente
de manera tan simple como incompresible. Como montar en bicicleta, leer una
funci@'on recursiva es duro al principio, pero despu@'es es simple.

@need 1200
Hay varios patrones recursivos diferentes. Un patr@'on muy simple se
parece a:

@smallexample
@group
(defun @var{name-of-recursive-function} (@var{argument-list})
  "@var{documentation}@dots{}"
  (if @var{do-again-test}
    @var{body}@dots{}
    (@var{name-of-recursive-function}
         @var{next-step-expression})))
@end group
@end smallexample

Cada vez que una funci@'on recursiva es evaluada, una nueva instancia
se crea y se dice qu@'e hacer. Los argumentos le dicen a la instancia
qu@'e 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@'on, que lo eval@'ua (o alguna transformaci@'on
de eso) para determinar si continuar o parar. El next-step-expression
est@'a dise@~nado as@'{@dotless{i}} que el do-again-test devuelve
falso cuando la funci@'on no se repetir@'{@dotless{i}}a mucho.

El do-again-test es algunas veces llamado la @dfn{condici@'on de
parar}, puesto que sirve para parar las repeticiones cuando se devuelve
falso.

@node Recursi@'on con lista
@subsection Recursi@'on con una lista

El ejemplo de un bucle @code{while} que imprimi@'o los elementos de
una lista de n@'umeros puede ser escrito
recursivamente. Aqu@'{@dotless{i}} est@'a el c@'odigo, incluyendo una
expresi@'on para asignar el valor de la variable @code{animales} a una
lista.

Si est@'a leyendo esto en el Info de Emacs, se puede evaluar esta
expresi@'on directamente en Info. De otro modo, se debe copiar el
ejemplo al b@'uffer @file{*scratch*} y eval@'ua cada expresi@'on
aqu@'{@dotless{i}}. Usa @kbd{C-u C-x C-e} para evaluar la expresi@'on
@code{(print-elements-recursively animals)} as@'{@dotless{i}} que los
resultado se imprimen en el b@'uffer; de otro modo el int@'erprete
Lisp intentar@'a presionar los resultados dentro de una
l@'{@dotless{i}}nea del @'area echo.

Tambi@'en, posiciona tu cursor inmediatamente despu@'es del @'ultimo
par@'entesis que cierra la funci@'on
@code{print-elements-recursively}, antes del comentario. De otro modo,
el int@'erprete Lisp intentar@'a evaluar el comentario.

@findex print-elements-recursively
@smallexample
@group
(setq animales '(gacela jirafa leon tigre))

(defun print-elements-recursively (list)
  "Imprime cada elemento de la LISTA de la l@'{@dotless{i}}nea en
  s@'{@dotless{i}}. Usa recursi@'on."
  (when list                            ; @r{do-again-test}
        (print (car list))              ; @r{body}
        (print-elements-recursively     ; @r{recursive call}
         (cdr list))))                  ; @r{next-step-expression}

(print-elements-recursively animales)
@end group
@end smallexample

La funci@'on @code{print-elements-recursively} primero chequea si hay
cualquier contenido en la lista; si lo hay, la funci@'on imprime el
primer elemento de la lista, el @sc{car} de la lista. Entonces la
funci@'on se `invoca en s@'{@dotless{i}}', pero da a s@'{@dotless{i}}
mismo como su argumento, no la lista completa, pero el segundo y
subsiguientes elementos de la lista, el @sc{cdr} de la lista.

Pon otro camino, si la lista no est@'a vac@'{@dotless{i}}a, la
funci@'on invoca otra instancia de c@'odigo que es similar al c@'odigo
inicial, pero es un hilo diferente de ejecuci@'on, con diferentes
argumentos a la primera instancia.

Veamos una manera m@'as, si la lista no est@'a vac@'{@dotless{i}}a, el
primer robot ensambla un segundo robot que cuenta qu@'e hacer; el
segundo robot es un individuo diferente desde el principio, pero es el
mismo modelo.

Cuando la segunda evaluaci@'on ocurre, la expresi@'on @code{when} se
eval@'ua 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@'on `llamarse a s@'{@dotless{i}} mismo'
con la @sc{cdr} del @sc{cdr} de la lista original.

Note que aunque nosotros decimos que la funci@'on `se llama a
s@'{@dotless{i}} misma', lo que significa es que el int@'erprete 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@'on `se invoca a s@'{@dotless{i}} misma', se
invoca a s@'{@dotless{i}} misma en una versi@'on de la lista
original. Eso crea una nueva instancia que funciona como una lista
ordenada.

Finalmente, la funci@'on se invoca a s@'{@dotless{i}} misma en una
lista vac@'{@dotless{i}}a. Eso crea una nueva instancia cuyo argumento
es @code{nil}. La expresi@'on condicional chequea el valor de
@code{lista}. Desde el valor de @code{lista} a @code{nil}, la
expresi@'on @code{when} devuelve falso as@'{@dotless{i}} la then-part
no est@'a evaluada. La funci@'on es como un todo que entonces devuelve
@code{nil}.

@need 1200
Cuando se eval@'ua la expresi@'on @code{(print-elements-recursively
animals)} en el b@'uffer @file{*scratch*}, se ver@'a este resultado:

@smallexample
@group
gacela

jirafa

leon

tigre
nil
@end group
@end smallexample

@need 2000
@node Funci@'on recursiva tri@'angulo
@subsection Recursi@'on en lugar de un contador
@findex triangle-recursively

@need 1200
La funci@'on @code{triangle} describe en una secci@'on previa si puede
ser escrita recursivamente. Se ve as@'{@dotless{i}}:

@smallexample
@group
(defun triangle-recursively (number)
  "Return the sum of the numbers 1 through NUMBER inclusive.
Uses recursion."
  (if (= number 1)                    ; @r{do-again-test}
      1                               ; @r{then-part}
    (+ number                         ; @r{else-part}
       (triangle-recursively          ; @r{recursive call}
        (1- number)))))               ; @r{next-step-expression}

(triangle-recursively 7)
@end group
@end smallexample

@noindent
Se puede instalar esta funci@'on evaluando y entonces se intenta
evaluar @code{(triangle-recursively 7)}. (Recuerda poner tu cursor
inmediatamente despu@'es de los @'ultimos par@'entesis de la
definici@'on de la funci@'on, antes del comentario.) La funci@'on
se eval@'ua a 28.

Para comprender c@'omo funciona la funci@'on, hay que considerar qu@'e
ocurre en varios casos cuando la funci@'on 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
@end menu

@ifnottex
@node Ejemplo recursivo y argumento con valor 1 o 2
@unnumberedsubsubsec Un argumento de 1 o 2
@end ifnottex

Primero, veamos qu@'e ocurre si el valor del argumento es 1.

La funci@'on tiene una expresi@'on @code{if} despu@'es de la cadena de
documentaci@'on. Esto chequea si el valor de @code{number} es igual a
1; si es as@'{@dotless{i}}, Emacs eval@'ua la then-part de la
expresi@'on @code{if}, que devuelve el n@'umero 1 como el valor de la
funci@'on. (Un tri@'angulo con una fila tiene un asterisco dentro.)

Sup@'on, sin embargo, que el valor del argumento es 2. En este caso,
Emacs eval@'ua la parte else de la expresi@'on @code{if}.

@need 1200
La parte else consiste de una adici@'on, la llamada recursiva para
@code{triangle-recursively} y una acci@'on de decremento; y se ve
as@'{@dotless{i}}:

@smallexample
(+ number (triangle-recursively (1- number)))
@end smallexample

Cuando Emacs eval@'ua esta expresi@'on, la expresi@'on interna es
evaluada primero; entonces las otras partes en
secuencia. Aqu@'{@dotless{i}} est@'an los pasos en detalle:

@table @i
@item Paso 1 @w{ } Eval@'ua la expresi@'on interna.

La expresi@'on interna es @code{(1- number)} as@'{@dotless{i}} Emacs
decrementa el valor de @code{number} desde 2 a 1.

@item Paso 2 @w{ } Eval@'ua la funci@'on @code{triangle-recursively}.

El int@'erprete Lisp crea una instancia individual de
@code{triangle-recursively}. Eso no importa que esta funci@'on est@'a
contenida con s@'{@dotless{i}} misma. Emacs pasa el resultado Paso 1
como el argumento usado por esta instancia de la funci@'on
@code{triangle-recursively}

En este caso, Emacs eval@'ua @code{triangle-recursively} con un
argumento de 1. Esto significa que esta evaluaci@'on de
@code{triangle-recursively} devuelve 1.

@item Paso 3 @w{ } Eval@'ua el valor de @code{number}.

La variable @code{number} es el segundo elemento de la lista que
empieza con @code{+}; su valor es 2.

@item Paso 4 @w{  } Eval@'ua la expresi@'on @code{+}.

La expresi@'on @code{+} recibe dos argumentos, el primero desde la
evaluaci@'on de @code{number} (Paso 3) y el segundo desde la
evaluaci@'on de @code{triangle-recursively} (Paso 2).

El resultado de la adici@'on es la suma de 2 + 1, y el n@'umero 3 es
devuelto, que es correcto. Un tri@'angulo con dos filas tiene tres
asteriscos ah@'{@dotless{i}}.
@end table

@node Ejemplo Recursivo de 3 o 4 argumentos
@unnumberedsubsubsec Un argumento de 3 o 4

Sup@'on que @code{triangle-recursively} es llamado con un argumento de
3.

@table @i
@item Paso 1 @w{ } Eval@'ua la do-again-test.

La expresi@'on @code{if} se eval@'ua primero. Esto es el test do-again
y devuelve falso, as@'{@dotless{i}} la parte else de la expresi@'on
@code{if} es evaluada. (Note que en este ejemplo, el do-again-test
causa la funci@'on para llamarse a s@'{@dotless{i}} misma cuando eso
se chequea como falso, no cuando eso se chequea como verdadero.)

@item Paso 2 @w{ } Eval@'ua la expresi@'on propia de la parte else.

La expresi@'on propia de la parte que es evaluada, decrementa 3 a
2. Esta la next-step-expression.

@item Paso 3 @w{ } Eval@'ua la funci@'on @code{triangle-recursively}.

El n@'umero 2 es pasado a la funci@'on @code{triangle-recursively}.

Nosotros ya sabemos qu@'e ocurre cuando Emacs eval@'ua
@code{triangle-recursively} con un argumento de 2. Despu@'es de ir a
trav@'es de la secuencia de acciones descritas temprano, eso devuelve
un valor de 3. As@'{@dotless{i}} que es lo que ocurrir@'a
aqu@'{@dotless{i}}.

@item Paso 4 @w{ } Eval@'ua la adici@'on.

3 ser@'a pasado como un argumento para la adici@'on y ser@'a a@~nadido
al n@'umero con el que la funci@'on se llam@'o, que es 3.
@end table

@noindent
El valor devuelto por la funci@'on como un todo ser@'a 6.

Ahora que sabemos qu@'e ocurrir@'a cuando @code{triangle-recursively}
llama con un argumento 3, es evidente lo que ocurrir@'a si se llama
con el argumento 4:

@quotation
@need 800
En la llamada recursiva, la evaluaci@'on de

@smallexample
(triangle-recursively (1- 4))
@end smallexample

@need 800
@noindent
devuelve el valor de evaluar

@smallexample
(triangle-recursively 3)
@end smallexample

@noindent
que es 6 este valor ser@'a a@~nadido a 4 por la adici@'on en la
tercera l@'{@dotless{i}}nea.
@end quotation

@noindent
El valor devuelto por la funci@'on como un todo ser@'a 10.

Cada vez que @code{triangle-recursively} se eval@'ua, se interpreta
una versi@'on de s@'{@dotless{i}} misma --- una instancia diferente en
s@'{@dotless{i}} --- con un peque@~no argumento, hasta que el
argumento es suficientemente peque@~no as@'{@dotless{i}} que no se
eval@'ua en s@'{@dotless{i}}.

Note que este particular dise@~no para una funci@'on recursiva
requiere que las operaciones sean diferidas.

Antes de que @code{(triangle-recursively 7)} pueda calcular su
respuesta, debe llamarse a @code{(triangle-recursively 6)}; y antes a
@code{(triangle-recursively 5)}; y as@'{@dotless{i}}. Esto es decir,
que el c@'alculo de @code{(triangle-recursively 7)} a crear debe ser
diferido hasta que @code{(triangle-recursively 6)} haga su c@'alculo;
y @code{(triangle-recursively 5)} lo complete; y as@'{@dotless{i}}.

Si cada una de estas instancias de @code{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@'{@dotless{i}}.

Hay un camino alrededor de este tipo de espera, que se discutir@'a en
@ref{Sin Aplazar, , Recursi@'on sin Defermentos.}

@node Recursi@'on con cond
@subsection Ejemplo de recursi@'on usando @code{cond}
@findex cond

La versi@'on de @code{triangle-recursively} antes descrita se escribi@'o
con la forma especial @code{if}. Eso puede tambi@'en ser escrita
usando otra forma especial llamada @code{cond}. El nombre de la forma
especial @code{cond} es una abreviaci@'on de la palabra @samp{conditional}.

Aunque la forma especial @code{cond} no se usa con frecuencia en las
fuentes de Emacs como @code{if}, se usa con suficiente frecuencia para
justificarse explicando.

@need 800
La plantilla para una expresi@'on @code{cond} se parece a:

@smallexample
@group
(cond
 @var{body}@dots{})
@end group
@end smallexample

@noindent
donde el @var{body} es una serie de listas.

@need 800
Escrito de manera m@'as completa, la plantilla se parece a esto:

@smallexample
@group
(cond
 (@var{first-true-or-false-test} @var{first-consequent})
 (@var{second-true-or-false-test} @var{second-consequent})
 (@var{third-true-or-false-test} @var{third-consequent})
  @dots{})
@end group
@end smallexample

Cuando el int@'erprete Lisp eval@'ua la expresi@'on @code{cond},
eval@'ua el primer elemento (el @sc{car} o true-or-false-test) de la
primera expresi@'on en una serie de expresiones con el cuerpo del
@code{cond}.

Si el true-or-false-test devuelve @code{nil} el resto de esta
expresi@'on, el consecuente, se descarta y el true-or-false-test de la
siguiente expresi@'on se eval@'ua. Cuando una expresi@'on encuentra un
true-or-false-test cuyo valor no es @code{nil}, el consecuente de esta
expresi@'on se eval@'ua. El consecuente puede ser una o m@'as
expresiones. Si el consecuente consiste de m@'as de una expresi@'on,
las expresiones son evaluadas en secuencia y el valor del @'ultimo se
devuelve. Si la expresi@'on 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@'on
@code{cond} devuelve @code{nil}.

@need 1250
Escrito usando @code{cond}, la funci@'on @code{triangle} se parece a esto:

@smallexample
@group
(defun triangle-using-cond (number)
  (cond ((<= number 0) 0)
        ((= number 1) 1)
        ((> number 1)
         (+ number (triangle-using-cond (1- number))))))
@end group
@end smallexample

@noindent
En este ejemplo, el @code{cond} devuelve 0 si el n@'umero es menor o
igual a 0, eso devuelve 1 si el n@'umero es 1 y eso eval@'ua @code{(+
number (triangle-using-cond (1- number)))} si el n@'umero es m@'as
grandes que 1.

@node Patrones recursivos
@subsection Patrones recursivos
@cindex Patrones recursivos

Aqu@'{@dotless{i}} hay tres patrones recursivos. Cada uno involucra
una lista. La recursi@'on no se necesita para involucrar listas, pero
Lisp se dise@~na para listas y esto provee un sentido de sus
capacidades primarias.

@menu
* Cada::                     Cada
* Acumular::                 Acumular
* Guardar::                  Guardar
@end menu

@node Cada
@unnumberedsubsubsec Patr@'on recursivo: @emph{every}
@cindex Every, tipo de patr@'on recursivo
@cindex Patr@'on recursivo: every

En el patr@'on recursivo @code{every}, se desarrolla una acci@'on por
cada elemento de una lista.

@need 1500
El patr@'on b@'asico es:

@itemize @bullet
@item
Si una lista es vac@'{@dotless{i}}a, devuelve @code{nil}.
@item
Else, act on the beginning of the list (the @sc{car} of the list)
    @itemize @minus
    @item
    through a recursive call by the function on the rest (the @sc{cdr}) of the
list,
    @item
    and, optionally, combine the acted-on element, using @code{cons}, with the
results of acting on the rest.
    @end itemize
@end itemize

@need 1500
Aqu@'{@dotless{i}} est@'a el ejemplo:

@smallexample
@group
(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
@end group

@group
(square-each '(1 2 3))
    @result{} (1 4 9)
@end group
@end smallexample

@need 1200
@noindent
Si @code{numbers-list} est@'a vac@'{@dotless{i}}o, no hay que hacer
nada. Pero si tiene contenido, se construye una lista combinando el
cuadrado del primer n@'umero en la lista con el resultado de la
llamada recursiva.

(El ejemplo sigue el patr@'on exactamente: se devuelve @code{nil} si
la lista de n@'umeros es vac@'{@dotless{i}}a. En la pr@'actica, se
escribir@'{@dotless{i}}a el condicional, as@'{@dotless{i}} se ejecuta
la acci@'on cuando la lista de n@'umeros no es vac@'{@dotless{i}}a.)

La funci@'on @code{print-elements-recursively} (@pxref{Recursi@'on con
lista, , Recursi@'on con una Lista}) es otro ejemplo de un patr@'on
@code{every}, excepto en este caso, en vez de traer los resultados
juntos usando @code{cons}, se imprime cada elemento de salida.

@need 1250
La funci@'on @code{print-elements-recursively} se parece a esto:

@smallexample
@group
(setq animales '(gacela jirafa leon tigre))
@end group

@group
(defun print-elements-recursively (list)
  "Imprime cada elemento de la LISTA de la l@'{@dotless{i}}nea en
  s@'{@dotless{i}}. Usa recursi@'on."
  (when list                            ; @r{do-again-test}
        (print (car list))              ; @r{body}
        (print-elements-recursively     ; @r{recursive call}
         (cdr list))))                  ; @r{next-step-expression}

(print-elements-recursively animales)
@end group
@end smallexample

@need 1500
El patr@'on para @code{print-elements-recursively} es:

@itemize @bullet
@item
Cuando la lista est@'a vac@'{@dotless{i}}a, no hacer nada.
@item
But when the list has at least one element,
    @itemize @minus
    @item
    act on the beginning of the list (the @sc{car} of the list),
    @item
    and make a recursive call on the rest (the @sc{cdr}) of the list.
    @end itemize
@end itemize

@node Acumular
@unnumberedsubsubsec Patr@'on recursivo: @emph{accumulate}
@cindex Acumular, tipo de patr@'on recursivo
@cindex Patr@'on recursivo: acumular

Otro patr@'on recursivo es llamado el patr@'on @code{accumulate}. En
el patr@'on recursivo @code{accumulate}, se realiza una acci@'on en
cada elemento de una lista y el resultado de esta acci@'on se acumula
con los resultados de desarrollar la acci@'on en otros elementos.

Esto es como `cada' patr@'on usando @code{cons}, excepto que este
@code{cons} no se est@'e usando, pero que alg@'un otro combine.

@need 1500
El patr@'on es:

@itemize @bullet
@item
Si una lista est@'a vac@'{@dotless{i}}a, devuelve cero o alguna otra
constante.
@item
Else, act on the beginning of the list (the @sc{car} of the list),
    @itemize @minus
    @item
    and combine that acted-on element, using @code{+} or some other combining
function, with
    @item
    a recursive call by the function on the rest (the @sc{cdr}) of the list.
    @end itemize
@end itemize

@need 1500
Aqu@'{@dotless{i}} hay un ejemplo:

@smallexample
@group
(defun add-elements (numbers-list)
  "A@~nade los elementos de NUMBERS-LIST juntos."
  (if (not numbers-list)
      0
    (+ (car numbers-list) (add-elements (cdr numbers-list)))))
@end group

@group
(add-elements '(1 2 3 4))
    @result{} 10
@end group
@end smallexample

@xref{Listar ficheros, , Creando una lista de ficheros}, para un ejemplo
del patr@'on acumulado.

@node Guardar
@unnumberedsubsubsec Patr@'on recursivo: @emph{keep}
@cindex Keep, el tipo de patr@'on recursivo
@cindex Patr@'on recursivo: keep

Un tercer patr@'on es llamado el patr@'on @code{keep}. En el patr@'on
recursivo @code{keep}, se chequea cada elemento de una lista; se
act@'ua en el elemento y los resultados se guardan solo si el elemento
encuentra un criterio.

De nuevo, esto se parece al patr@'on `every', excepto que el elemento
se descarta a menos que se encuentre un criterio.

@need 1500
El patr@'on tiene tres partes:

@itemize @bullet
@item
Si una lista es vac@'{@dotless{i}}a, devuelve @code{nil}.
@item
Else, if the beginning of the list (the @sc{car} of the list) passes a test
    @itemize @minus
    @item
    act on that element and combine it, using @code{cons} with
    @item
    a recursive call by the function on the rest (the @sc{cdr}) of the list.
    @end itemize
@item
Otherwise, if the beginning of the list (the @sc{car} of the list) fails the
test
    @itemize @minus
    @item
    skip on that element,
    @item
    and, recursively call the function on the rest (the @sc{cdr}) of the list.
    @end itemize
@end itemize

@need 1500
Aqu@'{@dotless{i}} hay un ejemplo que usa @code{cond}:

@smallexample
@group
(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@'ua 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)))))
@end group

@group
(manten-tres-letras '(uno dos tres cuatro cinco seis))
    @result{} (uno dos)
@end group
@end smallexample

Eso va sin decir que no se necesita usar @code{nil} como si el test
para cuando para; y se puede, de acuerdo, combinar estos patrones.

@node Sin Aplazar
@subsection Recursi@'on sin diferir
@cindex Diferir en recursi@'on
@cindex Recursi@'on sin diferir

Permita considerar de nuevo qu@'e ocurre con la funci@'on
@code{triangle-recursively}. Nosotros encontraremos que los c@'alculos
difieran hasta que todo pueda ser hecho.

@need 800
Aqu@'{@dotless{i}} est@'a la definici@'on de funci@'on:

@smallexample
@group
(defun triangle-recursively (number)
  "Devuelve la suma de los n@'umeros 1 a trav@'es de NUMBER inclusive
Usa recursi@'on."
  (if (= number 1)                    ; @r{do-again-test}
      1                               ; @r{then-part}
    (+ number                         ; @r{else-part}
       (triangle-recursively          ; @r{recursive call}
        (1- number)))))               ; @r{next-step-expression}
@end group
@end smallexample

@questiondown{}Qu@'e ocurre cuando se llama a esta funci@'on con un
argumento de 7?

La primera instancia de la funci@'on @code{triangle-recursively}
a@~nade el n@'umero 7 al valor devuelto por una segunda instancia de
@code{triangle-recursively}, una instancia que ha pasado un argumento
de 6. As@'{@dotless{i}}, el primer c@'alculo es:

@smallexample
(+ 7 (triangle-recursively 6))
@end smallexample

@noindent
La primera instancia de @code{triangle-recursively} --- se puede
querer pensar como un peque@~no robot --- no puede completar su
trabajo. Eso debe manejar el c@'alculo para
@code{(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@'on'. O, poner otro camino, eso es un diferente robot. Eso
es el mismo modelo como el primero; eso calcula n@'umeros de
tri@'angulo recursivamente; pero eso tiene un n@'umero de serie diferente.

@questiondown{}Y qu@'e hace @code{(triangle-recursively 6)}
devuelve? Eso devuelve el n@'umero 6 a@~nadido al valor devuelto para
evaluar @code{triangle-recursively} con un argumento de 5. Usando la
met@'afora del robot, eso cuestiona todav@'{@dotless{i}}a otro robot
para ayudarle.

@need 800
Ahora el total es:

@smallexample
(+ 7 6 (triangle-recursively 5))
@end smallexample

@need 800
@questiondown{}Y qu@'e ocurre despu@'es?

@smallexample
(+ 7 6 5 (triangle-recursively 4))
@end smallexample

Cada vez que @code{triangle-recursively} es llamado, excepto por la
@'ultima vez, eso crea otra instancia del programa --- otro robot ---
y pregunta para crear un c@'alculo.

@need 800
Finalmente, la adici@'on completa es de la siguiente manera:

@smallexample
(+ 7 6 5 4 3 2 1)
@end smallexample

Este dise@~no para la funci@'on difiere el c@'alculo del primer paso
hasta el segundo puede ser hecho, y difiere esto hasta que el tercero
puede ser hecho, y as@'{@dotless{i}}. Cada defermento significa el
ordenador debe recordar que est@'a 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@'as pasos.

@node No aplazar la soluci@'on
@subsection No hay soluci@'on pospuesta
@cindex No aplazar la soluci@'on
@cindex Sin posponer la soluci@'on
@cindex Soluci@'on no pospuesta

La soluci@'on al problema de operaciones pospuestas es para escribir
en una manera que no posponga operaciones@footnote{La frase @dfn{cola
recursiva} es usado para describir tal proceso, uno que usa `espacio
constante'.}. Esto requiere escribir a un patr@'on diferente, con
frecuencia uno que involucra escribiendo dos definiciones de
funci@'on, una funci@'on de `inicializaci@'on' y una funci@'on `ayuda'.

La funci@'on `inicializacion' configura el trabajo; la funci@'on
`ayudante' hace el trabajo.

@need 1200
Aqu@'{@dotless{i}} hay dos definiciones para a@~nadir n@'umeros. Son
as@'{@dotless{i}} de simple, aunque se encuentre duro de comprender.

@smallexample
@group
(defun triangle-initialization (number)
  "Devuelve la suma de los n@'umeros 1 a trav@'es de NUMBER inclusive.
Este es el componente de `inicializaci@'on' de una funci@'on d@'uo que 
usa recursi@'on"
  (triangle-recursive-helper 0 0 number))
@end group
@end smallexample

@smallexample
@group
(defun triangle-recursive-helper (sum counter number)
  "Devuelve SUM, usando COUNTER, a trav@'es de NUMBER inclusive.
Este es el componente `helper' de unas dos funciones
que usan recursi@'on."
  (if (> counter number)
      sum
    (triangle-recursive-helper (+ sum counter)  ; @r{suma}
                               (1+ counter)     ; @r{contador}
                               number)))        ; @r{n@'umero}
@end group
@end smallexample

@need 1250
Instalar ambas definiciones de funci@'on por evaluarlo, entonces llama
a @code{triangle-initialization} con 2 filas:

@smallexample
@group
(triangle-initialization 2)
    @result{} 3
@end group
@end smallexample

La funci@'on `inicializaci@'on' llama la primera instancia de la
funci@'on `ayudante' con tres argumentos: cero, cero, y un n@'umero
que es el n@'umero de filas en el tri@'angulo.

Los primeros dos argumentos pasaron a la funci@'on `ayuda' son valores
de inicializaci@'on. Estos valores son cambiados cuando
@code{triangle-recursive-helper} invocan nuevas
instancias.@footnote{La jerga es medianamente confusa:
@code{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, @code{suma},
@code{contador}, y @code{n@'umero}: el procedimiento es recursivo
porque la funci@'on `llama a s@'{@dotless{i}} mismo'. Por otro lado,
ambos el proceso y el procedimiento usado por
@code{triangle-recursively} son llamados recursivos. La palabra
`recursivo' tiene diferentes significados en los dos contextos.}

Perm@'{@dotless{i}}tase ver que ocurre cuando tenemos un tri@'angulo
que tiene una fila. (@exclamdown{}Este tri@'angulo tendr@'a un
asterisco dentro!)

@need 1200
@code{triangle-initialization} llamar@'a su ayudante con los
argumentos @w{@code{0 0 1}}. Esta funci@'on ejecutar@'a el test
condicional si @code{(> counter number)}:

@smallexample
(> 0 1)
@end smallexample

@need 1200
@noindent
y encuentra que el resultado es falso, as@'{@dotless{i}} invocar@'a la
else-part de la cla@'usula @code{if}:

@smallexample
@group
    (triangle-recursive-helper
     (+ sum counter)  ; @r{sum m@'as counter} @result{} @r{sum}
     (1+ counter)     ; @r{incrementa counter} @result{} @r{counter}
     number)          ; @r{number parece lo mismo}
@end group
@end smallexample

@need 800
@noindent
que computar@'a primero:

@smallexample
@group
(triangle-recursive-helper (+ 0 0)  ; @r{sum}
                           (1+ 0)   ; @r{counter}
                           1)       ; @r{number}
@exdent que es:

(triangle-recursive-helper 0 1 1)
@end group
@end smallexample

De nuevo, @code{(> counter number)} ser@'a falso, as@'{@dotless{i}} de
nuevo, el int@'erprete Lisp evaluar@'a
@code{triangle-recursive-helper}, creando una nueva instancia con
nuevos argumentos.

@need 800
Esta nueva instancia ser@'a;

@smallexample
@group
    (triangle-recursive-helper
     (+ sum counter)  ; @r{suma m@'as contador} @result{} @r{sum}
     (1+ counter)     ; @r{incrementar contador} @result{} @r{contador}
     number)          ; @r{n@'umero empieza lo mismo}

@exdent que es:

(triangle-recursive-helper 1 2 1)
@end group
@end smallexample

En este caso, el test @code{(> counter number)} @exclamdown{}ser@'a
cierto!  As@'{@dotless{i}} la instancia devolver@'a el valor de la
suma, que ser@'a 1, como se espera.

Ahora, permite pasar @code{triangle-initialization} un argumento de 2,
para encontrar cu@'antos asterisco hay en un tri@'angulo con dos filas.

Esta funci@'on llama @code{(triangle-recursive-helper 0 0 2)}.

@need 800
En fases, las instancias llamadas ser@'an:

@smallexample
@group
                          @r{suma contador n@'umero}
(triangle-recursive-helper 0    1       2)

(triangle-recursive-helper 1    2       2)

(triangle-recursive-helper 3    3       2)
@end group
@end smallexample

Cuando la @'ultima instancia se llama, el @code{(> counter number)} se
chequea si ser@'a cierto, as@'{@dotless{i}} la instancia devolver@'a
el valor de @code{sum}, que ser@'a 3.

Este tipo de patr@'on ayuda cuando est@'as escribiendo funciones que
puede usar recursos en un ordenador.

@need 1500
@node Ejercicio de Bucle
@section Ejercicio de bucles

@itemize @bullet
@item
Escribe una funci@'on similar a @code{triangle} en el que cada fila
tiene un valor que es la ra@'{@dotless{i}}z del n@'umero de la
fila. Usa un bucle @code{while}.

@item
Escribe una funci@'on similar para @code{triangle} que multiplique en vez
de a@~nadir los valores.

@item
Reescribe estas dos funciones recursivamente. Reescribe estas
funciones usando @code{cond}.

@c comma in printed title causes problem in Info cross reference
@item
Escribe una funci@'on para el modo Texinfo que crea una entrada
@'{@dotless{i}}ndice al principio de un p@'arrafo para cada
@samp{@@dfn} con el p@'arrafo. (En un fichero Texinfo, @samp{@@dfn}
marca una definici@'on. El libro es escrito en Texinfo.)

Muchas de las funciones necesitar@'an ser descritas en dos de los
cap@'{@dotless{i}}tulos, @ref{Cortando y almacenando texto, , Cortando
y almacenando texto} y @ref{Pegando, , Pegando texto}. Si usas
@code{forward-paragraph} para poner la entrada @'{@dotless{i}}ndice al
principio del p@'arrafo, tendr@'a que usar @w{@kbd{C-h f}}
(@code{describe-function}) para encontrar c@'omo conseguir que el comando
vaya hacia atr@'as.

Para m@'as informaci@'on, ver
@ifinfo
@ref{Indicando Definiciones, texinfo}.
@end ifinfo
@ifhtml
@ref{Indicando, , Indicando, texinfo, Manual de Texinfo}, que va al
manual Texinfo en el actual directorio. O, si est@'as en Internet,
mira @uref{http://www.gnu.org/software/texinfo/manual/texinfo/}
@end ifhtml
@iftex
``Indicando Definiciones, Comandos, etc.'' en @cite{Texinfo, el
Formato de Documentaci@'on de GNU}.
@end iftex
@end itemize

@node Buscar regexp
@chapter B@'usquedas de expresiones regulares
@cindex B@'usquedas, ilustrando
@cindex B@'usquedas de expresiones regulares
@cindex Patrones, buscando por
@cindex Mover frase y p@'arrafo
@cindex Frases, movimiento por
@cindex P@'arrafos, movimiento por

Las b@'usquedas expresiones regulares son usadas extensivamente en GNU
Emacs. Las dos funciones @code{forward-sentence} y
@code{forward-paragraph}, ilustran estas b@'usquedas bien. Usan
expresiones regulares para encontrar donde mover el punto. La frase
`expresi@'on regular' es con frecuencia escrita como `regexp'.

Las b@'usquedas de expresiones regulares son descritas en
@ref{B@'usqueda de Regexp, , B@'usqueda de Expresi@'on Regular, emacs,
El Manual de GNU Emacs}, tan bien como en @ref{Expresiones Regulares,
, , elisp, El Manual de Referencia de GNU Emacs Lisp}. Escribiendo
este cap@'{@dotless{i}}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@'odigo en
@code{forward-sentence} busca para el patr@'on de posibles caracteres
que podr@'{@dotless{i}}an marcar el fin de una frase, y mueve el punto
al otro lado.

Antes de mirar en el c@'odigo la funci@'on @code{forward-sentence}, es
valorable considerar que el patr@'on que marca el fin de una frase
debe estar. El patr@'on se discute en la siguiente secci@'on;
siguiendo que es una descripci@'on de la expresi@'on regular de
b@'usqueda, @code{re-search-forward}. La funci@'on
@code{forward-sentence} es descrito en la secci@'on
siguiente. Finalmente, la funci@'on @code{forward-paragraph} es
descrito en la @'ultima secci@'on de este
cap@'{@dotless{i}}tulo. @code{forward-paragraph} es una funci@'on
compleja que introduce varias funcionalidades.

@menu
* sentence-end::             La expresi@'on regular para 
                               @code{sentence-end}.
* re-search-forward::        Muy similar a @code{search-forward}.
* forward-sentence::         Un ejemplo sencillo de b@'usqueda con 
                               expresiones regulares.
* forward-paragraph::        Un ejemplo complejo de alguna cosa.
* etags::                    C@'omo crear tu propia tabla @file{TAGS}.
* Revisar regexp::           Revisar regexp
* Ejercicios re-search::     Ejercicios re-search
@end menu

@node sentence-end
@section La expresi@'on regular para @code{sentence-end}
@findex sentence-end

El s@'{@dotless{i}}mbolo @code{sentence-end} se asocia al patr@'on que
marca el fin de una frase. @questiondown{}Cu@'al ser@'{@dotless{i}}a
esta expresi@'on regular?

Claramente, una frase puede ser finalizada por un periodo, una marca
de inicio de interrogaci@'on, o una marca de exclamaci@'on. Puesto que
viene del ingl@'es, solo las cla@'usulas que finalizan con uno de
estos tres caracteres deber@'{@dotless{i}}an ser consideradas al fin de
una frase. Esto significa que el patr@'on incluir@'{@dotless{i}}a el
conjunto de caracteres:

@smallexample
[.?!]
@end smallexample

Sin embargo, no queremos que @code{forward-sentence} salte a un
periodo, una marca de pregunta, o una marca de exclamaci@'on, porque
tal car@'acter podr@'{@dotless{i}}a ser usado en el medio de una
frase. Un periodo, por ejemplo, se usa despu@'es de
abreviaciones. As@'{@dotless{i}}, otra informaci@'on es necesaria.

De acuerdo a la convenci@'on, escribe dos espacios despu@'es de cada
frase, pero solo un espacio despu@'es de un periodo, una marca de
pregunta, o una marca de exclamaci@'on 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@'{@dotless{i}}nea. Esto significa que la expresi@'on regular
incluir@'{@dotless{i}}a estos tres @'{@dotless{i}}tems como
alternativas.

@need 800
Este grupo de alternativas se parece a esto:

@smallexample
@group
\\($\\| \\|  \\)
       ^   ^^
      TAB  SPC
@end group
@end smallexample

@noindent
Aqu@'{@dotless{i}}, @samp{$} indica el fin de la l@'{@dotless{i}}nea, y
yo he apuntado donde el tab y dos espacios est@'an insertados en la
expresi@'on. Ambos est@'an insertados poniendo los caracteres actuales
dentro de la expresi@'on.

Dos barras invertidas, @samp{\\}, se requiere antes de los
par@'entesis y barras verticales: la primera barra invertida cita la
siguiente barra invertida en Emacs; y el segundo indica que el
siguiente caracter, el par@'entesis o la barra vertical, es especial.

@need 1000
Tambi@'en, una frase puede ser seguida por uno o m@'as retornos de
carro, como este:

@smallexample
@group
[
]*
@end group
@end smallexample

@noindent
Como en los tabuladores y espacios, un retorno de carro se inserta
dentro de una expresi@'on regular insert@'andolo literalmente. El
asterisco indica que el @key{RET} se repite cero o m@'as veces.

Pero una frase no consiste solo en un periodo, una marca de pregunta o
una marca de exclamaci@'on seguida por espacios apropiados: una marca
de cerrar comillas o cerrar un par@'entesis de alg@'un tipo puede
preceder el espacio. En realidad m@'as de una marca o par@'entesis
pueden preceder el espacio. Estas requieren una expresi@'on que se
parezca a:

@smallexample
[]\"')@}]*
@end smallexample

En esta expresi@'on, el primer @samp{]} es el primer caracter en la
expresi@'on; el segundo caracter es @samp{"}, que est@'a precedido
por un @samp{\} para contar Emacs el @samp{"} @emph{no} es
especial. Los @'ultimos tres caracteres son @samp{'}, @samp{)}, y
@samp{@}}.

Todo esto sugiere que el patr@'on de la expresi@'on regular para
asociar el fin de una frase ser@'{@dotless{i}}a; y, profundamente, si
se eval@'ua @code{sentence-end} y encuentra que se devuelve el valor
siguiente:

@smallexample
@group
sentence-end
     @result{} "[.?!][]\"')@}]*\\($\\|     \\|  \\)[
]*"
@end group
@end smallexample

@noindent
(Bien, no en GNU Emacs 22; porque es un esfuerzo crear el proceso
simple y manejar m@'as s@'{@dotless{i}}mbolos y lenguajes. Cuando el
valor de @code{sentence-end} es @code{nil}, entonces usa el valor
definido por la funci@'on @code{sentence-end} es @code{nil}, entonces
usa el valor definido por la funci@'on
@code{sentence-end}. (Aqu@'{@dotless{i}} se usa la diferencia entre un
valor y una funci@'on en Emacs Lisp.) La funci@'on devuelve un valor
construido desde las variables @code{sentence-end-base},
@code{sentence-end-double-space}, @code{sentence-end-without-period},
y @code{sentence-end-without-space}. La variable cr@'{@dotless{i}}tica
es @code{sentence-end-base}; su valor global es similar a uno descrito
debajo pero tambi@'en contiene marcas de cita adicionales. Estas
tienen diferentes grados de curvas. La variable
@code{sentence-end-without-period}, cuando es verdad, dice a Emacs que
una frase puede finalizar sin un periodo tal como texto en Thai.)

@ignore
@noindent
(Note that here the @key{TAB}, two spaces, and  @key{RET} are shown
literally in the pattern.)

This regular expression can be deciphered as follows:

@table @code
@item [.?!]
La primera parte del patr@'on son los tres caracteres, un periodo, una
pregunta marca y un marca de exclamaci@'on, con par@'entesis
cuadrados. El patr@'on empieza con uno un otro de estos caracteres.
@item []\"')@}]*
La segunda parte del patr@'on es el grupo de cerrar par@'entesis y
marcas de cita, que pueden aparecer cero o m@'as veces. Estos pueden
seguir el periodo, marca de pregunta o marca de exclamaci@'on. En una
expresi@'on regular la barra, @samp{\}, seguido por las dobes
comillas, @samp{"}, indica los casos de caracteres
string-quote. Normalmente, las dobles comillas es el @'unico caracter
en esta clase. El asterisco, @samp{*}, indica que los
@'{@dotless{i}}tems en el grupo previo (el grupo alrededor por
comillas cuadradas, @samp{[]} puede ser repetido cero o m@'as veces.

@item \\($\\|   \\|  \\)
La tercera parte del patr@'on es uno u otro de: si el fin de una
l@'{@dotless{i}}nea, o dos espacios en blanco, o un tabulador. Las
barras invertidas dobles son usadas para prevenir a Emacs desde leer
los par@'entesis y barras verticales como parte del patr@'on de
b@'usqueda; los par@'entesis son usados para marcar el grupo y las
barras verticales usadas para indicarse que los patrones de un lado de
ellos son alternativas. El signo del d@'olar es usados para indicar el
fin de una l@'{@dotless{i}}nea y ambos espacios y el tabulador son
cada uno insertados como est@'an para indicar lo que ellos son.

@item [@key{RET}]*
Finalmente, la @'ultima parte del patr@'on indica que el fin de la
l@'{@dotless{i}}nea o el espacio en blanco siguiendo el periodo, marca
de pregunta o marca de exclamaci@'on, pero no necesita, el retorno de
carro es insertado como un retorno de carro devuelve par@'entesis
cuadrados pero aqu@'{@dotless{i}} eso muestra @key{RET}.
@end table
@end ignore

@node re-search-forward
@section La funci@'on @code{re-search-forward}
@findex re-search-forward

La funci@'on @code{re-search-forward} es similar a la funci@'on
@code{search-forward}. (@xref{search-forward, , La Funci@'on
@code{search-forward}}.)

@code{re-search-forward} busca una expresi@'on regular. Si la
b@'usqueda es exitosa, deja el punto inmediatamente despu@'es del
@'ultimo caracter en el objetivo. Si la b@'usqueda es hacia atr@'as,
deja el punto antes del primer caracter en el objetivo. Se puede
contar @code{re-search-forward} para devolver @code{t} a
cierto. (Moviendo el punto es por ello un `efecto lateral'.)

Como @code{search-forward}, la funci@'on @code{re-search-forward} toma
cuatro argumentos:

@enumerate
@item
El primer argumento es la expresi@'on regular que la funci@'on
busca. La expresi@'on regular ser@'a una cadena entre comillas.

@item
El segundo argumento opcional limita c@'omo la funci@'on busca; es
un emparejamiento, que se especifica como una posici@'on en el
b@'uffer.

@item
El tercer argumento opcional especifica c@'omo la funci@'on responde al
fallo: @code{nil} como tercer argumento que causa la funci@'on para
se@~nalar un error (e imprime un mensaje) cuando la b@'usqueda falla;
cualquier otro valor causa devolver @code{nil} si la b@'usqueda falla
y @code{t} si la b@'usqueda tiene @'exito.

@item
El cuarto argumento opcional es el contaje repetido. Un contaje
negativo repetido causa @code{re-search-forward} para buscar hacia atr@'as.
@end enumerate

@need 800
La plantilla para @code{re-search-forward} se parece a esto:

@smallexample
@group
(re-search-forward "@var{regular-expression}"
                @var{limit-of-search}
                @var{what-to-do-if-search-fails}
                @var{repeat-count})
@end group
@end smallexample

El segundo, tercer, y cuarto argumentos son opcionales. Sin embargo,
si se quiere pasar un valor a uno o ambos de los @'ultimos dos
argumentos, se debe tambi@'en pasar un valor a todos los argumentos
precedentes. De otro modo, el int@'erprete Lisp errar@'a a qu@'e
argumento est@'as pasando el valor.

@need 1200
En la funci@'on @code{forward-sentence}, la expresi@'on regular ser@'a
el valor de la variable @code{sentence-end}. En forma simple, esto es:

@smallexample
@group
"[.?!][]\"')@}]*\\($\\|  \\|  \\)[
]*"
@end group
@end smallexample

@noindent
El l@'{@dotless{i}}mite de la b@'usqueda ser@'a el fin del p@'arrafo
(desde una frase no puede ir bajo un p@'arrafo). Si la b@'usqueda
falla, la funci@'on devuelve @code{nil}, y el contaje repite ser@'a
provisto por el argumento para la funci@'on @code{forward-sentence}.

@node forward-sentence
@section @code{forward-sentence}
@findex forward-sentence

El comando mueve el cursor hacia adelante una frase es una
ilustraci@'on honesta de c@'omo usar b@'usquedas de expresiones
regulares en Emacs Lisp. En realidad, la funci@'on parece m@'as larga
y m@'as complicada de lo que es; esto es porque la funci@'on est@'a
dise@~nada para ir hacia atr@'as tan bien como hacia adelante; y,
opcionalmente, a trav@'es de una frase. La funci@'on est@'a
normalmente asociada al comando @kbd{M-e}.

@menu
* Completa forward-sentence::  Completa forward-sentence
* Bucles while fwd-sentence::  Dos bucles @code{while}.
* Volver a buscar la frase en sentido directo::  Una b@'usqueda de 
                                                   expresi@'on regular.
@end menu

@ifnottex
@node Completa forward-sentence
@unnumberedsubsec Completa la definici@'on @code{forward-sentence}
@end ifnottex

@need 1250
Aqu@'{@dotless{i}} est@'a la c@'odigo para @code{forward-sentence}:

@c in GNU Emacs 22
@smallexample
@group
(defun forward-sentence (&optional arg)
  "Ve al siguiente `sentence-end'. Con el argumento, repite.
Con el argumento negativo, mueve atr@'as repetidamente a `sentence-beginning'.
La variable `sentence-end' es una expresi@'on regular que empareja el
fin de frases. Tambi@'en, cada p@'arrafo asociado termina las frases
bien.
@end group
@group
  (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)))
@end group
@group
    (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)))
@end group
@end smallexample

@ignore
GNU Emacs 21
@smallexample
@group
(defun forward-sentence (&optional arg) 
  
 "Mueve hacia adelante a la siguiente sentence-end. Con el argumento,
  repetir.  Con el argumento negativo, mueve hacia atr@'as
  repetidamente a sentence-beginning. La frase que finalizan son
  identificadas por el valor de sentence-end tratada como expresi@'on
  regular. Tambi@'en, cada p@'arrafo l@'{@dotless{i}}mite termina las
  frases bien"
@end group
@group
  (interactive "p")
  (or arg (setq arg 1))
  (while (< arg 0)
    (let ((par-beg
           (save-excursion (start-of-paragraph-text) (point))))
      (if (re-search-backward
           (concat sentence-end "[^ \t\n]") par-beg t)
          (goto-char (1- (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))))
@end group
@end smallexample
@end ignore

La funci@'on se ve larga a primera vista y es mejor mirar primero el
esqueleto, y entonces su m@'usculo. El camino para ver el esqueleto es
mirar en las expresiones que empiezan las columnas m@'as a la
izquierda:

@smallexample
@group
(defun forward-sentence (&optional arg)
  "@var{documentation}@dots{}"
  (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))))
       @var{rest-of-body-of-while-loop-when-going-backwards}
    (while (> arg 0)
      (let ((par-end (save-excursion (end-of-paragraph-text) (point))))
       @var{rest-of-body-of-while-loop-when-going-forwards}
    @var{handle-forms-and-equivalent}
@end group
@end smallexample

@exclamdown{}Esto parece bastante simple! La definici@'on de la
funci@'on consiste de documentaci@'on una expresi@'on
@code{interactive}, una expresi@'on @code{or}, una expresi@'on
@code{let}, y bucles @code{while}.

Permite mirar cada una de estas partes.

Notamos que la documentaci@'on es profunda y comprensible.

La funci@'on tiene una declaraci@'on @code{interactive "p"}. Esto
signifca que el argumento prefijo, si cualquiera es pasado a la
funci@'on como su argumento. (Esto ser@'a un n@'umero.) Si la
funci@'on no pasa un argumento (eso es opcional) entonces el argumento
@code{arg} ser@'a asociado a 1.

Cuando @code{forward-sentence} se llama no interactivamente sin un
argumento, @code{arg} est@'a asignado @code{nil}. La expresi@'on
@code{or} maneja esto. Lo que hace es dejar el valor de @code{arg}
como eso es, pero solo si @code{arg} est@'a asignado a un valor; o eso
asigna el valor de @code{arg} a 1, en el caso de @code{arg} est@'a
asignado a @code{nil}.

Lo siguiente es un @code{let}. Que especifica los valores de dos
variables locales @code{point} y @code{sentence-end}. El valor local
de punto, desde antes de la b@'usqueda, es usada en la funci@'on
@code{constrain-to-field} que maneja formularios y equivalentes. La
variable @code{sentence-end} est@'a asignada por la funci@'on
@code{sentence-end}.

@node Bucles while fwd-sentence
@unnumberedsubsec Los bucles @code{while}

Sigue dos bucles @code{while}. El primer @code{while} tiene un
true-or-false-test que chequea cierto si el argumento prefijo para
@code{forward-sentence} es un n@'umero negativo. Esto es para volver
hacia atr@'as. El cuerpo de este bucle es similar al cuerpo de la
segunda cl@'ausula @code{while}, pero eso no es exactamente el
mismo. Se obviar@'a este bucle @code{while} y concentra en el segundo
bucle @code{while}.

@need 1500
El segundo bucle @code{while} est@'a moviendo el punto hacia
adelante. Su esqueleto se parece a esto:

@smallexample
@group
(while (> arg 0)            ; @r{true-or-false-test}
  (let @var{varlist}
    (if (@var{true-or-false-test})
        @var{then-part}
      @var{else-part}
  (setq arg (1- arg))))     ; @code{while} @r{loop decrementer}
@end group
@end smallexample

El bucle @code{while} es el tipo de decremento. (@xref{Bucle que se
decrementa, , Un Bucle con un Contador de Decremento}.) Eso tiene un
true-or-false-test que chequea cierto tan largo con el contador (en
este caso, la variable @code{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@'un argumento prefijo es dado para @code{forward-sentece}, que
es el camino m@'as com@'un es usado, este bucle @code{while}
ejecutar@'a una vez, desde que el valor de @code{arg} ser@'a 1.

El cuerpo del cuerpo @code{while} consite de una expresi@'on
@code{let}, que crea y asocia una variable local, y tiene, su cuerpo,
una expresi@'on @code{if}.

@need 1250
El cuerpo del bucle @code{while} se parece a esto:

@smallexample
@group
(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)))
@end group
@end smallexample

La expresi@'on @code{let} crea y asocia la variable local
@code{par-end}. Como se ve, esta variable local est@'a dise@~nada para
proporcionar una asociaci@'on o l@'{@dotless{i}}mite para la
b@'usqueda de la expresi@'on regular. Si la b@'usqueda falla para
encontrar una frase apropiada finalizando en el p@'arrafo, eso
se parar@'a logrando el fin del p@'arrafo.

Pero primero, perm@'{@dotless{i}}tenos examinar c@'omo @code{par-end}
se asocia a la variable del fin del p@'arrafo. Lo que ocurre es que el
@code{let} asigna el valor de @code{par-end} al valor devuelto cuando
el int@'erprete eval@'ua la expresi@'on.

@smallexample
@group
(save-excursion (end-of-paragraph-text) (point))
@end group
@end smallexample

@noindent
En esta expresi@'on, @code{(end-of-paragraph-text)} mueve el punto al
fin del p@'arrafo, @code{(point)} devuelve el valor del punto, y
entonces @code{save-excursion} restaura el punto a su posici@'on
original. De este modo, el @code{let} asocia @code{par-end} al valor
devuelto por la expresi@'on @code{save-excursion}, que es la
posici@'on del fin del p@'arrafo.  (La funci@'on
@code{end-of-paragraph-text} usa @code{forward-paragraph}, que se
discutir@'a pronto.)

@need 1200
Emacs eval@'ua el cuerpo del @code{let}, que es una expresi@'on
@code{if} que se parece a esto:

@smallexample
@group
(if (re-search-forward sentence-end par-end t) ; @r{if-part}
    (skip-chars-backward " \t\n")              ; @r{then-part}
  (goto-char par-end)))                        ; @r{else-part}
@end group
@end smallexample

El test @code{if} si su primer argumento es cierto y si
as@'{@dotless{i}}, eval@'ua su parte then; de otro modo, el
int@'erprete Emacs Lisp eval@'ua la parte else. El true-or-false-test
de la expresi@'on @code{if} es la b@'usqueda de la expresi@'on regular.

Puede estar mal tener que mirar como el `trabajo real' de la funci@'on
@code{forward-sentence} es vista aqu@'{@dotless{i}}, pero esto es un
camino com@'un de este tipo de operaci@'on traida en Lisp.

@node Volver a buscar la frase en sentido directo
@unnumberedsubsec La b@'usqueda de expresiones regulares

La funci@'on @code{re-search-forward} busca el fin de la frase, que
es, para el patr@'on definido por la expresi@'on regular
@code{sentence-end}. Si el patr@'on es encontrado --- si el fin de la
frase se encuentra --- entonces la funci@'on @code{re-search-forward}
hace dos cosas:

@enumerate
@item
La funci@'on @code{re-search-forward} trae un efecto lateral, que es
mover el punto al final de la ocurrencia encontrada.

@item
La funci@'on @code{re-search-forward} devuelve un valor de
verdad. Esto es el valor recibido por el @code{if}, y significa que la
b@'usqueda fu@'e exitosa.
@end enumerate

@noindent
El efecto lateral, el movimiento del punto se completa antes de la
funci@'on @code{if} y es manejado por el valor devuelto por la exitosa
conclusi@'on de la b@'usqueda.

Cuando la funci@'on @code{if} recibe el valor de verdad desde una
llamada exitosa a @code{re-search-forward}, el @code{if} eval@'ua la
parte then que es la expresi@'on @code{(skip-chars-backward
"\t\n")}. Esta expresi@'on se mueve atr@'as a trav@'es de espacios en
blanco, los tabuladores o retornos de carro hasta un caracter impreso
es encontrado y entonces deja el punto correcto despu@'es del caracter
impreso cerrado de la frase, que es normalmente un periodo.

Por otro lado, si la funci@'on @code{re-search-forward} falla para
encontrar un patr@'on marcando el fin de la frase, la funci@'on
devuelve falso. Lo falso causa el @code{if} para evaluar su tercer
argumento, que es @code{(goto-char par-end)}: eso mueve el punto al
final del p@'arrafo.

(Y si el texto est@'a en una forma o equivalente, y apunta a que no
puede moverse completamente entonces la funci@'on
@code{constrain-to-field} empieza a funcionar.)

Las b@'usquedas de expresiones regulares son excepcionalmente @'utiles
y el patr@'on ilustrado por @code{re-search-forward}, en el que la
b@'usqueda es el test de una expresi@'on @code{if}, es manejable. Se
ver@'a o escribir@'a c@'odigo incorporando este patr@'on con frecuencia.

@node forward-paragraph
@section @code{forward-paragraph}: una mina de oro de funciones
@findex forward-paragraph

@ignore
@c in GNU Emacs 22
(defun forward-paragraph (&optional arg)
  "Move forward to end of paragraph.
With argument ARG, do it ARG times;
a negative argument ARG = -N means move backward N paragraphs.

A line which `paragraph-start' matches either separates paragraphs
\(if `paragraph-separate' matches it also) or is the first line of a paragraph.
A paragraph end is the beginning of a line which is not part of the paragraph
to which the end of the previous line belongs, or the end of the buffer.
Returns the count of paragraphs left to move."
  (interactive "p")
  (or arg (setq arg 1))
  (let* ((opoint (point))
         (fill-prefix-regexp
          (and fill-prefix (not (equal fill-prefix ""))
               (not paragraph-ignore-fill-prefix)
               (regexp-quote fill-prefix)))
         ;; Remove ^ from paragraph-start and paragraph-sep if they are there.
         ;; These regexps shouldn't be anchored, because we look for them
         ;; starting at the left-margin.  This allows paragraph commands to
         ;; work normally with indented text.
         ;; This hack will not find problem cases like "whatever\\|^something".
         (parstart (if (and (not (equal "" paragraph-start))
                            (equal ?^ (aref paragraph-start 0)))
                       (substring paragraph-start 1)
                     paragraph-start))
         (parsep (if (and (not (equal "" paragraph-separate))
                          (equal ?^ (aref paragraph-separate 0)))
                     (substring paragraph-separate 1)
                   paragraph-separate))
         (parsep
          (if fill-prefix-regexp
              (concat parsep "\\|"
                      fill-prefix-regexp "[ \t]*$")
            parsep))
         ;; This is used for searching.
         (sp-parstart (concat "^[ \t]*\\(?:" parstart "\\|" parsep "\\)"))
         start found-start)
    (while (and (< arg 0) (not (bobp)))
      (if (and (not (looking-at parsep))
               (re-search-backward "^\n" (max (1- (point)) (point-min)) t)
               (looking-at parsep))
          (setq arg (1+ arg))
        (setq start (point))
        ;; Move back over paragraph-separating lines.
        (forward-char -1) (beginning-of-line)
        (while (and (not (bobp))
                    (progn (move-to-left-margin)
                           (looking-at parsep)))
          (forward-line -1))
        (if (bobp)
            nil
          (setq arg (1+ arg))
          ;; Go to end of the previous (non-separating) line.
          (end-of-line)
          ;; Search back for line that starts or separates paragraphs.
          (if (if fill-prefix-regexp
                  ;; There is a fill prefix; it overrides parstart.
                  (let (multiple-lines)
                    (while (and (progn (beginning-of-line) (not (bobp)))
                                (progn (move-to-left-margin)
                                       (not (looking-at parsep)))
                                (looking-at fill-prefix-regexp))
                      (unless (= (point) start)
                        (setq multiple-lines t))
                      (forward-line -1))
                    (move-to-left-margin)
                    ;; This deleted code caused a long hanging-indent line
                    ;; not to be filled together with the following lines.
                    ;; ;; Don't move back over a line before the paragraph
                    ;; ;; which doesn't start with fill-prefix
                    ;; ;; unless that is the only line we've moved over.
                    ;; (and (not (looking-at fill-prefix-regexp))
                    ;;      multiple-lines
                    ;;      (forward-line 1))
                    (not (bobp)))
                (while (and (re-search-backward sp-parstart nil 1)
                            (setq found-start t)
                            ;; Found a candidate, but need to check if it is a
                            ;; REAL parstart.
                            (progn (setq start (point))
                                   (move-to-left-margin)
                                   (not (looking-at parsep)))
                            (not (and (looking-at parstart)
                                      (or (not use-hard-newlines)
                                          (bobp)
                                          (get-text-property
                                           (1- start) 'hard)))))
                  (setq found-start nil)
                  (goto-char start))
                found-start)
              ;; Found one.
              (progn
                ;; Move forward over paragraph separators.
                ;; We know this cannot reach the place we started
                ;; because we know we moved back over a non-separator.
                (while (and (not (eobp))
                            (progn (move-to-left-margin)
                                   (looking-at parsep)))
                  (forward-line 1))
                ;; If line before paragraph is just margin, back up to there.
                (end-of-line 0)
                (if (> (current-column) (current-left-margin))
                    (forward-char 1)
                  (skip-chars-backward " \t")
                  (if (not (bolp))
                      (forward-line 1))))
            ;; No starter or separator line => use buffer beg.
            (goto-char (point-min))))))

    (while (and (> arg 0) (not (eobp)))
      ;; Move forward over separator lines...
      (while (and (not (eobp))
                  (progn (move-to-left-margin) (not (eobp)))
                  (looking-at parsep))
        (forward-line 1))
      (unless (eobp) (setq arg (1- arg)))
      ;; ... and one more line.
      (forward-line 1)
      (if fill-prefix-regexp
          ;; There is a fill prefix; it overrides parstart.
          (while (and (not (eobp))
                      (progn (move-to-left-margin) (not (eobp)))
                      (not (looking-at parsep))
                      (looking-at fill-prefix-regexp))
            (forward-line 1))
        (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))
        (if (< (point) (point-max))
            (goto-char start))))
    (constrain-to-field nil opoint t)
    ;; Return the number of steps that could not be done.
    arg))
@end ignore

La funci@'on @code{forward-paragraph} mueve el punto al fin del
p@'arrafo. Eso est@'a normalmente asociado a @kbd{M-@}} y hace uso de
un n@'umero de funciones que son importantes en s@'{@dotless{i}},
incluyendo @code{let*}, @code{match-beginning}, y @code{looking-at}.

La definici@'on de funci@'on para @code{forward-paragraph} es
considerablemente mayor que la definici@'on de funci@'on para
@code{forward-sentence} porque eso funciona como un p@'arrafo, cada
l@'{@dotless{i}}nea puede empezar con un prefijo de relleno @emph{fill
prefix}.

Un prefijo de relleno @emph{fill prefix} consiste en una cadena de
caracteres que se repite al principio de cada
l@'{@dotless{i}}nea. Por ejemplo, en c@'odigo Lisp, es una
convenci@'on para empezar cada l@'{@dotless{i}}nea de un comentario de
p@'arrafo largo con @samp{;;; }. En modo Texto, cuatro espacios en
blanco crean otro prefijo de relleno @emph{fill prefix} com@'un,
creando un p@'arrafo indentado. (@xref{Fill Prefix, , , emacs, The GNU
Emacs Manual} para m@'as informaci@'on acerca de prefijos de relleno
@emph{fill prefix}.)

La existencia de un prefijo de relleno significa que adem@'as de ser
capaz de encontrar el fin de un p@'arrafo cuyas l@'{@dotless{i}}neas
empiezan m@'as a la izquierda, la funci@'on @code{forward-paragraph}
debe ser capaz de encontrar el fin de un p@'arrafo cuando todas o
muchas de las l@'{@dotless{i}}neas en el b@'uffer empiezan con el
prefijo de relleno @emph{fill prefix}.

M@'as all@'a, es algunas veces pr@'actico ignorar un prefijo de
relleno @emph{fill prefix} que existe, especialmente cuando las
l@'{@dotless{i}}neas en blanco separen p@'arrafos. Esto es una
complicaci@'on a@~nadida.

@menu
* forward-paragraph en breve::  Partes clave de la definici@'on de la 
                                  funci@'on.
* fwd-para let::             La expresi@'on @code{let*}.
* fwd-para while::           El bucle @code{while} con modo hacia adelante.
@end menu

@ifnottex
@node forward-paragraph en breve
@unnumberedsubsec Definici@'on de funci@'on @code{forward-paragraph}
@end ifnottex

En vez de imprimir toda la funci@'on @code{forward-paragraph},
nosotros solo imprimiremos partes de la misma. @exclamdown{}Lee sin
preparaci@'on, la funci@'on puede estar para desanimar!

@need 800
En esquema, la funci@'on se parece a esto:

@smallexample
@group
(defun forward-paragraph (&optional arg)
  "@var{documentation}@dots{}"
  (interactive "p")
  (or arg (setq arg 1))
  (let*
      @var{varlist}
    (while (and (< arg 0) (not (bobp)))     ; @r{backward-moving-code}
      @dots{}
    (while (and (> arg 0) (not (eobp)))     ; @r{forward-moving-code}
      @dots{}
@end group
@end smallexample

Las primeras partes de la funci@'on son rutinas: la funci@'on lista
argumentos que consisten de un argumento opcional. La documentaci@'on sigue.

La letra min@'uscula @samp{p} en la declaraci@'on @code{interactive}
significa que el argumento prefijo se procesa, si se pasa a la
funci@'on. Eso ser@'a un n@'umero, y es el contaje repetido de cu@'antos
p@'arrafos se mover@'a.  La expresi@'on @code{or} en la siguiente
l@'{@dotless{i}}nea maneja el caso com@'un cuando no hay argumentos
que se pasan a la funci@'on, esto ocurre si la funci@'on se llama
desde otro c@'odigo en vez de interactivamente. Este caso se describe
pronto. (@xref{forward-sentence, La funci@'on
@code{forward-sentence}}.) Ahora se logra el fin de la parte familiar
de esta funci@'on.

@node fwd-para let
@unnumberedsubsec La expresi@'on @code{let*}

La siguiente l@'{@dotless{i}}nea de la funci@'on
@code{forward-paragraph} empieza una expresi@'on @code{let*}. Esto es
tan diferente como @code{let}. El s@'{@dotless{i}}mbolo es @code{let*}
no @code{let}.

La forma especial @code{let*} es como @code{let} excepto que Emacs
asigna cada variable en secuencia, una despu@'es de otra, y las
variables en la @'ultima parte de la varlist hacen uso de los valores
para los que Emacs asign@'o variable al principio la varlist.

@ignore
( refappend save-excursion, , code save-excursion in code append-to-buffer .)
@end ignore

(@ref{append save-excursion, , @code{save-excursion} en
@code{append-to-buffer}}.)

En la expresi@'on @code{let*} en esta funci@'on, Emacs asigna un total
de siete variables: @code{opoint}, @code{fill-prefix-regexp},
@code{parstart}, @code{parsep}, @code{sp-parstart}, @code{start}, y
@code{found-start}.

La variable @code{parsep} aparece dos veces, primero, para borrar
instancias de @samp{^}, y segundo, para manejar prefijos rellenos.

La variable @code{opoint} es solo el valor de @code{point}. Como se
puede adivinar, eso se usa en una expresi@'on
@code{constrain-to-field}, solo como en @code{forward-sentence}.

La variable @code{fill-prefix-regexp} se asigna al valor devuelto para
evaluar la siguiente lista:

@smallexample
@group
(and fill-prefix
     (not (equal fill-prefix ""))
     (not paragraph-ignore-fill-prefix)
     (regexp-quote fill-prefix))
@end group
@end smallexample

@noindent
Esta es una expresi@'on cuyo primer elemento es la forma especial
@code{and}.

Como se aprendi@'o antes la (@pxref{Funci@'on kill-new, , La funci@'on
@code{kill-new}}), la forma especial @code{and} eval@'ua cada uno de
sus argumentos hasta uno de los argumentos y devuelve un valor de
@code{nil} en el que el caso de la expresi@'on @code{and} devuelve
@code{nil}; sin embargo, si ninguno de los argumentos devuelve un
valor de @code{nil}, el valor resultante de evaluar el @'ultimo
argumento es devuelto. (Puesto que tal valor no es @code{nil}, eso es
considerado verdad en Lisp.) En otras palabras, una expresi@'on
@code{and} devuelve un valor de verdad solo si todos sus argumentos
son verdad.
@findex and

En este caso, la variable @code{fill-prefix-regexp} est@'a asociado a
un valor no @code{nil} solo si el las siguientes cuatro expresiones
producen un valor true (por ej., un no @code{nil}) cuando son
evaluados; de otro modo, @code{fill-prefix-regexp} est@'a asociado a
@code{nil}.

@table @code
@item fill-prefix
Cuando esta variable se eval@'ua, el valor del prefijo de relleno
@emph{fill prefix}, si cualquiera, est@'a devuelto. Si no hay prefijo
relleno, la variable devuelve @code{nil}.

@item (not (equal fill-prefix "")
Esta expresi@'on chequea si un prefijo lleno es una cadena
vac@'{@dotless{i}}a, que es, una cadena sin caracteres en eso. Una
cadena vac@'{@dotless{i}}a no es @'util un prefijo relleno @emph{fill
prefix}.

@item (not paragraph-ignore-fill-prefix)
Esta expresi@'on devuelve @code{nil} si la variable
@code{paragraph-ignore-fill-prefix} ha sido cambiado siendo asignado
un valor de verdad tal como @code{t}.

@item (regexp-quote fill-prefix)
Este es el @'ultimo argumento para la forma especial @code{and}. Si
todos los argumentos de @code{and} son verdaderos, el valor resultante
de evaluar esta expresi@'on ser@'a devuelto por la expresi@'on
@code{and} y asociado a la variable @code{fill-prefix-regexp},
@end table

@findex regexp-quote
@noindent
El resultado de evaluar esta expresi@'on @code{and} con @'exito es que
@code{fill-prefix-regexp} se asociar@'a al valor de @code{fill-prefix}
como fu@'e modificado por la funci@'on @code{regexp-quote}. Lo que
@code{regexp-quote} hace es leer una cadena y devolver la expresi@'on
regular que asociar@'a exactamente la cadena y nada m@'as. Esto
significa que @code{fill-prefix-regexp} ser@'a asignada a un valor que
asociar@'a el prefijo si el prefijo existe. De otro modo, la variable
ser@'a asignada a @code{nil}.

Las dos variables locales siguientes en la expresi@'on @code{let*}
est@'an dise@~nadas para eliminar instancias de @samp{^} desde
@code{parstart} y @code{parsep}, las variables locales indican que
el p@'arrafo empieza como separador de p@'arrafo. La siguiente
expresi@'on asigna @code{parsep} de nuevo. Esto es manejar prefijos
rellenos.

Esta es la configuraci@'on que requiere la llamada de la definici@'on
@code{let*} en vez de @code{let}. El true-or-false-test para el
@code{if} depende de si la variable @code{fill-prefix-regexp} eval@'ua
a @code{nil} o alg@'un otro valor.

Si @code{fill-prefix-regexp} no tiene un valor, Emacs eval@'ua la
parte else de la expresi@'on @code{if} y asocia @code{parsep} a su
valor local. (@code{parsep} es una expresi@'on regular que asocia lo
que los p@'arrafos separan.)

Pero si @code{fill-prefix-regexp} tiene un valor, Emacs eval@'ua la
parte then de la expresi@'on @code{if} y asocia @code{parsep} a una
expresi@'on regular que incluye el @code{fill-prefix-regexp} como
parte del patr@'on.

Espec@'{@dotless{i}}ficamente, @code{parsep} est@'a asignado al valor
original del
p@'arrafo que separa la expresi@'on regular concatenada con una
expresi@'on alternativa que consiste del @code{fill-prefix-regexp}
seguido por espacios en blanco opcionales para el fin de la
l@'{@dotless{i}}nea. El espacio en blanco est@'a definido por
@w{@code{"[ \t]*$"}}.) El @samp{\\|} define esta porci@'on del regexp
como una alternativa a @code{parsep}.

De acuerdo a un comentario en el c@'odigo, la siguiente variable
local, @code{sp-parstart}, se usa para buscar, y entonces los dos
finales, @code{start} y @code{found-start}, se asignan a @code{nil}.

Ahora tenemos dentro el cuerpo del @code{let*}. La primera parte del
cuerpo del @code{let*} trata con el caso cuando la funci@'on es dada
a un argumento negativo y consiguientemente movi@'endose hacia
atr@'as. Nosotros saldremos de esta secci@'on yendo hacia atr@'as. 

@node fwd-para while
@unnumberedsubsec El bucle @code{while} hacia adelante

La segunda parte del cuerpo del @code{let*} trata con el proceso hacia
adelante. Eso es un bucle @code{while} que se repite si el valor de
@code{arg} es mayor que cero. En el uso m@'as com@'un de la funci@'on
el valor del argumento es 1, as@'{@dotless{i}} el cuerpo del bucle
@code{while} se eval@'ua exactamente una vez, y el cursor se mueve
hacia adelante un p@'arrafo.

@ignore
(while (and (> arg 0) (not (eobp)))

  ;; Move forward over separator lines...
  (while (and (not (eobp))
              (progn (move-to-left-margin) (not (eobp)))
              (looking-at parsep))
    (forward-line 1))
  (unless (eobp) (setq arg (1- arg)))
  ;; ... and one more line.
  (forward-line 1)

  (if fill-prefix-regexp
      ;; There is a fill prefix; it overrides parstart.
      (while (and (not (eobp))
                  (progn (move-to-left-margin) (not (eobp)))
                  (not (looking-at parsep))
                  (looking-at fill-prefix-regexp))
        (forward-line 1))

    (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))

    (if (< (point) (point-max))
        (goto-char start))))
@end ignore

Esta parte maneja tres situaciones: cuando el punto est@'a entre
p@'arrafos, cuando hay un prefijo de relleno y cuando no hay prefijo
de relleno @emph{fill prefix}.

@need 800
El bucle @code{while} se parece a esto:

@smallexample
@group
;; @r{yendo hacia adelante y no al fin del b@'uffer}
(while (and (> arg 0) (not (eobp)))

  ;; @r{entre p@'arrafos}
  ;; Mueve hacia adelante a trav@'es de l@'{@dotless{i}}neas de
  ;; separaci@'on...
  (while (and (not (eobp))
              (progn (move-to-left-margin) (not (eobp)))
              (looking-at parsep))
    (forward-line 1))
  ;;  @r{Esto decremento el bucle}
  (unless (eobp) (setq arg (1- arg)))
  ;; ... y una l@'{@dotless{i}}nea m@'as
  (forward-line 1)
@end group

@group
  (if fill-prefix-regexp
      ;; Hay un prefijo lleno; que sobreescribe parstart;
      ;; vamos adelante l@'{@dotless{i}}nea por l@'{@dotless{i}}nea
      (while (and (not (eobp))
                  (progn (move-to-left-margin) (not (eobp)))
                  (not (looking-at parsep))
                  (looking-at fill-prefix-regexp))
        (forward-line 1))
@end group

@group
    ;; 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))
@end group

@group
    ;; y si no hay prefijo y si no estamos al final
    ;; ir a lo que fu@'e encontrado en la b@'usqueda de expresiones regulares
    ;; para sp-parstart
    (if (< (point) (point-max))
        (goto-char start))))
@end group
@end smallexample

@findex eobp
Se puede ver que esto es un contador de decremento @code{while},
usando la expresi@'on @code{(setq arg (1- arg))} como lo que se
decrementa. Esta expresi@'on no est@'a lejos desde el @code{while},
pero est@'a oculta en otra macro Lisp, una macro @code{unless}. A
menos que estemos al final del b@'uffer --- esto es lo que la
funci@'on @code{eobp} determina; eso es una abreviaci@'on de @samp{Fin
del Buffer P} --- nosotros decrementamos el valor de @code{arg} por
uno.

(Si estamos al fin del b@'uffer, no podemos ir m@'as hacia adelante y
el siguiente bucle de la expresi@'on @code{while} chequear@'a falso
desde que el test es un @code{and} con @code{(not (eobp))}. La
funci@'on @code{not} significa exactamente como se esperaba; eso es
otro nombre de @code{null}, una funci@'on 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@'arrafos, a menos que vuelva al fin
del b@'uffer o pare viendo el valor local del separador del p@'arrafo.

El segundo @code{while} tambi@'en tiene una expresi@'on
@code{(move-to-left-margin)}. La funci@'on es autoexplicativa. Eso
est@'a dentro de una expresi@'on @code{progn} y no el @'ultimo
elemento de su cuerpo, as@'{@dotless{i}} es solo invocado para su
efecto lateral, que es mover el punto al margen izquierdo de la
l@'{@dotless{i}}nea actual.

@findex looking-at
La funci@'on @code{looking-at} es tambi@'en auto-explicativa; eso
devuelve cierto si el texto despu@'es del punto asocia la expresi@'on
regular dada como su argumento.

El resto del cuerpo del bucle se ve compleja al principio, pero tiene
sentido cuando se comprende.

@need 800
Primero considera que ocurre si hay un prefijo de relleno @emph{fill
prefix}:

@smallexample
@group
  (if fill-prefix-regexp
      ;; Hay un prefijo lleno; que sobreescribe parstart;
      ;; vamos adelante l@'{@dotless{i}}nea por l@'{@dotless{i}}nea
      (while (and (not (eobp))
                  (progn (move-to-left-margin) (not (eobp)))
                  (not (looking-at parsep))
                  (looking-at fill-prefix-regexp))
        (forward-line 1))
@end group
@end smallexample

@noindent
Esta expresi@'on mueve el punto hacia adelante l@'{@dotless{i}}nea por
l@'{@dotless{i}}nea tan lejos como que las cuatro condiciones son ciertas:

@enumerate
@item
Punto no est@'a al final del b@'uffer.

@item
Podemos mover al margen izquierdo del texto y no estar al fin del b@'uffer.

@item
El siguiente punto no separa p@'arrafos.

@item
El patr@'on que sigue el punto es la expresi@'on regular prefija rellena.
@end enumerate

La @'ultima condici@'on puede ser un puzzle, hasta que se recuerde qu@'e
punto fu@'e movido al principio de la l@'{@dotless{i}}nea temprana en
la funci@'on @code{forward-paragraph}. Esto significa que si el texto
tiene el prefijo relleno, la funci@'on @code{looking-at} se ver@'a.

@need 1250
Considera qu@'e ocurre cuando no hay un prefijo lleno.

@smallexample
@group
    (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))
@end group
@end smallexample

@noindent
El bucle @code{while} nos tiene buscando hacia adelante para
@code{sp-parstart}, que es la combinaci@'on de posibles espacios en
blanco con un valor local del comienzo de un p@'arrafo o de un
p@'arrafo separador. (Las @'ultimas dos son con una expresi@'on
empezando con @code{(?:)} as@'{@dotless{i}} que no est@'an
referenciadas por la funci@'on @code{match-beginning}.)

@need 800
Las dos expresiones,

@smallexample
@group
(setq start (match-beginning 0))
(goto-char start)
@end group
@end smallexample

@noindent
significa ir al comienzo del siguiente texto localizado por la
expresi@'on regular.

La expresi@'on @code{(match-beginning 0)} es nueva. Eso devuelve un
n@'umero especificando la posici@'on del comienzo del texto fuese
asociado a la @'ultima b@'usqueda.

La funci@'on @code{match-beginning} es usado aqu@'{@dotless{i}} porque
una caracter@'{@dotless{i}}stica de una b@'usqueda hacia adelante: una
b@'usqueda hacia adelante, sin dignidad si eso es una b@'usqueda plana
o una expresi@'on regular, mueve el punto al fin del texto que es
encontrado. En este caso, una b@'usqueda exitosa mueve el punto al
fin del patr@'on para @code{sp-parstart}.

Sin embargo, se quiere poner el punto al fin del actual p@'arrafo, no
en alg@'un lugar m@'as. En vez de eso, desde que la b@'usqueda
posiblemente incluye el separador del p@'arrafo, el punto puede
finalizar al principio de lo siguiente a menos que se use una
expresi@'on que incluya @code{match-beginning}.

@findex match-beginning
Cuando un argumento de 0, @code{match-beginning} devuelve la posici@'on
que es el comienzo del texto asociado por la b@'usqueda m@'as
reciente. En este caso, la b@'usqueda m@'as reciente parece
@code{sp-parstart}. La expresi@'on @code{(match-beginning 0)} devuelve
la posici@'on del comienzo de este patr@'on, en vez de la posici@'on
final de este patr@'on.

(Incidentalmente, cuando se pasa un n@'umero positivo como un
argumento, la funci@'on @code{match-beginning} devuelve la
localizaci@'on de punto en el que la expresi@'on con par@'entesis en
la @'ultima b@'usqueda a menos que la expresi@'on con par@'entesis
empiece con @code{\(?:}. No s@'e porque @code{\(?:} aparece
aqu@'{@dotless{i}} desde que el argumento es 0.)

@need 1250
La @'ultima expresi@'on cuando no hay prefijos es

@smallexample
@group
(if (< (point) (point-max))
    (goto-char start))))
@end group
@end smallexample

@noindent
Esto dice que si no hay prefijo lleno y no estamos al punto final que
se mover@'{@dotless{i}}a al principio de lo que fu@'e encontrado por
la b@'usqueda de la expresi@'on regular para @code{sp-parstart}.

La definici@'on completa para la funci@'on @code{forward-paragraph} no
solo incluye c@'odigo para avanzar, tambi@'en c@'odigo para retroceder.

Si est@'a leyendo esto dentro de GNU Emacs y quieres ver la funci@'on
completa, se puede escribir @kbd{C-h f} (@code{describe-function}) y
el nombre de la funci@'on. Esto da la documentaci@'on de funci@'on
y el nombre de la librer@'{@dotless{i}}a conteniendo las fuentes de la
funci@'on. Posiciona el punto a trav@'es del nombre de la
librer@'{@dotless{i}}a y presionar la tecla RET; ser@'a tomado
directamente a las fuentes. (@exclamdown{}Aseg@'urate de instalar las
fuentes! @exclamdown{}Sin eso, estar@'as como una persona que intenta
conducir un coche con los ojos cerrados!)

@node etags
@section Crea tu propio fichero @file{TAGS}
@findex etags
@cindex fichero de @file{TAGS}, crea el propio

Bajo @kbd{C-h f} (@code{describe-function}), otro camino para ver la
fuente de una funci@'on es escribir @kbd{M-.} (@code{find-tag}) y el
nombre de la funci@'on se asigna para eso. Esto es un buen h@'abito
para obtenerlo. El comando @kbd{M-.} (@code{find-tag}) toma
directamente a las fuentes de una funci@'on, variable, o nodo. La
funci@'on depende de tablas de etiquetas para saber donde ir.

Si la funci@'on @code{find-tag} pregunta primero por el nombre de una
tabla @file{TAGS}, dado el nombre de un fichero @file{TAGS} tal como
@file{/usr/local/src/emacs/src/TAGS}. (La ruta exacta a tu fichero
@file{TAGS} depende de c@'omo tu copia de Emacs fu@'e instalada. Yo
te cuento la localizaci@'on que provee tanto mi C y mis fuentes de
Emacs Lisp.)

Se puede tambi@'en crear tu propio fichero @file{TAGS} para los directorios
que faltan.

Con frecuencia se necesita construir e instalar etiquetas de tablas
por uno mismo. Esas no son construidas autom@'aticamente. Una tabla de
etiquetas llama a un fichero @file{TAGS}; el nombre es letras
may@'usculas.

Se puede crear un fichero @file{TAGS} llamando el programa
@code{etags} que viene como parte de la distribuci@'on
Emacs. Normalmente, @code{etags} est@'a compilado e instalado cuando
Emacs se construye. (@code{etags} no es una funci@'on Lisp o una parte
de Emacs; eso es un programa C.)

@need 1250
Para crear el fichero @file{TAGS}, primero cambia el directorio en el
que se quiere crear el fichero. En Emacs se puede hacer esto con el
comando @kbd{M-x cd}, o visitando un fichero en el directorio, o
listando el directorio @w{@code{etags *.el}} como el comando a ejecutar

@smallexample
M-x compile RET etags *.el RET
@end smallexample

@noindent
crear un fichero de @file{TAGS} para Emacs Lisp.

Por ejemplo, si se tiene un gran n@'umero de ficheros en el
directorio @file{~/emacs}, como se hace --- Yo tengo 137 @file{.el}
dentro, de que se carguen 12 --- se puede crear un fichero @file{TAGS}
para los ficheros Emacs Lisp en este directorio.

@need 1250
El programa @code{etags} toma en toda la consola usual `comodines'. Por
ejemplo, si tienes dos directorios para el que quieres un fichero
@file{TAGS} simple, escribe @w{@code{etags *.el ../elisp/*.el}}, donde
@file{../elisp/} es el segundo directorio:

@smallexample
M-x compile RET etags *.el ../elisp/*.el RET
@end smallexample

@need 1250
Tipo

@smallexample
M-x compile RET etags --help RET
@end smallexample

@noindent
para ver una lista de las opciones aceptadas por @code{etags} tan bien
como una lista de lenguajes soportados.

El programa @code{etags} maneja m@'as 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@'{@dotless{i}}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.

@file{etags} es muy @'util cuando se escribe c@'odigo por
t@'{@dotless{i}} mismo y quiere referirse a funciones que ya se han
escrito. Ahora ejecuta @code{etags} de nuevo en intervalos como se
escriben nuevas funciones, as@'{@dotless{i}} llegan a ser parte del
fichero @file{TAGS}.

Si piensa que un fichero @file{TAGS} apropiado que ya existe para lo
que quieres, pero no conoces donde est@'a, se puede usar el programa
@code{locate} para intentar encontrarlo.

Escribe @w{@kbd{M-x locate @key{RET} TAGS @key{RET}}} y Emacs
listar@'a para ti las rutas nombres completas de todos tus ficheros
@file{TAGS}. En mi sistema, este comando lista 34 fichero @file{TAGS}.
Por otro lado, un sistema `vanilla plano' que recientemente no
conten@'{@dotless{i}}a fichero @file{TAGS}.

Si la tabla de etiquetas que se quiere ha sido creada, se puede usar
el comando @code{M-x visit-tags-table} para especificarlo. De otro
modo, se necesitar@'a la tabla de etiquetas por t@'{@dotless{i}} mismo
y entonces usar @code{M-x visit-tags-table}.

@subsubheading Construyendo Etiquetas en las fuentes Emacs
@cindex Construyendo Etiquetas en las fuentes Emacs
@cindex Etiquetas en las fuentes Emacs
@findex crear etiquetas

Las fuentes GNU Emacs vienen con un @file{Makefile} que contiene un
comando sofisticado @code{etags} que crea, recoge, y asocia tablas de
etiquetas de todas las fuentes de Emacs y pone la informaci@'on dentro
de un fichero @file{TAGS} en el directorio @file{src/}. (El directorio
@file{src/} est@'a debajo del alto nivel de tu directorio Emacs.)

@need 1250
Para construir este fichero @file{TAGS}, se puede ir al alto nivel de
directorio de fuentes Emacs y ejecutar el comando de compilar @code{make
tags}:

@smallexample
M-x compile RET make tags RET
@end smallexample

@noindent
(El comando @code{make tags} trabaja bien con las fuentes de GNU
Emacs, tan bien como con otros paquetes fuentes.)

Para m@'as informaci@'on, mira @ref{Etiquetas, , Tablas de Etiquetas,
emacs, El Manual GNU Emacs}.

@node Revisar regexp
@section Revisar

Aqu@'{@dotless{i}} hay un breve resumen de algunas funciones
introducidas recientemente.

@table @code
@item while
Repetidamente eval@'ua el cuerpo de la expresi@'on tan larga como el
primer elemento del cuerpo chequea cierto. Entonces devuelve
@code{nil}. (La expresi@'on es evaluado solo por sus efectos laterales.)

@need 1250
Por ejemplo:

@smallexample
@group
(let ((foo 2))
  (while (> foo 0)
    (insert (format "foo is %d.\n" foo))
    (setq foo (1- foo))))

     @result{}      foo is 2.
             foo is 1.
             nil
@end group
@end smallexample

@noindent
(La funci@'on @code{insert} inserta sus argumentos en el punto; la
funci@'on @code{format} devuelve una cadena formateada desde sus
argumentos el camino @code{message} formatea sus argumentos; @code{\n}
produce una nueva l@'{@dotless{i}}nea.)

@item re-search-forward
Busca un patr@'on, y si el patr@'on se encuentra, mueve el punto al
resto solo despu@'es de eso.

@noindent
Toma cuatro argumentos, como @code{search-forward}:

@enumerate
@item
Una expresi@'on regular que especifica el patr@'on para
buscarlo. (@exclamdown{}Recuerda por marcas de comillas alrededor de
este argumento!)

@item
Opcionalmente, el l@'{@dotless{i}}mite de la b@'usqueda.

@item
Opcionalmente, que haces si la b@'usqueda falla, devuelve @code{nil} o
un mensaje de error.

@item
Opcionalmente, cu@'antas veces se puede repetir la b@'usqueda; si es
negativa, la b@'usqueda va hacia atr@'as.
@end enumerate

@item let*
Asocia algunas variables localmente a valores particulares, y entonces
eval@'ua los argumentos que permanencen, devolviendo el valor del
@'ultimo. Mientras se asocian las variables locales, se usan los
valores locales de variables asociadas pronto, si acaso.

@need 1250
Por ejemplo:

@smallexample
@group
(let* ((foo 7)
      (bar (* 3 foo)))
  (message "`bar' is %d." bar))
     @result{} `bar' is 21.
@end group
@end smallexample

@item match-beginning
Devuelve la posici@'on del principio del texto encontrado por la
@'ultima b@'usqueda de la expresi@'on regular.

@item looking-at
Devuelve @code{t} para verdadero si el texto despu@'es del punto se
asocia al argumento, que deber@'{@dotless{i}}a ser una expresi@'on.

@item eobp
Devuelve @code{t} para cierto si el punto est@'a en el fin de la parte
accesible de un b@'uffer. El fin de la parte accesible es el fin del
b@'uffer no est@'a encogido; eso es el fin de la parte encogida si el
b@'uffer est@'a encogido.
@end table

@need 1500
@node Ejercicios re-search
@section Ejercicios con @code{re-search-forward}

@itemize @bullet
@item
Escribe una funci@'on para buscar para una expresi@'on que detecte dos
o m@'as l@'{@dotless{i}}neas blancas en secuencia.

@item
Escribe una funci@'on para buscar palabras duplicadas, tales como `el
el'. @xref{Regexps, , Sintaxis para Expresiones Regulares, emacs, El
Manual de GNU Emacs}, para informaci@'on de c@'omo escribir un regexp
(una expresi@'on regular) para asociar una cadena que se compone de
dos mitades id@'enticas. Se puede disponer de varios regexps; algunos
son mejores que otros. La funci@'on que se usa es descrito en un
ap@'endice, a lo largo de varios regexps. @xref{the-the, , Funci@'on
de Palabras Duplicadas @code{the-the}}.
@end itemize

@node Contando palabras
@chapter Contando: repetici@'on y regexps
@cindex Repetici@'on para contar palabras
@cindex Expresiones regulares para contar palabras

La repetici@'on y b@'usqueda de expresiones regulares son herramientas
poderosas que con frecuencia se usan cuando se escribe c@'odigo en Emacs
Lisp. Este cap@'{@dotless{i}}tulo ilustra el uso de b@'usqueda de
expresiones regulares a trav@'es de la construcci@'on de comandos de
contaje de palabras usando bucles @code{while} y recursi@'on.

@menu
* Por qu@'e Contar Palabras::  Por qu@'e Contar Palabras
* @value{COUNT-WORDS}::      Usa un regexp, pero encuentra un problema.
* recursive-count-words::    Empezar en caso de que no haya palabras en la 
                               regi@'on.
* Ejercicio de Contar::      Ejercicio de Contar
@end menu

@ifnottex
@node Por qu@'e Contar Palabras
@unnumberedsec Contando palabras
@end ifnottex

La distribuci@'on de Emacs est@'andar contiene una funci@'on para
contar el n@'umero de l@'{@dotless{i}}neas en una regi@'on. 

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@'{@dotless{i}}a. Parece raro, pero durante mucho tiempo,
a Emacs le falt@'o un comando para contar palabras. Quiz@'as la gente
usaba Emacs mayoritariamente para codificar o documentar cosas que no
requieren contar palabras, o quiz@'as se restring@'{@dotless{i}}an al
sistema operativo el comando de contar palabras, @code{wc}. De manera
alternativa, la gente puede seguir la convenci@'on de las editoriales
y computaban un contaje de palabras dividiendo el n@'umero de caracteres
en un documento por cinco.

Hay mucho caminos para implementar un comando para contar
palabras. Aqu@'{@dotless{i}} hay algunos ejemplos, que pueden desear
compararse con el comando de Emacs est@'andar,
@code{count-words-region}.

@node @value{COUNT-WORDS}
@section La funci@'on @code{@value{COUNT-WORDS}}
@findex @value{COUNT-WORDS}

Un comando de contar palabras podr@'{@dotless{i}}a contar palabras en
una l@'{@dotless{i}}nea, p@'arrafo, regi@'on, o
b@'uffer. @questiondown{}Qu@'e comando funcionar@'{@dotless{i}}a? Se
podr@'{@dotless{i}}a dise@~nar el comando para contar el n@'umero de
palabras en un b@'uffer completo. Sin embargo, la tradici@'on Emacs
anima a la flexibilidad --- se puede querer contar palabras solo en
una secci@'on, en vez de en todo un b@'uffer. As@'{@dotless{i}}, tiene
m@'as sentido dise@~nar el comando para contar el n@'umero de palabras
en una regi@'on. Una vez tienes un comando @code{count-words-region},
se puede, si desea, contar palabras en un b@'uffer completo
marc@'andolo con @w{@kbd{C-x h}} (@code{mark-whole-buffer}).

Claramente, contar palabras es un acto repetitivo: empezando desde el
principio de la regi@'on, se cuenta la primera palabra, entonces la
segunda palabra, entonces la tercera palabra, y as@'{@dotless{i}},
hasta que logres el fin de la regi@'on. Esto significa que contar
palabras se ajusta idealmente a recursi@'on o a un bucle @code{while}.

@menu
* Dise@~nar @value{COUNT-WORDS}::  La definici@'on usando un bucle 
                                     @code{while}.
* Error de espacio en blanco::  El error de espacio en blanco en 
                                  @code{@value{COUNT-WORDS}}.
@end menu

@ifnottex
@node Dise@~nar @value{COUNT-WORDS}
@unnumberedsubsec Dise@~nando @code{@value{COUNT-WORDS}}
@end ifnottex

Primero, implementaremos el comando de contar palabras con un bucle
@code{while}, entonces con la recursi@'on. El comando, de acuerdo,
ser@'a interactivo.

@need 800
La plantilla para una definici@'on de funci@'on interactiva es, como
siempre:

@smallexample
@group
(defun @var{name-of-function} (@var{argument-list})
  "@var{documentation}@dots{}"
  (@var{interactive-expression}@dots{})
  @var{body}@dots{})
@end group
@end smallexample

Lo que necesitamos hacer es rellenar los slots.

El nombre de la funci@'on ser@'{@dotless{i}}a auto-explicativo y
similar al nombre del @code{count-lines-region} existente. Esto hace
que el nombre sea f@'acil de recordar. @code{count-words-region} es
una buena elecci@'on. Puesto que el nombre se usa ahora para el
comando de Emacs est@'andar para contar palabras, nosotros nombraremos
nuestra implementaci@'on como @code{@value{COUNT-WORDS}}.

La funci@'on cuenta palabras con una regi@'on. Esto significa que el
argumento lista debe contener s@'{@dotless{i}}mbolos que son asociados
a las dos posiciones, el principio y fin de la regi@'on. Estas dos
posiciones puede ser llamadas @samp{beginning} y @samp{end}
respectivamente. La primera l@'{@dotless{i}}nea de la documentaci@'on
ser@'{@dotless{i}}a una frase simple, desde que esto es todo lo que
est@'a impreso como documentaci@'on por un comando tal como
@code{apropos}. La expresi@'on interactiva ser@'a de la forma
@samp{(interactive "r")}, puesto que causar@'a que Emacs pase al
principio y fin de la regi@'on a la lista de argumentos de
funci@'on. Todo esto es rutina.

El cuerpo de la funci@'on necesita ser escrita para hacer tres tareas:
primero, configurar condiciones bajo las que el bucle @code{while}
pueda contar palabras, segundo, ejecutar el bucle @code{while}, y
tercero, enviar un mensaje al usuario.

Cuando un usuario llama a @code{@value{COUNT-WORDS}}, apunta a que
puede estar al principio o fin de la regi@'on. Sin embargo, el proceso
de conteo debe empezar al principio de la regi@'on. Esto significa que
querremos poner el punto que hay si eso no est@'a
all@'{@dotless{i}}. Ejecutando @code{(goto-char beginning)} asegura
esto. De acuerdo, querremos devolver el punto a su posici@'on esperada
cuando la funci@'on finalice su trabajo. Por esta raz@'on, el cuerpo
debe ser encerrado en una expresi@'on @code{save-excursion}.

La parte central del cuerpo de la funci@'on consiste en un bucle
@code{while} en el que una expresi@'on salta el punto hacia delante
palabra por palabra, y otra expresi@'on cuenta estos saltos. Si el
test-verdadero-o-falso del bucle @code{while} es verdadero, el punto
saltar@'{@dotless{i}}a hacia adelante, y si es falso el punto
estar@'{@dotless{i}}a al fin de la regi@'on.

Nosotros podr@'{@dotless{i}}amos usar @code{(forward-word 1)} como la
expresi@'on para mover el punto hacia adelante palabra por palabra,
pero eso es f@'acil de ver que Emacs identifica como una `palabra' si
se usa una b@'usqueda de expresi@'on regular.

Una expresi@'on regular busca lo que encuentra el patr@'on que se
est@'a buscando deja el punto despu@'es del @'ultimo car@'acter
emparejado. Esto significa que una sucesi@'on de palabras exitosas
busquen que mover@'a el punto adelante palabra por palabra.

Como materia pr@'actica, se quiere que la expresi@'on regular se
busque para saltar a trav@'es de un espacio en blanco y punt@'ue entre
palabras tan bien a trav@'es de las palabras en s@'{@dotless{i}}. Una
expresi@'on regexp que rechaza para saltar a trav@'es de espacios en
blanco entre palabras @exclamdown{}nunca saltar@'{@dotless{i}}a m@'as
de una palabra!. Esto significa que el regexp incluir@'{@dotless{i}}a
el espacio en blanco y la puntuaci@'on sigue a una palabra
cualquiera, como la palabra en s@'{@dotless{i}}. (Una palabra puede
finalizar un b@'uffer y no tiene cualquier espacio en blanco o
puntuaci@'on, as@'{@dotless{i}} esta parte del regexp debe ser
opcional.)

De este modo, queremos para el regexp es un patr@'on definiendo una o
m@'as palabras de caracteres que constituyen caracteres seguidos,
opcionalmente, por uno o m@'as caracteres que no son palabras
constituyentes. La expresi@'on regular para esto es:

@smallexample
\w+\W*
@end smallexample

@noindent
La tabla de sintaxis del b@'uffer determina qu@'e caracteres son y no
son palabras constituyentes. Para m@'as informaci@'on acerca de
sintaxis, @pxref{Tablas de Sintaxis, , Tablas de Sintaxis, elisp, El
Manual de Referencia de GNU Emacs Lisp}.

@need 800
La expresi@'on se parece a esto:

@smallexample
(re-search-forward "\\w+\\W*")
@end smallexample

@noindent
(Note que las barras invertidas que preceden el @samp{w} y
@samp{W}. Una barra invertida tiene significado especial al
int@'erprete Emacs Lisp. Eso indica que el caracter siguiente es
interpretado de manera diferente que la normal. Por ejemplo, los dos
caracteres, @samp{\n}, son una @samp{nueva l@'{@dotless{i}}nea}, en
vez de una barra invertida seguida por @samp{\n}. Dos barras
invertidas en una fila para una `barra invertida no especial',
as@'{@dotless{i}} Emacs Lisp interpreta el fin de mirar una barra
invertida simple seguida por una letra. As@'{@dotless{i}} descubre la
letra que es especial.)

Se necesita un contador para contar cu@'antas palabras hay; esta
variables debe primero ser asignado a 0 y entonces incrementados cada
vez que Emacs va alrededor del bucle @code{while}. La expresi@'on de
incremento es simple:

@smallexample
(setq count (1+ count))
@end smallexample

Finalmente, se quiere contar al usuario cu@'antas palabras hay en la
regi@'on. La funci@'on @code{message} presenta este tipo de
informaci@'on al usuario. El mensaje tiene que ser fraseado
de manera que se lea apropiadamente sin cuidado de cuantas palabras
hay en la regi@'on: no se quiere decir que ``hay una palabra en la
regi@'on''. El conflicto entre singular y plural no es gramatical. Se
puede resolver este problema usando una expresi@'on condicional que
eval@'ua diferentes mensajes dependiendo en el n@'umero de palabras en
la regi@'on. Hay tres posibilidades: no palabras en la regi@'on, una
palabra en la regi@'on, y m@'as de una palabra. Esto significa que la
forma especial @code{cond} es apropiada.

@need 1500
Todo esto lidera a la siguiente definici@'on de funci@'on:

@smallexample
@group
;;; @r{@exclamdown{}La Primera versi@'on; tiene errores!}
(defun count-words-region (beginning end)
  "Imprime el n@'umero de palabras en la regi@'on.
Las palabras est@'an definidas al menos una palabra
constituida de caracteres seguido por al menos un 
caracter que no constituye palabra. La tabla de 
sintaxis del b@'uffer determina qu@'e caracteres hay."
  (interactive "r")
  (message "Contando palaras en la regi@'on ... ")
@end group

@group
;;; @r{1. Configurar condiciones apropiadas.}
  (save-excursion
    (goto-char beginning)
    (let ((count 0))
@end group

@group
;;; @r{2. Ejecutar el} @r{bucle} while.
      (while (< (point) end)
        (re-search-forward "\\w+\\W*")
        (setq count (1+ count)))
@end group

@group
;;; @r{3. Enviar un mensaje al usuario.}
      (cond ((zerop count)
             (message
              "La regi@'on no tiene palabras."))
            ((= 1 count)
             (message
              "La regi@'on tiene 1 palabra."))
            (t
             (message
              "La regi@'on tiene %d palabras." count))))))
@end group
@end smallexample

@noindent
Como se escribe, la funci@'on funciona, pero no en todas las circunstancias.

@node Error de espacio en blanco
@subsection El error de espacio en blanco en @code{@value{COUNT-WORDS}}

El comando @code{@value{COUNT-WORDS}} descrito en la secci@'on
precedente tiene dos errores, o incluso, un error con dos
manifestaciones. Primero, si se marca una regi@'on conteniendo solo
espacio en blanco en el medio de alg@'un texto el comando
@exclamdown{}@code{@value{COUNT-WORDS}} cuenta que la regi@'on
contiene una palabra!. Segundo, si se marca una regi@'on conteniendo
solo espacios en blanco al final del b@'uffer o la porci@'on accesible
de un b@'uffer encogido, el comando muestra un mensaje de error que se
parece a esto:

@smallexample
B@'usqueda fallida: "\\w+\\W*"
@end smallexample

Si est@'a leyendo esto en Info en GNU Emacs, se puede testear para
estos errores por s@'{@dotless{i}} mismo.

Primero, eval@'ua la funci@'on de la manera usual para instalarlo.
@ifinfo
Aqu@'{@dotless{i}} hay una copia de la definici@'on. Emplaza tu cursor
despu@'es de cerrar los par@'entesis y escribir @kbd{C-x C-e} para
instalarlo.

@smallexample
@group
;; @r{@exclamdown{}La Primera versi@'on; tiene errores!}  (defun
@value{COUNT-WORDS} (beginning end) 
"Imprime el n@'umero de palabras en la regi@'on.  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@'uffer determina qu@'e caracteres hay."

@end group
@group
  (interactive "r")
  (message "Contando palabras en la regi@'on ... ")
@end group

@group
;;; @r{1. Configurar condiciones apropiadas.}
  (save-excursion
    (goto-char beginning)
    (let ((count 0))
@end group

@group
;;; @r{2. Ejecutar el} @r{bucle} while.
      (while (< (point) end)
        (re-search-forward "\\w+\\W*")
        (setq count (1+ count)))
@end group

@group
;;; @r{3. Env@'{@dotless{i}}a un mensaje al usuario.}
      (cond ((zerop count)
             (message "La regi@'on no tiene palabras."))
            ((= 1 count) (message "The regi@'on tiene 1 palabra."))
            (t (message "La regi@'on tiene %d palabras." count))))))
@end group
@end smallexample
@end ifinfo

@need 1000
Si se desea, se puede tambi@'en instalar este atajo para ser evaluado:

@smallexample
(global-set-key "\C-c=" '@value{COUNT-WORDS})
@end smallexample

Para conducir el primer test, asigna marca y punto al principio y fin
de la siguiente l@'{@dotless{i}}nea y entonces escribe @kbd{C-c =} (o
@kbd{M-x @value{COUNT-WORDS}} si no se ha asignado @kbd{C-c =}):

@smallexample
    uno   dos  tres
@end smallexample

@noindent
Emacs te contar@'a, correctamente, que la regi@'on tiene tres palabras.

Repite el test, pero marca el lugar al principio de la
l@'{@dotless{i}}nea y emplaza el punto justo @emph{antes} de la
palabra @samp{uno}. De nuevo escribe el comando @kbd{C-c =} (o
@kbd{M-x @value{COUNT-WORDS}}). Emacs cuenta que la regi@'on no tiene
palabras, puesto que eso est@'a compuesto solo por espacios en blanco
al principio de la l@'{@dotless{i}}nea. @exclamdown{}Pero en vez de
que Emacs cuente que la regi@'on tiene una palabra!

Para el tercer test, copia la l@'{@dotless{i}}nea de ejemplo al fin
del b@'uffer @file{*scratch*} y entonces escribe varios espacios al fin
de la l@'{@dotless{i}}nea. Posiciona la marca correcta despu@'es de la
palabra @samp{tres} y apunta al fin de la l@'{@dotless{i}}nea. (El fin
de la l@'{@dotless{i}}nea ser@'a el fin del b@'uffer.) Escribe @kbd{C-c
=} (o @kbd{M-x @value{COUNT-WORDS}}) como se hizo antes. De nuevo,
Emacs te contar@'{@dotless{i}}a que la regi@'on no tiene palabras,
puesto que eso est@'a compuesto solo de los espacios en blanco al fin
de la l@'{@dotless{i}}nea. En vez de eso, Emacs muestra un mensaje de
error diciendo @samp{B@'usqueda fallida}.

Los dos errores queman el mismo problema.

Considere la primera manifestaci@'on del error, en el que el comando
te cuenta que el espacio en blanco al principio de la
l@'{@dotless{i}}nea contiene una palabra. Lo que ocurre es esto: El
comando @code{M-x @value{COUNT-WORDS}} mueve el punto al principio de
la regi@'on. El test @code{while} si el valor del punto es m@'as
peque@~no de lo que el valor de @code{end}, que es. Por consiguiente,
en la expresi@'on regular se busca y encuentra la primera palabra. Eso
deja el punto despu@'es de la palabra. @code{count} que se establece a
uno. El bucle @code{while} repite; pero esta vez el valor del punto es
m@'as largo que el valor de @code{end}, el bucle sale; y la funci@'on
muestra un mensaje diciendo el n@'umero de palabras en la regi@'on es
uno. En breve, la expresi@'on regular busca y encuentra la palabra
incluso aunque eso est@'e fuera de la regi@'on marcada.

En la segunda manifestaci@'on del error, la regi@'on es un espacio en
blanco al fin del b@'uffer. Emacs dice @samp{B@'usqueda fallida}. Lo
que ocurre es que true-or-false-test en el bucle @code{while} chequea
verdad, as@'{@dotless{i}} la expresi@'on de b@'usqueda es
ejecutada. Pero desde que no hay m@'as palabras en el buffer, la
b@'usqueda falla.

En ambas manifestaciones del error, la b@'usqueda extiende o intenta
extenderse fuera de la regi@'on.

La soluci@'on es limitar la b@'usqueda a la regi@'on --- esto es una
acci@'on simple y limpia, pero como tu puedes tener que llegar a
esperar, eso no es tan simple como se podr@'{@dotless{i}}a pensar.

Como se ha visto, la funci@'on @code{re-search-forward} toma un
patr@'on de b@'usqueda como su primer argumento. Pero adem@'as de este
primer, argumento obligatorio, se aceptan tres argumentos
opcionales. El segundo argumento opcional asocia la b@'usqueda. El
tercer argumento opcional, si @code{t}, causa la funci@'on a devolver
@code{nil} en vez de la se@~nal un error si la b@'usqueda falla. El
cuarto argumento opcional es un contador repetido. (En Emacs, se puede
ver una documentaci@'on de la funci@'on escribiendo @kbd{C-h f}, el
nombre de la funci@'on, y entonces @key{RET}.)

En la definici@'on @code{@value{COUNT-WORDS}}, el valor del fin de la
regi@'on es tomada por la variable @code{end} que es pasada como un
argumento para la funci@'on. De este modo, se puede a@~nadir
@code{end} como un argumento para la b@'usqueda de la expresi@'on de
b@'usqueda:

@smallexample
(re-search-forward "\\w+\\W*" fin)
@end smallexample

Sin embargo, si se crea solo este cambio a la definici@'on
@code{@value{COUNT-WORDS}} y entonces se chequea la nueva versi@'on de
la definici@'on en una extensi@'on de espacio en blanco, se recibir@'a
un mensaje de error diciendo @samp{B@'usqueda fallida}.

Lo que ocurre es esto: la b@'usqueda se limita a la regi@'on, y
falla como se espera porque no hay caracteres de palabras
constituyentes en la regi@'on. 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@'on no tiene palabras".

La soluci@'on a este problema es proveer @code{re-search-forward} con
un tercer argumento de @code{t}, que causa la funci@'on para devolver
@code{nil} en vez la se@~nalar un error si la b@'usqueda falla.

Sin embargo, si se crea este cambio y se intenta, se ver@'a el mensaje
``Contando palabras en la regi@'on ...'' y @dots{} se guardar@'a
viendo qu@'e mensaje @dots{}, hasta que se escribe @kbd{C-g}
(@code{keyboard-quit}).

Aqu@'{@dotless{i}} est@'a lo que ocurre: la b@'usqueda est@'a limitada
a la regi@'on, como antes, y eso falla porque no hay caracteres no
constituyentes de palabras en la regi@'on, como se
espera. Por tanto, la expresi@'on @code{re-search-forward}
devuelve @code{nil}. Eso no hace nada m@'as. En particular, no mueve
el punto, que hace como un efecto lateral si se encuentra la
b@'usqueda objetiva. Despu@'es la expresi@'on @code{re-search-forward}
devuelve @code{nil}, la siguiente expresi@'on en el bucle @code{while}
est@'a evaluado. Esta expresi@'on incrementa el contador. Entonces el
bucle repite. El test true-or-false-test chequea cierto porque el
valor del punto es todav@'{@dotless{i}}a menor que el valor final,
desde que la expresi@'on @code{re-search-forward} no
mover@'{@dotless{i}}a el punto. @dots{} y el ciclo repite @dots{}

La definici@'on @code{@value{COUNT-WORDS}} requiere
todav@'{@dotless{i}}a de otra modificaci@'on para causar el
true-or-false-test del bucle @code{while} para chequear falso si la
b@'usqueda 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@'{@dotless{i}}a estar con la
regi@'on y la expresi@'n de b@'usqueda debe haber encontrado una
palabra para contar.

Por ambas la primera condici@'on y la segunda condici@'on deben ser
ciertas juntas, las dos expresiones, la regi@'on chequea y la
expresi@'on de b@'usqueda, puede estar unido con una forma especial
@code{and} y embebido en el bucle @code{while} como el
true-or-false-test, como esto:

@smallexample
(and (< (point) end) (re-search-forward "\\w+\\W*" end t))
@end smallexample

@c colon in printed section title causes problem in Info cross reference
@c also trouble with an overfull hbox
@iftex
@noindent
(Para informaci@'on acerca de @code{and}, ver @ref{Funci@'on kill-new,
, La funci@'on @code{kill-new}}.)
@end iftex
@ifinfo
@noindent
(@xref{Funci@'on kill-new, , La funci@'on @code{kill-new}}, para
informaci@'on acerca de @code{and}.)
@end ifinfo

La expresi@'on @code{re-search-forward} devuelve @code{t} si la
b@'usqueda es exitosa y como efecto lateral se mueve el
punto. Consiguientemente, como las palabras se encuentran, el punto es
movido a trav@'es de la regi@'on. Cuando la b@'usqueda de la expresi@'on
falla para encontrar otra palabra, o cuando el punto logra el fin de
la regi@'on, el test true-or-false-test es falso, el bucle @code{while}
existe, y la funci@'on @code{@value{COUNT-WORDS}} muestra uno u otro de
sus mensajes.

Despu@'es de incorporar estos cambios finales, el
@code{@value{COUNT-WORDS}} funciona sin errores (@exclamdown{}o al
menos, sin los errores que yo haya encontrado!. Aqu@'{@dotless{i}} est@'a
lo que parece:

@smallexample
@group
;;; @r{Versi@'on final:} @code{while}
(defun @value{COUNT-WORDS} (beginning end)
  "Imprime n@'umero de palabras en la regi@'on."
  (interactive "r")
  (message "Contando palabras en la regi@'on ... ")
@end group

@group
;;; @r{1. Configura condiciones apropiadas.}
  (save-excursion
    (let ((count 0))
      (goto-char beginning)
@end group

@group
;;; @r{2. Ejecuta el} @r{bucle} while
      (while (and (< (point) end)
                  (re-search-forward "\\w+\\W*" end t))
        (setq count (1+ count)))
@end group

@group
;;; @r{3. Enviar un mensaje al usuario.}
      (cond ((zerop count)
             (message
              "La regi@'on no tiene palabras."))
            ((= 1 count)
             (message
              "La regi@'on tiene 1 palabra."))
            (t
             (message
              "La regi@'on tiene %d palabras." count))))))
@end group
@end smallexample

@node recursive-count-words
@section Cuenta palabras recursivamente
@cindex Cuenta palabras recursivamente
@cindex Recursivamente contando palabras
@cindex Palabras, contadas recursivamente

Se puede escribir la funci@'on para contar palabras tanto de manera
recursiva como con un bucle @code{while}. Permita ver c@'omo se
hace.

Primero, se necesita reconocer que la funci@'on
@code{@value{COUNT-WORDS}} tiene tres trabajos: eso configura las
condiciones apropiadas para contar lo que ocurre; eso cuenta las
palabras en la regi@'on; y env@'{@dotless{i}}a un mensaje al usuario
contando cu@'antas palabras hay.

Si se escribe una funci@'on recursiva simple para hacer cualquier cosa
se recibir@'a un mensaje para cada llamada recursiva. Si la regi@'on
contiene 13 palabras, se recibir@'an trece mensajes, uno correcto
despu@'es del otro. @exclamdown{}No queremos esto!. En vez de eso,
se deben escribir dos funciones para hacer el trabajo, una (la
funci@'on recursiva) ser@'a usada dentro de la otra. Una funci@'on
configurar@'a las condiciones y muestra el mensaje; la otra
devolver@'a el contador de palabras.

Perm@'{@dotless{i}}tase comenzar con la funci@'on que causa el mensaje
que se muestra. Se puede continuar por llamarse @code{@value{COUNT-WORDS}}.

Esta es la funci@'on que el usuario llama. Ser@'a interactiva. En
realidad, ser@'a similar a nuestras versiones previas de esta
funci@'on, excepto que llamar@'a @code{recursive-count-words} para
determinar cu@'antas palabras hay en la regi@'on.

@need 1250
Se puede construir una plantilla legible para esta funci@'on, basada
en versiones previas:

@smallexample
@group
;; @r{Versi@'on Recursiva; usa la b@'usqueda de la expresi@'on regular}
(defun @value{COUNT-WORDS} (beginning end)
  "@var{documentation}@dots{}"
  (@var{interactive-expression}@dots{})
@end group
@group

;;; @r{1. Configura condiciones apropiadas.}
  (@var{explanatory message})
  (@var{set-up functions}@dots{}
@end group
@group

;;; @r{2. Contar las palabras.}
    @var{recursive call}
@end group
@group

;;; @r{3. Env@'{@dotless{i}}a un mensaje al usuario.}
    @var{message providing word count}))
@end group
@end smallexample

La definici@'on parece sencilla, excepto que como el contador devuelve
la llamada recursiva que debe ser pasada al mensaje mostrando el
contaje de palabras. Un peque@~no pensamiento sugiere que esto puede
ser hecho haciendo uso de una expresi@'on @code{let} al n@'umero de
palabras en la regi@'on, como se devuelve por la llamada recursiva; y
entonces la expresi@'on @code{cond}, que usa la asociaci@'on, puede
mostrar el valor al usuario.

Con frecuencia, uno piensa que se puede asociar una expresi@'on
@code{let} como algo secundario al trabajo `primario' de una
funci@'on. Pero en este caso, se podr@'{@dotless{i}}a considerar el
trabajo `primario' de la funci@'on, contando palabras, esto es hecho
con la expresi@'on @code{let}.

@need 1250
Usando @code{let}, la definici@'on de funci@'on se parece a:

@smallexample
@group
(defun @value{COUNT-WORDS} (beginning end)
  "Imprime el n@'umero de palabras en la regi@'on."
  (interactive "r")
@end group

@group
;;; @r{1. Configura condiciones apropiadas.}
  (message "Contando palabras en la regi@'on ... ")
  (save-excursion
    (goto-char beginning)
@end group

@group
;;; @r{2. Contar las palabras.}
    (let ((count (recursive-count-words end)))
@end group

@group
;;; @r{3. Enviar un mensaje al usuario.}
      (cond ((zerop count)
             (message
              "La regi@'on no tiene palabras."))
            ((= 1 count)
             (message
              "La regi@'on tiene 1 palabra."))
            (t
             (message
              "La regi@'on tiene %d palabras." count))))))
@end group
@end smallexample

Lo siguiente, que se necesita es escribir la funci@'on de contaje
recursivo.

Una funci@'on 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@'on ser@'a o no llamada de
nuevo. Puesto que estamos contando palabras en una regi@'on y puede
causar que una funci@'on se mueva el punto hacia delante por cada
palabra, el do-again-test puede chequear si el punto est@'a
todav@'{@dotless{i}}a con la regi@'on. El do-again-test
encontrar@'{@dotless{i}}a el valor del punto y determina si el punto
est@'a antes, en, o despu@'es del valor del fin de la regi@'on. Se
puede usar la funci@'on @code{point} para localizar el
punto. Claramente, se debe pasar el valor del fin de la regi@'on a la
funci@'on de contaje recursivo como un argumento.

Adem@'as, el do-again-test tambi@'en chequea si la b@'usqueda
encuentra una palabra. Si no, la funci@'on no se
llamar@'{@dotless{i}}a de nuevo.

La next-step-expression cambia un valor as@'{@dotless{i}} que cuando
la funci@'on recursiva se supone que debe parar de llamarse
as@'{@dotless{i}} misma, se para. M@'as precisamente, los cambios de
next-step-expression cambia un valor as@'{@dotless{i}} en el momento
adecuado, el do-again-test para la funci@'on recursiva de la llamada
en s@'{@dotless{i}} de nuevo. En este caso, la next-step-expression
puede ser la expresi@'on que mueve el punto hacia adelante, palabra
por palabra.

La tercera parte de una funci@'on recursiva es la llamada recursiva.

En alg@'un lugar, tambi@'en, se necesita una parte que hace el
`trabajo' de la funci@'on, una parte que es el
contaje. @exclamdown{}Una parte vital!

@need 1250
Pero ya, tenemos un gui@'on de la funci@'on recursiva de contaje:

@smallexample
@group
(defun recursive-count-words (region-end)
  "@var{documentation}@dots{}"
   @var{do-again-test}
   @var{next-step-expression}
   @var{recursive call})
@end group
@end smallexample

Ahora se necesita rellenar los slots. Permite comenzar con el caso
m@'as simple primero: si se apunta debajo del fin de la regi@'on, no
puede haber palabras en la regi@'on, as@'{@dotless{i}} la funci@'on
devuelve cero. De otro modo, si la b@'usqueda falla no hay palabras
para contar, as@'{@dotless{i}} la funci@'on devolver@'{@dotless{i}}a cero.

Por otro lado, si se apunta con la regi@'on y la b@'usqueda tiene
@'exito, la funci@'on se llamar@'{@dotless{i}}a de nuevo.

@need 800
De este modo, do-again-test se ver@'{@dotless{i}}a as@'{@dotless{i}}:

@smallexample
@group
(and (< (point) region-end)
     (re-search-forward "\\w+\\W*" region-end t))
@end group
@end smallexample

Note que la expresi@'on de b@'usqueda es parte del do-again-test ---
la funci@'on devuelve @code{t} si su b@'usqueda tiene @'exito y
@code{nil} si falla. (@xref{Error de espacio en blanco, , El Error de
Espacio en Blanco en @code{@value{COUNT-WORDS}}}), para una
explicaci@'on de c@'omo @code{re-search-forward} funciona.)

El do-again-test es el test true-or-false de una cl@'ausula
@code{if}. Claramente si el do-again-test tiene @'exito, la then-part
de la cl@'ausula @code{if} llamar@'{@dotless{i}}a a la funci@'on; pero
si eso falla, la else-part devolver@'{@dotless{i}}a cero desde que el
punto est@'a fuera de la regi@'on o la b@'usqueda fall@'o porque no
hab@'{@dotless{i}}a palabras a encontrar.

Pero antes de considerar la llamada recursiva, se necesita considerar
la next-step-expression. @questiondown{}Qu@'e es eso? De manera
interesante, eso es la parte de la b@'usqueda del do-again-test.

Adem@'as para devolver @code{t} o @code{nil} para el do-again-test,
@code{re-search-forward} mueve el punto hacia adelante como un efecto
lateral de una b@'usqueda exitosa. Esta es la acci@'on que cambia el
valor de punto as@'{@dotless{i}} que la funci@'on recursiva para de
llamarse a s@'{@dotless{i}} misma cuando el punto complete su
movimiento a trav@'es de la regi@'on. Por consiguiente, la expresi@'on
@code{re-search-forward} es la next-step-expression.

@need 1200
En esquema, entonces, el cuerpo de la funci@'on
@code{recursive-count-words} se parece a esto:

@smallexample
@group
(if @var{do-again-test-and-next-step-combined}
    ;; @r{then}
    @var{recursive-call-returning-count}
  ;; @r{else}
  @var{return-zero})
@end group
@end smallexample

@questiondown{}C@'omo incorporar el mecanismo que cuenta?

Si no est@'as acostumbrado a escribir funciones recursivas, una pregunta
como esta puede ser un problema. Pero eso puede y ser@'{@dotless{i}}a
enfocado sistem@'aticamente.

Se sabe que el mecanismo de contaje ser@'{@dotless{i}}a asociado en
alg@'un 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@'on que a@~nade uno al valor
devuelto por una llamada para @code{recursive-count-words}

@need 800
Considera varias casos:

@itemize @bullet
@item
Si hay dos palabras en la regi@'on, la funci@'on devolver@'a un valor
resultante de a@~nadir uno al valor devuelto al contar la primera
palabra, m@'as el n@'umero devuelto al contar las palabras que
permanecen en la regi@'on, que en este caso es una.

@item
Si hay una palabra en la regi@'on, la funci@'on
devolver@'{@dotless{i}}a un valor resultante de a@~nadir uno al valor
devuelto cuando eso cuenta esta palabra m@'as el n@'umero devuelto
cuando eso cuenta las palabras que permanecen en la regi@'on, que en
este caso es cero.

@item
Si no hay palabras en la regi@'on, la funci@'on
devolver@'{@dotless{i}}a cero.
@end itemize

Desde el esquema se puede ver que la parte else del @code{if} devuelve
cero para el caso en el que no hay palabras. Esto significa que la
parte then del @code{if} debe devolver un valor resultante de a@~nadir
uno al valor devuelto desde el contaje de las palabras que permanecen.

@need 1200
La expresi@'on se parece a esto, donde @code{1+} es una funci@'on que
a@~nade uno a su argumento.

@smallexample
(1+ (recursive-count-words region-end))
@end smallexample

@need 1200
La funci@'on completa @code{recursive-count-words} entonces se
parecer@'a e esto:

@smallexample
@group
(defun recursive-count-words (region-end)
  "@var{documentation}@dots{}"

;;; @r{1. do-again-test}
  (if (and (< (point) region-end)
           (re-search-forward "\\w+\\W*" region-end t))
@end group

@group
;;; @r{2. then-part: la llamada recursiva}
      (1+ (recursive-count-words region-end))

;;; @r{3. else-part}
    0))
@end group
@end smallexample

@need 1250
Perm@'{@dotless{i}}teme examinar c@'omo esto funciona:

Si no hay palabras en la regi@'on, la parte else de la expresi@'on
@code{if} es evaluada y, por tanto, la funci@'on devuelve cero.

Si hay una palabra en la regi@'on, el valor del punto es menor que el
valor de @code{region-end} y la b@'usqueda tiene @'exito. En este
caso, el true-or-false-test de la expresi@'on @code{if} chequea
cierto, y la then-part de la expresi@'on @code{if} es evaluada. La
expresi@'on de contaje se eval@'ua. Esta expresi@'on devuelve un valor
(que ser@'a el valor devuelto por la funci@'on completa) que es la
suma de uno a@~nadida al valor devuelto por una llamada recursiva.

Mientras tanto, la next-step-expression ha causado el punto para
saltar a trav@'es de la primera (y en este caso @'unica) palabra en la
regi@'on. Esto significa que cuando @code{(recursive-count-words
region-end)} est@'a evaluada una segunda vez, como un resultado de la
llamada recursiva, el valor del punto ser@'a igual o mayor que el
valor de la regi@'on final. As@'{@dotless{i}} esta vez,
@code{recursive-count-words} devolver@'a cero. El cero ser@'a
a@~nadido a uno, y la evaluaci@'on original de
@code{recursive-count-words} devolver@'a uno m@'as cero (uno) que es
la cantidad correcta.

Claramente, si hay dos palabras en la regi@'on, la primera llamada a
@code{recursive-count-words} devuelve uno que se a@~nade al valor
devuelto por el siguiente @code{recursive-count-words} en una regi@'on
donde est@'a la palabra que permanece --- que es, eso a@~nadir uno a
uno, produciendo dos, que es la cantidad correcta.

Similarmente, si hay tres palabras en la regi@'on, la primera llamada
@code{recursive-count-words} devuelve uno a@~nadido al valor devuelto
llamado @code{recursive-count-words} en una regi@'on conteniendo las
dos palabras que faltan --- y as@'{@dotless{i}}.

@need 1250
@noindent
Con documentaci@'on completa las dos funciones se parecen a esto:

@need 1250
@noindent
La funci@'on recursiva:

@findex recursive-count-words
@smallexample
@group
(defun recursive-count-words (region-end)
  "N@'umero de palabras entre punto y REGION-END."
@end group

@group
;;; @r{1. do-again-test}
  (if (and (< (point) region-end)
           (re-search-forward "\\w+\\W*" region-end t))
@end group

@group
;;; @r{2. then-part: la llamada recursiva}
      (1+ (recursive-count-words region-end))

;;; @r{3. else-part}
    0))
@end group
@end smallexample

@need 800
@noindent
El envoltorio:

@smallexample
@group
;;; @r{Versi@'on Recursiva}
(defun @value{COUNT-WORDS} (beginning end)
  "Imprime el n@'umero de palabras en la regi@'on.
@end group

@group
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@'e caracter hay.
@end group
@group
  (interactive "r")
  (message "Contando palabras en la regi@'on ... ")
  (save-excursion
    (goto-char beginning)
    (let ((count (recursive-count-words end)))
@end group
@group
      (cond ((zerop count)
             (message
              "La regi@'on no tiene palabras."))
@end group
@group
            ((= 1 count)
             (message "La regi@'on tiene 1 palabra."))
            (t
             (message
              "La regi@'on tiene %d palabras." count))))))
@end group
@end smallexample

@node Ejercicio de Contar
@section Ejercicio: contando puntuaci@'on

Usando un bucle @code{while}, escriba una funci@'on para contar el
n@'umero de marcas de puntuaci@'on en una regi@'on --- periodo, coma,
punto y coma, dos puntos, exclamaci@'on, marca y marca de
pregunta. Haga lo mismo usando recursi@'on.

@node Palabras en una funci@'on
@chapter Contando palabras en una @code{defun}
@cindex Contando palabras en un @code{defun}
@cindex Contando las palabras en un @code{defun}

El siguiente proyecto es contar el n@'umero de palabras en una
definici@'on de funci@'on. Claramente, esto se puede hacer usando
alguna variante de @code{@value{COUNT-WORDS}}. @xref{Contando
palabras, , Contando palabras: repetici@'on y regexps}. Si se est@'a
ahora yendo a contar las palabras en una definici@'on, es
suficientemente f@'acil marcar la definici@'on con el comando
@kbd{C-M-h} (@code{mark-defun}), y entonces se llama a
@code{@value{COUNT-WORDS}}.

Sin embargo, soy m@'as ambicioso: Yo quiero contar las palabras y
s@'{@dotless{i}}mbolos en cada definici@'on en las fuentes de Emacs y
entonces imprimir un grafo que muestre cu@'antas funciones hay de cada
tama@~no: cu@'antas contienen de 40 a 49 palabras o
s@'{@dotless{i}}mbolos, cu@'antas contienen de 50 a 59 palabras o
s@'{@dotless{i}}mbolos, y as@'{@dotless{i}}. Yo he sido con frecuencia
curioso de c@'omo es una funci@'on t@'{@dotless{i}}pica, y esto se
contar@'a.

@menu
* Divide y vencer@'as::      Divide y vencer@'as
* Palabras y S@'{@dotless{i}}mbolos::  @questiondown{}Qu@'e contar?
* Sintaxis::                 @questiondown{}Qu@'e constituye una palabra o 
                               s@'{@dotless{i}}mbolo?
* count-words-in-defun::     Similar a @code{@value{COUNT-WORDS}}.
* Varias funciones::         Contando varias funciones en un fichero.
* Encontrar un fichero::     @questiondown{}Quieres buscar en un fichero?
* lengths-list-file::        Una lista de los tama@~nos 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.
@end menu

@ifnottex
@node Divide y vencer@'as
@unnumberedsec Divide y vencer@'as
@end ifnottex

Descrito en una frase, el proyecto desanima; pero dividido dentro de
numerosos peque@~nos pasos, cada uno de los que podemos tomar en un
momento, el proyecto llegar ser menos
atemorizante. Perm@'{@dotless{i}}tenos considerar qu@'e pasos deben
ser:

@itemize @bullet
@item
Primero, escribe una funci@'on para contar las palabras en una
definici@'on. Esto incluye el problema de manejar
s@'{@dotless{i}}mbolos tan bien como palabras.

@item
Segundo, escribe una funci@'on para listar los n@'umeros de palabras
en cada funci@'on en un fichero. Esta funci@'on puede usar la
funci@'on @code{count-words-in-defun}.

@item
Tercero, escribe una funci@'on para listar los n@'umeros de palabras
en cada funci@'on en cada uno de varios ficheros. Esto encola
autom@'aticamente encontrando varios ficheros, cambi@'andolos, y
contando las palabras en las definiciones con ellos.

@item
Cuarto, escribe una funci@'on para convertir la lista de n@'umeros que
nosotros creamos en tres pasos para un formulario que se ajustar@'a
para imprimir un grafo.

@item
Quinto, escribe una funci@'on para imprimir los resultados como un grafo.
@end itemize

@exclamdown{}Esto es un proyecto! Pero si tomamos cada paso
lentamente, eso no ser@'a dif@'{@dotless{i}}cil.

@node Palabras y S@'{@dotless{i}}mbolos
@section @questiondown{}Qu@'e contar?
@cindex Palabras y s@'{@dotless{i}}mbolos en defun

Cuando nosotros primero empezamos pensando acerca del contaje de
palabras en una definici@'on de funci@'on, la primera pregunta es (o
podr@'{@dotless{i}}a ser) @questiondown{}qu@'e se va a contar?  Cuando
se habla de `palabras' con repecto a una definici@'on de funci@'on
Lisp, estamos actualmente hablando, en parte, de
`s@'{@dotless{i}}mbolos'. Por ejemplo, la siguiente funci@'on
@code{multiply-by-seven} contiene los cinco s@'{@dotless{i}}mbolos
@code{defun}, @code{multipy-by-seven}, @code{number}, @code{*}, y
@code{7}. Adem@'as, en la cadena de documentaci@'on, contiene cuatro
palabras @samp{Multiplicar}, @samp{NUMBER}, @samp{por}, y
@samp{siete}. El s@'{@dotless{i}}mbolo @samp{n@'umero} es repetido,
as@'{@dotless{i}} la definici@'on contiene un total de diez palabras y
s@'{@dotless{i}}mbolos.

@smallexample
@group
(defun multiplicar-por-siete (numero)
  "Multiplica NUMERO por siete."
  (* 7 numero))
@end group
@end smallexample

@noindent
Sin embargo, si se marca la definici@'on @code{multiply-by-seven} con
@kbd{C-M-h} (@code{mark-defun}), y entonces se llama a
@code{@value{COUNT-WORDS}} dentro, se encontrar@'a que
@code{@value{COUNT-WORDS}} @exclamdown{}reclama la definici@'on tiene
once palabras, no diez! @exclamdown{}Alguna cosa est@'a mal!

El problema es doble: @code{@value{COUNT-WORDS}} no cuenta el @samp{*}
como una palabra, y eso cuenta el s@'{@dotless{i}}mbolo simple,
@code{multiply-by-seven}, conteniendo tres palabras. Las conexiones
son tratadas como si fueran espacios entre palabras en vez de
conectores entre palabras @samp{multiply-by-seven} se cuenta como si
fuese escrito @samp{multiply-by-seven}.

La causa de esta confusi@'on es la expresi@'on regular que busca la
definici@'on @code{@value{COUNT-WORDS}} que mueve el punto hacia
delante palabra por palabra. En la versi@'on can@'onica de
@code{@value{COUNT-WORDS}}, el regexp es:

@smallexample
"\\w+\\W*"
@end smallexample

@noindent
Esta expresi@'on regular es un patr@'on definiendo una o m@'as
palabras constituyendo caracteres posiblemente seguidos por uno o
m@'as caracteres que no son palabras constituyentes. Esto significa
que los `caracteres que constituyen palabras' nos traen la cuesti@'on
de la sintaxis, que es el valor de una secci@'on en s@'{@dotless{i}}.

@node Sintaxis
@section @questiondown{}Qu@'e constituye una palabra o s@'{@dotless{i}}mbolo?
@cindex Categor@'{@dotless{i}}as de sintaxis y tablas

Emacs trata diferentes caracteres perteneciendo a diferentes
@dfn{categor@'{@dotless{i}}as de sintaxis}. Por ejemplo, la
expresi@'on regular, @samp{\\w+}, es un patr@'on especificando uno o
m@'as caracteres de @emph{palabras constituyentes}. Los caracteres de
palabras constituyentes son miembros de una categor@'{@dotless{i}}a de
sintaxis. Otras categor@'{@dotless{i}}a de sintaxis incluye la clase
de caracteres de puntuaci@'on, tales como el espacio en blanco o el
caracter de tabulaci@'on. (Para m@'as informaci@'on, ver
@ref{Sintaxis, Sintaxis, La Tabla de Sintaxis, emacs, El Manual GNU
Emacs}, y @ref{Tablas de Sintaxis, , Tablas de Sintaxis, elisp, El
Manual de Referencia GNU Emacs Lisp}.)

Las tablas de sintaxis especifican qu@'e caracteres pertenecen a qu@'e
categor@'{@dotless{i}}as. Normalmente un gui@'on no est@'a
especificado como un `caracter constituido por una palabra'. En vez de
eso, se especific@'o como estando en la `clase de caracteres que son
parte de los nombres de s@'{@dotless{i}}mbolos, pero no las palabras.'
Esto significa que la funci@'on @code{@value{COUNT-WORDS}} se trata del
mismo modo que trata un espacio en blanco entre palabras, que es el
por qu@'e @code{@value{COUNT-WORDS}} cuenta @samp{multiply-by-seven}
como tres palabras.

Hay dos caminos para causar que Emacs cuente @samp{multiply-by-seven}
como un s@'{@dotless{i}}mbolo: modificar la tabla de sintaxis o
modificar la expresi@'on regular.

Se podr@'{@dotless{i}}a redefinir un gui@'on (@emph{hyphen}) como un
caracter que constituye una palabra modificando la tabla de sintaxis
que Emacs guarda por cada modo. Esta acci@'on servir@'{@dotless{i}}a
nuestro prop@'osito, excepto que una conexi@'on es meramente el
caracter m@'as com@'un con s@'{@dotless{i}}mbolos que no son
t@'{@dotless{i}}picamente un caracter de palabra constituyente; hay
otros, tambi@'en.

Alternativamente, se puede redefinir la expresi@'on regular
@emph{regexp} usada en la definici@'on @code{count-words}
as@'{@dotless{i}} como incluir s@'{@dotless{i}}mbolos. Este
procedimiento tiene el m@'erito de la claridad, pero la tarea es un
peque@~no truco.

@need 1200
La primera parte es suficientemente simple: el patr@'on debe asignarse
``al menos un car@'acter que es una palabra o s@'{@dotless{i}}mbolo
constituyente''. De este modo:

@smallexample
"\\(\\w\\|\\s_\\)+"
@end smallexample

@noindent
El @samp{\\(} es la primera parte del constructo que agrupa esto que
incluye el @samp{\\w} y el @samp{\\s_} como alternativas, separadas
por los @samp{\\|}.  El @samp{\\w} asocia cualquier caracter de
palabra constituyente y el @samp{\\s_} asocia cualquier caracter que
es parte de un nombre de s@'{@dotless{i}}mbolo pero no una palabra de
caracteres constituyente. El @samp{+} sigue al grupo que indica que la
palabra o s@'{@dotless{i}}mbolo constituyan caracteres que deben ser
asociados al menos por uno.

Sin embargo, la segunda parte de regexp es m@'as dif@'{@dotless{i}}cil
de dise@~nar. Lo que queremos es seguir la primera parte con
``opcionalmente uno o m@'as caracteres que no constituyen una palabra
o s@'{@dotless{i}}mbolo''. Primero, se pensaba que se
podr@'{@dotless{i}}a definir esto con lo siguiente:

@smallexample
"\\(\\W\\|\\S_\\)*"
@end smallexample

@noindent
Las may@'usculas @samp{W} y @samp{S} asocian caracteres que @emph{no}
son constituyente de palabra o
s@'{@dotless{i}}mbolo. Desafortunadamente, esta expresi@'on asocia
cualquier caracter que sea o no una palabra constituyente no un
s@'{@dotless{i}}mbolo constituyente. @exclamdown{}Esto asocia
cualquier caracter!

Entonces se notific@'o que cada palabra o s@'{@dotless{i}}mbolo en mi
regi@'on test fu@'e seguida por alg@'un espacio (espacio en blanco,
tabulador, o nueva l@'{@dotless{i}}nea). As@'{@dotless{i}} yo
intent@'e emplazar un patr@'on para asociar uno o m@'as espacios en
blanco despu@'es del patr@'on para una o m@'as palabras o
s@'{@dotless{i}}mbolos constituyentes. Esto fall@'o,
tambi@'en. Palabras y s@'{@dotless{i}}mbolos son con frecuencia
separados por espacios en blanco, pero en el c@'odigo actual los
par@'entesis pueden seguir s@'{@dotless{i}}mbolos y puntuaci@'on puede
seguir las palabras. As@'{@dotless{i}} finalmente, se dise@~no un
patr@'on en el que la palabra o s@'{@dotless{i}}mbolo constituyente
es seguido opcionalmente por caracteres que no son espacios en blanco
y entonces son seguidos opcionalmente por espacios en blanco.

@need 800
Aqu@'{@dotless{i}} est@'a la expresi@'on regular completa:

@smallexample
"\\(\\w\\|\\s_\\)+[^ \t\n]*[ \t\n]*"
@end smallexample

@node count-words-in-defun
@section La funci@'on @code{count-words-in-defun}
@cindex Contando palabras en un @code{defun}

Se ha visto que hay varios caminos para escribir una funci@'on
@code{count-word-region}. Para escribir un
@code{count-words-in-defun}, se necesita solamente adaptar una de
estas versiones.

La versi@'on que usa un bucle @code{while} es f@'acil de comprender,
as@'{@dotless{i}} estoy yendo a adaptar esto. Porque
@code{count-words-in-defun} ser@'a parte de un programa m@'as
complejo, eso no necesita ser interactivo y no necesita mostrar un
mensaje pero solo devuelve el contaje. Estas consideraciones
simplifican la definici@'on un poco.

Por otro lado, @code{count-words-in-defun} ser@'a usado con un buffer
que contiene definiciones de funci@'on. Consiguientemente, es
razonable preguntar que la funci@'on determina si se llam@'o cuando el
punto est@'a con una definici@'on de funci@'on, y eso es, para
devolver el contaje para esta definici@'on. Esto a@~nade complejidad a
la definici@'on, pero nos guarda desde la necesidad de pasar
argumentos a la funci@'on.

@need 1250
Estas consideraciones nos llevan a preparar la siguiente plantilla:

@smallexample
@group
(defun count-words-in-defun ()
  "@var{documentation}@dots{}"
  (@var{set up}@dots{}
     (@var{while loop}@dots{})
   @var{return count})
@end group
@end smallexample

@noindent
As@'{@dotless{i}}, el trabajo es rellenar los slots.

Primero, la configuraci@'on.

Estamos presuponiendo que esta funci@'on ser@'a llamada con un
b@'uffer conteniendo definiciones de funci@'on. Apunta si ser@'a con
una definici@'on de funci@'on o no. Para que
@code{count-words-in-defun} funcione, el punto debe moverse al
principio de la definici@'on, un contador debe empezar a cero, y el
bucle contando debe parar cuando el punto logre el fin de la definici@'on.

La funci@'on @code{beginning-of-defun} busca atr@'as para un
delimitador de apertura tal como @samp{(} al principio de una
l@'{@dotless{i}}nea, y mueve el punto a esta posici@'on, o sino al
l@'{@dotless{i}}mite de la b@'usqueda. En la pr@'actica, esto significa
que @code{beginning-of-defun} mueve el punto al principio de un cierre
o definici@'on de funci@'on precedente, o sino al principio del buffer.

El bucle @code{while} requiere un contador para guardar la traza de
las palabras o s@'{@dotless{i}}mbolos siendo contados. Una expresi@'on
@code{let} puede ser usado para crear una variable local para este
prop@'osito, y lo asocia a un valor inicial de cero.

La funci@'on @code{end-of-defun} funciona como
@code{beginning-of-defun} excepto que mueve el punto al fin de la
definici@'on. @code{end-of-defun} puede ser usado como parte de una
expresi@'on que determina la posici@'on del fin de la definici@'on.

La configuraci@'on para @code{count-words-in-defun} toma forma
r@'apidamente: primero movemos el punto al principio de la
definici@'on, entonces se crea una variable local para manejar el
conteo, y finalmente, se graba la posici@'on del fin de la
definici@'on as@'{@dotless{i}} el bucle @code{while} conocer@'a cuando
parar el bucle.

@need 1250
El c@'odigo se parece a esto:

@smallexample
@group
(beginning-of-defun)
(let ((count 0)
      (end (save-excursion (end-of-defun) (point))))
@end group
@end smallexample

@noindent
El c@'odigo es simple. La @'unica ligera complicaci@'on es
probablemente ir al @code{end}: eso est@'a asociado a la posici@'on
del fin de la definici@'on por una expresi@'on @code{save-excursion}
que devuelve el valor del punto despu@'es de @code{end-of-defun}
temporalmente se mueve al fin de la definici@'on.

La segunda parte del @code{count-words-in-defun}, despu@'es de la
configuraci@'on, es el bucle @code{while}.

El bucle debe contener una expresi@'on que mueva el punto hacia
adelante palabra por palabra y s@'{@dotless{i}}mbolo por
s@'{@dotless{i}}mbolo, y otra expresi@'on que cuente los saltos. El
test-verdadero-o-falso para el bucle @code{while} chequear@'{@dotless{i}}a
verdadero tan largo como el punto deber@'{@dotless{i}}a saltar hacia
adelante, y falso si apunta al fin de la definici@'on. Ya se ha
redefinido la expresi@'on regular para esto, as@'{@dotless{i}} el
bucle es sencillo:

@smallexample
@group
(while (and (< (point) end)
            (re-search-forward
             "\\(\\w\\|\\s_\\)+[^ \t\n]*[ \t\n]*" end t)
  (setq count (1+ count)))
@end group
@end smallexample

La tercera parte de la definici@'on devuelve el contaje de palabras y
s@'{@dotless{i}}mbolos. Esta parte es la @'ultima expresi@'on con el
cuerpo de la expresi@'on @code{let}, y puede ser, muy la variable
local @code{count}, que cuando se eval@'ua devuelve el contaje.

@need 1250
Puesto junto, la definici@'on @code{count-words-in-defun} se ve
as@'{@dotless{i}}:

@findex count-words-in-defun
@smallexample
@group
(defun count-words-in-defun ()
  "Devuelve el n@'umero de palabras y s@'{@dotless{i}}mbolos en una defun."
  (beginning-of-defun)
  (let ((count 0)
        (end (save-excursion (end-of-defun) (point))))
@end group
@group
    (while
        (and (< (point) end)
             (re-search-forward
              "\\(\\w\\|\\s_\\)+[^ \t\n]*[ \t\n]*"
              end t))
      (setq count (1+ count)))
    count))
@end group
@end smallexample

@questiondown{}C@'omo se chequea esto? La funci@'on no es interactiva,
pero es f@'acil poner un envoltorio alrededor de la funci@'on para
hacerla interactiva; se puede usar casi el mismo c@'odigo como la
versi@'on recursiva de @code{@value{COUNT-WORDS}}:

@smallexample
@group
;;; @r{Versi@'on Interactiva.}
(defun count-words-defun ()
  "N@'umero de palabras y s@'{@dotless{i}}mbolos en una definici@'on
  de funci@'on."
  (interactive)
  (message
   "Contando palabras y s@'{@dotless{i}}mbolos en la definici@'on de funci@'on ... ")
@end group
@group
  (let ((count (count-words-in-defun)))
    (cond
     ((zerop count)
      (message
       "La definici@'on NO tiene palabras o s@'{@dotless{i}}mbolos."))
@end group
@group
     ((= 1 count)
      (message
       "La definici@'on tiene 1 palabra o s@'{@dotless{i}}mbolo."))
     (t
      (message
       "La definici@'on tiene %d palabras o s@'{@dotless{i}}mbolos." count)))))
@end group
@end smallexample

@need 800
@noindent
Permite reutilizar @kbd{C-c =} como un atajo conveniente:

@smallexample
(global-set-key "\C-c=" 'count-words-defun)
@end smallexample

Ahora se puede intentar @code{count-words-defun}: instala ambas
funciones @code{count-words-in-defun} y @code{count-words-defun}, y
asigna el atajo, y entonces emplaza el cursor con la siguiente definici@'on:

@smallexample
@group
(defun multiply-by-seven (number)
  "Multiplicar NUMBER por siete."
  (* 7 number))
     @result{} 10
@end group
@end smallexample

@noindent
@exclamdown{}@'Exito! La definici@'on tiene 10 palabras y
s@'{@dotless{i}}mbolos.

El siguiente problema es contar los n@'umeros de palabras y
s@'{@dotless{i}}mbolos en varias definiciones con un fichero simple.

@node Varias funciones
@section Contar varias @code{defuns} en un fichero

Un fichero tal como @file{simple.el} puede tener un centenar o m@'as
definiciones de funci@'on dentro. Nuestro objetivo es recoger
estad@'{@dotless{i}}sticas en muchos ficheros, pero en un primer
paso, nuestro objetivo inmediato es recoger estad@'{@dotless{i}}sticas
en un fichero.

La informaci@'on ser@'a una serie de n@'umeros, cada n@'umero siendo
el tama@~no de una definici@'on de funci@'on. Se pueden almacenar los
n@'umeros en una lista.

Se sabe que se querr@'a incorporar la informaci@'on considerando un
fichero con informaci@'on acerca de muchos otros ficheros; esto
significa que la funci@'on para contar el tama@~no de contaje con un
fichero solo necesita devolver la lista de tama@~nos. Eso no necesita
y no mostrar@'{@dotless{i}}a mensajes.

Los comando de contar palabras contienen una expresi@'on para saltar
el punto hacia adelante palabra por palabra y otra expresi@'on para
contar los saltos. La funci@'on devuelve los tama@~nos de definiciones
que pueden ser dise@~nadas para trabajar del mismo modo, con una
expresi@'on para saltar el punto hacia la definici@'on por
definici@'on y otra expresi@'on para construir el tama@~no de la lista.

Esta frase del problema hace elemental escribir la definici@'on de
funci@'on. Claramente, empezaremos el conteo al principio del fichero,
as@'{@dotless{i}} el primer comando ser@'a @code{(goto-char
(point-min))}. Lo siguiente, es empezar el bucle @code{while}; y este
true-or-false del bucle puede ser una b@'usqueda de expresi@'on
regular para la siguiente definici@'on de funci@'on ---
as@'{@dotless{i}} en el momento que la b@'usqueda tiene @'exito, el
punto se mueve hacia adelante y entonces el cuerpo del bucle es
evaluado. El cuerpo necesita una expresi@'on que construye la lista de
tama@~nos. @code{cons}, la lista de construcci@'on del comando, puede
ser usado para crear la lista. Esto es casi todo lo que hay.

@need 800
Aqu@'{@dotless{i}} est@'a este fragmento de c@'odigo que se ve
as@'{@dotless{i}}:

@smallexample
@group
(goto-char (point-min))
(while (re-search-forward "^(defun" nil t)
  (setq lengths-list
        (cons (count-words-in-defun) lengths-list)))
@end group
@end smallexample

Dejamos fuera el mecanismo para encontrar el fichero que contiene las
definiciones de funci@'on.

En ejemplos previos, nosotros hab@'{@dotless{i}}amos usado esto, el
fichero Info, o cambiamos atr@'as y adelante a alg@'un otro b@'uffer,
tal como el b@'uffer @file{*scratch*}.

Encontrar un fichero es un nuevo proceso que no tenemos
todav@'{@dotless{i}}a discutido.

@node Encontrar un fichero
@section Encontrar un fichero
@cindex Encontrar un fichero

Para encontrar un fichero en Emacs, se usa el comando @kbd{C-x C-f}
(@code{find-file}). Este comando es casi, pero no bastante correcto
para el problema de tama@~nos.

@need 1200
Permita mirar el fuente para @code{find-file}:

@smallexample
@group
(defun find-file (filename)
  "Edita el fichero FILENAME.
Cambia a un b@'uffer visitando el fichero FILENAME,
creando uno si no existe ya."
  (interactive "FFind file: ")
  (switch-to-buffer (find-file-noselect filename)))
@end group
@end smallexample

@noindent
(La versi@'on m@'as reciente de la definici@'on de funci@'on
@code{find-file} permite comodines especiales para visitar m@'ultiples
ficheros; que hacen la definici@'on m@'as compleja y no se discutir@'a
aqu@'{@dotless{i}}, ya que no es relevante. Se pueden ver sus fuentes
usando @kbd{M-.} (@code{find-tag}) o @kbd{C-h f}
(@code{describe-function}).)

@ignore
In Emacs 22
(defun find-file (filename &optional wildcards)
  "Edit file FILENAME.
Switch to a buffer visiting file FILENAME,
creating one if none already exists.
Interactively, the default if you just type RET is the current directory,
but the visited file name is available through the minibuffer history:
type M-n to pull it into the minibuffer.

Interactively, or if WILDCARDS is non-nil in a call from Lisp,
expand wildcards (if any) and visit multiple files.  You can
suppress wildcard expansion by setting `find-file-wildcards' to nil.

To visit a file without any kind of conversion and without
automatically choosing a major mode, use \\[find-file-literally]."
  (interactive (find-file-read-args "Find file: " nil))
  (let ((value (find-file-noselect filename nil nil wildcards)))
    (if (listp value)
        (mapcar 'switch-to-buffer (nreverse value))
      (switch-to-buffer value))))
@end ignore

La definici@'on que se est@'a mostrando posee una documentaci@'on
corta, pero completa y una especificaci@'on interactiva que muestra un
nombre de fichero cuando se usa el comando interactivamente. El cuerpo
de la definici@'on contiene dos funciones, @code{find-file-noselect} y
@code{switch-to-buffer}.

De acuerdo a su documentaci@'on como muestra por @kbd{C-h f} (el
comando @code{describe-function}), la funci@'on
@code{find-file-noselect} lee el fichero nombrado dentro de un
b@'uffer y devuelve el b@'uffer. (Su versi@'on m@'as reciente incluye
un argumento comod@'{@dotless{i}}n, tambi@'en, as@'{@dotless{i}} como
otro para leer un fichero literalmente y otro que suprime mensajes de
aviso. Estos argumentos opcionales son irrelevantes.) 

Sin embargo, la funci@'on @code{find-file-noselect} no selecciona el
b@'uffer en el que se pone el fichero. Emacs no cambia su atenci@'on
(o la tuya si est@'as usando @code{find-file-noselect}) al b@'uffer
seleccionado. Esto es lo que @code{switch-to-buffer} hace: eso cambia
el b@'uffer al que se dirige la atenci@'on de Emacs; y eso cambia el
b@'uffer mostrado en la ventana al nuevo b@'uffer. Se ha discutido el
b@'uffer cambiando a otro lugar. (@xref{Cambiando b@'uffers}.)

En este proyecto de histograma, no se necesita mostrar cada fichero en
la pantalla como el programa determina el tama@~no de cada
definici@'on con eso. En vez de emplear @code{switch-to-buffer}, se
puede trabajar con @code{set-buffer}, que redirige la atenci@'on del
programa de ordenador para un b@'uffer diferente pero no lo muestra en
pantalla. As@'{@dotless{i}} en vez llamar a @code{find-file} para
hacer el trabajo, debe escribir nuestra expresi@'on.

La tarea es f@'acil: usar @code{find-file-noselect} y @code{set-buffer}.

@node lengths-list-file
@section @code{lengths-list-file} en detalle

El n@'ucleo de la funci@'on @code{lengths-list-file} es un bucle
@code{while} conteniendo una funci@'on para mover el punto hacia
delante `funci@'on a funci@'on' y una funci@'on para contar el
n@'umero de palabras y s@'{@dotless{i}}mbolos en cada funci@'on. Este
n@'ucleo 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@'on de la funci@'on se parece a:
@findex lengths-list-file

@smallexample
@group
(defun lengths-list-file (filename)
  "Devuelve la lista de tama@~nos de definiciones con FILE.
La lista devuelta es una lista de n@'umeros.
Cada n@'umero es el n@'umero de palabras o
s@'{@dotless{i}}mbolos en una definici@'on."
@end group
@group
  (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)))
@end group
@end smallexample

@noindent
La funci@'on pasa un argumento, el nombre del fichero en el que se
trabajar@'a. Eso tiene cuatro l@'{@dotless{i}}neas de documentaci@'on,
pero sin especificaci@'on interactiva. Para evitar la preocupaci@'on
de si se ha estropeado el programa o no, la primera
l@'{@dotless{i}}nea del cuerpo es un mensaje de aviso.

La siguiente l@'{@dotless{i}}nea contiene un @code{save-excursion} que
devuelve a Emacs la atenci@'on al actual b@'uffer cuando la funci@'on
se completa. Esto es @'util en caso de embeber esta funci@'on en otra
funci@'on que presume que el punto restaura el b@'uffer original.

En la varlist de la expresi@'on @code{let}, Emacs encuentra el fichero
y ajusta la variable local @code{buffer} al b@'uffer conteniendo el
fichero. Al mismo tiempo, Emacs crea @code{lengths-list} como una
variable local.

Lo siguiente, Emacs cambia su atenci@'on al b@'uffer.

En la siguiente l@'{@dotless{i}}nea, Emacs crea el b@'uffer de solo
lectura. Idealmente, esta l@'{@dotless{i}}nea no es necesaria. Ninguna
de las funciones para contar palabras y s@'{@dotless{i}}mbolos en una
definici@'on de funci@'on cambiar@'{@dotless{i}}a el b@'uffer. Debajo,
el b@'uffer no est@'a yendo para ser guardado, incluso si eso fuese
cambiado. Esta l@'{@dotless{i}}nea es enteramente la consecuencia
grata, quiz@'as excesiva precauci@'on. La raz@'on para la precauci@'on
es que esta funci@'on y esta se llama a trabajar en las fuentes para
Emacs y eso es un inconveniente si est@'an inadvertidamente
modificadas. Eso va sin decir que no se realiz@'o una necesidad para
esta l@'{@dotless{i}}nea hasta que un experimento fu@'e cambiado hacia
un lado y empez@'o a modificar mis ficheros de fuentes Emacs @dots{}

Lo siguiente llama a alargar el b@'uffer si eso est@'a encogido. Esta
funci@'on es normalmente innecesaria --- Emacs crea un b@'uffer fresco
si ninguno ya existe; pero si un b@'uffer est@'a visitando el fichero
que ya existe que Emacs devuelve uno. En este caso, el b@'uffer puede
ser encogido y debe ser amplio. Si se quiere ser completamente `amigo
del usuario', se pondr@'{@dotless{i}}a en orden para guardar la
restricci@'on y la localizaci@'on del punto, pero no.

La expresi@'on @code{(goto-char (point-min))} mueve el punto al
principio del b@'uffer.

Entonces llega un bucle @code{while} en el que se devuelve el
`trabajo' de la funci@'on. En el bucle, Emacs determina el tama@~no de
cada definici@'on y construye una lista de tama@~nos conteniendo la
informaci@'on.

Emacs corta el b@'uffer despu@'es de trabajar a trav@'es de eso. Esto
es guardar espacio dentro de Emacs. Mi versi@'on de GNU Emacs 19
conten@'{@dotless{i}}a 300 ficheros fuente de inter@'es; GNU Emacs 22
contiene a trav@'es de un millar de ficheros fuente. Otra funci@'on
aplicar@'a @code{lengths-list-file} a cada uno de los ficheros.

Finalmente, la @'ultima expresi@'on con la expresi@'on @code{let} es
la variable @code{lengths-list}; su valor es devuelto como el valor de
la funci@'on completa.

Se puede probar esta funci@'on instal@'andolo en el modo
usual. Entonces posiciona tu cursor despu@'es de la siguiente
expresi@'on y escribe @kbd{C-x C-e} (@code{eval-last-sexp}).

@c !!! 22.1.1 lisp sources location here
@smallexample
(lengths-list-file
 "/usr/local/share/emacs/22.1.1/lisp/emacs-lisp/debug.el")
@end smallexample

@noindent
(Se puede necesitar cambiar la ruta del fichero; el @'unico
aqu@'{@dotless{i}} es para GNU Emacs versi@'on 22.1.1. Para cambiar la
expresi@'on, c@'opialo al b@'uffer @file{*scratch*} y
ed@'{@dotless{i}}talo.

@need 1200
@noindent
(Tambi@'en, para ver el tama@~no completo de la lista, en vez de una
versi@'on truncada se puede tener que evaluar lo siguiente:

@smallexample
(custom-set-variables '(eval-expression-print-length nil))
@end smallexample

@noindent
(@xref{defcustom, , Especificando Variables usando
@code{defcustom}}. Entonces eval@'ua la expresi@'on
@code{lengths-list-file}.)

@need 1200
La lista de tama@~nos para @file{debug.el} toma menos de un segundo
para producirse esto en GNU Emacs 22:

@smallexample
(83 113 105 144 289 22 30 97 48 89 25 52 52 88 28 29 77 49 43 290 232 587)
@end smallexample

@need 1500
(Usando mi vieja m@'aquina, la versi@'on 19 lista tama@~nos para
@file{debug.el} que en siete segundos para producen esto:

@smallexample
(75 41 80 62 20 45 44 68 45 12 34 235)
@end smallexample

(La versi@'on nueva de @file{debug.el} contiene m@'as defuns que la
temprana; y mi nueva m@'aquina es m@'as r@'apida que la vieja.

N@'otese que el tama@~no de la @'ultima definici@'on en el fichero es
el primero en la lista.

@node Varios ficheros
@section Contar palabras en @code{defuns} en diferentes ficheros

En la secci@'on previa, se creaba una funci@'on que devuelve una lista
de los tama@~nos de cada definici@'on en un fichero. Ahora, se quiere
definir una funci@'on para devolver una lista maestra de los tama@~nos
de las definiciones en una lista de ficheros.

Trabajar en cada elemento de una lista de ficheros es un acto repetitivo,
as@'{@dotless{i}} se puede usar un bucle @code{while} o recursi@'on.

@menu
* lengths-list-many-files::  Devolver una lista de tama@~nos de funciones.
* append::                   Adjuntar una lista a otra.
@end menu

@ifnottex
@node lengths-list-many-files
@unnumberedsubsec Determina las longitudes de @code{defuns}
@end ifnottex

El dise@~no usando un bucle @code{while} es rutina. El argumento que
se pasaba a la funci@'on es una lista de ficheros. Como se vi@'o
pronto (@pxref{Ejemplo de bucle}), se puede escribir un bucle
@code{while} de un modo que el cuerpo del bucle es evaluado si tal
lista contiene elementos, pero sale del bucle si la lista est@'a
vac@'{@dotless{i}}a. Para que este dise@~no funcione, el cuerpo del
bucle debe contener una expresi@'on que ordene la lista cada vez que
el cuerpo es evaluado, de modo que finalmente la lista est@'e
vac@'{@dotless{i}}a. La t@'ecnica normal es asignar el valor de la
lista para el valor del @sc{cdr} de la lista cada vez que el cuerpo es
evaluado.

@need 800
La plantilla se ve as@'{@dotless{i}}:

@smallexample
@group
(while @var{test-whether-list-is-empty}
  @var{body}@dots{}
  @var{set-list-to-cdr-of-list})
@end group
@end smallexample

Tambi@'en, recu@'erdanos que un bucle @code{while} devuelve @code{nil}
(el resultado de evaluar el true-or-false-test), no el resultado de
cualquier evaluaci@'on con su cuerpo. (Las evaluaciones con el cuerpo
del bucle son hechas para sus efectos laterales.) Sin embargo, la
expresi@'on que asigna la lista de tama@~nos es parte del cuerpo --- y
que es el valor que queremos devuelto por la funci@'on como un
todo. Para hacer esto cerramos el bucle @code{while} con una
expresi@'on @code{let}, y pone en orden que el @'ultimo elemento de la
expresi@'on @code{let} contiene el valor de lista de
tama@~nos. (@xref{Ejemplo de Incremento, , El Ejemplo del Bucle con un
Contador de Incremento}.)

@findex lengths-list-many-files
@need 1250
Estas consideraciones lideran directamente a la funci@'on en
s@'{@dotless{i}}:

@smallexample
@group
;;; @r{Usar bucle @code{while}.}
(defun lengths-list-many-files (list-of-files)
  "Devuelve la lista de tama@~nos de funciones en LIST-OF-FILES."
@end group
@group
  (let (lengths-list)

;;; @r{true-or-false-test}
    (while list-of-files
      (setq lengths-list
            (append
             lengths-list

;;; @r{Genera una lista de tama@~nos.}
             (lengths-list-file
              (expand-file-name (car list-of-files)))))
@end group

@group
;;; @r{Crea una lista ordenada de ficheros.}
      (setq list-of-files (cdr list-of-files)))

;;; @r{Devuelve la lista final de valores de tama@~nos.}
    lengths-list))
@end group
@end smallexample

@code{expand-file-name} es una funci@'on construida que convierte un
nombre de fichero al absoluto, forma de nombre de ruta. La funci@'on
emplea el nombre del directorio en el que la funci@'on se llama.

@c !!! 22.1.1 lisp sources location here
@need 1500
De este modo, si @code{expand-file-name} es llamado en @code{debug.el}
cuando Emacs est@'a visitando el directorio
@file{/usr/local/share/emacs/22.1.1/lisp/emacs-lisp/}

@smallexample
debug.el
@end smallexample

@need 800
@noindent
llega a ser

@c !!! 22.1.1 lisp sources location here
@smallexample
/usr/local/share/emacs/22.1.1/lisp/emacs-lisp/debug.el
@end smallexample

El @'unico nuevo elemento de esta definici@'on de funci@'on es la
todav@'{@dotless{i}}a no estudiada funci@'on @code{append}, que merece
una corta secci@'on en s@'{@dotless{i}}.

@node append
@subsection La funci@'on @code{append}

@need 800
La funci@'on @code{append} adjunta una lista a otra. De este modo,

@smallexample
(append '(1 2 3 4) '(5 6 7 8))
@end smallexample

@need 800
@noindent
produce la lista

@smallexample
(1 2 3 4 5 6 7 8)
@end smallexample

Esto es exactamente c@'omo queremos adjuntar dos listas de tama@~nos
producidas por @code{lengths-list-file} a cualquier otra. Los
resultados contrastan con @code{cons},

@smallexample
(cons '(1 2 3 4) '(5 6 7 8))
@end smallexample

@need 1250
@noindent
que construye una nueva lista en el que el primer argumento para
@code{cons} llega a ser el primer elemento de la nueva lista:

@smallexample
((1 2 3 4) 5 6 7 8)
@end smallexample

@node Varios ficheros recursivamente
@section Recursivamente cuenta palabras en diferentes ficheros

Bajo un bucle @code{while}, se puede trabajar cada lista de ficheros
con recursi@'on. Una versi@'on recursiva de
@code{lengths-list-many-files} es corta y simple.

La funci@'on 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@'on se llamar@'{@dotless{i}}a, que har@'a si la
@code{list-of-files} contiene los elementos que permanecen; la
`next-step-expression' resetea el @code{list-of-files} al @sc{cdr} en
s@'{@dotless{i}}, as@'{@dotless{i}} finalmente la lista ser@'a
vac@'{@dotless{i}}a; y la llamada recursiva llama en s@'{@dotless{i}}
a la lista ordenada. @exclamdown{}La funci@'on completa est@'a
ordenada por esta descripci@'on!
@findex recursive-lengths-list-many-files

@smallexample
@group
(defun recursive-lengths-list-many-files (list-of-files)
  "Devuelve la lista de tama@~nos de cada defun en LIST-OF-FILES."
  (if list-of-files                     ; @r{do-again-test}
      (append
       (lengths-list-file
        (expand-file-name (car list-of-files)))
       (recursive-lengths-list-many-files
        (cdr list-of-files)))))
@end group
@end smallexample

@noindent
En una frase, la funci@'on devuelve de tama@~nos de la lista para la
el primero de la @code{list-of-files} al resultado de llamarse
as@'{@dotless{i}} mismo al resto de @code{list-of-files}.

Aqu@'{@dotless{i}} hay un test
@code{recursive-lengths-list-many-files}, a lo largo de los resultados
de ejecutar @code{lengths-list-file} en cada uno de los ficheros
individualmente.

Instala @code{recursive-lengths-list-many-files} y
@code{lengths-list-file}, si es necesario, y entonces eval@'ua las
siguientes expresiones. Se puede necesitar cambiar las rutas de
ficheros; aqu@'{@dotless{i}} se trabaja cuando este fichero Info
y las fuentes de Emacs est@'an localizadas en sus lugares
personales. Para cambiar las expresiones, c@'opialas al b@'uffer
@file{*scratch*}, ed@'{@dotless{i}}talos y entonces eval@'ualos.

Los resultados son mostrados despu@'es del @samp{@result{}}. (Estos
resultados son para ficheros de Emacs versi@'on 22.1.1; ficheros desde
otras versiones de Emacs puede producir diferentes resultados.)

@c !!! 22.1.1 lisp sources location here
@smallexample
@group
(cd "/usr/local/share/emacs/22.1.1/")

(lengths-list-file "./lisp/macros.el")
     @result{} (283 263 480 90)
@end group

@group
(lengths-list-file "./lisp/mail/mailalias.el")
     @result{} (38 32 29 95 178 180 321 218 324)
@end group

@group
(lengths-list-file "./lisp/makesum.el")
     @result{} (85 181)
@end group

@group
  (recursive-lengths-list-many-files
   '("./lisp/macros.el"
     "./lisp/mail/mailalias.el"
     "./lisp/makesum.el"))
       @result{} (283 263 480 90 38 32 29 95 178 180 321 218 324 85 181)
@end group
@end smallexample

La funci@'on @code{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.

@node Preparar los datos
@section Preparar los datos para mostrarlos en un grafo

La funci@'on @code{recursive-lengths-list-many-files} devuelve una
lista de n@'umeros. Cada n@'umero graba el tama@~no de una
definici@'on de funci@'on. Lo que se necesita hacer ahora es
transformar estos datos dentro de una lista de n@'umeros ajustado para
generar un grafo. La nueva lista contar@'a cu@'antas definiciones de
funciones contienen menos de 10 palabras y s@'{@dotless{i}}mbolos,
cuantas contienen entre 10 y 19 palabras y s@'{@dotless{i}}mbolos,
cu@'antas contienen entre 20 y 29 palabras y s@'{@dotless{i}}mbolos, y
as@'{@dotless{i}}.

En breve, se necesita ir a trav@'es el tama@~no de la lista producida
por la funci@'on @code{recursive-lengths-list-many-files} y contar el
n@'umero de defuns con cada rango de tama@~nos, y produce una lista de
esto de n@'umeros.

@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@'on::  Contando definiciones de funci@'on
@end menu

@ifnottex
@node Datos para mostrar en detalle
@unnumberedsubsec El dato para mostrar en detalle
@end ifnottex

Basado en lo que hemos hecho antes, se prevee que no
ser@'{@dotless{i}}a dif@'{@dotless{i}}cil escribir una funci@'on que
`@sc{cdr}s' bajo la lista de tama@~nos, parece que cada elemento,
determina que rango de tama@~nos est@'a dentro, e incrementa un
contador para este rango.

Sin embargo, antes de empezar a escribir tal funci@'on, nosotros
considerar@'{@dotless{i}}amos las ventajas de ordenar los tama@~nos de
la lista primero, as@'{@dotless{i}} los n@'umeros son ordenados desde
el m@'as peque@~no al m@'as largo. Primero, ordenando se har@'a
f@'acil contar los n@'umeros en cada rango, desde dos n@'umeros
adyacentes ser@'a el mismo rango del tama@~no en rangos
adyacentes. Segundo, inspeccionando una lista ordenada, se puede
descubrir el n@'umero mayor y menor, y esto significa determinar el
rango de tama@~no mayor y menor que necesitar@'a.

@node Ordenando
@subsection Ordenando listas
@findex sort

Emacs contiene una funci@'on para listas ordenadas, llamadas (como se
podr@'{@dotless{i}}a adivinar) @code{sort}. La funci@'on @code{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@'o antes (@pxref{Tipo incorrecto de argumento, , Usando el
Tipo Incorrecto de Objeto como un Argumento}), un predicado es una
funci@'on que determina si alguna propiedad es verdadera o falsa. La
funci@'on @code{sort} reordenar@'a una lista de acuerdo a lo que la
propiedad del predicado usa; esto significa que @code{sort} puede ser
usado para ordenar listas no num@'ericas por un criterio no num@'erico
--- eso puede, por ejemplo, alfabetizar una lista.

@need 1250
La funci@'on @code{<} se usa cuando se ordena una lista
num@'erica. Por ejemplo,

@smallexample
(sort '(4 8 21 17 33 7 21 7) '<)
@end smallexample

@need 800
@noindent
produce esto:

@smallexample
(4 7 7 8 17 21 21 33)
@end smallexample

@noindent
(Note que en este ejemplo, ambos argumentos se citan
as@'{@dotless{i}} que los s@'{@dotless{i}}mbolos no se eval@'uan
antes de ser pasados por @code{sort} como argumentos.)

Ordenando la lista devuelta por la funci@'on
@code{recursive-lengths-list-many-files} es honesta; eso usa la
funci@'n @code{<}:

@ignore
2006 Oct 29
In GNU Emacs 22,  eval
(progn
  (cd "/usr/local/share/emacs/22.0.50/")
  (sort
   (recursive-lengths-list-many-files
    '("./lisp/macros.el"
      "./lisp/mail/mailalias.el"
      "./lisp/makesum.el"))
   '<))

@end ignore

@smallexample
@group
(sort
 (recursive-lengths-list-many-files
  '("./lisp/macros.el"
    "./lisp/mailalias.el"
    "./lisp/makesum.el"))
 '<)
@end group
@end smallexample

@need 800
@noindent
que produce:

@smallexample
(29 32 38 85 90 95 178 180 181 218 263 283 321 324 480)
@end smallexample

@noindent
(Note que en este ejemplo, el primer argumento para @code{sort} no
est@'a citado, desde que la expresi@'on debe ser evaluado
as@'{@dotless{i}} como producir la lista que es pasada para @code{sort}.)

@node Listar ficheros
@subsection Creando una lista de ficheros

La funci@'on @code{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@'{@dotless{i}}, se
escribir@'a una funci@'on para hacer el trabajo. En esta funci@'on,
se usa tanto un bucle @code{while} como una llamada recursiva.

@findex directory-files
En viejas versiones de GNU Emacs no hizo falta tener que escribir esta
funci@'on, puesto que todos los ficheros @samp{.el} en un
directorio. En vez de eso, se puede ser capaz de usar la funci@'on
@code{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 @file{lisp}. Esto
facilita la navegaci@'on. Por ejemplo, todos los ficheros de correo
relacionados que est@'an en el subdirectorio llamado @file{mail}. Pero al
mismo tiempo, esta facilidad fuerza a crear un fichero listando la
funci@'on que desciende dentro de los subdirectorios.

@findex files-in-below-directory
Se puede crear esta funci@'on, llamada
@code{files-en-below-directory}, usando funciones familiares tales
como @code{car}, @code{nthcdr}, y @code{substring} en conjunci@'on con
una funci@'on existente llamada
@code{directory-files-and-attributes}. Esta @'ultima funci@'on no solo
listas de ficheros en un directorio, incluyendo los nombres de
subdirectorios, pero tambi@'en sus atributos.

Para empezar nuestro objetivo: crear una funci@'on que nos permita
alimentas ficheros a @code{recursive-lengths-list-many-files} como una
lista que se parece a esto (pero con m@'as elementos):

@smallexample
@group
("./lisp/macros.el"
 "./lisp/mail/rmail.el"
 "./lisp/makesum.el")
@end group
@end smallexample

La funci@'on @code{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 @code{t} para un directorio, es una
cadena para el enlace simb@'olico (la cadena es el nombre enlazado), o
@code{nil}.

Por ejemplo, el primer fichero @samp{.el} en el directorio es
@file{abbrev.el}. Su nombre es
@file{/usr/local/share/emacs/22.1.1/lisp/abbrev.el} y no es un
directorio o un enlace simb@'olico.

@need 1000
Esto es c@'omo @code{directory-files-and-attributes} lista este
fichero y sus atributos:

@smallexample
@group
("abbrev.el"
nil
1
1000
100
@end group
@group
(20615 27034 579989 697000)
(17905 55681 0 0)
(20615 26327 734791 805000)
13188
"-rw-r--r--"
@end group
@group
nil
2971624
773)
@end group
@end smallexample

@need 1200
Por otro lado, @file{mail/} es un directorio con el directorio
@file{lisp/}. El principio del listado se parece a esto:

@smallexample
@group
("mail"
t
@dots{}
)
@end group
@end smallexample

(Para aprender acerca de los diferentes atributos, mira en la
documentaci@'on de @code{file-attributes}. Tenga en mente que la
funci@'on @code{file-attributes} no lista el nombre del fichero,
as@'{@dotless{i}} su primer elemento es
@code{directory-files-and-attributes} que es el segundo elemento.)

Se querr@'an nuestras nuevas funciones,
@code{files-in-below-directory}, para listar los fichero @samp{.el} en
el directorio eso es contado para chequear, y en los directorios bajo
este directorio.

Esto nos da una sugesti@'on de como construir
@code{files-in-below-directory}: con un directorio, la funci@'on
a@~nadir los nombres de ficheros @samp{.el} a una lista; y si, con un
directorio, la funci@'on viene con un subdirectorio,
ir@'{@dotless{i}}a dentro de este subdirectorio y repite sus acciones.

Sin embargo, nosotros notar@'{@dotless{i}}amos que cada directorio
contiene un nombre que se refiere a s@'{@dotless{i}} mismo, llamado
@file{.}, (``dot'') y un nombre que se refiere a su directorio padre,
llamado @file{..} (``doble punto''). (En @file{/}, el directorio
ra@'{@dotless{i}}z, @file{..} se refiere as@'{@dotless{i}} mismo,
desde que @file{/} no tiene padre.) Claramente, no que se quiere
nuestra funci@'on @code{files-in-below-directory} para introducir
estos directorio, desde que ellos siempre nos lideran, directamente o
indirectamente, al directorio actual.

Consecuentemente, nuestra funci@'on @code{files-in-below-directory}
debe hacer varias tareas:

@itemize @bullet
@item
Chequee para ver si se est@'a mirando en un nombre de fichero que
finaliza en @samp{.el} y si es as@'{@dotless{i}}, se a@~nade el nombre
a una lista.

@item
Chequee para ver si est@'a mirando en un nombre de fichero que es el
nombre de un directorio; y si es as@'{@dotless{i}},

@itemize @minus
@item
Chequee para ver si est@'a mirando en @file{.} o @file{..}; y si es
as@'{@dotless{i}} sal.

@item
O adem@'as, ve dentro de este directorio y repite el proceso.
@end itemize
@end itemize

Se permite escribir una definici@'on de funci@'on para hacer estas
tareas. Se usar@'a un bucle @code{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@'on recursivo es `acumular' (@pxref{Acumular, ,
Patr@'on recursivo: @emph{accumulate}}) usando @code{append} para
combinar.

@ignore
(directory-files "/usr/local/src/emacs/lisp/" t "\\.el$")
(shell-command "find /usr/local/src/emacs/lisp/ -name '*.el'")

(directory-files "/usr/local/share/emacs/22.1.1/lisp/" t "\\.el$")
(shell-command "find /usr/local/share/emacs/22.1.1/lisp/ -name '*.el'")
@end ignore

@c  /usr/local/share/emacs/22.1.1/lisp/

@need 800
Aqu@'{@dotless{i}} est@'a la funci@'on:

@smallexample
@group
(defun files-in-below-directory (directory)
  "Lista los ficheros .el en DIRECTORIO y en sus subdirectorios."
  ;; Aunque la funci@'on ser@'a usada no interactivamente,
  ;; ser@'a f@'acil chequear si lo hacemos interactivo.
  ;; El directorio tendr@'a un nombre tal como
  ;;  "/usr/local/share/emacs/22.1.1/lisp/"
  (interactive "DNombre del Directorio: ")
@end group
@group
  (let (el-files-list
        (current-directory-list
         (directory-files-and-attributes directory t)))
    ;; mientras estamos en el directorio actual
    (while current-directory-list
@end group
@group
      (cond
       ;; chequee para ver si el nombre del fichero finaliza en `.el'
       ;; y si es as@'{@dotless{i}}, a@~nade 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)))
@end group
@group
       ;; chequee si el nombre del fichero es un directorio
       ((eq t (car (cdr (car current-directory-list))))
        ;; decide si salir o hacer recursi@'on
        (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 ".."
            ()
@end group
@group
          ;; 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@'en 
      ;; ordena la lista as@'{@dotless{i}} mientras el bucle
      ;; eventualmente llega a un fin
      (setq current-directory-list (cdr current-directory-list)))
    ;; devuelve los ficheros
    el-files-list))
@end group
@end smallexample

@c (files-in-below-directory "/usr/local/src/emacs/lisp/")
@c (files-in-below-directory "/usr/local/share/emacs/22.1.1/lisp/")

Las funciones @code{files-in-below-directory} @code{directory-files}
toma un argumento, el nombre de un directorio.

@need 1250
De este modo, en mi sistema,

@c (length (files-in-below-directory "/usr/local/src/emacs/lisp/"))

@c !!! 22.1.1 lisp sources location here
@smallexample
@group
(length
 (files-in-below-directory "/usr/local/share/emacs/22.1.1/lisp/"))
@end group
@end smallexample

@noindent
se cuenta que dentro y debajo de mi directorio de fuentes Lisp hay
1031 ficheros @samp{.el}

@code{files-in-below-directory} devuelve una lista en orden
alfab@'etico inverso. Una expresi@'on para ordenar la lista en orden
que parece como este:

@smallexample
@group
(sort
 (files-in-below-directory "/usr/local/share/emacs/22.1.1/lisp/")
 'string-lessp)
@end group
@end smallexample

@ignore
(defun test ()
  "Test how long it takes to find lengths of all sorted elisp defuns."
  (insert "\n" (current-time-string) "\n")
  (sit-for 0)
  (sort
   (recursive-lengths-list-many-files
    (files-in-below-directory "/usr/local/src/emacs/lisp/"))
   '<)
  (insert (format "%s" (current-time-string))))
@end ignore

@node Contando definiciones de funci@'on
@subsection Contando definiciones de funci@'on

Nuestro objetivo inmediato es generar una lista que cuenta, cuantas
definiciones de funciones contienen menos de 10 palabras y
s@'{@dotless{i}}mbolos, cuantas contienen entre 10 y 19 palabras y
s@'{@dotless{i}}mbolos, cuantas contienen entre 20 y 29 palabras y
s@'{@dotless{i}}mbolos, y as@'{@dotless{i}}.

Con una lista ordenada de n@'umeros, es f@'acil: se cuentan cuantos
elementos de la lista son m@'as peque@~nos de 10, entonces, se
devuelven los n@'umeros contados, se cuenta cuantos son m@'as
peque@~nos de 20, entonces se devuelven los n@'umeros contados,
despu@'es se cuentan los que son m@'as peque@~nos de 30, y
as@'{@dotless{i}}. Cada uno de los n@'umeros, 10, 20, 30, 40, y como,
es m@'as grande que el tope de este rango. Se puede llamar a la lista
de tales n@'umeros, la lista @code{top-of-ranges}.

@need 1200
Si se desea, se podr@'{@dotless{i}}a generar esta lista
autom@'aticamente, pero es m@'as simple escribir una lista
manualmente. Aqu@'{@dotless{i}} est@'a:
@vindex top-of-ranges

@smallexample
@group
(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'.")
@end group
@end smallexample

Para cambiar los rangos, se edita esta lista.

Lo siguiente, que se necesita es escribir la funci@'on que crea la
lista del n@'umero de definiciones con cada rango. Claramente, esta
funci@'on debe tomar el @code{sorted-lengths} y las listas
@code{top-of-ranges} listas como argumentos.

La funci@'on @code{defuns-per-range} debe hacer dos cosas una y otra
vez: eso debe contar el n@'umero de definiciones con un rango
espec@'{@dotless{i}}fico por el actual valor top-of-range; y eso debe
dividir al siguiente gran valor en la lista @code{top-of-ranges}
despu@'es de contar el n@'umero de definiciones en el rango
actual. Desde que cada una de estas acciones es repetitiva, se puede
usar los bucles @code{while} para el trabajo. Un bucle cuenta el
n@'umero 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 @code{sorted-lengths} se cuentan para
cada rango; esto significa que el bucle para la lista
@code{sorted-lengths} ser@'a dentro del bucle para la lista
@code{top-of-ranges}, como un peque@~no adorno dentro de un gran adorno.

El bucle interno cuenta el n@'umero de definiciones con el rango. Eso
es un simple contaje del tipo en el que se ha visto
antes. (@xref{Incrementando el Bucle, , Un bucle con un contador de
incremento}). El test true-or-false del bucle chequea si el valor
desde la lista @code{sorted-lengths} es m@'as peque@~na que el actual
valor de lo alto del rango. Si es as@'{@dotless{i}}, la funci@'on
incrementa el contador y se chequea el siguiente valor desde la lista
@code{sorted-lengths}.

@need 1250
El bucle interno se parece a esto:

@smallexample
@group
(while @var{length-element-smaller-than-top-of-range}
  (setq number-within-range (1+ number-within-range))
  (setq sorted-lengths (cdr sorted-lengths)))
@end group
@end smallexample

El bucle de fuera debe empezar con el valor m@'as bajo de la lista
@code{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:

@smallexample
@group
(while top-of-ranges
  @var{body-of-loop}@dots{}
  (setq top-of-ranges (cdr top-of-ranges)))
@end group
@end smallexample

@need 1200
Se ponen juntos, los dos bucles como este:

@smallexample
@group
(while top-of-ranges

  ;; @r{Contar el n@'umero de elementos con el actual rango.}
  (while @var{length-element-smaller-than-top-of-range}
    (setq number-within-range (1+ number-within-range))
    (setq sorted-lengths (cdr sorted-lengths)))

  ;; @r{Mover al siguiente rango.}
  (setq top-of-ranges (cdr top-of-ranges)))
@end group
@end smallexample

Adem@'as, en cada circuito del bucle exterior, Emacs
grabar@'{@dotless{i}}a el n@'umero de definiciones con este rango (el
valor de @code{number-within-range}) en una lista. Se puede usar
@code{cons} para este prop@'osito. (@xref{cons, , @code{cons}}.)

La funci@'on @code{cons} trabaja bien, excepto que la lista que se
construye contendr@'a el n@'umero de definiciones para el alto rango y
su principio el n@'umero de definiciones para el m@'as bajo rango a su
fin. Esto es porque @code{cons} adjunta nuevos elementos de la lista
al principio de la lista, y desde los dos bucles que hacen c@'alculos
a trav@'es de la lista de tama@~nos desde lo bajo finaliza primero, el
@code{defuns-per-range-list} finalizar@'a el primer n@'umero m@'as
largo. Pero lo que se quiere es imprimir nuestro grafo con peque@~nos
valores primero y el m@'as grande despu@'es. La soluci@'on es invertir
el orden del @code{defuns-per-range-list}. Nosotros podemos hacer esto
usando la funci@'on @code{nreverse}, que invierte el orden de una
lista.
@findex nreverse

@need 800
Por ejemplo,

@smallexample
(nreverse '(1 2 3 4))
@end smallexample

@need 800
@noindent
produce:

@smallexample
(4 3 2 1)
@end smallexample

Note que la funci@'on @code{nreverse} es ``destructiva'' --- que es,
cambiar la lista a la que se aplica; esto contrasta con las
funciones @code{car} y @code{cdr}, que no son destructivas. En este
caso, no se quiere que el original @code{defuns-per-range-list},
de manera que no hay materia que se destruya. (La funci@'on
@code{reverse} provee un copia inversa de una lista, dejando la lista
original como es.)
@findex reverse

@need 1250
Pon todo junto, el @code{defuns-per-range} se parece a esto:

@smallexample
@group
(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)
@end group

@group
    ;; @r{Bucle Exterior.}
    (while top-of-ranges
@end group

@group
      ;; @r{Bucle Interno.}
      (while (and
              ;; @r{Necesita el n@'umero para el test num@'erico.}
              (car sorted-lengths)
              (< (car sorted-lengths) top-of-range))
@end group

@group
        ;; @r{Contar n@'umero de definiciones con el rango actual.}
        (setq number-within-range (1+ number-within-range))
        (setq sorted-lengths (cdr sorted-lengths)))

      ;; @r{Sal del bucle interno pero permanece con el bucle externo.}
@end group

@group
      (setq defuns-per-range-list
            (cons number-within-range defuns-per-range-list))
      (setq number-within-range 0)      ; @r{Resetear el contaje a cero.}
@end group

@group
      ;; @r{Mover al siguiente rango.}
      (setq top-of-ranges (cdr top-of-ranges))
      ;; @r{Especifica el siguiente mejor rango de valores.}
      (setq top-of-range (car top-of-ranges)))
@end group

@group
    ;; @r{Salir del bucle externo y contar el n@'umero de defuns m@'as
    ;; largas que}
    ;; @r{el valor m@'as largo del valor top-of-range.}
    (setq defuns-per-range-list
          (cons
           (length sorted-lengths)
           defuns-per-range-list))
@end group

@group
    ;; @r{Devuelve una lista del n@'umero de definiciones con cada rango,}
    ;; @r{ del m@'as peque@~no al m@'as largo.}
    (nreverse defuns-per-range-list)))
@end group
@end smallexample

@need 1200
@noindent
La funci@'on es simple excepto para una peque@~na funcionalidad. El
test verdadero-o-falso para el bucle interno se parece a esto:

@smallexample
@group
(and (car sorted-lengths)
     (< (car sorted-lengths) top-of-range))
@end group
@end smallexample

@need 800
@noindent
en vez de algo como esto:

@smallexample
(< (car sorted-lengths) top-of-range)
@end smallexample

El prop@'osito del test es determinar si el primer @'{@dotless{i}}tem
en la lista @code{sorted-lengths} es menor que el valor de lo mejor
del rango.

La versi@'on simple del test trabaja bien a menos que la lista
@code{sorted-lengths} tiene un valor @code{nil}. En este caso, la
expresi@'on @code{(car sorted-lengths)} devuelve @code{nil}. La
funci@'on @code{<} no se puede compara un n@'umero a @code{nil}, que
es una lista vac@'{@dotless{i}}a, as@'{@dotless{i}} Emacs se@~nala un
error y para la funci@'on desde el intento de continuar la ejecuci@'on.

La lista @code{sorted-lengths} siempre llega a ser @code{nil} cuando
el contador logra el fin de la lista. Esto significa que cualquier
intento de usar la funci@'on @code{defuns-per-range} con la versi@'on
simple del test fallar@'a.

Se resuelve el problema usando @code{(car sorted-lengths)} en
conjunci@'on con la expresi@'on @code{and}. La expresi@'on @code{(car
sorted-lengths)} devuelve un valor no @code{nil} tan largo como la
lista que tiene al menos un n@'umero con eso, pero devuelve @code{nil}
si la lista est@'a vac@'{@dotless{i}}a. La expresi@'on @code{and}
primero eval@'ua el @code{(car sorted-lengths)}, y si eso es
@code{nil}, devuelve falso @emph{sin} evaluar la expresi@'on @code{<}
 y devuelve este valor como el valor de la expresi@'on @code{and}.

@c colon in printed section title causes problem in Info cross reference
Este camino, evita un error.
@iftex
@noindent
(Para informaci@'on acerca de @code{and}, ver @ref{Funci@'on kill-new,
, La funci@'on @code{kill-new}}.)
@end iftex
@ifinfo
@noindent
(@xref{Funci@'on kill-new, , La funci@'on @code{kill-new}}, para
informaci@'on acerca de @code{and}.)
@end ifinfo

Aqu@'{@dotless{i}} hay un peque@~no test de la funci@'on
@code{defuns-per-range}. Primero, eval@'ua la expresi@'on que ajusta
(una resumida) lista @code{top-of-ranges} a la lista de valores,
entonces eval@'ua la expresi@'on para ajustar la lista
@code{sorted-lengths}, y entonces eval@'ua la funci@'on
@code{defuns-per-range}.

@smallexample
@group
;; @r{(La lista ordenada que usar@'a despu@'es.)}
(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)
@end group
@end smallexample

@need 800
@noindent
La lista devuelta se parece a esto:

@smallexample
(2 2 2 0 0 1 0 2 0 0 4)
@end smallexample

@noindent
Dentro, hay dos elementos de la lista @code{sorted-lengths} menores de
110, dos elementos entre 110 y 119, dos elementos entre 120 y 129 y
as@'{@dotless{i}}. Hay cuatro elementos con un valor de 200 o superior.

@c The next step is to turn this numbers' list into a graph.
@node Leyendo un grafo
@chapter Leyendo un grafo
@cindex Leyendo un grafo
@cindex Grafo prototipo
@cindex Prototipo de grafo
@cindex Cuerpo de grafo

Nuestro objetivo es construir un grafo mostrando los n@'umeros de
definiciones de funci@'on de varios tama@~nos en las fuentes de Emacs lisp.

Como una materia pr@'actica, si se estuviese creando un grafo,
probablemente usar@'{@dotless{i}}as un programa tal como
@code{gnuplot} para hacer el trabajo. (@code{gnuplot} est@'a 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@'{@dotless{i}} poder aprender m@'as.

En este cap@'{@dotless{i}}tulo, primero se escribe un grafo simple
imprimiendo la funci@'on. Esta primera definici@'on ser@'a un
@dfn{prototipo}, una funci@'on escrita r@'apidamente nos permite
reconocer este territorio de crear un grafo. Se descubren dragones, o
resulta que son mitos. Despu@'es de olisquear el terreno, nos
sentiremos m@'as confidentes y mejoraremos la funci@'on para etiquetar
las coordenadas autom@'aticamente.

@menu
* Columnas de un grafo::     Columnas de un grafo
* graph-body-print::         C@'omo imprimir el cuerpo de un grafo.
* recursive-graph-body-print::  recursive-graph-body-print
* Ejes Impresos::            Ejes Impresos
* Ejercicio de L@'{@dotless{i}}nea de Grafo::  Ejercicio de 
                                                 L@'{@dotless{i}}nea de Grafo
@end menu

@ifnottex
@node Columnas de un grafo
@unnumberedsec Imprimiendo las columnas de un grafo
@end ifnottex

Puesto que Emacs est@'a dise@~nado para ser flexible y trabajar con
todo tipo de terminales, incluyendo los terminales de caracteres, el
grafo necesitar@'a ser hecho desde s@'{@dotless{i}}mbolos de
`escritura'. Un asterisco har@'a; como nosotros mejoramos la funci@'on
de impresi@'on del grafo, se puede crear la elecci@'on del
s@'{@dotless{i}}mbolo como una opci@'on de usuario.

Se puede llamar a esta funci@'on @code{graph-body-print}; se tomar@'a
un @code{numbers-list} como su @'unico argumento. En esta fase, no se
etiquetar@'a el grafo, pero se imprime su cuerpo.

La funci@'on @code{graph-body-print} inserta una columna vertical de
asteriscos para cada elemento en la lista @code{numbers-list}. La
altura de cada l@'{@dotless{i}}nea est@'a determinada por el valor de
este elemento de la @code{numbers-list}.

Insertar columnas es un acto repetitivo; que significa que esta
funci@'on debe ser escrita con un bucle @code{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@'{@dotless{i}}nea a
l@'{@dotless{i}}nea, escribiendo. Se tienen dos rutas que se pueden
seguir: escribir nuestra funci@'on column-insertion o descubrir si una
que exista en Emacs.

Para ver si hay uno en Emacs, se puede usar el comando @kbd{M-x
apropos}. Este comando es como el comando @kbd{C-h a}
(@code{command-apropos}), excepto que @'ultimo encuentra solo estas
funciones que son comandos. El comando @kbd{M-x apropos} lista todos
los s@'{@dotless{i}}mbolos que se asocian a una expresi@'on regular,
incluyendo funciones que no son interactivas.
@findex apropos

Lo que se quiere buscar es alg@'un comando que imprima o inserte
columnas. Muy probablemente, el nombre de la funci@'on contendr@'a la
palabra `print' o la palabra `insert' o la palabra `column'. Por esta
raz@'on, podemos simplemente escribir @kbd{M-x apropos RET print
\|insert\|column RET} y se ve el resultado. En mi sistema, este comando
toma todav@'{@dotless{i}}a alg@'un 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 @'unica funci@'on que se ve como si se pudiera hacer el trabajo que
es @code{insert-rectangle}.

@need 1200
En realidad, esta es la funci@'on que queremos; su documentaci@'on dice:

@smallexample
@group
insert-rectangle:
Insertar texto de RECTANGLE con la esquina izquierda a punto
La primera l@'{@dotless{i}}nea de RECTANGLE es insertada al punto
su segunda l@'{@dotless{i}}nea es insertada a un punto verticalmente
bajo el punto, etc.
El RECTANGLE deber@'{@dotless{i}}a ser una lista de cadenas.
Despu@'es de este comando, la marca est@'a en la esquina izquierda
superior y el punto en la esquina derecha inferior.
@end group
@end smallexample

Se puede ejecutar un test r@'apido, para asegurar que hace lo que se
espera de eso.

Aqu@'{@dotless{i}} est@'a el resultado de emplazar el cursor despu@'es
de la expresi@'on @code{insert-rectangle} y escribiendo @kbd{C-u C-x
C-e} (@code{eval-last-sexp}). La funci@'on inserta las cadenas
@samp{"primero"}, @samp{"segundo"}, y @samp{"tercero"} en el
punto. Tambi@'en la funci@'on devuelve @code{nil}.

@smallexample
@group
(insert-rectangle '("primero" "segundo" "tercer"))primero
                                              segundo
                                              terceronil
@end group
@end smallexample

@noindent
De acuerdo, no se inserta el texto de la expresi@'on
@code{insert-rectangle} en s@'{@dotless{i}} dentro del b@'uffer en el
que se marca el grafo, pero se llamar@'a la funci@'on de nuestro
programa. Nosotros, sin embargo, tenemos que asegurar que el punto
est@'a en el b@'uffer en el lugar donde la funci@'on
@code{insert-rectangle} insertar@'a la columna de cadenas.

Si se est@'a leyendo esto en Info, se puede ver como este trabajo
cambia a otro b@'uffer, tal como el b@'uffer @file{*scratch*},
emplazando el punto a alg@'un lugar en el b@'uffer, se escribe
@kbd{M-:}, despu@'es se escribe la expresi@'on @code{insert-rectangle}
dentro del minib@'uffer en la consola, y entonces se escribe
@key{RET}. Esto causa que Emacs eval@'ue la expresi@'on en el
minib@'uffer, pero usa como el valor del punto la posici@'on del punto
en el b@'uffer @file{*scratch*}. (@kbd{M-:} es el atajo para
@code{eval-expression}. @code{nil} tampoco aparece en el b@'uffer
@file{*scratch*} desde que la expresi@'on se eval@'ua en el
minib@'uffer.)

Se encuentra cuando hacer esto hasta el punto que finaliza al fin de
la @'ultima l@'{@dotless{i}}nea insertada --- es decir, esta funci@'on
mueve el punto como un efecto lateral. Si se iba a repetir el comando,
con el punto en esta posici@'on, la siguiente inserci@'on
ser@'{@dotless{i}}a debajo y a la derecha de la inserci@'on
previa. @exclamdown{}Nosotros no queremos esto!. Si se est@'a yendo a
crear un gr@'afico de barras, las columnas necesitan estar debajo unas
de otras.

As@'{@dotless{i}} se descubre que cada ciclo del bucle @code{while}
de column-inserting debe reposicionar el punto al lugar que queremos,
y este lugar estar@'a arriba, no abajo, de la columna. M@'as all@'a,
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@'{@dotless{i}}nea cada vez, pero movido cubriendo a la derecha --- o
quiz@'as se puede @dots{}

Estamos planeando crear las columnas de la barra gr@'afica sin
asteriscos. El n@'umero de asteriscos en la columna es el n@'umero
espec@'{@dotless{i}}fico por el elemento actual del
@code{numbers-list}. Necesitamos construir una lista de asteriscos del
tama@~no derecho para cada llamada a @code{insert-rectangle}. Si esta
lista consiste @'unicamente del n@'umero requerido de asteriscos,
entonces tendremos la posici@'on de punto el n@'umero correcto de
l@'{@dotless{i}}neas bajo la base del gr@'afico para imprimirse
correctamente. Esto podr@'{@dotless{i}}a ser dif@'{@dotless{i}}cil.

Alternativamente, si podemos figurarnos alg@'un camino para pasar
@code{insert-rectangle} del mismo tama@~no cada vez, entonces podemos
posicionar el punto en la misma l@'{@dotless{i}}nea cada vez, pero se
mueve a trav@'es de una columna a la derecha por cada nueva
columna. Si hacemos esto, sin embargo, alguna de las entradas en la
lista pasaba a @code{insert-rectangle} y deben ser espacios en blanco
en vez de asteriscos. Por ejemplo, si la altura m@'axima del grafo es
5, pero la altura de la columna es 3, entonces @code{insert-rectangle}
requiere un argumento que se parezca a esto:

@smallexample
(" " " " "*" "*" "*")
@end smallexample

Esta @'ultima propuesta no es tan dif@'{@dotless{i}}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@'a, lo que funcionar@'{@dotless{i}}a bien para
gr@'aficas de esta altura; o podemos buscar a trav@'es de la lista de
n@'umeros y usar la altura m@'axima de la lista como la altura
m@'axima del grafo. Si la @'ultima operaci@'on fuera
dif@'{@dotless{i}}cil, entonces el procedimiento formal
ser@'{@dotless{i}}a f@'acil, pero hay una funci@'on construida en
Emacs para determinar el m@'aximo de sus argumentos. Se puede usar
esta funci@'on. La funci@'on se llamaba @code{max} y eso devuelve el
mayor de sus argumentos, que deben ser n@'umeros. De este modo, por
ejemplo,

@smallexample
(max  3 4 6 5 7 3)
@end smallexample

@noindent
devuelve 7. (Una funci@'on correspondiente llamada @code{min} devuelve
lo m@'as peque@~no de todos sus argumentos.)
@findex max
@findex min

Sin embargo, no podemos simplemente llama a @code{max} en el
@code{numbers-list}; la funci@'on @code{max} espera n@'umeros como sus
argumentos, no una lista de n@'umeros. De este modo, la siguiente
expresi@'on,

@smallexample
(max  '(3 4 6 5 7 3))
@end smallexample

@need 800
@noindent
produce el siguiente mensaje error;

@smallexample
Mal tipo de argumento: number-or-marker-p, (3 4 6 5 7 3)
@end smallexample

@findex apply
Se necesita una funci@'on que pasa una lista de argumentos a una
funci@'on. Esta funci@'on es @code{apply}. Esta funci@'on `aplica' su
primer argumento (una funci@'on) para los argumentos que permanecen,
el @'ultimo puede ser una lista.

@need 1250
Por ejemplo,

@smallexample
(apply 'max 3 4 7 3 '(4 8 5))
@end smallexample

@noindent
devuelve 8

(Incidentalmente, yo no sabr@'{@dotless{i}}a c@'omo aprender acerca de
esta funci@'on sin un libro tal como este. Eso es posible descubrir
otras funciones, como @code{search-forward} o @code{insert-rectangle},
adivinando una parte de sus nombres y entonces usando
@code{apropos}. Incluso aunque su base metaf@'orica es clara ---
`apply' su primer argumento al resto --- dudo que un novicio
vendr@'{@dotless{i}}a con esta palabra particular usando
@code{apropos} u otra ayuda. De acuerdo, podr@'{@dotless{i}}a ser
incorrecto; despu@'es de todo, la funci@'on fu@'e primero llamada por
alguien quien lo hab@'{@dotless{i}}a inventado.

El segundo y subsiguientes argumentos para @code{apply} son
opcionales, as@'{@dotless{i}} se puede usar @code{apply} para llamar a
una funci@'on y pasan los elementos de una lista, como este, que
tambi@'en devuelve 8:

@smallexample
(apply 'max '(4 8 5))
@end smallexample

Este camino tard@'{@dotless{i}}o usar@'a @code{apply}. La funci@'on
@code{recursive-lengths-list-many-files} devuelve una lista de
n@'umeros que se puede aplicar a @code{max} (se podr@'{@dotless{i}}a
tambi@'en aplicar @emph{(hacer apply)} a la lista de n@'umeros
ordenados; eso no importa si la lista est@'a o no).

@need 800
Aqu@'{@dotless{i}}, la operaci@'on para encontrar el tama@~no m@'aximo
del grafo es este:

@smallexample
(setq max-graph-height (apply 'max numbers-list))
@end smallexample

Ahora se puede devolver la pregunta de como crear una lista de cadenas
para una columna del grafo. Cuenta la m@'axima altura del grafo y el
n@'umero de asteriscos que aparecer@'{@dotless{i}}an en la columna, la
funci@'on devolver@'a una lista de cadenas para el comando a insertar
@code{insert-rectangle}.

Cada columna se realiza con asteriscos o espacios en blanco. Puesto que
la funci@'on pasa el valor del alto de la columna y el n@'umero de
asteriscos en el columna, el n@'umero de espacios en blanco puede ser
encontrado sustrayendo el n@'umero de asteriscos desde lo alto de la
columna. Dado el n@'umero de espacios en blanco y el n@'umero de
asteriscos, dos bucles @code{while} puede ser usado para construir la
lista:

@smallexample
@group
;;; @r{Primera versi@'on.}
(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)))
@end group

@group
    ;; @r{Llenar asteriscos.}
    (while (> actual-height 0)
      (setq insert-list (cons "*" insert-list))
      (setq actual-height (1- actual-height)))
@end group

@group
    ;; @r{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)))
@end group

@group
    ;; @r{Devuelve la lista completa.}
    insert-list))
@end group
@end smallexample

Si se instala esta funci@'on y entonces eval@'ua la siguiente
expresi@'on se ver@'a que devuelve la lista como se desea:

@smallexample
(column-of-graph 5 3)
@end smallexample

@need 800
@noindent
devuelve

@smallexample
(" " " " "*" "*" "*")
@end smallexample

Como est@'a escrito, @code{column-of-graph} contiene una grieta mayor:
los s@'{@dotless{i}}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@'a bien para un prototipo, pero tu, u
otro usuario, puede desear usar otros s@'{@dotless{i}}mbolos. Por
ejemplo, chequeando la funci@'on grafo, tu quieres usar un periodo en
vez del espacio, asegura el punto que est@'a siendo reposicionando
apropiadamente cada vez que la funci@'on @code{insert-rectangle} se
llama; o se podr@'{@dotless{i}}a querer sustituir un signo @samp{+} u
otro s@'{@dotless{i}}mbolo para el asterisco. Se podr@'{@dotless{i}}a
incluso querer hacer un graph-column que es m@'as que un ancho de
columna. El programa deber@'{@dotless{i}}a ser m@'as flexible. El
camino para hacer esto es reemplazar el espacio en blanco y el
asterisco con dos variables que se puede llamar @code{graph-blank} y
@code{graph-symbol} y define estas variables separadamente.

Tambi@'en la documentaci@'on no est@'a escrita. Estas consideraciones
nos llevan tambi@'en a la segunda versi@'on de la funci@'on:

@smallexample
@group
(defvar graph-symbol "*"
  "Cadena usada como s@'{@dotless{i}}mbolo en grafo, normalmente un asterisco.")
@end group

@group
(defvar graph-blank " "
  "La cadena como un espacio en blanco en grafo, normalmente un
  espacio en blanco.
graph-blank debe ser el mismo n@'umero de columnas amplio como graph-symbol.")
@end group
@end smallexample

@noindent
(Para una explicaci@'on de @code{defvar}, ver @ref{defvar, ,
Inicializando una Variable con @code{defvar}}.)

@smallexample
@group
;;; @r{Segunda versi@'on.}
(defun column-of-graph (max-graph-height actual-height)
  "Devuelve cadenas MAX-GRAPH-HEIGHT; ACTUAL-HEIGHT son
  s@'{@dotless{i}}mbolos de grafos.

@end group
@group
Los graph-symbols son entradas contiguo al fin de la lista. 
La lista ser@'a insertado como una columna de un grafo.
Las cadenas son tanto graph-blank o graph-symbol.
@end group

@group
  (let ((insert-list nil)
        (number-of-top-blanks
         (- max-graph-height actual-height)))
@end group

@group
    ;; @r{Rellenar en @code{graph-symbols}.}
    (while (> actual-height 0)
      (setq insert-list (cons graph-symbol insert-list))
      (setq actual-height (1- actual-height)))
@end group

@group
    ;; @r{Rellenar en @code{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)))

    ;; @r{Devuelve la lista completa.}
    insert-list))
@end group
@end smallexample

Si se desea, podr@'{@dotless{i}}amos reescribir @code{column-of-graph}
una tercera vez para proporcionar opcionalmente un gr@'afico de
l@'{@dotless{i}}neas, como gr@'afico de barras. Esto no
ser@'{@dotless{i}}a duro de hacer. Un camino para pensar en un grafo
de l@'{@dotless{i}}neas es que no es m@'as que un grafo de barras en
el que la parte de cada barra que est@'a debajo del alto es
blanco. Para construir una columna para gr@'afico de
l@'{@dotless{i}}neas, la funci@'on primero construyen una lista de
espacios en blanco que es una m@'as ordenada que el valor, entonces
usa @code{cons} para adjuntar un s@'{@dotless{i}}mbolo gr@'afico a la
lista; entonces eso usa @code{cons} de nuevo para adjuntar el `alto de
espacios en blanco' a la lista.

Es f@'acil ver como escribir tal funci@'on, pero puesto que no se
necesita eso, no se har@'a. Pero el trabajo podr@'{@dotless{i}}a ser
hecho, y si eso se hiciera, se har@'{@dotless{i}}a con
@code{column-of-graph}. Incluso m@'as importante, no se valora nada
m@'as que pocos cambios que tendr@'{@dotless{i}}an que ser hechos de
cualquier otra manera. La mejora, que se desea hacer, es simple.

Ahora, finalmente, volvemos a nuestra primera funci@'on de grafo
impresa. Esto imprime el cuerpo de un grafo, no las etiquetas para los
ejes horizontal y vertical, as@'{@dotless{i}} se puede llamar este
@code{graph-body-print}.

@node graph-body-print
@section La funci@'on @code{graph-body-print}
@findex graph-body-print

Despu@'es de nuestra preparaci@'on en la secci@'on precedente, la
funci@'on @code{graph-body-print} es simple. La funci@'on imprimir@'a
la columna despu@'es de la columna de asteriscos y espacios en blanco,
usando los elementos de la lista de n@'umeros para especificar el
n@'umero de asteriscos en cada columna. Esto es un acto repetitivo,
que significa que se puede usar un bucle @code{while} que decrementa o
una funci@'on recursiva para el trabajo. En esta secci@'on, se
escribir@'a la definici@'on usando un bucle @code{while}.

La funci@'on @code{column-of-graph} requiere el alto del grafo como un
argumento, as@'{@dotless{i}} se asigna y guarda esto como una variable
local.

Esto lidera a la siguiente plantilla para el bucle @code{while}
versi@'on de esta funci@'on:

@smallexample
@group
(defun graph-body-print (numbers-list)
  "@var{documentation}@dots{}"
  (let ((height  @dots{}
         @dots{}))
@end group

@group
    (while numbers-list
      @var{insert-columns-and-reposition-point}
      (setq numbers-list (cdr numbers-list)))))
@end group
@end smallexample

@noindent
Necesitamos rellenar los slots de la plantilla.

Claramente, se puede usar la expresi@'on @code{(apply 'max
numbers-list)} para determinar el alto del grafo.

El bucle @code{while} iterar@'a a trav@'es de @code{numbers-list} un
elemento a la vez. Como eso est@'a ordenado por la expresi@'on
@code{(setq numbers-list (cdr numbers-list))}, el @sc{car} de cada
instancia de la lista es el valor del argumento para @code{column-of-graph}.

En cada ciclo del bucle @code{while}, la funci@'on
@code{insert-rectangle} inserta la lista devuelta por
@code{column-of-graph}. Desde que la funci@'on
@code{insert-rectangle}, se necesita guardar la localizaci@'on de
punto al tiempo que el rect@'angulo se inserta, mueve atr@'as a esta
posici@'on despu@'es de que el rect@'angulo es insertado, y entonces
se mueve horizontalmente al siguiente lugar desde el que
@code{insert-rectangle} se llama.

Si las columnas se insertan en un car@'acter amplio, ser@'a si los
espacios en blanco y asteriscos se usan, el comando de reposici@'on
es simple @code{(forward-char 1)}; sin embargo, el ancho de una
columna puede ser m@'as grande que uno. Esto significa que el comando
de reposicionamiento ser@'{@dotless{i}}a escrito @code{(forward-char
symbol-width)}. El mejor lugar para asociar la variable
@code{symbol-width} al valor del width de la columna grafo est@'a en
la varlist de la expresi@'on @code{let}.

@need 1250
Estas consideraciones lideran a la siguiente definici@'on de funci@'on:

@smallexample
@group
(defun graph-body-print (numbers-list)
  "Imprime un gr@'afico 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)
@end group

@group
    (while numbers-list
      (setq from-position (point))
      (insert-rectangle
       (column-of-graph height (car numbers-list)))
      (goto-char from-position)
      (forward-char symbol-width)
@end group
@group
      ;; @r{Dibuja la columna del grafo por columna.}
      (sit-for 0)
      (setq numbers-list (cdr numbers-list)))
@end group
@group
    ;; @r{Emplaza el punto para etiquetas de ejes X.}
    (forward-line height)
    (insert "\n")
))
@end group
@end smallexample

@noindent
La expresi@'on inesperada en esta funci@'on es la expresi@'on
@w{@code{(sit-for
0)}} en el bucle @code{while}. Esta expresi@'on hace que el grafo
imprima la operaci@'on m@'as interesante para vigilar lo que
ser@'{@dotless{i}}a de otro modo. La expresi@'on causa que Emacs pare
(sit-for 0) para un momento cero y entonces redibuje la
pantalla. Puesto aqu@'{@dotless{i}}, eso causa que Emacs redibuje la
pantalla columna por columna. Sin eso, Emacs no
redibujar@'{@dotless{i}}a la pantalla hasta que la funci@'on exista.

Se puede chequear @code{graph-body-print} con una peque@~na lista de
n@'umeros.

@enumerate
@item
Instala @code{graph-symbol}, @code{graph-blank},
@code{column-of-graph}, que est@'an en
@iftex
@ref{Leyendo un grafo, , Leyendo un grafo},
@end iftex
@ifinfo
@ref{Columnas de un grafo},
@end ifinfo
and @code{graph-body-print}.

@need 800
@item
Copia la siguiente expresi@'on:

@smallexample
(graph-body-print '(1 2 3 4 6 4 3 5 7 6 5 2 3))
@end smallexample

@item
Cambia al b@'uffer @file{*scratch*} y emplaza el cursor donde quiere
que el grafo empiece.

@item
Escribe @kbd{M-:} (@code{eval-expression}).

@item
Pega la expresi@'on @code{graph-body-print} dentro del minib@'uffer con
@kbd{C-y} (@code{yank}).

@item
Presiona @key{RET} para evaluar la expresi@'on @code{graph-body-print}
@end enumerate

@need 800
Emacs imprimir@'a un grafo como este:

@smallexample
@group
                    *
                *   **
                *  ****
               *** ****
              ********* *
             ************
            *************
@end group
@end smallexample

@node recursive-graph-body-print
@section La funci@'on @code{recursive-graph-body-print}
@findex recursive-graph-body-print

La funci@'on @code{graph-body-print} puede tambi@'en ser escrito
recursivamente. La soluci@'on recursiva es dividida dentro de dos
partes: una fuera `wrapper' @emph{envoltorio} que usa una expresi@'on
@code{let} para determinar los valores varias variables que solo
necesitan ser encontradas una vez, tal como la m@'axima altura del
grafo, y una funci@'on dentro que es llamada recursivamente para
imprimir el grafo.

@need 1250
El `envoltorio' no es complicado:

@smallexample
@group
(defun recursive-graph-body-print (numbers-list)
  "Imprime un gr@'afico 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)))
@end group
@end smallexample

La funci@'on recursiva es un poco m@'as dif@'{@dotless{i}}cil. Eso
tiene cuatro partes: el `do-again-test', el c@'odigo impreso, la
llamada recursiva, y la `next-step-expression'. El `do-again-test' es
una expresi@'on @code{when} determina si la @code{numbers-list}
contiene cualquier elemento que permanece; si hace eso, la funci@'on
imprime una columna del grafo usando el c@'odigo impreso y se llama
as@'{@dotless{i}} mismo de nuevo. La funci@'on se llama as@'{@dotless{i}}
misma de nuevo de acuerdo al valor producido por la
`next-step-expression' que causa para llamar a actuar en una versi@'on
ordenada de la @code{numbers-list}.

@smallexample
@group
(defun recursive-graph-body-print-internal
  (numbers-list height symbol-width)
  "Imprime un gr@'afico de barras.
Usado con la funci@'on recursive-graph-body-print."
@end group

@group
  (when numbers-list
        (setq from-position (point))
        (insert-rectangle
         (column-of-graph height (car numbers-list)))
@end group
@group
        (goto-char from-position)
        (forward-char symbol-width)
        (sit-for 0)     ; @r{Dibuja un gr@'afico columna por columna.}
        (recursive-graph-body-print-internal
         (cdr numbers-list) height symbol-width)))
@end group
@end smallexample

@need 1250
Despu@'es de la siguiente instalaci@'on, esta expresi@'on puede ser
chequeada; aqu@'{@dotless{i}} hay un ejemplo:

@smallexample
(recursive-graph-body-print '(3 2 5 6 7 5 3 4 6 4 3 2 1))
@end smallexample

@need 800
Aqu@'{@dotless{i}} est@'a lo que @code{recursive-graph-body-print} produce:

@smallexample
@group
                *
               **   *
              ****  *
              **** ***
            * *********
            ************
            *************
@end group
@end smallexample

Cada una de estas dos funciones, @code{graph-body-print} o
@code{recursive-graph-body-print}, crea el cuerpo de un grafo.

@node Ejes Impresos
@section Necesidad para ejes impresos

Un grafo necesita ejes impresos, as@'{@dotless{i}} se puede orientar a
t@'{@dotless{i}} 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@'on que puede ser usada m@'as de una vez.

Por esta raz@'on, se han escrito mejoras a la funci@'on b@'asica
@code{print-graph-body} que autom@'aticamente 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@'on en un ap@'endice @xref{Grafo completo, , Un Grafo con
Ejes Etiquetados}.

@node Ejercicio de L@'{@dotless{i}}nea de Grafo
@section Ejercicio

Escribe una versi@'on de l@'{@dotless{i}}nea de grafo de la funciones
de impresi@'on del grafo.

@node Inicializaci@'on de Emacs
@chapter Tu fichero @file{.emacs}
@cindex fichero @file{.emacs}
@cindex Personalizando tu fichero @file{.emacs}
@cindex Fichero inicializaci@'on

``No te tiene que gustar Emacs para lo que te gusta'' --- esto que
parece una frase parad@'ojica es el secreto de GNU Emacs. En realidad,
Emacs es una herramienta gen@'erica. La mayor@'{@dotless{i}}a de la
gente que usa Emacs, lo personaliza para ajustarlo a sus necesidades.

GNU Emacs est@'a mayoritariamente escrito en Emacs Lisp; esto
significa que escribiendo expresiones en Emacs Lisp se puede modificar
o extender Emacs.

@menu
* Configuraci@'on por defecto::  Configuraci@'on por defecto
* Site-wide Init::           Se puede escribir site-wide ficheros init.
* defcustom::                Emacs escribir@'a c@'odigo para ti.
* Empezando un fichero .emacs::  C@'omo escribir un @code{fichero .emacs}.
* Texto y Autorelleno::      Corta l@'{@dotless{i}}neas autom@'aticamente.
* Alias de correo::          Usar abreviaciones para direcciones de correo 
                               electr@'onico.
* Indentar modo de tabulaciones::  No usar tabulaciones con @TeX{}
* Atajos de teclado::        Crear algunos atajos de teclado personales.
* Mapas de teclado::         M@'as acerca de atajos de teclado.
* Cargando ficheros::        Cargar (por ej. evaluar) ficheros 
                               autom@'aticamente.
* Autocarga::                Crear funciones disponibles.
* Extensi@'on simple::       Definir una funci@'on; enlazarla a una tecla.
* Colores X11::              Colores en X.
* Miscel@'anea::             Miscel@'anea
* Mode Line::                C@'omo personalizar tu mode line.
@end menu

@ifnottex
@node Configuraci@'on por defecto
@unnumberedsec Configuraci@'on por defecto de Emacs
@end ifnottex

Hay quien aprecia la configuraci@'on por defecto de Emacs. Despu@'es
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@'a yendo a usar
Emacs. @questiondown{}Qui@'en 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@'odigo C. (Suficientes lenguajes de programaci@'on tienen
sintaxis que permiten compartir funcionalidades, tal como el modo C es
ahora proporcionado por el modo CC, la `Colecci@'on C'.)

Pero cuando se conoce quien est@'a 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@'{@dotless{i}} eso se ajusta a
m@'{@dotless{i}}.

Se puede personalizar y extender Emacs escribiendo o adaptando un
fichero @file{~/.emacs}. Esto es un fichero de inicializaci@'on
personal; sus contenidos, escritos en Emacs Lisp, cuentan a Emacs qu@'e
hacer.@footnote{Tu puedes tambi@'en a@~nadir @file{.el} para
@file{~/.emacs} y llama a un fichero @file{~/.emacs}. En el pasado,
fu@'e prohibido escribir los atajos de teclado extra que el nombre
@file{~/.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.}

Un fichero @file{~/.emacs} contiene c@'odigo Emacs Lisp. Se puede
escribir este c@'odigo por uno mismo; o se puede usar la funcionalidad
@code{customize} para escribir el c@'odigo para ti. Se puede combinar
tus propias expresiones y expresiones auto-escritas personalizadas en
tu fichero @file{.emacs}.

(Yo prefiero por m@'{@dotless{i}} mismo escribir mis propias
expresiones, excepto para estas, fuentes particularmente, que se
encuentran f@'aciles de manipular usando el comando
@code{customize}. Yo combino los dos m@'etodos.)

La mayor@'{@dotless{i}}a de este cap@'{@dotless{i}}tulo es acerca de
escribir expresiones por uno mismo. Eso describe un fichero
@file{.emacs} simple; para m@'as informaci@'on, mira @ref{Fichero de
Inicio, , El Fichero de Inicio, emacs, El Manual GNU Emacs}, y la
@ref{Fichero de Inicio, , El Fichero de Inicio, elisp, El Manual de
Referencia GNU Emacs Lisp}.

@node Site-wide Init
@section Fichero de inicializaci@'on site-wide

@cindex fichero de inicio @file{default.el}
@cindex fichero inicio @file{site-init.el}
@cindex fichero @file{site-load.el}
Adem@'as de tu fichero de inicializaci@'on personal, Emacs
autom@'aticamente carga varios ficheros de inicializaci@'on amplios,
si existen. Tienen la misma forma que tu fichero @file{.emacs}, pero
se cargan por cualquiera.

Dos ficheros de incializaci@'on, @file{site-load.el} y
@file{site-init.el}, est@'an cargados dentro de Emacs y volcados
@emph{dumped} sin una versi@'on dumped de Emacs se cre@'o, como es
m@'as com@'un. (Las copias dumped de Emacs cargan m@'as
r@'apidamente. 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. @xref{Construyendo Emacs, ,
Construyendo Emacs, elisp, El Manual de Referencia de GNU Emacs Lisp},
y el fichero @file{INSTALL})

Los otros tres ficheros de inicializaci@'on se cargan
autom@'aticamente cada vez que se inicia Emacs, si existen. Son
@file{site-start.el}, que se carga @emph{antes} que tu fichero
@file{.emacs}, y @file{default.el}, y el tipo de fichero terminal, que
se cargan @emph{despu@'es} de tu fichero @file{.emacs}.

Las configuraciones y definiciones en tu fichero @file{.emacs}
sobreescribir@'an las configuraciones en conflicto y definiciones en
un fichero @file{site-start.el}, si eso existe; pero las
configuraciones y definiciones en un @file{default.el} o el tipo de
fichero terminal sobreescribir@'a estos en tu fichero
@file{.emacs}. (Se pueden prevenir interferencias desde un tipo de
fichero terminal configurando @code{term-file-prefix} para
@code{nil}. @xref{Extensi@'on simple, , Una extensi@'on simple}.)

@c Rewritten to avoid overfull hbox.
El fichero @file{INSTALL} que viene en la distribuci@'on contiene
descripciones de los fichero @file{site-init.el} y @file{site-load.el}.

Los ficheros @file{loadup.el}, @file{startup.el}, y @file{loaddefs.el}
controlan la carga. Estos ficheros est@'an en el directorio
@file{lisp} de la distribuci@'on Emacs y tiene valor de uso.

El fichero @file{loaddefs.el} contiene buenas sugerencias como las que
poner dentro de tu propio fichero @file{.emacs}, o dentro de un
fichero de inicializaci@'on amplio.

@node defcustom
@section Especificar variables usando @code{defcustom}
@findex defcustom

Se pueden especificar variables usando @code{defcustom}
as@'{@dotless{i}} que la gente pueda usar la funcionalidad de
Emacs @code{customize} para asignar sus valores. (No se puede usar
@code{customize} para escribir definiciones de funci@'on; pero se
pueden escribir @code{defuns} en tu fichero @file{.emacs}. En vez de
eso, se puede escribir cualquier expresi@'on Lisp en tu fichero
@file{.emacs}).

La funcionalidad @code{customize} depende de la forma especial
@code{defcustom}. Aunque se puede usar @code{defvar} o @code{setq}
para las variables que los usuarios asignan, la forma especial
@code{defcustom} est@'a dise@~nada para el trabajo.

Se puede usar tu conocimiento de @code{defvar} para escribir los
primeros tres argumentos para @code{defcustom}. El primer argumento
para @code{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@'on.

El cuarto y subsiguientes argumentos para @code{defcustom} especifican
los tipos y opciones; estos no son funcionales en @code{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
@samp{:}.

@need 1250
Por ejemplo, la variable de opciones personalizable
@code{text-mode-hook} se parece a esto:

@smallexample
@group
(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)
@end group
@end smallexample

@noindent
El nombre de la variable es @code{text-mode-hook}; no tiene valor por
defecto; y su cadena de documentaci@'on cuenta lo que hace.

La palabra clave @code{:type} le cuenta a Emacs el tipo de datos para
los que @code{text-mode-hook} ser@'{@dotless{i}}a asignado y como
muestra el valor en un b@'uffer de Personalizaci@'on.

La palabra clave @code{:options} especifica una lista sugerida de
valores para la variable. Normalmente, @code{:options} se asocia a un
gancho (@emph{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
@code{:options} se pretende ofrecer elecciones convenientes a un
usuario.

Finalmente, la palabra clave @code{:group} cuenta el comando de
Personalizaci@'on de Emacs en el que el grupo de la variable est@'a
localizado. Esto cuenta d@'onde encontralo.

La funci@'on @code{defcustom} reconoce m@'as de una docena de palabras
clave. Para m@'as informaci@'on, mire @ref{Personalizaci@'on, ,
Escribiendo las Definiciones de Personalizaci@'on, elisp, El Manual de
Referencia GNU Emacs Lisp}.

Considere @code{text-mode-hook} como un ejemplo.

Hay dos caminos para personalizar esta variable. Se puede usar el
comando de personalizaci@'on o escribir las expresiones apropiadas por
uno mismo.

@need 800
Usando el comando de personalizaci@'on, se puede escribir:

@smallexample
M-x customize
@end smallexample

@noindent
y encuentre que el grupo para editar ficheros de datos se llama
`datos'. Introduzca este grupo. El Hook @emph{Disparador} es el primer
miembro. Se puede hacer click en sus opciones varias, tal como
@code{turn-on-auto-fill}, para asignar los valores. Despu@'es de hacer
click en el bot@'on.

@smallexample
Gu@'ardalo para Futuras Sesiones
@end smallexample

@noindent
Emacs escribir@'a una expresi@'on en tu fichero @file{.emacs}. Se
parecer@'a a esto:

@smallexample
@group
(custom-set-variables
  ;; custom-set-variables fu@'e a@~nadido por Custom.
  ;; Si se edita a mano, tu podr@'{@dotless{i}}as liarte,
  ;; as@'{@dotless{i}} que ten cuidado.
  ;; Tu fichero init contendr@'{@dotless{i}}a solo esta instancia.
  ;; Si hay m@'as de uno, ellos no quieren trabajar.
 '(text-mode-hook (quote (turn-on-auto-fill text-mode-hook-identify))))
@end group
@end smallexample

@noindent
(La funci@'on @code{text-mode-hook-identify} cuenta
@code{toggle-text-mode-auto-fill} que buffers hay en modo Texto.  Eso
viene autom@'aticamente)

La funci@'on @code{custom-set-variables} funciona de alguna manera
diferente m@'as de un @code{setq}. Mientras yo nunca he aprendido las
diferencias, yo modifico las expresiones @code{custom-set-variable} en
mi fichero @file{.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@'on y
permitir a Emacs hacer el trabajo para ellos.

Otra funci@'on @code{custom-set-@dots{}} es
@code{custom-set-faces}. Esta funci@'on asigna varios tipos de
fuentes. A trav@'es del tiempo, yo he asignado un considerable
n@'umero de tipos. Algo de tiempo, yo las reseteo usando
@code{customize}; otras veces, simplemente edito la expresi@'on
@code{custom-set-faces} en mi fichero @file{.emacs} en s@'{@dotless{i}}.

El segundo modo de personalizar tu @code{text-mode-hook} es asignarte
a t@'{@dotless{i}} mismo en tu fichero @file{.emacs} usando c@'odigo
que no tiene nada que hacer con las funciones @code{custom-set-@dots{}}.

@need 800
Cuando se hace esto, y despu@'es usa @code{customize}, se ver@'a un
mensaje que dice:

@smallexample
CHANGED fuera de Personalizar; operando dentro aqu@'{@dotless{i}}
puede ser no confiable.
@end smallexample

@need 800
Este mensaje es solo un aviso. Si se puede cliquear en el bot@'on a

@smallexample
Gu@'ardalo para Futuras Sesiones
@end smallexample

@noindent
Emacs escribir@'a una expresi@'on @code{custom-set-@dots{}} cerca del
fin de tu fichero @file{.emacs} que ser@'a evaluado despu@'es de que
tu expresi@'on sea escrita a mano. Por esta raz@'on, se
sobreescribir@'a tu expresi@'on escrita a mano. Ning@'un da@~no ser@'a
hecho. Cuando se haga esto, sin embargo, ten cuidado para recordar que
expresi@'on est@'a activa; si olvidas, puedes confundirte por
t@'{@dotless{i}} mismo.

Tan largo como se recuerda donde los valores son configurados, no
habr@'a problemas. En cualquier eventos, los valores son siempre
configurados en tu fichero de inicializaci@'on, que es normalmente
llamado @file{.emacs}.

Yo mismo hago un @code{customize} para cualquier
cosa. Mayoritariamente, escribo expresiones por m@'{@dotless{i}}
mismo.

@findex defsubst
@findex defconst
Incidentalmente, para ser una definici@'on concerniente m@'as
completa: @code{defsubst} define una funci@'on inline. La sintaxis es
solo como esta de @code{defun}. @code{defconst} define un
s@'{@dotless{i}}mbolo como una constante. El intento es que ning@'un
programa o usuario cambiar@'{@dotless{i}}an un valor asignado por
@code{defconst}. (Se puede cambiar; el valor asignado es una variable;
pero por favor no lo haga.)

@node Empezando un fichero .emacs
@section Empieza por un fichero @file{.emacs}
@cindex fichero @file{.emacs}, empezando

Cuando se abre Emacs, se carga tu fichero @file{.emacs} a menos que
se cuente que no se especifique @samp{-q} en la l@'{@dotless{i}}nea de
comandos. (El comando @code{emacs -q} tu da un Emacs plano, fuera.)

Un fichero @file{.emacs} contiene expresiones Lisp. Con frecuencia, no
hay m@'as expresiones para configura valores; algunas veces esas son
definiciones de funciones.

@xref{Fichero de Inicio, , El Fichero de Inicio @file{~/.emacs},
emacs, El Manual GNU Emacs}, para una corta descripci@'on de fichero
de inicializaci@'on.

Este cap@'{@dotless{i}}tulo cubre algo del mismo suelo, pero es un
paseo entre extractos desde un completo, largamente usado fichero
@file{.emacs} --- por m@'{@dotless{i}}.

La primera parte del fichero consiste en comentario: me recuerdo a
m@'{@dotless{i}} mismo. Por ahora, yo recuerdo estas cosas, pero
cuando empec@'e, no.

@need 1200
@smallexample
@group
;;;; fichero .emacs de Bob
; Robert J. Chassell
; 26 de Septiembre de 1985
@end group
@end smallexample

@noindent
@exclamdown{}Mira en esta fecha! Yo empec@'e este fichero hace mucho
tiempo. Yo he estado a@~nadiendo cosas desde siempre.

@smallexample
@group
; Cada secci@'on en este fichero es introducido por una
; l@'{@dotless{i}}nea empezando con cuatro puntos y comas y cada
; entrada es introducida por una l@'{@dotless{i}}nea empezando con
; tres puntos y comas.
@end group
@end smallexample

@noindent
Esto describe las convenciones usuales para comentarios en Emacs
Lisp. Cada cosa en una l@'{@dotless{i}}nea que sigue un punto y coma
es un comentario. Dos, tres, y cuatro puntos y coma son usados como
subsecci@'on y marcas de secci@'on. (@xref{Comentarios, ,, elisp, El
Manual de Referencia GNU Emacs Lisp}, para m@'as comentarios.)

@smallexample
@group
;;;; La Tecla de Ayuda
; Control-h es la tecla de ayuda;
; despu@'es escribiendo control-h, escribe una letra a
; indica el asunto acerca del que quieres ayuda.
; Para una explicaci@'on de la facilidad de ayuda,
; escribe control-h dos veces en una fila.
@end group
@end smallexample

@noindent
Solo recuerda: escribe @kbd{C-h} dos veces para ayudar.

@smallexample
@group
; Para informarse acerca de cualquier modo, escribe control-h m
; mientras est@'e en este modo. Por ejemplo, para encontrar
; acerca del modo correo, introduce el modo correo y entonces
; escribe control-h m.
@end group
@end smallexample

@noindent
`Modo ayuda', como yo llamo a esto, es muy @'util. Usualmente, se
cuenta todo lo que se necesita saber.

De acuerdo, no se necesitan incluir comentarios y ficheros como estos
@file{.emacs}. Yo los inclu@'{@dotless{i}} en el m@'{@dotless{i}}o
porque se olvida el Modo ayuda o las convenciones para comentarios ---
pero era capaz de recordar ver aqu@'{@dotless{i}} record@'armelo a
m@'{@dotless{i}} mismo.

@node Texto y Autorelleno
@section Modo texto y auto relleno

Ahora regresa a la parte que `vuelve' al modo Texto y modo Auto Relleno.

@smallexample
@group
;;; Modo texto modo Auto Fill
;; Las siguiente dos l@'{@dotless{i}}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@'odigo.
(setq-default major-mode 'text-mode)
(add-hook 'text-mode-hook 'turn-on-auto-fill)
@end group
@end smallexample

@exclamdown{}Aqu@'{@dotless{i}} est@'a la primera parte de este
fichero @file{.emacs} que hace alguna cosa bajo recuerdo de un humano
olvidado!

La primera de las dos l@'{@dotless{i}}neas entre par@'entesis cuentan a
Emacs a cambiar al modo Texto que se encuentra un fichero, @emph{a menos
que} el fichero ir@'{@dotless{i}}a dentro de alg@'un otro modo, tal
como el modo C.

@cindex Por b@'uffer, lista de variables locales
@cindex Lista de variables locales, por b@'uffer,
@cindex Selecci@'on de modo autom@'atico
@cindex Modo de selecci@'on, autom@'atico
Cuando Emacs lee un fichero, eso parece la extensi@'on al nombre del
fichero. (La extensi@'on es la parte que viene despu@'es de un
@samp{.}.) Si el fichero finaliza con una extensi@'on @samp{.c} o
@samp{.h} entonces Emacs cambia al modo C. Tambi@'en, Emacs parece al
principio una l@'{@dotless{i}}nea no blanca del fichero; si la
l@'{@dotless{i}}nea dice @w{@samp{-*- C -*-}}, Emacs cambia al modo
C. Emacs posee una lista de extensiones y especificaciones que usa
autom@'aticamente. Adem@'as, Emacs se ve cerca de la @'ultima p@'agina
por buffer, ``lista variables locales''.

@ifinfo
@xref{Eligiendo Modos, , Como los Modos Mayores son Elegidos, emacs,
El Manual GNU Emacs}.

@xref{Variables de Fichero, , Variables Locales en Ficheros, emacs, El
Manual de GNU Emacs}.
@end ifinfo
@iftex
Mira las secciones ``C@'omo los Modos Mayores son Elegidos'' y
``Variables Locales en Fichero'' en @cite{El Manual GNU Emacs}.
@end iftex

Ahora, regresa al fichero @file{.emacs}.

@need 800
Aqu@'{@dotless{i}} est@'a la l@'{@dotless{i}}nea de nuevo;
@questiondown{}c@'omo funciona?

@cindex Modo Texto activado
@smallexample
(setq major-mode 'text-mode)
@end smallexample

@noindent
Esta l@'{@dotless{i}}nea es un resumen, pero completa la expresi@'on
Emacs Lisp.

Ya estamos familiarizados con @code{setq}. Eso asigna la siguiente
variable, @code{major-mode}, al subsiguiente valor, que es
@code{text-mode}. La marca de cita simple antes de @code{text-mode}
cuenta a Emacs como tratar directamente con el s@'{@dotless{i}}mbolo,
no con cualquier cosa que pudiera existir. @xref{set y setq, ,
Configurando el Valor de una Variable}, por un recuerdo de como
@code{setq} funciona. El principal punto es que no hay diferencia
entre el procedimiento que se usa para asignar un valor en su fichero
@file{.emacs} y el procedimiento que se usa en cualquier lugar m@'as
en Emacs.

@need 800
Aqu@'{@dotless{i}} est@'a la siguiente l@'{@dotless{i}}nea:

@cindex Modo de autoajuste activado
@findex add-hook
@smallexample
(add-hook 'text-mode-hook 'turn-on-auto-fill)
@end smallexample

@noindent
En esta l@'{@dotless{i}}nea, el comando @code{add-hook} a@~nade
@code{turn-on-auto-fill} para la variable.

@exclamdown{}@code{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@'{@dotless{i}} que cada vez que
Emacs cambia al modo Texto, Emacs tambi@'en cambia al modo de
autoajuste.

En breve, la primera l@'{@dotless{i}}nea causa a Emacs a entrar en
modo Texto cuando se edite un fichero, a menos que la extensi@'on del
nombre del fichero, una l@'{@dotless{i}}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@'ostrofe como parte de una palabra como una letra; pero Emacs no
considera un per@'{@dotless{i}}odo o un espacio como parte de una
palabra. De este modo, @kbd{M-f} se mueve hacia t@'{@dotless{i}} a
trav@'es de @samp{eso}. Por otro lado, en modo C, @kbd{M-f} para solo
despu@'es del @samp{t} de @samp{eso}.

La segunda l@'{@dotless{i}}nea causa que Emacs active el modo Auto
Fill cuando cambia al modo Texto. En modo Auto Fill, Emacs
autom@'aticamente rompe una l@'{@dotless{i}}nea que es demasiado
amplio y trae la parte excesivamente amplia de la l@'{@dotless{i}}nea
de debajo a la siguiente l@'{@dotless{i}}nea. Emacs rompe
l@'{@dotless{i}}neas entre palabras con ellas.

Cuando el modo Auto Fill est@'a desactivado, las l@'{@dotless{i}}neas
contin@'uan a la derecha como se escriben. Dependiendo de como
configuras el valor de @code{truncate-lines}, las palabras que se
escribe si desaparecen al lado derecho de la pantalla, o lo dem@'as
son mostradas, en un modo feo e ilegible, como una l@'{@dotless{i}}nea
de continuaci@'on en la pantalla.

@need 1250
Adem@'as, en esta parte de mi fichero @file{.emacs}, yo cuento a Emacs
el ajuste de comandos para insertar dos espacios despu@'es de dos
puntos:

@smallexample
(setq colon-double-space t)
@end smallexample

@node Alias de correo
@section Alias de correo

Aqu@'{@dotless{i}} hay un @code{setq} que `activa' el alias de correo,
para m@'as ocasiones.

@smallexample
@group
;;; 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)
@end group
@end smallexample

@cindex Alias de correo
@noindent
Este comando @code{setq} asigna el valor de la variable
@code{mail-aliases} al @code{t}. Desde que @code{t} significa cierto,
la l@'{@dotless{i}}nea dice, en efecto, ``S@'{@dotless{i}} 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 @file{~/.mailrc}. Se escribe
un alias como este:

@smallexample
alias geo george@@foobar.wiz.edu
@end smallexample

@noindent
Cuando se escribe un mensaje a Jorge, la direcci@'on a @samp{geo}; el
correo autom@'aticamente expandir@'a @samp{geo} a la direcci@'on completa.

@node Indentar modo de tabulaciones
@section Indentar modo de tabulaciones
@cindex Tabuladores, previniendo
@findex indent-tabs-mode

Por defecto, Emacs inserta tabulaciones en lugar en m@'ultiples
espacios cuando se formatea una regi@'on. (Por ejemplo, se
podr@'{@dotless{i}}an indentar muchas l@'{@dotless{i}}neas de texto
todo a la vez con el comando @code{indent-region}.) Los tabuladores se
ven bien en un terminal o con impresi@'on ordinaria, pero ellos
producen mala salida de indentaci@'on cuando se usa @TeX{} o Texinfo
puesto que @TeX{} ignora tabuladores.

@need 1250
Lo siguiente desactiva el modo de Indentar Tabulaciones:

@smallexample
@group
;;; Prevenir Tabulaciones Extra@~nas
(setq-default indent-tabs-mode nil)
@end group
@end smallexample

Note que esta l@'{@dotless{i}}nea usa @code{setq-default} en vez de el
comando @code{setq} que hemos visto antes. El comando
@code{setq-default} asigna valores solo en b@'uffers que no tienen sus
propios valores locales para la variable.

@ifinfo
@xref{Solo Espacios, Tabuladores versus Espacios, emacs, El Manual de GNU
Emacs}.

@xref{Variables de Fichero, , Variables Locales en Ficheros, emacs, El
Manual de GNU Emacs}.
@end ifinfo
@iftex
Ver secciones ``Tabuladores versus Espacios'' y ``Variables Locales en
Ficheros'' en @cite{El Manual de GNU Emacs}.
@end iftex

@need 1700
@node Atajos de teclado
@section Algunos atajos

Ahora para algunos atajos personales:

@smallexample
@group
;;; Compara ventanas
(global-set-key "\C-cw" 'compare-windows)
@end group
@end smallexample

@findex compare-windows
@code{compare-windows} es un comando excelente que compara el texto en
tu ventana actual con texto de la siguiente ventana. Eso hace la
comparaci@'on empezando al punto en cada ventana, moviendo a trav@'es
del texto en cada ventana tan lejos como ellos asocian. Yo uso este
comando todo el tiempo.

Esto tambi@'en muestra como configurar una tecla globalmente, para
todo los modos

@cindex Configurando una tecla globalmente
@cindex Asignar tecla global
@cindex Asignando tecla globalmente
@findex global-set-key
El comando es @code{global-set-key}. Es seguido por el atajo. En un
fichero @file{.emacs}, el atajo es escrito como se ve: @code{\C-c} que
se asocia a `control-c', que significa `presionar la tecla de control
y la tecla @key{c} al mismo tiempo'. La @code{w} significa `presionar
la tecla @key{w}'. El atajo es rodeado por dobles comillas. En la
documentaci@'on, se escribir@'{@dotless{i}}a esto como @w{@kbd{C-c
w}}. (Si estuviera asociando una tecla @key{META}, tal como @kbd{M-c},
en vez de una tecla de @key{CTRL}, se escribir@'{@dotless{i}}a
@w{@code{\M-c}} en su fichero @file{.emacs}. @xref{Reasociando Init, ,
Reasociando Teclas en Su Fichero Init, emacs, El Manual de GNU Emacs},
para m@'as detalles.)

El comando invocado por las teclas es @code{compare-windows}. Note que
@code{compare-windows} es precedido por una comilla simple; de otro
modo, Emacs primero intentar@'{@dotless{i}}a evaluar el
s@'{@dotless{i}}mbolo para determinar su valor.

Estas tres cosas, las marcas de dobles comillas, la barra invertida
antes de la @samp{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@'{@dotless{i}}a mi fichero
@file{.emacs} existente, y lo adaptar@'{@dotless{i}}a a lo que hay.

Como para el atajo en s@'{@dotless{i}}: @kbd{C-c w}, combina la tecla
prefija, @kbd{C-c}, con un caracter simple, en este caso,
@kbd{w}. Este conjunto de teclas, @kbd{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@'{@dotless{i}}a capaz de crear tal atajo
para el uso propio sin pisar fuerte en alg@'un atajo m@'as. Si siempre
se escribe una extensi@'on a Emacs, por favor, evite tomar cualquiera
de estas teclas para uso p@'ublico. Se cree que una tecla como
@kbd{C-c C-w} en vez de eso. De otra manera, ejecutar@'a sin sus
`propias' teclas.

@need 1250
Aqu@'{@dotless{i}} hay otro atajo, con un comentario:

@smallexample
@group
;;; Atajo para `occur'
; Yo uso mucho occur, as@'{@dotless{i}} permite asignarlo a una tecla:
(global-set-key "\C-co" 'occur)
@end group
@end smallexample

@findex occur
El comando @code{occur} muestra todas las l@'{@dotless{i}}neas en el
buffer actual que contiene un emparejamiento para una expresi@'on
regular. Asociar las l@'{@dotless{i}}neas que se muestran en un
b@'uffer llamado @file{*Occur*}. Este buffer sirve como un menu para
saltar a ocurrencias.

@findex global-unset-key
@cindex Disociando la tecla
@cindex Desasociar Tecla a Comando
@need 1250
Aqu@'{@dotless{i}} se muestra como desasignar una tecla,
as@'{@dotless{i}} no funciona:

@smallexample
@group
;;; Desasociar `C-x f'
(global-unset-key "\C-xf")
@end group
@end smallexample

Hay una raz@'on para esta no asociaci@'on: Yo encontr@'e
inadvertidamente escrito @w{@kbd{C-x f}} cuando signific@'o escribir
@kbd{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@~no que no quer@'{@dotless{i}}a. Puesto que duramente se
resete@'o mi ancho por defecto, yo simplemente disoci@'e la tecla.

@findex list-buffers, @r{reasociar}
@findex buffer-menu, @r{asociado a tecla}
@need 1250
Lo siguiente reasocia una tecla existente:

@smallexample
@group
;;; Reasocia `C-x C-b' al `buffer-menu'
(global-set-key "\C-x\C-b" 'buffer-menu)
@end group
@end smallexample

Por defecto, @kbd{C-x C-b} ejecute el comando
@code{list-buffers}. Este comando lista sus buffers en @emph{otra}
ventana. Desde que casi siempre se quiere hacer alguna cosa en esta
ventana, se prefiere el comando @code{buffer-menu}, que no solo lista
los buffers, pero mueve el punto dentro de esta ventana.

@node Mapas de teclado
@section Mapas de teclado
@cindex Mapas de teclado
@cindex Reasociando teclas

Emacs usa @dfn{keymaps} para grabar qu@'e teclas llaman a qu@'e
comandos. Cuando se use @code{global-set-key} para asignar los atajos
de teclados a un simple comando en todo @code{current-global-map}.

Modos espec@'{@dotless{i}}ficos, tales como modo C o modo Texto, tiene
sus propios mapas de teclado; mapas de teclado de modo
espec@'{@dotless{i}}fico sobreescribe el mapa global que es compartido
por todos los buffers.

La funci@'on @code{global-set-key} asocia, o reasocia, el mapa de
teclado global. Por ejemplo, las siguientes asociaciones la tecla
@kbd{C-x C-b} a la funci@'on @code{buffer-menu}:

@smallexample
(global-set-key "\C-x\C-b" 'buffer-menu)
@end smallexample

Mapas de teclado espec@'{@dotless{i}}fico de modo son asociados usando
la funci@'on @code{define-key}, que toma un mapa de teclado
espec@'{@dotless{i}}fico como un argumento, tan bien como la tecla y
el comando. Por ejemplo, mi fichero @file{.emacs} contiene la
siguiente expresi@'on asociada al comando
@code{texinfo-insert-@@group} comando a @kbd{C-c C-c g}:

@smallexample
@group
(define-key texinfo-mode-map "\C-c\C-cg" 'texinfo-insert-@@group)
@end group
@end smallexample

@noindent
La funci@'on @code{texinfo-insert-@@group} en s@'{@dotless{i}} es una
peque@~na extensi@'on del modo Texinfo que inserta @samp{@@group} dentro
de un fichero Texinfo. Se usa este comando todo el tiempo y se prefieren
escribir los tres atajos @kbd{C-c C-c g} en vez de los seis atajos
@kbd{@@ g r o u p}. (@samp{@@group} y su asociaci@'on @samp{@@end
group} son comandos que guarda todo el texto cerrado junto a una
p@'agina; muchos ejemplos multi-l@'{@dotless{i}}nea en este libro
est@'an rodeados por @samp{@@group @dots{} @@end group}.)

@need 1250
Aqu@'{@dotless{i}} est@'a la definici@'on de funci@'on
@code{texinfo-insert-@@group}:

@smallexample
@group
(defun texinfo-insert-@@group ()
  "Inserta la cadena @@group en un b@'uffer Texinfo."
  (interactive)
  (beginning-of-line)
  (insert "@@group\n"))
@end group
@end smallexample

(De acuerdo, podr@'{@dotless{i}}a haber usado el modo Abbrev para
dejar de escribir, en vez de escribir una funci@'on para insertar una
palabra; pero prefiero atajos de teclado consitentes con otro modo
Texinfo para atajos de teclado.)

Ver@'a numerosas expresiones @code{define-key} en @file{loaddefs.el}
tan bien como en varios modos de librer@'{@dotless{i}}as, tal como
@file{cc-mode.el} y @file{lisp-mode.el}.

@xref{Atajos de Teclado, , Personalizando Atajos de Teclado, emacs, El
Manual  GNU Emacs}, y @ref{Mapas de Teclado, , Mapas de Teclado,
elisp, El Manual de Referencia GNU Emacs Lisp}, para m@'as
informaci@'on acerca de mapas de teclado.

@node Cargando ficheros
@section Cargando ficheros
@cindex Cargando ficheros
@c findex load

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 @emph{releases}. Por ejemplo, los paquetes
Calendario y Diario son ahora parte del est@'andar GNU Emacs, como es Calc.

Se puede usar un comando @code{load} para evaluar un fichero completo
que significa instalar todas las funciones y variables en el fichero
Emacs. Por ejemplo:

@c (auto-compression-mode t)

@smallexample
(load "~/emacs/slowsplit")
@end smallexample

Esto eval@'ua, por ej.@: carga, el fichero @file{slowsplit.el} o si
eso existe, lo m@'as r@'apido, el fichero compilado
@file{slowsplit.elc} desde el subdirectorio @file{emacs} del
directorio home. El fichero contiene la funci@'on
@code{split-window-quietly}, que John Robinson escribi@'o en 1989.

La funci@'on @code{split-window-quietly} divide una ventana con el
m@'{@dotless{i}}nimo de redisplay. Yo lo instal@'e en 1989 porque
trabaj@'o bien con los terminales de 1200 baudios que entonces estaba
usando. Ahora, ocasionalmente vengo a trav@'es de una conexi@'on
lenta, pero contin@'ua usando la funci@'on porque me gusta el camino
que deja arriba del b@'uffer en el bajo de las nuevas ventanas y
arriba en la ventana superior. 

@need 1250
Para reemplazar el atajo de teclado por defecto
@code{split-window-vertically}, se debe tambi@'en desasignar esta
tecla y asociar las teclas a @code{split-window-quietly}, como este:

@smallexample
@group
(global-unset-key "\C-x2")
(global-set-key "\C-x2" 'split-window-quietly)
@end group
@end smallexample

@vindex load-path
Si se cargan muchas extensiones, como yo hago, entonces en vez de
especificar la posici@'on exacta del fichero, como se muestra arriba,
se puede especificar que directorio como parte del @code{load-path} de
Emacs. Entonces, cuando Emacs carga un fichero, buscar@'a que
directorio tan bien como su lista por defecto de directorios. (La
lista por defecto es especificada en @file{paths.h} cuando Emacs se
construye.)

@need 1250
El comando siguiente a@~nade tu directorio @file{~/emacs} a la ruta
existente:

@smallexample
@group
;;; Ruta Emacs
(setq load-path (cons "~/emacs" load-path))
@end group
@end smallexample

Incidentalmente, @code{load-library} es un interfaz interactivo a la
funci@'on @code{load}. La funci@'on se parece a esto:

@findex load-library
@smallexample
@group
(defun load-library (library)
  "Carga la librer@'{@dotless{i}}a llamada LIBRARY.
Esto es una interfaz a la funci@'on `load'."
  (interactive
   (list (completing-read "Carga la librer@'{@dotless{i}}a: "
                          (apply-partially 'locate-file-completion-table
                                           load-path
                                           (get-load-suffixes)))))
  (load library))
@end group
@end smallexample

El nombre de la funci@'on, @code{load-libray}, viene desde el uso de
`library' como un sin@'onimo para `file'. La fuente para el comando
@code{load-library} est@'a en la librer@'{@dotless{i}}a @file{files.el}.

Otro comando interactivo que hace un trabajo ligeramente diferente es
@code{load-file}. @xref{Librer@'{@dotless{i}}as Lisp, ,
Librer@'{@dotless{i}}as de C@'odigo Lisp para Emacs, emacs, El Manual
GNU Emacs}, para informaci@'on en la distinci@'on entre
@code{load-library} y este comando.

@node Autocarga
@section Autoloading
@findex autoload

En vez de instalar una funci@'on cargando el fichero que lo contiene,
o evaluando la definici@'on de funci@'on, se puede hacer la funci@'on
disponible pero actualmente no se instala hasta la primera vez
llamada. Este proceso se llama @dfn{autocarga} (@emph{autoloading}).

Cuando se ejecuta una funci@'on de autocarga, Emacs autom@'aticamente
eval@'ua el fichero que contiene la definici@'on, y entonces llama a
la funci@'on.

Emacs empieza r@'apido con funciones de autocarga, puesto que sus
librer@'{@dotless{i}}as no se cargan bien; pero si necesita esperar un
momento cuando su primer uso tal como una funci@'on, mientras que el
fichero que lo contiene se eval@'ua.

Raramente las funciones usadas son frecuentemente autocargadas. La
librer@'{@dotless{i}}a @file{loaddefs.el} coniene cientos de funciones
autocargadas, desde @code{bookmark-set} a @code{wordstar-mode}. Si se
usa una funci@'on `rara' frecuentemente, se deber@'{@dotless{i}}a
cargar este fichero de funci@'on con una expresi@'on de @code{load} en
tu fichero @file{.emacs}.

En mi fichero @file{.emacs}, se cargan 14 librer@'{@dotless{i}}as que
contienen funciones que de otro modo ser@'{@dotless{i}}an
autocargadas. (Actualmente, eso habr@'{@dotless{i}}a sido mejor para
incluir estos ficheros en mi Emacs `volcado', pero se
olvida. @xref{Construyendo Emacs, , Construyendo Emacs, elisp, El
Manual de Referencia GNU Emacs Lisp}, y el fichero @file{INSTALL} para
m@'as acerca de volcados.)

Se puede tambi@'en querer incluir expresiones autocargadas en tu
fichero @file{.emacs}. @code{autoload} es una funci@'on construida que
toma cinco argumento, los tres finales de los que son opcionales. El
primer argumento es el nombre de la funci@'on para ser autocargada. El
segundo es el nombre del fichero para ser cargado. El tercer
argumento es documentaci@'on para la funci@'on, y el cuarto cuenta si
la funci@'on puede ser llamada interactivmente. El quinto argumento
cuenta que tipo de objeto --- @code{autoload} puede manejar un mapa de
teclado o macro tan bien como una funci@'on (por defecto es una funci@'on).

@need 800
Aqu@'{@dotless{i}} hay un ejemplo t@'{@dotless{i}}pico:

@smallexample
@group
(autoload 'html-helper-mode
  "html-helper-mode" "Editar documentos HTML" t)
@end group
@end smallexample

@noindent
(@code{html-helper-mode} es una vieja alternativa a @code{html-mode},
que es una parte est@'andar de la distribuci@'on.)

@noindent
Esta expresi@'on autocarga la funci@'on @code{html-helper-mode}. Esto
se toma desde el fichero @file{html-helper-mode-el} (o desde la
versi@'on compilada @file{html-helper-mode.elc}, si eso existe). El
fichero debe ser localizado en un directorio espec@'{@dotless{i}}fico
por @code{load-path}. La documentaci@'on 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 @kbd{M-x
html-helper-mode}. (Se necesitan duplicar las funciones regulares de
documentaci@'on en la expresi@'on de autocarga porque la funci@'on
regular no est@'a todav@'{@dotless{i}}a cargada, as@'{@dotless{i}} su
documentaci@'on no est@'a disponible.)

@xref{Autocarga, , Autocarga, elisp, El Manual de Referencia de GNU
Emacs Lisp}, para m@'as informaci@'on.

@node Extensi@'on simple
@section Una extensi@'on simple: @code{line-to-top-of-window}
@findex line-to-top-of-window
@cindex Extensi@'on simple en fichero @file{.emacs}

Aqu@'{@dotless{i}} hay una simple extensi@'on a Emacs que mueve el
punto de l@'{@dotless{i}}nea arriba de la ventana. Yo uso esto todo el
tiempo, para hacer f@'acil de leer el texto.

Se puede poner el siguiente c@'odigo dentro de un fichero separado y
entonce cargarlo desde tu fichero @file{.emacs}, o se puede incluir
con tu fichero @file{.emacs}.

@need 1250
Aqu@'{@dotless{i}} est@'a la definici@'on

@smallexample
@group
;;; L@'{@dotless{i}}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@'{@dotless{i}}nea que apunta a lo alto de la ventana."
  (interactive)
  (recenter 0))
@end group
@end smallexample

@need 1250
Ahora el atajo.

En estos d@'{@dotless{i}}as, las teclas de funci@'on as@'{@dotless{i}}
como los eventos del rat@'on y caracteres no @sc{ascii} son escritos
con corchetes, sin marcas de citas. (En Emacs versi@'on 18 y
anteriores, se ten@'{@dotless{i}}a que escribir diferentes teclas de
funci@'on asignadas por cada diferente creaci@'on del terminal.)

Se puede asociar @code{line-to-top-of-window} a la tecla de funci@'on
@key{F6} as@'{@dotless{i}}:

@smallexample
(global-set-key [f6] 'line-to-top-of-window)
@end smallexample

Para m@'as informaci@'on, mira @ref{Reasociando el Init, , Reasociando
Teclas en tu fichero init, emacs, El Manual GNU Emacs}.

@cindex Condicional marcar@'an estas dos versiones de Emacs
@cindex Versi@'on de Emacs, eligiendo
@cindex Versi@'on de Emacs, eligiendo
Si ejecutas dos versiones de GNU Emacs, tal como las versiones 22 y
23, y usas un fichero @file{.emacs}, se puede seleccionar qu@'e c@'odigo
eval@'ua el siguiente condicional:

@smallexample
@group
(cond
 ((= 22 emacs-major-version)
  ;; eval@'ua la version 22
  ( @dots{} ))
 ((= 23 emacs-major-version)
  ;; eval@'ua la version 23 
  ( @dots{} )))
@end group
@end smallexample

Por ejemplo, en versiones m@'as recientes se ocultan los cursores por
defecto. Si se odia tal ocultaci@'on se escribe lo siguiente en mi
fichero @file{.emacs}@footnote{Cuando se empiezan las instancias de
Emacs que no cargan mi fichero @file{.emacs} o cualquier fichero,
tambi@'en se puede deshabilitar la ocultaci@'on:
@smallexample
emacs -q --no-site-file -eval '(blink-cursor-mode nil)'
@exdent O ahora,
usando un conjunto m@'as sofisticado de opciones, emacs -Q - D
@end smallexample
 }:

@smallexample
@group
(when (>= emacs-major-version 21)
  (blink-cursor-mode 0)
  ;; Inserta la nueva l@'{@dotless{i}}nea cuando se presiona `C-n' (next-line)
  ;; al fin del b@'uffer
  (setq next-line-add-newlines t)
@end group
@group
  ;; Cambia la imagen viendo
  (auto-image-file-mode t)
@end group
@group
  ;; Activa la barra de menu (esta barra tiene texto)
  ;; (Usa un argumento num@'erico para activarlo)
  (menu-bar-mode 1)
@end group
@group
   ;; Desactiva la barra de herramientas (esta barra tiene iconos)
   ;; (Usa argumentos num@'ericos para activarlo)
   (tool-bar-mode nil)
@end group
@group
  ;; Desactiva el modo tooltip para la tool bar
  ;; (Este modo causa explicaciones de iconos al pop up)
  ;; (Usa el argumento num@'erico 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
   )
@end group
@end smallexample

@node Colores X11
@section 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.

@need 1250
Aqu@'{@dotless{i}} est@'an las expresiones en un fichero @file{.emacs}
que establecen los valores:

@smallexample
@group
;; Asigna el color del cursor
(set-cursor-color "white")

;; Asigna el color del rat@'on
(set-mouse-color "white")

;; Asigna foreground y background
(set-foreground-color "white")
(set-background-color "darkblue")
@end group

@group
;;; Asigna colores para isearch y drag
(set-face-foreground 'highlight "white")
(set-face-background 'highlight "blue")
@end group

@group
(set-face-foreground 'region "cyan")
(set-face-background 'region "blue")
@end group

@group
(set-face-foreground 'secondary-selection "skyblue")
(set-face-background 'secondary-selection "darkblue")
@end group

@group
;; 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")))
@end group
@end smallexample

Las varias sombras de azul disparan mi ojo y me preveen de ver la
ventana desplegada.

Alternativamente, se podr@'{@dotless{i}}an haber configurado mis
especificaciones en varios ficheros inicializaci@'on de X. Por
ejemplo, se podr@'{@dotless{i}}a asignar el foreground, background,
cursor y puntero (por ej., rat@'on) colores en mi fichero
@file{~/.Xresources} como esto:

@smallexample
@group
Emacs*foreground:   white
Emacs*background:   darkblue
Emacs*cursorColor:  white
Emacs*pointerColor: white
@end group
@end smallexample

En cualquier evento que no es parte de Emacs, se asigna el color
ra@'{@dotless{i}}z de mi ventana X en mi fichero @file{~/.xinitrc},
como este@footnote{tambi@'en se ejecutan gestores de ventanas m@'as
modernos, tales como Enlightenment, Gnome, o KDE; en estos casos, con
frecuencia se especifica una imagen en vez de un color plano.}

@smallexample
xsetroot -solid Navy -fg white &
@end smallexample

@need 1700
@node Miscel@'anea
@section Configuraciones miscel@'aneas para un fichero @file{.emacs}

@need 1250
Aqu@'{@dotless{i}} hay unas pocas configuraciones miscel@'aneas:
@sp 1

@itemize @minus
@item
Asigna la forma y color del rat@'on del cursor:

@smallexample
@group
; Formas de Cursor est@'an definidas en
; `/usr/include/X11/cursorfont.h';
; por ejemplo, el cursor `objetivo' es n@'umero 128;
; el cursor `top_left_arrow' es el n@'umero 132.
@end group

@group
(let ((mpointer (x-get-resource "*mpointer"
                                "*emacs*mpointer")))
  ;; Si no se ha asignado tu puntero de rat@'on
  ;; entonces asignalo, de otro modo, d@'ejalo as@'{@dotless{i}}:
  (if (eq mpointer nil)
      (setq mpointer "132")) ; top_left_arrow
@end group
@group
  (setq x-pointer-shape (string-to-int mpointer))
  (set-mouse-color "white"))
@end group
@end smallexample

@item
O se pueden asignar los valores de una variedad de funcionalidades en
una alist, como esta:

@smallexample
@group
(setq-default
 default-frame-alist
 '((cursor-color . "white")
   (mouse-color . "white")
   (foreground-color . "white")
   (background-color . "DodgerBlue4")
   ;; (cursor-type . bar)
   (cursor-type . box)
@end group
@group
   (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")
   ))
@end group
@end smallexample

@item
Convierte @kbd{@key{CTRL}-h} dentro @key{DEL} y @key{DEL} dentro de
@kbd{@key{CTRL}-h}.@* (Algunos viejos teclados lo necesitan, aunque yo
no he visto el problema recientemente.)

@smallexample
@group
;; Traducir `C-h' a <DEL>.
; (keyboard-translate ?\C-h ?\C-?)

;; Traducir <DEL> a `C-h'.
(keyboard-translate ?\C-? ?\C-h)
@end group
@end smallexample

@item @exclamdown{}Desactiva un cursor oculto!

@smallexample
@group
(if (fboundp 'blink-cursor-mode)
    (blink-cursor-mode -1))
@end group
@end smallexample

@noindent
o empieza GNU Emacs con el comando @code{emacs -nbc}.

@need 1250
@item Cuando se usa `grep'@*
@samp{-i}@w{ } Ignore distinciones de letras@* @samp{-n}@w{ } El
prefijo de cada l@'{@dotless{i}}nea de la salida con el n@'umero de
l@'{@dotless{i}}neas@* @samp{-H}@w{ } Imprime el nombre de fichero
para cada cadena encontrada.@* @samp{-e}@w{ } Protege patrones
empezando con un caracter de gui@'on, @samp{-}

@smallexample
(setq grep-command "grep -i -nH -e ")
@end smallexample

@ignore
@c Evidently, no longer needed in GNU Emacs 22

item Automatically uncompress compressed files when visiting them

smallexample
(load "uncompress")
end smallexample

@end ignore

@item Encuentra un b@'uffer existente, incluso si eso tiene un nombre
diferente@*
Esto evita problemas con enlaces simb@'olicos.

@smallexample
(setq find-file-existing-other-name t)
@end smallexample

@item Configura tu entorno de lenguaje y el m@'etodo de entrada por defecto

@smallexample
@group
(set-language-environment "latin-1")
;; Recuerda que se puede habilitar o deshabilitar el texto de lenguaje
;; multilingüe con el comando @code{toggle-input-method'} (@kbd{C-\})
(setq default-input-method "latin-1-prefix")
@end group
@end smallexample

Si se quiere escribir con el caracter Chino `GB', asigna esto:

@smallexample
@group
(set-language-environment "Chinese-GB")
(setq default-input-method "chinese-tonepy")
@end group
@end smallexample
@end itemize

@subsubheading Arreglando Atajos de Teclados
@cindex Atajos de Teclado, arreglando
@cindex Asociaciones, teclas, arreglando

Algunos sistemas asocian teclas de maneras no agradables. Algunas
veces, por ejemplo, la tecla @key{CTRL} en un modo perverso en vez de
la lejan@'{@dotless{i}}a a la izquierda de la fila.

Normalmente, cuando las personas arreglan estos atajos de teclado, no
se cambia su fichero @file{~/.emacs}. En vez de eso, se asocian las
teclas apropiadas en sus consolas con los comandos @code{loadkeys} o
@code{install-keymap} en su script de inicio y entonces incluyen
comandos @code{xmodmap} en su fichero @file{.xinitrc} o
@file{.Xsession} para X Windows.

@need 1250
@noindent
Para un script de inicio:

@smallexample
@group
loadkeys /usr/share/keymaps/i386/qwerty/emacs2.kmap.gz
@exdent or
install-keymap emacs2
@end group
@end smallexample

@need 1250
@noindent
Para un fichero @file{.xinitrc} o un fichero @file{.Xsession} cuando la
tecla @key{Caps Lock} es que tan lejos de la fila del home:

@smallexample
@group
# 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@'aquinas de escribir desde 1885.)

xmodmap -e "clear Lock"
xmodmap -e "add Control = Caps_Lock"
@end group
@end smallexample

@need 1250
@noindent
En un @file{.xinitrc} o @file{.Xsession}, para convertir una tecla
@key{ALT} a una tecla @key{META}:

@smallexample
@group
# Algunos teclados mal dise@~nados tienen una tecla etiquetada ALT y no Meta
xmodmap -e "keysym Alt_L = Meta_L Alt_L"
@end group
@end smallexample

@need 1700
@node Mode Line
@section Una l@'{@dotless{i}}nea modificada
@vindex mode-line-format
@cindex Formato de Modo L@'{@dotless{i}}nea

Finalmente, una funcionalidad que realmente me gusta: un mode line
modificado.

Cuando se trabaja a trav@'es de una red, se olvida que m@'aquina se
est@'a usando. Tambi@'en, se tiende a perder la traza de donde se
est@'a, y a qu@'e l@'{@dotless{i}}nea se apunta.

As@'{@dotless{i}} se resetea mi mode line para que se parezca a esto:

@smallexample
-:-- foo.texi   rattlesnake:/home/bob/  Line 1  (Texinfo Fill) Top
@end smallexample

Estoy visitando un fichero llamado @file{foo.texi}, en mi m@'aquina
@file{rattlesnake} en mi b@'uffer @file{/home/bob}. Yo estoy en la
l@'{@dotless{i}}nea 1, en modo Texinfo, y estoy arriba del b@'uffer.

@need 1200
Mi fichero @file{.emacs} tiene una secci@'on que se parece a esto:

@smallexample
@group
;; Asigna un Mode Line que nos cuente que m@'aquina, que directorio, 
;; y que l@'{@dotless{i}}nea estoy on, m@'as la informaci@'on 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
   "    "
@end group
@group
   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
@end group
@group
   #("   %[(" 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")
   ;;   "-%-"
   )))
@end group
@end smallexample

@noindent
Aqu@'{@dotless{i}}, se redefine el mode line por defecto. La
mayor@'{@dotless{i}}a de las partes son desde el original; pero yo
creo unos pocos cambios. Yo asigno el formato de mode line
@emph{default} as@'{@dotless{i}} como permitir varios modos, tales
como Info, para sobreescribirlo.

Muchos elementos en la lista son auto-explicativos:
@code{mode-line-modified} es una variable que cuenta si el b@'uffer ha
sido modificado, @code{mode-name} cuenta el nombre del modo, y
as@'{@dotless{i}}. Sin embargo, el formato parece complicado porque
las dos funcionalidades no han sido discutidas.

@cindex Propiedades, en el ejemplo del modo l@'{@dotless{i}}nea
The first string in the mode line is a dash or hyphen, @samp{-}.  In the old
days, it would have been specified simply as @code{"-"}.  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 @code{tooltip-delay}.)

@need 1000
La nueva cadena de formato tiene una sintaxis especial:

@smallexample
#("-" 0 1 (help-echo "mouse-1: select window, ..."))
@end smallexample

@noindent
El @code{#(} empieza una lista. El primer elemento de la lista es la
cadena en s@'{@dotless{i}}, solo un @samp{-}. El segundo y tercer
elemento especifica el rango a trav@'es del cuarto elemento
aplicado. Un rango empieza @emph{despu@'es} un car@'acter,
as@'{@dotless{i}} un cero significa el rango que empieza solo
despu@'es del primer caracter; un 1 significa que el rango finaliza
solo despu@'es 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, @samp{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.

@xref{Propiedades de Texto, , Propiedades de Texto, elisp, El Manual
de Referencia de GNU Emacs Lisp}, y ver @ref{Formato Mode Line, ,
Formato Mode Line, elisp, El Manual de Referencia de GNU Emacs Lisp},
para m@'as informaci@'on.

@code{mode-line-buffer-identification} muestra el nombre del
buffer. Eso es una lista empezando por @code{(#("%12b" 0 4
@dots{}}. El @code{#(} empieza la lista.

El @samp{"%12b"} muestra el nombre del actual b@'uffer, usando la
funci@'on @code{buffer-name} con la que estamos familiarizados; el
`12' especifica el n@'umero m@'aximo de caracteres que ser@'an
mostrados. Cuando un nombre tiene pocos caracteres, el espacio en
blanco se a@~nade para rellenar este n@'umero. (Los nombres del
b@'uffer puede y con frecuencia ser@'an m@'as largos de 12 caracteres;
esta longitud funciona bien en la t@'{@dotless{i}}pica ventana de 80
columnas de ancho.)

@code{:eval} dice evaluar la siguiente forma y usa el resultado como
una cadena para mostrarse. En este caso, la expresi@'on muestra el
primer componente del sistema completo. El fin del primer componente
es un @samp{.} (`periodo'), as@'{@dotless{i}} se usa la funci@'on
@code{string-match} para contar el tama@~no del primer componente. La
subcadena desde el caracter cero a este tama@~no del primer
componente. La subcadena desde el caracter cero a este tama@~no es el
nombre de la m@'aquina.

@need 1250
Esta es la expresi@'on:

@smallexample
@group
(:eval (substring
        (system-name) 0 (string-match "\\..+" (system-name))))
@end group
@end smallexample

@samp{%[} y @samp{%]} causa un par de corchetes que aparezcan por cada
edici@'on nivel de edici@'on recursiva editando el nivel. @samp{%n}
dice `Encoger' cuando esto puede hacerse. @samp{%P} te cuenta el
porcentaje del b@'uffer que est@'a debajo de la ventana, o `arriba',
`abajo', o `todo'. (Una min@'uscula @samp{p} cuenta el porcentaje bajo
el alto de la ventana.) @samp{%-} inserta suficientes guiones para
rellenar la l@'{@dotless{i}}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@'on, escribe:

@smallexample
emacs -q
@end smallexample

@noindent
Esto inicializar@'a un Emacs que @emph{no} cargue tu @file{~/.emacs}
fichero de inicializaci@'on. Uno plano, el que trae Emacs por
defecto. Nada m@'as.

@node Depurando
@chapter Depurando
@cindex depurando

GNU Emacs tiene dos depuradores, @code{debug} y @code{edebug}. El
primero es construido dentro de las tripas de Emacs y est@'a siempre
contigo; el segundo requiere que exista una funci@'on antes de que se
pueda usar.

Ambos depuradores son descritos extensivamente en @ref{Depurando, ,
Depurando Programas Lisp, elisp, El Manual de Referencia GNU Emacs
Lisp}. En este cap@'{@dotless{i}}tulo, se explicar@'a un breve ejemplo
de esto.

@menu
* depurar::                  C@'omo usar el depurador construido.
* debug-on-entry::           Empezar depurando cuando se llama a una 
                               funci@'on.
* debug-on-quit::            Empezar depurando cuando se sale con @kbd{C-g}.
* edebug::                   C@'omo usar Edebug, un depurador a nivel de 
                               fuentes.
* Ejercicios de depuraci@'on::  Ejercicios de depuraci@'on
@end menu

@node depurar
@section @code{depurar}
@findex depurar

@c xref{Decrementing Loop,, Loop with a Decrementing Counter}, for a discussion.)
Sup@'on que se ha escrito una definici@'on de funci@'on que se
pretende devolver la suma de los n@'umeros 1 a trav@'es de un n@'umero
dado. (Esta es la funci@'on @code{triangle} discutida
pronto. @xref{Ejemplo de Decremento, , Ejemplo con Contador de
Decremento}, para una discusi@'on.)

Sin embargo, tu definici@'on de funci@'on tiene un error. Se ha
malescrito @samp{1=} por @samp{1-}. Aqu@'{@dotless{i}} est@'a la
definici@'on rota:

@findex triangle-bugged
@smallexample
@group
(defun triangle-bugged (number)
  "Devuelve suma de n@'umeros 1 a trav@'es de NUMBER inclusive."
  (let ((total 0))
    (while (> number 0)
      (setq total (+ total number))
      (setq number (1= number)))      ; @r{Error aqu@'{@dotless{i}}.}
    total))
@end group
@end smallexample

Si se est@'a leyendo esto en Info, se puede evaluar esta definici@'on
en el modo normal. Se ver@'a que @code{triangle-bugged} aparece en el
@'area echo.

@need 1250
Ahora eval@'ua la funci@'on @code{triangle-bugged} con un argumento de
4:

@smallexample
(triangle-bugged 4)
@end smallexample

@noindent
En un GNU Emacs reciente, se crear@'a e introducir@'a un b@'uffer
@file{*Backtrace*} que dice:

@noindent
@smallexample
@group
---------- 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)
@end group
@group
  eval((triangle-bugged 4))
  eval-last-sexp-1(nil)
  eval-last-sexp(nil)
  call-interactively(eval-last-sexp)
---------- Buffer: *Backtrace* ----------
@end group
@end smallexample

@noindent
(Se ha reformateado este ejemplo ligeramente; el depurador no contiene
muchas l@'{@dotless{i}}neas. As@'{@dotless{i}}, se puede salir del
depurador escribiendo @kbd{q} en el buffer @file{*Backtrace*}.)

En la pr@'actica, debido a un error tan simple como este, la
l@'{@dotless{i}}nea de `error Lisp' explica lo que se necesita saber
para corregir la definici@'on. La funci@'on @code{1=} est@'a
`vac@'{@dotless{i}}a'.

@ignore
@need 800
In GNU Emacs 20 and before, you will see:

@smallexample
La definici@'on de la funci@'on est@'a vac@'{@dotless{i}}o:@: 1=
@end smallexample

@noindent
which has the same meaning as the @file{*Backtrace*} buffer line in
version 21.
@end ignore

Sin embargo, si no se conoce con bastante certeza lo que est@'a
pasando, se puede leer la traza completa.

En este caso, se necesita ejecutar una versi@'on reciente de GNU
Emacs, que autom@'aticamente empieza el depurador que pone en el
b@'uffer @file{*Backtrace*}; o adem@'as, se necesita para empezar el
depurador manualmente como se describe debajo.

Lee el b@'uffer @file{*Backtrace*} de abajo a arriba; eso cuenta lo
que le hizo a Emacs tener un error. Emacs hace una llamada interactiva
a @kbd{C-x C-e} (@code{eval-last-sexp}), que lleva a la evaluaci@'on
de la expresi@'on @code{triangle-bugged}. Cada l@'{@dotless{i}}nea de
debajo cuenta lo que el int@'erprete Lisp evalu@'o.

@need 1250
La tercera l@'{@dotless{i}}nea desde lo alto del b@'uffer es

@smallexample
(setq number (1= number))
@end smallexample

@noindent
Emacs intent@'o evaluar esta expresi@'on; para hacerlo
as@'{@dotless{i}}, se intent@'o evaluar la expresi@'on interna para
ser mostrada en la segunda l@'{@dotless{i}}nea desde arriba:

@smallexample
(1= number)
@end smallexample

@need 1250
@noindent
Aqu@'{@dotless{i}} es donde el error ocurre; como se dice en la
l@'{@dotless{i}}nea de arriba:

@smallexample
Debugger entered--Lisp error: (void-function 1=)
@end smallexample

@noindent
Se puede corregir el error, reeval@'ua la definici@'on de funci@'on, y
entonces se puede testear de nuevo.

@node debug-on-entry
@section @code{debug-on-entry}
@findex debug-on-entry

Un GNU Emacs actual abre el depurador autom@'aticamente cuando la
funci@'on tiene un error.

@ignore
GNU Emacs version 20 and before did not; it simply
presented you with an error message.  You had to start the debugger
manually.
@end ignore

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@'odigo. Algunas veces,
@exclamdown{}su c@'odigo estar@'a libre de errores!

Se puede introducir el depurador cuando se llama a la funci@'on
llamando @code{debug-on-entry}.

@need 1250
@noindent
Tipo:

@smallexample
M-x debug-on-entry RET triangle-bugged RET
@end smallexample

@need 1250
@noindent
Ahora, eval@'ua lo siguiente:

@smallexample
(triangle-bugged 5)
@end smallexample

@noindent
Todas las versiones de Emacs crear@'an un b@'uffer @file{*Backtrace*}
y cuenta tu que eso es el principio para evaluar la funci@'on
@code{triangle-bugged}:

@smallexample
@group
---------- Buffer: *Backtrace* ----------
Debugger entered--entering a function:
* triangle-bugged(5)
  eval((triangle-bugged 5))
@end group
@group
  eval-last-sexp-1(nil)
  eval-last-sexp(nil)
  call-interactively(eval-last-sexp)
---------- Buffer: *Backtrace* ----------
@end group
@end smallexample

En el b@'uffer @file{*Backtrace*}, escribe @kbd{d}. Emacs evaluar@'a
la primera expresi@'on en @code{triangle-bugged}; el b@'uffer se
parece a esto:

@smallexample
@group
---------- 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))
@end group
@group
  eval-last-sexp-1(nil)
  eval-last-sexp(nil)
  call-interactively(eval-last-sexp)
---------- Buffer: *Backtrace* ----------
@end group
@end smallexample

@noindent
Ahora, escribe @kbd{d} de nuevo, ocho veces, lentamente. Cada vez que
se escribe @kbd{d} Emacs evaluar@'a otra expresi@'on en la
definici@'on de funci@'on.

@need 1750
Eventualmente, el b@'uffer se parece a esto:

@smallexample
@group
---------- 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)))
@group
@end group
* (let ((total 0)) (while (> number 0) (setq total ...)
        (setq number ...)) total)
* triangle-bugged(5)
  eval((triangle-bugged 5))
@group
@end group
  eval-last-sexp-1(nil)
  eval-last-sexp(nil)
  call-interactively(eval-last-sexp)
---------- Buffer: *Backtrace* ----------
@end group
@end smallexample

@need 1500
@noindent
Finalmente, despu@'es se escribe @kbd{d} dos veces m@'as, Emacs lograr@'a
el error y las dos l@'{@dotless{i}}neas superiores del buffer
@file{*Backtrace*} se ve as@'{@dotless{i}}:

@smallexample
@group
---------- Buffer: *Backtrace* ----------
Debugger entered--Lisp error: (void-function 1=)
* (1= number)
@dots{}
---------- Buffer: *Backtrace* ----------
@end group
@end smallexample

Escribiendo @kbd{d}, ser@'{@dotless{i}}a capaz de pasear a trav@'es de
la funci@'on.

Se puede salir de un buffer @file{*Backtrace*} escribiendo @kbd{q};
esto se sale de la traza, pero no cancela @code{debug-on-entry}.

@findex cancel-debug-on-entry
Para cancelar el efecto de @code{debug-on-entry}, llama a
@code{cancel-debug-on-entry} y el nombre de la funci@'on, como esto:

@smallexample
M-x cancel-debug-on-entry RET triangle-bugged RET
@end smallexample

@noindent
(Si est@'a leyendo esto en Info, cancela @code{debug-on-entry} ahora.)

@node debug-on-quit
@section @code{debug-on-quit} y @code{(debug)}

Adici@'on a la configuraci@'on @code{debug-on-error} o llamando
@code{debug-on-entry}, hay otros dos caminos para empezar @code{debug}.

@findex debug-on-quit
Se puede empezar @code{debug} siempre y cuando se escribe @kbd{C-g}
(@code{keyboard-quit}) se configura la variable @code{debug-on-quit}
para @code{t}. Esto es @'util para depurar bucles infinitos.

@need 1500
@cindex @code{(debug)} en c@'odigo
O, se puede insertar un l@'{@dotless{i}}nea que dice @code{(debug)}
dentro de tu c@'odigo donde se quiere que el depurador empiece,
as@'{@dotless{i}}:

@smallexample
@group
(defun triangle-bugged (number)
  "Devuelve suma de n@'umeros 1 a trav@'es de NUMERO inclusive."
  (let ((total 0))
    (while (> number 0)
      (setq total (+ total number))
      (debug)                         ; @r{Empieza el depurador.}
      (setq number (1= number)))      ; @r{Error aqu@'{@dotless{i}}.}
    total))
@end group
@end smallexample

La funci@'on @code{debug} se describe en detalle en @ref{Depurador, ,
El Depurador Lisp, elisp, El Manual de Referencia GNU Emacs Lisp}.

@node edebug
@section El depurador de nivel de fuentes @code{edebug}
@cindex Depurador de nivel de c@'odigo
@findex edebug

Edebug es un depurador a nivel de fuentes Edebug que normalmente
muestra las fuentes del c@'odigo que se est@'a depurando, con una
flecha a la izquierda que muestra que l@'{@dotless{i}}nea se est@'a
actualmente ejecutando.

Se puede pasear a trav@'es de la ejecuci@'on de una funci@'on,
l@'{@dotless{i}}nea a l@'{@dotless{i}}nea, o ejecutarse r@'apidamente
hasta lograr un @dfn{punto de ruptura} donde la ejecuci@'on pare.

Edebug se describe en @ref{edebug, , Edebug, elisp, El Manual de
Referencia de GNU Emacs Lisp}.

@need 1250
Aqu@'{@dotless{i}} hay una funci@'on con errores para
@code{triangle-recursively}. @xref{Funci@'on recursiva tri@'angulo,
, Recursi@'on en lugar de un contador}, para una revisi@'on de eso.

@smallexample
@group
(defun triangle-recursively-bugged (number)
  "Devuelve la suma of n@'umeros 1 a trav@'es de NUMBER inclusive.
Usa recursi@'on."
  (if (= number 1)
      1
    (+ number
       (triangle-recursively-bugged
        (1= number)))))               ; @r{Error aqu@'{@dotless{i}}.}
@end group
@end smallexample

@noindent
Normalmente, se instalar@'{@dotless{i}}a esta definici@'on
posicionando su cursor despu@'es de la funci@'on cerrando par@'entesis
y escribiendo @kbd{C-x C-e} (@code{eval-last-sexp}) o lo dem@'as
posicionando tu cursor con la definici@'on y escribiendo @kbd{C-M-x}
(@code{eval-defun}). (Por defecto, el comando @code{eval-defun}
funciona solo en modo Emacs Lisp o en el modo de interacci@'on de
Lisp.)

@need 1500
Sin embargo, para preparar esta definici@'on de funci@'on para Edebug,
se debe primero @dfn{instrumentar} el c@'odigo usando un comando
diferente. Se puede hacer esto posicionando el cursor dentro o
despu@'es de la definici@'on y escribiendo

@smallexample
M-x edebug-defun RET
@end smallexample

@noindent
Esto causar@'a que Emacs cargue Edebug autom@'aticamente si eso no
est@'a ya cargado y, apropiadamente prepara la funci@'on.

Despu@'es de preparar la funci@'on, emplaza tu cursor despu@'es
de la siguiente expresi@'on y escribe @kbd{C-x C-e} (@code{eval-last-sexp}):

@smallexample
(triangle-recursively-bugged 3)
@end smallexample

@noindent
Se vuelve a las fuentes de @code{triangle-recursively-bugged} y el
cursor se posiciona al principio del @code{if} de la
l@'{@dotless{i}}nea de la funci@'on. Tambi@'en, se ver@'a una flecha
en la mano izquierda al lado de esta l@'{@dotless{i}}nea donde la
funci@'on se est@'a ejecutando. (En los siguientes ejemplos, se
muestra la flecha con @samp{=>}; en un sistema de ventanas, se puede
ver la flecha como un tri@'angulo s@'olido en el `borde' de la
ventana.)

@smallexample
=>@point{}(if (= number 1)
@end smallexample

@noindent
@iftex
En el ejemplo, la posici@'on del punto es mostrado con una estrella,
@samp{@point{}} (en Info, eso es mostrado como @samp{-!-}).
@end iftex
@ifnottex
En el ejemplo, la localizaci@'on del punto es mostrado como
@samp{@point{}} (en un libro impreso, eso es mostrado con una estrella
apuntada).
@end ifnottex

Si ahora se presiona @key{SPC}, el punto se mover@'a a la siguiente
expresi@'on para ejecutarse; la l@'{@dotless{i}}nea se parece a esto:

@smallexample
=>(if @point{}(= number 1)
@end smallexample

@noindent
Como se continua presionando @key{SPC}, el puntero se mover@'a desde
la expresi@'on a la expresi@'on. Al mismo tiempo, siempre y cuando una
expresi@'on devuelva un valor, este valor ser@'a mostrado en el @'area
echo. Por ejemplo, despu@'es de mover el punto pasado @code{number},
se ver@'a lo siguiente:

@smallexample
Resultado: 3 (#o3, #x3, ?\C-c)
@end smallexample

@noindent
Esto significa el valor de @code{number} es 3, que son tres octales,
tres hexadecimales, y @sc{ascii} `control-c' (la tercera letra del
alfabeto, en caso de que se necesite conocer esta informaci@'on).

Uno puede continuar movi@'endose a trav@'es del c@'odigo hasta que
logre la l@'{@dotless{i}}nea con el error. Antes de la evaluaci@'on,
esta l@'{@dotless{i}}nea se parece a esto:

@smallexample
=>        @point{}(1= number)))))               ; @r{Error aqu@'{@dotless{i}}.}
@end smallexample

@need 1250
@noindent
Cuando se presiona @key{SPC} una vez de nuevo, se producir@'a un
mensaje de error que dice:

@smallexample
La definici@'on de la funci@'on est@'a vac@'{@dotless{i}}o:@: 1=
@end smallexample

@noindent
Este es el error.

Presiona @kbd{q} para salir de Edebug.

Para eliminar la instrumentaci@'on desde una definici@'on de
funci@'on, simplemente se reeval@'ua con un comando que no lo
instrumente. Por ejemplo, se podr@'{@dotless{i}}a posicionar su cursor
despu@'es de la definici@'on cerrando par@'entesis y escribiendo
@kbd{C-x C-e}. 

Edebug hace un gran trato antes de entrar en una funci@'on. Se puede
dirigir as@'{@dotless{i}} mismo, parando solo en un error o en puntos
espec@'{@dotless{i}}ficos, se puede causar para mostrar los valores
cambiantes de varias expresiones; se puede encontrar cuantas veces una
funci@'on se llama, y m@'as.

Edebug se describe en @ref{edebug, , Edebug, elisp, El Manual de
Referencia de GNU Emacs Lisp}.

@need 1500
@node Ejercicios de depuraci@'on
@section Ejercicios de depuraci@'on

@itemize @bullet
@item
Instale la funci@'on @code{@value{COUNT-WORDS}} y provoque que se
introduzca el depurador construido cuando se llame. Ejecute el comando
en una regi@'on conteniendo dos palabras. Se necesitar@'a presionar
@kbd{d} un n@'umero remarcable de veces. En el sistema, es un `hook'
llamado despu@'es que el comando se finaliza. (Para informaci@'on sobre
hooks, mira @ref{Resumen de Comandos, , Resumen del Comando Bucle,
elisp, El Manual de Referencia GNU Emacs Lisp}.)

@item
Copie @code{@value{COUNT-WORDS}} dentro del b@'uffer @file{*scratch*},
instrumente la funci@'on para Edebug, y navegue a trav@'es de su
ejecuci@'on. La funci@'on no necesita tener un error, aunque se puede
introducir uno si se desea. Si a la funci@'on le falta un error, el
paseo se completa sin problemas.

@item
Mientras se ejecuta Edebug, escriba @kbd{?} para ver una lista de todos
los comandos Edebug. (El @code{global-edebug-prefix} normalmente es
@kbd{C-x X}, por ej@: @kbd{@key{CTRL}-x} seguido por una tecla
may@'uscula @kbd{X}; use este prefijo para comandos hechos fuera del
b@'uffer de depuraci@'on Edebug.)

@item
En el b@'uffer de depuraci@'on Edebug, usa el comando @kbd{p}
(@code{edebug-bounce-point}) para ver si @code{@value{COUNT-WORDS}}
est@'a funcionando.

@item
Mueve el punto a alg@'un sitio debajo de la funci@'on y entonces
escribe el comando @kbd{h} (@code{edebug-goto-here}) para saltar a
esta localizaci@'on.

@item
Usa el comando @kbd{t} (@code{edebug-trace-mode}) para causar que
Edebug pasee a trav@'es de la funci@'on en s@'{@dotless{i}}; usa una
letra may@'uscula @kbd{T} para @code{edebug-Trace-fast-mode}.

@item
Asigna un punto de ruptura, entonces ejecuta Edebug en modo Traza
hasta que se logre el punto de parada.
@end itemize

@node Conclusi@'on
@chapter Conclusi@'on

Ahora se ha llegado al fin de esta Introducci@'on. Se ha aprendido lo
suficiente acerca de programaci@'on en Emacs Lisp para asignar
valores, para escribir ficheros @file{.emacs} para t@'{@dotless{i}}
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@'as por uno mismo.

Se han aprendido algunas bases de programaci@'on. Pero solo
algunas. Todav@'{@dotless{i}}a hay muchas cosas que son f@'aciles de
usar que no se han tocado.

Otra idea para seguir es leer las fuentes de Emacs o 
@ifnotinfo
@cite{El Manual de Referencia de GNU Emacs}.
@end ifnotinfo
@ifinfo
@ref{Arriba, , El Manual de Referencia de GNU Emacs Lisp, El Manual de
Referencia de GNU Emacs Lisp}.
@end ifinfo

Las fuentes de Emacs Lisp son una aventura. Cuando se leen las fuentes
vienen a trav@'es de una funci@'on o expresi@'on que nos es familiar,
se necesita imaginar o encontrar qu@'e se hace.

Ir al Manual de Referencia. Eso est@'a a trav@'es del completo, limpio
y f@'acil de leer descripci@'on de Emacs Lisp. Est@'a escrito no solo
para expertos, pero s@'{@dotless{i}} para gente que conoce lo que
usted conoce. (El @cite{Manual de Referencia} viene con la
distribuci@'on de GNU Emacs. Como esta introducci@'on, viene como un
fichero fuente Texinfo, as@'{@dotless{i}} se puede leer on-line como
un libro impreso.)

Ir a otra ayuda on-line que sea parte de GNU Emacs: la documentaci@'on
on-line para todas las funciones y variables, y @code{find-tag}, el
programa que va a las fuentes.

Aqu@'{@dotless{i}} hay un ejemplo de c@'omo explorar las
fuentes. Porque su nombre, @file{simple.el} es el fichero que se vi@'o
primero, hace tiempo. Como eso ocurre alguna de las funciones en
@file{simple.el} son complicadas, o al menos parece complicado a
primera vista. La funci@'on @code{open-line}, por ejemplo, parece
complicada.

Se puede querer pasear a trav@'es de esta funci@'on lentamente, como
nosotros hicimos la funci@'on
@code{forward-sentence}. (@xref{forward-sentence, La funci@'on
@code{forward-sentence}}.) O se puede querer salir de esta funci@'on
y mirar en otra, tal como @code{split-line}. No se necesita leer todas
las funciones. De acuerdo a @code{count-words-in-defun}, la funci@'on
@code{split-line} contiene 102 palabras y s@'{@dotless{i}}mbolos.

Incluso aunque sean pocas, @code{split-line} contiene expresiones que
no se han estudiado: @code{skip-chars-forward}, @code{indent-to},
@code{current-column} y @code{insert-and-inherit}.

Considera la funci@'on @code{skip-chars-forward}. (Eso es parte de la
definici@'on de funci@'on para @code{back-to-indentation}, que
muestra la @ref{Revisar, , Revisar}.)

En GNU Emacs, se puede encontrar m@'as acerca de
@code{skip-chars-forward} escribiendo @kbd{C-h f}
(@code{describe-function}) y el nombre de la funci@'on. Esto te da la
documentaci@'on de funci@'on.

Se puede ser capaz de adivinar que se hace por una funci@'on bien
llamada tal como @code{indent-to}; o se puede buscar,
tambi@'en. Incidentalmente, la funci@'on @code{describe-function} en
s@'{@dotless{i}} est@'a en @file{help.el}; esta es una de estas largas,
pero descifrables funciones. @exclamdown{}Se puede buscar
@code{describe-function} usando el comando @kbd{C-h f}!

En esta instancia, desde el c@'odigo es Lisp, el b@'uffer
@file{*Help*} contiene el nombre de la librer@'{@dotless{i}}a
conteniendo las fuentes de la funci@'on. Se puede poner el punto a
trav@'es del nombre de la librer@'{@dotless{i}}a y presiona la tecla
RET, que est@'a en esta situaci@'on est@'a asociado a
@code{help-follow}, y se toma directamente de las fuentes, en el mismo
camino que @kbd{M-.} (@code{find-tag}).

La definici@'on para @code{describe-function} ilustra como
personalizar las expresiones @code{interactive} sin usar los c@'odigos
de caracter est@'andar y eso muestra como crear un b@'uffer temporal.

(La funci@'on @code{indent-to} es escrita en C en vez de Emacs Lisp;
eso es una funci@'on `construida'. @code{help-follow} toma su fuente
como @code{find-tag}, cuando se configura apropiadamente.)

Se puede mirar en las fuentes de la funci@'on usando @code{find-tag},
que est@'a asociado a @kbd{M-.}. Finalmente, se puede encontrar que el
Manual de Referencia tiene que decir visitando el manual en Info, y
escribiendo @kbd{i} (@code{Info-index}) y el nombre de la funci@'on, o
buscando la funci@'on en el @'{@dotless{i}}ndice a una copia impresa
del manual.

Similarmente, se puede encontrar que significa por
@code{insert-and-inherit}.

Otros ficheros fuente interesantes incluyen @file{paragraphs.el},
@file{loaddefs.el} y @file{loadup.el}. El fichero @file{paragraphs.el}
incluye ordenar, funciones f@'acilmente comprendidas tan bien como las
largas. El fichero @file{loaddefs.el} contiene muchos autoloads
est@'andar y muchos mapas de teclado. Nunca se ha buscado en todo;
solo en las partes. @file{loadup.el} es el fichero que carga las
partes est@'andar de Emacs; eso cuenta un gran trato acerca de c@'omo
Emacs est@'a construido. (@xref{Construyendo Emacs, , Construyendo
Emacs, elisp, El Manual de Referencia GNU Emacs Lisp}, para m@'as
acerca de construcci@'on.)

Como dije, se han aprendido algunas cosas; sin embargo, y de manera
muy importante, se han tocado fuertes aspectos de la programaci@'on;
no se ha dicho nada acerca de como ordenar la informaci@'on, excepto
para usar la funci@'on predefinida @code{sort}; no se ha dicho nada
acerca de c@'omo almacenar la informaci@'on, 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@'actico con GNU Emacs. Lo que se ha hecho es comenzar. Este es el
fin del principio de una gran amistad.

@c ================ Appendix ================

@node the-the
@appendix La funci@'on @code{the-the}
@findex the-the
@cindex Funci@'on de palabras duplicadas
@cindex Palabras, duplicadas

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@'as frecuente, es duplicar ``el''; aqu@'{@dotless{i}}, se llama a la
funci@'on para detectar las palabras duplicadas, @code{the-the}.

@need 1250
Como primer paso, se podr@'{@dotless{i}}an usar las siguientes
expresiones regulares para buscar duplicados:

@smallexample
\\(\\w+[ \t\n]+\\)\\1
@end smallexample

@noindent
Este regexp asocia uno o m@'as caracteres que constituyen palabras
seguidas por uno o m@'as espacios, tabuladores, o nuevas
l@'{@dotless{i}}neas. Sin embargo, eso no detecta palabras duplicadas
en diferentes l@'{@dotless{i}}neas, desde la finalizaci@'on de la
primera palabra, el fin de la l@'{@dotless{i}}nea, es diferente desde
el fin de la segunda palabra, un espacio. (Para m@'as informaci@'on
acerca de expresiones regulares, mira el @ref{Buscar regexp, , B@'usquedas
de Expresiones Regulares}, tan bien como la @ref{Regexps, , Sintaxis de
Expresiones Regulares, emacs, El Manual de GNU Emacs}, y la
@ref{Expresiones Regulares, , Expresiones Regulares, elisp, El Manual
de Referencia GNU Emacs Lisp}.)

Se podr@'{@dotless{i}}an intentar buscar caracteres duplicados pero no
si el patr@'on 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@'{@dotless{i}}, @w{@samp{\\w+}} asocia a una o m@'as
caracteres de palabras constituyente y @w{@samp{\\W*}} asocia cero o
m@'as caracteres que no constituyen palabras.

@smallexample
\\(\\(\\w+\\)\\W*\\)\\1
@end smallexample

@noindent
De nuevo, no @'util.

Aqu@'{@dotless{i}} est@'a el patr@'on que uso. No es perfecto, pero
suficientemente bueno. @w{@samp{\\b}} asocia la cadena
vac@'{@dotless{i}}a provista al principio o fin de una palabra;
@w{@samp{[^@@ \n\t]+}} asocia una o m@'as ocurrencias de qu@'e
caracteres que @emph{no} son un @@-signo, espacio, nueva
l@'{@dotless{i}}nea, o tabulador.

@smallexample
\\b\\([^@@ \n\t]+\\)[ \n\t]+\\1\\b
@end smallexample

Uno puede escribir expresiones m@'as complicadas, pero esta
expresi@'on es suficientemente buena as@'{@dotless{i}}.

Aqu@'{@dotless{i}} est@'a la funci@'on @code{the-the}, como se incluye
en mi fichero @file{.emacs}, a lo largo de un atajo global manejable:

@smallexample
@group
(defun the-the ()
  "Busca hacia adelante para una palabra duplicada."
  (interactive)
  (message "Buscando palabras duplicadas ...")
  (push-mark)
@end group
@group
  ;; 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@'uffer")))
@end group

@group
;; Asocia `the-the' a  C-c \
(global-set-key "\C-c\\" 'the-the)
@end group
@end smallexample

@sp 1
Aqu@'{@dotless{i}} est@'a el test del texto:

@smallexample
@group
uno dos tres cuatro cinco
cinco seis siete
@end group
@end smallexample

Se pueden sustituir las otras expresiones regulares mostradas debajo en
la definici@'on de funci@'on y se prueba cada una de ellas en esta lista.

@node Kill Ring
@appendix Manejando el anillo de la muerte
@cindex Manejando el anillo de la muerte
@cindex Manejando el anillo de la muerte
@cindex Anillo, creando un lista como un

El anillo de la muerte es una lista que es transformada dentro de un
anillo que trabaja con la funci@'on @code{current-kill}. Los comandos
@code{yank} y @code{yank-pop} usan la funci@'on @code{current-kill}.

Este ap@'endice describe la funci@'on @code{current-kill} y los
comandos @code{yank} y @code{yank-pop}, pero primero, considere los
trabajo del kill ring. 

@menu
* Qu@'e hace el anillo de la muerte::  Qu@'e 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
@end menu

@ifnottex
@node Qu@'e hace el anillo de la muerte
@unnumberedsec Qu@'e hace el anillo de la muerte
@end ifnottex

@need 1250
El anillo de la muerte @emph{kill ring} tiene el tama@~no m@'aximo de
sesenta elementos; hacer una explicaci@'on con este n@'umero m@'aximo
quedar@'{@dotless{i}}a demasiado larga. En vez de eso, pensemos qu@'e
ocurre si se as@'{@dotless{i}}gna a cuatro. Por favor, eval@'ue lo
siguiente:

@smallexample
@group
(setq old-kill-ring-max kill-ring-max)
(setq kill-ring-max 4)
@end group
@end smallexample

@noindent
Entonces, por favor, copie cada l@'{@dotless{i}}nea del siguiente
ejemplo indentado dentro del anillo de la muerte @emph{kill ring}. Se
puede cortar cada l@'{@dotless{i}}nea con @kbd{C-k} o marcarla y
copiarla con @kbd{M-w}.

@noindent
(En un b@'uffer de solo lectura, tal como el b@'uffer @file{*info*}, el
comando kill, @kbd{C-k} (@code{kill-line}), no eliminar@'a el texto,
solamente lo mueve al anillo de la muerte @emph{kill ring}. Sin
embargo, el ordenador puede avisar con un beep. Alternativamente, para
silenciar, se puede copiar la regi@'on de cada l@'{@dotless{i}}nea con
el comando @kbd{M-w} (@code{kill-ring-save}). Se debe marcar cada
l@'{@dotless{i}}nea de este comando para tener @'exito, pero no
importa si al final se posiciona en el punto o la marca).

@need 1250
@noindent
Por favor, invoque las llamadas en orden, de modo que los cinco
elementos rellenen el anillo de la muerte @emph{kill ring}.

@smallexample
@group
primero algo de texto
segunda pieza de texto
tercera l@'{@dotless{i}}nea
cuarta l@'{@dotless{i}}nea de texto
quinto bit de texto
@end group
@end smallexample

@need 1250
@noindent
Entonces encuentra el valor de @code{kill-ring} evaluando

@smallexample
kill-ring
@end smallexample

@need 800
@noindent
Eso es:

@smallexample
@group
("quinto bit de texto" "cuarta l@'{@dotless{i}}nea de texto"
"tercera l@'{@dotless{i}}nea" "segunda pieza de texto")
@end group
@end smallexample

@noindent
El primer elemento, @samp{primero algo de texto}, fu@'e borrado.

@need 1250
Para devolver el viejo valor para el tama@~no del kill ring, eval@'ue:

@smallexample
(setq kill-ring-max old-kill-ring-max)
@end smallexample

@node current-kill
@appendixsec La funci@'on @code{current-kill}
@findex current-kill

La funci@'on @code{current-kill} cambia el elemento en el anillo de la
muerte @emph{kill ring} para el que el @code{kill-ring-yank-pointer}
apunta. (Tambi@'en, la funci@'on @code{kill-new} asigna
@code{kill-ring-yank-pointer} para apuntar al @'ultimo elemento del
anillo de la muerte @emph{kill ring}. La funci@'on @code{kill-new} se
usa directamente o indirectamente por @code{kill-append},
@code{copy-region-as-kill}, @code{kill-ring-save}, @code{kill-line}, y
@code{kill-region}.)

@menu
* C@'odigo para current-kill::  C@'odigo para current-kill
* Comprendiendo current-kill::  Comprendiendo current-kill
@end menu

@ifnottex
@node C@'odigo para current-kill
@unnumberedsubsec El c@'odigo @code{current-kill}
@end ifnottex


@need 1500
La funci@'on @code{current-kill} es usada por @code{yank} y por
@code{yank-pop}. Aqu@'{@dotless{i}} est@'a el c@'odigo para
@code{current-kill}:

@smallexample
@group
(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@~nade al frente del
anillo de la muerte @emph{kill ring} y devuelve el @'ultimo corte.
@end group
@group
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))))) 
@end group
@group
    (if interprogram-paste
        (progn
          ;; Deshabilita el programa de la funci@'on de corte cuando se
          ;; a@~nade el nuevo texto al anillo de la muerte @emph{kill ring},
          ;; as@'{@dotless{i}} Emacs no intenta poseer la selecci@'on
          ;; con id@'entico texto.
          (let ((interprogram-cut-function nil))
            (kill-new interprogram-paste))
          interprogram-paste)
@end group
@group
      (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)))))
@end group
@end smallexample

Recuerde tambi@'en que la funci@'on @code{kill-new} asigna
@code{kill-ring-yank-pointer} al @'ultimo elemento del anillo de la
muerte @emph{kill ring}, que significa que todas las funciones lo
llaman y asigna el valor de manera indirecta: @code{kill-append},
@code{copy-region-as-kill}, @code{kill-ring-save}, @code{kill-line} y
@code{kill-region}. 

@need 1500
Aqu@'{@dotless{i}} est@'a la l@'{@dotless{i}}nea en @code{kill-new},
que se explica en la @ref{Funci@'on kill-new, , La funci@'on
@code{kill-new}}.

@smallexample
(setq kill-ring-yank-pointer kill-ring)
@end smallexample

@ifnottex
@node Comprendiendo current-kill
@unnumberedsubsec @code{current-kill} en outline
@end ifnottex

La funci@'on @code{current-kill} parece compleja, pero usual, eso
puede ser comprendido tom@'andolo aparte pieza por pieza. Primero
m@'{@dotless{i}}ralo en la forma esquel@'etica:

@smallexample
@group
(defun current-kill (n &optional do-not-move)
  "Rota el punto a pegar por N lugares, y entonces devuelve el texto cortado."
  (let @var{varlist}
    @var{body}@dots{})
@end group
@end smallexample

Esta funci@'on tiene dos argumentos, uno es opcional. Hay una cadena
de documentaci@'on. @emph{No} es una funci@'on interactiva.

@menu
* Cuerpo de current-kill::   Cuerpo de current-kill
* Disgresi@'on concerniente de error::  C@'omo confundir humanos, pero no 
                                          ordenadores.
* Determinando el elemento::  Determinando el elemento
@end menu

@ifnottex
@node Cuerpo de current-kill
@unnumberedsubsubsec El cuerpo de @code{current-kill}
@end ifnottex

El cuerpo de la definici@'on de funci@'on es una expresi@'on
@code{let}, que por s@'{@dotless{i}} misma tiene tanto un cuerpo como
una @var{varlist}.

La expresi@'on @code{let} declara una variable que ser@'a solo usable
con las asociaciones de esta funci@'on. Esta variable se llama
@code{interprogram-paste} y se copia a otro programa. No se copia con
esta instancia de GNU Emacs. La mayor@'{@dotless{i}}a de los sistemas
de ventanas proveen una facilidad para pegar el
interprograma. Tristemente, esta facilidad normalmente provee solo el
@'ultimo elemento. La mayor@'{@dotless{i}}a de los sistemas de
ventanas no han adoptado un anillo de muchas posibilidades, incluso
aunque Emacs haya provisto esto durante d@'ecadas.

La expresi@'on @code{if} tiene dos partes, una si existe
@code{interprogram-paste} y otra si no.

@need 2000
Perm@'{@dotless{i}}tenos considerar el `si no' o la parte else de la
funci@'on @code{current-kill}. (La parte then usa la funci@'on
@code{kill-new}, que ya hemos descrito. @xref{Funci@'on kill-new, , La
funci@'on @code{kill-new}.})

@smallexample
@group
(or kill-ring (error "El Kill ring est@'a vac@'{@dotless{i}}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))
@end group
@end smallexample

@noindent
El c@'odigo primero chequea si el kill ring @emph{anillo de la muerte}
tiene contenido; de otro modo se@~nala un error.

@need 1000
Note que la expresi@'on @code{or} es muy similar para testear el
tama@~no con un @code{if}:

@findex zerop
@findex error
@smallexample
@group
(if (zerop (length kill-ring))          ; @r{parte-si}
    (error "Anillo de la muerte vac@'{@dotless{i}}o"))       ; @r{parte-entonces}
  ;; No hay parte-resto
@end group
@end smallexample

@noindent
Si no hay nada en el kill ring @emph{anillo de la muerte}, su tama@~no
debe ser cero y un mensaje de error se env@'{@dotless{i}}a al usuario:
@samp{El kill ring est@'a vac@'{@dotless{i}}o}. La funci@'on
@code{current-kill} usa una expresi@'on @code{or} que es simple. Pero
una expresi@'on @code{if} recuerda lo que lleva.

Esta expresi@'on @code{if} usa la funci@'on @code{zerop} que devuelve
cierto si el valor que se chequea es cero. Cuando @code{zerop} chequea
cierto, la parte then del @code{if} se eval@'ua. La parte then es una
lista empezando con la funci@'on @code{error}, que es una funci@'on
que es similar a la funci@'on @code{message} (@pxref{message, , La
Funci@'on @code{message}}) que imprime un mensaje de una
l@'{@dotless{i}}nea en el @'area echo. Sin embargo, adem@'as de
imprimir un mensaje, @code{error} tambi@'en eval@'ua la funci@'on que
est@'a embebida. Esto significa que el resto de la funci@'on no ser@'a
evaluada si el tama@~no del anillo de la muerte @emph{kill ring} es
cero.

Entonces la funci@'on @code{current-kill} selecciona el elemento a
devolver. La selecci@'on depende del n@'umero de lugares que
@code{current-kill} rota y donde @code{kill-ring-yank-pointer} apunta.

Lo siguiente, si el argumento @code{do-not-move} opcional es verdadero
o el actual valor de @code{kill-ring-yank-pointer} se establece al
punto de la lista. Finalmente, otra expresi@'on devuelve el primer
elemento de la lista incluso si el argumento @code{do-not-move} es
verdadero.

@ifnottex
@node Disgresi@'on concerniente de error
@unnumberedsubsubsec Disgresi@'on acerca de la palabra `error'
@end ifnottex

En mi opini@'on, es ligeramente err@'oneo, al menos para humanos, usar
el t@'ermino `error' como el nombre de la funci@'on @code{error}. Un
t@'ermino mejor ser@'{@dotless{i}}a `cancelar'. Estrictamente
hablando, de acuerdo, no se puede apuntar, mucho menos rotar un
puntero a una lista que no tiene tama@~no, as@'{@dotless{i}} 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 @emph{kill ring} est@'e lleno o vac@'{@dotless{i}}o. Esto es un
acto de exploraci@'on.

Desde el punto de vista humano, el acto de exploraci@'on y
descubrimiento no es necesariamente un error, y por esta raz@'on no
ser@'{@dotless{i}}a etiquetado como tal, incluso las vocales de un
ordenador. Como tal, el c@'odigo en Emacs implica que un humano que
est@'a actuando virtuosamente, explorando su entorno, est@'a teniendo
un error. Esto est@'a mal. Incluso aunque el ordenador tome los mismos
pasos como cuando hay `error', un t@'ermino tal como `cancelar'
tendr@'{@dotless{i}}a una clara connotaci@'on.

@ifnottex
@node Determinando el elemento
@unnumberedsubsubsec Determinando el elemento
@end ifnottex

Entre otras acciones, la else-part de la expresi@'on @code{if} asigna
el valor de @code{kill-ring-yank-pointer} a @code{ARGth-kill-element}
cuando el kill ring @emph{anillo de la muerte} tiene alguna cosa
dentro y el valor de @code{do-not-move} es @code{nil}.

@need 800
El c@'odigo se parece a esto:

@smallexample
@group
(nthcdr (mod (- n (length kill-ring-yank-pointer))
             (length kill-ring))
        kill-ring)))
@end group
@end smallexample

Esto necesita alg@'un examen. A menos que no se suponga mover el
puntero, la funci@'on @code{current-kill} cambia donde
@code{kill-ring-yank-pointer} apunta. Esto es lo que la expresi@'on
@w{@code{(setq kill-ring-yank-pointer ARGth-kill-element)}}
hace. Tambi@'en, claramente, @code{ARGth-kill-element} est@'a siendo
asignado para ser igual a alg@'un @sc{cdr} del anillo de la muerte
@emph{kill ring}, usando la funci@'on @code{nthcdr} que est@'a
descrita en una secci@'on temprana. (@xref{copy-region-as-kill}.)
¿C@'omo se hace?

Como se ha visto antes (@pxref{nthcdr}), la funci@'on @code{nthcdr}
funciona repetidamente tomando el @sc{cdr} de una lista --- eso toma
el @sc{cdr}, del @sc{cdr}, del @sc{cdr}, @dots{}

@need 800
Las siguientes dos expresiones producen el mismo resultado:

@smallexample
@group
(setq kill-ring-yank-pointer (cdr kill-ring))

(setq kill-ring-yank-pointer (nthcdr 1 kill-ring))
@end group
@end smallexample

Sin embargo, la expresi@'on @code{nthcdr} es m@'as complicada. Usa la
funci@'on @code{mod} para determinar que @sc{cdr} para seleccionar.

(Se recordar@'a buscar funciones propias primero, en vez de esto,
tendremos que ir dentro del @code{mod}.)

La funci@'on @code{mod} devuelve el valor de su primer argumento
m@'odulo el segundo; que es decir, eso devuelve el resto despu@'es de
dividir el primer argumento por el segundo. El valor devuelto tiene el
mismo signo que el segundo argumento.

@need 800
De este modo,

@smallexample
@group
(mod 12 4)
  @result{} 0  ;; @r{porque no hay resto}
(mod 13 4)
  @result{} 1
@end group
@end smallexample

@need 1250
En este caso, el primer argumento es con frecuencia peque@~no que el
segundo. Que est@'a bien.

@smallexample
@group
(mod 0 4)
  @result{} 0
(mod 1 4)
  @result{} 1
@end group
@end smallexample

Se puede adivinar lo que la funci@'on @code{-} hace. Eso es como
@code{+} pero sustrae en vez de a@~nadir; la funci@'on @code{-}
sustrae su segundo argumento desde el primero. Tambi@'en, ya se sabe
que la funci@'on @code{length} hace (@pxref{length}). Eso devuelve el
tama@~no de una lista.

Y @code{n} es el nombre del argumento requerido a la funci@'on
@code{current-kill}.

@need 1250
As@'{@dotless{i}} cuando el primer argumento a @code{nthcdr} es cero,
la expresi@'on @code{nthcdr} devuelve la lista entera, como se puede
ver evaluando lo siguiente:

@smallexample
@group
;; kill-ring-yank-pointer @r{and} kill-ring @r{tener un tama@~no de cuatro}
;; @r{and} (mod (- 0 4) 4) @result{} 0
(nthcdr (mod (- 0 4) 4)
        '("cuarta l@'{@dotless{i}}nea de texto"
          "tercera l@'{@dotless{i}}nea"
          "segunda pieza de texto"
          "primero algo de texto"))
@end group
@end smallexample

@need 1250
Cuando el primer argumento a la funci@'on @code{current-kill} es uno,
la expresi@'on @code{nthcdr} devuelve la lista sin su primer elemento.

@smallexample
@group
(nthcdr (mod (- 1 4) 4)
        '("cuarta l@'{@dotless{i}}nea de texto"
          "tercera l@'{@dotless{i}}nea"
          "segunda pieza de texto"
          "primero algo de texto"))
@end group
@end smallexample

@cindex @samp{variable global} definida
@cindex @samp{variable, global}, definida
Incidentalmente, tanto @code{kill-ring} y
@code{kill-ring-yank-pointer} son @dfn{variables globales}. Esto
significa que cualquier expresi@'on en Emacs Lisp puede acceder a
ellas. Ellas no son como las variables locales asignadas por
@code{let} o como los s@'{@dotless{i}}mbolos en una lista de
argumentos. Las variables locales pueden solo ser accedidas con el
@code{let} que los define o la funci@'on que los especifica en una
lista de argumentos (y con expresiones llamadas por ellos).

@ignore
@c texi2dvi fails when the name of the section is within ifnottex ...
(@xref{Prevent confusion, , @code{let} Prevents Confusion}, and
@ref{defun, , The @code{defun} Special Form}.)
@end ignore

@node pegar
@appendixsec @code{pegar}
@findex pegar

Despu@'es de aprender acerca de @code{current-kill}, el c@'odigo para
la funci@'on @code{yank} es casi f@'acil.

La funci@'on @code{yank} no usa la variable @code{kill-ring-yank-pointer}
directamente. Eso llama a @code{insert-for-yank} que llama a
@code{current-kill} que asigna la variable @code{kill-ring-yank-pointer}.

@need 1250
El c@'odigo se parece a esto:

@c in GNU Emacs 22
@smallexample
@group
(defun yank (&optional arg)
  "Reinserta (\"pega\") el @'ultimo logro del texto cortado.
M@'as precisamente, reinserta el texto cortado m@'as 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@'as recientemente cortado.
Cuando este comando inserta texto cortado dentro del b@'uffer, eso
honra a `yank-excluded-properties' y `yank-handler' como se describe
la cadena de documentaci@'on para `insert-for-yank-1', que se ve.

Ver tambi@'en el comando \\[yank-pop]."
@end group
@group
  (interactive "*P")
  (setq yank-window-start (window-start))
  ;; Si no tenemos todo el camino a trav@'es, crea last-command que
  ;; indique esto para el siguiente comando.
  (setq this-command t)
  (push-mark (point))
@end group
@group
  (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@'on, incluso aunque el comando
      ;; loop would desactivar@'{@dotless{i}}a la marca porque se
      ;; insertara el texto.
      (goto-char (prog1 (mark t)
                   (set-marker (mark-marker) (point) (current-buffer)))))
@end group
@group
  ;; Si tenemos todo el camino, haz que this-command lo indique.
  (if (eq this-command t)
      (setq this-command 'yank))
  nil)
@end group
@end smallexample

La expresi@'on clave es @code{insert-for-yank}, que inserta la cadena
devuelta por @code{current-kill}, pero elimina algo de propiedades de
texto desde eso.

Sin embargo, antes de tener esta expresi@'on, la funci@'on asigna el
valor de @code{yank-window-start} a la posici@'on devuelta por la
expresi@'on @code{(window-start)}, la posici@'on que muestra lo
que actualmente empieza. La funci@'on @code{yank} tambi@'en asigna
@code{this-command} y empuja la marca.

Despu@'es de pegar el elemento apropiado, si el argumento opcional es
un @sc{cons} en vez de un n@'umero o nada, se pone el punto al principio
del texto pegado y se marca al final.

(La funci@'on @code{prog1} es como @code{progn} pero devuelve el valor
de su primer argumento en vez del valor de su @'ultimo argumento. Su
primer argumento fuerza devolver la marca del b@'uffer como un
entero. Se puede ver la documentaci@'on para estas funciones
emplazando el punto a trav@'es de ellas en este b@'uffer y entonces
escribiendo @kbd{C-h f} (@code{describe-function}) seguido por un
@kbd{RET}; por defecto es la funci@'on.)

La @'ultima parte de la funci@'on cuenta que hacer cuando eso sucede.

@node yank-pop
@appendixsec @code{yank-pop}
@findex yank-pop

Despu@'es de comprender @code{yank} y @code{current-kill}, se conoce
como enfocar la funci@'on @code{yank-pop}. Dejando fuera la
documentaci@'on para guardar el espacio, se parece a esto:

@c GNU Emacs 22
@smallexample
@group
(defun yank-pop (&optional arg)
  "@dots{}"
  (interactive "*p")
  (if (not (eq last-command 'yank))
      (error "El comando previo no fu@'e un corte"))
@end group
@group
  (setq this-command 'yank)
  (unless arg (setq arg 1))
  (let ((inhibit-read-only t)
        (before (< (point) (mark t))))
@end group
@group
    (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)
@end group
@group
    (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)
@end group
@group
    (if before
        ;; Esto es como exchange-point-and-mark,
        ;; pero no activa la marca.
        ;; Es limpio evitar la activaci@'on, 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)
@end group
@end smallexample

La funci@'on es interactive con una peque@~na @samp{p}
as@'{@dotless{i}} el argumento prefijo es procesado y pasado a la
funci@'on. El comando puede solo ser usado despu@'es del yank previo;
de otro modo un mensaje de error se env@'{@dotless{i}}a. Este chequeo
usa la variable @code{last-command} que se asigna por @code{yank} y
discutida de alg@'un modo. (@xref{copy-region-as-kill}.)

La cl@'ausula @code{let} asigna la variable @code{before} a cierto o
falso dependiendo de si el punto est@'a antes o despu@'es de la marca
y entonce la regi@'on entre punto y marca se borra. Esta es la
regi@'on que fu@'e insertada por el yank previo y eso es este texto
que ser@'a reemplazado.

@code{funcall} llama a su primer argumento como una funci@'on, pasando
los argumentos que permanecen. El primer argumento es el que la
expresi@'on @code{or} devuelve. Los dos argumentos que permanecen son
las posiciones de punto y marca asignadas por el comando @code{yank}
precedente.

Hay m@'as, pero esta es la parte m@'as dura.

@node fichero anillo
@appendixsec El fichero @file{ring.el}
@cindex fichero @file{ring.el}

De manera interesante, GNU Emacs posee un fichero llamado
@file{ring.el} que provee muchas de las funcionalidades que ahora se
discuten. Pero las funciones tales como @code{kill-ring-yank-pointer}
no usan esta librer@'{@dotless{i}}a, posiblemente porque fueron
escritas pronto.

@node Grafo completo
@appendix Un grafo con ejes etiquetados

Los ejes impresos ayudan a comprender un grafo. Para crear escalas. En
un cap@'{@dotless{i}}tulo anterior (@pxref{Leyendo un grafo, , Leyendo
un grafo}), se escribi@'o el c@'odigo para imprimir el cuerpo de un
grafo. Aqu@'{@dotless{i}} se escribe el c@'odigo para imprimir y
etiquetar ejes horizontales y verticales, a lo largo del cuerpo en
s@'{@dotless{i}}.

@menu
* Ejemplo etiquetado::       Ejemplo etiquetado
* print-graph Varlist::      Expresi@'on @code{let} en @code{print-graph}.
* print-Y-axis::             Imprimir una etiqueta para los ejes verticales.
* print-X-axis::             Imprimir una etiqueta horizontal.
* Imprimir Grafo Entero::    La funci@'on para imprimir un grafo completo.
@end menu

@ifnottex
@node Ejemplo etiquetado
@unnumberedsec Grafo de ejemplo etiquetado
@end ifnottex

Puesto que las inserciones rellenan un b@'uffer a la derecha y debajo
del punto, el nuevo grafo imprime la funci@'on que primero
imprimir@'{@dotless{i}}a el eje vertical Y, despu@'es el cuerpo del
grafo, y finalmente el eje horizontal X. Esta secuencia nos da los
contenidos de la funci@'on:

@enumerate
@item
Configura c@'odigo.

@item
Imprime el eje Y.

@item
Imprime el cuerpo del grafo.

@item
Imprime el eje X.
@end enumerate

@need 800
Aqu@'{@dotless{i}} hay un ejemplo de como se ve un grafo finalizado:

@smallexample
@group
    10 -
                  *
                  *  *
                  *  **
                  *  ***
     5 -      *   *******
            * *** *******
            *************
          ***************
     1 - ****************
         |   |    |    |
         1   5   10   15
@end group
@end smallexample

@noindent
En este grafo, en ambos ejes vertical y horizontal se etiquetan con
n@'umeros. Sin embargo, en algunos grafos, el eje horizontal es tiempo
y estar@'{@dotless{i}}a mejor etiquetarlo con meses,
as@'{@dotless{i}}:

@smallexample
@group
     5 -      *
            * ** *
            *******
          ********** **
     1 - **************
         |    ^      |
       Enero Junio Enero
@end group
@end smallexample

Dentro, con un peque@~no pensamiento, se puede f@'acilmente venir con
una variedad de esquemas de etiquetado verticales y
horizontales. Nuestra tarea podr@'{@dotless{i}}a llegar a ser
complicada. Pero las complicaciones generan confusi@'on. En vez de
permitir esto, es mejor elegir un simple esquema de etiquetado para
nuestro primer esfuerzo, y modificarlo o reemplazarlo despu@'es.

@need 1200
Estas consideraciones sugieren el siguiente outline para la funci@'on
@code{print-graph}:

@smallexample
@group
(defun print-graph (numbers-list)
  "@var{documentation}@dots{}"
  (let ((height  @dots{}
        @dots{}))
@end group
@group
    (print-Y-axis height @dots{} )
    (graph-body-print numbers-list)
    (print-X-axis @dots{} )))
@end group
@end smallexample

Nosotros podemos trabajar en cada parte de la definici@'on de funci@'on
@code{print-graph}.

@node print-graph Varlist
@appendixsec La varlist @code{print-graph}
@cindex @code{print-graph} varlist

Para escribir la funci@'on @code{print-graph}, la primera tarea es
escribir la varlist en la expresi@'on @code{let}. (Nosotros dejaremos
por ahora cualquier pensamiento acerca de hacer la funci@'on
interactive o acerca de los contenidos de su cadena de documentaci@'on.)

La varlist asignar@'{@dotless{i}}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@'on
aqu@'{@dotless{i}}. Note que la funci@'on @code{print-graph-body}
tambi@'en requiere esta informaci@'on. No hay raz@'on para calcular la
altura del grafo en dos lugares diferentes, as@'{@dotless{i}}
cambiar@'{@dotless{i}}a @code{print-graph-body} desde el camino que
definimos pronto para tomar ventaja del c@'alculo.

De manera similar, tanto la funci@'on para imprimir la etiqueta del
eje X y la funci@'on @code{print-graph-body} se necesita aprender el
valor del ancho de cada s@'{@dotless{i}}mbolo. Se puede desarrollar el
c@'alculo aqu@'{@dotless{i}} y cambiar la definici@'on para
@code{print-graph-body} desde el camino que se defini@'o en el
cap@'{@dotless{i}}tulo previo.

El tama@~no de la etiqueta para el eje horizontal debe ser al menos
tan largo como el grafo. Sin embargo, esta informaci@'on es usada solo
en la funci@'on que imprime el eje horizontal, as@'{@dotless{i}} no
necesita calcularse aqu@'{@dotless{i}}.

Estos pensamientos nos llevan directamente a la siguiente forma para
la varlist en el @code{let} para @code{print-graph}:

@smallexample
@group
(let ((height (apply 'max numbers-list)) ; @r{Primera versi@'on.}
      (symbol-width (length graph-blank)))
@end group
@end smallexample

@noindent
Como se ver@'a, esta expresi@'on no es bastante correcta.

@need 2000
@node print-Y-axis
@appendixsec La funci@'on @code{print-Y-axis}
@cindex Ejes, imprimir vertical
@cindex imprimiendo eje Y
@cindex Imprimiendo Ejes Verticales
@cindex Imprimir eje vertical

El trabajo de la funci@'on @code{print-Y-axis} es imprimir una etiqueta
para el eje vertical que se parece a esto:

@smallexample
@group
    10 -




     5 -



     1 -
@end group
@end smallexample

@noindent
La funci@'on se pasar@'{@dotless{i}}a a lo alto del grafo, y
as@'{@dotless{i}}
construyen e insertan los n@'umeros y marcas apropiados.

@menu
* print-Y-axis en Detalle::  print-Y-axis en Detalle
* Altura de etiqueta::       @questiondown{}Qu@'e altura para el eje Y?
* Calcular un resto::        C@'omo calcular el resto de una divisi@'on.
* Elemento del Eje Y::       Construir una l@'{@dotless{i}}nea para el eje 
                               Y.
* Y-axis-column::            Generar una lista de etiquetas del eje Y.
* Pen@'ultimo print-Y-axis::  Una versi@'on no muy final.
@end menu

@ifnottex
@node print-Y-axis en Detalle
@unnumberedsubsec La funci@'on @code{print-Y-axis} en detalle
@end ifnottex

Es suficientemente f@'acil ver en la figura que la etiqueta del eje Y
pero se puede decir en palabras, y entonces escribir una definici@'on
de funci@'on para hacer el trabajo es otra materia. No es bastante
verdad decir que se quiere un n@'umero y un tic cada cinco
l@'{@dotless{i}}neas: solo hay tres l@'{@dotless{i}}neas entre el
@samp{1} y el @samp{5} (l@'{@dotless{i}}neas 2, 3 y 4), pero cuatro
l@'{@dotless{i}}neas entre el @samp{5} y el @samp{10}
(l@'{@dotless{i}}neas 6, 7, 8 y 9). Es mejor decir que se quiere un
n@'umero y un tic en la quinta l@'{@dotless{i}}nea desde abajo a cada
l@'{@dotless{i}}nea que es un m@'ultiplo de cinco.

@ifnottex
@node Altura de etiqueta
@unnumberedsubsec @questiondown{}A qu@'e altura se deber@'{@dotless{i}}a etiquetar?
@end ifnottex

La siguiente cuesti@'on es a que altura se
etiquetar@'{@dotless{i}}a. Sup@'on que la m@'axima altura de la columna
mayor del grafo es siete. La etiqueta superior en el eje Y
ser@'{@dotless{i}}a @samp{5 -}, ¿y el grafo se pegar@'{@dotless{i}}a
debajo de la etiqueta?, ¿o la etiqueta superior ser@'{@dotless{i}}a
@samp{7 -}, y marcar la vertical del grafo? ¿o ser@'{@dotless{i}}a la
etiqueta superior @code{10 -}, que es m@'ultiplo de cinco, y es
superior al valor m@'as alto del grafo?

La @'ultima forma es preferida. La mayor@'{@dotless{i}}a de los grafos
son rect@'angulos cuyos lados son un n@'umero integral de pasos a lo
largo --- 5, 10, 15, y as@'{@dotless{i}} 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@'on simple en la varlist para la
altura de la computaci@'on es err@'onea. La expresi@'on es
@code{(apply 'max numbers-list)}. Esto devuelve la altura precisa, no
la altura m@'axima m@'as de lo que es necesario para redondear el
m@'ultiplo de cinco. Una expresi@'on m@'as compleja es requerida.

Como es normal en casos como este, un problema complejo llega a ser
simple si est@'a dividido en varios problemas peque@~nos.

Primero, considere el caso cuando el valor superior del grafo es un
m@'ultiplo integral de cinco --- cuando eso es 5, 10, 15, o alg@'un
m@'ultiplo de cinco. Se puede usar este valor como la altura del eje Y.

Un camino simple y limpio para determinar si un n@'umero es m@'ultiplo
de cinco se divide por cinco y mira si la divisi@'on devuelve
resto. Si no hay resto, el n@'umero es un m@'ultiplo de cinco. De este
modo, siete dividido tiene un resto de dos, y siete no es un entero
m@'ultiplo 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@'ultiplo entero de cinco.

@node Calcular un resto
@appendixsubsec Viaje lateral: Calcula un resto

@findex % @r{(funci@'on resto)}
@cindex Funci@'on resto, @code{%}
En Lisp, la funci@'on para calcular un resto es @code{%}. La funci@'on
devuelve el resto de su primer argumento dividido por su segundo
argumento. Como ocurre, @code{%} es una funci@'on en Emacs Lisp que no
se puede implementar usando @code{apropos}: no se puede encontrar nada si
se escribe @kbd{M-x apropos @key{RET} resto @key{RET}}. El @'unico
camino para aprender la existencia de @code{%} es leer acerca de eso
en un libro tal como este o en las fuentes de Emacs Lisp.

Se puede probar la funci@'on @code{%} evaluando las siguientes dos
expresiones:

@smallexample
@group
(% 7 5)

(% 10 5)
@end group
@end smallexample

@noindent
La primera expresi@'on devuelve 2 y la segunda expresi@'on devuelve 0.

Para chequear si el valor devuelto es cero o alg@'un otro n@'umero, se
puede usar la funci@'on @code{zerop}. Esta funci@'on devuelve @code{t}
si su argumento debe ser un n@'umero, es cero.

@smallexample
@group
(zerop (% 7 5))
     @result{} nil

(zerop (% 10 5))
     @result{} t
@end group
@end smallexample

De este modo, la siguiente expresi@'on devolver@'a @code{t} si la
altura del grafo es divisible por cinco:

@smallexample
(zerop (% height 5))
@end smallexample

@noindent
(El valor de @code{height}, de acuerdo, puede ser encontrado desde
@code{(apply 'max numbers-list)}.)

Por otro lado, si el valor de @code{height} no es un m@'ultiplo de
cinco, nosotros queremos resetear el valor al siguiente m@'ultiplo de
cinco. Esta es la aritm@'etica sencilla usando funciones con las que
ya se est@'a familiarizado. Primero, se divide el valor de
@code{height} por cinco para determinar cuantas veces cinco va dentro
del n@'umero. De este modo, cinco va dentro doce veces. Si se a@~nade
uno a este cociente y se multiplica por cinco, obtendremos el valor
del siguiente m@'ultiplo de cinco que es m@'as largo que el
mayor. Cinco va dentro de doce dos veces. A@~nade uno a dos, y
multiplica por cinco; el resultado es quince, que es el siguiente
m@'ultiplo de cinco que es mayor de doce. La expresi@'on Lisp para
esto es:

@smallexample
(* (1+ (/ height 5)) 5)
@end smallexample

@noindent
Por ejemplo, si se eval@'ua lo siguiente, el resultado es 15:

@smallexample
(* (1+ (/ 12 5)) 5)
@end smallexample

Todo a trav@'es de esta discusi@'on, se ha estado usando `cinco' como
el valor para las etiquetas espaciadas en el eje Y; pero se puede
querer usar alg@'un otro valor. Generalmente,
reemplazar@'{@dotless{i}}a `cinco' con una variable a la que poder
asignar un valor. El mejor nombre que puedo pensar para esta variable
es @code{Y-axis-label-spacing}.

@need 1250
Usando este t@'ermino, y una expresi@'on @code{if}, se produce lo siguiente:

@smallexample
@group
(if (zerop (% height Y-axis-label-spacing))
    height
  ;; @r{else}
  (* (1+ (/ height Y-axis-label-spacing))
     Y-axis-label-spacing))
@end group
@end smallexample

@noindent
Esta expresi@'on devuelve el valor de @code{height} en
s@'{@dotless{i}} si la altura es incluso un m@'ultiplo del valor del
@code{Y-axis-label-spacing} o lo dem@'as computa y devuelve un valor
de @code{height} que es igual al siguiente m@'ultiplo mayor del valor
del @code{Y-axis-label-spacing}.

Se puede ahora incluir esta expresi@'on en la expresi@'on @code{let}
de la funci@'on @code{print-graph} (despu@'es de la primera
configuraci@'on del valor de @code{Y-axis-label-spacing}):
@vindex Y-axis-label-spacing

@smallexample
@group
(defvar Y-axis-label-spacing 5
  "N@'umero de l@'{@dotless{i}}neas desde una etiqueta del eje Y al siguiente.")
@end group

@group
@dots{}
(let* ((height (apply 'max numbers-list))
       (height-of-top-line
        (if (zerop (% height Y-axis-label-spacing))
            height
@end group
@group
          ;; @r{else}
          (* (1+ (/ height Y-axis-label-spacing))
             Y-axis-label-spacing)))
       (symbol-width (length graph-blank))))
@dots{}
@end group
@end smallexample

@noindent
(Note que el uso de la funci@'on @code{let*}: el valor inicial de la
altura es calculada una vez por la expresi@'on @code{(apply 'max
numbers-list)} y entonces el valor resultado de @code{height} es
usado para computar su valor final. @xref{fwd-para let, , La
expresi@'on @code{let*}}, para m@'as acerca de @code{let*}.)

@node Elemento del Eje Y
@appendixsubsec Construye un elemento del eje Y

Cuando se imprime el eje vertical, se quieren insertar cadenas tales
como @w{@samp{5 -}} y @w{@samp{10 - }} cada cinco
l@'{@dotless{i}}neas. M@'as all@'a, se quieren los n@'umeros agitados
para alinear, as@'{@dotless{i}} pocos n@'umeros deben ser acu@~nados
con espacios de gu@'{@dotless{i}}a. Si alguna de las cadenas usan dos
d@'{@dotless{i}}gitos, las cadenas con un simple d@'{@dotless{i}}gito
deben incluir una gu@'{@dotless{i}}a en blanco antes del n@'umero.

@findex number-to-string
Para figurarse el tama@~no del n@'umero, se usa la funci@'on
@code{length}. Pero la funci@'on @code{length} funciona solo con una
cadena, no con un n@'umero. As@'{@dotless{i}} el n@'umero tiene que
ser convertido desde un n@'umero a una cadena. Esto se hace con la
funci@'on @code{number-to-string}. Por ejemplo,

@smallexample
@group
(length (number-to-string 35))
     @result{} 2

(length (number-to-string 100))
     @result{} 3
@end group
@end smallexample

@noindent
(@code{number-to-string} se llama @code{int-to-string}; se ver@'a este
nombre alternativo en varias fuentes.)

Adem@'as, en cada etiqueta, cada n@'umero es seguido por una cadena
tal como @w{@samp{ - }}, que llamar@'a al marcador
@code{Y-axis-tic}. Esta variable est@'a definida con @code{defvar}:

@vindex Y-axis-tic
@smallexample
@group
(defvar Y-axis-tic " - "
   "La Cadena que sigue el n@'umero en una etiqueta del eje Y.")
@end group
@end smallexample

El tama@~no de la etiqueta Y es la suma del tama@~no del eje Y y el
tama@~no del n@'umero del alto del grafo.

@smallexample
(length (concat (number-to-string height) Y-axis-tic)))
@end smallexample

Este valor ser@'a calculado por la funci@'on @code{print-graph} en su
varlist como @code{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@'umero; y los dos juntos pueden ser precedidos por uno o
m@'as espacios dependiendo de c@'omo de largo es el n@'umero. La
etiqueta consiste de tres partes: los espacios que se lideran
(opcional), el n@'umero, y la marca tic. La funci@'on se pasa al
valor del n@'umero para la fila espec@'{@dotless{i}}fica, y el valor
del ancho de la l@'{@dotless{i}}nea de arriba, que es calculada (solo
una vez) por @code{print-graph}.

@smallexample
@group
(defun Y-axis-element (number full-Y-label-width)
  "Construye una etiqueta NUMERADA
Un elemento numerado se parece a esto ` 5 - ', 
y est@'a tan acu@~nado como se necesita as@'{@dotless{i}} todo se
alinea con el elemento para el n@'umero mayor."
@end group
@group
  (let* ((leading-spaces
         (- full-Y-label-width
            (length
             (concat (number-to-string number)
                     Y-axis-tic)))))
@end group
@group
    (concat
     (make-string leading-spaces ? )
     (number-to-string number)
     Y-axis-tic)))
@end group
@end smallexample

La funci@'on @code{Y-axis-element} concatena junto los espacios que se
lideran si cualquiera; el n@'umero, como una cadena; y la marca tic.

Para imaginarnos cuantos espacios gu@'{@dotless{i}}a la etiqueta
necesita, la funci@'on sustrae el tama@~no de la etiqueta --- el
tama@~no del n@'umero m@'as el tama@~no de la marca tic --- desde el
ancho de la etiqueta deseada.

@findex make-string
Los espacios en blanco se insertan usando la funci@'on
@code{make-string}. Esta funci@'on tiene dos argumentos: lo primero
cuenta como de larga ser@'a a cadena y el segundo es un
s@'{@dotless{i}}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, @samp{?}. @xref{Tipo de Caracter, , Tipo de
Caracter, elisp, El Manual de Referencia Emacs Lisp}, para una
descripci@'on de la sintaxis para caracteres. (De acuerdo, se
podr@'{@dotless{i}}a querer reemplazar el espacio en blanco por
alg@'un otro caracter @dots{}. Tu sabes qu@'e hacer.)

La funci@'on @code{number-to-string} es usada en la expresi@'on de
concatenaci@'on, para convertir el n@'umero a una cadena que es
concatenada con los espacios que se lideran y la marca de tic.

@node Y-axis-column
@appendixsubsec Crea un eje de la columna Y

Las funciones precedentes proporcionan todas las herramientas
necesarias para construir una funci@'on que genera una lista de
cadenas enumeradas y en blanco para inserta como la etiqueta para el
eje vertical:

@findex Y-axis-column
@smallexample
@group
(defun Y-axis-column (height width-of-label)
  "Construye la lista de ejes Y etiquetadas y cadenas en blanco.
Para height @emph{la altura} de la l@'{@dotless{i}}nea de debajo y width-of-label."
  (let (Y-axis)
@group
@end group
    (while (> height 1)
      (if (zerop (% height Y-axis-label-spacing))
          ;; @r{Insertar etiqueta.}
          (setq Y-axis
                (cons
                 (Y-axis-element height width-of-label)
                 Y-axis))
@group
@end group
        ;; @r{Else, insertar blancos.}
        (setq Y-axis
              (cons
               (make-string width-of-label ? )
               Y-axis)))
      (setq height (1- height)))
    ;; @r{Insertar la l@'{@dotless{i}}nea base.}
    (setq Y-axis
          (cons (Y-axis-element 1 width-of-label) Y-axis))
    (nreverse Y-axis)))
@end group
@end smallexample

En esta funci@'on, nosotros empezamos con el valor de @code{height} y
repetitivamente sustrae uno desde su valor. Despu@'es de cada
sustraci@'on, se chequea para ver si el valor es una integral
m@'ultiple del @code{Y-axis-label-spacing}. Si eso es, se construye
una etiqueta numerada usando la funci@'on @code{Y-axis-element}; si
no, se construye una etiqueta blanca usando la funci@'on
@code{make-string}. La l@'{@dotless{i}}nea base consiste del n@'umero
uno seguido por una marca tic.

@need 2000
@node Pen@'ultimo print-Y-axis
@appendixsubsec La versi@'on no demasiado final de @code{print-Y-axis}

La lista construida por la funci@'on @code{Y-axis-column} est@'a pasada
a la funci@'on @code{print-Y-axis}, que inserta la lista como una columna.

@findex print-Y-axis
@smallexample
@group
(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@'axima 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'.
@end group
@group
  (let ((start (point)))
    (insert-rectangle
     (Y-axis-column height full-Y-label-width))
    ;; @r{Posiciona el punto listo para inserta el grafo.}
    (goto-char start)
    ;; @r{Mueve el punto hacia adelante por valor de} full-Y-label-width
    (forward-char full-Y-label-width)))
@end group
@end smallexample

El @code{print-Y-axis} usa la funci@'on @code{insert-rectangle} para
inserta el eje Y creado por la funci@'on
@code{Y-axis-column}. Adem@'as, eso emplaza el punto en la posici@'on
correcta para imprimir el cuerpo del grafo.

Se puede chequear @code{print-Y-axis}:

@enumerate
@item
Instalar

@smallexample
@group
Y-axis-label-spacing
Y-axis-tic
Y-axis-element
Y-axis-column
print-Y-axis
@end group
@end smallexample

@item
Copia la siguiente expresi@'on:

@smallexample
(print-Y-axis 12 5)
@end smallexample

@item
Cambia al b@'uffer @file{*scratch*} y emplaza el cursor donde se
quiere el eje etiquetado para empezar. 

@item
Escribe @kbd{M-:} (@code{eval-expression}).

@item
Pega la expresi@'on @code{graph-body-print} dentro del minib@'uffer con
@kbd{C-y} (@code{yank}).

@item
Presiona @key{RET} para evaluar la expresi@'on
@end enumerate

Emacs imprimir@'a etiquetas verticalmente, el primero siendo
@w{@samp{10 -@w{ }}}. (La funci@'on @code{print-graph} pasar@'a el
valor de @code{height-of-top-line}, que en este caso finalizar@'a en
15, por esto lo que se obtiene podr@'{@dotless{i}}a aparecer como un error.)

@need 2000
@node print-X-axis
@appendixsec La funci@'on @code{print-X-axis}
@cindex Ejes, imprime horizontal
@cindex imprimiendo eje X
@cindex Imprime eje horizontal
@cindex Imprimiendo eje horizontal

Las etiquetas del eje X son como las etiquetas del eje Y, excepto que
los ticks son un l@'{@dotless{i}}nea debajo de los n@'umeros. Las
etiquetas se parece como esto:

@smallexample
@group
    |   |    |    |
    1   5   10   15
@end group
@end smallexample

El primer tic est@'a bajo la primera columna del grafo y est@'a
precedido por varios espacios en blanco. Estos espacios proporcionan
la habitaci@'on 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 @code{X-axis-label-spacing}.

La segunda fila del eje X consiste de n@'umeros, precedidos por varios
espacios en blanco y tambi@'en separado de acuerdo al valor de la
variable @code{X-axis-label-spacing}.

El valor de la variable @code{X-axis-label-spacing}
ser@'{@dotless{i}}a medido en unidades de @code{symbol-width}, puesto
que se puede querer cambiar el ancho de los s@'{@dotless{i}}mbolos que
est@'as usando para imprimir el cuerpo del grafo sin cambiar los
caminos del grafo que est@'a etiquetado.

@menu
* Diferencias similares::    Mucho como @code{print-Y-axis}, pero no 
                               exactamente.
* Eje X marca tic::          Crear marcas de tic para los ejes horizontales.
@end menu

@ifnottex
@node Diferencias similares
@unnumberedsubsec Similaridades y diferencias
@end ifnottex

La funci@'on @code{print-X-axis} est@'a construida m@'as o menos del
mismo modo como que la funci@'on @code{print-Y-axis} excepto que tiene
dos l@'{@dotless{i}}neas: la l@'{@dotless{i}}nea de marcas tic y los
n@'umeros. Nosotros escribiremos una funci@'on separado a imprimir
cada l@'{@dotless{i}}nea y entonces combinarlo con la funci@'on
@code{print-X-axis}.

Esto es un proceso de tres pasos:

@enumerate
@item
Escribe una funci@'on para imprimir el eje X marca tic,
@code{print-X-axis-tic-line}.

@item
Escribe una funci@'on imprime los n@'umeros X,
@code{print-X-axis-numbered-line}.

@item
Escribe una funci@'on para imprimir ambas l@'{@dotless{i}}neas, la
funci@'on @code{print-X-axis}, usando @code{print-X-axis-tic-line} y
@code{print-X-axis-numbered-line}.
@end enumerate

@node Eje X marca tic
@appendixsubsec Eje X marca tic

La primera funci@'on imprimir@'{@dotless{i}}a las marcas de tic del eje
X. Se deben especificar las marcas en s@'{@dotless{i}} y su espacio:

@smallexample
@group
(defvar X-axis-label-spacing
  (if (boundp 'graph-blank)
      (* 5 (length graph-blank)) 5)
  "N@'umeros de unidades desde un eje X al siguiente.")
@end group
@end smallexample

@noindent
(Note que el valor de @code{graph-blank} est'a asignado por otro
@code{defvar}. El predicado @code{boundp} chequea si ya ha sido
asignado; @code{boundp} devuelve @code{nil} si no lo tiene. Si
@code{graph-blank} fuera disociado y no usara esta construcci@'on
condicional, en un GNU Emacs reciente, se introducir@'{@dotless{i}}a
el depurador y mirar@'a un mensaje de error diciendo @samp{@w{Debugger
entered--Lisp error:} @w{(void-variable graph-blank)}}

@need 1200
Aqu@'{@dotless{i}} est@'a el @code{defvar} para @code{X-axis-tic-symbol}:

@smallexample
@group
(defvar X-axis-tic-symbol "|"
  "Cadena para insertar para apuntar a una columna en el eje X.")
@end group
@end smallexample

@need 1250
El objetivo es crear una l@'{@dotless{i}}nea que se parece a esto:

@smallexample
       |   |    |    |
@end smallexample

El primer tic es indentado as@'{@dotless{i}} que est@'a 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@'as un s@'{@dotless{i}}mbolo tic. El n@'umero de
espacios en blanco se determinan por el ancho del
s@'{@dotless{i}}mbolo tic y el @code{X-axis-label-spacing}.

@need 1250
El c@'odigo se parece a esto:

@smallexample
@group
;;; X-axis-tic-element
@dots{}
(concat
 (make-string
  ;; @r{Crea una cadena de blancos.}
  (-  (* symbol-width X-axis-label-spacing)
      (length X-axis-tic-symbol))
  ? )
 ;; @r{Concatena blancos con s@'{@dotless{i}}mbolos.}
 X-axis-tic-symbol)
@dots{}
@end group
@end smallexample

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 @code{full-Y-label-width} pasaba por la funci@'on
@code{print-graph}.

@need 1250
El c@'odigo para crear @code{X-axis-leading-spaces} se parece a esto:

@smallexample
@group
;; X-axis-leading-spaces
@dots{}
(make-string full-Y-label-width ? )
@dots{}
@end group
@end smallexample

Tambi@'en necesita determinar el tama@~no del eje horizontal, que es
el tama@~no de la lista de n@'umeros, y el n@'umero de ticks en el eje
horizontal:

@smallexample
@group
;; X-length
@dots{}
(length numbers-list)
@end group

@group
;; tic-width
@dots{}
(* symbol-width X-axis-label-spacing)
@end group

@group
;; number-of-X-ticks
(if (zerop (% (X-length tic-width)))
    (/ (X-length tic-width))
  (1+ (/ (X-length tic-width))))
@end group
@end smallexample

@need 1250
Todo esto lidera directamente a la funci@'on para imprimir el eje X:

@findex print-X-axis-tic-line
@smallexample
@group
(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)  ; @r{En la primera columna.}
@end group
@group
    ;; @r{Inserta el segundo tic en el lugar adecuado.}
    (insert (concat
             (make-string
              (-  (* symbol-width X-axis-label-spacing)
                  ;; @r{Inserta el espacio en blanco al segundo s@'{@dotless{i}}mbolo tic.}
                  (* 2 (length X-axis-tic-symbol)))
              ? )
             X-axis-tic-symbol))
@end group
@group
    ;; @r{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))))
@end group
@end smallexample

La l@'{@dotless{i}}nea de n@'umeros es igualmente simple:

@need 1250
Primero, creamos un elemento numerado con espacios en blanco antes de
cada n@'umero:

@findex X-axis-element
@smallexample
@group
(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))))
@end group
@end smallexample

Lo siguiente, se crea la funci@'on para imprimir la
l@'{@dotless{i}}nea numerada, empezando con el n@'umero ``1'' para la
primera columna:

@findex print-X-axis-numbered-line
@smallexample
@group
(defun print-X-axis-numbered-line
  (number-of-X-tics X-axis-leading-spaces)
  "Imprime la l@'{@dotless{i}}neas de n@'umeros del eje X"
  (let ((number X-axis-label-spacing))
    (insert X-axis-leading-spaces)
    (insert "1")
@end group
@group
    (insert (concat
             (make-string
              ;; @r{Inserta espacios en blanco al siguiente n@'umero.}
              (-  (* symbol-width X-axis-label-spacing) 2)
              ? )
             (number-to-string number)))
@end group
@group
    ;; @r{Insertar n@'umeros.}
    (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)))))
@end group
@end smallexample

Finalmente, se necesita escribir lo que @code{print-X-axis} que usa
@code{print-X-axis-tic-line} y @code{print-X-axis-numbered-line}.

La funci@'on debe determinar los valores locales de las variables
usadas por @code{print-X-axis-tic-line} y
@code{print-X-axis-numbered-line}, y entonces eso debe
llamarlas. Tambi@'en, debe imprimir el retorno de carro que separe las
dos l@'{@dotless{i}}neas.

La funci@'on consiste de una varlist que especifica cinco variables
locales, y llama cada una de las dos l@'{@dotless{i}}neas imprimiendo
funciones:

@findex print-X-axis
@smallexample
@group
(defun print-X-axis (numbers-list)
  "Imprime el eje X etique al tama@~no de NUMBERS-LIST."
  (let* ((leading-spaces
          (make-string full-Y-label-width ? ))
@end group
@group
       ;; symbol-width @r{se provee por} graph-body-print
       (tic-width (* symbol-width X-axis-label-spacing))
       (X-length (length numbers-list))
@end group
@group
       (X-tic
        (concat
         (make-string
@end group
@group
          ;; @r{Crea una cadena de espacios en blanco.}
          (-  (* symbol-width X-axis-label-spacing)
              (length X-axis-tic-symbol))
          ? )
@end group
@group
         ;; @r{Concatena espacio en blanco con s@'{@dotless{i}}mbolos
         tic.}
         X-axis-tic-symbol))
@end group
@group
       (tic-number
        (if (zerop (% X-length tic-width))
            (/ X-length tic-width)
          (1+ (/ X-length tic-width)))))
@end group
@group
    (print-X-axis-tic-line tic-number leading-spaces X-tic)
    (insert "\n")
    (print-X-axis-numbered-line tic-number leading-spaces)))
@end group
@end smallexample

@need 1250
Se puede testear @code{print-X-axis}:

@enumerate
@item
Instale @code{X-axis-tic-symbol}, @code{X-axis-label-spacing},
@code{print-X-axis-tic-line}, tanto como @code{X-axis-element},
@code{print-X-axis-numbered-line}, y @code{print-X-axis}.

@item
Copia la siguiente expresi@'on:

@smallexample
@group
(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))))
@end group
@end smallexample

@item
Cambia al b@'uffer @file{*scratch*} y emplaza el cursor donde se
quiere el eje etiquetado para empezar. 

@item
Escribe @kbd{M-:} (@code{eval-expression}).

@item
Pegue la expresi@'on de test dentro del minibuffer con @kbd{C-y}
(@code{yank}).

@item
Presiona @key{RET} para evaluar la expresi@'on
@end enumerate

@need 1250
Emacs imprimir@'a el eje horizontal as@'{@dotless{i}}
@sp 1

@smallexample
@group
     |   |    |    |    |
     1   5   10   15   20
@end group
@end smallexample

@node Imprimir Grafo Entero
@appendixsec Imprimiendo el grafo completo
@cindex Imprimiendo el grafo entero
@cindex Imprimiendo el grafo entero
@cindex Grafo, imprimiendo todo

Ahora estamos listos para imprimir el grafo completo.

La funci@'on para imprimir el grafo con las etiquetas apropiadas sigue
el esquema que creamos antes (@pxref{Grafo completo, , Un Grafo con
Ejes Etiquetados}), pero con adiciones.

@need 1250
Aqu@'{@dotless{i}} est@'a el esquema:

@smallexample
@group
(defun print-graph (numbers-list)
  "@var{documentation}@dots{}"
  (let ((height  @dots{}
        @dots{}))
@end group
@group
    (print-Y-axis height @dots{} )
    (graph-body-print numbers-list)
    (print-X-axis @dots{} )))
@end group
@end smallexample

@menu
* La versi@'on final::       Unos pocos cambios
* Testear print-graph::      Ejecutar un r@'apido test.
* Graficar palabras en funciones::  Ejecutando el c@'odigo final.
* lambda::                   C@'omo escribir una funci@'on an@'onima.
* mapcar::                   Aplicar una funci@'on a elementos de una lista.
* Otro Error::               Todav@'{@dotless{i}}a otro error @dots{} m@'as 
                               insidioso.
* Grafo impreso final::      @exclamdown{}El grafo en s@'{@dotless{i}}!
@end menu

@ifnottex
@node La versi@'on final
@unnumberedsubsec Cambios para la versi@'on final
@end ifnottex

La versi@'on 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@'on para espec@'{@dotless{i}}ficar
las etiquetas se incrementa la fila. Esta @'ultima funcionalidad
cambia a ser esencial; de otro modo, un grafo puede tener m@'as filas
que ajustarse en una muestra o en una hoja de papel.

@need 1500
Esta nueva funcionalidad requiere un cambio a la funci@'on
@code{Y-axis-column}, para a@~nadir @code{vertical-step} para
eso. Esta funci@'on es parece a esto:

@findex Y-axis-column @r{Versi@'on Final.}
@smallexample
@group
;;; @r{Versi@'on 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@'axima altura del grafo.
WIDTH-OF-LABEL es el m@'aximo ancho de la etiqueta.
VERTICAL-STEP, una opci@'on, es un entero positivo
que especifica cuanto una etiqueta de eje Y incrementa
cada l@'{@dotless{i}}nea. Por ejemplo, un paso de 5 
significa que cada l@'{@dotless{i}}nea es cinco unidades
del grafo."
@end group
@group
  (let (Y-axis
        (number-per-line (or vertical-step 1)))
    (while (> height 1)
      (if (zerop (% height Y-axis-label-spacing))
@end group
@group
          ;; @r{Inserta etiqueta.}
          (setq Y-axis
                (cons
                 (Y-axis-element
                  (* height number-per-line)
                  width-of-label)
                 Y-axis))
@end group
@group
        ;; @r{Else, inserta espacios en blanco.}
        (setq Y-axis
              (cons
               (make-string width-of-label ? )
               Y-axis)))
      (setq height (1- height)))
@end group
@group
    ;; @r{Inserta l@'{@dotless{i}}nea base.}
    (setq Y-axis (cons (Y-axis-element
                        (or vertical-step 1)
                        width-of-label)
                       Y-axis))
    (nreverse Y-axis)))
@end group
@end smallexample

Los valores para la m@'axima altura del grafo y el ancho de un
s@'{@dotless{i}}mbolo se computan por @code{print-graph} es su
expresi@'on @code{let}; as@'{@dotless{i}} @code{graph-body-print} debe
ser cambiado para aceptarlos.

@findex graph-body-print @r{Versi@'on Final.}
@smallexample
@group
;;; @r{Versi@'on Final.}
(defun graph-body-print (numbers-list height symbol-width)
  "Imprime una gr@'afica de barras del NUMBERS-LIST.
El numbers-list consiste en los valores del eje Y.
HEIGHT es la m@'axisma altura del grafo.
SYMBOL-WIDTH es el n@'umero de cada columna."
@end group
@group
  (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)
@end group
@group
      ;; @r{Dibuja el grafo columna por columna.}
      (sit-for 0)
      (setq numbers-list (cdr numbers-list)))
    ;; @r{Posiciona el punto para las etiquetas del eje X.}
    (forward-line height)
    (insert "\n")))
@end group
@end smallexample

@need 1250
Finalmente, el c@'odigo para la funci@'on @code{print-graph}:

@findex print-graph @r{Versi@'on Final.}
@smallexample
@group
;;; @r{Versi@'on Final.}
(defun print-graph
  (numbers-list &optional vertical-step)
  "El gr@'afico de barras etiquetadas del NUMBERS-LIST.
El numbers-list consiste en los valores de eje Y.
@end group

@group
Opcionalmente, VERTICAL-STEP, un entero positivo, especifica cuanto el
eje Y incrementa cada l@'{@dotless{i}}nea. Por ejemplo, un paso de 5
significa que cada fila es de cinco unidades.
@end group
@group
  (let* ((symbol-width (length graph-blank))
         ;; @code{height} @r{en ambos es el n@'umero m@'as largo}
         ;; @r{y el n@'umero con la mayor@'{@dotless{i}}a de los digitos.}
         (height (apply 'max numbers-list))
@end group
@group
         (height-of-top-line
          (if (zerop (% height Y-axis-label-spacing))
              height
            ;; @r{else}
            (* (1+ (/ height Y-axis-label-spacing))
               Y-axis-label-spacing)))
@end group
@group
         (vertical-step (or vertical-step 1))
         (full-Y-label-width
          (length
@end group
@group
           (concat
            (number-to-string
             (* height-of-top-line vertical-step))
            Y-axis-tic))))
@end group

@group
    (print-Y-axis
     height-of-top-line full-Y-label-width vertical-step)
@end group
@group
    (graph-body-print
     numbers-list height-of-top-line symbol-width)
    (print-X-axis numbers-list)))
@end group
@end smallexample

@node Testear print-graph
@appendixsubsec Testeando @code{print-graph}

@need 1250
Se puede chequear la funci@'on @code{print-graph} con una lista
ordenada de n@'umeros:

@enumerate
@item
Instala las versiones finales de @code{Y-axis-column},
@code{graph-body-print}, y @code{print-graph} (adem@'as del resto del
c@'odigo.)

@item
Copia la siguiente expresi@'on:

@smallexample
(print-graph '(3 2 5 6 7 5 3 4 6 4 3 2 1))
@end smallexample

@item
Cambia al b@'uffer @file{*scratch*} y emplaza el cursor donde se
quiere el eje etiquetado para empezar. 

@item
Escribe @kbd{M-:} (@code{eval-expression}).

@item
Pegue la expresi@'on de test dentro del minibuffer con @kbd{C-y}
(@code{yank}).

@item
Presiona @key{RET} para evaluar la expresi@'on
@end enumerate

@need 1250
Emacs imprimir@'a un grafo que se parece a:

@smallexample
@group
10 -


         *
        **   *
 5 -   ****  *
       **** ***
     * *********
     ************
 1 - *************

     |   |    |    |
     1   5   10   15
@end group
@end smallexample

@need 1200
Por otro lado, si se pasa a @code{print-graph} un @code{vertical-step}
valor de 2, evaluando esta expresi@'on:

@smallexample
(print-graph '(3 2 5 6 7 5 3 4 6 4 3 2 1) 2)
@end smallexample

@need 1250
@noindent
El grafo se parece a esto:

@smallexample
@group
20 -


         *
        **   *
10 -   ****  *
       **** ***
     * *********
     ************
 2 - *************

     |   |    |    |
     1   5   10   15
@end group
@end smallexample

@noindent
(Una pregunta: ¿es el `2' debajo del eje vertical un error o una
funcionalidad? Si se piensa que es un error, y ser@'{@dotless{i}}a un
`1', (o incluso un `0'), se pueden modificar las fuentes.)

@node Graficar palabras en funciones
@appendixsubsec Creando gr@'aficas de n@'umeros de palabras y s@'{@dotless{i}}mbolos

Ahora para el gr@'afico para el que todo este c@'odigo fu@'e escrito:
un gr@'afico que muestra cuantas definiciones de funci@'on contienen
unas pocas 10 palabras y s@'{@dotless{i}}mbolos, cuantas contienen
entre 10 y 19 palabras y s@'{@dotless{i}}mbolos, cuantos contienen
entre 20 y 29 palabras y s@'{@dotless{i}}mbolos, y as@'{@dotless{i}}.

Esto es un proceso de m@'ultiples pasos. Primero aseg@'urate que has
cargado todo el requisito del c@'odigo.

@need 1500
Eso es una buena idea para eliminar el valor de @code{top-of-ranges}
en caso de que has asignado a alg@'un valor diferente. Se puede
evaluar lo siguiente:

@smallexample
@group
(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)
@end group
@end smallexample

@noindent
Lo siguiente crea una lista del n@'umero de palabras y
s@'{@dotless{i}}mbolos en cada rango.

@need 1500
@noindent
Eval@'ua lo siguiente:

@smallexample
@group
(setq list-for-graph
       (defuns-per-range
         (sort
          (recursive-lengths-list-many-files
           (directory-files "/usr/local/emacs/lisp"
                            t ".+el$"))
          '<)
         top-of-ranges))
@end group
@end smallexample

@noindent
En mi vieja m@'aquina, esto lleva como una hora. Se parece a 303
ficheros Lisp en mi copia de Emacs version 19.23. Despu@'es de toda
esta computaci@'on, el @code{list-for-graph} ten@'{@dotless{i}}a este
valor:

@smallexample
@group
(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)
@end group
@end smallexample

@noindent
Esto significa que mi copia de Emacs tiene 537 definiciones de
funciones con poco menos de 10 palabras o s@'{@dotless{i}}mbolos en
s@'{@dotless{i}}, 1027 definiciones de funci@'on con 10 a 19 palabras
o s@'{@dotless{i}}mbolos dentro, 955 definiciones de funci@'on con 20
a 29 palabras o s@'{@dotless{i}}mbolos dentro, y as@'{@dotless{i}}.

Claramente, solo buscando esta lista se puede ver que la
mayor@'{@dotless{i}}a de definiciones de funci@'on contienen de diez a
treinta palabras y s@'{@dotless{i}}mbolos.

Ahora para imprimir. Nosotros @emph{no} queremos imprimir un grafo que
es de 1030 l@'{@dotless{i}}neas de alto @dots{}. En vez de eso,
imprimir@'{@dotless{i}}a un grafo que es mejor que venticinco
l@'{@dotless{i}}neas de alto. Un grafo cuya altura puede ser mostrada
en casi cualquier monitor, y f@'acilmente impreso en una hoja de papel.

Esto significa que cada valor en @code{list-for-graph} debe ser
reducido a un quinceavo de su valor presente.

Aqu@'{@dotless{i}} hay una corta funci@'on para hacer esto, usando dos
funciones que no se han visto todav@'{@dotless{i}}a, @code{mapcar} y
@code{lambda}.

@smallexample
@group
(defun one-fiftieth (full-range)
  "Devuelve la lista, con el cincuenteavo de cada elemento."
 (mapcar '(lambda (arg) (/ arg 50)) full-range))
@end group
@end smallexample

@node lambda
@appendixsubsec Una expresi@'on @code{lambda}: Anonimicidad @'util
@cindex Funci@'on An@'onima
@findex lambda

@code{lambda} es el s@'{@dotless{i}}mbolo para una funci@'on
an@'onima, una funci@'on sin un nombre. Cada vez que se use una
funci@'on an@'onima, se necesita incluir su cuerpo completo.

@need 1250
@noindent
De este modo,

@smallexample
(lambda (arg) (/ arg 50))
@end smallexample

@noindent
es una definici@'on de funci@'on que dice `devuelve el valor
resultante de dividir cualquier cosa que es pasada como @code{arg} por
50'.

@need 1200
Pronto, por ejemplo, se ten@'{@dotless{i}}a una funci@'on
@code{multiply-by-seven}; se multiplica su argumento por 7. Esta
funci@'on es similar, excepto que divide su argumento por 50; y, no
tiene nombre. El equivalente an@'onimo de @code{multiply-by-seven} es:

@smallexample
(lambda (number) (* 7 number))
@end smallexample

@noindent
(@xref{defun, , La forma especial @code{defun}}.)

@need 1250
@noindent
Si queremos multiplicar 3 por 7, podemos escribir:

@c !!! Clear print-postscript-figures if the computer formatting this
@c     document is too small and cannot handle all the diagrams and figures.
@c clear print-postscript-figures
@c set print-postscript-figures
@c lambda example diagram #1
@ifnottex
@smallexample
@group
(multiply-by-seven 3)
 \_______________/ ^
         |         |
      funci@'on  argumento
@end group
@end smallexample
@end ifnottex
@ifset print-postscript-figures
@sp 1
@tex
@center @image{lambda-1}
%%%% el viejo m@'etodo de incluir una imagen
% \input /usr/local/lib/tex/inputs/psfig.tex
% \centerline{\psfig{figure=/usr/local/lib/emacs/man/lambda-1.eps}}
% \catcode`\@=0 %
@end tex
@sp 1
@end ifset
@ifclear print-postscript-figures
@iftex
@smallexample
@group
(multiply-by-seven 3)
 \_______________/ ^
         |         |
      funci@'on  argumento
@end group
@end smallexample
@end iftex
@end ifclear

@noindent
Esta expresi@'on devuelve 21.

@need 1250
@noindent
De manera similar, se puede escribir:

@c lambda example diagram #2
@ifnottex
@smallexample
@group
((lambda (number) (* 7 number)) 3)
 \____________________________/ ^
               |                |
      funci@'on an@'onima     argumento
@end group
@end smallexample
@end ifnottex
@ifset print-postscript-figures
@sp 1
@tex
@center @image{lambda-2}
%%%% viejo m@'etodo de incluir una imagen
% \input /usr/local/lib/tex/inputs/psfig.tex
% \centerline{\psfig{figure=/usr/local/lib/emacs/man/lambda-2.eps}}
% \catcode`\@=0 %
@end tex
@sp 1
@end ifset
@ifclear print-postscript-figures
@iftex
@smallexample
@group
((lambda (number) (* 7 number)) 3)
 \____________________________/ ^
               |                |
      funci@'on an@'onima     argumento
@end group
@end smallexample
@end iftex
@end ifclear

@need 1250
@noindent
Si queremos dividir 100 por 50, se puede escribir:

@c lambda example diagram #3
@ifnottex
@smallexample
@group
((lambda (arg) (/ arg 50)) 100)
 \______________________/  \_/
             |              |
     funci@'on an@'onima   argumento
@end group
@end smallexample
@end ifnottex
@ifset print-postscript-figures
@sp 1
@tex
@center @image{lambda-3}
%%%% viejo m@'etodo de incluir una imagen 
% \input /usr/local/lib/tex/inputs/psfig.tex
% \centerline{\psfig{figure=/usr/local/lib/emacs/man/lambda-3.eps}}
% \catcode`\@=0 %
@end tex
@sp 1
@end ifset
@ifclear print-postscript-figures
@iftex
@smallexample
@group
((lambda (arg) (/ arg 50)) 100)
 \______________________/  \_/
             |              |
     funci@'on an@'onima   argumento
@end group
@end smallexample
@end iftex
@end ifclear

@noindent
Esta expresi@'on devuelve 2. El 100 es pasado para la funci@'on, que
divide este n@'umero por 50.

@xref{Expresiones Lambda, , Expresiones Lambda, elisp, El Manual de
Referencia GNU Emacs Lisp}, para m@'as acerca de @code{lambda}. Lisp y
expresiones Lambda se derivan del C@'alculo Lambda.

@node mapcar
@appendixsubsec La funci@'on @code{mapcar}
@findex mapcar

@code{mapcar} es una funci@'on que llama a su primer argumento con
cada elemento de su segundo argumento. El segundo argumento debe ser
una secuencia.

La parte @samp{map} del nombre viene de la frase matem@'atica,
`mapeando a trav@'es de un dominio', significa hace apply a una
funci@'on a cada uno de los elementos en un dominio. La frase
matem@'atica est@'a basada en la met@'afora de un superviviente
paseando, un paso en un momento, a trav@'es de un @'area @'el est@'a
mapeando. Y @samp{car}, de acuerdo, viene desde la noci@'on Lisp del
primero de una lista.

@need 1250
@noindent
Por ejemplo,

@smallexample
@group
(mapcar '1+ '(2 4 6))
     @result{} (3 5 7)
@end group
@end smallexample

@noindent
La funci@'on @code{1+} a@~nade uno a su argumento, es ejecutada en
@emph{each} de la lista, y una nueva lista es devuelta.

En contraste con esto @code{apply}, se aplica su primer argumento a todo
lo que permanece. (@xref{Leyendo un grafo, , Leyendo un grafo}, para
una explicaci@'on de @code{apply}.)

@need 1250
En la definici@'on de @code{one-fiftieth}, el primer argumento es la
funci@'on an@'onima:

@smallexample
(lambda (arg) (/ arg 50))
@end smallexample

@noindent
y el segundo argumento es @code{full-range}, que ser@'a asociado para
@code{list-for-graph}.

@need 1250
La expresi@'on completa se parece a esto:

@smallexample
(mapcar (lambda (arg) (/ arg 50)) full-range))
@end smallexample

@xref{Funciones de Mapeo, , Mapeando Funciones, elisp, El Manual de
Referencia de GNU Emacs Lisp}, para m@'as acerca de @code{mapcar}.

Usando la funci@'on @code{one-fiftieth}, se puede generar una lista en
el que cada elemento es un cincuenteavo del tama@~no del
correspondiente elemento en @code{list-for-graph}.

@smallexample
@group
(setq fiftieth-list-for-graph
      (one-fiftieth list-for-graph))
@end group
@end smallexample

@need 1250
La lista resultante se parece a esto:

@smallexample
@group
(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)
@end group
@end smallexample

@noindent
As@'{@dotless{i}}, @exclamdown{}ya estamos casi listos para imprimir!
(Tambi@'en se notifica la p@'erdida de informaci@'on: muchos de los
rangos superiores son 0, esto significa que menos de 50 funciones
ten@'{@dotless{i}}an muchas palabras o s@'{@dotless{i}}mbolos --- pero
no necesariamente significando que niguna ten@'{@dotless{i}}a muchas
palabras o s@'{@dotless{i}}mbolos.)

@node Otro Error
@appendixsubsec Otro error @dots{} m@'as insidioso
@cindex Error, del tipo m@'as insidioso
@cindex Insidioso tipo de error

@exclamdown{}Se dijo `casi listo para imprimir'! De acuerdo, hay un
error en la funci@'on @code{print-graph} @dots{}. Esta tiene una
opci@'on @code{vertical-step}, pero no una opci@'on
@code{horizontal-step}. La escala @code{top-of-range} va desde 10 a
300 por decenas. Pero la funci@'on @code{print-graph} imprimir@'a solo
 uno por uno.

Esto es un ejemplo cl@'asico de lo que algunos consideramos el tipo
m@'as insidioso de error, el error de omisi@'on. Este no es el tipo de
error que se puede encontrar estudiando el c@'odigo, para eso no es el
c@'odigo; 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@'odigo que sea f@'acil de comprender y
f@'acil de cambiar. Intenta ser consciente, siempre y cuando se pueda,
esto es siempre que tengas que escribir, @emph{ser@'a} reescrito, si
no pronto, eventualmente. Un m@'aximo duro de seguir.

Esta es la funci@'on @code{print-X-axis-numbered-line} que necesita el
trabajo; y entonces el @code{print-X-axis} y la funci@'on
@code{print-graph} necesita ser adaptada. No se necesita mucho para
ser hecho; hay uno simp@'atico: los n@'umeros podr@'{@dotless{i}}an
alinearse con marcas de tic. Esto toma un peque@~no pensamiento.

@need 1250
Aqu@'{@dotless{i}} est@'a el @code{print-X-axis-numbered-line} corregido:

@smallexample
@group
(defun print-X-axis-numbered-line
  (number-of-X-tics X-axis-leading-spaces
   &optional horizontal-step)
  "Imprime la l@'{@dotless{i}}neas de n@'umeros X-axis"
  (let ((number X-axis-label-spacing)
        (horizontal-step (or horizontal-step 1)))
@end group
@group
    (insert X-axis-leading-spaces)
    ;; @r{Elimina espacios extra de gu@'{@dotless{i}}a.}
    (delete-char
     (- (1-
         (length (number-to-string horizontal-step)))))
    (insert (concat
             (make-string
@end group
@group
              ;; @r{Inserta espacio en blanco.}
              (-  (* symbol-width
                     X-axis-label-spacing)
                  (1-
                   (length
                    (number-to-string horizontal-step)))
                  2)
              ? )
             (number-to-string
              (* number horizontal-step))))
@end group
@group
    ;; @r{Insertar los n@'umeros 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)))))
@end group
@end smallexample

@need 1500
Si se est@'a leyendo esto en Info, se pueden ver las nuevas versiones
@code{print-X-axis} y @code{print-graph} y los evaluarlas. Si se
est@'a leyendo esto en un libro impreso, se pueden ver las
l@'{@dotless{i}}neas cambiadas aqu@'{@dotless{i}} (el texto completo
es mucho para imprimir).

@iftex
@smallexample
@group
(defun print-X-axis (numbers-list horizontal-step)
  @dots{}
    (print-X-axis-numbered-line
     tic-number leading-spaces horizontal-step))
@end group
@end smallexample

@smallexample
@group
(defun print-graph
  (numbers-list
   &optional vertical-step horizontal-step)
  @dots{}
    (print-X-axis numbers-list horizontal-step))
@end group
@end smallexample
@end iftex

@ifnottex
@smallexample
@group
(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."
@end group
@group
;; Valor del s@'{@dotless{i}}mbolo symbol-width and full-Y-label-width
;; se pasan por `print-graph'.
  (let* ((leading-spaces
          (make-string full-Y-label-width ? ))
       ;; symbol-width @r{is provided by} graph-body-print
       (tic-width (* symbol-width X-axis-label-spacing))
       (X-length (length numbers-list))
@end group
@group
       (X-tic
        (concat
         (make-string
          ;; @r{Crea una cadena de espacios en blanco.}
          (-  (* symbol-width X-axis-label-spacing)
              (length X-axis-tic-symbol))
          ? )
@end group
@group
         ;; @r{Concatena espacios en blanco con el
         s@'{@dotless{i}}mbolo tic.}
         X-axis-tic-symbol))
       (tic-number
        (if (zerop (% X-length tic-width))
            (/ X-length tic-width)
          (1+ (/ X-length tic-width)))))
@end group

@group
    (print-X-axis-tic-line
     tic-number leading-spaces X-tic)
    (insert "\n")
    (print-X-axis-numbered-line
     tic-number leading-spaces horizontal-step)))
@end group
@end smallexample

@smallexample
@group
(defun print-graph
  (numbers-list &optional vertical-step horizontal-step)
  "Imprime el gr@'afico de barras etiquetada de los NUMBERS-LIST.
Los numbers-list consisten en los valores del eje Y."
@end group

@group
Opcionalmente, VERTICAL-STEP, un entero positivo, especifica cuanto un
eje Y se incrementa por cada l@'{@dotless{i}}nea. Por ejemplo, un paso
de 5 significa que cada fila es de cinco unidades.
@end group

@group
Opcionalmente, HORIZONTAL-STEP, un entero positivo,
especifica cuanto se incrementa en un eje X cada columna."
  (let* ((symbol-width (length graph-blank))
         ;; @code{height} @r{es ambos el n@'umero m@'as largo}
         ;; @r{y el n@'umero con la mayor@'{@dotless{i}}a de los d@'{@dotless{i}}gitos.}
         (height (apply 'max numbers-list))
@end group
@group
         (height-of-top-line
          (if (zerop (% height Y-axis-label-spacing))
              height
            ;; @r{else}
            (* (1+ (/ height Y-axis-label-spacing))
               Y-axis-label-spacing)))
@end group
@group
         (vertical-step (or vertical-step 1))
         (full-Y-label-width
          (length
           (concat
            (number-to-string
             (* height-of-top-line vertical-step))
            Y-axis-tic))))
@end group
@group
    (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)))
@end group
@end smallexample
@end ifnottex

@c qqq
@ignore
Graphing Definitions Re-listed

@need 1250
Here are all the graphing definitions in their final form:

@smallexample
@group
(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)
 "Lista especificando rangos para `defuns-per-range'.")
@end group

@group
(defvar graph-symbol "*"
  "Cadena usada como s@'{@dotless{i}}mbolo en grafo, normalmente un asterisco.")
@end group

@group
(defvar graph-blank " "
  "La cadena como un espacio en blanco en grafo, normalmente un
  espacio en blanco.
graph-blank debe ser el mismo n@'umero de columnas amplio como graph-symbol.")
@end group

@group
(defvar Y-axis-tic " - "
   "La Cadena que sigue el n@'umero en una etiqueta del eje Y.")
@end group

@group
(defvar Y-axis-label-spacing 5
  "N@'umero de l@'{@dotless{i}}neas desde una etiqueta del eje Y al siguiente.")
@end group

@group
(defvar X-axis-tic-symbol "|"
  "Cadena para insertar para apuntar a una columna en el eje X.")
@end group

@group
(defvar X-axis-label-spacing
  (if (boundp 'graph-blank)
      (* 5 (length graph-blank)) 5)
  "N@'umeros de unidades desde un eje X al siguiente.")
@end group
@end smallexample

@smallexample
@group
(defun count-words-in-defun ()
  "Devuelve el n@'umero de palabras y s@'{@dotless{i}}mbolos en una defun."
  (beginning-of-defun)
  (let ((count 0)
        (end (save-excursion (end-of-defun) (point))))
@end group

@group
    (while
        (and (< (point) end)
             (re-search-forward
              "\\(\\w\\|\\s_\\)+[^ \t\n]*[ \t\n]*"
              end t))
      (setq count (1+ count)))
    count))
@end group
@end smallexample

@smallexample
@group
(defun lengths-list-file (filename)
  "Devuelve la lista de tama@~nos de definiciones con FILE.
La lista devuelta es una lista de n@'umeros.
Cada n@'umero es el n@'umero de palabras o
s@'{@dotless{i}}mbolos en una definici@'on."
@end group

@group
  (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))
@end group

@group
      (while (re-search-forward "^(defun" nil t)
        (setq lengths-list
              (cons (count-words-in-defun) lengths-list)))
      (kill-buffer buffer)
      lengths-list)))
@end group
@end smallexample

@smallexample
@group
(defun lengths-list-many-files (list-of-files)
  "Retorna la lista de tama@~nos de defuns en LIST-OF-FILES."
  (let (lengths-list)
;;; @r{true-or-false-test}
    (while list-of-files
      (setq lengths-list
            (append
             lengths-list
@end group
@group
;;; @r{Genera una lista de longitudes.}
             (lengths-list-file
              (expand-file-name (car list-of-files)))))
;;; @r{Crea una lista de ficheros ordenada.}
      (setq list-of-files (cdr list-of-files)))
;;; @r{Devuelve el valor final de las longitudes.}
    lengths-list))
@end group
@end smallexample

@smallexample
@group
(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)
@end group

@group
    ;; @r{Bucle Exterior.}
    (while top-of-ranges

      ;; @r{Bucle Interior.}
      (while (and
              ;; @r{Necesita el n@'umero para el test num@'erico.}
              (car sorted-lengths)
              (< (car sorted-lengths) top-of-range))

        ;; @r{Cuenta el n@'umero de definiciones con el rango actual.}
        (setq number-within-range (1+ number-within-range))
        (setq sorted-lengths (cdr sorted-lengths)))
@end group

@group
      ;; @r{Bucle de salida interna, pero permanece con el bucle exterior.}

      (setq defuns-per-range-list
            (cons number-within-range defuns-per-range-list))
      (setq number-within-range 0)      ; @r{Resetea el contador a cero.}

      ;; @r{Mover al siguiente rango.}
      (setq top-of-ranges (cdr top-of-ranges))
      ;; @r{Especifica el siguiente mejor rango de valores.}
      (setq top-of-range (car top-of-ranges)))
@end group

@group
    ;; @r{Salir del bucle exterior y cuenta el n@'umero de defuns tan largas como}
    ;; @r{el valor m@'as largo (top-of-range).}
    (setq defuns-per-range-list
          (cons
           (length sorted-lengths)
           defuns-per-range-list))

    ;; @r{Devuelve una lista del n@'umero de definiciones con cada rango,}
    ;; @r{ del m@'as peque@~no al m@'as largo.}
    (nreverse defuns-per-range-list)))
@end group
@end smallexample

@smallexample
@group
(defun column-of-graph (max-graph-height actual-height)
  "Devuelve la lista de cadenas MAX-GRAPH-HEIGHT;
ACTUAL-HEIGHT son los s@'{@dotless{i}}mbolos del grafo.
Los s@'{@dotless{i}}mbolos del grafo son entradas contiguas 
al fin de la lista.
La lista ser@'a insertada como una columna de un grafo.
Las cadenas son tanto grafos en blanco como 
s@'{@dotless{i}}mbolos de un grafo."
@end group

@group
  (let ((insert-list nil)
        (number-of-top-blanks
         (- max-graph-height actual-height)))

    ;; @r{Rellenar en @code{graph-symbols}.}
    (while (> actual-height 0)
      (setq insert-list (cons graph-symbol insert-list))
      (setq actual-height (1- actual-height)))
@end group

@group
    ;; @r{Rellenar en @code{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)))

    ;; @r{Devuelve la lista completa.}
    insert-list))
@end group
@end smallexample

@smallexample
@group
(defun Y-axis-element (number full-Y-label-width)
  "Construye una etiqueta NUMERADA
Un elemento numerado se parece a esto ` 5 - ', 
y est@'a tan acu@~nado como se necesita as@'{@dotless{i}} todo se
alinea con el elemento para el n@'umero mayor."
@end group
@group
  (let* ((leading-spaces
         (- full-Y-label-width
            (length
             (concat (number-to-string number)
                     Y-axis-tic)))))
@end group
@group
    (concat
     (make-string leading-spaces ? )
     (number-to-string number)
     Y-axis-tic)))
@end group
@end smallexample

@smallexample
@group
(defun print-Y-axis
  (height full-Y-label-width &optional vertical-step)
  "Inserta el eje Y por HEIGHT y FULL-Y-LABEL-WIDTH.
La altura debe ser la m@'axima altura del grafo.
La altura completa es el ancho del mayor elemento etiquetado.
Opcionalmente, se imprime de acuerdo a VERTICAL-STEP."
@end group
@group
;; Valor de la altura y full-Y-label-width
;; son pasados por `print-graph'.
  (let ((start (point)))
    (insert-rectangle
     (Y-axis-column height full-Y-label-width vertical-step))
@end group
@group
    ;; @r{Posiciona el punto lista para insertar el grafo.}
    (goto-char start)
    ;; @r{Mueve el punto hacia adelante por el valor de} full-Y-label-width
    (forward-char full-Y-label-width)))
@end group
@end smallexample

@smallexample
@group
(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)  ; @r{En la primera columna.}
@end group
@group
    ;; @r{Inserta el segundo tic en el lugar adecuado.}
    (insert (concat
             (make-string
              (-  (* symbol-width X-axis-label-spacing)
                  ;; @r{Inserta el espacio en blanco al segundo s@'{@dotless{i}}mbolo tic.}
                  (* 2 (length X-axis-tic-symbol)))
              ? )
             X-axis-tic-symbol))
@end group
@group
    ;; @r{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))))
@end group
@end smallexample

@smallexample
@group
(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))))
@end group
@end smallexample

@smallexample
@group
(defun graph-body-print (numbers-list height symbol-width)
  "Imprime un gr@'afico de barras de la NUMBERS-LIST.
La numbers-list consiste en los valores de eje Y.
HEIGHT es el m@'aximo tama@~no del grafo.
SYMBOL-WIDTH es el n@'umero de cada columna."
@end group
@group
  (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)
@end group
@group
      ;; @r{Dibuja el grafo columna por columna.}
      (sit-for 0)
      (setq numbers-list (cdr numbers-list)))
    ;; @r{Posiciona el punto para las etiquetas del eje X.}
    (forward-line height)
    (insert "\n")))
@end group
@end smallexample

@smallexample
@group
(defun Y-axis-column
  (height width-of-label &optional vertical-step)
  "Construye una lista de etiquetas del eje Y.
HEIGHT es la m@'axima del grafo.
WIDTH-OF-LABEL es el m@'aximo ancho de la etiqueta.
@end group
@group
VERTICAL-STEP, una opci@'on, es un entero positivo
que especifica cuanto una etiqueta del eje Y incrementa
por cada l@'{@dotless{i}}nea. Por ejemplo, un paso de 5 
significa que cada l@'{@dotless{i}}nea es cinco unidades
del grafo"
  (let (Y-axis
        (number-per-line (or vertical-step 1)))
@end group
@group
    (while (> height 1)
      (if (zerop (% height Y-axis-label-spacing))
          ;; @r{Inserta la etiqueta.}
          (setq Y-axis
                (cons
                 (Y-axis-element
                  (* height number-per-line)
                  width-of-label)
                 Y-axis))
@end group
@group
        ;; @r{Else, inserta espacios en blanco.}
        (setq Y-axis
              (cons
               (make-string width-of-label ? )
               Y-axis)))
      (setq height (1- height)))
@end group
@group
    ;; @r{Inserta l@'{@dotless{i}}nea base.}
    (setq Y-axis (cons (Y-axis-element
                        (or vertical-step 1)
                        width-of-label)
                       Y-axis))
    (nreverse Y-axis)))
@end group
@end smallexample

@smallexample
@group
(defun print-X-axis-numbered-line
  (number-of-X-tics X-axis-leading-spaces
   &optional horizontal-step)
  "Imprime la l@'{@dotless{i}}neas de n@'umeros X-axis"
  (let ((number X-axis-label-spacing)
        (horizontal-step (or horizontal-step 1)))
@end group
@group
    (insert X-axis-leading-spaces)
    (delete-char (- (1- (length (number-to-string horizontal-step)))))
    (insert (concat
             (make-string
              ;; @r{Inserta el espacio en blanco al siguiente n@'umero.}
              (-  (* symbol-width X-axis-label-spacing)
                  (1- (length (number-to-string horizontal-step)))
                  2)
              ? )
             (number-to-string (* number horizontal-step))))
@end group
@group
    ;; @r{Inserta n@'umeros que permanazcan.}
    (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)))))
@end group
@end smallexample

@smallexample
@group
(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."
@end group
@group
;; Valor del s@'{@dotless{i}}mbolo symbol-width and full-Y-label-width
;; se pasan por `print-graph'.
  (let* ((leading-spaces
          (make-string full-Y-label-width ? ))
       ;; symbol-width @r{is provided by} graph-body-print
       (tic-width (* symbol-width X-axis-label-spacing))
       (X-length (length numbers-list))
@end group
@group
       (X-tic
        (concat
         (make-string
          ;; @r{Crea una cadena de espacios en blanco.}
          (-  (* symbol-width X-axis-label-spacing)
              (length X-axis-tic-symbol))
          ? )
@end group
@group
         ;; @r{Concatena espacios en blanco con el
         s@'{@dotless{i}}mbolo tic.}
         X-axis-tic-symbol))
       (tic-number
        (if (zerop (% X-length tic-width))
            (/ X-length tic-width)
          (1+ (/ X-length tic-width)))))
@end group

@group
    (print-X-axis-tic-line
     tic-number leading-spaces X-tic)
    (insert "\n")
    (print-X-axis-numbered-line
     tic-number leading-spaces horizontal-step)))
@end group
@end smallexample

@smallexample
@group
(defun one-fiftieth (full-range)
  "Devuelve la lista, cada n@'umero del que es 1/50 posiciones previas."
 (mapcar '(lambda (arg) (/ arg 50)) full-range))
@end group
@end smallexample

@smallexample
@group
(defun print-graph
  (numbers-list &optional vertical-step horizontal-step)
  "Imprime el gr@'afico de barras etiquetada de los NUMBERS-LIST.
Los numbers-list consisten en los valores del eje Y."
@end group

@group
Opcionalmente, VERTICAL-STEP, un entero positivo, especifica cuanto un
eje Y se incrementa por cada l@'{@dotless{i}}nea. Por ejemplo, un paso
de 5 significa que cada fila es de cinco unidades.
@end group

@group
Opcionalmente, HORIZONTAL-STEP, un entero positivo,
especifica cuanto se incrementa en un eje X cada columna."
  (let* ((symbol-width (length graph-blank))
         ;; @code{height} @r{es ambos el n@'umero m@'as largo}
         ;; @r{y el n@'umero con la mayor@'{@dotless{i}}a de los d@'{@dotless{i}}gitos.}
         (height (apply 'max numbers-list))
@end group
@group
         (height-of-top-line
          (if (zerop (% height Y-axis-label-spacing))
              height
            ;; @r{else}
            (* (1+ (/ height Y-axis-label-spacing))
               Y-axis-label-spacing)))
@end group
@group
         (vertical-step (or vertical-step 1))
         (full-Y-label-width
          (length
           (concat
            (number-to-string
             (* height-of-top-line vertical-step))
            Y-axis-tic))))
@end group
@group

    (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)))
@end group
@end smallexample
@c qqq
@end ignore

@page
@node Grafo impreso final
@appendixsubsec El gr@'afico impreso

Cuando est@'e hecho e instalado, se puede llamar al comando
@code{print-graph} como esto:
@sp 1

@smallexample
@group
(print-graph fiftieth-list-for-graph 50 10)
@end group
@end smallexample
@sp 1

@noindent
Aqu@'{@dotless{i}} est@'a el gr@'afico:
@sp 2

@smallexample
@group
1000 -  *
        **
        **
        **
        **
 750 -  ***
        ***
        ***
        ***
        ****
 500 - *****
       ******
       ******
       ******
       *******
 250 - ********
       *********                     *
       ***********                   *
       *************                 *
  50 - ***************** *           *
       |   |    |    |    |    |    |    |
      10  50  100  150  200  250  300  350
@end group
@end smallexample

@sp 2

@noindent
El grupo largo de funciones contienen de 10 a 19 palabras y
s@'{@dotless{i}}mbolos.

@node Software Libre y Manuales Libres
@appendix Software Libre y Manuales Libres

@strong{por Richard M. Stallman}
@sp 1

La mayor deficiencia en sistemas operativos libres no est@'a en el
software --- es la falta de buenos manuales libres que se puedan
incluir en estos sistemas. Muchos de nuestros programas m@'as
importantes no vienen con manuales completos. La documentaci@'on 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.

@'Erase una vez, hace muchos a@~nos, se piensa que
aprender@'{@dotless{i}}a Perl. Se tiene una copia de un manual libre,
pero se encontr@'o dif@'{@dotless{i}}cil de leer. Cuando pregunto a
los usuarios de Perl acerca de alternativas, me contaron que
ser@'{@dotless{i}}an mejor los manuales introductorios --- pero estos
no eran libres.

¿Por qu@'e era esto? Los autores de los buenos manuales
los hab@'{@dotless{i}}an escrito para O'Reilly Associates, que los
publicaron con t@'erminos restrictivos --- no copiando, no
modificando, los ficheros fuentes est@'an disponibles --- que los
excluyen desde la comunidad de software libre.

No era la primera vez que esto ocurr@'{@dotless{i}}a, y (para
nuestra comunidad es una gran p@'erdida) eso est@'a lejos desde el
@'ultimo. 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@'abil me cuente que un manual que
est@'a escribiendo, con el que @'el espera ayudar al proyecto GNU ---
y entonces ten@'{@dotless{i}}a mis esperanzas frustradas, como se ha
procedi@'o a explicar que @'el ten@'{@dotless{i}}a que haber firmado
un contrato con una editorial que restringir@'{@dotless{i}}a eso,
as@'{@dotless{i}} que no puede usarlo.

Debido a que escribir buen ingl@'es es una habilidad rara entre
programadores, se pueden perder manuales por este motivo.

La documentaci@'on, como el software, es una cuesti@'on 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@'{@dotless{i}} estaban bien. La Free Software Foundation
@emph{Fundaci@'on por el Software Libre} @uref{http://shop.fsf.org,
vende copias impresas} de @uref{http://www.gnu.org/doc/doc.html,
manuales libres de GNU}, tambi@'en. Pero los manuales de GNU est@'an
disponibles en forma de c@'odigo fuente, mientras que estos manuales
est@'an 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@'on de dar a todos los usuarios ciertas libertades. La
redistribuci@'on (incluyendo redistribuci@'on comercial) debe ser
permitida, as@'{@dotless{i}} el manual puede acompa@~nar cada copia
del programa, en l@'{@dotless{i}}ne o en papel. El permiso para modificar
es crucial tambi@'en.

Como regla general, no se cree que sea esencial para la gente tener
permisos para modificar todas las partes de art@'{@dotless{i}}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@'a
obligado a dar permisos para modificar art@'{@dotless{i}}culos como
este, que describen nuestras acciones y nuestras vistas.

Pero hay una raz@'on particular de por qu@'e la libertad de modificar
es crucial para la documentaci@'on de software libre. Cuando las
personas ejercita su derecho a modificar el software, y a@~nadir o
cambiar sus funcionalidades, si son consciente ellos cambiar@'an el
manual tambi@'en --- as@'{@dotless{i}} se puede proveer
documentaci@'on usable y cuidada con el programa modificado. Un manual
que prohibe a los programadores ser consciente y finalizar el trabajo,
o m@'as 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@'on es
inaceptable, algunos tipos de l@'{@dotless{i}}mites en el m@'etodo de
modificar no tiene tanto problema. Por ejemplo, los requisitos para
preservar la noticia de autores del copyright, los t@'erminos de
distribuci@'on, o la lista de autores, est@'en ok. Eso es tambi@'en 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@'ecnicos. (Algunos manuales de GNU los tienen).

Estos tipos de restricciones no son un problema porque, como materia
pr@'actica, no para al programador consciente desde la adaptaci@'on
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@'ecnico
del manual, y entonces se distribuye el resultado en todos los medios
usuales, a trav@'es de todos los canales usuales; de otro modo, las
restricciones bloquean la comunidad, el manual no es libre, y
as@'{@dotless{i}} no se necesita otro manual.

Desafortunadamente, con frecuencia es duro encontrar a alguien a
escribir otro manual cuando un manual privativo. El obst@'aculo es que
muchos usuario piensan que un manual privativo es suficientemente
bueno --- as@'{@dotless{i}} ellos no ven la necesidad de escribir un
manual libre. Ellos no ven que el sistema operativo tiene un gazapo
que necesita se rellenado.

@questiondown{}Por qu@'e los usuarios piensan que los manuales
privativos son suficientemente buenos? Algunos no han considerado la
cuesti@'on. Espero que este art@'{@dotless{i}}culo har@'a alguna cosa
para cambiar esto.

Otros usuarios considera manuales privativos aceptables para la misma
raz@'on as@'{@dotless{i}} muchas personas software privativo
aceptable: ellos judgan en t@'erminos puramente pr@'acticos, 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@'an guiadas por esto quienes valoran
la libertad.

Por favor, populariza esta cuesti@'on. Se contin@'ua a perder manuales
para publicaci@'on privativa. Si se populariza que los manuales
privativos no son suficientes, quiz@'as la siguiente persona que
quiere ayudar a GNU escribiendo documentaci@'on realizar@'a, antes de
que sea demasiado tarde, lo que @'el debe que todo sea libre.

Se puede tambi@'en 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@'erminos de la distribuci@'on de un manual
antes de que se compre, y preferimos manuales copyleft a los no copyleft.

@sp 2
@noindent
Note: La Fundaci@'on para el Software Libre mantiene una p@'agina en
su sitio Web que liste libros libres disponibles desde otras
editoriales:@* @uref{http://www.gnu.org/doc/other-free-books.html}

@node GNU Free Documentation License
@appendix GNU Free Documentation License

@cindex FDL, GNU Free Documentation License
@include doclicense.texi

@node @'Indice
@unnumbered @'Indice

@ignore
MENU ENTRY: NODE NAME.
@end ignore

@printindex cp

@iftex
@c Place biographical information on right-hand (verso) page

@tex
\par\vfill\supereject
\ifodd\pageno
    \global\evenheadline={\hfil} \global\evenfootline={\hfil}
    \global\oddheadline={\hfil} \global\oddfootline={\hfil}
    %\page\hbox{}\page
\else
%    \par\vfill\supereject
    \global\evenheadline={\hfil} \global\evenfootline={\hfil}
    \global\oddheadline={\hfil} \global\oddfootline={\hfil}
    %\page\hbox{}%\page
    %\page\hbox{}%\page
\fi
@end tex

@c page
@w{ }

@c ================ Biographical information ================

@w{ }
@sp 8
@center Acerca del Autor
@sp 1
@end iftex

@ifnottex
@node Acerca del Autor
@unnumbered Acerca del Autor
@end ifnottex

@quotation
Robert J. Chassell ha trabajado con GNU Emacs desde 1985. @'El
escribe, edita y ense@~na Emacs y Emacs Lisp, y habla alrededor del
mundo acerca de la libertad del software. Chassell es Director
fundador y Tesorero de la Fundaci@'on por el Software Libre (FSF). @'El
se gradu@'o la Universidad de Cambridge, en Inglaterra. @'El tiene un
inter@'es cont@'inuo en historia econ@'omica y social y vuela su
propio aeroplano
@end quotation

@c @page
@c @w{ }
@c
@c @c Prevent page number on blank verso, so eject it first.
@c @tex
@c \par\vfill\supereject
@c @end tex

@c @iftex
@c @headings off
@c @evenheading @thispage @| @| @thistitle
@c @oddheading            @| @| @thispage
@c @end iftex

@bye
