Conceptos¶
- Es un lenguaje multiparadigma (principalmente funcional).
- Los valores se declaran con
define. - Los paréntesis guían la ejecución:
- En
(función ...), el primer elemento a la izquierda debe ser una función. - Se evalúan de adentro hacia afuera. Ejemplo:
(+ (* 2 3) (* 3 4))→ primero(* 2 3)y(* 3 4)(izquierda a derecha), luego(+ 6 12)→18. - Condicionales:
if:(if pregunta respuesta_true respuesta_false).cond:[(pregunta respuesta)] ... [(else respuesta)]. Se evalúan de arriba hacia abajo.- Las listas son la estructura de datos (colección) más utilizada. Tienen la forma cabeza-cola:
(cons valor lista): la lista puede ser no vacía (cons) o vacía (empty).(car lista): accede al primer elemento.(cdr lista): accede al resto de la lista.- Existe azúcar sintáctico con combinaciones como
cadr(car (cdr ...)) ocaadr(car (car (cdr ...))). (list x x x): es una abstracción decons.'(x x y): todo lo interior se transforma en símbolo o número. Un símbolo (o átomo) es un tipo de dato indivisible que inicia con'x.
#lang eopl
; Notación prefija: (f args...)
(display (+ 1 2 3 4 5)) ; Muestra la suma de 1 a 5
(define valor 3) ; Define una variable llamada 'valor' con el número 3
(define funcion
(lambda (x y z) ; Define una función anónima con parámetros x, y, z
(* (+ x y) (+ x z)) ; Retorna el producto de (x+y) y (x+z)
)
)
(display "\n") ; Salto de línea
(display (funcion 1 2 3)) ; Llama a 'funcion' con argumentos 1,2,3 y muestra el resultado
(define mayorEdad
(lambda (edad)
(if
(>= edad 18) ; Condición: ¿edad mayor o igual a 18?
"Es mayor de edad" ; Si es verdadero
"Es menor de edad" ; Si es falso
)))
(define mayorEdadPro
(lambda (edad)
(cond
[(and (>= edad 0) (< edad 18)) "Es menor de edad"] ; Caso: entre 0 y 17
[(>= edad 18) "Es mayor de edad"] ; Caso: 18 o más
[else (eopl:error "Edad no válida")]))) ; Error si la edad es negativa
;; Listas
;; Estructura cabeza-cola
(define listaA (cons 1 (cons 2 (cons 3 empty)))) ; Lista construida con cons
(define listaB (list 1 2 3)) ; Lista usando la función list
(define listaC '(1 2 3)) ; Lista simbólica (los elementos se toman literalmente)
(define cuadrado (lambda (x) (* x x))) ; Función que calcula el cuadrado de x
(define listaD (list (cuadrado 1) (cuadrado 2) (cuadrado 3))) ; Lista con cuadrados evaluados
(define listaF '((cuadrado 1) (cuadrado 2) (cuadrado 3))) ; Lista simbólica (no evalúa cuadrado)
(map (lambda (x) (+ x 2)) listaA) ; Aplica (x+2) a cada elemento de listaA
(define listaG (list (list 1 2 3) (list 2 3 4))) ; Lista de listas usando list
(define listaH '((1 2 3) (2 3 4))) ; Lista simbólica de listas
(define listaI '(((((1 2 3 (3))) (4 5 6) (2 3)) 2) 4)) ; Lista anidada compleja
Usando recursión para resolver problemas¶
En Racket, la recursión es el método principal para resolver problemas iterativos.
- Caso base: Situación trivial que detiene la recursión.
- Caso recursivo: Reduce el problema y avanza hacia el caso base.
;; Sumar los elementos de una lista
(define sumar-elemento
(lambda (lst)
(cond
[(null? lst) 0] ; Caso base: lista vacía, suma es 0
[else (+ (car lst) (sumar-elemento (cdr lst)))]))) ; Caso recursivo: cabeza + suma de la cola
(define sumar-elemento-lista-listas
(lambda (lst)
(cond
[(null? lst) 0] ; Caso base: lista vacía
[(list? (car lst)) (+ (sumar-elemento-lista-listas (car lst)) ; Si el primer elemento es una lista, sumar recursivamente
(sumar-elemento-lista-listas (cdr lst)))] ; y sumar el resto de la lista
[else (+ (car lst) (sumar-elemento-lista-listas (cdr lst)))]))) ; Si no es lista, sumar cabeza y continuar
(define sumar-elementoxD
(lambda (lst [acc 0]) ; Parámetro opcional 'acc' (acumulador) inicializado en 0
(cond
[(null? lst) acc] ; Caso base: devolver acumulador
[else (sumar-elementoxD (cdr lst) (+ acc (car lst)))]))) ; Caso recursivo: acumular cabeza y procesar cola
Conceptos teóricos adicionales¶
- Evaluación perezosa (lazy evaluation): Racket no es perezoso por defecto, pero ofrece construcciones como
delayyforcepara evaluación diferida. - Funciones de orden superior: Funciones que reciben o retornan otras funciones, como
map,filter,foldl. - Clausuras (closures): Una función que captura el entorno donde fue definida, permitiendo acceso a variables externas.
- Tipado dinámico: Los tipos se verifican en tiempo de ejecución, no en compilación.
- Inmutabilidad: Los datos en Racket son inmutables por defecto; las operaciones crean nuevos valores en lugar de modificar existentes.
Tabla de resumen¶
| Concepto | Descripción | Ejemplo |
|---|---|---|
| Define | Define variables o funciones. | (define x 5) |
| Lambda | Crea funciones anónimas. | (lambda (x) (* x x)) |
| If | Condicional simple. | (if (> x 0) "positivo" "negativo") |
| Cond | Condicional múltiple. | (cond [(> x 0) "+"] [(< x 0) "-"] [else "cero"]) |
| Cons | Construye una lista (cabeza + cola). | (cons 1 (cons 2 empty)) |
| Car | Obtiene el primer elemento de una lista. | (car '(a b c)) → a |
| Cdr | Obtiene el resto de la lista. | (cdr '(a b c)) → (b c) |
| List | Crea una lista a partir de elementos. | (list 1 2 3) |
| Lista simbólica | Lista con elementos literales (no evaluados). | '(a b c) |
| Recursión | Técnica para repetir operaciones llamándose a sí misma. | Ver sumar-elemento |
| Recursión con acumulador | Recursión que lleva un estado acumulado. | Ver sumar-elementoxD |
| Map | Aplica una función a cada elemento de una lista. | (map add1 '(1 2 3)) → (2 3 4) |
Comentarios adicionales¶
- Racket es un dialecto de Scheme, que a su vez pertenece a la familia Lisp. Su sintaxis minimalista (muchos paréntesis) puede ser desafiante al inicio, pero permite una gran expresividad.
- La recursión es fundamental debido a la inmutabilidad de las listas; los bucles imperativos (como
for) son menos comunes. - Las listas en Racket son listas enlazadas simples, por lo que operaciones como
carson O(1), pero acceder a un elemento por índice es O(n). - Es recomendable usar funciones de orden superior (
map,filter,foldl) cuando sea posible, ya que son más declarativas y reducen errores. - Para depurar, se puede usar
(display ...)o herramientas del entorno (DrRacket) para inspeccionar valores. - En programas más grandes, es buena práctica documentar funciones con comentarios que especifiquen los tipos esperados y el propósito, aunque Racket no tenga tipado estático.