Vous êtes sur la page 1sur 201

Departamento de Electrnica e Informtica, Universidad Centroamericana Jos Simen Caas

Programando con Racket 5


por

Eduardo NAVAS
versin 1.0 2010.07.21

Este libro fue desarrollado nicamente con software libre. Entre las herramientas usadas,

AT X, L X, GNU/Linux, GNOME, KDE, KmPlot, GIMP, Python, etc. se encuentran: L E Y

CC-BY-NC-SA
Este es un libro libre con la licencia

Creative Commons Attribution-Noncommercial-Share Alike 3.0.


Los detalles pueden ser consultados en: http://creativecommons.org/licenses/by-nc-sa/3.0/deed.es La versin digital y el material adicional puede ser descargado de: www.aliamondano-eo.wikidot.com/racket-5 http://dei.uca.edu.sv/publicaciones/ ISBN: 978-99923-73-61-3 Editado y preparado desde el

Departamento de Electrnica e Infomtica


El Salvador, Centroamrica.

de la

Universidad Centroamericana Jos Simen Caas,

Dedico esta obra al egosmo

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

PLT Scheme, un sistema de programacin de larga tradicin

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

Ejemplos de cdigo de lenguajes funcionales . . . . . . . . . . . . . . . . . .

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

3. Expresiones Racket - Notacin Preja


3.1. 3.2. Notacin para la sintaxis de Racket . . . . . . . . . . . . . . . . . . . . . . . Notacin preja de Racket . . . . . . . . . . . . . . . . . . . . . . . . . . . .

27
27 27

4. Interaccin con Racket


4.1. Ejecucin interactiva . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1. 4.1.2. 4.2. 4.2.1. Deniciones e interacciones con DrRacket Ejecucin interactiva con Racket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29
29 30 30 31 31

Ejecucin no interactiva

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Parmetros de la lnea de comandos

5. Compilacin de programas Racket


5.1. 5.2. Lo bsico sobre compilacin . . . . . . . . . . . . . . . . . . . . . . . . . . . Compilacin con mltiples mdulos . . . . . . . . . . . . . . . . . . . . . . .

33
33 33

II. Introduccin al lenguaje Racket


6. Elementos bsicos
6.1. Comentarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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

Llamadas a funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Bloques condicionales 6.4.1. 6.4.2. 6.4.3. 6.4.4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

if . . . and y or cond . . case . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6.5. 6.6.

Bloques de cdigo secuencial . . . . . . . . . . . . . . . . . . . . . . . . . . . Ms sobre llamadas a funciones . . . . . . . . . . . . . . . . . . . . . . . . .

7. Funciones annimas - Bloques lambda


7.1. 7.2. Bloques

lambda

45
45 46 . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Funciones/Expresiones que producen funciones

8. Asignacin local
8.1. 8.2. 8.3.

define let . . let* .

49
49 50 50

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

III. Elementos del lenguaje


9. Listas e Iteracin
9.1. Listas 9.1.1. 9.1.2. 9.2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lista vaca o nula . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Funciones bsicas sobre listas . . . . . . . . . . . . . . . . . . . . . .

51
53
53 54 54 56 56 56 57 58 59 59 60 61 62 62

Iteracin automtica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.2.1. 9.2.2. 9.2.3. 9.2.4. 9.2.5.

map . . . . . . . andmap y ormap filter . . . . . for-each . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Versiones generales de las funciones de iteracin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9.3.

Iteracin manual 9.3.1.

Aplicacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9.4.

Pares y listas 9.4.1. 9.4.2.

Convencin de impresin . . . . . . . . . . . . . . . . . . . . . . . . . Notacin inja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10.Recursin
10.1. Recursin por Posposicin de trabajo . . . . . . . . . . . . . . . . . . . . . . 10.2. Recursin de Cola . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

67
67 67

10

ndice general

11.Tipos de dato integrados del lenguaje


11.1. Booleanos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2. Nmeros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2.1. Clasicacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Clasicacin por Exactitud Clasicacin por Conjuntos 11.2.2. Otras bases 11.2.3. Comparaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

12.Expresiones y Deniciones Avanzadas


12.1. La funcin 12.2. Bloques

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 . . . . . . . . . . . . . . . . .

arity-at-least . . . . . . . procedure-arity . . . . . . . procedure-arity-includes?


12.3.1. 12.3.2. 12.3.3.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

12.3. Resultados mltiples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

values . . . . . . . . . . . . define-values . . . . . . . let-values, y let*-values

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

12.4. Asignaciones

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13.Tipos de dato denidos por el programador


13.1. Estructuras simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

101
101

11

ndice general
13.2. Estructuras derivadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 104 104

13.3. Estructuras transparentes y opacas . . . . . . . . . . . . . . . . . . . . . . . 13.4. Estructuras mutables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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

15.2.2. Lectura avanzada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.3. Tipos de Puerto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.3.1. Archivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

open-input-file . . . . . open-output-file . . . . open-input-output-file

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Procesamiento automatizado . . . . . . . . . . . . . . . . . . . . . .

15.3.2. Cadenas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.3.3. Conexiones TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15.4. Puertos de Entrada/Salida por defecto . . . . . . . . . . . . . . . . . . . . .

16.Excepciones
16.1. Atrapar Excepciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16.2. Las funciones error y raise . . . . . . . . . . . . . . . . . . . . . . . . . . . .

127
127 128

17.Evaluacin Dinmica de Cdigo


17.1. La funcin

eval

131
131 132 . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17.2. Creacin y ejecucin dinmica de cdigo fuente

18.Programacin Orientada a Objetos


18.1. Denicin de Clases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18.2. Denicin de Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18.3. Creacin de instancias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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

IV. Interfaces Grcas de Usuario


19.Introduccin a las interfaces grcas de usuario con Racket
19.1. Hola Mundo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19.2. Ejecucin y compilacin 19.4. Ventanas de dilogo 19.6. Pneles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19.3. Introduccin a los eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19.5. Eventos de cuadros de texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

141
143
143 144 144 147 148 150

20.Uso de los diversos controles de Racket 21.Dibujo con Lienzos


21.1. Dibujo en un

153 163
163 165

canvas %

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

21.2. Interaccin avanzada con

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.

Grca de ecuacin seccionada

x < 1 x + 2 f (x) = 1 1 x < 0 2 x + 1 0 x

. . . . . . .

41

19.1. hola-mundo.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19.2. eventos-1.rkt 19.3. eventos-2.rkt 19.4. eventos-3.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

22.1. Diagrama de clases de los mens en Racket

22.2. Diagrama de objetos del ejemplo 1-mens.rkt

22.3. 1-mens.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22.4. 2-mens.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22.5. 5-seleccin-color.rkt - men . . . . . . . . . . . . . . . . . . . . . . . . . . .

22.6. 5-seleccin-color.rkt - Selector de color 1 . . . . . . . . . . . . . . . . . . . . 22.7. 5-seleccin-color.rkt- Selector de color 2 . . . . . . . . . . . . . . . . . . . .

15

ndice de guras
23.1. mini-paint.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183

16

Parte I

Introduccin a la Programacin Funcional con Racket

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.

variable_contador representa el estado del

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,

presentado arriba, el resultado de la expresin

no slo depende del nmero

10,

aumentar_contador(10)

sino de otra variable ajena a la funcin.

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.

1.3. Lenguajes de Programacin Funcionales


Existen dos grandes categoras de lenguajes funcionales: los funcionales puros y los funcionales hbridos. La diferencia entre ambos radica en que los lenguajes funcionales hbridos son menos dogmticos que los puros, al incluir conceptos tomados de los lenguajes imperativos, como las secuencias de instrucciones o la asignacin de variables. En contraste, los lenguajes funcionales puros tienen una mayor potencia expresiva, conservando a la vez su transparencia referencial, algo que no se cumple siempre con un lenguaje funcional hbrido. Sin embargo, es de mencionar que en un lenguaje de programacin funcional puro, en la prctica, sera muy difcil programar sistemas; aunque son muy buenos para aplicaciones eminentemente matemticas.

20

1.4 Ejemplos de cdigo de lenguajes funcionales


Entre los lenguajes funcionales puros, cabe destacar a Haskell y Miranda. Los lenguajes funcionales hbridos ms conocidos son Lisp, los dialectos de Scheme y Ocaml. Erlang es un lenguaje funcional de programacin concurrente. R es un lenguaje funcional dedicado a la estadstica. Mathematica y Maxima son tambin lenguajes/entornos funcionales, orientados totalmente al lgebra simblica. Entre otros lenguajes que se podran utilizar para programacin funcional, se podran incluir a Perl, usando exclusivamente funciones denidas por el usuario. As como Python, como lenguaje que incorpora el paradigma funcional.

1.4. Ejemplos de cdigo de lenguajes funcionales


En Haskell:

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

fac (0) -> 1; fac ( N ) when N > 0 -> N * fac (N -1) .

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

.sh, por lo que hay que asignarle los permisos de ejecucin,


1

necesarios para poder ejecutarlo :

$ chmod u+x racket-xxxx.sh $ ./racket-xxxx.sh


3. A continuacin, el instalador pregunta si se desea hacer una instalacin tipo Unix o una instalacin en una sla carpeta. La opcin por defecto es no hacer una instalacin tipo Unix. 4. Luego se pregunta en cul carpeta se desea realizar la instalacin (en caso de haber respondido no en el paso anterior. La opcin por defecto es del usuario o en cualquier otra. 5. A continuacin se procede a realizar la instalacin en la carpeta elegida y aqu termina la instalacin. Automticamente se instalan las pginas de la documentacin ocial de Racket en la carpeta de instalacin elegida. Si la carpeta de instalacin elegida no fue en la carpeta del usuario, es muy probable que la carpeta de la documentacin sea

/usr/plt,

para la cual

se requiere tener permisos de superusuario. Tambin se puede instalar en la carpeta

/usr/share/doc/plt, $ raco docs

/usr/plt/doc/.

En esta carpeta habr un archivo

/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

Figura 2.1: Sitio de descarga de Racket

2.2. Instalacin desde repositorios


Por el momento , las distribuciones de GNU/Linux no incluyen la nueva versin (la 5.0) de

Racket.

En su lugar, todava incluyen la serie 4.x de

compatible con todo el contenido de este libro , en esta primera versin). Es slo cuestin

