Las condicionales en Racket son fundamentales para controlar el flujo de nuestros programas, permitiéndonos evaluar expresiones y devolver resultados distintos según el resultado de esas evaluaciones. En esencia, una condicional realiza un testeo y, dependiendo de si la condición es verdadera o falsa, devuelve un valor u otro.
En Racket, la forma más básica de condicional es la función if. Esta recibe tres partes: una condición, una expresión para el caso verdadero y otra para el caso falso. Por ejemplo, si escribimos:
(if true 'yep 'nope)
el resultado será 'yep' porque la condición es verdadera. Si la condición es false, devolverá 'nope'. Es importante destacar que en Racket cualquier valor que no sea false se considera verdadero, por lo que incluso un número como 2 se interpreta como verdadero en un if.
Para hacer nuestras condiciones más precisas, podemos usar funciones que verifican el tipo de dato de un valor. Por ejemplo, string? nos dice si un valor es una cadena, char? si es un carácter, y number? si es un número. Esto nos permite construir funciones que respondan según el tipo de dato que reciben. Por ejemplo:
(define (es-cadena x)
(if (string? x)
'yep
'nope))
Si llamamos a (es-cadena "hola") obtendremos 'yep', mientras que (es-cadena 4) devolverá 'nope'.
Además de verificar tipos, es común comparar valores. La función equal? es muy versátil para esto, ya que compara dos valores y devuelve true si son iguales, incluso si son listas, comparando recursivamente cada elemento. Por ejemplo:
(equal? "x" "x") ; devuelve true
(equal? "x" "y") ; devuelve false
(equal? '(1 2 3) '(1 2 3)) ; devuelve true
Para comparar números, Racket ofrece funciones como =, <, >, <= y >=. Estas funciones toman dos números y devuelven un booleano según la comparación. Por ejemplo:
(= 5 5) ; true
(> 1 0) ; true
(< 0 1) ; true
(>= 1 1) ; true
Es importante recordar que el orden de los argumentos importa: (> 1 0) es verdadero porque 1 es mayor que 0, pero (> 0 1) es falso.
En cuanto a operadores lógicos, Racket incluye las funciones and, or y not. La función and devuelve verdadero solo si todos sus argumentos son verdaderos, y puede recibir cualquier cantidad de parámetros:
(and true true true) ; true
(and true false true) ; false
Por su parte, or devuelve verdadero si al menos uno de sus argumentos es verdadero:
(or false false true) ; true
(or false false false) ; false
La función not invierte el valor booleano de su argumento:
(not true) ; false
(not false) ; true
Además, Racket incluye operadores menos comunes pero muy útiles, como nand, nor y xor. El operador nand devuelve falso solo si todos sus argumentos son verdaderos; en caso contrario, devuelve verdadero. Es como un not aplicado a un and:
(nand true true) ; false
(nand true false) ; true
El operador nor devuelve verdadero solo si todos sus argumentos son falsos, es decir, es un not aplicado a un or:
(nor false false) ; true
(nor false true) ; false
Por último, xor (o o exclusivo) devuelve verdadero solo si exactamente uno de sus dos argumentos es verdadero. A diferencia de and y or, xor solo acepta dos argumentos:
(xor true false) ; true
(xor true true) ; false
(xor false false) ; false
Cuando las condiciones se vuelven más complejas y necesitamos evaluar múltiples casos, anidar muchos if puede resultar engorroso y difícil de mantener. Para estos casos, Racket ofrece la expresión cond, que permite evaluar varias condiciones de forma ordenada y clara.
La sintaxis de cond consiste en una serie de pares, cada uno formado por una condición y una expresión a devolver si esa condición es verdadera. Estos pares se escriben entre corchetes. Por ejemplo, podemos definir una función que nos diga qué tipo de dato es un valor:
(define (que-soy x)
(cond
[(string? x) "string"]
[(number? x) "número"]
[(boolean? x) "booleano"]
[(char? x) "carácter"]
[else "no sé lo que soy"]))
En esta función, cond evalúa cada condición en orden. La primera que sea verdadera determina el resultado. Si ninguna condición se cumple, se ejecuta la cláusula else, que actúa como un caso por defecto.
Probando esta función:
(que-soy "hola") ; "string"
(que-soy 5) ; "número"
(que-soy true) ; "booleano"
(que-soy #\A) ; "carácter"
(que-soy '(1 2)) ; "no sé lo que soy"
Esto hace que cond sea una herramienta muy útil para evitar múltiples if anidados y mantener nuestro código limpio y legible.
En resumen, en Racket contamos con una variedad de herramientas para construir condicionales: desde el simple if, pasando por funciones para verificar tipos y comparar valores, hasta operadores lógicos que nos permiten combinar condiciones de forma flexible. Cuando las condiciones se multiplican, cond nos ayuda a organizar esas pruebas de manera clara y eficiente. Así podemos construir programas que respondan correctamente a diferentes situaciones y tipos de datos.