2016-09-11 2 views
0

Ich bin ganz neu in Haskell und würde gerne wissen, wie die folgende Ausgabe zu erzielen, ohne eine feste Verständnis Liste (oder in der Tat eine applicative Funktors wie lifta) unter Verwendung dhControl.Applicative Hebe auf n-Listen

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

Das obige Codebeispiel verarbeitet nur 3 Listen zB xyz. Wie kann ich dasselbe erreichen, indem n Listen verwendet werden, z. z.B. [[1,11]] oder [[1,11], [1,11], [1,11], [1,11], [1,11]]?

PS - Ich sah mit einer Steuerung Applicative Funktor LiftA, aber es ist begrenzt auf LiftA3 z.

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

Danke.

Antwort

3

Wenn Sie n Kopien derselben Liste mit [1,11] Sie replicateM verwenden können:

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] 

In der Regel können Sie sequence verwenden, um ein Multi-Liste kartesisches Produkt auszuführen:

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

ja danke - auf der Suche nach ... nub $ map sum $ Sequenz [[1,11], [1,11]] usw. als nicht monadisch ... – Craig

0

Wenn Sie die Flexibilität der Handhabung von Eingängen wollen, die nicht nur Listen von [1,11] sind:

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

Sie können jede Liste der Liste der Nummern übergeben:

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

Einschließlich aber nicht beschränkt auf, Ihr Beispiel:

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

Hier ist seine Art:

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

A s geschrieben, sumsOfCombinations gibt Ihnen die genaue Ausgabe, die Sie suchen. Aber ich glaube nicht, ist es notwendig, eine Liste von Listen zurück, so würde ich wählen:

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

Beachten Sie, dass Sie einen Helfer aus jedem dieser extrahieren können, um Ihnen die Kombinationen von Elementen aus den Listen :

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

Also dann haben Sie:

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

oder, wenn Sie nicht über eine Liste von Listen zurückgeben müssen:

sumsOfCombinations' xs = sum <$> combinations xs 
0

Allgemeiner, was Sie wollen, ist das kartesische Produkt aller Listen in einer gegebenen Liste. Sobald Sie das haben, können Sie sie beliebig kombinieren.

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

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