2010-02-27 7 views
2

Je suis curieux de savoir s'il est possible de construire dynamiquement une liste de compréhension dans Haskell.Construire dynamiquement la compréhension de liste dans Haskell

À titre d'exemple, si je donne les résultats suivants:

all_pows (a,a') (b,b') = [ a^y * b^z | y <- take a' [0..], z <- take b' [0..] ] 

-je obtenir ce que je suis après

*Main> List.sort $ all_pows (2,3) (5,3) 
[1,2,4,5,10,20,25,50,100] 

Cependant, ce que je voudrais vraiment est d'avoir quelque chose comme

all_pows [(Int,Int)] -> [Integer] 

Pour que je puisse supporter N paires d'arguments sans construire N versions de all_pows. Je suis encore assez nouveau pour Haskell, alors j'ai peut-être oublié quelque chose d'évident. Est-ce seulement possible?

Répondre

11

La magie de la liste monade:

 
ghci> let powers (a, b) = [a^n | n <- [0 .. b-1]] 
ghci> powers (2, 3) 
[1,2,4] 
ghci> map powers [(2, 3), (5, 3)] 
[[1,2,4],[1,5,25]] 
ghci> sequence it 
[[1,1],[1,5],[1,25],[2,1],[2,5],[2,25],[4,1],[4,5],[4,25]] 
ghci> mapM powers [(2, 3), (5, 3)] 
[[1,1],[1,5],[1,25],[2,1],[2,5],[2,25],[4,1],[4,5],[4,25]] 
ghci> map product it 
[1,5,25,2,10,50,4,20,100] 
ghci> let allPowers list = map product $ mapM powers list 
ghci> allPowers [(2, 3), (5, 3)] 
[1,5,25,2,10,50,4,20,100] 

Cela mérite sans doute un peu plus d'explications.

Vous auriez pu écrire votre propre

cartesianProduct :: [[a]] -> [[a]] 
cartesianProduct [] = [[]] 
cartesianProduct (list:lists) 
    = [ (x:xs) | x <- list, xs <- cartesianProduct lists ] 

telle que cartesianProduct [[1],[2,3],[4,5,6]][[1,2,4],[1,2,5],[1,2,6],[1,3,4],[1,3,5],[1,3,6]]. Cependant, comprehensions et monads sont intentionnellement similaires. Le Prelude standard a sequence :: Monad m => [m a] -> m [a], et quand m est la liste monad [], il fait exactement ce que nous avons écrit ci-dessus. Comme autre raccourci, mapM :: Monad m => (a -> m b) -> [a] -> m [b] est simplement une composition de sequence et map.

Pour chaque liste interne de puissances différentes de chaque base, vous souhaitez les multiplier par un nombre unique. Vous pouvez écrire ce récursive

product list = product' 1 list 
    where product' accum [] = accum 
     product' accum (x:xs) 
      = let accum' = accum * x 
      in accum' `seq` product' accum' xs 

ou à l'aide d'un pli

import Data.List 
product list = foldl' (*) 1 list 

mais en fait, product :: Num a => [a] -> a est déjà défini! J'aime cette langue ☺☺☺

+0

'let pouvoirs (a, b) = [a^n | n <- [0 .. b-1]] ' – Tordek

+0

@Tordek Merci, j'ai survolé l'original un peu trop vite. – ephemient

+0

Magnifique, merci. – ezpz

Questions connexes