Я считаю, что расширение понимания списка облегчает чтение:
[ m | n <- [1..5], m <- [2*n,3*n] ]
Может быть полезно изучить, что именно это делает и как это связано с другими решениями. Давайте определим это как функцию:
mult lst = [ m | n <- lst, m <- [2*n,3*n] ]
После моды, это Desugars до
mult' lst =
concatMap (\n -> concatMap (\m -> [m]) [2*n,3*n]) lst
Выражение concatMap (\m -> [m])
помещает m
в список для немедленного выравнивания его - это эквивалентно map id
.
Сравните это с ответом @ FunctorSalad:
mult1 lst = concatMap (\n -> [n*2,n*3]) lst
Мы оптимизировали прочь concatMap (\m -> [m])
.
Теперь @ Вили ответ:
mult2 lst = concat [ [(n*2),(n*3)] | n <- lst]
Это desugars к:
mult2' lst = concat (concatMap (\n -> [[2*n,3*n]]) lst)
Как и в первом решении, приведенном выше, мы излишне создаем список списков, которые мы должны concat
удалить.
Я не думаю, что есть решение, которое использует списки, но десугары для mult1
. Моя интуиция заключается в том, что компиляторы Haskell, как правило, достаточно умны, чтобы это не имело значения (или, наоборот, ненужные concat
являются дешевыми из-за ленивых вычислений (в то время как они смертельны для активных языков)).