diff options
Diffstat (limited to 'es-es')
-rw-r--r-- | es-es/c-es.html.markdown | 417 | ||||
-rw-r--r-- | es-es/elisp-es.html.markdown | 377 |
2 files changed, 794 insertions, 0 deletions
diff --git a/es-es/c-es.html.markdown b/es-es/c-es.html.markdown new file mode 100644 index 00000000..2e7cf8be --- /dev/null +++ b/es-es/c-es.html.markdown @@ -0,0 +1,417 @@ +--- +language: c +filename: learnc.c +contributors: + - ["Adam Bard", "http://adambard.com/"] +translators: + - ["Francisco García", "http://flaskbreaker.tumblr.com/"] +lang: es-es +--- + +¡Ah!, C. Aun hoy en día sigue siendo el lenguaje por excelencia de la +computación moderna de alto rendimiento. + +C es el lenguaje de más bajo nivel que la mayoría de los programadores +llegarán a usar, pero lo compensa de sobra con pura velocidad. Solo +ten en cuenta el manejo manual de memoria y te llevará tan lejos como +necesites. + +```c +// Los comentarios de una sola línea comienzan con // + +/* +Los comentarios multilínea tienen este aspecto. +*/ + +// Importa cabeceras con #include +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +// Declara por adelantado las armaduras de las funciones en un archivo .h, +// o al principio de tu archivo .c . +void function_1(); +void function_2(); + +// El punto de entrada de tu programa es una función llamada main con +// retorno de tipo entero (integer). +int main() { + +// Muestra la salida usando printf, para el "formato print" +// %d es un entero, \n es una nueva línea +printf("%d\n", 0); // => Muestra 0 +// Todas las sentencias deben terminar con un punto y coma. + +/////////////////////////////////////// +// Tipos +/////////////////////////////////////// + +// Tienes que declarar una variable antes de usarla. La declaración de una +// variable necesites que especifiques su tipo; el tipo de una variable +// determina su tamaño en bytes. + +// 'ints' (enteros) son normalmente de 4 bytes +int x_int = 0; + +// 'shorts' son normalmente de 2 bytes +short x_short = 0; + +// 'chars' son fijo de 1 byte +char x_char = 0; +char y_char = 'y'; // Los caracteres literales se entrecomillan con '' + +// 'longs' son a menudo de 4 a 8 bytes; 'long longs' son fijo de por lo +// menos 64 bits +long x_long = 0; +long long x_long_long = 0; + +// 'floats' son normalmente números de coma flotante de 32 bits +float x_float = 0.0; + +// 'doubles' son normalmente números de coma flotante de 64 bits +double x_double = 0.0; + +// Todos los tipos enteros pueden ser 'unsigned'. Esto significa que no +// pueden ser negativos, pero el valor máximo de una variable 'unsigned' +// es mayor que el de una no 'unsigned' del mismo tamaño. +unsigned char ux_char; +unsigned short ux_short; +unsigned int ux_int; +unsigned long long ux_long_long; + +// Todos menos 'char', que es siempre de 1 byte, varían el tamaño +// dependiendo de tu máquina. sizeof(T) te dice el tamaño de una variable +// de tipo T en bytes por lo que podemos expresar el tamaño de estos tipos +// portatilmente. +// Por ejemplo, +printf("%lu\n", sizeof(int)); // => 4 (en máquinas con 'words' de 4 bytes) + +// Los arrays deben ser inicializados con un tamaño concreto. +char my_char_array[20]; // Este array ocupa 1 * 20 = 20 bytes +int my_int_array[20]; // Este array ocupa 4 * 20 = 80 bytes + // (suponiendo que tenemos 'words' de 4-byte) + + +// Puedes inicializar un array a 0 así: +char my_array[20] = {0}; + +// Indexar un array es como en otros lenguajes -o, más bien, otros +// lenguajes son como C- +my_array[0]; // => 0 + +// Los arrays varían; ¡son sólo memoria! +my_array[1] = 2; +printf("%d\n", my_array[1]); // => 2 + +// Las cadenas (strings) son sólo arrays de 'chars' (caracteres) +// terminados en un byte NUL (0x00), representado en las cadenas como el carácter especial '\0'. +// (No tenemos porqué añadir el byte nulo en cadenas literales; el +// compilador lo añade al final por nosotros.) +char a_string[20] = "Esto es una cadena"; +printf("%s\n", a_string); // %s se sutituye por una cadena. + +/* +Te habrás dado cuenta de que a_string es solo de 18 caracteres. +El 'char' #19 es el byte nulo. +El 'char' #20 es de valor indefinido. +*/ + +printf("%d\n", a_string[18]); // => 0 + +/////////////////////////////////////// +// Operadores +/////////////////////////////////////// + +int i1 = 1, i2 = 2; // Forma corta de declaración múltiple +float f1 = 1.0, f2 = 2.0; + +// La aritmética es sencilla +i1 + i2; // => 3 +i2 - i1; // => 1 +i2 * i1; // => 2 +i1 / i2; // => 0 (0.5, pero es truncado tras el 0) + +f1 / f2; // => 0.5, más o menos épsilon +// Módulo está también +11 % 3; // => 2 + +// Los operadores de comparación te resultaran familiares, pero no hay +// booleanos en C. Usamos enteros (ints) en su lugar. 0 es falso, +// cualquier otra cosa es verdadero. (Los operadores de comparación +// siempre devuelven 0 o 1) +3 == 2; // => 0 (Falso) +3 != 2; // => 1 (Verdadero) +3 > 2; // => 1 +3 < 2; // => 0 +2 <= 2; // => 1 +2 >= 2; // => 1 + +// La lógica funiona en enteros +!3; // => 0 (not lógico) +!0; // => 1 +1 && 1; // => 1 (and lógico) +0 && 1; // => 0 +0 || 1; // => 1 (or lógico) +0 || 0; // => 0 + +// ¡Operadores de bits! +~0x0F; // => 0xF0 (Negación) +0x0F & 0xF0; // => 0x00 (AND) +0x0F | 0xF0; // => 0xFF (OR) +0x04 ^ 0x0F; // => 0x0B (XOR) +0x01 << 1; // => 0x02 (desplazar hacia la izquierda (por 1)) +0x02 >> 1; // => 0x01 (desplazar hacia la derecha (por 1)) + +/////////////////////////////////////// +// Estructuras de Control +/////////////////////////////////////// + +if (0) { + printf("Yo nunca ocurro\n"); +} else if (0) { + printf("Yo tampoco ocurro nunca\n"); +} else { + printf("Yo me muestro\n"); +} + +// Mientras el bucle exista +int ii = 0; +while (ii < 10) { + printf("%d, ", ii++); // ii++ incrementa ii en uno, después de usar su valor. +} // => muestra "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " + +printf("\n"); + +int kk = 0; +do { + printf("%d, ", kk); +} while (++kk < 10); // ++kk incrementa kk en uno, antes de usar su valor. +// => muestra "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " + +printf("\n"); + +// Bucles 'for' también +int jj; +for (jj=0; jj < 10; jj++) { + printf("%d, ", jj); +} // => muestra "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " + +printf("\n"); + +/////////////////////////////////////// +// Cambios de Tipo +/////////////////////////////////////// + +// Cada valor en C tiene un tipo, pero tu puedes ingresar un valor en +// otro tipo si quieres. + +int x_hex = 0x01; // Puedes asignar hexadecimales a variables + +// El cambio de tipos intentará mantener sus valores numéricos +printf("%d\n", x_hex); // => Muestra 1 +printf("%d\n", (short) x_hex); // => Muestra 1 +printf("%d\n", (char) x_hex); // => Muestra 1 + +// Los tipos se desbordan sin aviso +printf("%d\n", (char) 257); // => 1 (El valor máximo de un 'char' es 255) + +// Los tipos enteros puden cambiarse a tipos de coma flotante, y viceversa +printf("%f\n", (float)100); // %f se sustituye por un 'float' +printf("%lf\n", (double)100); // %lf se sustituye por un 'double' +printf("%d\n", (char)100.0); + +/////////////////////////////////////// +// Punteros +/////////////////////////////////////// + +// Un puntero es una variable declarada para almacenar una dirección de +// memoria. Su declaración además nos dirá el tipo de dato al que apunta. +// Puedes obtener la dirección de memoria de tus variables, y después +// enlazarlas con ellos. + +int x = 0; +printf("%p\n", &x); // Usa & para obtener la dirección de una variable. +// (%p se sustituye por un puntero) +// => Muestra alguna dirección de memoria; + +// Los tipos de puntero terminan con * en su declaración +int* px; // px es un puntero a un 'int' +px = &x; // Almacena la dirección de x en px +printf("%p\n", px); // => Muestra alguna dirección de memoria + +// Para obtener el valor de la dirección a la que apunta un puntero, pon +// * delante para desreferenciarle. +printf("%d\n", *px); // => Muestra 0, el valor de x y de la dirección a la + // que apunta px + +// También puedes cambiar el valor al que está apuntando el puntero. +// Tenemos que meter la desreferencia entre paréntesis porque ++ tiene +// prioridad frente a *. +(*px)++; // Incrementa el valor al que apunta px en 1 +printf("%d\n", *px); // => Muestra 1 +printf("%d\n", x); // => Muestra 1 + +int x_array[20]; // Los arrays son una buena manera de distribuir bloques +int xx; // continuos de memoria. +for (xx=0; xx<20; xx++) { + x_array[xx] = 20 - xx; +} // Inicializa x_array a 20, 19, 18,... 2, 1 + +// Declara un puntero de tipo 'int' y lo inicializa para apuntar a x_array +int* x_ptr = x_array; +// x_ptr ahira apunta al primer elemento del 'array' (el entero 20). +// Esto funciona porque las 'arrays' actualmente son solo punteros a su +// primer elemento. + +// Los 'arrays' son punteros a su primer elemento. +printf("%d\n", *(x_ptr)); // => Muestra 20 +printf("%d\n", x_array[0]); // => Muestra 20 + +// Los punteros aumentan y disminuyen en función de su tipo. +printf("%d\n", *(x_ptr + 1)); // => Muestra 19 +printf("%d\n", x_array[1]); // => Muestra 19 + +// Puedes también asigner dinamicamente bloques contiguos de memoria con +// la función malloc de la librería estándard, que toma un entero como +// argumento representando el número de bytes a asignar de la pila. +int* my_ptr = (int*) malloc(sizeof(int) * 20); +for (xx=0; xx<20; xx++) { + *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx funcionaría también aquí +} // Inicializa la memoria a 20, 19, 18, 17... 2, 1 (como 'ints') + +// Desreferenciando la memoria que no has asignado te dará resultados +// impredecibles +printf("%d\n", *(my_ptr + 21)); // => Prints who-knows-what? + +// Cuando hallas acabado con el bloque de memoría malloc, necesitas +// liberarlo o sino nadie más podrá usarlo hasta que tu programa se cierre +free(my_ptr); + +// Las cadenas pueden ser 'arrays' de chars, pero normalmente se +// representan con punteros 'char': +char* my_str = "This is my very own string"; + +printf("%c\n", *my_str); // => 'T' + +function_1(); +} // fin de la función main + +/////////////////////////////////////// +// Funciones +/////////////////////////////////////// + +// Sintexis de la declaración de funciones: +// <tipo de retorno> <nombre>(<argumentos>) + +int add_two_ints(int x1, int x2){ + return x1 + x2; // Usa 'return' para dar una salida +} + +/* +Las funciones son de paso por valor, pero puedes hacer tus propias +referencias con punteros de manera que las funciones puedan cambiar sus +valores. + +Ejemplo: invertidor de cadenas in-situ +*/ + +// Una función 'void' no retorna valor +void str_reverse(char* str_in){ + char tmp; + int ii=0, len = strlen(str_in); // Strlen es parte de la librería + for(ii=0; ii<len/2; ii++){ // estándard + tmp = str_in[ii]; + str_in[ii] = str_in[len - ii - 1]; // ii-th último 'char' + str_in[len - ii - 1] = tmp; + } +} + +/* +char c[] = "Esto es una prueba."; +str_reverse(c); +printf("%s\n", c); // => ".abeurp anu se otsE" +*/ + +/////////////////////////////////////// +// Definición de tipos y estructuras +/////////////////////////////////////// + +// Los 'Typedefs' pueden ser utilizados para crear alias de tipos. +typedef int my_type; +my_type my_type_var = 0; + +// Las estructuras son sólo grupos de datos. +struct rectangle { + int width; + int height; +}; + + +void function_1(){ + + struct rectangle my_rec; + + // Utiliza los miembros de una estructura con . + my_rec.width = 10; + my_rec.height = 20; + + // Puedes declarar punteros a estructuras + struct rectangle* my_rec_ptr = &my_rec; + + // Usa la desreferencia para modificar sus miembros... + (*my_rec_ptr).width = 30; + + // ... o usa la abreviatura -> + my_rec_ptr->height = 10; // Lo mismo que (*my_rec_ptr).height = 10; +} + +// Puedes aplicar un 'typedef' a una estructura por conveniencía. +typedef struct rectangle rect; + +int area(rect r){ + return r.width * r.height; +} + +/////////////////////////////////////// +// Punteros a Funciones +/////////////////////////////////////// +/* +En tiempo de ejecución, las funciones se localizan en unas direcciones de +memoria concretas. Los punteros a funciones son como cualquier otro +puntero (almacenan una dirección de memoria), pero pueden ser usados para +utilizar funciones directamente, o para pasar 'handlers' (o funciones +'callback') por todos lados. +Sin embargo, la sintaxis de definición parecera confusa al principio. + +Ejemplo: usar str_reverse desde un puntero +*/ +void str_reverse_through_pointer(char * str_in) { + // Define un puntero a una función, llamado f. + void (*f)(char *); // La armadura debe coincidir exactamente con al función objetivo. + f = &str_reverse; // Assigna la dirección de la función (determinado en tiempo de ejecuión) + (*f)(str_in); // Llamando la función desde el puntero + // f(str_in); // Esta es una alternativa para llamarla pero con una sintaxis igual de válida. +} + +/* +Tanto tiempo como las armaduras de las funciones coincidan, podrás asignar +cualquier función al mismo puntero. +Los punteros a funciones son normalmente envueltos en 'typedef' para +simplificar su legibilidad, como sigue: +*/ + +typedef void (*my_fnp_type)(char *); + +// Es usado para declarar la variable puntero actual: +// ... +// my_fnp_type f; + +``` + +## Otras lecturas + +Lo mejor que puedes en contrar es una copia de [K&R, aka "The C Programming Language"](https://en.wikipedia.org/wiki/The_C_Programming_Language) + +Otro buen recurso es [Learn C the hard way](http://c.learncodethehardway.org/book/) + +Aparte de eso, Google es tu amigo. diff --git a/es-es/elisp-es.html.markdown b/es-es/elisp-es.html.markdown new file mode 100644 index 00000000..8c220109 --- /dev/null +++ b/es-es/elisp-es.html.markdown @@ -0,0 +1,377 @@ +--- +language: elisp +contributors: + - ["Bastien Guerry", "http://bzg.fr"] +translators: + - ["Guillermo Vayá", "http://willyfrog.es"] +lang: es-es +filename: learn-emacs-lisp.el +--- + +```scheme +;; Introduccion a Emacs Lisp en 15 minutos (v0.2d) +;; +;; Autor: Bastien / @bzg2 / http://bzg.fr +;; Traducción: Guillermo Vayá +;; +;; Antes de nada, lee este texto de Peter Norvig: +;; http://norvig.com/21-days.html +;; +;; Ahora instala GNU Emacs 24.3: +;; +;; Debian: apt-get install emacs +;; (o sigue las instrucciones de tu distribución preferida) +;; OSX: http://emacsformacosx.com/emacs-builds/Emacs-24.3-universal-10.6.8.dmg +;; Windows: http://ftp.gnu.org/gnu/windows/emacs/emacs-24.3-bin-i386.zip +;; +;; Puedes encontrar información general sobre Emacs en: +;; http://www.gnu.org/software/emacs/#Obtaining + +;; Aviso importante: +;; +;; Seguir este tutorial no provocará daños en tu ordenador a menos que +;; te enfades tanto que que acabes tirándolo al suelo. En tal caso +;; declino cualquier responsabilidad. ¡A divertirse! + + +;; "N. del. T.": Algunos términos comunes de la informática se han dejado +;; sin traducir ya que es mucho más probable que el lector los conozca en +;; su forma en inglés, siendo la versión en español de muy raro uso. +;; Además "sexps" se ha decidido traducir por sexpresión. +;; Por último, añadir que no se han traducido los ejemplos de código ya que no +;; es necesario entender qué dice el string para comprender el funcionamiento +;; y podría llevar a error. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Inicia Emacs. +;; +;; Pulsa la tecla `q' para pasar el mensaje de bienvenida. +;; +;; Mira a la línea gris en la parte inferior de la ventana: +;; +;; "*scratch*" es el nombre del espacio editable donde estás. +;; A este espacio editable se le llama "buffer". +;; +;; Scratch es el buffer por defecto cuando abres Emacs. +;; En Emacs nunca editas ficheros, sino que editas buffers que +;; posteriormente pueden grabarse a un fichero. +;; can save to a file. +;; +;; "Lisp interaction" indica el conjunto de ordenes disponibles. +;; +;; Emacs dispone de un set de comandos disponibles en cualquier buffer +;; ("built-ins") y aparte varios conjuntos de ordenes disponibles +;; según el modo específico que esté activo. En nuestro caso +;; estamos usando `lisp-interaction-mode', el cual incluye las +;; ordenes necesarias para evaluar y navegar código Elisp. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Un punto y coma comienza un comentario. Pueden ponerse en cualquier +;; posicion de la linea. +;; +;; Los programas en Elisp se componen de expresiones simbólicas +;; tambien llamadas "sexps": +(+ 2 2) + +;; Esta expresión simbólica se lee tal que "Suma 2 y 2" + +;; Las sexpresiones se rodean por paréntesis, y pueden anidarse: +(+ 2 (+ 1 1)) + +;; Una expresion simbólica está formada bien por átomos o bien por otras +;; expresiones simbólicas. En el ejemplo de arriba, 1 y 2 son átomos, +;; mientras que (+ 2 (+ 1 1)) y (+ 1 1) son expresiones simbólicas. + +;; Gracias a `lisp-interaction-mode' puedes evaluar las sexpresiones. +;; Coloca el cursor justo despues del paréntesis de cierre y +;; mantén pulsada la tecla Control y la j (para abreviar usaremos "C-j"). + +(+ 3 (+ 1 2)) +;; ^ pon aquí el cursor +;; `C-j' => 6 + +;; `C-j' añade el resultado de la evaluación al buffer. + +;; `C-xC-e' muestra el mismo resultado pero en la linea inferior +;; la cual se llama "minibuffer". Este será el metodo que usaremos +;; normalmente para no llenar el buffer con texto inútil. + +;; `setq' guarda un valor en una variable: +(setq my-name "Bastien") +;; `C-xC-e' => "Bastien" (aparece en el mini-buffer) + +;; `insert' añade "Hello!" en el punto donde esté tu cursor: +(insert "Hello!") +;; `C-xC-e' => "Hello!" + +;; Aunque hemos usado `insert' con solo un parámetro "Hello!", se +;; pueden pasar más. Por ejemplo, en esta otra sexpresión usamos dos: + +(insert "Hello" " world!") +;; `C-xC-e' => "Hello world!" + +;; Se pueden usar variables en lugar de strings: +(insert "Hello, I am " my-name) +;; `C-xC-e' => "Hello, I am Bastien" + +;; Puedes combinar sexpresiones en funciones: +(defun hello () (insert "Hello, I am " my-name)) +;; `C-xC-e' => hello + +;; Evaluemos la funcion: +(hello) +;; `C-xC-e' => Hello, I am Bastien + +;; Los parentesis vacios en la definicion de una funcion indican +;; que no acepta parámetros. En cualquier caso, usar `my-name' siempre +;; es aburrido, asi que vamos a hacer que la función accepte un parámetro +;; (en este caso el parametro se llama "name"): +(defun hello (name) (insert "Hello " name)) +;; `C-xC-e' => hello + +;; Ahora vamos a llamar a la funcion con el string "you" como valor para +;; el único parámetro que posee. +(hello "you") +;; `C-xC-e' => "Hello you" + +;; ¡Genial! + +;; Descansa un poco y respira. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Ahora cambiaremos al nuevo buffer, llamado "*test*", en una nueva ventana. + +(switch-to-buffer-other-window "*test*") +;; `C-xC-e' +;; => [La pantalla ahora tiene dos ventanas y el cursor está en el buffer *test*] + +;; Mueve el ratón sobre la ventana superior y pulsa el boton izdo. para volver. +;; Otra forma es usando `C-xo' (pulsa simultaneamente control y x y luego la o) +;; para ir a la otra ventana. + +;; Se pueden combinar varias sexpresiones mediante `progn': +(progn + (switch-to-buffer-other-window "*test*") + (hello "you")) +;; `C-xC-e' +;; => [De las dos ventanas de la pantalla, el cursor está en la marcada como *test*] + +;; A partir de ahora, si no te importa, dejaremos de decir que pulses `C-xC-e': +;; tendrás que hacerlo para ejecutar cada sexpresión que siga. + +;; También tendrás que volver al buffer *scratch* bien con el ratón o con `C-xo'. + +;; En ocasiones será util limpiar el buffer: +(progn + (switch-to-buffer-other-window "*test*") + (erase-buffer) + (hello "there")) + +;; O volver a la ventana anterior: +(progn + (switch-to-buffer-other-window "*test*") + (erase-buffer) + (hello "you") + (other-window 1)) + +;; Puedes enlazar un valor a una variable local con `let': +(let ((local-name "you")) + (switch-to-buffer-other-window "*test*") + (erase-buffer) + (hello local-name) + (other-window 1)) + +;; En este caso, no hace falta añadir `progn' ya que `let' permite combinar +;; varias sexpresiones. + +;; Vamos a darle formato a un string: +(format "Hello %s!\n" "visitor") + +;; Cada %s indica la posicion donde irá un string, el cual será reemplazado +;; por "visitor". "\n" es el caracter de nueva línea. + +;; Mejoremos nuestra funcion usando `format': +(defun hello (name) + (insert (format "Hello %s!\n" name))) + +(hello "you") + +;; Creemos una nueva funcion que utililce `let': +(defun greeting (name) + (let ((your-name "Bastien")) + (insert (format "Hello %s!\n\nI am %s." + name ; the argument of the function + your-name ; the let-bound variable "Bastien" + )))) + +;; Y ahora la evaluamos: +(greeting "you") + +;; Algunas funciones son interactivas: +(read-from-minibuffer "Enter your name: ") + +;; Al evaluar esta función, ésta devuelve lo que hayas introducido. + +;; Ahora hagamos nuestra función `greeting' preguntar por tu nombre: +(defun greeting (from-name) + (let ((your-name (read-from-minibuffer "Enter your name: "))) + (insert (format "Hello!\n\nI am %s and you are %s." + from-name ; the argument of the function + your-name ; the let-bound var, entered at prompt + )))) + +(greeting "Bastien") + +;; Y ahora la completamos mostrando el resultado en la otra ventana: +(defun greeting (from-name) + (let ((your-name (read-from-minibuffer "Enter your name: "))) + (switch-to-buffer-other-window "*test*") + (erase-buffer) + (insert (format "Hello %s!\n\nI am %s." your-name from-name)) + (other-window 1))) + +;; Probémosla: +(greeting "Bastien") + +;; Descansa un poco y respira. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Creemos una lista de nombres: +(setq list-of-names '("Sarah" "Chloe" "Mathilde")) + +;; Para coger el primer elemento de la lista usaremos `car': +(car list-of-names) + +;; Para coger todos menos el primer elemento de la lista +;; usaremos `cdr': +(cdr list-of-names) + +;; Para añadir un elemento al comienzo de la lista utilizamos `push': +(push "Stephanie" list-of-names) + +;; OJO: `car' y `cdr' no modifican la lista, mientras que `push' sí. +;; ¡Es una diferencia importante! Algunas funciones no tienen efectos +;; colaterales (como `car') mientras que otras sí (como `push'). +;; "N. del T.": estos efectos colaterales se les llama `side-effects' en +;; las distintas variantes de lisp. + +;; Llamemos a `hello' con cada elemento de `list-of-names': +(mapcar 'hello list-of-names) + +;; Retocamos `greeting' para que salude a todos los que estén en `list-of-names': +(defun greeting () + (switch-to-buffer-other-window "*test*") + (erase-buffer) + (mapcar 'hello list-of-names) + (other-window 1)) + +(greeting) + +;; ¿Te acuerdas de la función `hello' definida un poco más arriba? +;; Recibía un parámetro: `name'. Así que `mapcar' llama a `hello' con cada +;; elemento de `list-of-names' como parámetro de `hello'. + +;; Ahora ordenaremos un poco lo que tenemos en el buffer: + +(defun replace-hello-by-bonjour () + (switch-to-buffer-other-window "*test*") + (goto-char (point-min)) + (while (search-forward "Hello") + (replace-match "Bonjour")) + (other-window 1)) + +;; (goto-char (point-min)) mueve el cursor al principio del buffer. +;; (search-forward "Hello") busca un string "Hello". +;; (while x y) evalua la/s sexpresion/es y mientras que x devuelva +;; alguna cosa. +;; En el momento que x devuelva `nil' (es decir nada), sale del +;; bucle `while'. + +(replace-hello-by-bonjour) + +;; Observamos que todas las veces que teníamos la palabra "Hello" en el buffer *test* +;; han sido reemplazadas por "Bonjour". + +;; Y además, hemos obtenido un error: "Search failed: Hello". +;; +;; Para evitar este error, hay que decirle a `search-forward' si debería dejar de +;; buscar en el buffer en algún momento y si debería fallar sin quejarse cuando +;; no encuentra nada. + +;; (search-forward "Hello" nil t) justo hace eso: + +;; El argumento `nil' significa que la busqueda no está ligada a ninguna posición. +;; Y el argumento `t' le pide que no diga nada si no encuentra el string. + +;; Usaremos esta sexpresión en la función siguiente, la cual ya +;; no muestra ningún error: + +(defun hello-to-bonjour () + (switch-to-buffer-other-window "*test*") + (erase-buffer) + ;; Say hello to names in `list-of-names' + (mapcar 'hello list-of-names) + (goto-char (point-min)) + ;; Replace "Hello" by "Bonjour" + (while (search-forward "Hello" nil t) + (replace-match "Bonjour")) + (other-window 1)) + +(hello-to-bonjour) + +;; Añadamos algo de color a los nombres: + +(defun boldify-names () + (switch-to-buffer-other-window "*test*") + (goto-char (point-min)) + (while (re-search-forward "Bonjour \\(.+\\)!" nil t) + (add-text-properties (match-beginning 1) + (match-end 1) + (list 'face 'bold))) + (other-window 1)) + +;; Esta función nos presenta `re-search-forward': en vez de +;; buscar el string "Bonjour" exacto, se busca por un patrón +;; usando una "expresión regular" (lo cual se muestra abreviado +;; en el prefijo "re-" del inglés "Regular Expression"). + +;; La expresión regular a utilizar es "Bonjour \\(.+\\)!" y se traduce como: +;; el string "Bonjour ", seguido de +;; un grupo de | representado por \\( ... \\) +;; cualquier caracter | representado por . +;; al menos una vez | representado por + +;; y el string "!". + +;; ¿Preparado? ¡Probemoslo! + +(boldify-names) + +;; `add-text-properties' añade propiedades al texto, como una fuente. + +;; ¡Hale! ¡Ya lo tenemos! ¡Feliz hacking! + +;; Si quieres saber más sobre una función o una variable: +;; +;; C-h v la-variable RET +;; C-h f la-funcion RET +;; +;; Si quieres leer el manual de Emacs Lisp desde dentro de Emacs: +;; +;; C-h i m elisp RET +;; +;; Para leer una introducción en linea de Emacs Lisp: +;; https://www.gnu.org/software/emacs/manual/html_node/eintr/index.html + +;; Me gustaría agradecer a las siguientes personas su feedback y sugerencias: +;; - Wes Hardaker +;; - notbob +;; - Kevin Montuori +;; - Arne Babenhauserheide +;; - Alan Schmitt +;; - LinXitoW +;; - Aaron Meurer +``` |