12. Variables

Práctica 07

Da la vuelta a una lista.

* (my-reverse '(a b c d e))
(E D C B A)

Teoría

Como en otros lenguajes, disponemos de variables locales y globales. Sin embargo el scope (ámbito) de las variables en Common Lisp es muy importante y tiene particularidades que debes conocer.

Variables locales

Se definen con la función let o let*, y solo son accesibles dentro del bloque donde se definen.

(let ((x 10)
      (y 20))
  (+ x y)) ; 30

Si intento hacer la misma operación aritmética fuera del bloque let, obtendré un error:

(let ((x 10)
      (y 20)))

(+ x y) ; Error: Variable X is unbound.

No importa cuán profundo esté tu código, que mientras estén dentro del bloque let las variables serán accesibles.

Sin embargo debes saber que las variables no respetan el orden en las cuales tu las defines. Por ejemplo:

(let ((x 1)
       (y 2)
       (z (+ x y))) ; Error: Variable X is unbound.
    z)

Obtienes un error porque x y y no están definidas en el momento de calcular z. La solución es evaluarlas, y para ello existe let*:

(let* ((x 1)
       (y 2)
       (z (+ x y))) ; Ahora funciona correctamente.
    z) ; 3

La diferencia entre let y let* es que let evalúa todas las inicializaciones de las variables en paralelo, mientras que let* las evalúa secuencialmente, permitiendo que las variables definidas anteriormente sean utilizadas en las inicializaciones posteriores.

¿Cuándo debo usar cada uno? let por defecto ya que es más eficiente, y let* solo cuando necesites que una variable dependa de otra.

Variables dinámicas

Podríamos considerarlas como variables globales, pero con un scope es dinámico.

Se definen con defparameter o defvar.

(defparameter *mi-variable* 42)

(defvar *otra-variable* "Hola, mundo!")

Sus diferencias son sutiles pero importantes.

defparameter siempre inicializa la variable, incluso si ya existe. defvar solo inicializa la variable si no existe previamente.

Por ejemplo, si ejecutas:

(defparameter *mi-variable* 100)
*mi-variable* ; 100

(defparameter *mi-variable* 200)
*mi-variable* ; 200
La variable *mi-variable* vale 200 porque defparameter la ha redefinido.

(defvar *otra-variable* "Hola mundo!")
(defvar *otra-variable* "Nos vemos luego!")
*otra-variable* ; "Hola mundo!"
La variable *otra-variable* sigue valiendo "Hola mundo!" porque ya estaba definida. Para sobreescribirla debes usar setf:

(setf *otra-variable* "Nos vemos luego!")
*otra-variable* ; "Nos vemos luego!"

Una buena práctica es no cambiar los valores de las variables dinámicas a menos que sea estrictamente necesario, ya que puede llevar a comportamientos inesperados en el código. En su lugar instancia variables locales dentro de funciones o bloques let.

(defparameter *impuesto* 21)

(defun calcular-precio-con-impuesto-reducido (precio)
  (let ((*impuesto* 10)) ; Variable local
    (* precio (+ 1 (/ *impuesto* 100)))))

This work is under a Attribution-NonCommercial-NoDerivatives 4.0 International license.

Desafíos de programación atemporales y multiparadigmáticos

Desafíos de programación atemporales y multiparadigmáticos

Te encuentras ante un librillo de actividades, divididas en 2 niveles de dificultad. Te enfrentarás a los casos más comunes que te puedes encontrar en pruebas técnicas o aprender conceptos elementales de programación.

Buy the book

Will you buy me a coffee?

Comments

There are no comments yet.

Visitors in real time

You are alone: 🐱