¿Por qué usar la función nula en lugar de==[] para verificar la lista vacía en Haskell?
is-empty empty-list (4)
Estoy leyendo el capítulo "Comenzando" de Learn You a Haskell for Great Good! . Dice:
null
comprueba si una lista está vacía. Si lo es, devuelveTrue
, de lo contrario devuelveFalse
. Use esta función en lugar dexs == []
(si tiene una lista llamadaxs
)
Lo intenté en Ghci:
xs = [] -- and then,
xs == []
null xs
Ambos son
True
.
Me pregunto cuál es la diferencia.
¿Debo usar la función
null
lugar de
== []
y por qué?
Además de las buenas respuestas dadas hasta ahora,
null
realidad tiene tipo
null :: Foldable t => t a -> Bool
No sé si ha llegado a las clases de tipos en LYAH, pero el problema es que
null
se puede usar no solo para listas, sino para cualquier estructura de datos que implemente
null
.
Esto quiere decir que el uso de
null
en un
Map
o en un
Set
es válido.
> 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 se pierde nada con escribir código más general.
Una nota al margen
En muchos casos, terminará queriendo usar una función como
null
para realizar 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 caja vacía.
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.
Hay una diferencia.
Para utilizar
x == []
, el tipo de los elementos de la lista debe ser un miembro de la clase de tipos
Eq
.
De hecho, la declaración de instancia define la verificación de la igualdad de dos listas:
instance Eq a => Eq [a] where
[] == [] = True
(x:xs) == (y:ys) = x == y && xs == ys
_ == _ = False
Eso significa que no puede usar
x == []
si
x
es, por ejemplo, una lista de
IO Int
s.
null :: [a] -> Bool
por otro lado, usa la coincidencia de patrones.
Esto se
implementa como
:
null :: [a] -> Bool null [] = True null (_:_) = False
Entonces, independientemente del tipo de elementos de la lista, siempre se verificará.
También una función simple que filtre toda la lista vacía fallaría:
withoutEmpty = filter (== [])
y eso sería:
withoutEmpty = filter null
Darse cuenta de:
withoutEmpty ls = filter (==[]) ls
Funcionará bien, pero el punto importante es que en algunos casos, como el otro, podría fallar.
También mire a @cole answer, que complementa todas las respuestas aquí, el typeclass Foldable tiene la función
null
que hay que implementar:
Para ver más información de Foldable aquí.
Usted debe utilizar
null
.
En la mayoría de los casos, no importa, pero es un buen hábito para hacerlo de todos modos, porque en ocasiones es posible que desee verificar si una lista de cosas no comparables está vacía.
Aquí hay un ejemplo corto y claro que muestra esta diferencia:
> null [id]
False
> [id] == []
<interactive>: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] == []