2009-02-20 92 views
6

因此,例如,我說我有一個數字列表,我想創建一個包含每個數字乘以2和3的列表。是否有任何方法可以執行類似以下操作的任何方法,但可以取回單個數字列表而不是列表中的數字列表?你可以在Haskell中一次創建列表理解的多個元素嗎?

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] 

回答

13

你可以使用concat。

concat [ [(n*2),(n*3)] | n <- [1..5]] 
output: [2,3,4,6,6,9,8,12,10,15] 
5

在一些類似的案件concatMap也可方便,但這裏並沒有太大變化:

concatMap (\n -> [n*2,n*3]) [1..5]
+0

對於實例Monad []`,`(>> =)== flip concatMap` ......似乎Chris的回答掩蓋了該部分,但這個答案是上面的一個子集。 – ephemient 2009-07-06 20:51:59

17

我發現擴展列表理解使這更易於閱讀:

[ 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] 

這desugars到:

mult2' lst = concat (concatMap (\n -> [[2*n,3*n]]) lst) 

作爲第一個解決方案上面,我們是不必要的創建,我們必須concat離開列表的列表。

我不認爲有一個解決方案,使用列表解析,但desugars到mult1。我的直覺是,Haskell編譯器通常足夠聰明,這並不重要(或者,由於懶惰的評估(儘管它們在渴望的語言中它們是致命的),不必要的concat很便宜)。

相關問題