¿Se puede crear más de un elemento de una lista a la vez con una lista de comprensión Haskell?
-
05-09-2019 - |
Pregunta
Así, por ejemplo, decir que tenía una lista de números y quería crear una lista que contenía cada número multiplicado por 2 y 3. ¿Hay alguna manera de hacer algo como lo siguiente, pero volver a una lista única de números en lugar de una lista de listas de números?
mult_nums = [ [(n*2),(n*3)] | n <- [1..5]]
-- this returns [[2,3],[4,6],[6,9],[8,12],[10,15]]
-- but we want [2,3,4,6,6,9,8,12,10,15]
Solución
podría utilizar concat.
concat [ [(n*2),(n*3)] | n <- [1..5]]
output: [2,3,4,6,6,9,8,12,10,15]
Otros consejos
Me parece que se amplía la lista de comprensión hace que esto sea más fácil de leer:
[ m | n <- [1..5], m <- [2*n,3*n] ]
Podría ser útil examinar exactamente lo que esto hace, y cómo se relaciona con otras soluciones. Vamos a definir como una función:
mult lst = [ m | n <- lst, m <- [2*n,3*n] ]
Después de una moda, este desugars a
mult' lst =
concatMap (\n -> concatMap (\m -> [m]) [2*n,3*n]) lst
El concatMap (\m -> [m])
expresión está terminando m
en una lista con el fin de aplanar inmediatamente-es equivalente a map id
.
Compare esto con la respuesta de @ FunctorSalad:
mult1 lst = concatMap (\n -> [n*2,n*3]) lst
Hemos optimizado de distancia concatMap (\m -> [m])
.
Ahora @ respuesta de Vili:
mult2 lst = concat [ [(n*2),(n*3)] | n <- lst]
Esta desugars a:
mult2' lst = concat (concatMap (\n -> [[2*n,3*n]]) lst)
Al igual que en la primera solución anterior, estamos creando innecesariamente una lista de listas que tenemos que concat
de distancia.
No creo que hay una solución que utiliza listas por comprensión, pero desugars a mult1
. Mi intuición es que los compiladores de Haskell son generalmente lo suficientemente inteligente que esto no tendría importancia (o, alternativamente, que concat
s innecesarios son baratos debido a la evaluación perezosa (mientras que son letales en idiomas ansiosos)).
En algunos casos similares concatMap también puede ser conveniente, aunque aquí no cambia mucho:
concatMap (\n -> [n*2,n*3]) [1..5]