Haskell 列表理解无限列表问题
Haskell List comprehensions infinite list problem
我正在尝试学习 Haskell 和理解列表,但找不到解决方案:
mylist = [x*y | x <- [1..], y <- [1..]]
经过我的试验,结果是这样的
mylist = [1,2,3,4,5,...]
因为在列表理解中,x
取值 1
,然后 y
重复更改值。
但我的目标是完成不同的任务,以便获得以下结果:
mylist = [1,2,2,4,3,3,6.....]
我的意思是我想要混合组合而不是每个组合分开,因为我有一个严重的问题来获得合适的结果。
我再举个具体的例子
我想要一个包含以下形式的所有号码的列表:
num = 2^x * 3^y
x
和 y
必须采用所有值 >= 0
.
我的方法如下:
powers = [2^x * 3^y | x <- [0..], y <- [0..]]
但是这样我只取 3 的幂,因为 x
总是 0。
我试过这个
multiples = nub (merge (<=) powers2 powers3)
powers3 = [2^x * 3^y | x <- [0..], y <- [0..]]
powers2 = [2^x * 3^y | y <- [0..], x <- [0..]]
以便合并不同的值,但同样,值 6、12 等。缺少 - 结果是这样的:
mylist = [1,2,3,4,8,9,16,27,32,64,81...]
您显示的代码,
multiples = nub (merge (<=) powers2 powers3)
powers3 = [2^x * 3^y | x <- [0..], y <- [0..]]
powers2 = [2^x * 3^y | y <- [0..], x <- [0..]]
相当于
powers3 = [2^x * 3^y | x <- [0], y <- [0..]]
= [2^0 * 3^y | y <- [0..]]
= [3^y | y <- [0..]]
powers2 = [2^x * 3^y | y <- [0], x <- [0..]]
= [2^x * 3^0 | x <- [0..]]
= [2^x | x <- [0..]]
所以你只产生2和3的幂,没有任何混合倍数。因此,保证流中没有重复项,并且 nub
不是必需的。当然它是不完整的。
但是让我们换个角度来看。有人在评论中提议用这些数字创建一个二维网格:
mults23_2D = [[2^x * 3^y | y <- [0..]] | x <- [0..]]
{-
1 3 9 27 81 ...
2 6 18 54 ...
4 12 36 108 ...
8 24 72 ...
16 ...
.......
-}
现在我们有所进展。至少现在 none 被跳过了。我们只需要了解如何将它们 加入 成一个排序的、递增的数字流。简单的concat
当然不行。我们需要按顺序合并它们。一个众所周知的函数 merge
可以做到这一点,前提是参数已经排序,增加列表。
产生的每一行已经按递增顺序排列,但是它们有无限多。别怕,foldr
可以做到。我们定义
mults23 = foldr g [] [[2^x * 3^y | y <- [0..]] | x <- [0..]]
-- foldr g [] [a,b,c,...] == a `g` (b `g` (c `g` (....)))
where
g (x:xs) ys =
这里有点棘手。如果我们定义 g = merge
,我们将有一个 运行-away 递归,因为每个 merge
都想知道其 "right"(第二个)参数流的头元素。
为了防止这种情况,我们立即生成最左边的元素。
x : merge xs ys
就是这样。
工具使用
我需要一个无穷大的笛卡尔积函数。无限函数必须采用 table 的对角线。
对角线遍历的对模式为
0 0 – 0 1, 1 0 – 0 2, 1 1, 2 0 – 0 3, 1 2, 2 1, 3 0
我喜欢对称性,但模式是用第一个数字向前计数,用第二个数字向后计数,当用无限函数表示时是
diag2 xs ys = [ (m,n) | i<- [1..], (m,n) <- zip (take i xs) (reverse.take i $ ys) ]
无限生成只是为了使用任何数量,无论数量有多大。
可能重要的是,对完整的集合取对角线或三角数。
revt n
根据您的输入生成一个三角数。如果你想要 25 个元素 revt 25
将 return 7. tri 7
将 return 28 take
的参数。 revt
和 tri
是
tri n = foldl (+) 1 [2..n]
revt n = floor (sqrt (n*2))
制作和使用 taket
很好,直到您学会了前 10 个左右的三角数。
taket n xs = take (tri $ revt n) xs
现在,有了一些工具,我们将它们(主要是 1 个)应用到一个问题中。
[ 2^a * 3^b | (a,b) <- sort.taket 25 $ diag2 [0..] [0..]]
[1,3,9,27,81,243,729, 2,6,18,54,162,486, 4,12,36,108,324, 8,24,72,216, 16,48,144, 32,96, 64]
而且是对角线。第一组 7 长,第二组 6 长,倒数第二组 2 长,最后一组 1 长。 revt 25
是 7。tri 7
是输出列表的长度 28。
我正在尝试学习 Haskell 和理解列表,但找不到解决方案:
mylist = [x*y | x <- [1..], y <- [1..]]
经过我的试验,结果是这样的
mylist = [1,2,3,4,5,...]
因为在列表理解中,x
取值 1
,然后 y
重复更改值。
但我的目标是完成不同的任务,以便获得以下结果:
mylist = [1,2,2,4,3,3,6.....]
我的意思是我想要混合组合而不是每个组合分开,因为我有一个严重的问题来获得合适的结果。
我再举个具体的例子
我想要一个包含以下形式的所有号码的列表:
num = 2^x * 3^y
x
和 y
必须采用所有值 >= 0
.
我的方法如下:
powers = [2^x * 3^y | x <- [0..], y <- [0..]]
但是这样我只取 3 的幂,因为 x
总是 0。
我试过这个
multiples = nub (merge (<=) powers2 powers3)
powers3 = [2^x * 3^y | x <- [0..], y <- [0..]]
powers2 = [2^x * 3^y | y <- [0..], x <- [0..]]
以便合并不同的值,但同样,值 6、12 等。缺少 - 结果是这样的:
mylist = [1,2,3,4,8,9,16,27,32,64,81...]
您显示的代码,
multiples = nub (merge (<=) powers2 powers3)
powers3 = [2^x * 3^y | x <- [0..], y <- [0..]]
powers2 = [2^x * 3^y | y <- [0..], x <- [0..]]
相当于
powers3 = [2^x * 3^y | x <- [0], y <- [0..]]
= [2^0 * 3^y | y <- [0..]]
= [3^y | y <- [0..]]
powers2 = [2^x * 3^y | y <- [0], x <- [0..]]
= [2^x * 3^0 | x <- [0..]]
= [2^x | x <- [0..]]
所以你只产生2和3的幂,没有任何混合倍数。因此,保证流中没有重复项,并且 nub
不是必需的。当然它是不完整的。
但是让我们换个角度来看。有人在评论中提议用这些数字创建一个二维网格:
mults23_2D = [[2^x * 3^y | y <- [0..]] | x <- [0..]]
{-
1 3 9 27 81 ...
2 6 18 54 ...
4 12 36 108 ...
8 24 72 ...
16 ...
.......
-}
现在我们有所进展。至少现在 none 被跳过了。我们只需要了解如何将它们 加入 成一个排序的、递增的数字流。简单的concat
当然不行。我们需要按顺序合并它们。一个众所周知的函数 merge
可以做到这一点,前提是参数已经排序,增加列表。
产生的每一行已经按递增顺序排列,但是它们有无限多。别怕,foldr
可以做到。我们定义
mults23 = foldr g [] [[2^x * 3^y | y <- [0..]] | x <- [0..]]
-- foldr g [] [a,b,c,...] == a `g` (b `g` (c `g` (....)))
where
g (x:xs) ys =
这里有点棘手。如果我们定义 g = merge
,我们将有一个 运行-away 递归,因为每个 merge
都想知道其 "right"(第二个)参数流的头元素。
为了防止这种情况,我们立即生成最左边的元素。
x : merge xs ys
就是这样。
工具使用
我需要一个无穷大的笛卡尔积函数。无限函数必须采用 table 的对角线。 对角线遍历的对模式为
0 0 – 0 1, 1 0 – 0 2, 1 1, 2 0 – 0 3, 1 2, 2 1, 3 0
我喜欢对称性,但模式是用第一个数字向前计数,用第二个数字向后计数,当用无限函数表示时是
diag2 xs ys = [ (m,n) | i<- [1..], (m,n) <- zip (take i xs) (reverse.take i $ ys) ]
无限生成只是为了使用任何数量,无论数量有多大。
可能重要的是,对完整的集合取对角线或三角数。
revt n
根据您的输入生成一个三角数。如果你想要 25 个元素 revt 25
将 return 7. tri 7
将 return 28 take
的参数。 revt
和 tri
是
tri n = foldl (+) 1 [2..n]
revt n = floor (sqrt (n*2))
制作和使用 taket
很好,直到您学会了前 10 个左右的三角数。
taket n xs = take (tri $ revt n) xs
现在,有了一些工具,我们将它们(主要是 1 个)应用到一个问题中。
[ 2^a * 3^b | (a,b) <- sort.taket 25 $ diag2 [0..] [0..]]
[1,3,9,27,81,243,729, 2,6,18,54,162,486, 4,12,36,108,324, 8,24,72,216, 16,48,144, 32,96, 64]
而且是对角线。第一组 7 长,第二组 6 长,倒数第二组 2 长,最后一组 1 长。 revt 25
是 7。tri 7
是输出列表的长度 28。