Asignaciones con let y let*

let permite crear asignaciones locales de expresiones a identificadores que existen durante la vida del cuerpo asociado a let, pero no fuera. let* nos permite asignar expresiones que involucren identificadores declarados en el mismo rec.

Cuando trabajamos con constantes y variables en programación, es común que definamos valores que queremos que permanezcan inalterables a lo largo de todo nuestro código. Por ejemplo, podemos definir una constante como pi con un valor fijo, y esta definición suele tener un ámbito global dentro del archivo. Esto es útil para valores que no cambian y que queremos tener accesibles en cualquier parte del programa.

Sin embargo, cuando nos enfrentamos a funciones que realizan operaciones complejas, como una multiplicación extensa, no es práctico ni legible manejar todo directamente con constantes globales. En estos casos, necesitamos variables locales que dependan de los parámetros de la función y que desaparezcan una vez que la función termina su ejecución. Para esto, podemos usar la palabra clave let, que nos permite declarar variables locales con un ámbito limitado a la función o bloque donde se definen.

La sintaxis de let consiste en una lista de asignaciones dentro de corchetes, donde cada asignación tiene la forma de un identificador seguido de una expresión. Después de estas asignaciones, se evalúa un cuerpo de código donde las referencias a esos identificadores se sustituyen por sus valores asignados. Por ejemplo, si escribimos:

(let ([x 4] [y 5])
  (+ x y))

lo que sucede es que se crean dos variables locales, x con valor 4 y y con valor 5, y luego se evalúa la suma de x y y, resultando en 9. Fuera de este bloque, x y y no existen, lo que evita conflictos con otras variables del mismo nombre en ámbitos superiores.

Un aspecto importante es que las variables definidas dentro de un let tienen prioridad sobre las que existen fuera. Si ya tenemos variables x y y definidas globalmente, las definiciones dentro del let las ocultan temporalmente mientras se evalúa su cuerpo. Esto permite anidar let y redefinir variables sin afectar el estado global.

Sin embargo, let tiene una particularidad que puede causar confusión cuando las asignaciones dependen unas de otras. Por ejemplo, si intentamos hacer:

(let ([x 5] [y (+ 2 x)])
  (display y))

esperaríamos que y sea 7, ya que x es 5 y sumamos 2. Pero en realidad, el resultado es 3. Esto ocurre porque en let las asignaciones se realizan todas al final, es decir, las expresiones de las asignaciones no pueden referirse a las variables que se están definiendo en ese mismo let. Por lo tanto, cuando se evalúa (+ 2 x), la variable x aún no tiene asignado el valor 5, sino que toma el valor que tenía fuera del let (o no existe), lo que lleva a resultados inesperados.

Para solucionar este problema, podemos usar let* (pronunciado let estrella), que es una variante de let que asigna las variables secuencialmente, tan pronto como se definen. Esto significa que en let*, cada asignación puede depender de las anteriores dentro del mismo bloque. Por ejemplo:

(let* ([x 5] [y (+ 2 x)])
  (display y))

Aquí, x se asigna primero con valor 5, y luego y se asigna con la expresión (+ 2 x), donde x ya tiene el valor 5, por lo que y será 7, como esperábamos.

En resumen, let es útil para definir variables locales con ámbito limitado, pero no permite que las asignaciones dependan unas de otras dentro del mismo bloque. Para casos donde necesitamos que las asignaciones sean secuenciales y dependientes, let* es la opción adecuada, ya que asigna las variables en orden y permite que cada expresión de asignación use las variables definidas anteriormente. Esto nos ayuda a escribir código más claro y evitar errores en asignaciones secuenciales dentro de funciones.

Lista de reproducción
  1. 1
    Introducción al entorno
    16 minutos
  2. 2
    Definiciones, funciones y comentarios
    16 minutos
  3. 3
    Tipos de datos
    23 minutos
  4. 4
    Listas: manipulación, iteración y recursión
    25 minutos
  5. 5
    Todo sobre las condicionales
    17 minutos
  6. 6
    Revisitando las definiciones
    15 minutos
  7. 7
    Funciones lambda (lo básico)
    13 minutos
  8. 8
    Asignaciones con let y let*
    9 minutos