Está en la página 1de 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

de la

Universidad Centroamericana Jos Simen Caas,


El Salvador, Centroamrica.

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

17

1. Programacin Funcional

19

1.1.

Objetivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

19

1.2.

Caractersticas

20

1.3.

Lenguajes de Programacin Funcionales

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

20

1.4.

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

21

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

2. Instalacin de Racket

23

2.1.

Instalacin con el instalador ocial

2.2.

Instalacin desde repositorios

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

23

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

24

2.2.1.

Debian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

24

2.2.2.

Fedora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

25

3. Expresiones Racket - Notacin Preja

27

3.1.

Notacin para la sintaxis de Racket . . . . . . . . . . . . . . . . . . . . . . .

27

3.2.

Notacin preja de Racket . . . . . . . . . . . . . . . . . . . . . . . . . . . .

27

4. Interaccin con Racket


4.1.

4.2.

29

Ejecucin interactiva . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29

4.1.1.

Deniciones e interacciones con DrRacket

4.1.2.

Ejecucin interactiva con Racket

Ejecucin no interactiva
4.2.1.

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

30

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

30

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

31

Parmetros de la lnea de comandos

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

5. Compilacin de programas Racket

31

33

5.1.

Lo bsico sobre compilacin . . . . . . . . . . . . . . . . . . . . . . . . . . .

33

5.2.

Compilacin con mltiples mdulos . . . . . . . . . . . . . . . . . . . . . . .

33

II. Introduccin al lenguaje Racket

35

6. Elementos bsicos

37

6.1.

Comentarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

37

ndice general
6.2.

Deniciones Globales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

37

6.2.1.

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

38

6.3.

Llamadas a funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39

6.4.

Bloques condicionales

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

39

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

39

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

40

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

41

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

42

6.4.1.
6.4.2.
6.4.3.
6.4.4.

Identicadores

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

6.5.

Bloques de cdigo secuencial . . . . . . . . . . . . . . . . . . . . . . . . . . .

43

6.6.

Ms sobre llamadas a funciones . . . . . . . . . . . . . . . . . . . . . . . . .

43

7. Funciones annimas - Bloques lambda


lambda

45

7.1.

Bloques

7.2.

Funciones/Expresiones que producen funciones

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

8. Asignacin local
8.1.
8.2.
8.3.

define
let . .
let* .

45
46

49

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

49

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

50

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

50

III. Elementos del lenguaje

51

9. Listas e Iteracin

53

9.1.

9.2.

Listas

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

53

9.1.1.

Lista vaca o nula . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

54

9.1.2.

Funciones bsicas sobre listas

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

54

Iteracin automtica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

56

9.2.4.

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

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

58

9.2.5.

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

59

9.2.1.
9.2.2.
9.2.3.

9.3.

Iteracin manual
9.3.1.

9.4.

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

56

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

56

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

57

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

59

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

60

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

61

9.4.1.

Pares y listas

Convencin de impresin . . . . . . . . . . . . . . . . . . . . . . . . .

62

9.4.2.

Notacin inja

62

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

10.Recursin

10

67

10.1. Recursin por Posposicin de trabajo . . . . . . . . . . . . . . . . . . . . . .

67

10.2. Recursin de Cola

67

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

ndice general

11.Tipos de dato integrados del lenguaje

69

11.1. Booleanos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

69

11.2. Nmeros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

70

11.2.1. Clasicacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

70

Clasicacin por Exactitud

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

70

Clasicacin por Conjuntos

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

72

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

72

11.2.2. Otras bases

11.2.3. Comparaciones

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

73

11.2.4. Constantes especiales . . . . . . . . . . . . . . . . . . . . . . . . . . .

73

11.3. Caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

74

11.4. Cadenas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

76

11.4.1. Cadenas mutables

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

11.4.2. Comparacin entre cadenas

77

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

78

11.4.3. Otras funciones de cadena . . . . . . . . . . . . . . . . . . . . . . . .

79

11.5. Bytes y Cadenas de Bytes . . . . . . . . . . . . . . . . . . . . . . . . . . . .

80

11.6. Smbolos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

81

11.7. Palabras clave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

83

11.8. Pares y listas

83

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

11.9. Vectores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

84

11.10.Tablas Hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

85

11.11.Void

86

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

12.Expresiones y Deniciones Avanzadas


apply
lambda .

89

12.1. La funcin

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

89

12.2. Bloques

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

89

12.2.1. Funciones con cualquier nmero de parmetros

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

90

. . . . . . . . . . .

90

12.2.3. Funciones con parmetros opcionales . . . . . . . . . . . . . . . . . .

91

12.2.4. Funciones con parmetros con nombre

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

92

12.2.5. Funciones con aridad mltiple . . . . . . . . . . . . . . . . . . . . . .

93

12.2.2. Funciones con un mnimo nmero de parmetros

12.2.6. Consultando la aridad de las funciones . . . . . . . . . . . . . . . . .

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

94

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

94

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

95

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


12.3.1.
12.3.2.
12.3.3.

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

12.4. Asignaciones

94

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

96

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

97

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

97

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

97

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

98

13.Tipos de dato denidos por el programador


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

101
101

11

ndice general
13.2. Estructuras derivadas

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

102

13.3. Estructuras transparentes y opacas . . . . . . . . . . . . . . . . . . . . . . .

104

13.4. Estructuras mutables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

104

14.Mdulos Funcionales

109

14.1. Visibilizando deniciones de estructuras

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

15.Entrada y Salida
15.1. Imprimir datos

111
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

111

15.2. Leer datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

113

15.2.1. Lectura "bsica"

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

113

15.2.2. Lectura avanzada . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

114

15.3. Tipos de Puerto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

115

15.3.1. Archivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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

116

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

116

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

116

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

117

Ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

117

Procesamiento automatizado

118

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

15.3.2. Cadenas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

119

15.3.3. Conexiones TCP

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

120

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

122

16.Excepciones

127

16.1. Atrapar Excepciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

127

16.2. Las funciones error y raise . . . . . . . . . . . . . . . . . . . . . . . . . . . .

128

17.Evaluacin Dinmica de Cdigo


17.1. La funcin

eval

131

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

17.2. Creacin y ejecucin dinmica de cdigo fuente

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

18.Programacin Orientada a Objetos


18.1. Denicin de Clases

12

110

131
132

133

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

133

18.2. Denicin de Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

133

18.3. Creacin de instancias

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

133

18.4. Mtodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

134

18.4.1. Denicin e Invocacin de Mtodos . . . . . . . . . . . . . . . . . . .

134

18.4.2. Sustitucin de mtodos

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

134

18.4.3. Mtodos no sustitubles

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

135

18.5. Parmetros de inicializacin . . . . . . . . . . . . . . . . . . . . . . . . . . .

135

18.6. Funciones que operan sobre clases/interfaces/objetos . . . . . . . . . . . . .

136

18.7. Ejemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

137

ndice general

IV. Interfaces Grcas de Usuario

141

19.Introduccin a las interfaces grcas de usuario con Racket

143

19.1. Hola Mundo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


19.2. Ejecucin y compilacin

143

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

144

19.3. Introduccin a los eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . .

144

19.4. Ventanas de dilogo

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

147

19.5. Eventos de cuadros de texto . . . . . . . . . . . . . . . . . . . . . . . . . . .

148

19.6. Pneles

150

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

20.Uso de los diversos controles de Racket

153

21.Dibujo con Lienzos

163

21.1. Dibujo en un

canvas %

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

163

canvas %

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

22.1. Ejemplo de editor sencillo de texto

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

174

22.2. Mens contextuales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

177

21.2. Interaccin avanzada con

22.Mens

165

171

23.Proyecto: Minipaint

183

V. Apndices

197

A. Diferencias entre PLT Scheme y Racket

199

13

ndice general

14

ndice de guras
2.1.

6.1.

Sitio de descarga de Racket

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

Grca de ecuacin seccionada

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

2
x + 1 0 x

24

. . . . . . .

41

19.1. hola-mundo.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

143

19.2. eventos-1.rkt

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

144

19.3. eventos-2.rkt

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

145

19.4. eventos-3.rkt

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

146

19.5. dialogo.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

147

19.6. text-eld.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

148

19.7. pneles.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

150

20.1. controles.rkt, tab 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

153

20.2. controles.rkt, tab 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

153

20.3. controles.rkt, tab 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

154

20.4. controles.rkt, tab 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

155

20.5. controles.rkt, tab 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

156

20.6. controles.rkt, tab 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

157

20.7. controles.rkt, tab 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

158

21.1. canvas1.rkt

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

163

21.2. canvas2.rkt

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

165

21.3. canvas3.rkt

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

167

21.4. canvas4.rkt

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

169

22.1. Diagrama de clases de los mens en Racket

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

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

171

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

172

22.3. 1-mens.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

173

22.4. 2-mens.rkt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

175

22.5. 5-seleccin-color.rkt - men

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

179

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

180

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

181

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

15

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

16

183

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

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

C:

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

14

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

variable_contador representa el estado del

programa.

1.2. Caractersticas
Los programas escritos en un lenguaje funcional estn constituidos nicamente por deniciones de funciones, entendiendo stas, no como subprogramas clsicos de un lenguaje
imperativo, sino como funciones puramente matemticas, en las que se verican ciertas

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 parmetpropiedades como la

ros 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 ,

22

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]

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

/usr/plt,

para la cual

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


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/share/doc/plt,

/usr/plt/doc/.

/usr/share/plt,
index.html.

En esta carpeta habr un archivo

En todo caso, con el comando

$ raco docs
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


2

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

PLT Scheme

(que es completamente

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

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

llamada

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


distribucin de GNU/Linux que contiene a

PLT Scheme

en sus repositorios.

2.2.1. Debian
En distribuciones basadas en

Debian, basta con instalar el paquete plt-scheme:

# apt-get install plt-scheme

Tambin sera buena idea, instalar el paquete

plt-scheme-doc que instala la documentacin

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

2
3

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

Al momento de escribir este libro


vase el apndice A

24

que es el ndice de la documentacin.

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

Fedora, basta con instalar el paquete plt-scheme:

# yum install 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.

El metaagrupamiento se hace con llaves:

}.

El metasmbolo

+,

indica al menos una ocurrencia del smbolo precedente.

El metasmbolo

*,

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)

Por ejemplo, la expresin inja

5a + 2bc2

es:

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

racket

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

cin y compilacin).
En el caso de

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

que este Entorno se acomoda a diversas variantes de Scheme soportadas por el intrprete

racket.

y compilador

En nuestro caso particular, usaremos la opcin Usar el lenguaje

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

racket),

el lenguaje

por omisin es esta variante.

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

substring,

con tres parmetros:

una cadena, y dos nmeros enteros.

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,

archivo (por convencin, con extensin

primero hay que guardar las deniciones en un

.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

567

cuando se ejecute.

Para ejecutarlo, vaya la lnea de comandos:

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

current-command-line-arguments que retorna un

vector inmutable de cadenas inmutables, una por cada parmetro. Por ejemplo, considere
el siguiente programa:

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

raco que es la herramienta de compilacin de


$ raco --help.

Racket. Puede obtener una breve descripcin de todas sus posiblidades con

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

#|

|#.

y los comentarios de bloque son

Ejemplo:

1
2
3
4
5
6
7
8

# lang racket
; Todos los programas Racket deben comenzar con esta lnea de arriba .
#|

Este es un comentario en Racket ,


que tiene varias lneas .

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

evaluar

<expresin>.

Una denicin de la forma

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

variable-con-guiones, variable+con+ms-y-t
123abc, +-, variable-interrogativa???,  23..4,  variable/dividida, etc.
Por lo dems, se pueden utilizar identicadores como

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 eho
san
go-
ciu
aude-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)

Racket dene muchas funciones integradas del lenguaje. Por ejemplo

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

(hornear

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
y

or

y retorna

#t

En Racket, las funciones lgicas de conjuncin y disyuncin, son respectivamente


y su sintaxis es:

(and <expresin>*)

La primera retorna

#f

#t

y retorna

#f

(or <expresin>*).

si encuentra que uno de sus parmetros se evala a

en caso contrario. La segunda retorna


a

#t

#f,

and

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

10
11
12

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

2
x + 1 0 x

" 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

> ( define ( seccionada x )


( cond [( < x -1)
(+ x 2) ]
[( and ( >= x -1) ( < x 0) )
1]
[( >= x 0)
(+ ( - ( sqr x ) ) 1) ]) )

>

19
20
21
22
23
24
25

28
29
30
31
32
33
34

; -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 ?"]) )

18

27

x < -1: x +2

> ( seccionada -4)


-2
> ( seccionada -.5)
1
> ( seccionada 1)
0

17

26

> ( responder - ms
" No s "
> ( responder - ms
" hola , gusto de
> ( responder - ms
" perdn , qu ?"
> ( responder - ms
" nos vemos , que

" hoy ?")


" hola pepe ")
verte !"
" la derivada de la funcin exponencial es ella misma ")
" adis programa ")
te vaya bien !"

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

secuencia de instrucciones,

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


est presente de manera nativa en los bloques
y

let,

dispone del bloque

1
2
3
4
5
6
7
8
9
10

lambda, define (para funciones), cond, case

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

begin:

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

lambda

Considere la siguiente expresin:

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

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.

Pero suponga que la funcin

7.1. Bloques lambda


En Racket as como en muchos otros lenguajes de programacin, un

bloque lambda

produce una funcin directamente, sin tener que declararla.


El bloque lambda tiene la siguiente sintaxis:

(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

1
2

2
3
4

produce en s misma una funcin:

> ( lambda ( s ) ( string - append " " s "!") )


# < procedure >
Entonces, usando

lambda,

lambda.

lambda,

la llamada a componer puede ser reescrita como:

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

lambda

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

ciones:

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

lambda a un identicador. Las siguientes

dos deniciones son equivalentes:

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

define

let

se pueden hacer mltiples

para cada asignacin.

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

La sintaxis de

Cada clusula de asignacin es un

<identificador>

y una

<expresin>

rodeadas por

corchetes, y las expresiones que van despus de las clusulas, son el cuerpo del
cada clusula, al

<identificador>

se le asigna el resultado de la

usado dentro del cuerpo. Fuera del bloque

let,

<expresin>

let.

En

para ser

los identicadores no son visibles.

Por ejemplo:

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

let estn disponibles slo en el cuerpo del let, as que las clusulas de
let*, por el contrario, permite que

asignacin no se pueden referir unas a otras. El bloque


clusulas posteriores, referencien clusulas anteriores:

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

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

list:

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

Con la constante especial

empty

Con la constante especial

null

Con la forma tradicional de Lisp:

'()

(list)

, que es un caracter de apstrofe seguido de

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

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

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

Ejemplos:

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

> '()
()
> empty
()
> null
()
> ( list )
()
> (( lambda ( L ) ( if ( empty ? L ) " vaca " " no vaca ") ) null )
" vaca "
> (( lambda ( L ) ( if ( empty ? L ) " vaca " " no vaca ") ) '() )
" vaca "
> (( lambda ( L ) ( if ( null ? L ) " vaca " " no vaca ") ) empty )
" vaca "
> (( lambda ( L ) ( if ( null ? L ) " vaca " " no vaca ") ) '(" a ") )
" no vaca "

9.1.2. Funciones bsicas sobre listas


length

para vericar la longitud de una lista

list-ref

para extraer el i-simo elemento de una lista (los ndices comienzan desde

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

54

9.1 Listas
append

para unir listas

reverse
member
list?

para invertir el orden de una lista

para vericar si un elemento est en una lista

para vericar si un identicador se corresponde con una lista (que puede estar

vaca)

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

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

propias de los lenguajes funcionales, para recorrer y procesar secuencias (listas) de elementos.

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

andmap

ormap.

En sus formas

ms simples, ambas toman como parmetros una funcin y una lista. En el caso de la

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

primera, retorna

#t;

y devuelve

La funcin

ormap

es

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

de conjuncin, que es lo que aplica

andmap. ormap

devuelve

#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
lista - nmeros )
" Esta funcin espera una lista de nmeros "
)))

22
23
24
25
26
27
28
29
30
31
32
33

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

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

for-each:

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

funcin sobre los elementos de la lista. Con

ignora el resultado de las evaluaciones de la

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

first

ms primitivos

como los siguientes:

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

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?)
Ejemplos:

1
2
3
4
5

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

En el caso que como segundo argumento se le pase algo que no sea una lista, la funcin
cons devuelve un

Un Par

Par

Pareja.

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)

cons? con ms sentido para los pares: pair?. Tambin hay


first y rest para pares: car y cdr. Estas ltimas funcionan

Hay una funcin equivalente a


funciones correspondientes a

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

#f

x 1, y 2)

retornar

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

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

hola

se con-

'(h o l a). Note que no se piden los caracteres si no las letras en

forma de cadena.
17. Dada una lista compuesta por cadenas, ordenar dicha lista tomando como criterio la
longitud de las cadenas (No usar

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,

1
2
3
4
5
6
7
8

->
=
=
=
=
=
=
=

(longitud (list a b c))

se da este proceso:

( 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

1
2
3
4
5

longitud

con recursin de cola:

( define ( longitud L )
; funcin local longitud - aux :
( define ( longitud - aux L longitud - actual )
( cond
[( empty ? L ) longitud - actual ]

67

10 Recursin
[ else ( longitud - aux ( rest L ) (+ longitud - actual 1) ) ]) )
; este es el cuerpo de longitud , que llama a longitud - aux :
( longitud - aux L 0) )

6
7
8

(longitud (list a b c)):

Ahora veamos el clculo de

1
2
3
4
5
6

->
=
=
=
=
=

( longitud ( list " a "


( longitud - aux ( list
( longitud - aux ( list
( longitud - aux ( list
( longitud - aux ( list
3

" b " " c ") )


" a " " b " " c ") 0)
" b " " c ") 1)
" c ") 2)
) 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

booleano

lgico.

Slo tiene dos valores constantes,

#t para verdadero y #f para falso (tambin se aceptan las formas #F y #T, pero las

versiones en minsculas son preferidas).


Existe la funcin
o

1
2
3
4

#f:

boolean?

que verica si un valor es una de las dos constantes lgicas,

#t

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

Un valor numrico se puede validar con la funcin

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

en Racket.

number?:

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

nmeros exactos

es

exacto

inexacto.

son:

1. Los enteros
2. Los racionales
3. Los complejos con parte real exacta y parte imaginaria exacta
Los

70

nmeros inexactos

son:

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

exact->inexact e inexact->exact para convertir

de un tipo a otro:

1
2
3
4
5
6
7
8

> ( exact - > inexact 1/3)


0.3333333333333333
> ( exact - > inexact (/ 7 8) )
0.875
> ( inexact - > exact 0.3333333333333333333333333333)
6004799503160661/18014398509481984
Adems, existe una forma de forzar la representacin, como exacto o inexacto, de un nmero,
independientemente de la forma en que se escriba. Con los prejos

1
2
3
4
5
6
7
8

#e

#i:

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

Propagacin de la exactitud

Con los operadores aritmticos bsicos, los nmeros exactos

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

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

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

#b, #o, #x,

10,

pero puede

respectivamente:

11.2 Nmeros

11.2.3. Comparaciones
Los nmeros exactos pueden ser comparados con la funcin

= o con equal?, pero los nmeros

inexactos, debido a su propia naturaleza, deberan ser comparados


de

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

por igualdad, ya que su representacin no es exacta:

por proximidad

en lugar

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

minscula y un nmero hexadecimal de

dos bytes:

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;

string-ref

devuelve un caracter de una cadena, dada su posicin; y

string-length

devuelve su longitud medida en caracteres

Ejemplos:

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,

es decir, que no pueden ser cambiados durante el curso de su existencia como

objetos del programa. Pero si requerimos alterar una cadena durante la ejecucin, debemos
crear una

cadena mutable.

Veamos las funciones para crear una cadena mutable y alterar

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.

string->immutable-string

convierte una cadena mutable en su versin inmutable

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

copia total o parcialmente el contenido de una cadena mutable o

inmutable a otra cadena mutable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

> ( make - string 4 #\ c )


" cccc "
> ( define cadena - mutable ( make - string 4 #\ c ) )
> ( string - length cadena - mutable )
4
> ( string - ref cadena - mutable 2)
#\ c
> ( string - set ! cadena - mutable 2 #\ a )
> cadena - mutable
" ccac "
> ( define cadena - inmutable ( string - > immutable - string cadena - mutable ) )
> ( immutable ? cadena - inmutable )
#t
> ( immutable ? cadena - mutable )
#f
> ( define otra - cadena - mutable ( make - string 10) )
> otra - cadena - mutable
"\ u0000 \ u0000 \ u0000 \ u0000 \ u0000 \ u0000 \ u0000 \ u0000 \ u0000 \ u0000 "
> ( string - copy ! otra - cadena - mutable 0 " buen da ")
> otra - cadena - mutable
" buen da \ u0000 \ u0000 "

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

devuelve una nueva cadena mutable, resultado de concantenar una

serie de cadenas.

string->list

devuelve una lista de todos los caracteres correspondientes a una ca-

dena.

list->string

devuelve una nueva cadena mutable que contiene todos los caracteres

de la cadena proporcionada.

substring

devuelve una nueva cadena mutable que es un subconjunto de la cadena

proporcionada.
Ejemplos:

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

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

[#x0,#xff]).

La funcin

byte?

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

especco, sino un subconjunto de los nmeros enteros.


Ejemplos:

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

#.

Y al igual

inmutables.

Cuando

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


muestra su valor en octal.
Estas son algunas funciones para manipular cadenas de bytes:

bytes-ref

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

bytes-set!

cambia un byte de una cadena de bytes mutable, dada su posicin y el

nuevo byte.

bytes?

verica si un valor es una cadena de bytes.

Ejemplos:

1
2
3
4
5
6
7
8

> #" aBcD "


#" aBcD "
> ( define cad - bytes #" aBcD ")
> ( bytes - ref cad - bytes 0) ;; La letra 'a '
97
>
> ( define otra - cadena ( make - bytes 4 97) )
> otra - cadena

80

11.6 Smbolos
9
10
11
12
13
14
15
16
17
18

#" aaaa "


> ( bytes - set !
> otra - cadena
#" baaa "
>
> ( bytes - set !
> ( bytes - set !
> ( bytes - set !
> otra - cadena
#" b \5\ n \0"

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.

string->symbol

convierte una cadena en su correspondiente smbolo.

symbol->string

convierte un smbolo en su respectiva cadena.

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

#:palabra.

No constituyen una expresin

el paso de parmetros por nombre.

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

son tratados en el captulo 9, en sus formas

mutables, de las que s se hablar aqu.

Hay dos detalles importantes sobre la

mutabilidad

inmutables.

Pero tambin

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

mcons

pares (y listas) mutables:

construye un par mutable (puede ser una lista mutable).

mpair?

verica si un par es mutable.

set-mcar!

para cambiar el primer elemento de un par mutable.

set-mcdr!

para cambiar el segundo elemento de un par mutable.

mcar

mcdr

devuelven el primer y segundo elemento de un par mutable respectiva-

mente.
Ejemplos:

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

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

19

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.

vector-ref

devuelve un elemento de un vector en funcin de su posicin.

list->vector

convierte una lista en un vector con los mismos elementos.

vector->list

convierte un vector en su representacin de lista.

vector-set!

84

modica un valor de un vector mutable dada su posicin.

11.10 Tablas Hash


vector-length

devuelve la longitud de un vector.

Ejemplos:

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.

vector->immutable-vector

devuelve un vector inmutable dado otro vector (que si

ya es inmutable, es el mismo devuelto).

vector-copy!

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

mapeo

de

claves,

valores

claves como los valores pueden ser valores arbitrarios en Racket, y


valores suele ser en tiempo constante, a diferencia del tiempo

el tiempo de acceso a los

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.

make-hash

no recibe parmetros y devuelve una tabla 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

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

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

emos que se ejecuten por sus efectos colaterales, como las funciones

86

display, printf,

11.11 Void
otras. En esos casos, utilizamos el procedimiento especial
especial

1
2
3
4
5
6
7

#<void>:

void

, que devuelve el objeto

> ( void )
> ( begin
" Este bloque no devuelve nada ..."
( void )
)
> void
# < procedure : void >

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

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

avanzadas del lenguaje Scheme para construir expresiones

y para denir funciones.

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)

+ espera
apply:

La funcin
la funcin

1
2
3
4
5
6
7
8

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

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

Y el resultado equivale a:

(<funcin> <parmetro-0> <parmetro-1> ... ).

12.2. Bloques lambda


Recordemos primero que la forma bsica de los bloques

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


Un bloque

lambda

con

parmetros formales, acepta

lambda

es:

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

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

Un parmetro de la forma

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

> ( define saludar


( lambda ( nombre [ apellido " Prez "])
( string - append " Hola , " nombre " " apellido ) ) )
> ( saludar " Pedro ")
" Hola , Pedro Prez "
> ( saludar " Pedro " " Martnez ")
" Hola , Pedro Martnez "

10
11
12
13
14
15
16
17
18
19

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

o segn la nomenclatura de Scheme,

parmetros de palabra clave (vase la seccin 11.7):

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

<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

Un parmetro especicado como

pasado a la funcin usando la misma


e

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


la

palabra clave

en lugar de correspondencia de la posicin.

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

Los parmetros obligatorios por posicin.

En este caso, el parmetro real y el formal

se corresponden por la posicin de ambos.


2.

Los parmetros opcionales por posicin.

En este caso, el parmetro real, si est, se

corresponde por la posicin con el formal.


3.

4.

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.
Los parmetros opcionales por palabra clave. En este caso,
palabra clave.

el parmetro real, si se

indica, se corresponde con el formal por la

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

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

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

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

case-lambda,

que crea una funcin que puede tener un

comportamiento completamente diferente dependiendo del nmero de parmetros reales


que le sean pasados. Un bloque

case-lambda

tiene la sintaxis:

( case - lambda
[ < parmetros - formales - case > < expresiones - cuerpo >+ ]*
)
< parmetros - formales - case > ::= ( < identificador - parmetro >* ) |
< lista - de - parmetros > |
( < identificador - parmetro >+ . < lista - de parmetros > )

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

Donde cada bloque


es equivalente a

Al llamar una funcin denida por un

case-lambda

es como aplicar 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

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

Tambin

podemos mencionar a la estructura

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

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


Una instancia

donde

value

es un entero no negativo.

a denida como (define a (make-arity-at-least <num>)) indica que una


<num> parmetros reales.

funcin/procedimiento acepta al menos

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

procedure-arity devuelve informacin sobre la aridad de un procedimiento.


(procedure-arity <funcin>). Devuelve una de tres cosas:

Su sintaxis es:

94

12.2 Bloques lambda


Un entero no negativo, lo que signica que

<funcin> acepta ese nmero de parmet-

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>

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:

(procedure-arity-includes? <funcin> <k>), donde <k> es un entero


<funcin> acepta <k> parmetros.

no negativo. Esta funcin responde si


Ejemplos:

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

quotient/remainder

quotient y remainder

produce los mismos dos

valores al mismo tiempo:

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

1
2
3
4
5
6

values

acepta cualquier cantidad de parmetros y los devuelve todos:

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

1
2
3
4
5
6
7

<expresin>

debe coincidir con el nmero de identicadores.

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


> cociente
2
> residuo
1

12.3.3. let-values, y let*-values


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

De la misma manera que

let-values
1
2
3
4
5
6

en una denicin,

> ( define ( muestra - cociente -y - residuo n1 n2 )


( let - values ([( cociente residuo ) ( quotient / remainder n1 n2 ) ])
( printf " El cociente es : ~ a \ n " cociente )
( printf " El residuo es : ~ a \ n " residuo )
)
)

97

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

let-values y let*-values es la misma que entre let y let*: let-values


let*-values hace asignaciones secuencialmente.

hace asignaciones en paralelo y

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

set!

set!-values.

La sintaxis es:

(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

N.

Es decir:

retornar

y como segundo

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

ser pasados en cualquier orden.

100

puedan

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>

es una funcin constructora que sirve para crear estruc-

turas del nuevo tipo, y toma tantos parmetros como campos tenga el tipo.

<nombre-estructura>?

es una funcin lgica que verica si el resultado de una ex-

presin es del nuevo tipo.

<nombre-estructura>-<nombre-campo>

son una serie de funciones que devuelven el valor

de un campo de un elemento del nuevo tipo.


Por ejemplo:

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

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

16

101

13 Tipos de dato denidos por el programador


17
18

> ( punto - y mi - punto )


2
Por defecto, las estructuras creadas as son

inmutables.

Por lo que existe una funcin para

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


es la siguiente:

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

a su vez, se deriva otra llamada

base:derivada:descendiente,

base,

debera

y de esta se deriva otra llamada


ser

descendiente,

base:derivada.

Y si de esta,

su nombre formal

debera

ser

as:

(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

transparente,

se imprime como

un vector, mostrando el contenido de los campos.


La sintaxis para denir un tipo de estructura

transparente

es:

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


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

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

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

se crea una por cada campo de

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

respectivamente , luego

retornar una lista con los 3 puntos ordenados de menor a mayor bajo el criterio de
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

(x . y)

y en el otro campo la distancia

puntoD,

la cual tiene en

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

Mdulos Fun-

bibliotecas de objetos/-

de otros lenguajes.

En general un

mdulo sirve para encapsular cierto cdigo, sin que el usuario del mismo tenga

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:

#lang racket es un
.rkt (.ss o .scm).

mdulo funcional, cuyo nombre es el nombre del archivo, sin la extensin

privadas. Y para que sean tiles para


pblicas.

Por defecto, todas las deniciones de un mdulo, son


otros usuarios/programadores, hay que hacerlas
Por ejemplo:

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

# lang racket
; pastel . rkt
;; Vuelve ' pblica ' la definicin de ' imprimir - pastel ' y ' nmero - por defecto ':
( provide imprimir - pastel nmero - por - defecto )
;; Estas
( define
( define
( define
( define

definiciones son invisibles fuera de este mdulo


flama #\.)
candela #\|)
pan #\ x )
base #\ -)

( define nmero - por - defecto 3)


; Dibuja un pastel con n candelas
( define imprimir - pastel
( lambda ([ n nmero - por - defecto ])
( if ( and ( integer ? n ) ( exact - nonnegative - integer ? n ) )
( begin
( printf "
~ a \ n " ( make - string n flama ) )
( printf " . -~a -.\ n " ( make - string n candela ) )
( printf " _ | x ~ ax | _ \ n " ( make - string n pan ) )
( printf " - - -~a - - -\ n " ( make - string n base ) )
)
( error " Se espera un nmero entero no negativo ")
)))

109

14 Mdulos Funcionales
Entonces, desde otro archivo en el mismo directorio, se puede invocar la funcin

imprimir-pastel,

por ejemplo desde el siguiente archivo:

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

require)

a un mdulo funcional,

este es ejecutado, de tal manera que se realizan todas las deniciones en l, y se ejecutan
todas las expresiones que contenga.

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

provide:

Y con ello, disponemos de las funciones de manipulacin para la estructura (make-estructura,

estructura?, estructura-campo1,

110

etc.) en otro mdulo que importe a

biblioteca.rkt.

15 Entrada y Salida
Aqu se describe lo bsico para comprender las posibilidades de

Entrada y Salida

en

Scheme.

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

> (display 1/2)


1/2

> (write #\x)


#\x

> (display #\x)


x

> ;Note las comillas en la salida


> (write hola)
"hola"

> ;No hay comillas en la salida


> (display "hola")
hola

> (write #"nos vemos")


#"nos vemos"

> (display #"nos vemos")


nos vemos

> (write '|smbolo partido|)


|smbolo partido|

> (display '|smbolo partido|)


smbolo partido

> (write '("cadena" smbolo))


("cadena" smbolo)

> (display '("cadena" smbolo))


(cadena smbolo)

> (write write)


#<procedure:write>

> (display write)


#<procedure:write>

Finalmente, la funcin

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
de formateo, como

~a o ~s. Poner ~a provoca que el parmetro correspondiente sea agregado


~s provoca que sea agregado con write:

con display, y poner

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


The

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

Reader ),

es un

analizador lxico y sintctico desdendente recursivo,

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

(current-input-port)

que se explica ms adelante, en la seccin 15.4):

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

UTF-8.

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

Lee un caracter en la codicacin de  el lector , que

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

interpreta el n de lnea cuando encuentra el caracter

\n.

Este es el

comportamiento correcto en sistemas Unix.

'return

interpreta el n de lnea cuando encuentra el caracter

\r.

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>}? ):

Lee una cadena de a lo sumo

<cuenta>

caracteres.

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

(, [

{,

), ]

},

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.

#t, #T, #f
#(, #[

#{,

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

|#).

inicia un nmero inexacto, exacto,

hexadecimal, octal, decimal o binario, respectivamente.

#hash

inicia una tabla hash.

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

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

Consulte la seccin

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

cerrar.

La funcin de apertura,

depende del tipo particular de puerto que se necesite abrir, pero la funcin de cierre slo depende de la direccin del ujo; en todos los casos son

close-input-port y close-output-port.

Tambin hay otras funciones que operan sobre puertos:

input-port?

que verica si el parmetro indicado es un puerto de entrada/lectura.

output-port?
port?

que verica si el parmetro indicado es un puerto de salida/escritura.

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

da/escritura.

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

es:

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

'error

116

lanza una excepcin cuando el archivo ya existe.

'append

si el archivo ya existe, el cursor se coloca al nal del archivo.

'update

se coloca al nal del archivo y genera una excepcin si no existe.

15.3 Tipos de Puerto


'can-update

abre el archivo sin truncarlo (es decir, sin borrarlo), o lo crea si no

existe.

'replace

borra el archivo, si existe, y crea uno nuevo.

'truncate

borra el contenido del archivo, si existe.

'must-truncate borra el

contenido de un archivo existente, y lanza una excepcin si

no existe.

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.

'append

si el archivo ya existe, el cursor se coloca al nal del archivo.

'update

se coloca al nal del archivo y genera una excepcin si no existe.

'replace

borra el archivo, si existe, y crea uno nuevo.

'truncate

borra el contenido del archivo, si existe.

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
( aux ( open - input - file nombre - archivo ) 1)
( error ( string - append " No existe el archivo " nombre - archivo ))
)

17
18
19

20
21
22
23
24
25
26
27

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

<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,
respectivamente.
El comportamiento es el siguiente:
1. Se intenta abrir el archivo indicado en

<ruta>

utilizando el modo y comportamiento

indicado en los parmetros opcionales.


2. Una vez abierto el archivo, se ejecuta

<procedimiento>

pasndole como parmetro

al puerto recin abierto.


3. Cuando

<procedimiento>

naliza, se cierra el puerto correspondiente.

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


call-with-output-file.

4. Finalmente, el resultado de
o

La utilidad de estas funciones es que las funciones que contienen la lgica del procesamiento
de los ujos (de entrada o de salida) no se mezclen con
es un procedimiento que depende del tipo de puerto.
Considere la siguiente variante del cdigo anterior:

1
2

# lang racket
; lee - lneas2 . rkt

118

la logstica de abrir el ujo, lo cual

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

hacer lo mismo con las cadenas de texto. Las funciones para abrir un puerto de cadena son:

open-input-string

open-output-string.

Por lo dems, funcionan igual que cualquier

puerto:

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

las conex-

iones que lleguen por ah.

tcp-accept

para que un servidor

tcp-connect
tcp-close

acepte

conexiones provenientes de un cliente.

para que un cliente solicite una conexin con un servidor.

para terminar una escucha de puerto, es la contraparte de

tcp-listen.

Ejemplo:

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

1
2
3
4
5
6
7

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

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


display, printf, write, read-char, read-line
read para imprimir informacin en patalla. Estas funciones, utilizan por defecto tres ujos

Hasta ahora, se han utilizado las funciones


y

predeterminados:

(current-input-port)

devuelve el puerto de entrada estndar.

(current-output-port)
(current-error-port)

devuelve el puerto de salida estndar.

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

cambia el puerto de entrada estndar a

(current-output-port <p>)
(current-error-port <p>)

cambia el puerto de salida estndar a

<p>.
<p>.

cambia el puerto de salida estndar de error a

<p>.

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

#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

informacin alguna.

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
lanza una excepcin. Y a
atrapada , se gestionar imprimiendo en la salida estndar de

En Scheme, cuando sucede un error en tiempo de ejecucin, se


menos que la excepcin sea

error un mensaje asociado con la excepcin y terminando los clculos.


Por ejemplo:

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

> (/ 100 0)
. . /: division by zero
> ( car 35)
. . car : expects argument of type < pair >; given 35
> ( define p ( open - input - string " Esta es la cadena fuente ") )
> ( read - string 5 p )
" Esta "
> ( close - input - port p )
> ( read - string 5 p )
. . read - string : input port is closed

16.1. Atrapar Excepciones


atrapar una excepcin, se usa el bloque with-handlers que tiene la sintaxis:
(with-handlers ( { [<f-evaluadora> <f-manejadora>] }* ) <exp-cuerpo>+ )

Para

Y funciona de la siguiente manera: Cuando aparece una forma como esta en el curso actual

<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

de ejecucin, se comienzan a evaluar las expresiones del cuerpo, las

nivel superior la atrape (talvez).


Todas las funciones

<f-evaluadora> y las <f-manejadora> deben recibir un nico parmetro

obligatorio que ser el valor que represente a la excepcin lanzada en el cuerpo. Tpicamente
ser una instancia de alguna estructura derivada de

exn:fail

(recurdese la seccin 13.2).

Ejemplo:

127

16 Excepciones
1
2
3
4

> ( with - handlers ([ exn : fail : contract : divide - by - zero ?


( lambda (e ) + inf .0) ])
(/ 100 0) )
+ inf .0

5
6
7
8
9
10

> ( with - handlers ([ exn : fail : contract : divide - by - zero ?


( lambda (e ) + inf .0) ])
( car 35) )
. . car : expects argument of type < pair >; given 35

11
12
13
14
15
16
17
18
19
20
21
22

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

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

1
2
3
4
5
6
7

exn:fail:

raise

excepciones

error),

que no se apeguen a esta

exn:fail

o de alguna de

pero en Scheme, podemos

costumbre.

nos permite lanzar cualquier objeto o valor como una excepcin:

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

eval

toma una expresin 

apostrofada 

(es decir, una expresin precedida por

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

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

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

eval

read

para convertir dinmicamente una cadena con una

expresin de racket vlida, en una funcin que evala esa expresin. A continuacin se
presentan tres ejemplos:

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

lambda es un procedimiento sin nombre, existe el bloque

class que es una clase sin nombre. Su sintaxis es:


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

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

Y al igual que podemos utilizar

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.

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

Para denir una clase que implemente interfaces, se usa el bloque

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

lambda

para funciones que slo se invocarn una

vez.
La forma de

<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

1
2
3
4

define/public

es una forma abreviada de:

( 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

ciertos identicadores

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

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

send:

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

1
2
3
4

define/override

es una forma abreviada de:

( begin
( override < nombre - mtodo >)
( define < nombre - mtodo > <exp - lambda_con_PARMETROS_y_EXP - CUERPO > )
)
El bloque

override

sobreescritos

134

sirve para indicar todos los identicadores de las funciones que sern

en esta clase.

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

so-

define/public-final

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

heredado):

(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

A y estos
(super-new).

puede llevar los parmetros indicados en

cuando en

se encuentre la llamada a

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.

interface?
object=?

toma un valor y verica si es una clase o no.

toma dos objetos y verica si son el mismo.

class->interface toma una clase y devuelve la interface implcitamente denida por


la clase.

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?

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

una interface que extiende a la interface proporcionada.

method-in-interface?

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

# lang racket
; cola . rkt
;; Definicin de una clase Cola
( define cola %
( class object %

( super - new ) ;; Siempre debe inicializarse la superclase

8
9

( define elementos '() ) ;; Este valor es " privado " , dentro de la clase .

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

( 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

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

cola %:

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

1
2
3
4
5
6

# lang racket
; pila . rkt
;; Definicin de una clase Pila
( define pila %
( class object %

( super - new )

8
9

( define elementos '() )

10
11

( public tamao ) ;; ' public ' y ' define ' separados


( define ( tamao )
( length elementos )
)

12
13
14
15
16

( public meter ) ;; ' public ' y ' define ' con ' lambda ' separados
( define meter
( lambda ( nuevo - elemento )
( set ! elementos ( cons nuevo - elemento elementos ) )
)
)

17
18
19
20
21
22
23

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

24
25
26
27
28
29
30
31
32
33
34
35
36

Ejemplos de interaccin con la clase

1
2
3

define/public:

> ( define pilita ( new pila %))


> ( new pila %)
#( struct : object : pila % ...)

138

pila %:

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

gracket en lugar del

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

$ raco exe -o ejecutable --gui hola-mundo.rkt

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

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

callback

que se ejecutar cuando el evento suceda.

# 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

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

callback

se puede usar para procesar varios eventos:

# 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


[ parent ventana ]
[ label " Botn 2"]
[ callback funcin - manejadora ]
))

24
25
26
27
28
29

( 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

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

dialog %:

# 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

)]

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

51
52
53

( send ventana show # t )

19.5. Eventos de cuadros de texto

Figura 19.6: text-eld.rkt

1
2

# 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


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

54
55
56
57
58
59

( 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

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

event )
set - label " Clic del botn izquierdo ") ) ])
event )
set - label " Clic del botn derecho ") ) ])

31
32
33

( send ventana show # t )

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

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

33
34
35

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

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

165

21 Dibujo con Lienzos


5
6
7
8
9
10
11
12

( define ventana ( new frame %


[ label " Ejemplo de eventos en canvas "]
[ width 400]
[ height 400]) )
( define canvas - hijo2 %
( class canvas %

13

( super - new )
( define primer - punto ( make - object point % 0 0) )

14
15
16

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

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

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

4
5
6
7

( 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

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

20

( super - new )
( define punto - ini - recta ( make - object point % 0 0) )
( define punto - ant - recta ( make - object point % 0 0) )

21
22
23

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


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

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

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

86
87
88

( 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

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

52
53
54

( send ventana show # t )


Otro ejemplo con mens contextuales:

1
2
3
4
5
6
7
8

# 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

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

66
67
68

( 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
( send dc set - pen lpiz - slido )
)]

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

))
( define opcin3 ( new menu - item %
[ parent men ]
[ label " Azul "]
[ callback
( lambda ( m c )
( send dc set - pen lpiz - invertido )
( send lpiz - slido set - color ( make - object color % 0
0 255) )
( send dc set - pen lpiz - slido )
)]
))
( define opcin4 ( new menu - item %
[ parent men ]
[ label " Otro ..."]
[ callback
( lambda ( m c )
( send dc set - pen lpiz - invertido )
;( send lpiz - slido set - color ( make - object color % 0
0 255) )
( let ([ nuevo - color ( get - color - from - user " Elija un
color " ventana ( send lpiz - slido get - color ) ) ])
( when nuevo - color
( send lpiz - slido set - color nuevo - color )
)
)
( send dc set - pen lpiz - slido )
)]
))
( send ventana show # t )

182

23 Proyecto: Minipaint

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

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

36

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

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

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

107
108
109
110
111
112
113

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

114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

( send punto - anterior set - x ( send evento get - x ) )


( send punto - anterior set - y ( send evento get - y ) )
( actualizar - rectngulo )

133
134
135
136

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

137
138
139
140
141
142
143
144
145
146

( send dc draw - rectangle


rect - x rect - y rect - ancho rect - alto )

147
148
149
150
151
152
153
154

))

155
156
157

; 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
[(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 ) )
)
]
)

206
207
208
209

210
211
212
213

)
( send dc set - pen lpiz - slido )
( send lpiz - invertido set - color ( send lpiz slido get - color ) )
)]
[ style ( list ' vertical ' vertical - label ) ]
))

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

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

252

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

324
325
326
327
328
329
330
331
332
333
334
335
336

)]

( send dc set - brush brocha ) ; configurar


la brocha
)
( set ! nombre - del - archivo nombre - archivo )
( set ! modificado ? # f )
( send mi - canvas refresh )
)

( 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

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

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

( 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

scheme

3. El lenguaje principal del intrprete de PLT Scheme se llama

y no

racket

como en Racket. Por ello, la primera lnea de los programas de PLT Scheme deben
comenzar con la lnea:

#lang scheme,

en lugar de

#lang racket

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


DrScheme) en lugar de

drracket.

como en Racket.

drscheme

(y se llama

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


es

mzscheme

en lugar de

racket.

6. El intrprete de los programas Racket con Interfaz Grca de Usuario en versiones


anteriores a la 5.0 es

mred

en lugar de

gracket.

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

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

mzc

en lugar de

raco:

para programas sin interfaz grca, y con:

$ 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

scheme/gui.

Para mayor informacin sobre el cambio de nombre, rerase al sitio:


http://racket-lang.org/new-name.html.
-

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

la Comunidad de desarrolladores de Racket (http://racket-lang.org/people.html).


[2] http://www.htdp.org/2003-09-26/Book/ -

How to Design Programs (An Introduction to

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

201

También podría gustarte