Académique Documents
Professionnel Documents
Culture Documents
Eduardo NAVAS
versin 1.0 2010.07.21
Este libro fue desarrollado nicamente con software libre. Entre las herramientas usadas,
CC-BY-NC-SA
Este es un libro libre con la licencia
de la
Prlogo
Este libro evolucion a partir del material preparado para las clases de la materia Programacin Funcional, impartida para la Carrera de Licenciatura en Ciencias de la Computacin de la Universidad Centroamericana Jos Simen Caas. Despus de un ao de trabajo, este libro incluye un recorrido por las caractersticas bsicas del lenguaje Racket, en su versin 5.
Racket 5
es la nueva versin de
en el aprendizaje de la programacin de computadoras, a travs del paradigma funcional, basndose en el lenguaje Scheme. Realmente no existe, formalmente hablando, un lenguaje llamado Scheme, sino que se le llama as a una familia de lenguajes de programacin funcionales (vase el captulo 1). En este libro, se discute especcamente el dialecto conocido como Racket (anteriormente PLT Scheme), uno de los ms difundidos. Si se quiere un estudio ms purista sobre Scheme, revise el estndar R5RS que tambin es soportado por el intrprete de Racket. Los temas abordados en la Parte I incluyen una introduccin a la programacin funcional, una sencilla gua de instalacin de Racket y una introduccin a la interaccin con Racket y DrRacket. En la Parte II se introduce el lenguaje Racket en s, a travs de sus elementos bsicos y los bloques lambda, caractersticos de la programacin funcional. La Parte III describe los dems elementos del lenguaje y contiene mltiples ejercicios para que el lector practique sus nuevos conocimientos. Finalmente, la Parte IV muestra las capacidades de Racket para implementar programas con interfaces gracas de usuario. Y por ltimo, la Parte V incluye un anexo describiendo las diferencias entre la versin 5 de Racket y la serie 4.x de PLT Scheme.
ndice general
I. Introduccin a la Programacin Funcional con Racket
1. Programacin Funcional
1.1. 1.2. 1.3. 1.4. Objetivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Caractersticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lenguajes de Programacin Funcionales
17
19
19 20 20 21
2. Instalacin de Racket
2.1. 2.2. Instalacin con el instalador ocial Instalacin desde repositorios 2.2.1. 2.2.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Debian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Fedora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
23 24 24 25
27
27 27
29
29 30 30 31 31
Ejecucin no interactiva
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
33 33
35
37
37
ndice general
6.2. Deniciones Globales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2.1. 6.3. 6.4. Identicadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 38 39 39 39 40 41 42 43 43
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.5. 6.6.
lambda
45
45 46 . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8. Asignacin local
8.1. 8.2. 8.3.
49
49 50 50
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
53
53 54 54 56 56 56 57 58 59 59 60 61 62 62
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.3.
Aplicacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.4.
10.Recursin
10.1. Recursin por Posposicin de trabajo . . . . . . . . . . . . . . . . . . . . . . 10.2. Recursin de Cola . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
67
67 67
10
ndice general
69
69 70 70 70 72 72 73 73 74 76 77 78 79 80 81 83 83 84 85 86
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.2.4. Constantes especiales . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.3. Caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.4. Cadenas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.4.1. Cadenas mutables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.4.2. Comparacin entre cadenas
11.4.3. Otras funciones de cadena . . . . . . . . . . . . . . . . . . . . . . . . 11.5. Bytes y Cadenas de Bytes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.6. Smbolos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.7. Palabras clave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.8. Pares y listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.9. Vectores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.10. Tablas Hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.11. Void . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
apply lambda .
89
89 89 90 90 91 92 93 94 94 94 95 96 97 97 97 98 . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12.2.1. Funciones con cualquier nmero de parmetros 12.2.2. Funciones con un mnimo nmero de parmetros 12.2.4. Funciones con parmetros con nombre
12.2.3. Funciones con parmetros opcionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.2.5. Funciones con aridad mltiple . . . . . . . . . . . . . . . . . . . . . . 12.2.6. Consultando la aridad de las funciones . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12.4. Asignaciones
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
101
101
11
ndice general
13.2. Estructuras derivadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 104 104
14.Mdulos Funcionales
14.1. Visibilizando deniciones de estructuras . . . . . . . . . . . . . . . . . . . .
109
110
15.Entrada y Salida
15.1. Imprimir datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.2. Leer datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.2.1. Lectura "bsica" . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
111
111 113 113 114 115 116 116 116 117 117 118 119 120 122
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16.Excepciones
16.1. Atrapar Excepciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16.2. Las funciones error y raise . . . . . . . . . . . . . . . . . . . . . . . . . . . .
127
127 128
eval
131
131 132 . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
133
133 133 133 134 134 134 135 135 136 137
18.4. Mtodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18.4.1. Denicin e Invocacin de Mtodos . . . . . . . . . . . . . . . . . . . 18.4.2. Sustitucin de mtodos 18.4.3. Mtodos no sustitubles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18.5. Parmetros de inicializacin . . . . . . . . . . . . . . . . . . . . . . . . . . . 18.6. Funciones que operan sobre clases/interfaces/objetos . . . . . . . . . . . . . 18.7. Ejemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
ndice general
141
143
143 144 144 147 148 150
153 163
163 165
canvas %
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
canvas %
. . . . . . . . . . . . . . . . . . . . . . .
22.Mens
22.1. Ejemplo de editor sencillo de texto . . . . . . . . . . . . . . . . . . . . . . . 22.2. Mens contextuales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
171
174 177
23.Proyecto: Minipaint
183
V. Apndices
A. Diferencias entre PLT Scheme y Racket
197
199
13
ndice general
14
ndice de guras
2.1. Sitio de descarga de Racket . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
6.1.
. . . . . . .
41
143 144 145 146 147 148 150 153 153 154 155 156 157 158 163 165 167 169 171 172 173 175 179 180 181
19.5. dialogo.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19.6. text-eld.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19.7. pneles.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20.1. controles.rkt, tab 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20.2. controles.rkt, tab 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20.3. controles.rkt, tab 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20.4. controles.rkt, tab 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20.5. controles.rkt, tab 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20.6. controles.rkt, tab 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20.7. controles.rkt, tab 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.1. canvas1.rkt 21.2. canvas2.rkt 21.3. canvas3.rkt 21.4. canvas4.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
ndice de guras
23.1. mini-paint.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
16
Parte I
17
1 Programacin Funcional
La programacin funcional, iniciada a nales de la dcada de los 50's, es aquella cuyo paradigma se centra en el Clculo Lambda. Este paradigma es ms til para el rea de inteligencia articial (ya que satisface mejor las necesidades de los investigadores en esta rea), y en sus campos secundarios: clculo simblico, pruebas de teoremas, sistemas basados en reglas y procesamiento del lenguaje natural. La caracterstica esencial de la programacin funcional es que los clculos se ven como una funcin matemtica que hace corresponder entradas y salidas.
1.1. Objetivo
El objetivo es conseguir lenguajes expresivos y matemticamente elegantes, en los que no sea necesario bajar al nivel de la mquina para describir el proceso llevado a cabo por el programa, y evitando el concepto de estado del cmputo. Los lenguajes funcionales tienen el propsito de acercar su notacin a la notacin normal de la matemtica, cosa que no ocurre, por ejemplo, con los lenguajes imperativos (como
Java ).
El estado de cmputo o estado de clculo o estado de programa, se entiende como un registro (con una o ms variables) del estado en el que se encuentra el programa en un momento dado. En la prctica, este registro del estado de un programa, se implementa con variables globales, de las que depende el curso de ejecucin de alguna parte del programa. Por ejemplo, considere el siguiente cdigo en lenguaje
C:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Archivo : no - funcional . c # include < stdio .h > int variable_contador = 0; int aumentar_contador ( int incremento ) { variable_contador += incremento ; return variable_contador ; } void mostrar_contador ( void ) { printf ( " El valor del contador es : %d \ n " , variable_contador ) ; }
19
1 Programacin Funcional
15 16 17 18 19 20 21 22
int main ( void ) { mostrar_contador () ; aumentar_contador (5) ; mostrar_contador () ; aumentar_contador (10) ; mostrar_contador () ; return 0; }
En este pequeo programa, se puede decir que programa.
1.2. Caractersticas
Los programas escritos en un lenguaje funcional estn constituidos nicamente por deniciones de funciones, entendiendo stas, no como subprogramas clsicos de un lenguaje imperativo, sino como funciones puramente matemticas, en las que se verican ciertas propiedades como la
transparencia referencial. La transparencia referencial, signica que el signicado de una expresin depende nicamente del signicado de sus subexpresiones o parmetros, no depende de clculos previos ni del orden de evaluacin de sus parmetros o subexpresiones, y por tanto, implica la carencia total de efectos colaterales. No hay algo como el estado de un programa, no hay variables globales. En el caso del programa
no-funcional.c,
10,
aumentar_contador(10)
Otras caractersticas propias de estos lenguajes (consecuencia directa de la ausencia de estado de cmputo y de la transparencia referencial) son la no existencia de asignaciones de variables y la falta de construcciones estructuradas como la secuencia o la iteracin (no hay
for, ni while, etc.). Esto obliga en la prctica, a que todas las repeticiones de instrucciones
se lleven a cabo por medio de funciones recursivas.
20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
-- Funcin recursiva para calcular el factorial de un nmero factorial :: Integer -> Integer factorial n = if n ==0 then 1 else n * factorial ( n - 1) -- Sumar elementos de una lista sumar :: [ Integer ] -> Integer sumar [] = 0 sumar ( x : xs ) = x + sumar ( xs ) -- Funcin para calcular el valor de e (2.71828182845905) euler :: Double -> Double euler 0.0 = 1.0 euler n = 1.0 / product [1.. n ] + euler ( n - 1.0)
En Miranda:
1 2
|| Lista de cuadrados de n donde n es tomado de la lista de todos los enteros positivos : squares = [ n * n | n <- [1..] ]
En OCaml:
1 2 3 4
(* Longitud de una lista *) let rec long = function |[] -> 0 | x :: xs -> 1 + long xs ;;
En Erlang:
1 2
21
1 Programacin Funcional
En Python:
1 2 3 4 5 6 7 8 9 10 11 12
>>> vec = [2 , 4 , 6] >>> [3* x for x in vec ] [6 , 12 , 18] >>> [3* x for x in vec if x > 3] [12 , 18] >>> [[ x , x **2] for x in vec ] [[2 , 4] , [4 , 16] , [6 , 36]] >>> >>> >>> [8 , vec1 = [2 , 4 , 6] vec2 = [4 , 3 , -9] [ x * y for x in vec1 for y in vec2 ] 6 , -18 , 16 , 12 , -36 , 24 , 18 , -54]
22
2 Instalacin de Racket
2.1. Instalacin con el instalador ocial
A continuacin de describen los pasos bsicos de instalacin: 1. Vaya al sitio http://racket-lang.org/download/ y descargue el instalador correspondiente o ms cercano a su distribucin, tal como se muestra en la gura 2.1. 2. El archivo descargado es un
/usr/plt,
para la cual
/usr/plt/doc/.
/usr/share/plt, index.html.
En todo caso, con el comando se lanza la pgina del ndice de la documentacin instalada con el navegador por defecto del Sistema Operativo.
o simplemente ejecutar:
$ sh racket-xxxx.sh
23
2 Instalacin de Racket
Racket.
compatible con todo el contenido de este libro , en esta primera versin). Es slo cuestin
PLT Scheme
PLT Scheme
en sus repositorios.
2.2.1. Debian
En distribuciones basadas en
ocial de la versin instalada por el paquete anterior. Con este paquete, est disponible la
/usr/share/plt/doc/index.html
2 3
24
2.2.2. Fedora
En distribuciones
En esta distribucin no se encuentra la documentacin como paquete, por lo que hay que consultarla en lnea, o descargarla.
25
2 Instalacin de Racket
26
<smbolo_no_terminal>.
<
>
representan smbolos no
Todas las secuencias de caracteres no delimitadas, representan smbolos terminales. Por ejemplo:
define, (, ), let. {
y
}.
+, *,
indica al menos una ocurrencia del smbolo precedente. indica ninguna, una o varias ocurrencias del smbolo precedente.
(<operador> <operando>*),
es decir,
(* (> (+ (+
2 5 2 4
3) -> equivale a (2 * 3) 6)-> equivale a (5 > 6) 3 10)-> equivale a (2 + 3 + 10) (* 3 2))-> equivale a (4 + 3 * 2)
5a + 2bc2
es:
(+ (* 5 a) (* 2 b c c)).
27
28
racket,
racket
que este Entorno se acomoda a diversas variantes de Scheme soportadas por el intrprete y compilador declarado en el cdigo fuente. Cuando se selecciona esta opcin, en el rea de texto para escribir el programa, aparece la lnea:
#lang racket
Esta lnea, al inicio de cualquier archivo de texto, indica que el cdigo a continuacin, es la variante ms completa (en trminos de bibliotecas disponibles y capacidad del lenguaje) de todas las variantes soportadas por Racket, conocido como
Lenguaje Racket.
Cuando se ejecuta el Racket en la lnea de comandos (con el comando por omisin es esta variante.
racket),
el lenguaje
racket,
normal. En ella, se puede escribir una expresin (aqu no hay comandos, ni instrucciones), presionar Intro y el intrprete devuelve el resultado de la expresin.
29
1 2 3 4 5 6 7 8
> 5 5 > (+ ( sqr 4) ( sqr 3) ) 25 > " Hola Mundo !" " Hola Mundo !" > ( substring " Hola Mundo !" 6 11) " Mundo "
En la ltima expresin, se invoc a una funcin llamada una cadena, y dos nmeros enteros.
substring,
substring.
Para
ello, en el rea de deniciones (el rea de texto superior) se escribe algo como:
1 2 3 4 5 6
1 2 3 4
> ( extraer "1234567890") "567" > ( extraer " este es un texto con muchos caracteres ") " es "
racket,
1 2 3
> ( enter ! " extraer . rkt ") > ( extraer "1234567890") "567"
La funcin
enter!
acin a las deniciones del archivo, igual que el botn Run de DrRacket.
30
1 2 3 4 5 6 7 8
# lang racket ; extraer2 . rkt ( define ( extraer str ) ( substring str 4 7) ) ( extraer "1234567890")
Ese es un programa completo que imprime en pantalla Para ejecutarlo, vaya la lnea de comandos:
567
cuando se ejecute.
1 2 3
vector inmutable de cadenas inmutables, una por cada parmetro. Por ejemplo, considere
1 2 3 4 5 6
# lang racket ; linea - de - comandos . rkt ( display " Los parmetros pasados al programa son : \ n ") ( write ( current - command - line - arguments ) ) ( newline )
Puede ejecutarlo as:
Los parmetros pasados al programa son: #("hola," "esta es" "una" "prueba")
31
32
1 2 3
1 2 3
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# lang racket ; principal . rkt ( require " secundario . rkt ") ( define parmetros ( current - command - line - arguments ) ) ( funcin - pblica " hola ") ( funcin - pblica constante - de - mdulo ) ( if (( vector - length parmetros ) . > . 0) ( for - each funcin - pblica ( vector - > list parmetros ) ) ( display " No se pasaron parmetros \ n ") ) ( display " Adis !\ n ")
33
# lang racket ; secundario . rkt ( provide funcin - pblica constante - de - mdulo ) ( define constante - de - mdulo " Esta constante est en secundario . rkt ") ( define ( funcin - pblica parmetro ) ( funcin - privada parmetro ) ) ( define ( funcin - privada parmetro ) ( display " Esta es una funcin declarada e implementada en secundario . rkt \ n ") ( display " El parmetro pasado es : ") ( write parmetro ) ( newline ) ) " Cuando se importa un mdulo , se ejecuta como un script "
Y para compilarlos, simplemente se hace:
$ ./ejecutable "otros parmetros" unidos "Cuando se importa un mdulo, se ejecuta como un script" Esta es una funcin declarada e implementada en secundario.rkt El parmetro pasado es: "hola" Esta es una funcin declarada e implementada en secundario.rkt El parmetro pasado es: "Esta constante est en secundario.rkt" Esta es una funcin declarada e implementada en secundario.rkt El parmetro pasado es: "otros parmetros" Esta es una funcin declarada e implementada en secundario.rkt El parmetro pasado es: "unidos" Adis! $
34
Parte II
35
6 Elementos bsicos
A continuacin se presenta un recorrido por las principales y ms bsicas partes del lenguaje Racket.
6.1. Comentarios
Los comentarios son elementos escenciales en todo lenguaje de programacin, ya que permiten que el programador aclare la futura lectura del cdigo fuente. En Racket, los comentarios de una lnea comienzan con delimitados por Ejemplo:
#|
|#.
1 2 3 4 5 6 7 8
# lang racket ; Todos los programas Racket deben comenzar con esta lnea de arriba . #| Este es un comentario en Racket , que tiene varias lneas .
evaluar
<expresin>.
(define (<identificador> <identificador>*) <expresin>+ ) le asigna al primer <identificador> una funcin (o procedimiento) que toma tantos argumentos como <identificador>es restantes haya dentro de los parntesis. El cuerpo de la funcin es la serie <expresin>+ y cuando la funcin es llamada, devuelve el resultado de la ltima <expresin>.
Ejemplo:
37
6 Elementos bsicos
1 2 3 4 5 6 7 8 9 10 11 12 13
> mximo 3 > ( prefijo " Hola , cmo ests ?") " Hol " > prefijo # < procedure : prefijo > > substring # < procedure : substring >
Una funcin puede tener mltiples expresiones, pero la funcin slo devuelve el resultado de la ltima:
1 2 3 4 5 6 7 8 9
( define ( hornear sabor ) ( printf " Precalentando el horno para ...\ n ") " Esta cadena es completamente ignorada " ( string - append " pastel de " sabor ) ) > ( hornear " manzana ") Precalentando el horno para ... " pastel de manzana "
6.2.1. Identicadores
Los identicadores en Racket son muy liberales. A diferencia de otros lenguajes de programacin que restringen mucho los caracteres vlidos para sus identicadores, en Racket, prcticamente no hay restricciones. Los nicos caracteres no vlidos en los identicadores son:
\.
( ) [ ] { } , ' ` ; # |
y tampoco estn permitidos los espacios dentro de los identicadores. Por lo dems, se pueden utilizar identicadores como
> (define -en-espaol 1) > (define -deutsch 2) > (define e ho san go- ciu a ude-en-Esperanto 3)
38
(<identificador> <expresin>*)
donde la secuencia de expresiones determina el nmero de parmetros reales pasados a la funcin referenciada por el identicador. Por ejemplo
pia).
(prefijo hola)
(hornear
string-append, substring,
etc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
> ( if ( < 1 2) " menor " " mayor ") " menor " > ( if ( positive ? ( sqrt 4) ) " s es positivo " " no es positivo ") " s es positivo " > ( define ( responder - saludo s ) ( if ( equal ? " hola " ( substring s 0 4) ) " hola , gusto de verte !" " perdn ?" ) ) > ( responder - saludo " hola programa ") " hola , gusto de verte !" > ( responder - saludo " El da est muy bonito , verdad ?") " perdn ?"
Como en otros lenguajes de programacin, las sentencias condicionales (as como muchas otras cosas) se pueden anidar dentro de otras:
39
6 Elementos bsicos
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
> ( define ( responder - saludo s ) ( if ( string ? s ) ( if ( equal ? " hola " ( substring s 0 4) ) " hola , gusto de verte !" " perdn ?" ) " perdn , qu ?" ) ) > ( responder - saludo " hola programa ") " hola , gusto de verte !" > ( responder - saludo 3.1416) " perdn , qu ?" > ( responder - saludo " El da est muy bonito , verdad ?") " perdn ?"
Esto tambin se podra escribir como:
1 2 3 4 5 6 7 8
> ( define ( responder - saludo s ) ( if ( if ( string ? s ) ( equal ? " hola " ( substring s 0 4) ) #f) " hola , gusto de verte !" " perdn , qu ?" ) )
6.4.2. and y or
En Racket, las funciones lgicas de conjuncin y disyuncin, son respectivamente y su sintaxis es:
(and <expresin>*) #f
and
or #t
La primera retorna a
y retorna
#t
y retorna
#f
#t
Java ).
Ejemplo:
1 2 3 4 5 6 7 8 9
> ( and ( < 3.1416 ( expt 10.1424 3.8) ) ( not ( negative ? pi ) ) ) #t > ( define ( responder - saludo s ) ( if ( and ( string ? s ) ( >= ( string - length s ) ( string - length " hola ") ) ( equal ? " hola " ( substring s 0 4) ) ) " hola , gusto de verte !"
40
10 11 12
6.4.3. cond
Una forma de bloques condicionales anidadas (if anidados) es:
#t.
41
6 Elementos bsicos
Por ejemplo (ver la gura 6.1):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
> ( define ( seccionada x ) ( cond [( < x -1) (+ x 2) ] [( and ( >= x -1) ( < x 0) ) 1] [( >= x 0) (+ ( - ( sqr x ) ) 1) ]) ) > ( seccionada -4) -2 > ( seccionada -.5) 1 > ( seccionada 1) 0 >
x < -1: x +2
( define ( responder - ms s ) ( cond [( equal ? " hola " ( substring s 0 4) ) " hola , gusto de verte !"] [( equal ? " adis " ( substring s 0 5) ) " nos vemos , que te vaya bien !"] [( and ( equal ? " " ( substring s 0 1) ) ( equal ? "?" ( substring s ( - ( string - length s ) 1) ) ) ) " No s "] [ else " perdn , qu ?"]) ) " hoy ?") " hola pepe ") verte !" " la derivada de la funcin exponencial es ella misma ") " adis programa ") te vaya bien !"
> ( responder - ms " No s " > ( responder - ms " hola , gusto de > ( responder - ms " perdn , qu ?" > ( responder - ms " nos vemos , que
se cierre con un
y un
se cierre con un
corchetes junto a los parntesis hace del cdigo Racket ligeramente ms legible.
6.4.4. case
Los bloques
case
> ( case (+ 7 5)
42
[(1 2 3) " pequeo "] [(10 11 12) " grande "]) " grande " > ( case ( - 7 5) [(1 2 3) " pequeo "] [(10 11 12) " grande "]) " pequeo " > ( case (* 7 5) [(1 2 3) " pequeo "] [(10 11 12) " grande "] [ else " fuera de rango "]) " fuera de rango "
secuencia de instrucciones,
let,
por lo que esas alternativas suelen bastar. Pero para aquellos casos en los que no, se
begin:
1 2 3 4 5 6 7 8 9 10
> ( if ( < 5 6) ( begin ( display " Aqu podemos escribir muchas cosas \ n ") " Pero slo el ltimo elemento ser el resultado " " cinco es menor que seis " ) " cinco no es menor que seis " ) Aqu podemos escribir muchas cosas " cinco es menor que seis "
1 como:
(<expresin-de-funcin> <expresin>* )
La
<expresin-de-funcin>,
una funcin.
Por ejemplo:
43
6 Elementos bsicos
1 2 3 4 5 6 7
> ( define ( duplicar valor ) (( if ( string ? valor ) string - append +) valor valor ) ) > ( duplicar " cadena ") " cadenacadena " > ( duplicar 3) 6
Aqu, el bloque Si la
if
+).
<expresin-de-funcin>
primer elemento dentro de los parntesis debe ser una funcin. Por ejemplo, la siguiente expresin:
> (1 2 3)
produce el error:
1 2 3 4 5 6
> ( define ( componer funcin valor ) ( funcin ( funcin valor ) ) ) > ( componer sqrt 256) 4 > ( componer sqr 2) 16
44
lambda
(+ 5 4)
Es equivalente a:
1 2 3 4
1 2 3 4
> ( define ( poner - admiracin s ) ( string - append " " s "!") ) > ( componer poner - admiracin " hola ") " hola !!"
Pero suponga que la funcin
poner-admiracin slo llamar cuando se llame una vez a componer. Entonces puede escribir la funcin poner-admiracin directamente en la llamada a componer desde donde ser invocada. Entonces se usan los bloques lambda.
bloque lambda
45
define)1 ,
lambda.
lambda,
1 2
> ( lambda ( s ) ( string - append " " s "!") ) # < procedure >
Entonces, usando
lambda,
1 2 3 4
> ( componer ( lambda ( s ) ( string - append " " s "!") ) " hola ") " hola !!" > ( componer ( lambda ( s ) ( string - append " " s "!?") ) " hola ") " hola !?!?"
lambda
1 2 3 4 5 6 7 8 9
> ( define ( hacer - Agregar - afijos prefijo sufijo ) ( lambda ( s ) ( string - append prefijo s sufijo ) ) ) > ( componer ( hacer - Agregar - afijos " <" " >") " hola ") " < < hola > >" > ( componer ( hacer - Agregar - afijos " " "!") " hola ") " hola !!" > ( componer ( hacer - Agregar - afijos " < <" " > >") " hola ") " < < < < hola > > > >"
Tambin pueden asignarse el resultado de una funcin que retorna funciones a un identicador:
1 2 3 4 5 6
> ( define poner - admiracin ( hacer - Agregar - afijos " " "!") ) > ( define menos - seguro ( hacer - Agregar - afijos " " "?!") ) > ( componer menos - seguro " ah nombre ") " ah nombre ?!?!" > ( componer poner - admiracin " en serio ") " en serio !!"
Tambin puede asignarse directamente un bloque dos deniciones son equivalentes:
1 2 3 4
> ( define ( poner - admiracin s ) ( string - append " " s "!") ) > ( define poner - admiracin
1
46
( lambda ( s ) ( string - append " " s "!") )) > poner - admiracin # < procedure : poner - admiracin >
47
48
8 Asignacin local
Hay al menos tres formas de hacer asignacin local en Racket: Con
let*.
define,
con
let
y con
8.1. define
Hagamos otra ampliacin de la sintaxis para los bloques de funciones:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
> ( define ( conversar s ) ( define ( comienza - con ? prefijo ) ; local a conversar ( define longitud - prefijo ( string - length prefijo )) ; local a comienza - con ? ( and ( >= ( string - length s ) longitud - prefijo ) ( equal ? prefijo ( substring s 0 longitud - prefijo ) ) ) ) ( cond [( comienza - con ? " hola ") " hola , qu ondas ?"] [( comienza - con ? " adis ") " adis , nos vemos "] [ else " ah ?"]) ) > ( conversar " hola programa ") " hola , qu ondas ?" > ( conversar " hace fro en los talleres ") " ah ?" > ( conversar " adis programa ") " adis , nos vemos " > comienza - con ? reference to an identifier before its definition : comienza - con ?
Todas las deniciones dentro de la denicin de una funcin, son locales a ella, y por tanto, invisibles desde fuera de ella. Como todo en Racket, las deniciones se pueden anidar indenidamente unas dentro de otras.
49
8 Asignacin local
8.2. let
Otra forma de hacer asignaciones locales, es con el bloque bre
define
let.
Una ventaja de
let
so-
define.
Adems, con
define
let
<identificador> let,
y una
<expresin>
rodeadas por
corchetes, y las expresiones que van despus de las clusulas, son el cuerpo del
<identificador>
se le asigna el resultado de la
<expresin>
let.
En
para ser
1 2 3 4 5 6 7 8 9 10 11
> ( let ([ x 1] [ y 2]) ( display ( string - append " La suma de " ( number - > string x ) " ms " ( number - > string y ) " es : " ( number - > string (+ x y ) ) ) ) ) La suma de 1 ms 2 es : 3 > (+ x y ) reference to an identifier before its definition : x
8.3. let*
Las asignaciones de asignacin no se pueden referir unas a otras. El bloque clusulas posteriores, referencien clusulas anteriores:
let estn disponibles slo en el cuerpo del let, as que las clusulas de let*, por el contrario, permite que
1 2 3 4 5
50
Parte III
51
9 Listas e Iteracin
En este captulo se describen los pares y sus casos particulares, las listas. Adems, se describen los mecanismos propios de Racket para procesar y recorrer listas.
9.1. Listas
Las listas son el tipo de dato ms prominente de Racket, como dialecto de Scheme y a su vez de Lisp. No es de extraar que haya funciones especialmente avanzadas y de alto nivel para procesar y manipular listas. Hay varias maneras diferentes de crear listas en Racket. La principal de ellas es utilizando la funcin
list:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
> ( list " rojo " " verde " " azul ") (" rojo " " verde " " azul ") > ( list 1 2 3 4) (1 2 3 4) > ( list ( exp 1) ( sqrt 2) ) (2.718281828459045 1.4142135623730951) > ( list " cadena " 123 9.87654) (" cadena " 123 9.87654) > ( define mi - lista ( list " a " 2 3.1416) ) > mi - lista (" a " 2 3.1416)
Otra forma, es utilizar la notacin tradicional de Lisp, con apstrofe:
1 2 3 4 5 6 7
> '(" otra lista " " con nmeros " 3 4 5.322) (" otra lista " " con nmeros " 3 4 5.322) > ( define mi - lista '(" otra lista " " con nmeros " 3 4 5.322) ) > mi - lista (" otra lista " " con nmeros " 3 4 5.322)
53
9 Listas e Iteracin
list
sin parmetros:
(list)
Para vericar si una expresin se evala a una lista vaca, se pueden utilizar tambin varias funciones: La funcin de evaluacin lgica La funcin Ejemplos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
> '() () > empty () > null () > ( list ) () > (( lambda ( L ) ( if ( empty ? L ) " vaca " " no vaca ") ) null ) " vaca " > (( lambda ( L ) ( if ( empty ? L ) " vaca " " no vaca ") ) '() ) " vaca " > (( lambda ( L ) ( if ( null ? L ) " vaca " " no vaca ") ) empty ) " vaca " > (( lambda ( L ) ( if ( null ? L ) " vaca " " no vaca ") ) '(" a ") ) " no vaca "
list-ref
54
9.1 Listas
append
para unir listas para invertir el orden de una lista
para vericar si un identicador se corresponde con una lista (que puede estar
Ejemplos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
> '(" cero " 1 " dos " 3 " cuatro " 5.322) (" cero " 1 " dos " 3 " cuatro " 5.322) > ( length '(" cero " 1 " dos " 3 " cuatro " 5.322) ) 6 > ( list - ref '(" cero " 1 " dos " 3 " cuatro " 5.322) 2) " dos " > ( list - ref '(" cero " 1 " dos " 3 " cuatro " 5.322) 5) 5.322 > ( list - ref '(" cero " 1 " dos " 3 " cuatro " 5.322) 6) list - ref : index 6 too large for list : (" cero " 1 " dos " 3 " cuatro " 5.322) > ( append '(" cero " 1 " dos " 3 " cuatro " 5.322) ( list " a " " b " " c ") ( list " un elemento ") ) (" cero " 1 " dos " 3 " cuatro " 5.322 " a " " b " " c " " un elemento ") > ( reverse '(" cero " 1 " dos " 3 " cuatro " 5.322) ) (5.322 " cuatro " 3 " dos " 1 " cero ") > ( member " seis " '(" cero " 1 " dos " 3 " cuatro " 5.322) ) #f > ( if ( member " cero " '(" cero " 1 " dos " 3 " cuatro " 5.322) ) " s est " " no est ") " s est " > ( list ? empty ) #t > ( list ? 4) #f > ( list ? '(" hola ") ) #t
55
9 Listas e Iteracin
propias de los lenguajes funcionales, para recorrer y procesar secuencias (listas) de elemen-
9.2.1. map
La primera de ellas, es la funcin
los elementos de una lista, para generar otra lista. Por ejemplo:
1 2 3 4 5 6 7 8 9
> ( map sqrt ( list 1 2 4 9 16) ) (1 1.4142135623730951 2 3 4) > ( map ( lambda ( x ) (+ 1 ( sqr x ) ) ) ( list -5 -4 -3 -2 -1 0 1 2 3 4 5) ) (26 17 10 5 2 1 2 5 10 17 26) > ( map ( lambda ( i ) ( string - append " " i "!") ) ( list " buenos das " " buenas noches ") ) (" buenos das !" " buenas noches !")
andmap
ormap.
En sus formas es
ms simples, ambas toman como parmetros una funcin y una lista. En el caso de la
#t;
y devuelve
#t si el resultado de evaluar la funcin sobre cada elemento de la lista #f si el resultado de evaluar alguno de los elementos de la lista es #f. andmap. ormap
devuelve
La funcin
ormap
#t
si la funcin se evala a
1 2 3 4 5 6 7 8 9 10
> ( andmap string ? '(" una cadena " " otra cadena ") ) #t > ( andmap string ? '(" una cadena " " otra cadena " 123456) ) #f > ( andmap number ? ( list 1 3.35 1+8 i ) ) #t > ( andmap number ? ( list 1 3.35 1+8 i " el de la izquierda es un complejo ") )
1
En realidad s hay, puesto que es un lenguaje funcional hbrido. Pero su necesidad es ciertamente algo que est fuera del paradigma funcional.
56
#f > ( ormap ( lambda ( x ) ( and ( real ? x ) ( positive ? x ) ) ) ( list " Slo complejos :" -1+1 i 0+8 i ( sqrt -4) -9 -5 i ) ) #f > ;;;;;;;; Ejemplo de validacin de parmetros con andmap : ;;;;;;;;;;;;; > ( define ( suma - tres - enteros - positivos a b c ) ( if ( andmap ( lambda ( x ) ( and ( integer ? x ) ( positive ? x ) ) ) ( list a b c ) ) (+ a b c ) " Los parmetros no son enteros positivos ") ) > ( suma - tres - enteros - positivos 2 3 5) 10 > ( suma - tres - enteros - positivos 2 3 -5) " Los parmetros no son enteros positivos "
9.2.3. filter
La funcin
filter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
> ( filter string ? ( list 3 " a " " b" 4 5 6) ) (" a " " b ") > ( filter complex ? ( list " Slo complejos :" -1+1 i 0+8 i ( sqrt -4) -9 -5 i ) ) ( -1+1 i 0+8 i 0+2 i -9 -5 i ) > ; Dejar slo los elementos que sean impares y mltiplos de 3;;;;;;;;;;;;;;;;;;;; > ( filter ( lambda ( x ) ( and ( odd ? x ) ;; impar (= 0 ( remainder x 3) ) ) ) ;; residuo ( list 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) ) (3 9 15) > ; Ahora como una funcin que recibe una lista como parmetro ;;;;;;;;;;;;;;;;;;;;; > ( define filtra - impares -y - mltiplos - de -3 ( lambda ( lista - nmeros ) ( if ( and ( list ? lista - nmeros ) ( andmap integer ? lista - nmeros ) ) ( filter ( lambda ( x ) ( and ( odd ? x ) (= 0 ( remainder x 3) ) ) )
57
9 Listas e Iteracin
22 23 24 25 26 27 28 29 30 31 32 33
lista - nmeros ) " Esta funcin espera una lista de nmeros " ))) > ( filtra - impares -y - mltiplos - de -3 ( list 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) ) (3 9 15) > ( filtra - impares -y - mltiplos - de -3 ( list " otra cosa ") ) " Esta funcin espera una lista de nmeros " > ( filtra - impares -y - mltiplos - de -3 " otra cosa ") " Esta funcin espera una lista de nmeros "
9.2.4. for-each
Existe la necesidad, eventualmente, de recorrer una lista, pero sin considerar el posible resultado de las evaluaciones. Generalmente, este sucede cuando necesitamos mostrar en pantalla cierta informacin, resultado de procesar una lista. Entonces, puede utilizarse la funcin nativa
for-each:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
> ( for - each ( lambda ( x ) ( display x) ) ( list 1 2 3 4 5) ) 12345 > ( for - each ( lambda ( x ) ( display x) ( newline ) ) ( list 1 2 3 4 5) ) 1 2 3 4 5 > ;; Compare los resultados entre map y for - each : ;;;;;;;;;;;;;;;; > ( for - each integer ? ( list 2 3.1 4 5 6.6) ) > ( map integer ? ( list 2 3.1 4 5 6.6) ) (# t # f # t # t #f )
La funcin
for-each,
a diferencia de
map,
for-each
58
ormap
de slo una. Las listas deben tener la misma longitud, y la funcin dada debe aceptar un parmetro por cada lista:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
> ( map + ( list 1 2 3 4 5) ( list 10 100 1000 10000 100000) ) (11 102 1003 10004 100005) > ( map ( lambda ( s n ) ( substring s 0 n ) ) ( list " agua loca " " hoja de papel " " dulcera ") ( list 4 4 7) ) (" agua " " hoja " " dulcera ") > ;;;; Compare otra vez el comportamiento de map vs . for - each : ;;;;;;;;;;;;;; > ( map / ( list 1 2 3 4 5) ( list 5 4 3 2 1) ) (1/5 1/2 1 2 5) > ( for - each ( lambda ( a b ) ( printf "~ a \ n " (/ a b ) ) ) ( list 1 2 3 4 5) ( list 5 4 3 2 1) ) 1/5 1/2 1 2 5
map.
ms primitivos
first
rest devuelve una lista con los elementos de una lista no vaca, sin su primer elemento
(el resultado puede ser una lista vaca si la lista de entrada tena slo un elemento)
cons
Ejemplos:
cons? verica si un elemento es una lista no vaca (lo contrario de empty? y de null?)
1 2 3 4 5 6
59
9 Listas e Iteracin
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
> ( cons " cabeza " empty ) (" cabeza ") > ( cons " nueva " ( cons " cabeza " empty ) ) (" nueva " " cabeza ") > ( empty ? empty ) #t > ( empty ? ( cons " cabeza " empty ) ) #f > ( cons ? empty ) #f > ( cons ? ( cons " cabeza " empty ) ) #t
9.3.1. Aplicacin
Teniendo a nuestra disposicin estas funciones de
bajo nivel
1 2 3 4 5 6 7 8 9 10
( define ( longitud L ) ( cond [( empty ? L ) 0] [ else (+ 1 ( longitud ( rest L ) ) ) ]) ) ( define ( mapear f L ) ( cond [( empty ? L ) empty ] [ else ( cons ( f ( first L) ) ( mapear f ( rest L ) ) ) ]) )
Tambin podemos hacer funciones que procesen listas de manera bsica. Por ejemplo considere la siguiente funcin para generar listas de nmeros enteros:
1 2 3 4 5 6 7 8 9 10 11 12 13
( define secuencia - de - enteros ( lambda ( num - elementos inicio paso ) ( define ( aux i contador lista ) ( if ( >= contador num - elementos ) ( reverse lista ) ( aux (+ i paso ) ( add1 contador ) ( cons i lista ) ) )) ( if ( and ( exact - nonnegative - integer ? num - elementos ) ( integer ? inicio ) ( integer ? paso ) ) ( aux inicio 0 empty ) ( error " Error en los parmetros ") )
60
))
cons acepta dos parmetros, y el segundo no necesariamente debe ser una lista.
Par
o
En el caso que como segundo argumento se le pase algo que no sea una lista, la funcin cons devuelve un
Pareja.
Un Par
en Racket no es otra cosa que dos elementos (de cualquier tipo), ligados entre s.
Una lista no vaca, de hecho, es un par compuesto por un elemento (el primero) y una lista (que puede ser vaca). La notacin que utiliza Racket para representar los pares es la de los elementos, encerrados entre parntesis y separados por un espacio en blanco, un punto y otro espacio en blanco:
1 2 3 4 5
> ( cons 1 2) (1 . 2) > ( cons " una cadena " 4) (" una cadena " . 4)
Hay una funcin equivalente a funciones correspondientes a
cons? con ms sentido para los pares: pair?. Tambin hay first y rest para pares: car y cdr. Estas ltimas funcionan
con cualquier tipo par (incluyendo las listas no vacas) y las primeras, slo funcionan con listas no vacas, pero no con pares. Ejemplos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
> ( define vaco '() ) > ( define par ( cons 1 2) ) > ( define lista ( cons 1 ( cons 2 '() ) ) ) > ( pair ? vaco ) #f > ( pair ? par ) #t > ( pair ? lista ) #t > ( car par ) 1 > ( car lista ) 1 > ( cdr par ) 2 > ( cdr lista ) (2) > ( list ? vaco ) #t
61
9 Listas e Iteracin
21 22 23 24
1 2
(0 . (1 . 2)) se convierte en (0 1 . 2). La utilidad de esta, aparentemente, extraa regla, es para volver legibles las listas, ya que, por ejemplo, (1 . (2 . (3 . ()))) que es una lista de tres elementos en su notacin de punto se convierte en (1 2 3), lo cual es
As, ms fcil de leer.
puntos
cuencia parentizada, mientras el elemento no sea ni el primero ni el ltimo. Esta convencin de sintaxis ejecuta una conversin que mueve el elemento entre los
puntos
Esta convencin posibilita una especie de notacin inja, a la cual estamos ms acostumbrados:
1 2 3 4 5 6 7 8
62
63
9 Listas e Iteracin
64
sort).
2. Dada una lista compuesta por nmeros enteros eliminar los elementos repetidos de dicha lista. Retornar una nueva lista. Nota: Se pide se pide usar
display,
retornar
3. Dada una lista compuesta por cadenas, construir una nueva lista a partir de la anterior formada por los elementos que no estn repetidos. Ejemplo para mayor comprensin:
'(hola).
4. Dada una lista compuesta por cadenas, construir una cadena formada por cada cadena
'(hola mundo) retornar holamundo. (Note que de ser la segunda cadena mundo se retornara hola mundo. Puede usar las primitivas que desee. Se recomienda leer sobre string-append.
que se encuentre en la lista. Ejemplo 5. Dada una lista compuesta por listas, retornar verdadero si todas las sublistas estn vacas y falso si por lo menos una posee algn elemento. Puede usar cualquier primitiva. 6. Dada una lista compuesta por 5 nmeros no repetidos, retornar el nmero mayor de dicha lista (ojo se pide retornar no usar
display).
7. Dada una lista compuesta por 5 cadenas no repetidas, retornar la cadena de mayor longitud. En caso de que existan 2 o ms cadenas de igual longitud y estas resulten las de mayor longitud, retornar ambas cadenas (para facilitar el ejercicio puede retornar la cadena o las cadenas dentro de una lista). 8. Dada una lista compuesta por nmeros enteros, desplegar la cantidad de nmeros pares y la cantidad de nmeros impares. 9. Dada una lista compuesta por nmeros enteros, retornar la sumatoria de todos los nmeros pares. 10. Dada una lista compuesta por nmeros enteros y dado un nmero, retornar nmero se encuentra en la lista y
member).
#f
#t
si el
11. Dada una lista compuesta por nmeros y dado un nmero, eliminar dicho nmero de la lista si este se encuentra en ella (puede usar cualquier primitiva).
65
9 Listas e Iteracin
12. Dada una lista compuesta por tres puntos (un punto es una lista, ejemplo un punto y
x 1, y 2)
retornar
#f
#t
'(1 2)
es
en caso contrario (es equiltero si sus tres lados son iguales). NOTA : Frmula
(x1 , y1 )
(x2 , y2 ): d =
(x2 x1 )2 + (y2 y1 )2
13. Dada una lista compuesta por listas, retornar una lista compuesta por los elementos de cada sublista. Ejemplo
pueden existir elementos repetidos. 14. Dada una lista compuesta por cadenas, retornar la cantidad de vocales dentro de dicha lista. Ejemplo
'(hola mundo)
retornar 4.
15. Dada una lista compuesta por cadenas, retornar la lista compuesta por las cadenas sin sus vocales. Ejemplo:
'(hola mundo)
retornar
'(hl mnd)
note que se
eliminaron las vocales. El orden de las cadenas no debe cambiar. 16. Dada una cadena, pasar cada letra de la cadena a una lista, ejemplo vierte en forma de cadena. 17. Dada una lista compuesta por cadenas, ordenar dicha lista tomando como criterio la longitud de las cadenas (No usar
'(h o l a). Note que no se piden los caracteres si no las letras en
hola
se con-
sort).
18. Elaborar una funcin que reciba como parmetro una lista de nmeros enteros y positivos, la funcin evaluar la lista de nmeros, si la lista est ordenada de mayor a menor, la funcin retornar dos listas (usando la funcin
values)
la primer lista
contendr los nmeros pares de la lista original, respetando el mismo orden de mayor a menor, y la segunda lista contendr los nmeros impares de la lista original respetando el orden de la lista original; en caso contrario, es decir si la lista pasada de parmetro est desordenada, se retornar la lista ordenada de mayor a menor.
66
10 Recursin
10.1. Recursin por Posposicin de trabajo
En el caso del siguiente cdigo de la funcin
longitud,
posposicin de trabajo:
1 2 3 4
se da este proceso:
1 2 3 4 5 6 7 8
-> = = = = = = =
( longitud ( list " a " " b " " c ") ) (+ 1 ( longitud ( list " b " " c ") ) ) (+ 1 (+ 1 ( longitud ( list " c ") ) ) ) (+ 1 (+ 1 (+ 1 ( longitud ( list ) ) ) ) ) (+ 1 (+ 1 (+ 1 0) ) ) (+ 1 (+ 1 1) ) (+ 1 2) 3
Como puede verse, se tienen que apilar todos los clculos y todas las sumas quedan
tas
pospues-
hasta que se alcanza el caso trivial de la recursin, que en este caso es cuando se en-
cuentra una lista vaca. Si la longitud de la lista es demasiado grande, provocar un gran consumo de memoria. Esto no es algo extrao , sin embargo resulta ser ineciente en Racket, ya que este lenguaje provee una optimizacin importante para la recursin de cola, que se explica a continuacin.
longitud
1 2 3 4 5
( define ( longitud L ) ; funcin local longitud - aux : ( define ( longitud - aux L longitud - actual ) ( cond [( empty ? L ) longitud - actual ]
67
10 Recursin
6 7 8
[ else ( longitud - aux ( rest L ) (+ longitud - actual 1) ) ]) ) ; este es el cuerpo de longitud , que llama a longitud - aux : ( longitud - aux L 0) )
Ahora veamos el clculo de
1 2 3 4 5 6
-> = = = = =
( longitud ( list " a " ( longitud - aux ( list ( longitud - aux ( list ( longitud - aux ( list ( longitud - aux ( list 3
Note que no hay retornos pendientes en ningn momento, tampoco hay clculos (en este caso, sumas) que queden pendientes en cada paso de la recursin. En Racket, cuando una funcin se reduce a una expresin cuyos parmetros son totalmente conocidos, toda la memoria de la funcin es liberada y ya no queda rastro de su invocacin. Esto no slo sucede con la recursin de cola, sino con cualquier llamada para la cual no queden clculos pendientes. Esta es una diferencia importante de Racket con respecto a otros lenguajes de programacin no funcionales, ya que en otros lenguajes, an haciendo recursin de cola, siempre queda memoria de las llamadas anteriores, apiladas esperando algn
return, end
o equivalente.
Esto provoca que la cantidad de memoria necesaria para ejecutar el procedimiento recursivo es aproximadamente lineal a la profundidad de la llamada. En Racket, la recursin de cola se ejecuta en una cantidad de memoria ja, para toda la ejecucin de la funcin recursiva. Queda entonces, la atenta invitacin a utilizar recursin de cola en los programas hechos con Racket, siempre que sea posible.
68
11.1. Booleanos
El tipo ms simple de Racket es el que son
#t para verdadero y #f para falso (tambin se aceptan las formas #F y #T, pero las boolean?
que verica si un valor es una de las dos constantes lgicas,
booleano
lgico.
#f:
#t
1 2 3 4
if, cond, and, or y otras, todos los valores posibles en Racket, excepto #f se evalan
como verdadero:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
> ( define ( mostrar - valor - de - verdad v ) ( if v # t # f )) > ( mostrar - valor - de - verdad "") #t > ( mostrar - valor - de - verdad " no ") #t > ( mostrar - valor - de - verdad empty ) #t > ( mostrar - valor - de - verdad '(1 2 3) ) #t > ( mostrar - valor - de - verdad #() ) #t > ( mostrar - valor - de - verdad #(1 2 3) )
69
11.2. Nmeros
A continuacin se presenta el tratamiento de los
nmeros
en Racket.
number?:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
> ( number ? 3) #t > ( number ? 3.1416) #t > ( number ? "3") #f > ( number ? 5+8 i ) #t > ( number ? 5/8) #t > ( number ? 3.45 e -200) #t
11.2.1. Clasicacin
Hay dos formas de clasicar nmeros en Racket: Por exactitud y por conjuntos.
nmero
es
exacto
inexacto.
nmeros exactos
son:
1. Los enteros 2. Los racionales 3. Los complejos con parte real exacta y parte imaginaria exacta Los
nmeros inexactos
son:
70
11.2 Nmeros
1. Los reales de coma otante 2. Los complejos con parte real inexacta o parte imaginaria inexacta Existen las funciones
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
> ( exact ? 7) #t > ( inexact ? 7) #f > ( inexact ? empty ) . . inexact ?: expects argument of type < number >; given () > ( inexact ? "") . . inexact ?: expects argument of type < number >; given "" > ( inexact ? 8.999993 -8.325421 i ) #t > ( inexact ? 7/8) #f
Pueden tambin utilizarse las funciones de un tipo a otro:
1 2 3 4 5 6 7 8
> ( exact - > inexact 1/3) 0.3333333333333333 > ( exact - > inexact (/ 7 8) ) 0.875 > ( inexact - > exact 0.3333333333333333333333333333) 6004799503160661/18014398509481984
Adems, existe una forma de forzar la representacin, como exacto o inexacto, de un nmero, independientemente de la forma en que se escriba. Con los prejos
#e
#i:
1 2 3 4 5 6 7 8
Propagacin de la exactitud
los clculos:
se mantienen exactos tras los clculos y los inexactos se mantienen inexactos a travs de
71
ZQRC
1 2 3 4 5 6 7 8 9 10 11
> ( integer ? -5) #t > ( rational ? -5/9) #t > ( real ? -5/9) #t > ( complex ? -5/9) #t
10,
pero puede
respectivamente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
> # b11 3 > # o10 8 > # xff 255 > # b111 .01 7.25 > # xf /5 3
72
11.2 Nmeros
11.2.3. Comparaciones
Los nmeros exactos pueden ser comparados con la funcin de
por proximidad
en lugar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
> (= 3 6/2) #t > (= 4+8 i 8/2+24/3 i ) #t > ( equal ? 4+8 i 8/2+24/3 i ) #t > (= 4.0+8.0 i 8/2+24/3 i ) #t > (= 4.0 4) #t > (= 0.1 1/10) #f > ( inexact - > exact 0.1) 3602879701896397/36028797018963968 > ( let ([ a 0.1] [ b 1/10] [ tolerancia 0.00001]) ( < ( abs ( - a b ) ) tolerancia ) ) #t > ( define ( son - reales - iguales ? a b tol ) ( < ( abs ( - a b ) ) tol ) )
+inf.0/-inf.0
+nan.0/-nan.0 que resultan de clculos indeterminados como cero entre cero, innito
entre innito, cero por innito, innito menos innito, etc.
1 2 3 4
73
- inf .0 > 1.79 e -400 0.0 > 1.79 e308 1.79 e +308 > 1.79 e309 + inf .0 > ;; 'NaN ' significa : Not a Number . > (/ 0.0 0.0) + nan .0 > (/ + inf .0 - inf .0) + nan .0 > (* 0.0 - inf .0) + nan .0 > (+ + inf .0 - inf .0) + nan .0
Si estos valores especiales se pasan como parmetro a alguna funcin que espere nmeros, su resultado ser del mismo tipo (excepto para algunas funciones para las que tiene signicado):
1 2 3 4 5 6 7 8
> ( cos (* (+ (* 0.0 - inf .0) 1) 9) ) + nan .0 > ( atan + inf .0) 1.5707963267948966 > (* 2 ( atan + inf .0) ) ; pi 3.141592653589793
11.3. Caracteres
Un
caracter
gramacin como
Java ).
#\
1 2 3 4
74
11.3 Caracteres
5 6 7 8 9 10
A pesar que un caracter se corresponda con un entero en Racket, a diferencia de otros lenguajes (como
Java
C ),
char->integer
integer->char:
Si algn caracter no tiene una representacin imprimible, este siempre se puede mostrar con la notacin Unicode tradicional de una letra dos bytes:
1 2 3 4
> ( integer - > char 17) #\ u0011 > ( char - > integer #\ u011D ) 285
75
11.4. Cadenas
Una
cadena
se escriben entre comillas dobles. Como en otros lenguajes, para poder escribir comillas dobles dentro de la cadena, hay que
\. Esto se conoce como secuencia de escape. De la misma manera, hay varias secuencias de escape, como \\ para escribir una pleca, \n para una nueva lnea, \r para un retorno de carro. Y para escribir un caracter dado su cdigo octal, \777 y \uFFFF
utilizar la secuencia para escribirlo en funcin de su cdigo hexadecimal Unicode. La funcin
display
76
11.4 Cadenas
Ejemplos:
string
forma una nueva cadena a partir de una serie de caracteres; devuelve un caracter de una cadena, dada su posicin; y devuelve su longitud medida en caracteres
string-ref
Ejemplos:
string-length
1 2 3 4 5 6 7 8 9 10 11 12 13
> ( string #\ H #\ o #\ l #\ a ) " Hola " > ( string ) "" > ( string - ref " Hola " 0) #\ H > ( string - ref " Hola " 3) #\ a > ( string - length " Hola ") 4
inmutables,
crear una
es decir, que no pueden ser cambiados durante el curso de su existencia como Veamos las funciones para crear una cadena mutable y alterar
objetos del programa. Pero si requerimos alterar una cadena durante la ejecucin, debemos
cadena mutable.
su contenido:
make-string
77
string->immutable-string
immutable? verica si un objeto es inmutable no slo las cadenas pueden ser mutables
.
string-copy!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
> ( make - string 4 #\ c ) " cccc " > ( define cadena - mutable ( make - string 4 #\ c ) ) > ( string - length cadena - mutable ) 4 > ( string - ref cadena - mutable 2) #\ c > ( string - set ! cadena - mutable 2 #\ a ) > cadena - mutable " ccac " > ( define cadena - inmutable ( string - > immutable - string cadena - mutable ) ) > ( immutable ? cadena - inmutable ) #t > ( immutable ? cadena - mutable ) #f > ( define otra - cadena - mutable ( make - string 10) ) > otra - cadena - mutable "\ u0000 \ u0000 \ u0000 \ u0000 \ u0000 \ u0000 \ u0000 \ u0000 \ u0000 \ u0000 " > ( string - copy ! otra - cadena - mutable 0 " buen da ") > otra - cadena - mutable " buen da \ u0000 \ u0000 "
78
11.4 Cadenas
string-ci=?, string-ci<?, string-ci<=?, string-ci>?, string-ci>=?
para hacer
string-locale=?, string-locale<?, string-locale>?, string-locale-ci=?, string-locale-ci<?, string-locale-ci>? para hacer comparaciones en funcin de ciertas consideraciones
alfabticas y lexicogrcas, en lugar de slo por las posiciones en Unicode. Ejemplos:
1 2 3 4 5 6 7 8 9 10 11
> ( string - ci <? " algo " " Bsico ") #t > ( string <? " algo " " Bsico ") #f > ( string - locale >? " rbol " " burro ") #f > ( string >? " rbol " " burro ") #t
list->string substring
Ejemplos:
devuelve una nueva cadena mutable que contiene todos los caracteres
de la cadena proporcionada. devuelve una nueva cadena mutable que es un subconjunto de la cadena
proporcionada.
1 2 3 4 5 6 7 8 9 10 11 12 13
> ( string - append " Esta " " es una cadena " " unida " ( make - string 3 #\ -) ) " Esta es una cadena unida - - -" > ( string - > list " cadena ") (#\ c #\ a #\ d #\ e #\ n #\ a ) > ( list - > string '(#\ C #\ a #\ d #\ e #\ n #\ a ) ) " Cadena " > ( substring "0123456789" 1 7) "123456" > ( substring "0123456789" 4)
79
[#x0,#xff]).
Ejemplos:
byte?
1 2 3 4 5 6
cadenas de bytes,
comunicaciones de bajo nivel. Estas cadenas no tienen codicacin Unicode, sino ASCII. En modo interactivo, se muestran como cadenas normales precedidas de un que con las cadenas normales las cadenas Unicode son por defecto muestra su valor en octal. Estas son algunas funciones para manipular cadenas de bytes:
inmutables.
#.
Y al igual Cuando
bytes-ref
de relleno.
make-bytes devuelve una nueva cadena de bytes mutable, dada su longitud y un byte bytes-set!
nuevo byte. cambia un byte de una cadena de bytes mutable, dada su posicin y el
bytes?
Ejemplos:
1 2 3 4 5 6 7 8
> #" aBcD " #" aBcD " > ( define cad - bytes #" aBcD ") > ( bytes - ref cad - bytes 0) ;; La letra 'a ' 97 > > ( define otra - cadena ( make - bytes 4 97) ) > otra - cadena
80
11.6 Smbolos
9 10 11 12 13 14 15 16 17 18
#" aaaa " > ( bytes - set ! > otra - cadena #" baaa " > > ( bytes - set ! > ( bytes - set ! > ( bytes - set ! > otra - cadena #" b \5\ n \0"
11.6. Smbolos
Un
smbolo
es como una cadena inmutable, pero sin la posibilidad de acceder a sus carac-
teres. Su utilidad radica en que son buenos para servir como etiquetas o valores constantes, o enumeraciones para las funciones. Hay algunas funciones que sirven para manipularlos:
symbol?
para vericar si un valor es smbolo o no. convierte una cadena en su correspondiente smbolo. convierte un smbolo en su respectiva cadena.
string->symbol symbol->string
Un smbolo se imprime como un identicador, pero puede estar compuesto por caracteres no permitidos en los identicadores espacios en blanco y
( ) [ ] { } , ' ` ; # | \,
en cuyo caso, se imprime como una secuencia de caracteres, encerrados en barras verticales:
||.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
> ' smbolo smbolo > ( symbol ? ' smbolo ) #t > ( symbol ? " smbolo ") #f > ( string - > symbol " este - es - un - smbolo ") este - es - un - smbolo > ( string - > symbol " este es un smbolo ") | este es un smbolo |
Por ejemplo, considere el siguiente archivo de cdigo:
1 2
81
( define secuencia - de - enteros ;; significado - fin puede ser ' nmero -de - elementos ' valor - final ( lambda ( inicio fin paso significado - fin ) ( define ( aux - num - elementos i contador lista ) ( if ( >= contador fin ) ( reverse lista ) ( aux - num - elementos (+ i paso ) ( add1 contador ) ( cons i lista ) ) )) ( define ( aux - valor - final i lista ) ( if ( >= i fin ) ( reverse lista ) ( aux - valor - final (+ i paso ) ( cons i lista ) ) ) ) ( if ( and ( integer ? fin ) ( integer ? inicio ) ( integer ? paso ) ) ( if ( equal ? significado - fin ' nmero - de - elementos ) ( if ( exact - nonnegative - integer ? fin ) ( aux - num - elementos inicio 0 empty ) ( error " El nmero de elementos debe ser no negativo ") ) ( if ( equal ? significado - fin ' valor - final ) ( aux - valor - final inicio empty ) ( error " El ltimo parmetro se esperaba como ' nmero - de elementos o como ' valor - final ") ) ) ( error " Error en los parmetros . Los primeros tres deben ser enteros .") ) ))
1 2 3 4 5 6 7 8 9 10 11
> ( secuencia - de - enteros 2 5 2 ' nmero - de - elementos ) (2 4 6 8 10) > ( secuencia - de - enteros 2 5 2 ' valor - final ) (2 4) > ( secuencia - de - enteros 0 10 3 ' nmero - de - elementos ) (0 3 6 9 12 15 18 21 24 27) > ( secuencia - de - enteros 0 10 3 ' valor - final ) (0 3 6 9)
82
palabras clave
#:palabra.
pares y listas
inmutables.
Pero tambin
de los pares:
pair?
list?
mcons
construye un par mutable (puede ser una lista mutable). verica si un par es mutable. para cambiar el primer elemento de un par mutable. para cambiar el segundo elemento de un par mutable. devuelven el primer y segundo elemento de un par mutable respectiva-
mpair?
mcdr
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
> ( mpair ? ( mcons 3 '() ) ) #t > ( mcons 3 '() ) {3} > ( mcons 3 ( mcons 2 ( mcons 1 '() ) ) ) {3 2 1} > ( define lista - mutable ( mcons 3 ( mcons 2 ( mcons 1 '() ) ) ) ) > ( define par - mutable ( mcons " a " " b ") ) > par - mutable {" a " . " b "} > ( pair ? lista - mutable ) #f
83
> ( pair ? par - mutable ) #f > ( mpair ? lista - mutable ) #t > ( mpair ? par - mutable ) #t > ( mcdr lista - mutable ) {2 1} > ( set - mcar ! par - mutable " algo ms ") > par - mutable {" algo ms " . "b "} > lista - mutable {3 2 1} > ( set - mcdr ! lista - mutable "??") > lista - mutable {3 . "??"}
Los pares y listas mutables se imprimen encerrados en llaves, pero es slo una convencin para imprimir, pero no para escribirlas directamente.
11.9. Vectores
Un
vector es un arreglo de longitud ja de valores arbitrarios. A diferencia de una lista, que
es una lista lineal de nodos enlazados en memoria, un vector soporta acceso a sus elementos lectura y escritura en tiempo constante. Esa es bsicamente su mayor diferencia. Otra diferencia, es que al imprimirse, un vector se muestra como una lista precedida por un
#.
vector construye un nuevo vector mutable conteniendo los parmetros de la funcin. vector?
verica si su parmetro es un vector. devuelve un elemento de un vector en funcin de su posicin. convierte una lista en un vector con los mismos elementos. convierte un vector en su representacin de lista.
vector-ref
84
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
> #(1 " dos " 3.1) ;; Esto genera un nuevo vector inmutable #(1 " dos " 3.1) > ( define v #(1 " dos " 3.1) ) > ( vector - ref v 0) 1 > ( vector - ref v 2) 3.1 > ( vector - > list v) (1 " dos " 3.1) > ( list - > vector '(" a " " b " " c ") ) #(" a " " b " " c ") > ( vector 1 2 3) #(1 2 3) > ( define v ( vector 0 1 2) ) > ( vector - set ! v 1 " uno ") > v #(0 " uno " 2)
Tambin hay algunas otras funciones para manipular vectores mutables e inmutables de manera parecida a las listas:
make-vector
valor de relleno.
vector-immutable
igual que vector pero devuelve un vector inmutable. devuelve un vector inmutable dado otro vector (que si
vector->immutable-vector vector-copy!
ya es inmutable, es el mismo devuelto). copia total o parcialmente el contenido de un vector (mutable o in-
tabla hash
claves como los valores pueden ser valores arbitrarios en Racket, y valores suele ser en tiempo constante, a diferencia del tiempo
mapeo
de
claves,
valores
de acceso a los vectores que siempre es constante y a diferencia del de las listas que es linealmente creciente dependiendo de la posicin del elemento a accesar.
85
hash?
verica si un elemento es una tabla hash. no recibe parmetros y devuelve una tabla hash
make-hash
mutable
vaca.
hash-set! agrega una asociacin dentro de una tabla hash mutable, sobreescribiendo
cualquier asociacin previa para la clave indicada.
hash-set toma una tabla hash inmutable, una clave y un valor, y devuelve otra tabla
hash inmutable equivalente a la anterior ms la nueva asociacin entre la clave y el valor indicados.
hash-ref devuelve el valor al que corresponde una clave indicada, dentro de una tabla
hash indicada, si es que existe.
hash-remove hash-count
Ejemplos:
tenidos en ella.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
> ( define ht - lenguajes ( make - hash ) ) > ( hash - set ! ht - lenguajes " c " '( estructurado bibliotecas compilado ) ) > ( hash - set ! ht - lenguajes " java " '( oo paquetes compilado ) ) > ( hash - set ! ht - lenguajes " racket " '( funcional mdulos interpretado ) ) > ( hash - ref ht - lenguajes " java ") ( oo paquetes compilado ) > ( hash - ref ht - lenguajes " python ") . . hash - ref : no value found for key : " python " > ( hash - ref ht - lenguajes " python " " no est ") " no est " > ( hash - count ht - lenguajes ) 3 > ( hash - set ! ht - lenguajes " python " '( multiparadigma mdulos interpretado ) ) > ( hash - count ht - lenguajes ) 4 > ht - lenguajes # hash ((" python " multiparadigma mdulos interpretado ) (" racket " funcional mdulos interpretado ) (" c " estructurado bibliotecas compilado ) (" java " oo paquetes compilado ) )
11.11. Void
Eventualmente, necesitamos construir funciones
emos que se ejecuten por sus efectos colaterales, como las funciones
86
11.11 Void
otras. En esos casos, utilizamos el procedimiento especial especial
#<void>:
void
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
> ( void ) > ( begin " Este bloque no devuelve nada ..." ( void ) ) > void # < procedure : void > > ;;; Tambin sirve cuando slo queremos la parte verdadera ( o falsa ) de un if : ;;;;;;;;;;; > ( define ( mostrar - si - es - entero n ) ( if ( integer ? n ) ( printf " El parmetro es un entero \ n ") ( void ) ) ) > ( mostrar - si - es - entero 3) El parmetro es un entero > ( mostrar - si - es - entero 5.7) > ( mostrar - si - es - entero " hola ") > ( mostrar - si - es - entero -3) El parmetro es un entero > ( void ? ( printf ) #t > ;;; Compare estas dos ejecuciones : ;;;;;;;;;;;;;;;;;;;;;;; > ( for - each display '(1 2 3) ) 123 > ( map display '(1 2 3) ) 123(# < void > # < void > # < void >)
87
88
cualquier nmero de parmetros, pero una llamada especca siempre especica un nmero jo de parmetros reales. Como resultado, no se puede pasar directamente una lista de argumentos a una funcin:
1 2 3 4 5
>
> ( promedio '(1 2 3) ) +: expects argument of type < number >; given (1 2 3)
La funcin la funcin
+ espera apply:
1 2 3 4 5 6 7 8
> ( define ( promedio L ) ;; Esta s va a funcionar (/ ( apply + L ) ( length L ) ) ) > ( promedio '(1 2 3) ) 2 > ( promedio '(1 2 3 4 5) ) 3
Su sintaxis es:
(apply <funcin> (list <parmetro-0> <parmetro-1> ...)). (<funcin> <parmetro-0> <parmetro-1> ... ).
Y el resultado equivale a:
lambda
es:
lambda
con
89
> (( lambda ( x ) ( number - > string x ) ) 3) "3" > (( lambda ( x y) (+ x y ) ) 10 20) 30 > (( lambda ( x y) (+ x y ) ) 10) # < procedure >: expects 2 arguments , given 1: 10
1 2 3 4 5 6 7 8 9 10 11 12 13 14
> (( lambda x x ) 1 2 3) (1 2 3) > (( lambda x x )) () > ( define mayor - valor - absoluto ( lambda lista ( apply max ( map abs lista ) ) ) ) > ( mayor - valor - absoluto -5 -4 -3 -2 -1 0 1 2 3) 5
( lambda ( <parmetro-formal>+ . <lista-de-parmetros> ) <expresin>+ ) <parmetro-formal> son identicadores a los que se les asignarn obligatoriamente los primeros valores de los parmetros reales pasados a la funcin. <lista-de-parmetros>
Todos los es un identicador que ser una lista con todos los parmetros reales restantes, si los hubiera. Ejemplo:
1 2 3
> ( define mayor - valor - absoluto ( lambda ( primero . lista ) ( apply max ( map abs ( cons primero lista ) ))
90
> ( mayor - valor - absoluto ) procedure mayor - valor - absoluto : expects at least 1 argument , given 0 > ( mayor - valor - absoluto -5 -4 -3 -2 -1 0 1 2 3) 5
lambda
( lambda < parmetros - formales > < expresiones - cuerpo >+ ) < parmetros - formales > ::= ( < parmetro >* ) | < lista - de - parmetros > | ( < parmetro >+ . < lista - de - parmetros > ) < parmetro > ::= < identificador - de - parmetro > | [ < identificador - de - parmetro > < valor - por - defecto > ]
Un parmetro de la forma
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
> ( define saludar ( lambda ( nombre [ apellido " Prez "]) ( string - append " Hola , " nombre " " apellido ) ) ) > ( saludar " Pedro ") " Hola , Pedro Prez " > ( saludar " Pedro " " Martnez ") " Hola , Pedro Martnez " > ( define saludar ( lambda ( nombre [ apellido ( if ( equal ? nombre " Juan ") " Prez " " Martnez ") ]) ( string - append " Hola , " nombre " " apellido ) ) ) > ( saludar " Pedro ") " Hola , Pedro Martnez "
91
> ( saludar " Juan ") " Hola , Juan Prez " > ( saludar " Eduardo " " Navas ") " Hola , Eduardo Navas "
( lambda < parmetros - formales > < expresiones - cuerpo >+ ) < parmetros - formales > ::= ( < parmetro >* ) | < lista - de - parmetros > | ( < parmetro >+ . < lista - de - parmetros > ) < parmetro > ::= < identificador - de - parmetro > | [ < identificador - de - parmetro > < valor - por - defecto > ] | < palabra - clave > < identificador - de - parmetro > | < palabra - clave > [ < identificador - de - parmetro > < valor - por defecto > ]
Un parmetro especicado como e la
<palabra-clave> <identificador-de-parmetro> es <palabra-clave>. La posicin del binomio <palabra-clave> <identificador-de-parmetro> en la lista de parmetros reales no importa para hacer
palabra clave
1.
En este momento vale la pena decir que existen cuatro tipos de parmetros:
Los parmetros obligatorios por posicin. Los parmetros opcionales por posicin.
Los parmetros obligatorios por palabra clave. Con estos, el parmetro real, debe ir precedido por una palabra clave y se corresponder con el parmetro formal que est precedido por esa misma palabra clave.
indica, se corresponde con el formal por la
4.
Los parmetros opcionales por palabra clave. En este caso, palabra clave.
el parmetro real, si se
Tambin, hay que agregar que una vez que se dene un parmetro opcional (por posicin o por palabra clave), los parmetros siguientes deben ser todos opcionales. Ejemplos:
92
> ( define saludar ( lambda ( nom #: apellido ape ) ( string - append " Hola , " nom " " ape ) ) ) > ( saludar " Eduardo " #: apellido " Navas ") " Hola , Eduardo Navas " > ( saludar #: apellido " Navas " " Eduardo ") " Hola , Eduardo Navas " > ( define saludar ( lambda (#: saludo [ sal " Hola "] nom #: apellido [ ape " Prez "]) ( string - append sal " , " nom " " ape ) ) ) > ( saludar " Juan ") " Hola , Juan Prez " > ( saludar " Karl " #: apellido " Marx ") " Hola , Karl Marx " > ( saludar " Juan " #: saludo " Qu ondas ?") " Qu ondas ? , Juan Prez " > ( saludar " Eduardo " #: apellido " Navas " #: saludo " Bonan Matenon ") " Bonan Matenon , Eduardo Navas "
case-lambda, case-lambda
comportamiento completamente diferente dependiendo del nmero de parmetros reales tiene la sintaxis:
( case - lambda [ < parmetros - formales - case > < expresiones - cuerpo >+ ]* ) < parmetros - formales - case > ::= ( < identificador - parmetro >* ) | < lista - de - parmetros > | ( < identificador - parmetro >+ . < lista - de parmetros > )
Donde cada bloque es equivalente a
lambda
para el
primer caso en que coincida el nmero de parmetros reales con los formales.
93
case-lambda
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
> ( define funcin - de - mltiple - aridad ( case - lambda [( x ) " un parmetro "] [( x y ) " dos parmetros "] [( x y z . w ) " al menos tres parmetros "]) ) > ( funcin - de - mltiple - aridad 1) " un parmetro " > ( funcin - de - mltiple - aridad 1 2) " dos parmetros " > ( funcin - de - mltiple - aridad 1 2 3) " al menos tres parmetros " > ( funcin - de - mltiple - aridad 1 2 3 4) " al menos tres parmetros "
Tambin
arity-at-least
Esta estructura tiene la denicin (vase el captulo 13):
donde
value
es un entero no negativo.
a denida como (define a (make-arity-at-least <num>)) indica que una <num> parmetros reales.
Esto puede sonar muy extrao en este momento, pero no es tan complicado, as que mejor siga leyendo el resto de la seccin.
procedure-arity
La funcin
Su sintaxis es:
procedure-arity devuelve informacin sobre la aridad de un procedimiento. (procedure-arity <funcin>). Devuelve una de tres cosas:
94
<funcin>
arity-at-least,
lo que signica
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
> ( procedure - arity cons ) 2 > ( procedure - arity list ) #( struct : arity - at - least 0) > ( arity - at - least - value ( procedure - arity list ) ) 0 > ( arity - at - least - value ( procedure - arity ( lambda ( x . y ) x ) ) ) 1 > ( procedure - arity ( case - lambda [( x ) " un parmetro "] [( x y ) " dos parmetros "] [( x y . z ) " al menos dos parmetros "]) ) (1 2 #( struct : arity - at - least 2) )
procedure-arity-includes?
Tiene la sintaxis:
(procedure-arity-includes? <funcin> <k>), donde <k> es un entero <funcin> acepta <k> parmetros.
1 2 3 4 5 6 7 8 9 10 11
> ( procedure - arity - includes ? cons 2) #t > ( procedure - arity - includes ? cons 3) #f > ( procedure - arity - includes ? ( case - lambda [( x ) " un parmetro "] [( x y ) " dos parmetros "] [( x y . z ) " al menos dos parmetros "]) 3) #t
95
> ( procedure - arity - includes ? ( case - lambda [( x ) " un parmetro "] [( x y ) " dos parmetros "] [( x y . z ) " al menos dos parmetros "]) 10) #t
Este es un ejemplo en el que se valida la aridad de una funcin pasada como parmetro:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
> ( define ( componer - funcin - unaria f x ) ( if ( and ( procedure ? f ) ( procedure - arity - includes ? f 1) ) (f (f x)) " El primer parmetro proporcionado , no es una funcin unaria ") ) > ( componer - funcin - unaria sqrt 16) 2 > ( componer - funcin - unaria cons 16) " El primer parmetro proporcionado , no es una funcin unaria " > ( componer - funcin - unaria sqr 3) 81
quotient/remainder
quotient y remainder
1 2 3 4 5 6 7 8 9
96
12.3.1. values
La funcin
values
1 2 3 4 5 6
values
se devuelven los resultados del clculo y no una lista con los resultados.
A diferencia de otros lenguajes de programacin, que fuerzan al programador a devolver un slo valor (considere lenguajes como
12.3.2. define-values
El bloque
<expresin>
1 2 3 4 5 6 7
> ( define - values ( cociente residuo ) ( quotient / remainder 101 50) ) > cociente 2 > residuo 1
let-values
1 2 3 4 5 6
en una denicin,
> ( define ( muestra - cociente -y - residuo n1 n2 ) ( let - values ([( cociente residuo ) ( quotient / remainder n1 n2 ) ]) ( printf " El cociente es : ~ a \ n " cociente ) ( printf " El residuo es : ~ a \ n " residuo ) ) )
97
let-values y let*-values es la misma que entre let y let*: let-values let*-values hace asignaciones secuencialmente.
12.4. Asignaciones
En ciertos casos
desesperados,
1
set!
set!-values.
Como ya habr notado el lector, las asignaciones de variables, no suelen necesitarse en el paradigma funcional.
98
retornar
y como segundo
N.
Es decir:
N.
2. Elaborar una funcin cuya restriccin es que tiene que recibir parmetros indenidos es decir el nmero de parmetros puede ser variable, para este ejercicio se pide que si se recibe un nmero tiene que retornar el nmero, si recibe dos nmeros tiene que retornar el mayor de ambos, si son tres nmeros retornar las dos races de la ecuacin cuadrtica, en la que cada nmero ser el coeciente literal de
Ax2 + Bx + C = 0.
3. Elaborar una funcin que reciba de parmetro una cadena y un carcter, este carcter ser el que se busque en la cadena y por cada ocurrencia de este carcter en la cadena se sustituir por un espacio en blanco. La restriccin de este ejercicio es que la cadena y el carcter pueden ser pasados de parmetro en diferente orden y la funcin deber funcionar correctamente. 4. Elaborar una funcin que reciba de parmetro una lista de smbolos que representen los atributos de un automvil y una lista de smbolos con los valores de estos atributos. La funcin retornar una lista que contenga pares, cada par contendr smbolos, indicando su atributo y su valor. Ejemplo: Si ingresamos lo siguiente:
> (automovil '(Hatchback Suzuki Forza1 Rojo si Manual) '(Tipo Marca Modelo Color A/C Transmisin))
el resultado ser:
( (Tipo . Hatchback) (Marca . Suzuki) (Modelo . Forza1) (Color . Rojo) (A/C . si) (Transmisin . Manual))
5. Elaborar una funcin que reciba una lista variable de parmetros. >Si a la funcin no se le pasa ningn parmetro, debe retornar una lista vaca. >Si slo se le pasa de parmetro un vector de nmeros enteros, retornar el vector ordenado de forma ascendente. >Si el nico parmetro no es vector o es vector pero no contiene nmeros enteros, retornar #f. >Si se le pasa de primer parmetro un vector de nmeros enteros
99
(queda a libertad el nmero de atributos). Como segundo parmetro deber recibir una lista que contenga los valores para cada atributo proporcionado en la primer lista. Notar que las listas deben ser del mismo tamao y que todos los datos de la segunda lista deben ser cadenas a excepcin de la edad que est en la posicin tres que es un nmero entero y positivo. La funcin deber retornar una lista de pares que contenga el atributo y su valor. 7. Elaborar una funcin que reciba de parmetro un nmero indenido de parmetros, con la nica restriccin que los parmetros debern ser slo nmeros enteros y positivos. Si la funcin no recibe parmetro alguno, entonces deber retornar una lista vaca, si recibe un solo parmetro entonces deber de retornar el parmetro, si recibe dos parmetros deber retornar un par con esos dos valores, si recibe tres parmetros entonces deber retornar el nmero mayor, si recibe cuatro parmetros retornar el nmero menor, si recibe cinco o ms parmetros deber retornar un vector de los elementos ordenados de menor a mayor. 8. Elaborar una funcin que reciba de parmetro a lo sumo tres parmetros, que representen un conjunto de coordenadas (x,y), estas coordenadas sern pasadas de parmetros en formato de pares es decir
retornar una lista vaca, si hay un solo parmetro retornar el punto en el plano cartesiano en forma de par , si recibe dos puntos retornar la distancia entre los dos puntos, si son tres puntos retornar el rea del tringulo formado. 9. Elaborar una funcin que reciba 2 nmeros enteros
pares donde la primera posicin ser el nmero y la segunda una cadena con si o no que indicar si el nmero es primo o no, se tomarn todos los nmeros comprendidos en el rango
puedan
100
make-<nombre-estructura> <nombre-estructura>?
turas del nuevo tipo, y toma tantos parmetros como campos tenga el tipo. es una funcin lgica que verica si el resultado de una ex-
<nombre-estructura>-<nombre-campo>
Por ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
> ( define - struct punto ( x y ) ) > ( define mi - punto ( make - punto 1 2) ) > mi - punto # < punto > > ( punto ? " punto ") #f > ( punto ? mi - punto ) #t > ( punto - x mi - punto ) 1
101
inmutables.
( struct - copy < nombre - estructura > < expresin - de - estructura > { [ < nombre - campo > < expresin - para - un - campo > ] }* )
<expresin-de-estructura> debe producir una instancia del tipo <nombre-estructura>. El resultado de la funcin string-copy es una nueva instancia de <nombre-estructura> que es idntica a la producida por <expresin-de-estructura>, excepto que sus campos indiLa cados en los corchetes tienen el valor correspondiente al resultado de la expresin indicada. Otra cosa importante de destacar es que no hay una vericacin semntica ni de tipo de los valores que se asignan a los campos de las estructuras. Ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
> ( define p1 ( make - punto 1 2) ) > ( define p2 ( struct - copy punto p1 [ x 3]) ) > ( punto - x p2 ) 3 > ( punto - y p2 ) 2 > ( define p3 ( struct - copy punto ( make - punto 10 20) [ y 5]) ) > ( punto - x p3 ) 10 > ( punto - y p3 ) 5
tura, que es un tipo de estructura que extiende a otro tipo, o que se deriva de otro. La sintaxis es:
102
> ( define - struct punto ( x y ) ) > ( define - struct ( punto3d punto ) (z ) ) > ( define p ( make - punto3d 10 9 8) ) > p # < punto3d > > ( punto ? p ) #t > ( punto3d ? p ) #t > ( punto3d - x p ) 10 > ( punto - x p ) 10 > ( punto3d - z p ) 8
Vale la pena mencionar que cuando se trata de estructuras derivadas, hay una convencin de nombres en Scheme:
derivada,
base:derivada:descendiente,
descendiente,
debera
base,
base:derivada.
Y si de esta,
su nombre formal
debera
ser
(define-struct base (...)) (define-struct (base:derivada base) (...)) (define-struct (base:derivada:descendiente base:derivada) (...))
Esta convencin permite rastrear la jerarqua de estructuras, en los casos en los que amerite. Para el caso de Racket, las estructuras de casi todas las Excepciones (ver captulo 16), se
exn. As, por ejemplo, la excepcin lanzada cuando se intenta dividir por cero se llama exn:fail:contract:divide-by-zero. Con este nombre,
derivan de una excepcin madre llamada es posible rastrear la jerarqua de derivacin de la excepcin, que a su vez permite con un poco de prctica por parte del programador entender la clasicacin de esta, slo con su nombre.
103
opaca,
de la estructura a la que corresponde. En cambio si fuera un vector, mostrando el contenido de los campos. La sintaxis para denir un tipo de estructura
transparente,
es:
se imprime como
transparente
1 2 3 4 5 6
> ( define - struct persona ( nombre direccin telfono ) #: transparent ) > ( define eduardo ( make - persona " Eduardo NAVAS " " Antiguo Cuscatln " "2210 -6600 , ext 1048") ) > eduardo #( struct : persona " Eduardo NAVAS " " Antiguo Cuscatln " "2210 -6600 , ext 1048")
La razn por la que las estructuras son por defecto opacas, es para proveer mayor
sulamiento
encap-
set-<nombre-estructura>-<nombre-campo>!;
la estructura. Ejemplo:
1 2 3 4 5 6 7 8 9 10 11
> ( define - struct punto ( x y ) #: mutable ) > ( define p ( make - punto 2.5 3.6) ) > p # < punto > > ( set - punto - x ! p 10) > ( punto - x p ) 10
104
parente :
1 2 3 4 5 6 7 8 9 10 11
mutable
y como
trans-
> ( define - struct persona ( nombre direccin telfono ) #: mutable #: transparent ) > ( define eduardo ( make - persona " Eduardo " " El Salvador " "2210 -6600") ) > eduardo #( struct : persona " Eduardo " " El Salvador " "2210 -6600") > ( set - persona - nombre ! eduardo " Edgardo ") > eduardo #( struct : persona " Edgardo " " El Salvador " "2210 -6600")
105
106
respectivamente , luego
retornar una lista con los 3 puntos ordenados de menor a mayor bajo el criterio de
(x . y)
puntoD,
la cual tiene en
107
108
14 Mdulos Funcionales
As como en otros lenguajes de programacin, en Scheme se pueden denir
cionales.
clases
Estos
mdulos
equivalen a las
bibliotecas de funciones
bibliotecas de objetos/-
Mdulos Fun-
de otros lenguajes.
En general un
mdulo sirve para encapsular cierto cdigo, sin que el usuario del mismo tenga
#lang racket es un .rkt (.ss o .scm).
que conocer los detalles de implementacin. En el caso de Racket, se trata de encapsular deniciones de funciones, de constantes, de estructuras, de clases, etc. Por defecto, un archivo de cdigo Scheme, que comience con la lnea:
mdulo funcional, cuyo nombre es el nombre del archivo, sin la extensin Por defecto, todas las deniciones de un mdulo, son otros usuarios/programadores, hay que hacerlas Por ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
# lang racket ; pastel . rkt ;; Vuelve ' pblica ' la definicin de ' imprimir - pastel ' y ' nmero - por defecto ': ( provide imprimir - pastel nmero - por - defecto ) ;; Estas ( define ( define ( define ( define definiciones son invisibles fuera de este mdulo flama #\.) candela #\|) pan #\ x ) base #\ -)
( define nmero - por - defecto 3) ; Dibuja un pastel con n candelas ( define imprimir - pastel ( lambda ([ n nmero - por - defecto ]) ( if ( and ( integer ? n ) ( exact - nonnegative - integer ? n ) ) ( begin ( printf " ~ a \ n " ( make - string n flama ) ) ( printf " . -~a -.\ n " ( make - string n candela ) ) ( printf " _ | x ~ ax | _ \ n " ( make - string n pan ) ) ( printf " - - -~a - - -\ n " ( make - string n base ) ) ) ( error " Se espera un nmero entero no negativo ") )))
109
14 Mdulos Funcionales
Entonces, desde otro archivo en el mismo directorio, se puede invocar la funcin por ejemplo desde el siguiente archivo:
imprimir-pastel,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
# lang racket ; mostrador -de - pasteles . rkt ( define secuencia - de - enteros ( lambda ( num - elementos [ inicio 0] [ paso 1]) ( define ( aux i contador lista ) ( if ( >= contador num - elementos ) ( reverse lista ) ( aux (+ i paso ) ( add1 contador ) ( cons i lista ) ) )) ( if ( and ( exact - nonnegative - integer ? num - elementos ) ( integer ? inicio ) ( integer ? paso ) ) ( aux inicio 0 empty ) ( error " Error en los parmetros ") ) )) ( require " pastel . rkt ") ; Imprime un pastel de ' nmero - por - defecto ' candelas : ( imprimir - pastel ) ( printf " El nmero por defecto de candelas es : ~ a \ n " nmero - por - defecto ) ; Imprime 8 pasteles desde 0 hasta 7 candelas : ( for - each imprimir - pastel ( secuencia - de - enteros 8) )
Para ejecutarlo, evaluamos el comando:
$ racket mostrador-de-pasteles.rkt
Otro detalle importante, es que cuando se invoca (con todas las expresiones que contenga.
require)
a un mdulo funcional,
este es ejecutado, de tal manera que se realizan todas las deniciones en l, y se ejecutan
provide:
Y con ello, disponemos de las funciones de manipulacin para la estructura (make-estructura, etc.) en otro mdulo que importe a
biblioteca.rkt.
110
15 Entrada y Salida
Aqu se describe lo bsico para comprender las posibilidades de Scheme.
Entrada y Salida
en
En Scheme, un
puerto
terminal, una conexin TCP o una cadena en memoria. Ms especcamente un puerto de entrada representa un ujo desde el cual un programa puede leer datos y un puerto de salida representa un ujo que un programa puede usar para escribir datos.
write.
en el lenguaje, que es la misma forma en que se muestran los valores en el entorno interactivo.
display.
caracter. Es una forma muy legible de mostrar los datos, pero es menos precisa sobre el tipo de dato que se muestra.
111
15 Entrada y Salida
write display
> (write 1/2) 1/2 > (write #\x) #\x > ;Note las comillas en la salida > (write hola) "hola" > (write #"nos vemos") #"nos vemos" > (write '|smbolo partido|) |smbolo partido| > (write '("cadena" smbolo)) ("cadena" smbolo) > (write write) #<procedure:write>
Finalmente, la funcin de formateo, como
> (display 1/2) 1/2 > (display #\x) x > ;No hay comillas en la salida > (display "hola") hola > (display #"nos vemos") nos vemos > (display '|smbolo partido|) smbolo partido > (display '("cadena" smbolo)) (cadena smbolo) > (display write) #<procedure:write> printf
formatea una cadena de texto con el contenido de otros
valores. Estos otros valores, se ingresan como parmetros extra en la funcin, y en la cadena con display, y poner
~a o ~s. Poner ~a provoca que el parmetro correspondiente sea agregado ~s provoca que sea agregado con write:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
> ( define ( prueba - de - printf valor ) ( printf " Con display : ~ a \ nCon write : ~ s \ n " valor valor ) ) > ( prueba - de - printf " hola ") Con display : hola Con write : " hola " > ( prueba - de - printf #\ r ) Con display : r Con write : #\ r > ( prueba - de - printf #" cadena ascii ") Con display : cadena ascii Con write : #" cadena ascii " > ( prueba - de - printf #(" vector " " con nmeros " 3) ) Con display : #( vector con nmeros 3) Con write : #(" vector " " con nmeros " 3)
112
Reader ),
es un
The
es decir, un programa
(current-input-port)
(read-char {<entrada>}? ):
por defecto es
UTF-8.
(read-byte {<entrada>}? ):
ascii.
(read-line {<entrada> {<modo>}? }? ): Lee una cadena que va desde el punto actual del cursor hasta el prximo n de lnea. Lo que se considera como n de lnea depende del segundo parmetro opcional:
<modo> ::= { 'linefeed | 'return | 'return-linefeed | 'any | 'any-one } y el valor por defecto es 'linefeed.
'linefeed 'return
interpreta el n de lnea cuando encuentra el caracter
\n. \r.
Este es el
comportamiento correcto en sistemas Unix. interpreta el n de lnea cuando encuentra el caracter Este es el
'any interpreta el n de lnea cuando encuentra un \n, \r o \r\n. 'any-one interpreta el n de lnea cuando encuentra un \n o un \r.
<cuenta>
113
15 Entrada y Salida
En todos los casos, pueden devolver el objeto especial
eof-object?.
eof
(read {<entrada>}? )
La funcin
read
(, [ ), ] ;
o o
indica el inicio de un par o una lista. indica el cierre de una estructura previamente abierta (no necesariamente
una lista, como se explica ms abajo). indica el inicio de una cadena, que se cierra en la siguiente indica que toda esa lnea es un comentario y ser ignorada. o
.
#F,
#{,
inicia un caracter, tal y como se escriben en el lenguaje. inicia una cadena de bytes.
# % inicia un smbolo (lo mismo que si no coincide con ningn otro de estos patrones).
inicia una palabra clave. inicia un bloque de comentario que ser ignorado (hasta que se encuentre un
|#).
#i, #e, #x, #o, #d, #b, #I, #E, #X, #O, #D, #B, #hash
inicia una tabla hash.
#sx inicia una expresin de racket (Scheme eXpression ). Esta opcin es muy til para
convertir texto en cdigo fuente. Esto se aplica en el cap Evaluacin Dinmica. Ejemplos (en todos ellos, tan slo la ltima lnea es la respuesta de la expresin, y todas las lneas entre la expresin y la respuesta fue introducida por el teclado):
Resumida aqu
114
> ( read ) 3 3 > (+ 2 ( read ) ) 4 6 > (+ 1 ( read ) ) # xf 16 > ( string - append " Hola , " ( read ) ) " Eduardo " " Hola , Eduardo " > ( string - append " Hola , " ( read ) ) #| este es un comentario muy largo que tiene varias lneas y que sern ignoradas por el lector |# " Eduardo " " Hola , Eduardo " > ( rest ( read ) ) (1 " cadena " ; Este es un comentario de una lnea 3.45 #(1 2 3) ; otro comentario ) (" cadena " 3.45 #(1 2 3) )
Consulte la seccin
abrir
a travs de l, y cuando ya no se necesiten, estos se deber pende de la direccin del ujo; en todos los casos son
cerrar.
La funcin de apertura,
depende del tipo particular de puerto que se necesite abrir, pero la funcin de cierre slo de-
close-input-port y close-output-port.
input-port? port?
que verica si el parmetro indicado es un puerto de entrada/lectura. que verica si el parmetro indicado es un puerto de salida/escritura.
output-port?
da/escritura.
port-closed?
115
15 Entrada y Salida
eof-object? verica si el parmetro proporcionado (que debera provenir de la lectura
de un ujo de entrada/lectura) indica que ya se ha acabado el ujo (puede implicar una conexin terminada o el n de un archivo).
flush-output
15.3.1. Archivos
open-input-file. Para abrir un archivo para escritura, se usa la funcin open-output-file. Para abrir un archivo para lectura y escritura se usa la funcin open-input-output-file.
Para abrir un archivo para lectura, se utiliza la funcin Ejemplo:
1 2 3 4 5 6 7
> ( define salida ( open - output - file " archivo . txt ") ) > ( display " Hola " salida ) > ( close - output - port salida ) > ( define entrada ( open - input - file " archivo . txt ") ) > ( read - line entrada ) " Hola " > ( close - input - port entrada )
A continuacin se describe la sintaxis de las funciones de apertura de puerto de archivo:
open-input-file
La sintaxis completa de la funcin open-input-file es: (open-input-file <ruta> {#:mode { 'binary | 'text } }? ), donde la opcin por defecto para el parmetro #:mode es 'binary.
open-output-file
La sintaxis completa de la funcin
(open-output-file <ruta> {#:mode { 'binary | 'text } }? {#:exists { 'error | 'append | 'update | 'can-update | 'replace | 'truncate | 'must-truncate } }? ), donde el parmetro #:exits indica el comportamiento a seguir cuando el archivo indicado en <ruta> ya existe. Por defecto se toma 'error. Su signicado
es:
open-output-file
es:
'error
lanza una excepcin cuando el archivo ya existe. si el archivo ya existe, el cursor se coloca al nal del archivo. se coloca al nal del archivo y genera una excepcin si no existe.
'append 'update
116
'replace
borra el archivo, si existe, y crea uno nuevo. borra el contenido del archivo, si existe. contenido de un archivo existente, y lanza una excepcin si
'truncate
no existe.
'must-truncate borra el
open-input-output-file open-input-output-file es: (open-input-output-file <ruta> {#:mode { 'binary | 'text } }? {#:exists { 'error | 'append | 'update | 'replace | 'truncate } }? ), donde el parmetro #:exits indica el comportamiento a seguir cuando el archivo indicado en <ruta> ya existe. Por defecto se toma 'error. Su signicado es:
La sintaxis completa de la funcin
'error
lanza una excepcin cuando el archivo ya existe. si el archivo ya existe, el cursor se coloca al nal del archivo. se coloca al nal del archivo y genera una excepcin si no existe. borra el archivo, si existe, y crea uno nuevo. borra el contenido del archivo, si existe.
'append 'update
'replace
'truncate
Ejemplo
Este es un programa que lee e imprime en pantalla todas las lneas de un archivo proporcionado como parmetro, anteponindoles el nmero de lnea correspondiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# lang racket ; lee - lneas . rkt ( define ( mostrar - lneas nombre - archivo ) ( define ( aux flujo nmero -de - lnea ) ( let ([ lnea ( read - line flujo ) ]) ( if ( eof - object ? lnea ) ( close - input - port flujo ) ( begin ( printf "~ a : ~ s \ n " nmero -de - lnea lnea ) ( aux flujo ( add1 nmero - de - lnea ) ) ) ) ) ) ( if ( file - exists ? nombre - archivo )
117
15 Entrada y Salida
17 18 19 20 21 22 23 24 25 26 27
( aux ( open - input - file nombre - archivo ) 1) ( error ( string - append " No existe el archivo " nombre - archivo )) )
( let ([ parmetros ( current - command - line - arguments ) ]) ( if ( not (= 1 ( vector - length parmetros ) ) ) ( error " Se espera el nombre de un archivo como parmetro ") ( mostrar - lneas ( vector - ref parmetros 0) ) ) )
Este se ejecuta:
Procesamiento automatizado
Existen accesoriamente, dos funciones para realizar de manera automatizada la apertura de un archivo y pasarle el puerto abierto resultante a una funcin. Estas funciones son:
(call-with-output-file <ruta> <procedimiento> {#:mode { 'binary | 'text } }? {#:exists { 'error | 'append | 'update | 'replace | 'truncate } }? )
En ambos casos, respectivamente. El comportamiento es el siguiente: 1. Se intenta abrir el archivo indicado en indicado en los parmetros opcionales. 2. Una vez abierto el archivo, se ejecuta al puerto recin abierto. 3. Cuando
<ruta>
<procedimiento>
debe ser
una funcin que reciba como nico parmetro obligatorio un puerto de entrada o de salida,
<ruta>
<procedimiento>
<procedimiento>
4. Finalmente, el resultado de o
La utilidad de estas funciones es que las funciones que contienen la lgica del procesamiento de los ujos (de entrada o de salida) no se mezclen con es un procedimiento que depende del tipo de puerto. Considere la siguiente variante del cdigo anterior:
1 2
118
( define ( mostrar - lneas2 flujo - de - datos ) ( define ( aux flujo nmero -de - lnea ) ( let ([ lnea ( read - line flujo ) ]) ( if ( eof - object ? lnea ) ( void ) ( begin ( printf "~ a : ~ s \ n " nmero - de - lnea lnea ) ( aux flujo ( add1 nmero - de - lnea ) ) ) ) ) ) ( aux flujo - de - datos 1) ) ( let ([ parmetros ( current - command - line - arguments ) ]) ( if ( not (= 1 ( vector - length parmetros ) ) ) ( error " Se espera el nombre de un archivo como parmetro ") ( let ([ nombre - archivo ( vector - ref parmetros 0) ]) ( if ( file - exists ? nombre - archivo ) ( call - with - input - file nombre - archivo mostrar - lneas2 ) ( error ( string - append " No existe el archivo " nombre - archivo )) ) ) ) )
15.3.2. Cadenas
As como un archivo puede
abrirse
para leer de l o para escribir en l, tambin se puede Por lo dems, funcionan igual que cualquier
hacer lo mismo con las cadenas de texto. Las funciones para abrir un puerto de cadena son:
open-input-string
puerto:
open-output-string.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
> ( define cadena - fuente " Esta es una lnea de una cadena \ nEsta es la segunda \ ny la tercera .") > ( define p - lectura ( open - input - string cadena - fuente ) ) > ( read - line p - lectura ) " Esta es una lnea de una cadena " > ( read - line p - lectura ) " Esta es la segunda " > ( read - line p - lectura ) " y la tercera ." > ( read - line p - lectura ) # < eof > > ( close - input - port p - lectura ) > > > ( define p - escritura ( open - output - string ) )
119
15 Entrada y Salida
15 16 17 18 19 20 21 22 23 24
> ( get - output - string p - escritura ) "" > ( for - each ( lambda ( x ) ( display x p - escritura ) ( newline p - escritura ) ) '(0 "1" " segundo " #" cuarto ") ) > ( get - output - string p - escritura ) "0\ n1 \ nsegundo \ ncuarto \ n " > ( close - output - port p - escritura )
La funcin
en forma de cadena.
las conex-
tcp-accept tcp-close
Ejemplo:
acepte
tcp-connect
tcp-listen.
1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9
# lang racket ; comunicacion . rkt ( provide hablar - inmediato ) ( define hablar - inmediato ( lambda ( puerto - salida cadena . parmetros ) ( apply fprintf ( cons puerto - salida ( cons cadena parmetros ) ) ) ( flush - output puerto - salida ) )) # lang racket ; servidor . rkt ( require " comunicacion . rkt ") ( define servidor ( tcp - listen 65432) ) ;; Aqu va el puerto de escucha . Falla si est ocupado . ( define ( escuchar - aux entrada salida ) ( let ([ lnea ( read - line entrada ) ])
120
( if ( eof - object ? lnea ) ( void ) ( begin ( cond [( equal ? "" lnea ) ( void ) ] [( and ( char =? #\ ( string - ref lnea 0) ) ( char =? #\? ( string - ref lnea ( sub1 ( string - length lnea ) ) ) ) ) ;( display " pregunta \n ") ( hablar - inmediato salida " Usted ha hecho una pregunta ...\ n ") ( sleep 2) ( hablar - inmediato salida " Buscando la respuesta \ n ") ( sleep 2) ( hablar - inmediato salida " Lo siento , no s la respuesta \ n ") ] [( equal ? " ya no escuche ms " lnea ) ( display " mensaje para salir , recibido \ n ") ( tcp - close servidor ) ( exit ) ] [ else ;( display " mensaje incomprensible \ n ") ( hablar - inmediato salida " No entiendo lo que me dice \ n ") ] ) ( escuchar - aux entrada salida ) ) ) )
( define ( escuchar ) ( define - values ( entrada salida ) ( tcp - accept servidor ) ) ( printf " Este es el servidor : Conexin aceptada \ n ") ( hablar - inmediato salida " Hola , este es su amigo el Servidor , cmo est ?\ n ") ( escuchar - aux entrada salida ) ( printf " Este es el servidor : Conexin terminada \ n ") ( escuchar ) ) ( escuchar ) # lang racket ; cliente . rkt ( require " comunicacion . rkt ") ;; La IP del servidor ( o su nombre de dominio ) y el puerto ( define - values ( lectura escritura ) ( tcp - connect " localhost " 65432) )
1 2 3 4 5 6 7
121
15 Entrada y Salida
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
( define ( comunicarse ) ( let ([ comando ( read - line ) ]) ( if ( equal ? " salir " comando ) ( begin ( close - output - port escritura ) ( exit ) ) ( if ( port - closed ? escritura ) ( begin ( printf " El puerto ya se cerr \ nSaliendo ...\ n ") ( exit ) ) ( hablar - inmediato escritura "~ a \ n " comando ) ) ) ) ( comunicarse ) ) ( define ( escuchar ) ( let ([ mensaje ( read - line lectura ) ]) ( if ( eof - object ? mensaje ) ( void ) ( begin ( printf "~ a \n > > " mensaje ) ( escuchar ) ) ) ) ) ( void ( thread escuchar ) ) ( comunicarse )
display, printf, write, read-char, read-line read para imprimir informacin en patalla. Estas funciones, utilizan por defecto tres ujos (current-input-port) (current-error-port)
devuelve el puerto de entrada estndar. devuelve el puerto de salida estndar.
(current-output-port)
Para cambiar los puertos por defecto, se pueden usar estas mismas funciones con un parmetro puerto:
122
(current-output-port <p>)
123
15 Entrada y Salida
124
#\u0042.
#\u0040
7. Construya la funcin de desencriptamiento correspondiente al ejercicio anterior. 8. Se ha dejado una tarea en la que se tiene que entregar un informe de 500 palabras, el profesor tiene que calicar de forma rpida y con exactitud lo que se pidi, por eso necesita, entre otras cosas, un programa que cuente las palabras, y le pidi la ayuda a usted . As que tiene que elaborar un programa que reciba de parmetro el nombre del archivo a revisar y tiene que mostrar el nmero de palabras que tiene el archivo. 9. Usando la estructura
persona
persona
no existe retornar un mensaje de error. 10. Construya una funcin que retorne informacin alguna.
#t
125
15 Entrada y Salida
11. Elaborar un programa que reciba de parmetro el nombre de un archivo de texto, dicho archivo debe contener en cada lnea una serie de palabras. La primera representa el nombre de un continente y las dems representan nombres de los pases de ese continente, se pide leerlos del archivo y mostrarlos en la salida estndar en forma de pares que contengan una cadena con el nombre del continente y un vector de cadenas con los nombre de los pases en el archivo. Los vectores debern estar ordenados alfabticamente y los pares debern mostrarse tambin ordenados por el nombre del continente. Si el archivo no existe retornar un mensaje de error. 12. Elabore un programa que realice la funcin de buscar una palabra en un archivo de texto. El programa recibir de parmetro el nombre del archivo, pero pedir en tiempo de ejecucin una palabra a buscar y si la encuentra, mostrar un mensaje indicndolo junto con la la y la columna en la que la encontr. Si no la encontr, mostrar el mensaje correspondiente. Si el archivo no existe mostrar un mensaje de error. 13. Elaborar una funcin que reciba como primer parmetro el nombre de un archivo origen.txt y como segundo parmetro el nombre de un archivo destino.txt . La funcin deber copiar la ltima letra del archivo origen.txt en la primer posicin del archivo destino.txt , la penltima letra del archivo origen.txt en la segunda posicin del archivo destino.txt y as sucesivamente.
126
16 Excepciones
En Scheme, cuando sucede un error en tiempo de ejecucin, se menos que la excepcin sea
error un mensaje asociado con la excepcin y terminando los clculos. Por ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12
> (/ 100 0) . . /: division by zero > ( car 35) . . car : expects argument of type < pair >; given 35 > ( define p ( open - input - string " Esta es la cadena fuente ") ) > ( read - string 5 p ) " Esta " > ( close - input - port p ) > ( read - string 5 p ) . . read - string : input port is closed
atrapar una excepcin, se usa el bloque with-handlers que tiene la sintaxis: (with-handlers ( { [<f-evaluadora> <f-manejadora>] }* ) <exp-cuerpo>+ )
Y funciona de la siguiente manera: Cuando aparece una forma como esta en el curso actual de ejecucin, se comienzan a evaluar las expresiones del cuerpo, las
<exp-cuerpo>. Si este cdigo lanza alguna excepcin, se llama la primera funcin <f-evaluadora>. Si esta se evala a verdadero, se ejecuta la correspondiente <f-manejadora> y su resultado ser el resultado del bloque with-handlers. Si <f-evaluadora> se evala a falso, se probar con la siguiente <f-evaluadora> si la hay, y as sucesivamente. Si ninguna <f-evaluadora> resulta en verdadero, la excepcin ser relanzada para que otro bloque with-handlers de <f-evaluadora> y las <f-manejadora> deben recibir un nico parmetro exn:fail
(recurdese la seccin 13.2).
obligatorio que ser el valor que represente a la excepcin lanzada en el cuerpo. Tpicamente ser una instancia de alguna estructura derivada de Ejemplo:
127
16 Excepciones
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
> ( with - handlers ([ exn : fail : contract : divide - by - zero ? ( lambda (e ) + inf .0) ]) (/ 100 0) ) + inf .0 > ( with - handlers ([ exn : fail : contract : divide - by - zero ? ( lambda (e ) + inf .0) ]) ( car 35) ) . . car : expects argument of type < pair >; given 35 > ( with - handlers ([ exn : fail : contract : divide - by - zero ? ( lambda (e ) + inf .0) ] [ exn : fail ? ( lambda ( e ) ( exn - message e ) ) ]) ( define p ( open - input - string " Esta es la cadena fuente ") ) ( display ( read - string 5 p )) ( close - input - port p ) ( read - string 5 p ) ) Esta " read - string : input port is closed "
error
exn:fail:
1 2 3 4 5 6
> ( error " Error fatal !! Todos vamos a morir !!") . . Error fatal !! Todos vamos a morir !! > ( with - handlers ([ exn : fail ? ( lambda ( e ) " Que no cunda el pnico !") ]) ( error " Error fatal !! Todos vamos a morir !!") ) " Que no cunda el pnico !"
Lo usual es que las excepciones sean instancias de la estructura sus derivadas (lo que incluye el resultado de la funcin lanzar nuestras propias La funcin
excepciones
error),
exn:fail
o de alguna de
costumbre.
raise
1 2 3 4 5 6 7
> ( raise 2) uncaught exception : 2 > ( with - handlers ([( lambda ( v ) ( equal ? v 2) ) ( lambda ( v ) ' dos ) ]) ( raise 2) ) dos > ( with - handlers ([( lambda ( v ) ( equal ? v 2) ) ( lambda ( v ) ' dos ) ] [ string ? ( lambda ( e ) ( printf " La excepcin es una cadena \ n ") ) ])
128
129
16 Excepciones
130
dinmico,
eval
apostrofada
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
> ( eval '(+ 1 2) ) 3 > ( eval ( read ) ) (* 4 (+ 2 3) ) 20 > ( define expresin '(+ x (* x 5) ) ) > ( define x 2) > ( eval expresin ) 12 > ( cons sqrt '(4) ) (# < procedure : sqrt > 4) > ( eval ( cons sqrt '(4) ) ) 2 > ( define ( f x ) ( expt 2 x ) ) > (( eval 'f ) 4) 16 > ( define smbolo 'f ) > (( eval smbolo ) 5) 32 > smbolo f
131
eval
read
expresin de racket vlida, en una funcin que evala esa expresin. A continuacin se
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 9 10 11 12 13 1 2 3 4 5 6 7 8 9 10 11 12
> ( define expresin ( read ) ) "(+ x (* x 5) ) " > ( define x ( read ) ) 2 > ( define p - cad ( open - input - string expresin ) ) > ( define resultado ( eval ( read p - cad ) ) ) > resultado 12 > ( define cadena "(+ x 1) ") > ( define funcin - cadena ( string - append "# sx ( lambda ( x) " cadena ") ") ) > funcin - cadena "# sx ( lambda ( x ) (+ x 1) ) " > ( define p ( open - input - string funcin - cadena ) ) > ( close - input - port p ) > ( define exp ( read p ) ) > (( eval exp ) 3) 4 > (( eval exp ) 1.22) 2.2199999999999998 > (( eval exp ) 3.1416) 4.1416 > ( define cadena "# sx ( lambda ( x y ) (+ ( sqrt ( sqr x ) ( sqr y ) ) ) ) ") > ( define entrada ( open - input - string cadena ) ) > ( define hipotenusa ( eval ( read entrada ) ) ) > ( read entrada ) # < eof > > ( close - input - port entrada ) > hipotenusa # < procedure > > ( procedure - arity hipotenusa ) 2 > ( hipotenusa 3 4) 5
132
class que es una clase sin nombre. Su sintaxis es: ( class <superclase> <declaracin-o-expresin>* )
Y al igual que podemos utilizar
define con lambda para denir funciones/procedimientos con nombre, podemos utilizar define con class para denir clases con nombre: (define <nombre-clase> (class <superclase> <declaracin-o-expresin>* ))
Por convencin, los nombres de las clases en Scheme, terminan con el caracter %. La clase raz integrada del lenguaje se llama
object %.
<identificador>
clase que implemente la interface. De no ser as, se lanzar un error al momento de evaluar la denicin de la clase en cuestin. Para denir una clase que implemente interfaces, se usa el bloque
133
lambda
<parmetro-de-inicializacin>
18.4. Mtodos
18.4.1. Denicin e Invocacin de Mtodos
Dentro del cuerpo de una clase, en su seccin de deniciones, se denen los mtodos de la clase con el bloque:
define/public
1 2 3 4
( begin ( public < nombre - mtodo >) ( define < nombre - mtodo > <exp - lambda_con_PARMETROS_y_EXP - CUERPO > ) )
El bloque
pblicas
public
sirve para indicar todos los identicadores de las funciones que sern
provide
para hacer
visibles o pblicos
send:
ciertos identicadores
define/override
1 2 3 4
( begin ( override < nombre - mtodo >) ( define < nombre - mtodo > <exp - lambda_con_PARMETROS_y_EXP - CUERPO > ) )
El bloque
sobreescritos
override
sirve para indicar todos los identicadores de las funciones que sern
en esta clase.
134
breescritos
define/override-final
heredado):
define/public-final
soy
1 2 3 4
( begin ( public - final < nombre - mtodo >) ( define < nombre - mtodo > <exp - lambda_con_PARMETROS_y_EXP - CUERPO > ) )
y
1 2 3 4
( begin ( override - final < nombre - mtodo >) ( define < nombre - mtodo > <exp - lambda_con_PARMETROS_y_EXP - CUERPO > ) )
Los bloques
public-final
override-final
sobreescritos
init
( class < superclase > < declaracin -o - expresin >* ( init < parmetro - formal >* ) < declaracin -o - expresin >* )
donde:
new, pero pasando los parmetros con sus respectivos nombres de parmetro formal: (new <nombre-clase> <parmetro-real>* )
bloque donde:
135
cuando en
se encuentre la llamada a
A y estos (super-new).
init).
init),
y una
Entonces la instanciacin
A dene sus parmetros de inicializacin y que su clase derivada B tambin dene los suyos, diferentes de los de A. Entonces, en la inicializacin de B debe hacerse una invocacin a super-new con los parmetros correspondientes para la inicializacin de A, con
Supongamos que el bloque:
(super-new <parmetro-real>* )
interface? object=?
la clase.
class->interface toma una clase y devuelve la interface implcitamente denida por object-interface toma un objeto y devuelve la interface implcitamente declara por
la clase del objeto.
is-a?
de la clase, o si el valor es una instacia de alguna clase que implemente la interface proporcionada.
subclass?
la clase proporcionada.
implementation? toma un valor y una interface y verica si el valor es una clase que
implementa la interface proporcionada.
implementation-extension? method-in-interface?
una interface que extiende a la interface proporcionada. toma un smbolo y una interface y verica si la interface (o
alguna de sus ancestros) contiene un miembro con el mismo nombre que el smbolo.
interface->method-names
object-method-arity-includes?
y verica si el objeto en cuestin tiene un mtodo llamado como el smbolo y que adems acepte ese nmero de parmetros.
136
18.7 Ejemplos
18.7. Ejemplos
Este es un ejemplo sobre denicin de clases y mtodos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
# lang racket ; cola . rkt ;; Definicin de una clase Cola ( define cola % ( class object % ( super - new ) ;; Siempre debe inicializarse la superclase ( define elementos '() ) ;; Este valor es " privado " , dentro de la clase . ( define / public ( tamao ) ( length elementos ) ) ( define / public ( meter nuevo - elemento ) ( set ! elementos ( cons nuevo - elemento elementos ) ) ) ( define / public ( sacar ) ( if ( empty ? elementos ) ( error " Intento de extraer un elemento de una Cola vaca !") ( let ([ e ( last elementos ) ] ;; ' last ' devuelve el ltimo elemento de una lista ;; ' take ' devuelve una lista con los primeros elementos de una lista [ lista ( take elementos ( sub1 ( length elementos ) ) ) ]) ( set ! elementos lista ) e ) ) ) )
cola %:
1 2 3 4 5 6 7 8 9 10 11 12
> ( define colita ( new cola %)) > colita #( struct : object : cola % ...) > ( send colita tamao ) 0 > ( send colita sacar ) . . Intento de extraer un elemento de una Cola vaca ! > ( send colita meter 1234) > ( send colita tamao ) 1 > ( for - each ( lambda ( e ) ( send colita meter e ) ) '("1" "2" "3" "4") ) > ( send colita tamao )
137
5 > ( send colita sacar ) 1234 > ( send colita tamao ) 4 > ( send colita sacar ) "1"
Ejemplo para aclarar el signicado de
define/public:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
# lang racket ; pila . rkt ;; Definicin de una clase Pila ( define pila % ( class object % ( super - new ) ( define elementos '() ) ( public tamao ) ;; ' public ' y ' define ' separados ( define ( tamao ) ( length elementos ) ) ( public meter ) ;; ' public ' y ' define ' con ' lambda ' separados ( define meter ( lambda ( nuevo - elemento ) ( set ! elementos ( cons nuevo - elemento elementos ) ) ) ) ( define / public ( sacar ) ;; ' public ' y ' define ' juntos ( if ( empty ? elementos ) ( error " Intento de extraer un elemento de una Pila vaca !") ( let ([ e ( first elementos )] [ lista ( rest elementos ) ]) ( set ! elementos lista ) e ) ) ) ) )
pila %:
1 2 3
> ( define pilita ( new pila %)) > ( new pila %) #( struct : object : pila % ...)
138
18.7 Ejemplos
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
( send pilita tamao ) ( send pilita meter sqrt ) ( send pilita tamao ) (( send pilita sacar ) 81) ( send pilita tamao )
( for - each ( lambda ( e ) ( send pilita meter e ) ) '( cos sqrt 3 " hola ") ) (( lambda ( pila ) ( define ( sacar - todo p ) ( if ( positive ? ( send p tamao ) ) ( begin ( printf " Elemento : ~ a \ n " ( send p sacar ) ) ( sacar - todo p ) ) ( void ) ) ) ( sacar - todo pila ) ) pilita ) Elemento : hola Elemento : 3 Elemento : sqrt Elemento : cos
139
140
Parte IV
141
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# lang racket ; hola - mundo . rkt ; invocar al mdulo gui ( require racket / gui ) ; Crear una ventanta ( define ventana ( new frame % [ label " Hola Mundo !"]) ) ; Crear y ponerle un objeto ' message %' a la ventana ( define mensaje ( new message % [ parent ventana ] [ label " Esta es una etiqueta con un poco de texto de prueba \ nen dos lneas "]) ) ; Mostrar la ventana al usuario ( send ventana show # t )
143
Existen varios mecanismos para manejar eventos. Entre ellos, algunos objetos, permiten indicar un procedimiento de
callback
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# lang racket ; eventos -1. rkt ( require racket / gui ) ( define ventana ( new frame % [ label " Mi primer evento !"]) ) ( define mensaje ( new message % [ parent ventana ] [ label " Los eventos de los botones son ..."]) ) ( new button % [ parent ventana ] [ label " Mostrar respuesta "] ; Funcin a invocar cuando se presione el botn . ; Debe ser una funcin binaria , recibe una referencia al botn , ; y una instancia ' control - event %'. [ callback ( lambda ( botn evento ) ; Los objetos ' message %' tienen un mtodo 'set - label '
144
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
# lang racket ; eventos -2. rkt ( require racket / gui ) ( define ventana ( new frame % [ label " Mi segundo evento !"]) ) ( define mensaje ( new message % [ parent ventana ] [ label " Los eventos de los botones son ..."]) ) ; Se est mostrando la respuesta ? ( define respuesta - mostrada #f ) ( define mi - botn ( new button % [ parent ventana ] [ label " Mostrar respuesta "] [ callback ( lambda ( botn evento ) ( if respuesta - mostrada ( begin ( send mensaje set - label " Los eventos de los botones son ...") ( send mi - botn set - label " Mostrar respuesta ") ( set ! respuesta - mostrada # f ) ) ( begin ( send mensaje set - label " sencillos :) ") ( send mi - botn set - label " Ocultar respuesta ") ( set ! respuesta - mostrada # t ) ) )
145
callback
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# lang racket ; eventos -3. rkt ( require racket / gui ) ( define ventana ( new frame % [ label " Mltiples eventos "]) ) ( define ( funcin - manejadora b c ) ( if ( object =? b botn1 ) ( send mensaje set - label " Se presion el botn 1") ( send mensaje set - label " Se presion el botn 2") ) ) ( define botn1 ( new button % [ parent ventana ] [ label " Botn 1"] [ callback funcin - manejadora ] )) ( define mensaje ( new message % [ parent ventana ] [ label " An no se ha presionado ningn botn "]) ) ( define botn2 ( new button %
146
[ parent ventana ] [ label " Botn 2"] [ callback funcin - manejadora ] )) ( send ventana show # t )
Figura 19.5: dialogo.rkt Se pueden lanzar ventanas de dilogo, de manera muy sencilla, con la clase
dialog %:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# lang racket ; dialogo . rkt ( require racket / gui ) ; Ventana principal ( define ventana ( new frame % [ label " Inicio de sesin "]) ) ( define datos ( new message % [ label " An no ha iniciado sesin "] [ parent ventana ] [ auto - resize # t ] )) ( define lanzar ( new button % [ parent ventana ] [ label " Iniciar sesin "] [ callback ( lambda ( b c ) ( send ventana - de - dilogo show # t ) ( send datos set - label ( string - append " Usuario : '"
147
))
)]
( send txt - usuario get - value ) " ' , Contrasea : '" ( send txt - contrasea get - value ) " '" )
; La otra ventana , de dilogo ( define ventana - de - dilogo ( new dialog % [ label " Identifquese por favor "]) ) ( define txt - usuario ( new text - field % [ label " Usuario :"] [ parent ventana - de - dilogo ] )) ( define txt - contrasea ( new text - field % [ label " Contrasea :"] [ parent ventana - de - dilogo ] [ style ( list ' single ' password ) ] )) ( new button % [ parent ventana - de - dilogo ] [ label " Aceptar "] [ callback ( lambda ( b c ) ( send ventana - de - dilogo show # f ) ) ] ) ( send ventana show # t )
1 2 3
148
( require racket / gui ) ; Ventana principal ( define ventana ( new frame % [ label " Eventos de ' text - field % '"]) ) ( define mensaje ( new message % [ label " An no ha escrito nada en el cuadro de texto "] [ parent ventana ] )) ( define copia - contenido ( new message % [ label ""] [ parent ventana ] [ auto - resize # t ]) ) ( define texto ( new text - field % [ label " Escriba algo :"] [ parent ventana ] [ init - value " Valor por defecto "] [ callback ( lambda ( obj control ) ( case ( send control get - event - type ) [ ' text - field ( send mensaje set - label " Evento ' text - field ") ( send copia - contenido set - label ( send texto get - value ) ) ] [ ' text - field - enter ( send mensaje set - label " Evento ' text - field - enter ") ] ) )] )) ( define otro - texto ( new text - field % [ label " ms texto :"] [ parent ventana ] [ init - value " Cuando presione Enter aqu , la ventana se cerrar "] [ callback ( lambda ( o c ) ( if ( equal ? ' text - field - enter ( send c get - event - type ) ) ; Esto dispara la funcin de ' callback ' de 'btn - salir ': ( send btn - salir command ( new control - event % [ event - type ' button ]) ) ( void ) ) )] )) ( define btn - salir ( new button % [ label " Salir "]
149
[ parent ventana ] [ callback ( lambda ( b c ) ( send ventana show # f ) ) ]) ) ( send ventana show # t )
19.6. Pneles
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# lang racket ; pneles . rkt ( require racket / gui ) ( define ventana ( new frame % [ label " Pneles horizontales "]) ) ( define mensaje ( new message % [ parent ventana ] [ label " Pneles horizontales "] [ auto - resize # t ] )) ;( define panel ( new horizontal - pane % [ parent ventana ]) ) ( define panel ( new horizontal - panel % [ parent ventana ]) ) #| La diferencia entre ' pane %' y ' panel %' es que ' pane %' slo sirve para administrar la distribucin de los dems controles , no puede ser ocultado o deshabilitado ,
150
19.6 Pneles
20 21 22 23 24 25 26 27 28 29 30 31 32 33
ni soporta manejo de eventos . |# ( new button % [ parent panel ] [ label " Botn Izquierdo "] [ callback ( lambda ( button ( send mensaje ( new button % [ parent panel ] [ label " Botn Derecho "] [ callback ( lambda ( button ( send mensaje ( send ventana show # t )
event ) set - label " Clic del botn izquierdo ") ) ]) event ) set - label " Clic del botn derecho ") ) ])
151
152
1 2 3 4 5 6 7 8 9 10 11
# lang racket ; controles . rkt ( require racket / gui ) ( define ventana ( new frame % [ label " Otros controles "]) ) ;; Objetos de la ventana principal : -------------------------------------------( define texto ( new message % [ parent ventana ] [ label " Objeto 'tab - panel % ':"]
153
12 13 14 15 16 17 18 19 20 21 22
23 24 25 26 27 28 29 30 31 32 33 34 35
)) ( define opciones ( list " Botones " " Casillas de verificacin " " Opcin mltiple " " Listas " " Cuadros de texto " " Otros " " Canvas ") ) ( define tab ( new tab - panel % [ parent ventana ] [ choices opciones ] [ callback ( lambda ( t c ) ; una instancia de 'tab - panel %' y de ' control - event %' ( let * ([ ix ( send tab get - selection ) ] [ ix - str ( number - > string ix ) ] [ nombre - ficha ( send tab get - item - label ix ) ]) ( send mensaje set - label ( string - append " Se seleccion la ficha " ix - str " con nombre '" nombre - ficha " '") ) ( send tab delete - child ( first ( send tab get - children ) )) ( send tab add - child ( list - ref lista - pneles ix ) ) ) )] )) ( define mensaje ( new message % [ parent ventana ] [ label " Aqu se mostrarn los eventos de los objetos "] [ auto - resize # t ] )) ;; Objetos pneles : ------------ ----------------------- ----------------------
154
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
vertical - panel % vertical - panel % vertical - panel % vertical - panel % vertical - panel % vertical - panel % vertical - panel %
tab ]) ) tab ][ style tab ][ style tab ][ style tab ][ style tab ][ style tab ][ style
'( deleted ) ]) ) '( deleted ) ]) ) '( deleted ) ]) ) '( deleted ) ]) ) '( deleted ) ]) ) '( deleted ) ]) )
( define lista - pneles ( list panel0 panel1 panel2 panel3 panel4 panel5 panel6 ) ) ;; Panel 0 - Botones ---------- ----------------- ------------------ ------------( define panel - botones ( new horizontal - pane % [ parent panel0 ]) ) ( define ( funcin - botn b c) ( send mensaje set - label ( string - append " Clic en el botn '" ( send b get label ) " '") ) ) ( define botn1 ( new button % [ parent panel - botones ] [ label " aqu "] [ callback funcin - botn ]) ) ( define panel - botones2 ( new vertical - pane % [ parent panel - botones ]) ) ( define botn2 ( new button % [ parent panel - botones2 ] [ label " all "] [ callback funcin - botn ]) ) ( define botn3 ( new button % [ parent panel - botones2 ] [ label " otro "]
155
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
[ callback funcin - botn ]) ) ( define botn4 ( new button % [ parent panel - botones2 ] [ label " y otro "] [ callback funcin - botn ]) ) ( define botn5 ( new button % [ parent panel - botones ] [ label " y ms "] [ callback funcin - botn ]) ) ;; Panel 1 - Casillas de verificacin ---------------------------------------( define ( funcin - chequeo c e ) ; una instancia ' check - box %' y de ' control event %' ( send mensaje set - label ( string - append " Se " ( if ( send c get - value ) " seleccion " " deseleccion ") " la casilla '" ( send c get - label ) " '") ) ) ( define chequeo1 ( new check - box % [ label " Chequame "] [ parent panel1 ] [ value # f ] [ callback funcin - chequeo ]) ) ( define chequeo2 ( new check - box % [ label " Este es otro ' check - box %'"] [ parent panel1 ] [ value # t ] [ callback funcin - chequeo ]) ) ( define chequeo3 ( new check - box %
156
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
[ label " Este no responde a ningn evento ,\ ntiene tres lneas \ ny por defecto no est marcado "] [ parent panel1 ] )) ;; Panel 2 - Opcin mltiple ---------------------------------------------( define ( funcin - opcin - mltiple r c ) ; instancia ' radio - box %' y ' control event %' ( send mensaje set - label ( string - append " Se marc la opcin " ( number - > string ( send r get - selection ) ) " con texto '" ( send r get - item - label ( send r get - selection ) ) " ' del grupo '" ( let ([ t ( send r get - label ) ]) ( if t t " < sin - texto >") ) " '" )) ) ;( send panel2 set - orientation # t ) ; orientacin horizontal ( define panel - radio1 ( new radio - box % [ label " Verticales "] [ parent panel2 ] [ choices ( list " Opcin 1" " Opcin 2") ] [ callback funcin - opcin - mltiple ] )) ( define panel - radio2 ( new radio - box %
157
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
[ label " Horizontales "] [ parent panel2 ] [ choices ( list " Opcin 1" " Opcin 2") ] [ callback funcin - opcin - mltiple ] [ style ( list ' horizontal ) ] [ selection 1] )) ( define panel - radio3 ( new radio - box % [ label " Horizontales con la etiqueta arriba "] [ parent panel2 ] [ choices ( list " Opcin 1" " Opcin 2") ] [ callback funcin - opcin - mltiple ] [ style ( list ' horizontal ' vertical - label ) ] )) ( define panel - radio4 ( new radio - box % [ label " Verticales con la etiqueta arriba "] [ parent panel2 ] [ choices ( list " Opcin 1" " Opcin 2") ] [ callback funcin - opcin - mltiple ] [ style ( list ' vertical ' vertical - label ) ] )) ( define panel - radio5 ( new radio - box % [ label # f ] [ parent panel2 ] [ choices ( list " Sin etiqueta " " Slo estn los ' radio - box %'")] [ callback funcin - opcin - mltiple ]
158
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
)) ;; Panel 3 - Listas ------------------------------------------------------( define ( funcin - lista r c) ; instancia de lista y ' control - event %' ( send mensaje set - label ( string - append " Se marc la opcin " ( number - > string ( send r get - selection ) ) " con texto '" ( send r get - string - selection ) " ' de la lista '" ( let ([ t ( send r get - label ) ]) ( if t t " < sin - texto >") ) " '" )) ) ( define panel - lista1 ( new horizontal - pane % [ parent panel3 ]) ) ( define eleccin1 ( new choice % [ label " Primera lista "] [ choices ( list " Opcin 1" " Opcin 2" " etc .") ] [ parent panel - lista1 ] [ callback funcin - lista ] [ selection 2] )) ( define eleccin2 ( new choice % [ label " Segunda lista "] [ choices ( list " Opcin 1" " Opcin 2" " etc .") ] [ parent panel - lista1 ] [ callback funcin - lista ] [ style ( list ' vertical - label )] )) ( define eleccin3 ( new choice % [ label # f] [ choices ( list " Opcin 1" " Opcin 2" " etc .") ] [ parent panel - lista1 ] [ callback funcin - lista ] )) ( define panel - lista2 ( new horizontal - pane % [ parent panel3 ]) ) ( define lista1 ( new list - box % [ label " Primera lista "] [ choices ( list " Opcin 1" " Opcin 2" " etc .") ] [ parent panel - lista2 ] [ callback funcin - lista ] [ selection 2] )) ( define lista2 ( new list - box % [ label " Segunda lista "] [ choices ( list " Opcin 1" " Opcin 2" " etc .") ] [ parent panel - lista2 ] [ callback funcin - lista ] [ style ( list ' multiple ' vertical - label ) ] ))
159
( define lista3 ( new list - box % [ label # f ] [ choices ( list " Opcin 1" " Opcin 2" " etc .") ] [ parent panel - lista2 ] [ callback funcin - lista ] [ style ( list ' extended ' vertical - label ) ] )) ; ver adicionalmente , los mtodos 'get - selections ' y 'is - selected ? ' de ' list - box %' ;; Panel 4 - Cuadros de texto --------------------------------------------( define ( funcin - texto t c) ( send mensaje set - label ( string - append " Texto : < <" ( send t get - value ) " > >") ) ) ( define texto1 ( new text - field % [ label " Etiqueta "] [ parent panel4 ] [ init - value " escriba algo "] [ callback funcin - texto ] )) ( define texto2 ( new text - field % [ label " Etiqueta "] [ parent panel4 ] [ init - value " etiqueta arriba "] [ style ( list ' vertical - label ' single ) ] [ callback funcin - texto ] )) ( define texto3 ( new text - field % [ label # f ] [ parent panel4 ] [ init - value " sin etiqueta arriba "] [ style ( list ' multiple ) ] [ callback funcin - texto ] )) ( define combo1 ( new combo - field % [ label " Combo 1"] [ parent panel4 ] [ choices ( list " Opcin 1" " Opcin 2" " etc .") ] [ init - value " por defecto "] [ callback ( lambda ( c e ) ( send mensaje set - label ( string - append " Evento del ' combo field %' " ( send c get - label ) )))] )) ( define combo2 ( new combo - field % [ label " Agrega opciones al precionar Enter :"] [ parent panel4 ] ;[ choices ( list " Opcin 1" " Opcin 2" " etc .") ]
160
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
[ choices null ] [ callback ( lambda (c e ) ( when ( equal ? ( send e get - event - type ) ' text - field enter ) ( begin ( send c append ( send c get - value ) ) ( send mensaje set - label ( string - append " Texto agregado : '" ( send c get - value ) " '") ) ) ) )] )) ;; Panel 5 - Otros ------------------------ -------------------------------( define msg - otros1 ( new message % [ label " Slider :"] [ parent panel5 ]) ) ( define ( evento - slider s e ) ( send mensaje set - label ( string - append " Valor del slider '" ( send s get - label ) " ': " ( number - > string ( send s get - value ) ) ) ) ( if ( object =? s slider1 ) ( send gauge1 set - value ( send s get - value ) ) ( send gauge2 set - value ( send s get - value ) ) ) ) ( define slider1 ( new slider % [ label " Valor1 :"] [ parent panel5 ] [ min - value 0] [ max - value 100] [ init - value 30] [ callback evento - slider ] )) ( define slider2 ( new slider % [ label " Valor2 :"] [ parent panel5 ] [ min - value 0] [ max - value 100] [ style ( list ' vertical ' plain ) ] [ callback evento - slider ] )) ( define msg - otros2 ( new message % [ label " Gauge :"] [ parent panel5 ]) )
161
( define gauge1 ( new gauge % [ label " Gauge 1:"] [ parent panel5 ] [ range 100] )) ( send gauge1 set - value ( send slider1 get - value ) ) ( define gauge2 ( new gauge % [ label " Gauge 2:"] [ parent panel5 ] [ style '( vertical ) ] [ range 100] )) ( send gauge2 set - value ( send slider2 get - value ) ) ;; Panel 6 - Canvas -------------------------- -----------------------------( define canvas - hijo % ( class canvas % ( define / override ( on - event evento ) ( send mensaje set - label ( string - append " Evento de ratn en el Canvas : (" ( number - > string ( send evento get - x ) ) " ," ( number - > string ( send evento get - y ) ) ") " ) )) ( define / override ( on - char evento ) ( send mensaje set - label ( string - append " Evento de teclado en el Canvas : " ( let ([ t ( send evento get - key - code ) ]) ( if ( char ? t ) ( string t ) ( symbol - > string t ) ) ) ))) ( super - new ) )) ( define c ( new canvas - hijo % [ parent panel6 ] )) ;; Finalmente mostrar la ventana : ----------------------------------------( send ventana show # t )
162
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# lang racket ; canvas1 . rkt ( require racket / gui ) ( define ventana ( new frame % [ label " Ejemplo de dibujo en canvas "] [ width 400] [ height 400]) ) ; Objeto ' canvas %' ( define canvas ( new canvas % [ parent ventana ] [ paint - callback ( lambda ( c dc ) ; instancia de ' canvas %' y 'dc < %>' ( dibujar dc ) )]
163
)) ; Colores : ( define negro ( make - object color % 0 0 0) ) ; RGB ( define rojo ( make - object color % 255 0 0) ) ( define azul ( make - object color % 0 0 255) ) ( define amarillo ( make - object color % 255 255 0) ) ; Lpices y brochas ( define lpiz - negro - punteado ( make - object pen % negro 1 ' dot ) ) ; color grueso estilo ( define lpiz - rojo - slido ( make - object pen % rojo 2 ' solid ) ) ( define lpiz - azul - lneas ( make - object pen % azul 3 'long - dash ) ) ( define lpiz - negro - invertido ( make - object pen % negro 1 ' xor ) ) ( define lpiz - transparente ( make - object pen % negro 1 ' transparent ) ) ( define brocha - negra - slida ( make - object brush % negro ' solid ) ) ; color estilo ( define brocha - azul - invertida ( make - object brush % azul ' xor ) ) ( define brocha - amarilla - rallada ( make - object brush % amarillo ' bdiagonal hatch ) ) ( define brocha - transparente ( make - object brush % negro ' transparent ) ) ; Funcin de dibujo ( define ( dibujar dc ) ; recibe una instancia del ' drawing context ' ( send dc set - pen lpiz - negro - punteado ) ( send dc set - brush brocha - amarilla - rallada ) ( send dc draw - ellipse 50 50 200 200) ; x y ancho alto ( send dc set - pen lpiz - rojo - slido ) ( send dc set - brush brocha - azul - invertida ) ( send dc draw - rectangle 100 100 50 50) ; x y ancho alto ( send dc set - pen lpiz - azul - lneas ) ( send dc draw - arc 100 100 50 50 0.0 pi ) ; x y ancho alto rad - inicio rad fin ( send dc set - brush brocha - transparente ) ( send dc draw - arc 50 50 200 200 0.0 (/ pi 4) ) ( send ( send ( send ( send dc dc dc dc set - pen lpiz - negro - invertido ) draw - line 0 0 400 400) ; x1 y1 x2 y2 set - pen lpiz - negro - punteado ) draw - line 0 400 400 0)
( send dc set - text - background negro ) ; color ( send dc set - text - foreground azul ) ; color ( send dc draw - text " Hola cmo ests ?" 200 200) ; texto x y ( send dc draw - text " Otro texto con " 100 300 # f 0 (/ pi 4) ) ; texto x y combinar ? despl ngulo ( send dc set - text - mode ' solid ) ; el otro es ' transparent ( send dc set - text - foreground amarillo )
164
( send dc draw - text " Con fondo " 300 300) ( send dc set - pen lpiz - azul - lneas ) ( send dc draw - spline 0 400 200 200 400 400) ( send dc set - pen lpiz - negro - punteado ) ( send dc set - brush brocha - amarilla - rallada ) ( let ([ puntos ( list ( make - object point % 0 0) ( make - object point % 50 0) ( make - object point % 25 50) ) ]) ( send dc draw - lines puntos 340 50) ; puntos [ x y ] ( send dc draw - polygon puntos 340 150) ; puntos [ x y estilo ] ) ) ( send ventana show # t )
1 2 3 4
165
( define ventana ( new frame % [ label " Ejemplo de eventos en canvas "] [ width 400] [ height 400]) ) ( define canvas - hijo2 % ( class canvas % ( super - new ) ( define primer - punto ( make - object point % 0 0) ) ( define / override ( on - event evento ) ( when ( send evento button - down ? ' left ) ( send primer - punto set - x ( send evento get - x) ) ( send primer - punto set - y ( send evento get - y) ) ) ( when ( send evento button - up ? ' left ) ( send ( send this get - dc ) draw - line ( send primer - punto get - x ) ( send primer - punto get - y ) ( send evento get - x ) ( send evento get - y ) ) ) ( when ( and ( send evento dragging ?) ( send evento get - right - down ) ) ( send ( send this get - dc ) draw - point ( send evento get - x ) ( send evento get - y ) ) ) ) )) ( define c2 ( new canvas - hijo2 % [ parent ventana ] [ style '( border ) ] )) ( define mensaje ( new message % [ parent ventana ] [ label " Arrastre con clic izquierdo y luego con derecho "] )) ( send ventana show # t )
A continuacin se implementa el mismo cdigo, pero con memoria:
1 2 3 4 5 6 7
# lang racket ; canvas3 . rkt ( require racket / gui ) ( define ventana ( new frame % [ label " Ejemplo de canvas con memoria "]
166
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
[ width 400] [ height 400]) ) ;; Tcnica de doble buffer : ( define bitmap - de - buffer ( make - object bitmap % 400 400) ) ( define dc ( make - object bitmap - dc % bitmap - de - buffer ) ) ( send dc clear ) ; Esto inicializa el bitmap ( define canvas - hijo2 % ( class canvas % ( super - new ) ( define primer - punto ( make - object point % 0 0) ) ( define / override ( on - event evento ) ( when ( send evento button - down ? ' left ) ( send primer - punto set - x ( send evento get - x) ) ( send primer - punto set - y ( send evento get - y) ) ) ( when ( send evento button - up ? ' left ) ( send dc draw - line ( send primer - punto get - x ) ( send primer - punto get - y ) ( send evento get - x ) ( send evento get - y ) ) ; Forzar el redibujado en este momento ( send this refresh )
167
))
) ( when ( and ( send evento dragging ?) ( send evento get - right - down ) ) ( send dc draw - point ( send evento get - x ) ( send evento get - y )) ; Forzar el redibujado en este momento ( send this refresh ) ) )
( define c2 ( new canvas - hijo2 % [ parent ventana ] [ style '( border ) ] [ paint - callback ( lambda (c dc - canvas ) ; Dibuja el bitmap en el dc - canvas : ( send dc - canvas draw - bitmap bitmap - de - buffer 0 0) )] )) ( define mensaje ( new message % [ parent ventana ] [ label " Arrastre con clic izquierdo y luego con derecho "] )) ( send ventana show # t )
Ahora un ejemplo similar, pero con refresco automtico y con memoria:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# lang racket ; canvas4 . rkt ( require racket / gui ) ;; Tcnica de doble buffer : ( define bitmap - de - buffer ( make - object bitmap % 400 400) ) ( define dc ( make - object bitmap - dc % bitmap - de - buffer ) ) ( send dc clear ) ; Esto inicializa el bitmap ; Lpices : ( define negro ( make - object color % 0 0 0) ) ( define lpiz - negro - slido ( make - object pen % negro 2 ' solid ) ) ( define lpiz - negro - invertido ( make - object pen % negro 2 ' xor ) ) ( send dc set - pen lpiz - negro - slido ) ( define canvas - hijo2 % ( class canvas % ( super - new ) ( define punto - ini - recta ( make - object point % 0 0) ) ( define punto - ant - recta ( make - object point % 0 0) )
168
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
( define punto - ant - lpiz ( make - object point % 0 0) ) ( define / override ( on - event evento ) ; BOTN DERECHO ( when ( send evento button - down ? ' right ) ( send punto - ant - lpiz set - x ( send evento get - x ) ) ( send punto - ant - lpiz set - y ( send evento get - y ) ) ) ( when ( and ( send evento dragging ?) ( send evento get - right - down ) ) ( send dc draw - line ( send punto - ant - lpiz get - x ) ( send punto - ant - lpiz get - y ) ( send evento get - x ) ( send evento get - y ) ) ( send punto - ant - lpiz set - x ( send evento get - x ) ) ( send punto - ant - lpiz set - y ( send evento get - y ) ) ( send this refresh ) ) ; BOTN IZQUIERDO ( when ( send evento button - down ? ' left ) ( send punto - ini - recta set - x ( send evento get - x ) ) ( send punto - ini - recta set - y ( send evento get - y ) ) ( send punto - ant - recta set - x ( send evento get - x ) ) ( send punto - ant - recta set - y ( send evento get - y ) ) ) ( when ( and ( send evento dragging ?)
169
))
( send evento get - left - down ) ) ( send dc set - pen lpiz - negro - invertido ) ( send dc draw - line ( send punto - ini - recta get - x ) ( send punto - ini - recta get - y ) ( send punto - ant - recta get - x ) ( send punto - ant - recta get - y ) ) ( send punto - ant - recta set - x ( send evento get - x ) ) ( send punto - ant - recta set - y ( send evento get - y ) ) ( send dc draw - line ( send punto - ini - recta get - x ) ( send punto - ini - recta get - y ) ( send punto - ant - recta get - x ) ( send punto - ant - recta get - y ) ) ( send dc set - pen lpiz - negro - slido ) ( send this refresh ) ) ( when ( send evento button - up ? ' left ) ( send dc draw - line ( send punto - ini - recta get - x ) ( send punto - ini - recta get - y ) ( send evento get - x ) ( send evento get - y ) ) ; Forzar el redibujado en este momento ( send this refresh ) ) )
( define ventana ( new frame % [ label " Ejemplo de canvas con efectos "] [ width 400] [ height 400]) ) ( define c2 ( new canvas - hijo2 % [ parent ventana ] [ style '( border ) ] [ paint - callback ( lambda (c dc - canvas ) ; Dibuja el bitmap en el dc - canvas : ( send dc - canvas draw - bitmap bitmap - de - buffer 0 0) )] )) ( define mensaje ( new message % [ parent ventana ] [ label " Arrastre con clic izquierdo y luego con derecho "] )) ( send ventana show # t )
170
22 Mens
En la gura 22.1 se muestra el diagrama de clases de las clases relacionadas con mens en Racket. En la gura 22.2 se ilustra el diagrama de objetos de los mens implementados en el archivo
1-mens.rkt.
1 2 3 4 5 6 7
# lang racket ;1 - mens . rkt ( require racket / gui ) ( define ventana ( new frame % [ label " Ejemplo de Mens "]) ) ( define barra - menu ( new menu - bar % [ parent ventana ] ;[ demand - callback ( lambda ( bm ) ( printf " evento \ n ") ) ]
171
22 Mens
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
)) ( define txt - texto ( new text - field % [ label # f] [ parent ventana ] [ style '( multiple ) ] )) ( send txt - texto min - width 600) ( send txt - texto min - height 600) ( define mnu - archivo ( new menu % [ label "& Archivo "] [ parent barra - menu ]) ) ( define mnu - nuevo ( new menu - item % [ parent mnu - archivo ] [ label "& Nuevo "] [ shortcut #\ n ] [ callback ( lambda ( m c ) ( send txt - texto set - value "") )]
172
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
)) ( define no - hacer - nada ( lambda ( m c ) ( void ) )) ( define mnu - abrir ( new menu - item % [ parent mnu - archivo ] [ label "& Abrir ..."] [ shortcut #\ a ] [ callback no - hacer - nada ] )) ( define mnu - guardar ( new menu - item % [ parent mnu - archivo ] [ label "& Guardar ..."] [ shortcut #\ g ] [ callback no - hacer - nada ] )) ( define mnu - sep ( new separator - menu - item % [ parent mnu - archivo ]) ) ( define mnu - salir ( new menu - item % [ parent mnu - archivo ] [ label "& Salir "] [ shortcut #\ s ] [ callback ( lambda ( m c )
173
22 Mens
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
))
( define mnu - otro ( new menu % [ label " Otro men "][ parent barra - menu ]) ) ( define mnu - submen ( new menu % [ label " Submen "][ parent mnu - otro ]) ) ( define mnu - elemento1 ( new menu - item % [ parent mnu - submen ] [ label " Este es el primer subelemento "] [ callback no - hacer - nada ] )) ( define mnu - elemento2 ( new menu - item % [ parent mnu - submen ] [ label " Este es el segundo subelemento "] [ callback no - hacer - nada ] )) ( define mnu - seleccin ( new checkable - menu - item % [ label " Chequame "] [ parent mnu - otro ] [ callback no - hacer - nada ] )) ( define mnu - mostrar - estado ( new menu - item % [ label " Mostrar valor de ' Chequame '"] [ parent mnu - otro ] [ callback ( lambda ( m c ) ( message - box " Ejemplo de ' message - box '" ( format " El valor del men ' Chequame ' es ~ a" ( send mnu - seleccin is - checked ?) ) ) )] )) ( send ventana show # t )
# lang racket ;3 - auxiliar . rkt ( require racket / gui ) ( provide abrir - archivo guardar - archivo ) ( define ( abrir - archivo msg par ) ( define ruta ( get - file msg par # f # f " txt " null '( (" Archivos de texto " "*. txt ") (" Todos " "*.*") ) ) ) ( if ruta ( path - > string ruta ) #f
174
( define ( guardar - archivo msg par ) ( define ruta ( put - file msg par # f # f " txt " null '( (" Archivos de texto " "*. txt ") (" Todos " "*.*") ) ) ) ( if ruta ( path - > string ruta ) #f ) )
1 2 3 4 5 6 7 8 9 10
# lang racket ;2 - mens . rkt ( require racket / gui ) ( require "3 - auxiliar . rkt ") ( define ventana ( new frame % [ label " Ejemplo de Mens y dilogos bsicos "]) ) ( define barra - menu ( new menu - bar % [ parent ventana ] )) ( define txt - texto ( new text - field % [ label # f]
175
22 Mens
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
[ parent ventana ] [ style '( multiple ) ] )) ( send txt - texto min - width 600) ( send txt - texto min - height 600) ( define mnu - archivo ( new menu % [ label "& Archivo "] [ parent barra - menu ]) ) ( define mnu - nuevo ( new menu - item % [ parent mnu - archivo ] [ label "& Nuevo "] [ shortcut #\ n ] [ callback ( lambda ( m c ) ( send txt - texto set - value "") )] )) ( define no - hacer - nada ( lambda ( m c ) ( void ) )) ( define mnu - abrir ( new menu - item % [ parent mnu - archivo ] [ label "& Abrir ..."] [ shortcut #\ a ] [ callback ( lambda ( m c ) ( let ([ nombre - archivo ( abrir - archivo " Abrir archivo ..." ventana ) ]) ( when nombre - archivo ( call - with - input - file nombre - archivo ( lambda ( f) ( define ( aux f ) ( let ([ cadena ( read - string 1000 f ) ]) ( unless ( eof - object ? cadena ) ( send txt - texto set - value ( string - append ( send txt texto get - value ) cadena ) ) ) ) ) ( send txt - texto set - value "") ( aux f ) ) ) ) ) )] )) ( define mnu - guardar ( new menu - item % [ parent mnu - archivo ]
176
[ label "& Guardar ..."] [ shortcut #\ g ] [ callback ( lambda ( m c ) ( let ([ nombre - archivo ( guardar - archivo " Guardar archivo ..." ventana ) ]) ( if nombre - archivo ( call - with - output - file nombre - archivo ( lambda ( f) ( display ( send txt - texto get - value ) f ) ) ) ( message - box " Error " " No se seleccion ningn archivo " ventana ) ) ) )] )) ( define mnu - sep ( new separator - menu - item % [ parent mnu - archivo ]) ) ( define mnu - salir ( new menu - item % [ parent mnu - archivo ] [ label "& Salir "] [ shortcut #\ s ] [ callback ( lambda ( m c ) ( send ventana show # f ) )] )) ( send ventana show # t )
# lang racket ;4 - mens - contextuales . rkt ( require racket / gui ) ( define ventana ( new frame % [ label " Ejemplo de Mens Contextuales "]) ) ( define brocha ( make - object brush % ( make - object color % 0 0 255) ' solid ) ) ( define mi - canvas % ( class canvas % ( super - new ) ( define / override ( on - event evento ) ; BOTN DERECHO ( when ( send evento button - down ? ' right ) ( send this popup - menu men ( send evento get - x ) ( send evento get - y ) )
177
22 Mens
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
)) ( define canvas ( new mi - canvas % [ parent ventana ] [ paint - callback ( lambda (c dc ) ( define - values ( ancho alto ) ( send dc get - size ) ) ( send dc set - brush brocha ) ( send dc draw - rectangle 0 0 ancho alto ) )] )) ( send ventana min - width 600) ( send ventana min - height 600) ( define ( imprime - men m c ) ( printf " Opcin seleccionada : '~a '\ n " ( send m get - label ) ) ) ( define men ( new popup - menu % ) ) ( define opcin1 ( new menu - item % [ parent men ] [ label " Opcin 1"] [ callback imprime - men ] )) ( define opcin2 ( new menu - item % [ parent men ] [ label " Opcin 2"] [ callback imprime - men ] )) ( define opcin3 ( new menu - item % [ parent men ] [ label " Opcin 3"] [ callback imprime - men ] )) ( send ventana show # t )
Otro ejemplo con mens contextuales:
1 2 3 4 5 6 7 8 9
# lang racket ;5 - seleccin - color . rkt ( require racket / gui ) ;; Tcnica de doble buffer : ( define bitmap - de - buffer ( make - object bitmap % 400 400) ) ( define dc ( make - object bitmap - dc % bitmap - de - buffer ) )
178
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
( send dc clear ) ; Esto inicializa el bitmap ; Lpices : ( define negro ( make - object color % 0 0 0) ) ( define lpiz - slido ( make - object pen % negro 2 ' solid )) ( define lpiz - invertido ( make - object pen % negro 2 ' xor ) ) ( send dc set - pen lpiz - slido ) ( define canvas - hijo2 % ( class canvas % ( super - new ) ( define punto - ant - lpiz ( make - object point % 0 0) ) ( define / override ( on - event evento ) ; BOTN DERECHO ( when ( send evento button - down ? ' right ) ( send this popup - menu men ( send evento get - x ) ( send evento get - y ) ) ) ; BOTN IZQUIERDO ( when ( send evento button - down ? ' left ) ( send punto - ant - lpiz set - x ( send evento get - x ) ) ( send punto - ant - lpiz set - y ( send evento get - y ) ) ) ( when ( and ( send evento dragging ?) ( send evento get - left - down ) ) ( send dc draw - line ( send punto - ant - lpiz get - x ) ( send punto - ant - lpiz get - y ) ( send evento get - x ) ( send evento get - y )
179
22 Mens
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
))
) ( send punto - ant - lpiz set - x ( send evento get - x ) ) ( send punto - ant - lpiz set - y ( send evento get - y ) ) ( send this refresh ) )
( define ventana ( new frame % [ label " Ejemplo de canvas con efectos "] [ width 400] [ height 400]) ) ( define c2 ( new canvas - hijo2 % [ parent ventana ] ;[ style '( border ) ] [ paint - callback ( lambda (c dc - canvas ) ; Dibuja el bitmap en el dc - canvas : ( send dc - canvas draw - bitmap bitmap - de - buffer 0 0) )] )) ( define mensaje ( new message % [ parent ventana ] [ label " Arrastre con clic izquierdo y luego haga clic derecho "] )) ( define men ( new popup - menu % ) )
180
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
( define opcin0 ( new menu - item % [ parent men ] [ label " Negro "] [ callback ( lambda ( m c ) ( send dc set - pen lpiz - invertido ) ( send lpiz - slido set - color ( make - object color % 0 0 0) ) ( send dc set - pen lpiz - slido ) )] )) ( define opcin1 ( new menu - item % [ parent men ] [ label " Rojo "] [ callback ( lambda ( m c ) ( send dc set - pen lpiz - invertido ) ( send lpiz - slido set - color ( make - object color % 255 0 0) ) ( send dc set - pen lpiz - slido ) )] )) ( define opcin2 ( new menu - item % [ parent men ] [ label " Verde "] [ callback ( lambda ( m c ) ( send dc set - pen lpiz - invertido ) ( send lpiz - slido set - color ( make - object color % 0 255 0) )
181
22 Mens
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
)) ( define opcin3 ( new menu - item % [ parent men ] [ label " Azul "] [ callback ( lambda ( m c ) ( send dc set - pen lpiz - invertido ) ( send lpiz - slido set - color ( make - object color % 0 0 255) ) ( send dc set - pen lpiz - slido ) )] )) ( define opcin4 ( new menu - item % [ parent men ] [ label " Otro ..."] [ callback ( lambda ( m c ) ( send dc set - pen lpiz - invertido ) ;( send lpiz - slido set - color ( make - object color % 0 0 255) ) ( let ([ nuevo - color ( get - color - from - user " Elija un color " ventana ( send lpiz - slido get - color ) ) ]) ( when nuevo - color ( send lpiz - slido set - color nuevo - color ) ) ) ( send dc set - pen lpiz - slido ) )] )) ( send ventana show # t )
182
23 Proyecto: Minipaint
1 2 3 4 5 6
# lang racket ; mini - paint . rkt ( require racket / gui ) ( define ANCHO 600)
183
23 Proyecto: Minipaint
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
( define ALTO 600) ( define lista - de - formas ( list ' libre ' lnea ' rectngulo ) ) ( define forma ( list - ref lista - de - formas 0) ) ( define nombre - del - archivo #f ) ( define modificado ? # f ) ;; Tcnica de doble buffer : ( define bitmap - de - buffer ( make - object bitmap % ANCHO ALTO ) ) ( define dc ( make - object bitmap - dc % bitmap - de - buffer ) ) ( send dc clear ) ; Inicializar el bitmap ; Lpices y brocha : ( define color - slido ( make - object color % 0 0 0) ) ( define lpiz - slido ( make - object pen % color - slido 2 ' solid ) ) ( define lpiz - invertido ( make - object pen % color - slido 2 ' xor ) ) ( define brocha ( make - object brush % color - slido ' transparent ) ) ( send dc set - pen lpiz - slido ) ( send dc set - brush brocha ) ( define ( menor -y - diferencia - absoluta a b ) ( values ( min a b ) ( abs ( - a b ) ) ) ) ( define canvas - hijo % ( class canvas % ( super - new ) ( define punto - inicial ( make - object point % 0 0) ) ; Punto sobre el que hizo clic al principio . ( define punto - anterior ( make - object point % 0 0) ) ; Punto anterior donde estuvo el ratn . ( define rect - x 0) ( define rect - y 0) ( define rect - ancho 0) ( define rect - alto 0) ( define ( actualizar - rectngulo ) #| Actualiza los valores de rect -x , rect -y , rect - ancho y rect - alto en funcin de los puntos punto - inicial y punto - anterior .|# ( set ! - values ( rect - x rect - ancho ) ( menor -y - diferencia - absoluta ( send punto - inicial get - x ) ( send punto - anterior get - x ) ) ) ( set ! - values ( rect - y rect - alto )
184
( menor -y - diferencia - absoluta ( send punto - inicial get - y ) ( send punto - anterior get - y ) ) )
( define / override ( on - event evento ) ;; Forma libre : ( when ( equal ? forma ' libre ) ( when ( send evento button - down ? ' left ) ( send punto - anterior set - x ( send evento get - x ) ) ( send punto - anterior set - y ( send evento get - y ) ) ( set ! modificado ? # t ) ) ( when ( and ( send evento dragging ?) ( send evento get - left - down ) ) ( send dc draw - line ( send punto - anterior get - x ) ( send punto - anterior get - y ) ( send evento get - x ) ( send evento get - y ) ) ( send punto - anterior set - x ( send evento get - x )) ( send punto - anterior set - y ( send evento get - y )) ( send this refresh ) ) ) ;; Lnea : ( when ( equal ? forma ' lnea ) ( when ( send evento button - down ? ' left ) ( send punto - inicial set - x ( send evento get - x )) ( send punto - inicial set - y ( send evento get - y )) ( send punto - anterior set - x ( send evento get - x) ) ( send punto - anterior set - y ( send evento get - y) ) ( send dc set - pen lpiz - invertido ) ( set ! modificado ? # t ) ) ( when ( and ( send evento dragging ?) ( send evento get - left - down ) ) ( send dc draw - line ( send punto - inicial get - x ) ( send punto - inicial get - y ) ( send punto - anterior get - x ) ( send punto - anterior get - y ) ) ( send punto - anterior set - x ( send evento get - x) ) ( send punto - anterior set - y ( send evento get - y) ) ( send dc draw - line ( send punto - inicial get - x ) ( send punto - inicial get - y ) ( send punto - anterior get - x ) ( send punto - anterior get - y ) ) ( send this refresh ) ) ( when ( send evento button - up ? ' left ) ( send dc set - pen lpiz - slido )
185
23 Proyecto: Minipaint
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
) ;; Rectngulo : ( when ( equal ? forma ' rectngulo ) ( when ( send evento button - down ? ' left ) ( send punto - inicial set - x ( send evento get -x ) ) ( send punto - inicial set - y ( send evento get -y ) ) ( send punto - anterior set - x ( send evento get - x ) ) ( send punto - anterior set - y ( send evento get - y ) ) ( set ! rect - x ( send evento get - x ) ) ( set ! rect - y ( send evento get - x ) ) ( set ! rect - ancho 0) ( set ! rect - alto 0) ( send dc set - pen lpiz - invertido ) ( set ! modificado ? # t ) ) ( when ( and ( send evento dragging ?) ( send evento get - left - down ) ) ( send dc draw - rectangle rect - x rect - y rect - ancho rect - alto ) ( send punto - anterior set - x ( send evento get - x ) ) ( send punto - anterior set - y ( send evento get - y ) ) ( actualizar - rectngulo ) ( send dc draw - rectangle rect - x rect - y rect - ancho rect - alto ) ( send this refresh ) ) ( when ( send evento button - up ? ' left ) ( send dc set - pen lpiz - slido ) ( send punto - anterior set - x ( send evento get - x ) ) ( send punto - anterior set - y ( send evento get - y ) ) ( actualizar - rectngulo ) ( send dc draw - rectangle rect - x rect - y rect - ancho rect - alto ) ; Forzar el redibujado en este momento ( send this refresh ) )
( send dc draw - line ( send punto - inicial get - x ) ( send punto - inicial get - y ) ( send evento get - x ) ( send evento get - y ) ) ; Forzar el redibujado en este momento ( send this refresh ) )
))
186
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
( class frame % ( super - new ) ( define / augment ( on - close ) ( send mnu - salir command ( new control - event % [ event - type ' menu ]) ) ) )) ( define ventana ( new frame - hijo % [ label " Mini - paint "] [ stretchable - width # f ] [ stretchable - height # f ] )) ( define mi - canvas ( new canvas - hijo % [ parent ventana ] [ min - width ANCHO ] [ min - height ALTO ] [ style '(no - focus ) ] [ paint - callback ( lambda ( c dc - canvas ) ; Dibuja el bitmap en el dc - canvas : ( send dc - canvas draw - bitmap bitmap - de - buffer 0 0) )] )) ( define panel ( new horizontal - panel % [ parent ventana ]) ) ( define radio - forma ( new radio - box % [ label " Seleccione forma de dibujo :"] [ parent panel ] [ choices ( list " Forma libre " " Lnea " " Rectngulo ") ] [ callback ( lambda ( r c ) ( set ! forma ( list - ref lista -de - formas ( send r get - selection ) ) ) )] [ style ( list ' vertical ' vertical - label ) ] )) ( define radio - color ( new radio - box % [ label " Seleccione el color :"] [ parent panel ] [ choices ( list " Negro " " Blanco " " Rojo " " Verde " " Azul " " Otro ...") ] [ callback ( lambda ( r c ) ( send dc set - pen lpiz - invertido ) ( send lpiz - slido set - color ( case ( send r get - selection ) [(0) ( make - object color % 0 0 0) ] [(1) ( make - object color % 255 255 255) ] [(2) ( make - object color % 255 0 0) ] [(3) ( make - object color % 0 255 0) ]
187
23 Proyecto: Minipaint
206 207 208 209
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
) ( send dc set - pen lpiz - slido ) ( send lpiz - invertido set - color ( send lpiz slido get - color ) ) )] [ style ( list ' vertical ' vertical - label ) ] ))
[(4) ( make - object color % 0 0 255) ] [(5) ( let ([ nuevo - color ( get - color - from - user " Elija un color " ventana ( send lpiz slido get - color ) ) ]) ( if nuevo - color nuevo - color ( send lpiz - slido get - color ) ) ) ] )
( define barra - grueso ( new slider % [ label " Grueso de la lnea :"] [ parent panel ] [ min - value 1] [ max - value 50] [ init - value 2] [ callback ( lambda ( s e ) ( send lpiz - invertido set - width ( send s get - value ) ) ( send dc set - pen lpiz - invertido ) ( send lpiz - slido set - width ( send s get - value ) ) ( send dc set - pen lpiz - slido ) )] )) ( define filtro '( (" Archivos de imagen PNG " "*. png ") (" Todos " "*.*") ) ) ( define ( abrir - archivo msg par ) ( define ruta ( get - file msg par # f # f " png " null filtro ) ) ( if ruta ( path - > string ruta ) #f ) ) ( define ( guardar - archivo msg par ) ( define ruta ( put - file msg par # f # f " png " null filtro ) ) ( if ruta ( path - > string ruta ) #f ) )
188
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
( define barra - menu ( new menu - bar % [ parent ventana ]) ) ( define mnu - archivo ( new menu % [ label "& Archivo "] [ parent barra - menu ]) ) ( define mnu - nuevo ( new menu - item % [ parent mnu - archivo ] [ label "& Nuevo "] [ shortcut #\ n ] [ callback ( lambda ( m c ) ( send dc clear ) ( send mi - canvas refresh ) ( set ! nombre - del - archivo # f ) )] )) ( define mnu - abrir ( new menu - item % [ parent mnu - archivo ] [ label "& Abrir ..."] [ shortcut #\ a ] [ callback ( lambda ( m c ) ( when ( or ( not modificado ?) ( equal ? 1 ( message - box / custom " Advertencia " " Si abre un nuevo archivo perder los cambios realizados " " Abrir archivo " " Cancelar " #f ventana '( caution disallow - close default =2) ))) ( let ([ nombre - archivo ( abrir - archivo " Abrir imagen ..." ventana ) ]) ( when nombre - archivo ( let ([ nuevo - buffer ( make - object bitmap % 1 1) ]) ( send dc set - pen " black " 1 ' solid ) ; desligando el lpiz - slido ( send dc set - brush " black " ' solid ) ; desligando la brocha ( send nuevo - buffer load - file nombre archivo ) ; abrir archivo ( set ! dc ( make - object bitmap - dc % nuevo buffer ) ) ; nuevo dc ( set ! bitmap - de - buffer nuevo - buffer ) ; usar el nuevo ( send dc set - pen lpiz - slido ) ; configurar el lpiz
189
23 Proyecto: Minipaint
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
))
)]
( send dc set - brush brocha ) ; configurar la brocha ) ( set ! nombre - del - archivo nombre - archivo ) ( set ! modificado ? # f ) ( send mi - canvas refresh ) )
324 325 326 327 328 329 330 331 332 333 334 335 336
( define mnu - guardar ( new menu - item % [ parent mnu - archivo ] [ label "& Guardar ..."] [ shortcut #\ g ] [ callback ( lambda ( m c ) ( when modificado ? ( if nombre - del - archivo ( begin ( send bitmap - de - buffer save - file nombre - del - archivo ' png ) ( set ! modificado ? # f ) ) ( let ([ nombre - archivo ( guardar - archivo " Guardar archivo ..." ventana ) ]) ( if nombre - archivo ( begin ( send bitmap - de - buffer save - file nombre - archivo ' png ) ( set ! modificado ? # f ) ( set ! nombre - del - archivo nombre archivo ) ) ( message - box " Error " " No se seleccion ningn nombre " ventana ) ) ) ) ) )] )) ( define mnu - sep ( new separator - menu - item % [ parent mnu - archivo ]) ) ( define mnu - salir ( new menu - item % [ parent mnu - archivo ] [ label "& Salir "] [ shortcut #\ s ] [ callback
190
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
( lambda ( m c ) ( when ( and modificado ? ( equal ? 1 ( message - box / custom " Advertencia " " No ha guardado el archivo actual " " Guardar archivo " " No guardar " #f ventana '( caution disallow - close default =1) ))) ( if nombre - del - archivo ( send bitmap - de - buffer save - file nombre - del - archivo ' png ) ( let ([ nombre - archivo ( guardar - archivo " Guardar archivo ..." ventana ) ]) ( if nombre - archivo ( send bitmap - de - buffer save - file nombre - archivo ' png ) ( void ) ) ) ) ) ( send ventana show # f ) )] )) ( send ventana show # t )
191
23 Proyecto: Minipaint
192
193
23 Proyecto: Minipaint
inicialmente tendr un rea de texto vaca donde se pueda escribir, al presionar el men archivo y la opcin de nuevo, el contenido del rea de texto se borrar, dejando limpia el rea de texto, si se presiona la opcin abrir, se abrir un cuadro de dialogo para poder buscar y seleccionar una archivo de texto, luego al seleccionar y abrir el archivo seleccionado, la informacin se cargar en el rea de texto, para poder editarse, si se desea o si slo se desea ver el contenido. Si se elige la opcin de guardar se abrir un cuadro de dialogo para poder guardar el archivo en un lugar del disco duro, donde se desee. Y al presionar la opcin de salir, el programa terminar. 6. Elaborar un programa que muestre una ventana que contenga un list-box de 5 elementos (elementos de su eleccin) y un botn seleccionar , cuando se d clic a dicho botn, deber aparecer una ventana emergente con el elemento seleccionado al centro de la ventana y un botn salir que permitir cerrar la ventana emergente. 7. Realizar un programa que muestre una ventana cuyo ttulo ser "formulario" en esta se presentar un formulario donde el usuario ingresar los siguientes datos:
a) b) c) d)
- Nombre (text-eld) - edad (combo-box edad mxima 90 aos) - sexo (radio-button M F) - botn nalizar El botn nalizar cerrar la ventana "formulario" y abrir la ventana "revisado" donde mostrar los datos ingresados por el usuario, esta ventana presentar dos botones "guardar" y "salir". "guardar": Los datos sern guardados en un archivo. "salir": cerrar el programa en caso de no guardar enviar un mensaje que indique "datos no almacenados".
8. Realizar un programa que muestre la ventana cuyo ttulo ser "pases" esta presentar un list-box que contendr una lista de pases almacenados en el archivo "pases.txt" y presentar dos botones "eliminar" "salir". "eliminar": eliminar el pas seleccionado de la lista y del archivo. "salir" : cerrar la ventana. 9. Realizar un programa que muestre una ventana cuyo ttulo ser "Seleccionar ao", esta ventana presentar un slider que tendr una lista de aos desde el ao 1900 hasta el ao 3000 y un botn "seleccionar", al dar clic al botn "seleccionar" aparecer una ventana cuyo ttulo ser el ao seleccionado, esta ventana contendr dos text-eld "nombre" y "suceso" en donde se almacenar el nombre de la persona que digita la informacin y el suceso ocurrido en el ao seleccionado nalmente la ventana presentar el botn "guardar" lo cual permitir almacenar la informacin en un archivo. Nota la ventana "seleccionar ao" no debe cerrarse sino simplemente quedar inactiva mientras se ingresan los datos en la segunda ventana, al momento de guardar la in-
194
formacin, la ventana emergente se cerrar y se podr utilizar la ventana "seleccionar ao" nuevamente.
195
23 Proyecto: Minipaint
196
Parte V
Apndices
197
Racket
es el nuevo nombre de
PLT Scheme,
signica que Racket 5.0 equivale a PLT Scheme 5.0. 2. Las extensiones tradicionales de PLT Scheme son preeren las extensiones
.rkt.
.ss
.scm.
3. El lenguaje principal del intrprete de PLT Scheme se llama comenzar con la lnea:
scheme
y no
racket
como en Racket. Por ello, la primera lnea de los programas de PLT Scheme deben
en lugar de
#lang racket
drscheme
mzscheme
en lugar de
6. El intrprete de los programas Racket con Interfaz Grca de Usuario en versiones anteriores a la 5.0 es
mred
gracket. mzc
en lugar de
raco:
scheme/gui.
199
200
Bibliografa
[1] http://docs.racket-lang.org/ (2009-2010) -
Sitio de documentacin ocial de Racket, por How to Design Programs (An Introduction to
Computing and Programming), por Matthias Felleisen, Robert Bruce Findler, Matthew
Flatt, Shriram Krishnamurthi. The MIT Press, Massachusetts Institute of Technology.
201