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]]
source to share
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
source to share
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.)
source to share