Taller de Elixir #6 – Case, cond e if

Las estructuras de flujo de control de flujo son case, cond e if.

Case

Case nos permite comparar un valor con muchos patrones hasta que encontremos uno coincidente:

iex> case {1, 2, 3} do
...>   {4, 5, 6} ->
...>     "This clause won't match"
...>   {1, x, 3} ->
...>     "This clause will match and bind x to 2 in this clause"
...>   _ ->
...>     "This clause would match any value"
...> end
"This clause will match and bind x to 2 in this clause"

Si desea comparar patrones con una variable existente, debe usar el operador ^:

iex> x = 1
1
iex> case 10 do
...>   ^x -> "Won't match"
...>   _ -> "Will match"
...> end
"Will match"

Las cláusulas también permiten que se especifiquen condiciones adicionales a través de guards:

iex> case {1, 2, 3} do
...>   {1, x, 3} when x > 0 ->
...>     "Will match"
...>   _ ->
...>     "Would match, if guard condition were not satisfied"
...> end
"Will match"

La primera cláusula anterior solo coincidirá cuando x sea positivo.

Tenga en cuenta que los errores en los guardias no tienen fugas, sino que simplemente hacen que el guardia falle:

iex> hd(1)
** (ArgumentError) argument error
iex> case 1 do
...>   x when hd(x) -> "Won't match"
...>   x -> "Got #{x}"
...> end
"Got 1"

Si ninguna de las cláusulas coincide, se genera un error:

iex> case :ok do
...>   :error -> "Won't match"
...> end
** (CaseClauseError) no case clause matching: :ok

Consulte la documentación completa de los guardias para obtener más información sobre los guardias, cómo se usan y qué expresiones están permitidas en ellos.

Tenga en cuenta que las funciones anónimas también pueden tener múltiples cláusulas y guardias:

iex> f = fn
...>   x, y when x > 0 -> x + y
...>   x, y -> x * y
...> end
<12.71889879/2 in :erl_eval.expr/5>
iex> f.(1, 3)
4
iex> f.(-1, 3)
-3

El número de argumentos en cada cláusula de función anónima debe ser el mismo, de lo contrario se genera un error.

iex> f2 = fn
...>   x, y when x > 0 -> x + y
...>   x, y, z -> x * y + z
...> end
** (CompileError) iex:1: cannot mix clauses with different arities in anonymous functions

Cond

Case es útil cuando necesita hacer coincidir valores diferentes. Sin embargo, en muchas circunstancias, queremos verificar diferentes condiciones y encontrar la primera que no se evalúa como nula o falsa. En tales casos, uno puede usar cond:

iex> cond do
...>   2 + 2 == 5 ->
...>     "This will not be true"
...>   2 * 2 == 3 ->
...>     "Nor this"
...>   1 + 1 == 2 ->
...>     "But this will"
...> end
"But this will"

Esto es equivalente a las cláusulas else if en muchos idiomas imperativos (aunque aquí se usan con menos frecuencia).

Si todas las condiciones devuelven nulo o falso, se genera un error (CondClauseError). Por esta razón, puede ser necesario agregar una condición final, igual a verdadera, que siempre coincidirá con:

iex> cond do
...>   2 + 2 == 5 ->
...>     "This is never true"
...>   2 * 2 == 3 ->
...>     "Nor this"
...>   true ->
...>     "This is always true (equivalent to else)"
...> end
"This is always true (equivalent to else)"

Finalmente, note cond considera que cualquier valor además de nil y false es verdadero:

iex> cond do
...>   hd([1, 2, 3]) ->
...>     "1 is considered as true"
...> end
"1 is considered as true"

if y unless

Además de case y cond, también tenemos las macros if/2 y unless/2, que son útiles cuando necesita verificar una sola condición:

iex> if true do
...>   "This works!"
...> end
"This works!"
iex> unless true do
...>   "This will never be seen"
...> end
nil

Si la condición if/2 devuelve false o nil, el cuerpo dado entre do/end no se ejecuta y en su lugar devuelve nil. Lo contrario sucede con unless/2.

También admiten bloques más:

iex> if nil do
...>   "This won't be seen"
...> else
...>   "This will"
...> end
"This will"

Bloques do/end

Como hemos visto en las cuatro estructuras de control: case, cond, if y unless. En todas estaban envueltas en bloques do/end. Sucede que también podríamos escribir si es así:

iex> if true, do: 1 + 2
3

Los bloques do/end son una conveniencia sintáctica construida sobre las palabras clave. Es por eso que los bloques do/end no requieren una coma entre el argumento anterior y el bloque. Son útiles exactamente porque eliminan la verbosidad al escribir bloques de código. Estos son equivalentes:

iex> if true do
...>   a = 1 + 2
...>   a + 10
...> end
13
iex> if true, do: (
...>   a = 1 + 2
...>   a + 10
...> )
13

Las listas de palabras clave juegan un papel importante en el lenguaje y son bastante comunes en muchas funciones y macros.

Deja una respuesta