2016-09-11 31 views
0

我很新的Haskell和想知道如何實現以下輸出,而無需使用一個固定的理解列表(或的確是一個適用函子像liftA)即上正列表Control.Applicative提升

> [ [x+y+z] | x <- [1,11], y <- [1,11], z <- [1,11]] 
> [[3],[13],[13],[23],[13],[23],[23],[33]] 

上面的代碼示例僅處理3個列表,例如XYZ。我如何用n個列表來實現同樣的事情,例如例如[[1,11]]或[[1,11],[1,11],[1,11],[1,11],[1,11]]?我使用一個控制應用函數liftA但看它的限制liftA3例如,

λ> :m + Control.Applicative 
λ> let combine = liftA2 (,) 
λ> combine "ab" "cd" 
[('a','c'),('a','d'),('b','c'),('b','d')] 

謝謝。

回答

3

如果您使用的是同一列表的ň副本[1,11]您可以使用replicateM

import Control.Monad 

ghci> replicateM 3 [1,11] 
[[1,1,1],[1,1,11],[1,11,1],[1,11,11],[11,1,1],[11,1,11],[11,11,1],[11,11,11]] 

ghci> map sum (replicateM 3 [1,11]) 
[3,13,13,23,13,23,23,33] 

在一般情況下,你可以使用sequence執行多表笛卡爾乘積:

ghci> sequence [ [1,11], [2,22], [3,33] ] 
[[1,2,3],[1,2,33],[1,22,3],[1,22,33],[11,2,3],[11,2,33],[11,22,3],[11,22,33]] 
+0

是的,謝謝 - 尋找... nub $ map sum $ sequence [[1,11],[1,11]]等等,因爲它不是monadic ... – Craig

0

如果您想要處理輸入的靈活性,這些輸入不只是列表[1,11]

λ> import Control.Applicative (liftA2) 
λ> let sumsOfCombinations xs = (:[]) . sum <$> foldr (liftA2 (:)) [[]] xs 

你可以通過它的數字列表中的任何名單:

λ> sumsOfCombinations' [[0,100],[-1,0,1],[0,1000]] 
[-1,999,0,1000,1,1001,99,1099,100,1100,101,1101] 

包括,但不限於,你的例子:

λ> sumsOfCombinations $ replicate 3 [1,11] 
[[3],[13],[13],[23],[13],[23],[23],[33]] 

λ> sumsOfCombinations $ replicate 4 [1,11] 
[[4],[14],[14],[24],[14],[24],[24],[34],[14],[24],[24],[34],[24],[34],[34],[44]] 

下面是它的類型:

λ> :t sumsOfCombinations 
sumsOfCombinations :: (Num b, Foldable t) => t [b] -> [[b]] 

A寫的,sumsOfCombinations給你你正在尋找的確切輸出。不過,我不認爲這是必要返回一個列表的列表,所以我會選擇:

λ> let sumsOfCombinations' xs = sum <$> foldr (liftA2 (:)) [[]] xs 

λ> :t sumsOfCombinations' 
sumsOfCombinations' :: (Num b, Foldable t) => t [b] -> [b] 

λ> sumsOfCombinations' $ replicate 3 [1,11] 
[3,13,13,23,13,23,23,33] 

注意,您可以從每一種提取助手,讓您從列表中元素的組合:

λ> let combinations = foldr (liftA2 (:)) [[]] 
λ> combinations [[1,2],[3,4],[5,6]] 
[[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]] 

,那麼你必須:

sumsOfCombinations xs = (:[]) . sum <$> combinations xs 

,或者,如果你不需要返回一個列表的列表:

sumsOfCombinations' xs = sum <$> combinations xs 
0

更一般地說,你想要的是給定列表中所有列表的笛卡爾乘積。一旦你有了,那麼你可以以任何你喜歡的方式將它們結合起來。

cartesian :: [[a]] -> [[a]] 
cartesian [] = [[]] 
cartesian (xs:xss) = [x : ys | x <- xs, ys <- cartesian xss] 

mkSums :: [[Int]] -> [[Int]] 
mkSums = map ((\x -> [x]) . sum) . cartesian