简体   繁体   English

Haskell 列表推导式无限列表问题

[英]Haskell List comprehensions infinite list problem

I'm trying to learn Haskell and comprehension lists but cannot find solution on this:我正在尝试学习 Haskell 和理解列表,但找不到解决方案:

mylist = [x*y | x <- [1..], y <- [1..]]

After my trials the result is something like this经过我的试验,结果是这样的

mylist = [1,2,3,4,5,...]

because in list comprehensions, x takes the value 1 ,and then y changes value repeatedly.因为在列表推导式中, x取值为1 ,然后y重复更改值。

But my goal is to achieve a different assignment so as to have the following result:但我的目标是完成不同的任务,从而得到以下结果:

mylist = [1,2,2,4,3,3,6.....]

I mean i want the combinations being mixed and not each one apart,because I have a serious problem to have the suitable result.我的意思是我想要混合组合而不是每个组合,因为我有一个严重的问题来获得合适的结果。

I will give a more specific example.我会举一个更具体的例子。

I want a list that will have all numbers of this form:我想要一个包含这种形式的所有数字的列表:

num = 2^x * 3^y 

x and y must take all values >= 0 . xy必须取所有值>= 0

My approach is the following:我的方法如下:

powers = [2^x * 3^y | x <- [0..], y <- [0..]]

But in this way I only take powers of 3, because x is constantly 0.但是这样我只取 3 的幂,因为x始终为 0。

I tried this one我试过这个

multiples = nub (merge (<=) powers2 powers3)
powers3 = [2^x * 3^y | x <- [0..], y <- [0..]]
powers2 = [2^x * 3^y | y <- [0..], x <- [0..]]

so as to merge the different ones but again,the values 6,12,etc.以便合并不同的但同样,值 6,12 等。 are missing - the result is this:丢失了 - 结果是这样的:

mylist = [1,2,3,4,8,9,16,27,32,64,81...]

The code that you show,你展示的代码,

multiples = nub (merge (<=) powers2 powers3)
powers3 = [2^x * 3^y | x <- [0..], y <- [0..]]
powers2 = [2^x * 3^y | y <- [0..], x <- [0..]]

is equivalent to相当于

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..]]

so you only produce the powers of 2 and 3 , without any mixed multiples.所以你只产生23的幂,没有任何混合倍数。 As such, there are guaranteed to be no duplicates in the stream, and the nub was not necessary.因此,保证流中没有重复项,并且没有必要使用nub And of course it's incomplete.当然,它是不完整的。

But let's look at it at another angle.但让我们换个角度来看。 It was proposed in the comments to create a 2D grid out of these numbers:在评论中建议使用这些数字创建一个 2D 网格:

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  ...
  .......     
-}

Now we're getting somewhere.现在我们正在到达某个地方。 At least now none are skipped.至少现在没有一个被跳过。 We just need to understand how to join them into one sorted, increasing stream of numbers.我们只需要了解如何将它们连接成一个有序的、递增的数字流。 Simple concat of course won't do.简单的concat当然不行。 We need to merge them in order.我们需要按顺序合并它们。 A well-known function merge does that, provided the arguments are already ordered, increasing lists.一个众所周知的函数merge做到这一点,前提是参数已经排序,增加列表。

Each row produced is already in increasing order, but there are infinitely many of them.生成的每一行都已经按递增顺序排列,但它们的数量是无限多的。 Never fear, foldr can do it.不要害怕, foldr可以做到。 We define我们定义

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 = 

Here it is a little bit tricky.这里有点棘手。 If we define g = merge , we'll have a run-away recursion, because each merge will want to know the head element of its "right" (second) argument stream.如果我们定义g = merge ,我们将有一个失控的递归,因为每个merge都想知道它的“右”(第二个)参数流的头元素。

To prevent that, we produce the leftmost element right away.为了防止这种情况,我们立即生成最左边的元素。

                x : merge xs ys

And that's that.就是这样。

Tool use工具使用

I needed an infinite Cartesian product function.我需要一个无限的笛卡尔积函数。 An infinite function must take the diagonals of a table.无限函数必须采用表格的对角线。 The pair pattern of a diagonal traversal is对角线遍历的对模式是

0 0 – 0 1, 1 0 – 0 2, 1 1, 2 0 – 0 3, 1 2, 2 1, 3 0 0 0 – 0 1, 1 0 – 0 2, 1 1, 2 0 – 0 3, 1 2, 2 1, 3 0

I love the symmetries but the pattern is counting forward with first digit and backward with second which when expressed in an infinite function is我喜欢对称性,但模式是用第一个数字向前计数,用第二个数字向后计数,当用无限函数表示时是

diag2 xs ys = [ (m,n) | i<- [1..], (m,n) <- zip (take i xs) (reverse.take i $ ys) ]

The infinite generation is just to take any amount however large to work with.无限代只是取任何数量来工作。 What may be important, also is taking a diagonal or triangular number for a complete set.可能重要的是,取一个对角线或三角形数来表示一个完整的集合。 revt n makes a triangular number from you input. revt n根据您的输入生成一个三角形数。 If you want 25 elements revt 25 will return 7. tri 7 will return 28 the parameter for take .如果你想要 25 个元素, revt 25将返回revt 25 tri 7将返回 28 的参数take revt and tri are revttri

tri n = foldl (+) 1 [2..n]
revt n = floor (sqrt (n*2))

Making and using taket is good until you learn the first 10 or so triangular numbers.在你学会前 10 个左右的三角形数之前,制作和使用taket是很好的。

taket n xs = take (tri $ revt n) xs

Now, with some tools in place we apply them (mostly 1) to a problem.现在,有了一些工具,我们将它们(主要是 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] [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]

And it's a diagonal.而且是对角线。 The first group is 7 long, the second is 6 long, the second-to-the-last is 2 long and the last is 1 long.第一组7长,第二组6长,倒数第二组2长,最后一组1长。 revt 25 is 7. tri 7 is 28 the length of the output list. revt 25revt 25 tri 7是 28 输出列表的长度。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM