On this page:
1.1 Tipos primitivos
1.2 Usar funciones predefinidas
1.3 Condicionales
1.4 Definir identificadores
1.5 Definir funciones
1.6 ¿Dónde encuentro información sobre...?

1 Elementos Básicos

Éric Tanter

El ambiente de desarrollo (IDE) DrRacket divide inicialmente el espacio en dos partes, una para definiciones, y otra para interactuar con el lenguaje directamente, al estilo de un terminal Unix. Usaremos la forma interactiva para empezar a explorar el lenguaje.

1.1 Tipos primitivos

Números, incluyendo fracciones y números imaginarios:

> 1

1

> -3

-3

> 4.02

4.02

> 6.02e+23

6.02e+23

> 1+2i

1+2i

> 4/3

4/3

Booleanos:

> #t

#t

> #f

#f

Strings (incluyendo caracteres Unicode):

> "hola"

"hola"

> "hola \"mundo\" feliz"

"hola \"mundo\" feliz"

> "λx:(μα.α→α).xx"

"λx:(μα.α→α).xx"

Símbolos:

> 'hola

'hola

Un símbolo es un valor atómico. Por ende, determinar la igualdad de dos símbolos es barato (tiempo constante), a diferencia de una comparación de strings (lineal).

Otros tipos primitivos incluyen caracteres, bytes y byte strings, void, undefined, y estructuras de datos como pares, listas, cajas, tablas de hash, y vectores. Veremos algunos más adelante.

1.2 Usar funciones predefinidas

Scheme es un lenguaje con sintáxis prefijada con paréntesis. El primer elemento después del paréntesis "(" es la función a aplicar, y todo lo demás hasta el paréntesis ")" correspondiente son los argumentos (separados por espacios). Por ejemplo, para aplicar funciones aritméticas (que reciben un número variable de argumentos):

> (+ 1 2)

3

> (* 2 4 5)

40

> (- 1 1/4)

3/4

Eso significa que los paréntesis en Scheme tienen un significado (¡y muy importante!). Las pueden ver como el equivalente de las paréntesis de aplicación de funciones y procedimientos en otros lenguajes (por ejemplo foo(1) en C se escribe (foo 1) en Scheme).

Y similarmente para otras funciones matemáticas y lógicas:

> (+ 1 (- 3 4))

0

> (sqrt -1)

0+1i

> (or (< 5 4)
      (equal? 1 (- 6 5)))

#t

> (and (not (zero? 10))
       (+ 1 2 3))

6

Como se puede apreciar en el último ejemplo, en Scheme, todo lo que no es #f es verdadero.

Manipulación de strings:

> (string-append "ho" "la")

"hola"

> (string-length "hola mundo")

10

> (substring "Apple" 1 3)

"pp"

> (string->symbol "Apple")

'Apple

Hay varias formas de imprimir, por ejemplo printf:

> (printf "hola~n")

hola

> (printf "hola ~a ~s~n" "mundo" "feliz")

hola mundo "feliz"

Scheme es un lenguaje seguro (¡no hay segmentation faults!). Al invocar una función con argumentos del tipo equivocado, se genera un error:

> (+ 1 "hola")

+: contract violation

  expected: number?

  given: "hola"

  argument position: 2nd

  other arguments...:

   1

Existe un dialecto de Racket, llamado Typed Racket, que es estáticamente tipeado. Puede encontrar información en la documentación.

El mensaje de error explica claramente lo que pasó. Es importante notar que el error se reporta en tiempo de ejecución. Scheme no es un lenguaje estáticamente tipeado, al igual que JavaScript y Python, entre otros.

Ejercicio: imprima (con printf) la raíz cuadrada de -1/4.

1.3 Condicionales

El clásico:
> (if (> 4 10)
      "hola"
      "chao")

"chao"

> (if (> 12 10)
      "hola"
      "chao")

"hola"

Los ifs se pueden anidar:

> (if (> 2 3)
      (printf "hola")
      (if (> 6 5)
          (printf "chao")
          #f))

chao

Pero es más cómodo usar cond para este tipo de condicional múltiple:

El uso de paréntesis cuadrados es totalmente opcional, es solamente con fines de legibilidad. Veremos otros usos de esos paréntesis conformemente a las buenas prácticas de la comunidad Racket a lo largo del curso.

> (cond [(> 2 3) (printf "hola")]
        [(> 6 5) (printf "chao")]
        [else #f])

chao

1.4 Definir identificadores

Se puede definir identificadores tal que queden globalmente disponibles. Esas definiciones se pueden hacer en la parte de definiciones del IDE:

(define MAX 100)

Después de hacer click en el botón "Run", el identificador MAX queda enlazado con el valor 100, disponible para interactuar:

> MAX

100

> (< 25 MAX)

#t

También se puede definir un identificador en la parte de interacciones del IDE. De esta manera, el identificador queda definido para toda la sesión de interacción. Hacer click en "Run" inicia una nueva sesión, en la cual el identificador no estará definido.

> (define x 10)
> (+ x 1)

11

Como hemos visto, la sintáxis de los identificadores en Scheme, incluyendo para nombres de funciones, es bastante liberal. Casi cualquier secuencia de caracteres que no sea un espacio es un identificador: +, number?, pass/fail, set!, λ=>α, etc. son identificadores totalmente válidos. En realidad, solamente los paréntesis (cualquier forma) y los caracteres ,.;|\ son especiales (y obviamente, las secuencias de caracteres que forman los números).

> (define !λ=>-α/β?☺ "weird")
> !λ=>-α/β?☺

"weird"

Se puede también introducir identificadores con alcance local con let:

> x

10

> (let ([x 3]
        [y 2])
    (+ x y))

5

> x

10

> y

y: undefined;

 cannot reference undefined identifier

El identificador x dentro del let esconde el x definido globalmente. Pero una vez que uno sale del let, el identificador original sigue disponible e inalterado. Similarmente, y es introducido solamente en el cuerpo del let, de manera que no está definido una vez fuera del cuerpo del let.

Notar que let no permite usar un identificador en el cálculo de otro identificador introducido después en el mismo let. Para esto hay que usar let*, que es equivalente a lets anidados:

> (let ([a 3]
        [b (+ a a)])
    b)

a: undefined;

 cannot reference undefined identifier

> (let* ([a 3]
         [b (+ a a)])
    b)

6

Ejercicio: introduzca localmente dos identificadores locales, asociados a números, y retorne el máximo.

1.5 Definir funciones

Además de las funciones existentes, se pueden definir funciones propias:

(define (double x)
  (+ x x))

 

> (double 2)

4

También se puede definir una función directamente en la parte de interacciones del IDE:

> (define (foo x)
    (if (< x 10)
        (printf "menor")
        (printf "mayor")))
> (foo 4)

menor

> (foo 11)

mayor

Más adelante veremos herramientas metodológicas para Definir Funciones.

Ejercicio: defina la función (sum a b) que suma sus dos parámetros.

Ejercicio: defina la función (pick-random x y) que retorna en forma aleatoria uno de sus argumentos. (La función (random) genera un número aleatorio entre 0 y 1).

1.6 ¿Dónde encuentro información sobre...?

La mejor manera de explorar Racket es usar el Help Desk (menú Help en DrRacket), que abre la documentación de Racket en local (la documentación también está disponible en la web). Las partes más importantes son el Racket Guide para una explicación al estilo "tutorial", y la Racket Reference para una descripción exhaustiva del lenguaje Racket y de todas las funciones y librerías incluidas.

¡La documentación de Racket es sumamente útil y completa! Acostúmbrese a usarla desde ya.