我通过列表理解生成列表列表,但我不知道如何通过使用参数使子列表的长度变量。以下输入是元组(first, second)
和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]]
答案 0 :(得分:8)
您可以使用replicateM
执行此任务。它被定义为
replicateM :: Monad m => Int -> m a -> m [a]
replicateM n m = sequence (replicate n m)
此处的连接是将列表理解转换为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]
为了更清楚,让我们将[first..second]
替换为m
:
do let m = [first..second]
a <- m
b <- m
c <- m
return [a, b, c]
所以在这里你可以看到m
刚刚被复制n
次,因此replicateM
。让我们看看这些类型是如何排列的:
replicateM :: Monad m => Int -> m a -> m [a]
m ~ []
replicateM_List :: Int -> [a] -> [[a]]
如果您需要在任意列表上执行此操作,而不仅仅是重复相同的列表,您可以在其上使用sequence
答案 1 :(得分:5)
TL; DR使用理解和折叠或者使用bheklilr的复制M建议
你知道你对列表理解做了些什么,所以让我们先看一下以一切可能的方式预先列出列表值的函数来递归地看待如何做到这一点,以便
ghci> prepend "123" ["first","second"]
["1first","1second","2first","2second","3first","3second"]
prepend :: [a] -> [[a]] -> [[a]]
prepend xs yss = [x:ys| x<-xs, ys<-yss]
现在让我们制作列表列表,首先使用replicate :: Int -> a -> [a]
复制我们的列表n次,然后通过折叠列表prepend
复制其他列表前面的每个副本:
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]]
我确定你可以弄清楚如何使用(start, finish)
对作为参数。
正如bheklilr在评论中指出的那样,我们可以import Control.Monad
并获得
replicateM :: Monad m => Int -> m a -> m [a]
如果您是专家,那么
replicateM :: Int -> [a] -> [[a]]
做那样做你想要的:
ghci> replicateM 2 [1..3]
[[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]]
如果像我一样,你没有像bheklil一样聪明的心态,
你可以使用hoogle like this来搜索我们需要的类型的函数(在这种情况下为[a] -> Int -> [[a]]
),并找到第三个函数为replicateM
。 (drop
和take
不做我们想做的事。)