我发现扩展列表理解使这更容易阅读:
[ 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])。
现在@vili 的回答:
mult2 lst = concat [ [(n*2),(n*3)] | n <- lst]
这意味着:
mult2' lst = concat (concatMap (\n -> [[2*n,3*n]]) lst)
与上面的第一个解决方案一样,我们不必要地创建了一个列表列表,我们必须 concat 离开。
我认为没有使用列表推导的解决方案,但对mult1 进行了取消处理。我的直觉是 Haskell 编译器通常足够聪明,这无关紧要(或者,由于惰性评估,不必要的 concats 很便宜(而它们在急切的语言中是致命的))。