Variable list length

I am creating a list of lists via list comprehension, but I have no idea how to make the subscription length variable using a parameter. The input for the following is a tuple (first, second)

and Integer

z

:

z

= 1:

[[a] | a <- [first..second]]

      

z

= 2:

[[a, b] | a <- [first..second], b <- [first..second]]

      

z

= 3:

[[a, b, c] | a <- [first..second], b <- [first..second], c <- [first..second]]

      

+3


source to share


2 answers


You can use replicateM

for this task. It is defined as

replicateM :: Monad m => Int -> m a -> m [a]
replicateM n m = sequence (replicate n m)

      

The connection here is to turn list comprehension into notation do

:

[[a] | a <- [first..second]] == do
    a <- [first..second]
    return [a]

[[a, b] | a <- [first..second], b <- [first..second]] == do
    a <- [first..second]
    b <- [first..second]
    return [a, b]

[[a, b, c] | a <- [first..second], b <- [first..second], c <- [first..second]] == do
    a <- [first..second]
    b <- [first..second]
    c <- [first..second]
    return [a, b, c]

      

To make it clearer, replace [first..second]

with m

:



do  let m = [first..second]
    a <- m
    b <- m
    c <- m
    return [a, b, c]

      

So you can see that it is m

just replicated n

once hence replicateM

. See how the types line up too:

replicateM :: Monad m => Int -> m a -> m [a]

m ~ []

replicateM_List :: Int -> [a] -> [[a]]

      

If you need to do this on arbitrary lists, rather than just repeating the same list, you can simply use sequence

on it

+7


source


TL; DR use insight and fold or go with bheklilr replicateM suggestion

Understanding and fold

You know what you are doing with a list, so let's see how to do it recursively by first writing a function that adds the values โ€‹โ€‹of the list in every possible way, so

ghci> prepend "123" ["first","second"]
["1first","1second","2first","2second","3first","3second"]

      

prepend :: [a] -> [[a]] -> [[a]]
prepend xs yss = [x:ys| x<-xs, ys<-yss]

      

Now let's make a list of lists, first using replicate :: Int -> a -> [a]

to replicate our list n times, then prepend

each copy before the others, collapsing the list:

lol :: [a] -> Int -> [[a]]
lol xs n = foldr prepend [[]] $ replicate n xs

      

ghci> lol "ab" 3
["aaa","aab","aba","abb","baa","bab","bba","bbb"]
ghci> lol [1..3] 2
[[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]]

      

I'm sure you can figure out how to use this with a pair (start, finish)

as an argument.



replicateM

As bheklilr points out in the comment, we can import Control.Monad

both get

replicateM :: Monad m => Int -> m a -> m [a]

      

If you are an expert on lists, you get

replicateM :: Int -> [a] -> [[a]]

      

with what you want:

ghci> replicateM 2 [1..3]
[[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]]

      

If, like me, you don't have a brilliant mind like bheklilr, you can use hoogle like this to search for functions with the type you want ( [a] -> Int -> [[a]]

in this case) and find that third replicateM

. ( drop

and take

don't do what we want.)

+3


source







All Articles