Siéntete en la libertad de compartir nuestros tutoriales y códigos en tus redes, necesitamos de tu ayuda para ampliar nuestra comunidad.
Solución:
Deberías usar null
. En la mayoría de los casos no importa, pero de todos modos es un buen hábito, porque de vez en cuando querrás comprobar si una lista de cosas no comparables está vacía. Aquí hay un ejemplo breve y nítido que muestra esta diferencia:
> null [id]
False
> [id] == []
:1:1: error:
• No instance for (Eq (a0 -> a0)) arising from a use of ‘==’
(maybe you haven't applied a function to enough arguments?)
• In the expression: [id] == []
In an equation for ‘it’: it = [id] == []
Hay una diferencia. Para usar x == []
el tipo de los elementos de la lista debe ser un miembro de la Eq
clase de tipo. De hecho, la verificación de la igualdad de dos listas se define mediante la declaración de instancia:
instance Eq a => Eq [a] where
[] == [] = True
(x:xs) == (y:ys) = x == y && xs == ys
_ == _ = False
Eso significa que no puedes usar x == []
si x
es por ejemplo una lista de IO Int
s.
null :: [a] -> Bool
por otro lado, utiliza la coincidencia de patrones. Esto se implementa como:
null :: [a] -> Bool null [] = True null (_:_) = False
Entonces, independientemente de qué tipo sean los elementos de la lista, siempre se verificará el tipo.
Además de las buenas respuestas dadas hasta ahora, null
en realidad tiene tipo
null :: Foldable t => t a -> Bool
No sé si has llegado a typeclasses en LYAH, pero en resumen es que null
se puede usar no solo para listas, sino para cualquier estructura de datos que implemente null
.
Esto quiere decir que usando null
en un Map
o un Set
es válido, también.
> null Map.empty
True
> null (Map.singleton 1)
False
> null Set.empty
True
> null (Set.singleton 1)
False
> null []
True
> null [1]
False
No creo que sea especialmente común escribir funciones que deban ser tan generales, pero no está de más escribir por defecto un código más general.
Una nota al margen
En muchos casos, terminará queriendo usar una función como null
para hacer un comportamiento condicional en una lista (u otra estructura de datos). Si ya sabe que su entrada es una estructura de datos específica, es más elegante simplemente hacer coincidir el patrón en su caso vacío.
Comparar
myMap :: (a -> b) -> [a] -> [b]
myMap f xs
| null xs = []
myMap f (x:xs) = f x : myMap f xs
a
myMap' :: (a -> b) -> [a] -> [b]
myMap' f [] = []
myMap' f (x:xs) = f x : myMap' f xs
En general, debe intentar preferir la coincidencia de patrones si tiene sentido.