List monad - Haskell

Welcome to the Functional Programming Zulip Chat Archive. You can join the chat here.

Vincent L

Hi, I found a small exercice: counting all the tuple (x1, x2, x3, x4) whose sum is equal to 18. For that I used list comprehension:

allCombination n = [(x1, x2, x3, x4)|
  x1 <- lst,
  x2 <- lst,
  x3 <- lst,
  x4 <- lst,
  x1 + x2 + x3 + x4 == n]
  where lst = [0..n]

main = putStrLn $ show $ length (allCombination 18)

Is it possible to be more generic ? Like here I have a tuple of 4 element but would it be possible to have an arbitrary number of element ? For instance via a monad.

Vincent L

Something like

import Control.Monad

allCombination eltcnt n =  do
  newlst <- traverse undefined [0..eltcnt]
  guard $  (sum newlst) == n
  where lst = [0..n]


main = putStrLn $ show $ length (allCombination 4 18)

Issue is, I'm not sure traverse will work as I expect it to do

Vincent L

if I replace undefined by \_-> lst it doesn't work unfortunatly

Vincent L

hmm actually it does weird

Vincent L

nvm I got my interval wrong

Bernd Losert

If you use this guy, you could do it like this:

allCombination eltcnt n = do
  candidate <- variateRep eltcnt [0..n]
  guard (sum candidate == n)
Bernd Losert

Or more simply:

allCombination eltcnt n = filter (\ candidate -> sum candidate == n) (variateRep eltcnt [0..n])
rhendric

More generally, replicateM does the same thing and lives in the base library. (Not sure what the advantage of variateRep would be. Better handling if eltcnt is negative, maybe? Performance?)

bradrn

Yes, I’d do:

allCombination n = fmap tuplize $ filter ((==18) . sum) $ replicateM 4 [0..n]
  where tuplize [a,b,c,d] = (a,b,c,d)