2009-12-06 4 views
2

Donc, je regardais la question here, et construit une solution plutôt laide pour le problème. Tout en essayant de le nettoyer, j'ai commencé à enquêter sur la compréhension de la liste et la liste de la monade. Ce que j'ai décidé de faire était de mettre en place un compteur par chiffre en utilisant la liste monad. Compte tenu d'une séquence d'entrée de chiffres, [1, 2], je voulais générer une séquence de sortie qui ressemblait à:mettre en œuvre un compteur par chiffre en utilisant la liste monad

[ [ 0, 0], 
    [ 0, 1 ], 
    [ 0, 2 ], 
    [ 1, 0 ], 
    [ 1, 1 ], 
    [ 1, 2 ] ] 

C'est, j'itérer sur toutes les valeurs possibles de tous les éléments dans la liste dans cette gamme.

Le haskell.org list monad documentation dit:

La fonction liée est appliquée à toutes les valeurs possibles dans la liste d'entrée et les listes résultantes sont concaténés pour produire une liste de tous les résultats possibles.

Excellent! On dirait parfait ... Voici le code que j'ai écrit pour produire la solution:

count :: [Integer] -> [[Integer]] 
count [] = [] 
count (x:xs) = 
    -- get all possible sequences for the remaining digits 
    let 
    remDigits :: [[Integer]] 
    remDigits = count xs 
    in 
    -- pull out a possible sequence for the remaining digits 
    do nextDigits <- remDigits 
    -- pull out all possible values for the current digit 
    y <- [0..x] 
    -- record that "current digit" : "remaining digits" is 
    -- a valid output. 
    return (y:nextDigits) 

Mais appeler count avec tout produit la liste vide, et je ne sais pas pourquoi. Qu'est-ce que je rate?

+2

Si vous changez simplement votre cas de base en 'count [] = [[]]', ce code fonctionne. – ephemient

+0

En fait, c'était précisément la réponse que je cherchais ... J'avais compris que mon problème était que, dans le cas de base, il n'y avait pas de solution dans la liste monad, donc il n'y avait rien à construire. La réponse de CBFraser ci-dessous a abordé cela, mais votre solution est plus proche de ce que j'avais en tête à l'origine. –

Répondre

2

Tout d'abord, vous avez besoin d'un cas de base pour la liste singleton en tant qu'argument. Essayez ceci:

count :: [Integer] -> [[Integer]] 
count [] = [] 
count [n] = map (\x -> [x]) [0..n] 
count (x:xs) = 
    do y <- [0..x] 
     nextDigits <- count xs 
     return (y:nextDigits) 

main = do 
    print $ count [1] 
    print $ count [1,2] 
+1

Produit un résultat différent de celui spécifié par l'OP! – Dario

+0

Merci - vous avez absolument raison. –

+0

Le bug restant concerne l'ordre dans lequel j'utilisais les monades. J'aurais dû avoir y <- [0..x] à l'extérieur, et nextDigits <- compter xs à l'intérieur. –

8
count = sequence . map (enumFromTo 0) 

Oui, il est vraiment aussi simple que cela. Faites un essai :)

+0

+1, c'est une très belle solution – CBFraser

+0

+1 pour être sans point mais pas inutile;) – Dario

3

Pour être complet, vous pouvez également exprimer la logique comme la compréhension de la liste, ce qui est probablement la meilleure façon d'utiliser la liste monade pour des fonctions simples:

count (x:xs) = [ (y:ys) | y <- [0..x], ys <- count xs ] 
8

encore plus court

count = mapM (enumFromTo 0) 
+1

D'oh, je ne sais pas comment j'ai raté la traduction mécanique de 'sequence + map' à' mapM', mais +1 pour l'amélioration évidente: D – ephemient

Questions connexes