Comparar elementos de dos listas en Haskell

publicado por: Anonymous

He probado a comparar elementos pertenecientes a dos listas en Haskell y no termino de comprender el resultado obtenido.

Cito de aprendehaskell.es:

Las listas pueden ser comparadas si los elementos que contienen pueden ser comparados. Cuando usamos <, <=, >, y >= para comparar listas, son comparadas en orden lexicográfico. Primero son comparadas las cabezas. Luego son comparados los segundos elementos y así sucesivamente.

Decidí probar en el compilador WinGHCI la siguiente comparación:

Prelude> [1,2,3] < [4,5,2]

El resultado obtenido fue: True

Lo que yo entendía de la cita, es que al ir comparando en orden lexicográfico, primero compara el 1 con el 4, y como 1<4, es true, después compara el 2 con el 5, y como 2<5 es true, pero, al comparar 3<2 debería salir false. De manera que el resultado que yo esperaba era false. Sin embargo, obtengo true.

La pregunta es, ¿Haskell solo compara el primer elemento y no compara el resto?, o ¿compara primero el primero, luego el segundo…? PERO ¿siempre se queda con el resultado del primero? lo cual sería absurdo, pues no tendría sentido realizar el resto de operaciones ya que el resultado no va a variar.

Gracias

solución

Cuando dos listas se comparan por orden lexicográfico, se comparan elemento a elemento hasta que alguno de ellos difiere, o hasta que se acaban los elementos de alguna de las dos listas (en cuyo caso todos los elementos hasta el momento eran iguales y es más pequeña la lista con menos elementos). Esto no es una característica especial de Haskell, otros lenguajes como Python implementan el mismo criterio.

Por eso, en tu ejemplo [1,2,3] < [4,5,2] la primera lista es menor que la segunda, porque el primer elemento de la primera ya es menor que el primer elemento de la segunda. Si las listas fuesen [4,5,2] < [4,5,1], como los dos primeros elementos de ambas listas son iguales, llegaría a compararse el 2 con el 1, determinando que la primera lista es mayor que la segunda.

La comparación que tú esperas, donde todos los elementos deben ser mayores, menores, etc, puedes conseguirla por ejemplo, comparando los elementos con zipWith:

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

zipWith toma una función (en este caso (<), (>), (<=) o (>=)) y dos listas, y combina las listas aplicando dicha función. Por ejemplo:

ghci> zipWith (<) [1,2,3] [4,5,2]
[True, True, False]

Finalmente, puedes utilizar la función and :: Foldable t => t Bool -> Bool
para comprobar que todos los elementos de la lista son True, es decir, que todos los elementos satisfacen la relación de orden aplicada elemento a elemento.

ghci> and $ zipWith (<) [1,2,3] [4,5,2]
False
ghci> and $ zipWith (<) [1,2,3] [4,5,6]
True
ghci> and $ zipWith (>=) [1,2,6] [1,2,1]
True
Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *