Si la expresión if es como una Guards, Case ... of es como el encabezado de la función completa: puedes tener la coincidencia de patrones complejos que puedes usar con cada argumento, ¡y puedes tener Guards!
Escribiremos la función de agregar para conjuntos (una colección de valores únicos) que representaremos como una lista desordenada:
insert(X,[]) ->
[X];
insert(X,Set) ->
case lists:member(X,Set) of
true -> Set;
false -> [X|Set]
end.
Si enviamos un conjunto vacío y un término X para agregar, nos devuelve una lista que contiene solo X. De lo contrario, la función de listas: member/2 verifica si un elemento es parte de una lista y devuelve verdadero si es, falso si no lo es. En el caso de que ya tuviéramos el elemento X en el conjunto, no necesitamos modificar la lista. De lo contrario, agregamos X como primer elemento de la lista.
En este caso, la combinación de patrones fue realmente sencilla. Puede volverse más complejo:
beach(Temperature) ->
case Temperature of
{celsius, N} when N >= 20, N =< 45 ->
'favorable';
{kelvin, N} when N >= 293, N =< 318 ->
'scientifically favorable';
{fahrenheit, N} when N >= 68, N =< 113 ->
'favorable in the US';
_ ->
'avoid beach'
end.
Aquí, la respuesta de "¿es el momento adecuado para ir a la playa?" se da en 3 sistemas de temperatura diferentes: grados Celsius, Kelvin y Fahrenheit. El pattern matching y guards se combinan para devolver una respuesta que satisfaga todos los usos. Como se señaló anteriormente, case... of expresiones son más o menos lo mismo que un grupo de cabezales funcionales con guards. De hecho podríamos haber escrito nuestro código de la siguiente manera:
beachf({celsius, N}) when N >= 20, N =< 45 ->
'favorable';
...
beachf(_) ->
'avoid beach'.
Esto plantea la pregunta: ¿cuándo deberíamos usar funciones if o case... of ?