PLT Scheme

(que es completamente llamada

PLT Scheme, Racket, se encuentre en los repositorios de las distribuciones ms difundidas.


de tiempo (unos 6 meses o un ao) para que la nueva versin de distribucin de GNU/Linux que contiene a

El proceso de instalacin es en general muy sencillo. Especialmente cuando usamos una

PLT Scheme

en sus repositorios.

2.2.1. Debian
En distribuciones basadas en

# apt-get install plt-scheme

Debian, basta con instalar el paquete plt-scheme:


plt-scheme-doc que instala la documentacin

Tambin sera buena idea, instalar el paquete pgina

ocial de la versin instalada por el paquete anterior. Con este paquete, est disponible la

/usr/share/plt/doc/index.html

que es el ndice de la documentacin.

2 3

Al momento de escribir este libro vase el apndice A

24

2.2 Instalacin desde repositorios


Para instalar la documentacin junto con el programa, ejecute el siguiente comando:

# apt-get install plt-scheme plt-scheme-doc

2.2.2. Fedora
En distribuciones

# yum install plt-scheme

Fedora, basta con instalar el paquete plt-scheme:

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

3 Expresiones Racket - Notacin Preja


3.1. Notacin para la sintaxis de Racket
Desde este momento en adelante, se utilizar la siguiente notacin tipo BNF para explicar la sintaxis del lenguaje: Todas las secuencias de caracteres delimitadas por terminales. Por ejemplo:

<smbolo_no_terminal>.

<

>

representan smbolos no

Todas las secuencias de caracteres no delimitadas, representan smbolos terminales. Por ejemplo:

define, (, ), let. {
y

El metaagrupamiento se hace con llaves: El metasmbolo El metasmbolo

}.

+, *,

indica al menos una ocurrencia del smbolo precedente. indica ninguna, una o varias ocurrencias del smbolo precedente.

3.2. Notacin preja de Racket


En Racket, todas las expresiones tienen la forma:

(<operador> <operando>*),

es decir,

que estn siempre en notacin preja con pareamiento completo:

(* (> (+ (+

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:

Por ejemplo, la expresin inja

(+ (* 5 a) (* 2 b c c)).

27

3 Expresiones Racket - Notacin Preja

28

4 Interaccin con Racket


Dependiendo de cmo se vea, Racket es: un lenguaje de programacin, una familia de lenguajes de programacin, variantes de Scheme, que a su vez, es un dialecto de Lisp; o un conjunto de herramientas de programacin. Racket tiene bsicamente dos herramientas principales:

racket,

el compilador, intrprete y sistema de ejecucin interactiva; y

DrRacket, un IDE que corre sobre cin y compilacin). En el caso de

racket

(es decir, que lo usa como motor de ejecu-

DrRacket1 , debe especicarse el lenguaje en particular que se va a utilizar, ya racket.


En nuestro caso particular, usaremos la opcin Usar el lenguaje

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

4.1. Ejecucin interactiva


La parte de abajo de la interfaz de DrRacket (comando de comandos

racket,

drracket), y la herramienta de lnea

funcionan como un rea de interacciones, al estilo de una terminal

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.

Para mayor informacin sobre DrRacket, lase la documentacin ocial de DrRacket.

29

4 Interaccin con Racket


Por ejemplo:

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,

con tres parmetros:

4.1.1. Deniciones e interacciones con DrRacket


Se pueden denir funciones propias, basndose en otras funciones como

substring.

Para

ello, en el rea de deniciones (el rea de texto superior) se escribe algo como:

1 2 3 4 5 6

# lang racket ; extraer . rkt ( define ( extraer str ) ( substring str 4 7) )


Presionar el botn Run y luego, en el rea de interacciones (la terminal de abajo), ya se puede invocar esa funcin:

1 2 3 4

> ( extraer "1234567890") "567" > ( extraer " este es un texto con muchos caracteres ") " es "

4.1.2. Ejecucin interactiva con Racket


Para poder hacer esto mismo con

racket,

primero hay que guardar las deniciones en un

archivo (por convencin, con extensin

.rkt), por ejemplo en un archivo llamado extraer.rkt.

Entonces, en la lnea de comandos, hacemos:

1 2 3

> ( enter ! " extraer . rkt ") > ( extraer "1234567890") "567"
La funcin

enter!

carga el archivo pasado como parmetro y cambia el contexto de evalu-

acin a las deniciones del archivo, igual que el botn Run de DrRacket.

30

4.2 Ejecucin no interactiva

4.2. Ejecucin no interactiva


Si tiene el archivo:

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

$ racket extraer2 . rkt " 567 " $


Se dice que es ejecucin no interactiva porque uno no puede invocar a voluntad funciones denidas en el archivo. Slo se ejecutan las deniciones y llamadas que se encuentran en el archivo. Sin embargo, los programas pueden ser interactivos en el sentido que el curso de la ejecucin se puede cambiar en tiempo de ejecucin.

4.2.1. Parmetros de la lnea de comandos


La ejecucin de un programa, puede controlarse, por ejemplo, con parmetros de la lnea de comandos. Esto se logra con la funcin el siguiente programa:

current-command-line-arguments que retorna un

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:

$ racket linea-de-comandos.rkt hola, "esta es" una prueba


Y la salida sera:

Los parmetros pasados al programa son: #("hola," "esta es" "una" "prueba")

31

4 Interaccin con Racket

32

5 Compilacin de programas Racket


5.1. Lo bsico sobre compilacin
Como parte de Racket, se incluye el programa Racket. Puede obtener una breve descripcin de todas sus posiblidades con

raco que es la herramienta de compilacin de $ raco --help.

La compilacin de un programa Racket es muy sencilla. Suponga que tiene el programa:

1 2 3

# lang racket ; hola . rkt ( display " Hola Mundo !\ n ")


Se compila as:

$ raco exe -o ejecutable hola.rkt


Para ejecutarlo, dependiendo de la conguracin de la terminal:

1 2 3

$ ./ ejecutable Hola Mundo ! $

5.2. Compilacin con mltiples mdulos


El hecho de tener un programa separado en mdulos funcionales, no afecta el proceso de compilacin. Simplemente hay que compilar el archivo que contiene la ejecucin inicial de nuestra aplicacin. Por ejemplo, considere los siguientes dos archivos:

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

5 Compilacin de programas Racket


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

# 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:

$ raco exe -o ejecutable principal.rkt


Y para ejecutar el programa:

$ ./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

Introduccin al lenguaje Racket

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:

#|

|#.

y los comentarios de bloque son

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 .

|# ( display " Bueno , esto no es comentario , es cdigo \ n ") ;; Esto s ; -)

6.2. Deniciones Globales


Una denicin de la forma

(define <identificador> <expresin>) le asigna a <identificador> el resultado de


Una denicin de la forma

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

( define mximo 3) ( define ( prefijo str ) argumento ( substring str 0 mximo ) )

; Define que mximo es 3 ; Define que prefijo es una funcin de un

> 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:

\.

( ) [ ] { }  , ' ` ; # |

Tampoco se pueden utilizar identicadores que se correspondan con literales numricos

y tampoco estn permitidos los espacios dentro de los identicadores. Por lo dems, se pueden utilizar identicadores como

variable-con-guiones, variable+con+ms-y-t 123abc, +-, variable-interrogativa???,  23..4,  variable/dividida, etc.


Y, puesto que, el intrprete racket procesa archivos Unicode, los identicadores pueden contener y estar formados por cualesquiera caracteres vlidos en esa codicacin (se recomienda que los archivos de cdigo fuente estn en codicacin UTF-8). Por ejemplo, las siguientes declaraciones son vlidas para el intrprete de Racket:

> (define -en-espaol 1) > (define -deutsch 2) > (define e ho san go- ciu a ude-en-Esperanto 3)

38

6.3 Llamadas a funciones

6.3. Llamadas a funciones


Tpicamente una llamada a funcin tiene la forma

(<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

Racket dene muchas funciones integradas del lenguaje. Por ejemplo

string-length, string?, sqrt, +, -, <, >=, number?, equal?,

string-append, substring,

etc.

6.4. Bloques condicionales


6.4.1. if
La forma de un bloque condicional en Racket es:

(if <expresin-lgica> <expresin-para-verdadero> <expresin-para-falso>)


Cuando se evala un

if, se evala la primera expresin. Si esta resulta verdadera, se retorna

el resultado de la segunda expresin, y de lo contrario, el resultado de la tercera. Por ejemplo:

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

(or <expresin>*). #f,

and

or #t

La primera retorna a

si encuentra que uno de sus parmetros se evala a

y retorna

en caso contrario. La segunda retorna

#t

y retorna

#f

#t

si encuentra que uno de sus parmetros se evala

en caso contrario. Funcionan como se espere que funcionen en otros

lenguajes de programacin, y adems funcionan en cortocircuito (como en otros lenguajes como

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

6.4 Bloques condicionales

Figura 6.1: Grca de ecuacin seccionada

x < 1 x + 2 f (x) = 1 1 x < 0 2 x + 1 0 x

10 11 12

" perdn , qu ?" )

6.4.3. cond
Una forma de bloques condicionales anidadas (if anidados) es:

(cond { [ <expresin-de-prueba> <expresin>* ] }* )


Este bloque condicional contiene una secuencia de clusulas entre corchetes. En cada clusula, la primera expresin es una expresin de prueba o evaluacin. Si esta se evala a verdadero, entonces las restantes clusulas del grupo son evaluadas, y la sentencia completa retorna el valor de la ltima expresin de esa clusula; el resto de las clusulas son ignoradas. Si la evaluacin de la expresin de prueba se evala a falso, entonces el resto de las expresiones de la clusula son ignoradas y la evaluacin contina con la prxima clusula. La ltima clusula puede usar la constante else que es un sinnimo para

#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

; -1 <x <0 : 1 ; 0<x : -x ^2+1

( 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

En Racket, el uso de parntesis y corchetes es completamente intercambiable, mientras un

se cierre con un

y un

se cierre con un

no hay problema. Sin embargo, el uso de

corchetes junto a los parntesis hace del cdigo Racket ligeramente ms legible.

6.4.4. case
Los bloques

case

sirven para corresponder el resultado de una expresin con una serie de

valores y evaluar diferentes expresiones en funcin de eso. La sintaxis bsica es:

(case <expresin-de-prueba> { [ ( <valores>+ ) <expresin>+ ] }* )


Por ejemplo:

> ( case (+ 7 5)

42

6.5 Bloques de cdigo secuencial


2 3 4 5 6 7 8 9 10 11 12 13

[(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 "

6.5. Bloques de cdigo secuencial


En la idea bsica del paradigma funcional, no existe algo como la est presente de manera nativa en los bloques y

secuencia de instrucciones,

pero como Racket es hbrido, s disponde esta caracterstica. La secuencia de instrucciones

let,

lambda, define (para funciones), cond, case

por lo que esas alternativas suelen bastar. Pero para aquellos casos en los que no, se

dispone del bloque

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 "

6.6. Ms sobre llamadas a funciones


Racket es un lenguaje muy potente y muy expresivo. Las llamadas a funciones, no slo pueden hacerse utilizando directamente los identicadores de las funciones. Tambin pueden hacerse utilizando expresiones que devuelvan referencias a funciones. As, la sintaxis de llamadas a funciones se puede ampliar

1 como:

(<expresin-de-funcin> <expresin>* )
La

<expresin-de-funcin>,

debe ser una expresin cuyo resultado sea

una funcin.

Por ejemplo:

Esta an no es la forma ms general

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

retorna una funcin a travs de su nombre (string-append o

+).

<expresin-de-funcin>

no devolviera una funcin, se generara un error, ya que el

primer elemento dentro de los parntesis debe ser una funcin. Por ejemplo, la siguiente expresin:

> (1 2 3)
produce el error:

procedure application: expected procedure, given: 1; arguments were: 2 3


Note que, puesto que una funcin puede ser devuelta por una expresin, una funcin tambin puede se pasada como parmetro a otra funcin:

1 2 3 4 5 6

> ( define ( componer funcin valor ) ( funcin ( funcin valor ) ) ) > ( componer sqrt 256) 4 > ( componer sqr 2) 16

44

7 Funciones annimas - Bloques


Considere la siguiente expresin:

lambda

(+ 5 4)
Es equivalente a:

1 2 3 4

( define a 5) ( define b 4) ... (+ a b )


La segunda forma sera innecesariamente larga si los valores de a y b slo se utilizarn una vez. De la misma manera, cuando una funcin slo se llama una vez, tener que declararla es innecesariamente largo. Por ello, Racket incluye la posibilidad de escribir funciones annimas. Por ejemplo:

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.

7.1. Bloques lambda


En Racket as como en muchos otros lenguajes de programacin, un produce una funcin directamente, sin tener que declararla. El bloque lambda tiene la siguiente sintaxis:

bloque lambda

(lambda ( <identificador>* ) <expresin>+ )


La serie de identicadores se corresponde, uno a uno, con los parmetros formales de la funcin a producir; y las expresiones son el cuerpo de la funcin. Como en la declaracin

45

7 Funciones annimas - Bloques lambda


tradicional de funciones (con

define)1 ,

el resultado de la funcin (cuando se llame), es el

resultado de la ltima expresin del cuerpo del bloque La evaluacin de un bloque

lambda.

lambda,

produce en s misma una funcin:

1 2

> ( lambda ( s ) ( string - append " " s "!") ) # < procedure >
Entonces, usando

lambda,

la llamada a componer puede ser reescrita como:

1 2 3 4

> ( componer ( lambda ( s ) ( string - append " " s "!") ) " hola ") " hola !!" > ( componer ( lambda ( s ) ( string - append " " s "!?") ) " hola ") " hola !?!?"

7.2. Funciones/Expresiones que producen funciones


Otro uso de ciones:

lambda

es como resultado para una funcin (o expresiones) que produce fun-

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:

lambda a un identicador. Las siguientes

1 2 3 4

> ( define ( poner - admiracin s ) ( string - append " " s "!") ) > ( define poner - admiracin
1

En realidad, lo tradicional, es usar lambda para denir funciones.

46

7.2 Funciones/Expresiones que producen funciones


5 6 7 8 9

( lambda ( s ) ( string - append " " s "!") )) > poner - admiracin # < procedure : poner - admiracin >

47

7 Funciones annimas - Bloques lambda

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:

(define (<identificador> <identificador>* ) <definicin>* <expresin>+ )


y

( lambda ( <identificador>* ) <definicin>* <expresin>+ )


La diferencia con respecto a la sintaxis anteriormente mostrada, es que hay un bloque opcional de deniciones antes del cuerpo de la funcin. Por ejemplo:

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-

es que puede ser colocada en cualquier lugar dentro de una expresin y no

slo al principio de la funcin, como

define.

Adems, con

asignaciones al mismo tiempo, en lugar de hacer un La sintaxis de

define

let

se pueden hacer mltiples

para cada asignacin.

let es: (let ( { [<identificador> <expresin>] }* ) <expresin>+ )


Cada clusula de asignacin es un cada clusula, al

<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

usado dentro del cuerpo. Fuera del bloque Por ejemplo:

los identicadores no son visibles.

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

> ( let * ([ x 1] [ y 2] [ z (+ x y ) ]) ( printf " La suma de ~ a y ~ a es : ~ a " x y z ) ) La suma de 1 y 2 es : 3

50

Parte III

Elementos del lenguaje

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

9.1.1. Lista vaca o nula


La lista vaca, se puede escribir de diversas maneras en Racket: Invocando a la funcin

list

sin parmetros:

(list)

Con la constante especial Con la constante especial

empty null '()


, que es un caracter de apstrofe seguido de

Con la forma tradicional de Lisp: parntesis vacos.

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:

empty?: (if (empty? L) vaca no vaca)

null?: (if (null? L) vaca no vaca)

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 "

9.1.2. Funciones bsicas sobre listas


length
para vericar la longitud de una lista para extraer el i-simo elemento de una lista (los ndices comienzan desde

list-ref

cero, como en la mayora de lenguajes de programacin).

54

9.1 Listas
append
para unir listas para invertir el orden de una lista

reverse member list?


vaca)

para vericar si un elemento est en 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

9.2. Iteracin automtica


En Racket no hay ciclos tos.

for o while1 , por lo que se utilizan ciertas funciones predenidas,

propias de los lenguajes funcionales, para recorrer y procesar secuencias (listas) de elemen-

9.2.1. map
La primera de ellas, es la funcin

map que utiliza los resultados de aplicar una funcin sobre

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 !")

9.2.2. andmap y ormap


Otras funciones tiles para hacer validaciones de listas son primera, retorna

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

se comporta como se espera, pero aplicando disyuncin lgica en lugar

de conjuncin, que es lo que aplica

#t

si la funcin se evala a

verdadero para alguno de los elementos de la lista. Ejemplos:

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

9.2 Iteracin automtica


11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

#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

sirve para ltrar elementos de una lista, segn el criterio especicado

por una funcin de validacin. Ejemplo:

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,

ignora el resultado de las evaluaciones de la

funcin sobre los elementos de la lista. Con

for-each

slo importan los efectos colaterales

de las invocaciones (como las escrituras en pantalla o en archivo), no su resultado.

58

9.3 Iteracin manual

9.2.5. Versiones generales de las funciones de iteracin


Las funciones

map, for-each, andmap

ormap

pueden manipular mltiples listas, en lugar

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

9.3. Iteracin manual


Eventualmente es necesario procesar listas a ms bajo nivel que el que proveen funciones como

map.

En esos casos, se requiere de mecanismos

ms primitivos

como los siguientes:

first

devuelve el primer elemento de una lista no vaca

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:

concatena un elemento a una lista, produciendo una lista nueva

cons? verica si un elemento es una lista no vaca (lo contrario de empty? y de null?)
1 2 3 4 5 6

> ( first ( list 1 2 3) ) 1 > ( rest ( list 1 2 3) ) (2 3)

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

para manipular funciones,

podramos construir nuestras propias funciones de longitud de lista y de mapeo de lista:

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

9.4 Pares y listas


14

))

9.4. Pares y listas


La funcin

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

> ( list ? par ) #f > ( list ? lista ) #t

9.4.1. Convencin de impresin


Racket tiene una convencin para imprimir los pares, que puede llegar a ser muy confusa. Por ejemplo, considere el siguiente resultado:

1 2

> ( cons 0 ( cons 1 2) ) (0 1 . 2)


Lo anterior es un par, cuyo segundo elemento es otro par que no es una lista. La regla para la impresin es la siguiente: Usar siempre la notacin de punto, pero si el punto est inmediatamente seguido de una apertura de parntesis, entonces, remover el punto, el parntesis de apertura y el correspondiente parntesis de cierre.

(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.

9.4.2. Notacin inja


Existe una convencin particular en Racket que, aunque no es tradicional en Lisp y otros dialectos de Scheme, puede mejorar la legibilidad de ciertas partes de nuestras funciones. Un par de

puntos

pueden aparecer alrededor de un solo elemento en una se-

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

hacia el frente de la secuencia parentizada.

Esta convencin posibilita una especie de notacin inja, a la cual estamos ms acostumbrados:

1 2 3 4 5 6 7 8

> (1 . + . 2 3 4 5) 15 > '(1 . + . 2 3 4 5) (+ 1 2 3 4 5) > (1 . < . 2) #t

62

9.4 Pares y listas


9 10 11 12 13 14 15 16 17

> '(1 . < . 2) ( < 1 2) > (1 2 3 . * . 4) 24 > '(1 2 3 . * . 4) (* 1 2 3 4)

63

9 Listas e Iteracin

64

Ejercicios de Listas e iteracin


1. Dada una lista desordenada de nmeros enteros ordenar dicha lista de mayor numero a menor, tomar en cuenta que pueden existir nmeros repetidos en dicha lista (No utilizar la funcin

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

un lista, es decir que no

por lo dems, se puede utilizar cualquier primitiva.

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 mundo mundo)

la nueva lista ser

'(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

si dicho nmero no se encuentra (NO USAR

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

si dichos puntos forman un tringulo equiltero,

en caso contrario (es equiltero si sus tres lados son iguales). NOTA : Frmula

de distancia entre los puntos

(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

'( (1 2) (2 3)) retornar (1 2 2 3). Como puede observar,

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,

el tipo de recursin usada es

posposicin de trabajo:
1 2 3 4

( define ( longitud L ) ( cond [( empty ? L ) 0] [ else (+ 1 ( longitud ( rest L ) ) ) ]) )


Y al evaluar, por ejemplo,

(longitud (list a b c))

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.

10.2. Recursin de Cola


Considere la siguiente versin de

longitud

con recursin de cola:

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

(longitud (list a b c)):


" b " " c ") ) " a " " b " " c ") 0) " b " " c ") 1) " c ") 2) ) 3)

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 Tipos de dato integrados del lenguaje


Aqu se describen los principales tipos integrados, nativos de Racket. El lenguaje incluye muchos otros tipos de datos complejos que no sern abordados aqu.

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.

Slo tiene dos valores constantes,

versiones en minsculas son preferidas). Existe la funcin o

#f:

#t

1 2 3 4

> ( boolean ? 0) #f > ( boolean ? # f ) #t


A pesar de que se espera un valor de verdad en las expresiones de prueba de las construcciones

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 Tipos de dato integrados del lenguaje


19 20 21 22

#t > ( mostrar - valor - de - verdad #\ a ) #t

11.2. Nmeros
A continuacin se presenta el tratamiento de los

nmeros

en Racket.

Un valor numrico se puede validar con la funcin

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.

Clasicacin por Exactitud


En Racket, un Los

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

exact? e inexact? para determinar si un nmero pertenece a uno de

los dos tipos anteriores.

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:

exact->inexact e inexact->exact para convertir

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

> # e0 .2 1/5 > # i1 /5 0.2 > # i4 +5 i 4.0+5.0 i

Propagacin de la exactitud
los clculos:

Con los operadores aritmticos bsicos, los nmeros exactos

se mantienen exactos tras los clculos y los inexactos se mantienen inexactos a travs de

71

11 Tipos de dato integrados del lenguaje


1 2 3 4 5 6 7 8 9 10

> ( define ( sigma f a b ) ( if (= a b ) 0 (+ ( f a ) ( sigma f (+ a 1) b )) ) ) > ( sigma ( lambda ( x ) (/ 1 107/210 x ) ) 5 8)

> ( sigma ( lambda ( x ) (/ 1.0 x ) ) 5 8) 0.5095238095238095

Clasicacin por Conjuntos


Tal como en la matemtica tradicional, los nmeros se categorizan por la jerarqua del conjunto al que pertenecen:

ZQRC

(es decir, los enteros estn includos en los

racionales, estos en los reales, y estos en los complejos):

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

11.2.2. Otras bases


La base para todos los nmeros (desde los enteros hasta los complejos) es forzarse a que sea base 2, base 8 o base 16 con los prejos

#b, #o, #x,

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

= o con equal?, pero los nmeros

inexactos, debido a su propia naturaleza, deberan ser comparados

por igualdad, ya que su representacin no es exacta:

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 ) )

11.2.4. Constantes especiales


Existen cuatro constantes especiales, denidas por la IEEE:

+inf.0/-inf.0

que resultan de sobrepasar la capacidad de representacin de los

nmeros en coma otante, por arriba o por abajo, respectivamente.

+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

> (/ 8.0 0.0) + inf .0 > -5.38 e700

73

11 Tipos de dato integrados del lenguaje


5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

- 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

en Racket, es un valor escalar Unicode (igual que en otros lenguajes de pro-

gramacin como

Java ).

Los caracteres literales, se expresan como una secuencia

#\

seguido del caracter correspon-

diente, si es que estos tienen una representacin imprimible y escribible:

1 2 3 4

> #\0 #\0 > #\ a #\ a

74

11.3 Caracteres
5 6 7 8 9 10

> #\ newline #\ newline > #\ space #\ space > #\& #\&

A pesar que un caracter se corresponda con un entero en Racket, a diferencia de otros lenguajes (como

Java

C ),

no se pueden mezclar directamente con los nmeros. Para

poder hacerlo, se utilizan las funciones

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:

minscula y un nmero hexadecimal de

1 2 3 4

> ( integer - > char 17) #\ u0011 > ( char - > integer #\ u011D ) 285

Existen ciertas funciones tiles para manipular y procesar caracteres:

75

11 Tipos de dato integrados del lenguaje

11.4. Cadenas
Una

cadena

es un arreglo de caracteres de longitud ja. Como en muchos otros lenguajes,

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

escribe los caracteres de la cadena, pero sin las comillas, a diferencia

de lo que sucede cuando el resultado de una expresin es una cadena.

76

11.4 Cadenas
Ejemplos:

Hay tres funciones bsicas para la creacin y manipulacin de cadenas:

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

11.4.1. Cadenas mutables


Por defecto, los literales de cadena escritos en el cdigo fuente, se convierten en cadenas

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

recibe una longitud para la nueva cadena mutable y opcionalmente un

caracter de relleno, por defecto el caracter nulo (\u0000).

77

11 Tipos de dato integrados del lenguaje


string-set!
modica un caracter de una cadena mutable, dada su posicin. convierte una cadena mutable en su versin inmutable

string->immutable-string

(si recibe una inmutable, la devuelve a ella misma).

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

copia total o parcialmente el contenido de una cadena mutable o

inmutable a otra cadena mutable.

> ( 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 "

11.4.2. Comparacin entre cadenas


La comparacin entre cadenas se realiza con las siguientes funciones:

string=?, string<?, string<=?, string>?, string>=?

para hacer comparaciones

simples en funcin del orden relativo de los caracteres en el estndar Unicode.

78

11.4 Cadenas
string-ci=?, string-ci<?, string-ci<=?, string-ci>?, string-ci>=?
para hacer

comparaciones insensibles al caso (sin distincin entre maysculas o minsculas).

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

11.4.3. Otras funciones de cadena


string-append string->list
dena. devuelve una nueva cadena mutable, resultado de concantenar una serie de cadenas. devuelve una lista de todos los caracteres correspondientes a una ca-

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

11 Tipos de dato integrados del lenguaje


14 15 16 17

"456789" > ( substring "0123456789" 4 5) "4"

11.5. Bytes y Cadenas de Bytes


Un

[#x0,#xff]).
Ejemplos:

Byte, en Racket, es un entero exacto en el intervalo cerrado [0,255] (o en hexadecimal,


La funcin

byte?

reconoce este tipo de nmeros. No es en realidad un tipo

especco, sino un subconjunto de los nmeros enteros.

1 2 3 4 5 6

> ( byte ? # xfa ) #t > ( byte ? 56) #t > ( byte ? 256) #f


Su utilidad radica en que sirven para construir

cadenas de bytes,

que se utilizan para

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

se imprimen en pantalla, se usa la codicacin ASCII, y si un byte no es imprimible, se

bytes-ref
de relleno.

devuelve un byte de la cadena de bytes dada su posicin.

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:

verica si un valor es una cadena de bytes.

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"

otra - cadena 0 98) ;; La letra 'b '

otra - cadena 3 0) otra - cadena 2 10) otra - cadena 1 5)

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

# lang racket ; smbolo . rkt

81

11 Tipos de dato integrados del lenguaje


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

