¿Se puede crear más de un elemento de una lista a la vez con una lista de comprensión Haskell?

StackOverflow https://stackoverflow.com/questions/567840

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]
¿Fue útil?

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 concats 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]
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top