| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Introduction to Scheme
Comenzaremos con una introducción a Scheme. Para esta breve introducción utilizaremos el intérprete GUILE para explorar la manera en que el lenguaje funciona. Una vez nos hayamos familiarizado con Scheme, mostraremos cómo se puede integrar el lenguaje en los archivos de LilyPond.
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Scheme sandbox
La instalación de LilyPond incluye también la de la implementación
Guile de Scheme. Sobre casi todos los sistemas puede experimentar
en una “caja de arena” de Scheme abriendo una ventana del
terminal y tecleando ‘guile’. En algunos sistemas, sobre todo
en Windows, podría necesitar ajustar la variable de entorno
GUILE_LOAD_PATH a la carpeta ../usr/share/guile/1.8
dentro de la instalación de LilyPond (para conocer la ruta
completa a esta carpeta, consulte
información
(learning)Otras fuentes de información sección ‘Otras fuentes de información’ en Manual de Aprendizaje). Como alternativa, los usuarios de Windows pueden
seleccionar simplemente ‘Ejecutar’ del menú Inicio e introducir
‘guile’.
Sin embargo, está disponible un cajón de arena de Scheme listo para funcionar con todo LilyPond cargado, con esta instrucción de la línea de órdenes:
lilypond scheme-sandbox |
Una vez está funcionando el cajón de arena, verá un indicador del sistema de Guile:
guile> |
Podemos introducir expresiones de Scheme en este indicador para experimentar con Scheme. Si quiere usar la biblioteca readline de GNU para una más cómoda edición de la línea de órdenes de Scheme, consulte el archivo ‘ly/scheme-sandbox.ly’ para más información. Si ya ha activado la biblioteca readline para las sesiones de Guile interactivas fuera de LilyPond, debería funcionar también en el cajón de arena.
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Scheme variables
Las variables de Scheme pueden tener cualquier valor válido de Scheme, incluso un procedimiento de Scheme.
Las variables de Scheme se crean con define:
guile> (define a 2) guile> |
Las variables de Scheme se pueden evaluar en el indicador del sistema de guile, simplemente tecleando el nombre de la variable:
guile> a 2 guile> |
Las variables de Scheme se pueden imprimir en la pantalla utilizando la función display:
guile> (display a) 2guile> |
Observe que el valor 2 y el indicador del sistema
guile se muestran en la misma línea. Esto se puede evitar
llamando al procedimiento de nueva línea o imprimiendo un carácter
de nueva línea.
guile> (display a)(newline) 2 guile> (display a)(display "\n") 2 guile> |
Una vez que se ha creado una variable, su valor se puede modificar
con set!:
guile> (set! a 12345) guile> a 12345 guile> |
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Scheme simple data types
El concepto más básico de un lenguaje son sus tipos de datos: números, cadenas de caracteres, listas, etc. He aquí una lista de los tipos de datos que son de relevancia respecto de la entrada de LilyPond.
Los valores Booleanos son Verdadero y Falso. Verdadero en Scheme es
#t y Falso es #f.
Los números se escriben de la forma normal, 1 es el número
(entero) uno, mientras que -1.5 es un número en coma
flotante (un número no entero).
Las cadenas se encierran entre comillas:
"esto es una cadena" |
Las cadenas pueden abarcar varias líneas:
"esto es una cadena" |
y los caracteres de nueva línea al final de cada línea se incluirán dentro de la cadena.
Los caracteres de nueva línea también se pueden añadir mediante la
inclusión de \n en la cadena.
"esto\nes una\ncadena de varias líneas" |
Las comillas dobles y barras invertidas se añaden a las cadenas
precediéndolas de una barra invertida. La cadena \a dijo
"b" se introduce como
"\\a dijo \"b\"" |
Existen más tipos de datos de Scheme que no se estudian aquí. Para ver un listado completo, consulte la guía de referencia de Guile, http://www.gnu.org/software/guile/manual/html_node/Simple-Data-Types.html.
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Scheme compound data types
También existen tipos de datos compuestos en Scheme. Entre los tipos más usados en la programación de LilyPond se encuentran las parejas, las listas, las listas-A y las tablas de hash.
| Parejas | ||
| Listas | ||
| Listas asociativas (listas-A) | ||
| Tablas de hash |
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Pairs
El tipo fundacional de datos compuestos de Scheme es la
pareja. Como se espera por su nombre, una pareja son dos
valores unidos en uno solo. El operador que se usa para formar
una pareja se llama cons.
guile> (cons 4 5) (4 . 5) guile> |
Observe que la pareja se imprime como dos elementos rodeados por
paréntesis y separados por un espacio, un punto (.) y otro
espacio. El punto no es un punto decimal, sino más bien un
indicador de pareja.
Las parejas también se pueden introducir como valores literales precediéndolos de un carácter de comilla simple o apóstrofo.
guile> '(4 . 5) (4 . 5) guile> |
Los dos elementos de una pareja pueden ser cualquier valor válido de Scheme:
guile> (cons #t #f)
(#t . #f)
guile> '("bla-bla" . 3.1415926535)
("bla-bla" . 3.1415926535)
guile>
|
Se puede accede al primero y segundo elementos de la pareja
mediante los procedimientos de Scheme car y cdr,
respectivamente.
guile> (define mipareja (cons 123 "Hola") … ) guile> (car mipareja) 123 guile> (cdr mipareja) "Hola" guile> |
Nota: cdr se pronuncia "could-er", según Sussman y Abelson,
véase
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-14.html#footnote_Temp_133
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Lists
Una estructura de datos muy común en Scheme es la
lista. Formalmente, una lista ‘bien hecha’ se define como
la lista vacía, representada como '() y con longitud cero,
o bien como una pareja cuyo cdr es a su vez una lista más
corta.
Existen muchas formas de crear listas. Quizá la más común es con
el procedimiento list:
guile> (list 1 2 3 "abc" 17.5) (1 2 3 "abc" 17.5) |
La representación de una lista como elementos individuales separados por espacios y encerrada entre paréntesis es realmente una forma compacta de las parejas con punto que constituyen la lista, donde el punto e inmediatamente un paréntesis de apertura se suprimen junto al paréntesis de cierre correspondiente. Sin esta compactación, la salida habría sido
(1 . (2 . (3 . ("abc" . (17.5 . ())))))
|
De igual forma que con la salida, una lista puede escribirse (después de haber añadido un apóstrofo para evitar su interpretación como una llamada de función) como una lista literal encerrando sus elementos entre paréntesis:
guile> '(17 23 "fulano" "mengano" "zutano") (17 23 "fulano" "mengano" "zutano") |
Las listas son una parte fundamental de Scheme. De hecho, Scheme se considera un dialecto de Lisp, donde ‘lisp’ es una abreviatura de ‘List Processing’ (proceso de listas). Todas las expresiones de Scheme son listas.
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Association lists (alists)
Un tipo especial de listas son las listas asociativas o listas-A. Se puede usar una lista-A para almacenar datos para su fácil recuperación posterior.
Las listas-A son listas cuyos elementos son parejas. El
car de cada elemento se llama clave, y el cdr
de cada elemento se llama valor. El procedimiento de
Scheme assoc se usa para recuperar un elemento de la
lista-A, y cdr se usa para recuperar el valor:
guile> (define mi-lista-a '((1 . "A") (2 . "B") (3 . "C"))) guile> mi-lista-a ((1 . "A") (2 . "B") (3 . "C")) guile> (assoc 2 mi-lista-a) (2 . "B") guile> (cdr (assoc 2 mi-lista-a)) "B" guile> |
Las listas-A se usan mucho en LilyPond para almacenar propiedades y otros datos.
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Hash tables
Estructuras de datos que se utilizan en LilyPond de forma ocasional. Una tabla de hash es similar a una matriz, pero los índices de la matriz pueden ser cualquier tipo de valor de Scheme, no sólo enteros.
Las tablas de hash son más eficientes que las listas-A si hay una gran cantidad de datos que almacenar y los datos cambian con muy poca frecuencia.
La sintaxis para crear tablas de hash es un poco compleja, pero veremos ejemplos de ello en el código fuente de LilyPond.
guile> (define h (make-hash-table 10)) guile> h #<hash-table 0/31> guile> (hashq-set! h 'key1 "val1") "val1" guile> (hashq-set! h 'key2 "val2") "val2" guile> (hashq-set! h 3 "val3") "val3" |
Los valores se recuperan de las tablas de hash mediante
hashq-ref.
guile> (hashq-ref h 3) "val3" guile> (hashq-ref h 'key2) "val2" guile> |
Las claves y los valores se recuperan como una pareja con
hashq-get-handle. Ésta es la forma preferida, porque
devuelve #f si no se encuentra la clave.
guile> (hashq-get-handle h 'key1) (key1 . "val1") guile> (hashq-get-handle h 'frob) #f guile> |
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Calculations in Scheme
Scheme se puede usar para hacer cálculos. Utiliza sintaxis
prefija. Sumar 1 y 2 se escribe como (+ 1 2) y
no como el tradicional 1+2.
guile> (+ 1 2) 3 |
Los cálculos se pueden anidar; el resultado de una función se puede usar para otro cálculo.
guile> (+ 1 (* 3 4)) 13 |
Estos cálculos son ejemplos de evaluaciones; una expresión como
(* 3 4) se sustituye por su valor 12.
Los cálculos de Scheme son sensibles a las diferencias entre enteros y no enteros. Los cálculos enteros son exactos, mientras que los no enteros se calculan con los límites de precisión adecuados:
guile> (/ 7 3) 7/3 guile> (/ 7.0 3.0) 2.33333333333333 |
Cuando el intérprete de Scheme encuentra una expresión que es una lista, el primer elemento de la lista se trata como un procedimiento a evaluar con los argumentos del resto de la lista. Por tanto, todos los operadores en Scheme son operadores prefijos.
Si el primer elemento de una expresión de Scheme que es una lista que se pasa al intérprete no es un operador o un procedimiento, se produce un error:
guile> (1 2 3) Backtrace: In current input: 52: 0* [1 2 3] <unnamed port>:52:1: In expression (1 2 3): <unnamed port>:52:1: Wrong type to apply: 1 ABORT: (misc-error) guile> |
Aquí podemos ver que el intérprete estaba intentando tratar el 1 como un operador o procedimiento, y no pudo hacerlo. De aquí que el error sea "Wrong type to apply: 1".
Así pues, para crear una lista debemos usar el operador de lista, o podemos precederla de un apóstrofo para que el intérprete no trate de evaluarla.
guile> (list 1 2 3) (1 2 3) guile> '(1 2 3) (1 2 3) guile> |
Esto es un error que puede aparecer cuando trabaje con Scheme dentro de LilyPond.
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Scheme procedures
Los procedimientos de Scheme son expresiones de Scheme ejecutables que devuelven un valor resultante de su ejecución. También pueden manipular variables definidas fuera del procedimiento.
| Definir procedimientos | ||
| Predicados | ||
| Valores de retorno |
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Defining procedures
Los procedimientos se definen en Scheme con define:
(define (nombre-de-la-función arg1 arg2 ... argn) expresión-de-scheme-que-devuelve-un-valor) |
Por ejemplo, podemos definir un procedimiento para calcular la media:
guile> (define (media x y) (/ (+ x y) 2)) guile> media #<procedure media (x y)> |
Una vez se ha definido un procedimiento, se llama poniendo el nombre del procedimiento dentro de una lista. Por ejemplo, podemos calcular la media de 3 y 12:
guile> (media 3 12) 15/2 |
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Predicates
Los procedimientos de Scheme que devuelven valores booleanos se suelen llamar predicados. Por convenio (pero no por necesidad), los nombres de predicados acaban en un signo de interrogación:
guile> (define (menor-que-diez? x) (< x 10)) guile> (menor-que-diez? 9) #t guile> (menor-que-diez? 15) #f |
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Return values
Los procedimientos de Scheme siempre devuelven un valor de retorno, que es el valor de la última expresión ejecutada en el procedimiento. El valor de retorno puede ser cualquier valor de Scheme válido, incluso una estructura de datos compleja o un procedimiento.
A veces, el usuario quiere tener varias expresiones de Scheme
dentro de un procedimiento. Existen dos formas en que se pueden
combinar distintas expresiones. La primera es el procedimiento
begin, que permite evaluar varias expresiones, y devuelve
el valor de la última expresión.
guile> (begin (+ 1 2) (- 5 8) (* 2 2)) 4 |
La segunda forma de combinar varias expresiones es dentro de un
bloque let. Dentro de un bloque let, se crean una serie de
ligaduras o asignaciones, y después se evalúa una secuencia de
expresiones que pueden incluir esas ligaduras o asignaciones. El
valor de retorno del bloque let es el valor de retorno de la
última sentencia del bloque let:
guile> (let ((x 2) (y 3) (z 4)) (display (+ x y)) (display (- z 4)) … (+ (* x y) (/ z x))) 508 |
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof Scheme conditionals
| if | ||
| cond |
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof if
Scheme tiene un procedimiento if:
(if expresión-de-prueba expresión-de-cierto expresión-de-falso) |
expresión-de-prueba es una expresión que devuelve un valor
booleano. Si expresión-de-prueba devuelve #t, el
procedimiento if devuelve el valor de la
expresión-de-cierto, en caso contrario devuelve el valor de
la expresión-de-falso.
guile> (define a 3) guile> (define b 5) guile> (if (> a b) "a es mayor que b" "a no es mayor que b") "a no es mayor que b" |
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] | [Arriba] | [Índice general] | [Índice] | [ ? ] |
@translationof cond
Otro procedimiento condicional en Scheme es cond:
(cond (expresión-de-prueba-1 secuencia-de-expresiones-resultante-1)
(expresión-de-prueba-2 secuencia-de-expresiones-resultante-2)
…
(expresión-de-prueba-n secuencia-de-expresiones-resultante-n))
|
Por ejemplo:
guile> (define a 6) guile> (define b 8) guile> (cond ((< a b) "a es menor que b") ... ((= a b) "a es igual a b") ... ((> a b) "a es mayor que b")) "a es menor que b" |
| [ < ] | [ > ] | [ << ] | [ Subir ] | [ >> ] |
Este documento ha sido generado por gub el el 13 julio 2020 utilizando texi2html 1.82.
Otros idiomas: English, deutsch, français.
Acerca de la selección automática del idioma.