2 Estructuras de Datos
Aparte de los datos primitivos simples que hemos visto, Scheme soporta múltiples estructuras compuestas, como pares, listas, y vectores.
2.1 Pares
La estructura más básica es el par, que pega dos valores juntos.
> (cons 1 2) '(1 . 2)
> (car (cons 1 2)) 1
> (cdr (cons 1 2)) 2
Ejercicio: defina la función (pair-add1 p) que recibe un par de números y retorna un nuevo par dónde los dos elementos fueron incrementados en "1".
2.2 Listas
Toda estructura se puede codificar con pares. En particular, las listas pueden ser construidas encadenando pares (con cons), usando empty (o null, o '()) como último elemento.
> empty '()
> (cons 2 empty) '(2)
> (cons 1 (cons 2 (cons 3 empty))) '(1 2 3)
> (define l (list 1 2 3 4 5 6))
> l '(1 2 3 4 5 6)
> (append (list 1 2 3) (list 4 5 6)) '(1 2 3 4 5 6)
> (cons (list 1 2 3) (list 4 5 6)) '((1 2 3) 4 5 6)
Como una lista es en realidad unos pares encadenados, se puede usar car y cdr (y sus combinaciones) para acceder a cualquier elemento de una lista:
> (car l) 1
> (cdr l) '(2 3 4 5 6)
> (car (cdr l)) 2
> (cadr l) 2
> (cadddr l) 4
> (first l) 1
> (rest l) '(2 3 4 5 6)
> (second l) 2
> (fourth l) 4
> x x: undefined;
cannot reference undefined identifier
> 'x 'x
> (1 2 3) application: not a procedure;
expected a procedure that can be applied to arguments
given: 1
arguments...:
2
3
> '(1 2 3) '(1 2 3)
> (second '(1 2 3)) 2
> (list 1 2 (+ 1 2)) '(1 2 3)
> '(1 2 (+ 1 2)) '(1 2 (+ 1 2))
> (second '(define (inc x) (+ 1 x))) '(inc x)
En Racket, las listas y los pares son immutables. Existen versiones mutables de pares y listas, aúnque no las usaremos en el curso.
Ejercicio: defina la función list-pick-random que retorna un elemento al azár dentro de una lista. (La función (random k) retorna un número aleatorio entre 0 y k-1.)
2.3 Vectores
Un vector en Scheme es (casi) como un arreglo en C. La diferencia importante es que el acceso a un vector es seguro: si el índice es fuera del rango del vector, se lanza un error. La mayor diferencia entre arreglos y listas es que el acceso a cualquier posición se hace en tiempo constante (con vector-ref). Por comparación, dado que una lista es una estructura encadenada, el acceso a cualquier posición se hace en tiempo lineal.
> (define v (vector 1 2 3))
> (vector-ref v 2) 3
Por convención, las funciones que modifican de manera imperativa el estado del programa tienen un nombre que termina con el símbolo !.
> (vector-set! v 2 "hola")
> v '#(1 2 "hola")
> (define v2 #(1 2 3))
> (vector-set! v2 0 -10) vector-set!: contract violation
expected: (and/c vector? (not/c immutable?))
given: '#(1 2 3)
argument position: 1st
other arguments...:
0
-10
> (vector->list v2) '(1 2 3)
> (list->vector '(1 2 3)) '#(1 2 3)
Ejercicio: defina la función vector-set-random! que cambia un elemento al azár dentro de un vector por un valor dado.