( 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 .") ) ))

Tiene la siguiente salida:

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

11.7 Palabras clave

11.7. Palabras clave


Las

palabras clave

son elementos de la forma

en s mismas y sirven para

el paso de parmetros por nombre.

#:palabra.

No constituyen una expresin Su utilidad se explica en la

subseccin 12.2.4 en la pgina 92.

11.8. Pares y listas


Los

pares y listas

hay pares y listas

mutables, de las que s se hablar aqu. mutabilidad

son tratados en el captulo 9, en sus formas

inmutables.

Pero tambin

Hay dos detalles importantes sobre la

de los pares:

1. La lista vaca no es mutable ni inmutable. 2. Las funciones

pair?

list?

slo reconocen pares y listas inmutables.

A continuacin, veamos cmo manipular

pares (y listas) mutables:

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?

set-mcar! set-mcdr! mcar


Ejemplos: y mente.

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

11 Tipos de dato integrados del lenguaje


20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

> ( 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

#.

Cuando se escribe un vector con esta notacin, por defecto es inmutable.

Algunas funciones bsicas para manipular vectores son:

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

list->vector vector->list vector-set!

modica un valor de un vector mutable dada su posicin.

84

11.10 Tablas Hash


vector-length
Ejemplos: devuelve la longitud de un vector.

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

crea un vector mutable de un tamao especicado y opcionalmente un

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-

mutable) a un vector mutable.

11.10. Tablas Hash


Una

tabla hash

es una estructura de dato que implementa el

arbitrarios. Tanto las

el tiempo de acceso a los

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

11 Tipos de dato integrados del lenguaje


Tal como con otros tipos de dato en Racket, existe una gran cantidad de funciones nativas para manipular tablas hash, adems de existir en versin mutable e inmutable:

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:

elimina una clave y su respectivo valor de una tabla hash mutable.

devuelve el tamao de una tabla hash medida en nmero de pares con-

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

que no devuelvan nada, sino que slo querdisplay, printf,


y

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

, que devuelve el objeto

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

11 Tipos de dato integrados del lenguaje

88

12 Expresiones y Deniciones Avanzadas


Aqu se discute sobre otras formas y para denir funciones.

avanzadas del lenguaje Scheme para construir expresiones

12.1. La funcin apply


La sintaxis para la llamada de funciones,

(<expresin-funcin> <parmetro>*), soporta

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

>

( define ( promedio L ) ;;;;; no va a funcionar (/ (+ L ) ( length L ) ) )

> ( promedio '(1 2 3) ) +: expects argument of type < number >; given (1 2 3)
La funcin la funcin

+ espera apply:

los parmetros uno por uno, no en una lista. En su lugar, utilizamos

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:

12.2. Bloques lambda


Recordemos primero que la forma bsica de los bloques

( lambda ( <parmetro-formal>* ) <expresin>+ )


Un bloque

lambda

es:

lambda

con

parmetros formales, acepta

parmetros reales. Por ejemplo:

89

12 Expresiones y Deniciones Avanzadas


1 2 3 4 5 6 7 8

> (( 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

12.2.1. Funciones con cualquier nmero de parmetros


Los bloques lambda tambin tiene la sintaxis opcional: ( lambda <lista-de-parmetros> <expresin>+ ) Donde <lista-de-parmetros> es un identicador que no va encerrado entre parntesis que contendr una lista con todos los parmetros reales pasados a la funcin:

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

12.2.2. Funciones con un mnimo nmero de parmetros


Se puede tambin, denir que una funcin tenga un mnimo nmero de parmetros obligatorios, pero sin mximo. La sintaxis es:

( 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

12.2 Bloques lambda


4 5 6 7 8 9 10 11

> ( 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

12.2.3. Funciones con parmetros opcionales


La sintaxis de los bloques

lambda

se puede ampliar para permitir parmetros opcionales:

( 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

[<identificador-de-parmetro> <valor-por-defecto>] es opcional. Cuando el argumento no es indicado en la llamada, la expresin <valor-por-defecto>


produce un valor que se asigna como parmetro real. Esta expresin puede hacer referencia a cualquier parmetro precedente. Y todos los parmetros siguientes a uno opcional, deben ser opcionales; no se puede denir un parmetro obligatorio despus de uno opcional en una misma funcin. Ejemplos:

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

12 Expresiones y Deniciones Avanzadas


20 21 22 23 24 25

> ( saludar " Juan ") " Hola , Juan Prez " > ( saludar " Eduardo " " Navas ") " Hola , Eduardo Navas "

12.2.4. Funciones con parmetros con nombre


La sintaxis de los bloques

lambda es an ms mplia, y puede inclur parmetros con nombre,


parmetros de palabra clave (vase la seccin 11.7):

o segn la nomenclatura de Scheme,

( 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

pasado a la funcin usando la misma

<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

la correspondencia con los parmetros formales, ya que se asignar por correspondencia de

palabra clave
1.

en lugar de correspondencia de la posicin.

En este momento vale la pena decir que existen cuatro tipos de parmetros:

Los parmetros obligatorios por posicin. Los parmetros opcionales por posicin.

En este caso, el parmetro real y el formal

se corresponden por la posicin de ambos. 2. En este caso, el parmetro real, si est, se

corresponde por la posicin con el formal. 3.

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

12.2 Bloques lambda


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

> ( 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 "

12.2.5. Funciones con aridad mltiple


Otra forma de denir funciones con aridad variable, pero con un nmero nito de parmetros formales, es con el bloque que le sean pasados. Un bloque

case-lambda, case-lambda

que crea una funcin que puede tener un

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

[ <parmetros-formales-case> <expresiones-cuerpo>+ ], (lambda <parmetros-formales-case> <expresiones-cuerpo>+) case-lambda


es como aplicar un

Al llamar una funcin denida por un

lambda

para el

primer caso en que coincida el nmero de parmetros reales con los formales.

93

12 Expresiones y Deniciones Avanzadas


Cabe aclarar que el bloque

case-lambda

slo soporta parmetros obligatorios por posicin

ni parmetros por palabra clave (ni obligatorios ni opcionales). Ejemplo:

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 "

12.2.6. Consultando la aridad de las funciones


Cuando escribimos funciones que reciben funciones como parmetros, es necesario vericar si la aridad de las ltimas es vlida para el propsito de nuestra funcin. Para ello, Scheme provee funciones de manipulacin y consulta de informacin de funciones. Entre ellas, podemos mencionar a podemos mencionar a la estructura

procedure-arity, y procedure-arity-includes?. arity-at-least.

Tambin

arity-at-least
Esta estructura tiene la denicin (vase el captulo 13):

(define-struct arity-at-least (value)),


Una instancia funcin/procedimiento acepta al menos

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

12.2 Bloques lambda


Un entero no negativo, lo que signica que ros nicamente. Una instancia de la estructura transparente arity-at-least, lo que signica que <funcin> acepta un mnimo nmero de parmetros, y ese mnimo es el valor (entero no negativo) del campo value de la estructura devuelta. Una lista de enteros no negativos e instancias de que

<funcin> acepta ese nmero de parmet-

<funcin>

arity-at-least,

lo que signica

acepta cualquier nmero de parmetros que coincidan con uno de los

elementos de la lista. Ejemplos:

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:

no negativo. Esta funcin responde si Ejemplos:

(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

12 Expresiones y Deniciones Avanzadas


12 13 14 15 16 17 18

> ( 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

12.3. Resultados mltiples


Una expresin normalmente produce un nico resultado, pero algunas expresiones pueden producir mltiples resultados. Por ejemplo, en Scheme, las funciones producen un nico valor, pero la funcin valores al mismo tiempo:

quotient/remainder

quotient y remainder

produce los mismos dos

1 2 3 4 5 6 7 8 9

> ( quotient 13 3) 4 > ( remainder 13 3) 1 > ( quotient / remainder 13 3) 4 1


Visualmente, los dos valores aparecen en lneas diferentes; algortmicamente hablando, esto en consistente con el hecho que los algoritmos puede producir mltiples valores de salida, as como pueden tomar mltiples valores de entrada.

96

12.3 Resultados mltiples

12.3.1. values
La funcin

values

acepta cualquier cantidad de parmetros y los devuelve todos:

1 2 3 4 5 6

> ( values ) > ( values " a " 1 #\ a ) "a" 1 #\ a


Eventualmente nuestras funciones deben devolver dos o ms valores simultneamente. En esos casos, se podra optar por devolver una lista o vector con los valores correspondientes; pero usar la funcin

values

values es ms elegante y algortmicamente ms apropiado, porque con

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

Java ), el lenguaje Racket permite acercar de

nuevo el cdigo del programa a su representacin matemtica.

12.3.2. define-values
El bloque

define-values asigna mltiples identicadores al mismo tiempo producidos por

mltiples resultados de una nica expresin:

(define-values ( <identificador>* ) <expresin> )


El nmero de resultados de

<expresin>

debe coincidir con el nmero de identicadores.

1 2 3 4 5 6 7

> ( define - values ( cociente residuo ) ( quotient / remainder 101 50) ) > cociente 2 > residuo 1

12.3.3. let-values, y let*-values


De la misma manera que

let-values
1 2 3 4 5 6

define-values asigna mltiples resultados let*-values asignan mltiples resultados localmente:

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

12 Expresiones y Deniciones Avanzadas


7 8 9 10

> ( muestra - cociente -y - residuo 102 25) El cociente es : 4 El residuo es : 2


La diferencia entre

hace asignaciones en paralelo y

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

es posible considerar la asignacin de nuevos valores a vari-

ables ya existentes . Esto se hace con las funciones La sintaxis es:

set!

set!-values.

(set! <identificador> <expresin>) y (set!-values ( <identificador>* ) <expresin>)


Los identicadores deben haber sido asignados previamente, por lo que no sirven para inicializar variables. Es pertinente hacer la aclaracin que el abuso de las asignaciones puede producir resultados inesperados (pero no erroneos), debido a que las asignaciones directas no son propias del paradigma funcional.

Como ya habr notado el lector, las asignaciones de variables, no suelen necesitarse en el paradigma funcional.

98

Ejercicios de Expresiones y Deniciones Avanzadas


1. Elaborar una funcin, a la cual si se le pasa de parmetro un nmero real su raz cuadrada, pero si se le pasa de parmetro un nmero parmetro otro nmero entero positivo sacar a

retornar

y como segundo

N.

Es decir:

indicando el grado de la raz que se le

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

12 Expresiones y Deniciones Avanzadas


y de segundo parmetro un nmero entero, la funcin ingresar el nmero dentro del vector y deber retornar el vector ordenado ascendentemente. >Si se le pasa como primer parmetro un vector de nmeros enteros, y como segundo y tercer parmetro dos nmeros enteros, la funcin deber buscar en el vector el nmero pasado como segundo parmetro en el vector y sustituirlo por el nmero pasado como tercer parmetro, y deber retornar el vector ordenado de forma ascendente. *Si hay ms parmetros o si los parmetros son incorrectos entonces se mostrar un mensaje de error indicando que los parmetros son incorrectos. 6. Elaborar una funcin que reciba dos listas como parmetro, la primer lista que deber recibir contendr smbolos que correspondan a los atributos de una persona. Esto podra ser as:

'(nombre apellido edad sexo estado-civil telfono dui nit)

(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

'(x . y) si no se recibe parmetro alguno entonces

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

que retorne una lista de

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

[A, B ], la restriccin de este ejercicio es que los parmetros A y B

puedan

ser pasados en cualquier orden.

100

13 Tipos de dato denidos por el programador


Aqu hablaremos sobre cmo denir variables compuestas por varios campos. Sobre Objetos y clases, lase el captulo 18.

13.1. Estructuras simples


La sintaxis bsica para declarar estructuras es:

( define-struct <nombre-estructura> (<nombre-campo>* ) )


Con esta denicin, Scheme tambin crea una serie de funciones adicionales para poder manipular las estructuras de ese nuevo tipo:

make-<nombre-estructura> <nombre-estructura>?

es una funcin constructora que sirve para crear estruc-

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-

presin es del nuevo tipo.

<nombre-estructura>-<nombre-campo>
Por ejemplo:

son una serie de funciones que devuelven el valor

de un campo de un elemento del nuevo tipo.

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

13 Tipos de dato denidos por el programador


17 18

> ( punto - y mi - punto ) 2


Por defecto, las estructuras creadas as son es la siguiente:

inmutables.

Por lo que existe una funcin para

copiar estructuras y opcionalmente actualizar algunos campos en la nueva copia. Su sintaxis

( 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

13.2. Estructuras derivadas


Una forma extendida de

define-struct puede ser usada para denir un subtipo de estruc-

tura, que es un tipo de estructura que extiende a otro tipo, o que se deriva de otro. La sintaxis es:

(define-struct (<nombre-estructura> <estructura-madre>) ( <nombre-campo>* ) )


La

<estructura-madre> debe ser el nombre de la estructura a la que <nombre-estructura>

extiende. Por ejemplo:

102

13.2 Estructuras derivadas


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

> ( 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:

Si hay una estructura madre llamada

derivada,

el nombre formal de esta, as:

a su vez, se deriva otra llamada

base:derivada:descendiente,

descendiente,

debera

base,

y de esta se deriva otra llamada ser

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

13 Tipos de dato denidos por el programador

13.3. Estructuras transparentes y opacas


Cuando una estructura se dene de la forma

( define-struct <nombre-estructura> (<campo>* ) )


por defecto es

opaca,

es decir, que cuando se imprime, slo se muestra el nombre del tipo

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

( define-struct <nombre-estructura> (<nombre-campo>* ) #:transparent)


La diferencia en la denicin, es una palabra clave que se agrega despus de los campos. Ejemplo:

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-

a las bibliotecas que se implementen con Scheme.

13.4. Estructuras mutables


Si eventualmente se requiriera de una estructura cuyos campos deban ser alterados, el tipo de estructura debe declararse como mutable, as:

( define-struct <nombre-estructura> (<nombre-campo>* ) #:mutable)


Al declararse as un tipo de estructura, se crean tambin una serie extra, de funciones con el nombre

set-<nombre-estructura>-<nombre-campo>!;

se crea una por cada campo de

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

13.4 Estructuras mutables


Cabe recalcar que un tipo de estructura puede ser declarado como

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

13 Tipos de dato denidos por el programador

106

Ejercicios de Tipos denidos por el programador


1. Crear una funcin que pida en tiempo de ejecucin un nmero entero positivo que indique el da, un nmero entero positivo que represente un mes, y un nmero entero positivo que represente un ao, y retornar una estructura de tipo fecha, la denicin de la estructura es la que se muestra a continuacin:

(define-struct fecha (da mes ao) #:transparent)


2. Elaborar una funcin que pida en ejecucin tres puntos del plano cartesiano, y cada punto ser una estructura de tipo  punto con campos la distancia al origen. 3. Elaborar una funcin que reciba como parmetro una lista de estructuras de tipo fecha, y que retorne la lista ordenada de fecha anterior a posterior. Si algn elemento que est en la lista no es de tipo fecha, retornar una lista nula. 4. Elaborar una funcin que reciba una cadena que corresponda a un nombre de persona, y un nmero indicando la edad de la persona, y como ltimo parmetro el nmero de DUI(cadena) de la persona, la funcin deber de retornar una estructura transparente de tipo persona, pero con la condicin que si la persona es menor de edad el campo de DUI estar vaco pudindose modicar en el futuro. 5. Elabore una funcin que reciba como parmetro una estructura de tipo persona, la funcin deber de retornar una estructura de tipo empleado (derivada de persona) y para ello se deber de capturar en tiempo de ejecucin el NIT(cadena) y el nmero de telfono (cadena). 6. Elaborar un funcin que reciba como parmetro una lista de estructuras de tipo persona, dicha funcin deber retornar la lista de estructuras ordenada alfabticamente por nombre de persona. Note que nombres como  scar , van junto con los nombres con letra inicial  o y no antes de los nombres con inicial  a , ni despus de los nombres con inicial  z . 7. Elaborar una funcin que reciba de parmetro un conjunto de puntos en forma de pares, la funcin deber de retornar un vector ordenado de mayor a menor distancia al origen, que contenga los puntos pero con una estructura un campo el par

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

y en el otro campo la distancia

de ese punto al origen.

107

13 Tipos de dato denidos por el programador

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:

privadas. Y para que sean tiles para pblicas.

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

14.1. Visibilizando deniciones de estructuras


biblioteca.rkt tuvieramos la denicin (define-struct estructura (campo1 campo2), y quisieramos
Si en el archivo hacer visible la denicin

de la estructura, debemos agregar un bloque especial en la forma

(provide ... (struct-out estructura) ... ) estructura?, estructura-campo1,

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

representa un ujo de entrada o de salida, como un archivo, una

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.

15.1. Imprimir datos


En Scheme hay dos formas de imprimir valores de tipos primitivos:

write.

Esta funcin imprime un valor en la misma manera en que este se representa

en el lenguaje, que es la misma forma en que se muestran los valores en el entorno interactivo.

display.

Esta funcin tiende a reducir un valor a su representacin de bytes o de

caracter. Es una forma muy legible de mostrar los datos, pero es menos precisa sobre el tipo de dato que se muestra.

He aqu algunas comparaciones sobre el comportamiento de ambas:

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

15.2 Leer datos


Resumiendo:

~a -> display ~s -> write

15.2. Leer datos


Existen muchos mecanismos para leer datos en Scheme. De hecho,  el lector de Scheme (

Reader ),

es un

analizador lxico y sintctico desdendente recursivo,

The

es decir, un programa

procesador bastante avanzado.

15.2.1. Lectura "bsica"


Existen siertas funciones bsicas, muy tpicas de un lenguaje de alto nivel como Scheme. En todos los siguientes casos, el puerto de lectura/entrada es opcional, y su valor por defecto es la entrada estndar (o, lo que es lo mismo, lo que devuelve la funcin que se explica ms adelante, en la seccin 15.4):

(current-input-port)

(read-char {<entrada>}? ):
por defecto es

UTF-8.

Lee un caracter en la codicacin de  el lector , que

(read-byte {<entrada>}? ):

Lee un byte, es decir, un cdigo

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

comportamiento correcto en sistemas Macintosh.

'return-linefeed interpreta el n de lnea cuando encuentra la secuencia \r\n.


Este es el comportamiento correcto en sistemas Windows.

'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.

(read-string <cuenta> {<entrada>}? ):


caracteres.

Lee una cadena de a lo sumo

<cuenta>

(read-bytes <cuenta> {<entrada>}? ): <cuenta> bytes.

Lee una cadena de bytes de a lo sumo

113

15 Entrada y Salida
En todos los casos, pueden devolver el objeto especial

eof-object?.

eof

que se verica con la funcin

La devolucin de este valor, indica que se alcanz el n del ujo.

Los ejemplos se presentan en la pgina 117.

15.2.2. Lectura avanzada


Se dispone de la funcin

(read {<entrada>}? )
La funcin

read

que tiene la sintaxis:

read por defecto lee un {, },

dato de los tipos nativos de Scheme en un slo paso. El

ujo del cual lee la funcin, debe seguir cierta sintaxis :

(, [ ), ]  ;

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

.

#t, #T, #f #(, #[ #\ # #: #|


o

#F,

se convierten en los respectivos valores booleanos.

#{,

indican el inicio de vectores.

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.

inicia un nmero inexacto, exacto,

hexadecimal, octal, decimal o binario, respectivamente.

, y ` y otros smbolos y combinaciones tienen otros signicados ms all del objetivo


de este libro.

#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

15.3 Tipos de Puerto


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

> ( 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

The Reader (http://docs.racket-lang.org/reference/reader.html) de

la documentacin ocial de Racket para ms detalles.

15.3. Tipos de Puerto


En cada caso, es necesario

abrir

los puertos para poder transmitir (leer o escribir) datos

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.

Tambin hay otras funciones que operan sobre puertos:

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.

que verica si el parmetro indicado es un puerto de entrada/lectura o sali-

port-closed?

que verica si un puerto est cerrado.

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

fuerza el vaciado del buer hacia el dispositivo de escritura.

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

15.3 Tipos de Puerto


'can-update
existe. abre el archivo sin truncarlo (es decir, sin borrarlo), o lo crea si no

'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:

$ racket lee-lneas.rkt <archivo>

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-input-file <ruta> <procedimiento> {#:mode { 'binary | 'text } }? )


y

(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>

es la ruta y nombre de un archivo, y

<procedimiento>

debe ser

una funcin que reciba como nico parmetro obligatorio un puerto de entrada o de salida,

<ruta>

utilizando el modo y comportamiento

<procedimiento>

pasndole como parmetro

<procedimiento>

naliza, se cierra el puerto correspondiente.

4. Finalmente, el resultado de o

<procedimiento> es el resultado de call-with-input-file call-with-output-file.

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:

la logstica de abrir el ujo, lo cual

1 2

# lang racket ; lee - lneas2 . rkt

118

15.3 Tipos de Puerto


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

( 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

get-output-string toma un puerto de salida de cadena y devuelve el contenido

en forma de cadena.

15.3.3. Conexiones TCP


Con Racket se pueden realizar conexiones TCP con gran facilidad. Bsicamente se utilizan tres funciones:

tcp-listen que abre un puerto de la computadora servidor para escuchar


iones que lleguen por ah.

las conex-

tcp-accept tcp-close
Ejemplo:

para que un servidor

acepte

conexiones provenientes de un cliente.

tcp-connect

para que un cliente solicite una conexin con un servidor.

para terminar una escucha de puerto, es la contraparte de

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

15.3 Tipos de Puerto


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

( 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 )

15.4. Puertos de Entrada/Salida por defecto


Hasta ahora, se han utilizado las funciones y predeterminados:

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)

devuelve el puerto de salida estndar de error.

Para cambiar los puertos por defecto, se pueden usar estas mismas funciones con un parmetro puerto:

122

15.4 Puertos de Entrada/Salida por defecto


(current-input-port <p>) (current-error-port <p>)
cambia el puerto de entrada estndar a cambia el puerto de salida estndar a

<p>. <p>. <p>.

(current-output-port <p>)

cambia el puerto de salida estndar de error a

123

15 Entrada y Salida

124

Ejercicios de Entrada y Salida


1. Dado como parmetro el nombre de un archivo, elaborar un programa que elimine del archivo todas las letras  a . 2. Haga una variante del ejercicio anterior en el que esta vez dado de parmetro el nombre del archivo y dos caracteres, el primer carcter se buscar para ser sustituido por el segundo carcter en todo el archivo. 3. Elaborar una funcin que reciba de parmetro el nombre de un archivo y que retorne el nmero de lneas que este archivo tiene. Si el archivo no existe retornar -1. 4. Hacer un programa que dado como parmetro el nombre de un archivo de texto, aplicarle una suerte de encriptamiento, en el que cada carcter en posicin par, se almacene en un archivo llamado  par.txt y cada carcter en posicin impar se almacenara en un archivo llamado  impar.txt , el archivo original ser eliminado quedando slo los dos archivos resultantes. 5. Haga un programa que desencripte un archivo encriptado con el algoritmo del ejercicio anterior, dados los archivos  par.txt e  impar.txt . 6. Elaborar una funcin de encriptamiento en el que dado de parmetro el nombre de un archivo de texto, sumarle a cada carcter en posicin par dos caracteres, y a cada carcter en posicin impar sumarle tres posiciones. Por ejemplo, si el carcter est en posicin par, se deber sustituir por el carcter

#\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

construya una funcin que ingrese 5 instancias de

en un archivo llamado  registro.txt , una estructura por lnea. Si el archivo

no existe retornar un mensaje de error. 10. Construya una funcin que retorne informacin alguna.

#t

si un archivo llamado  informacin.txt existe

y tiene contenido, es decir que no est vaco, y

#f en caso de que no exista o no tenga

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

lanza una excepcin. Y a atrapada , se gestionar imprimiendo en la salida estndar de

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

16.1. Atrapar Excepciones


Para

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).

nivel superior la atrape (talvez). Todas las funciones

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 "

16.2. Las funciones error y raise


La funcin

error

es una manera de crear su propia excepcin, ya que toma una cadena de

texto como parmetro, y la encapsula en una estructura de tipo

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

que no se apeguen a esta

costumbre.

pero en Scheme, podemos

raise

nos permite lanzar cualquier objeto o valor como una excepcin:

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

16.2 Las funciones error y raise


8 9

( raise " otro error ") ) La excepcin es una cadena

129

16 Excepciones

130

17 Evaluacin Dinmica de Cdigo


Scheme es un lenguaje de programacin

dinmico,

ya que ofrece muchas facilidades para

cargar, compilar y hasta construr nuevo cdigo en tiempo de ejecucin.

17.1. La funcin eval


La funcin un caracter apstrofo ' ) y la evala. Otra forma de describir el parmetro es como una lista de identicadores y otros valores primitivos. Por ejemplo:

eval

toma una expresin 

apostrofada 

(es decir, una expresin precedida por

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

17 Evaluacin Dinmica de Cdigo

17.2. Creacin y ejecucin dinmica de cdigo fuente


Puede utilizarse la funcin presentan tres ejemplos:

eval

read

para convertir dinmicamente una cadena con una

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

18 Programacin Orientada a Objetos


En este libro no se abordarn los conceptos relacionados con el paradigma de Programacin Orientada a Objetos, sino que se aborda cmo implementar tal programacin en Scheme.

18.1. Denicin de Clases


De la misma forma que un bloque

class que es una clase sin nombre. Su sintaxis es: ( class <superclase> <declaracin-o-expresin>* )
Y al igual que podemos utilizar

lambda es un procedimiento sin nombre, existe el bloque

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 %.

18.2. Denicin de Interfaces


En Scheme, las interfaces se denen as:

( interface (<superinterface>*) <identificador>* )


Donde

<identificador>

es un identicador que deber ser provisto como pblico por la

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

class*: ( class* <superclase> (<interface>*) <declaracin-o-expresin>* )

18.3. Creacin de instancias


new: (new <nombre-clase> <parmetro-de-inicializacin>* )
Para crear una instancia de una clase se utiliza el bloque

133

18 Programacin Orientada a Objetos


Tambin podra utilizarse en la forma:

(new (class ...) <parmetro-de-inicializacin>* ), pero sera poco legible y slo se


prodra crear una instancia de esa clase. Aunque si slo se crear una instancia de la clase, esta forma es conveniente, igual que usar vez. La forma de

lambda

para funciones que slo se invocarn una

<parmetro-de-inicializacin>

se describe en la seccin 18.5.

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 (<nombre-mtodo> <parmetros>* ) <exp-cuerpo>* )


Este bloque

define/public

es una forma abreviada de:

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

(igual que el bloque

provide

para hacer

visibles o pblicos
send:

ciertos identicadores

de los mdulos). Para invocar un mtodo de un objeto, se utiliza el bloque

(send <instancia> <nombre-mtodo> <parmetros>* )

18.4.2. Sustitucin de mtodos


En algunos casos, una clase hija debe redenir mtodos de clase. Esto se hace con el bloque

define/override: (define/override (<nombre-mtodo> <parmetros>* ) <exp-cuerpo>* )


Este bloque

define/override

es una forma abreviada de:

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

18.5 Parmetros de inicializacin

18.4.3. Mtodos no sustitubles


En algunos casos, una clase debe (re)denir mtodos de clase que no puedan ser

breescritos

por sus descendientes. Esto se hace con los bloques

define/override-final
heredado):

define/public-final

soy

(dependiendo de si es un mtodo nuevo en la clase actual o uno

(define/public-final (<nombre-mtodo> <parmetros>* ) <exp-cuerpo>* ) (define/override-final (<nombre-mtodo> <parmetros>* ) <exp-cuerpo>* )


Ambos bloques

define/public-final y define/override-final respectivamente son for-

mas abreviadas de:

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

de funciones que no podrn ser

sobreescritos

sirven para indicar todos los identicadores

en las clases descendientes de esta.

18.5. Parmetros de inicializacin


Para indicar que la inicializacin de una instancia de una clase requiere parmetros, se utiliza el bloque

init

dentro de la denicin de la clase:

( class < superclase > < declaracin -o - expresin >* ( init < parmetro - formal >* ) < declaracin -o - expresin >* )
donde:

<parmetro-formal> ::= <identificador> | [<identificador> <exp-valor-por-defecto>]


Para crear una instancia y pasarle los parmetros correspondientes, se utiliza el mismo

new, pero pasando los parmetros con sus respectivos nombres de parmetro formal: (new <nombre-clase> <parmetro-real>* )
bloque donde:

<parmetro-real> ::= [<identificador> <valor>]

135

18 Programacin Orientada a Objetos

Supongamos que una clase clase de

dene sus parmetros de inicializacin (tiene su

no dene parmetros de inicializacin (no tiene

puede llevar los parmetros indicados en

cuando en

se encuentre la llamada a

A y estos (super-new).

init).

init),

y una

Entonces la instanciacin

sern pasados al inicializador de

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>* )

18.6. Funciones que operan sobre clases/interfaces/objetos


object? class?
toma un valor y verica si es un objeto o no. toma un valor y verica si es una clase o no. toma un valor y verica si es una clase o no.

interface? object=?
la clase.

toma dos objetos y verica si son el mismo.

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?

toma un valor y una clase o interface, y verica si el valor es una instancia

de la clase, o si el valor es una instacia de alguna clase que implemente la interface proporcionada.

subclass?

toma un valor y una clase, y verica si el valor es una clase derivada de

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?

toma un valor y una interface y verica si el valor es

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

toma una interface y devuelve una lista de smbolos que

indican los nombres de los miembros de la interface y de sus ancestros.

object-method-arity-includes?

toma un objeto, un smbolo y un entero positivo

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 ) ) ) )

Ejemplos de interaccin con la clase

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

18 Programacin Orientada a Objetos


13 14 15 16 17 18 19

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 ) ) ) ) )

Ejemplos de interaccin con la clase

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

> 0 > > 1 > 9 > 0 > >

( 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

18 Programacin Orientada a Objetos

140

Parte IV

Interfaces Grcas de Usuario

141

19 Introduccin a las interfaces grcas de usuario con Racket


A continuacin se describen algunos tpicos bsicos sobre interfces grcas de usuario en Racket. Para poder usar interfaces grcas de usuario en Racket, es necesario agregar el mdulo

gui, con la lnea: (require racket/gui)


En ese mdulo est denida la jerarqua de clases, y las clases, del modelo de interfaces de Racket.

19.1. Hola Mundo

Figura 19.1: hola-mundo.rkt

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

19 Introduccin a las interfaces grcas de usuario con Racket

19.2. Ejecucin y compilacin


Para ejecutar el programa anterior y cualquier otro programa Racket desde lnea de comandos que incluya interfaces grcas de usuario, debe usarse el comando

racket tradicional: $ gracket hola-mundo.rkt $ raco exe -o ejecutable --gui hola-mundo.rkt

gracket en lugar del

Y para compilar, hay que incluir la opcin - -gui en la lnea de compilacin:

19.3. Introduccin a los eventos

Figura 19.2: eventos-1.rkt

Existen varios mecanismos para manejar eventos. Entre ellos, algunos objetos, permiten indicar un procedimiento de

callback

que se ejecutar cuando el evento suceda.

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

19.3 Introduccin a los eventos


18 19 20 21 22

( send mensaje set - label " sencillos :) ") )

( send ventana show # t )

Figura 19.3: eventos-2.rkt

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

19 Introduccin a las interfaces grcas de usuario con Racket


30 31 32 33 34 35

( send ventana show # t )

Figura 19.4: eventos-3.rkt Una misma funcin de

callback

se puede usar para procesar varios eventos:

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

19.4 Ventanas de dilogo


24 25 26 27 28 29

[ parent ventana ] [ label " Botn 2"] [ callback funcin - manejadora ] )) ( send ventana show # t )

19.4. Ventanas de dilogo

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

19 Introduccin a las interfaces grcas de usuario con Racket


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

))

)]

( 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 )

19.5. Eventos de cuadros de texto

Figura 19.6: text-eld.rkt

1 2 3

# lang racket ; text - field . rkt

148

19.5 Eventos de cuadros de texto


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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

( 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

19 Introduccin a las interfaces grcas de usuario con Racket


54 55 56 57 58 59

[ parent ventana ] [ callback ( lambda ( b c ) ( send ventana show # f ) ) ]) ) ( send ventana show # t )

19.6. Pneles

Figura 19.7: pneles.rkt

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

19 Introduccin a las interfaces grcas de usuario con Racket

152

20 Uso de los diversos controles de Racket

Figura 20.1: controles.rkt, tab 1

Figura 20.2: controles.rkt, tab 2

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

20 Uso de los diversos controles de Racket

Figura 20.3: controles.rkt, tab 3

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

Figura 20.4: controles.rkt, tab 4

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

( define ( define ( define ( define ( define ( define ( define

panel0 panel1 panel2 panel3 panel4 panel5 panel6

( new ( new ( new ( new ( new ( new ( new

vertical - panel % vertical - panel % vertical - panel % vertical - panel % vertical - panel % vertical - panel % vertical - panel %

[ parent [ parent [ parent [ parent [ parent [ parent [ parent

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

20 Uso de los diversos controles de Racket

Figura 20.5: controles.rkt, tab 5

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

Figura 20.6: controles.rkt, tab 6

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

20 Uso de los diversos controles de Racket

Figura 20.7: controles.rkt, tab 7

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

20 Uso de los diversos controles de Racket


193 194 195 196 197 198 199 200 201 202 203 204 205 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

( 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

20 Uso de los diversos controles de Racket


291 292 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 324 325 326 327 328 329 330 331 332

( 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

21 Dibujo con Lienzos


21.1. Dibujo en un canvas %

Figura 21.1: canvas1.rkt

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

21 Dibujo con Lienzos


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 60

)) ; 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

21.2 Interaccin avanzada con canvas %


61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77

( 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 )

21.2. Interaccin avanzada con canvas %

Figura 21.2: canvas2.rkt

1 2 3 4

# lang racket ; canvas2 . rkt ( require racket / gui )

165

21 Dibujo con Lienzos


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 37 38 39 40 41 42 43 44

( 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

21.2 Interaccin avanzada con canvas %

Figura 21.3: canvas3.rkt

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

21 Dibujo con Lienzos


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

))

) ( 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

21.2 Interaccin avanzada con canvas %

Figura 21.4: canvas4.rkt

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

21 Dibujo con Lienzos


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 82 83 84 85 86 87 88 89 90 91 92 93 94 95

))

( 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

Figura 22.1: Diagrama de clases de los mens en Racket

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

Figura 22.2: Diagrama de objetos del ejemplo 1-mens.rkt

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

Figura 22.3: 1-mens.rkt

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

))

( send ventana show # f ) )]

( 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 )

22.1. Ejemplo de editor sencillo de texto


1 2 3 4 5 6 7 8 9 10 11

# 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

22.1 Ejemplo de editor sencillo de texto


12 13 14 15 16 17 18 19 20 21

( 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 ) )

Figura 22.4: 2-mens.rkt

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

22.2 Mens contextuales


60 61 62 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

[ 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 )

22.2. Mens contextuales


1 2 3 4 5 6 7 8 9 10 11 12 13 14

# 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

22.2 Mens contextuales

Figura 22.5: 5-seleccin-color.rkt - men

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

Figura 22.6: 5-seleccin-color.rkt - Selector de color 1

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

22.2 Mens contextuales

Figura 22.7: 5-seleccin-color.rkt- Selector de color 2

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 )

( send dc set - pen lpiz - slido ) )]

182

23 Proyecto: Minipaint

Figura 23.1: mini-paint.rkt

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

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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106

( 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 ) )

))

( define frame - hijo %

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

Ejercicios de Interfaces Grcas de Usuario


1. Elaborar un programa que muestre una ventana que contenga una etiqueta, pidiendo el nombre de una persona y una caja de texto donde se escribir el nombre, y un botn  enviar cuando se presione el botn, se crear una segunda ventana mostrando un saludo unido con el nombre que fue escrito en la primer ventana y un botn  regresar . Cuando la segunda ventana se cree ella tendr el foco y la primer ventana no se podr acceder, a menos que se presione el botn  regresar de la segunda ventana, que cerrar la ventana dos y de nuevo estar habilitada la primer ventana. 2. Elaborar un programa que muestre una ventana que tenga como nombre  Encriptamiento de cadenas , esta ventana tendr una caja de texto que diga que debe de ingresar una cadena, una segunda caja de texto que diga cadena encriptada, y tres botones, el primer botn  Encriptar que al ser presionado encriptar la cadena ingresada en la primer caja de texto y la mostrar en la segunda caja de texto, si al presionar el botn de  Encriptar la primera caja de texto esta vaca, mostrar un ventana que indique que la caja de texto esta vaca. El segundo botn  Limpiar borrar la informacin que est en ambas cajas de texto. Y el botn  Salir que terminar el programa. 3. Elaborar un programa que muestre una ventana que contenga al lado izquierdo una caja de texto con una etiqueta  agregar hijo y un botn  agregar y del lado derecho de la ventana una lista que originalmente est vaca, al escribir una cadena en la caja de texto y al presionar el botn, la cadena que fue escrita en la caja de texto se agregar a la lista del lado derecho de la ventana, quitando la informacin de la caja de texto, dejndola preparada para un nuevo valor, se debe validar que si la caja de texto est vaca no se podr agregar algo a la lista, esta validacin se har mostrando una ventana que lo indique. 4. Elaborar un programa que muestre una ventana que contenga como ttulo  Cargar imagen , y un botn que diga  Cargar este botn abrir un cuadro de dilogo, para poder buscar archivos de imgenes, seleccionar una imagen y al abrirla, abrir una nueva ventana, donde se muestre la imagen seleccionada, y junto a un botn de regresar, que regresar a la ventana inicial. 5. Elaborar un programa que muestre una ventana que contenga una barra de mens, con el men Archivo, que contendr como hijos: nuevo, abrir, guardar y salir. La ventana

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

A Diferencias entre PLT Scheme y Racket


Las diferencias radican en lo siguiente: 1.

Racket

es el nuevo nombre de

PLT Scheme,

comenzando con la versin 5.0. Lo que

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.

Con Racket ahora se

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

#lang scheme, drracket. racket.


en lugar de

en lugar de

#lang racket

como en Racket. (y se llama

4. El ejecutable de DrRacket en versiones anteriores a la 5.0 es DrScheme) en lugar de

drscheme

5. El ejecutable de la herramienta de consola de Racket en versiones anteriores a la 5.0 es

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

7. La compilacin con PLT Scheme se realiza con el comando

$ mzc --exe <nom-ejecutable> <archivo-fuente>.ss


para programas sin interfaz grca, y con:

raco:

$ mzc --gui-exe <nom-ejecutable> <archivo-fuente>.ss


para programas con interfaz grca. 8. En PLT Scheme, el mdulo de interfaces grcas de usuario se llama Para mayor informacin sobre el cambio de nombre, rerase al sitio: http://racket-lang.org/new-name.html. -

scheme/gui.

199

A Diferencias entre PLT Scheme y Racket

200

Bibliografa
[1] http://docs.racket-lang.org/ (2009-2010) -

Sitio de documentacin ocial de Racket, por How to Design Programs (An Introduction to

la Comunidad de desarrolladores de Racket (http://racket-lang.org/people.html). [2] http://www.htdp.org/2003-09-26/Book/ -

Computing and Programming), por Matthias Felleisen, Robert Bruce Findler, Matthew
Flatt, Shriram Krishnamurthi. The MIT Press, Massachusetts Institute of Technology.

201

Vous aimerez peut-être aussi