【问题标题】:Haskell List comprehensions infinite list problemHaskell List 理解无限列表问题
【发布时间】:2019-06-03 08:06:13
【问题描述】:

我正在尝试学习 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 

xy 必须采用所有值 &gt;= 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...]

【问题讨论】:

  • 所以只是订购问题?我想知道[x*y | (x,y) &lt;- zip [1..] [1..]] 是否可行?嗯,是的,不,这实际上是同时发生的。实际上很有趣的问题。
  • @BartekBanachewicz 只需在 sort 前面加上有限列表即可。
  • 如果您将所有值x, y 排列在二维网格上,您能否显示您打算遍历它们的路径?
  • powers3=[2^x*3^y | 怎么样? x
  • @mkrieger1 简单的递增顺序。您可能的意思是合并,而不是合并排序。 @ Jam-aica 是的,它可以做到。有一个包数据排序列表;并且我添加的两个标签有许多高度相关的条目。 :)

标签: haskell list-comprehension infinite hamming-numbers smooth-numbers


【解决方案1】:

你展示的代码,

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

所以你只产生 23 的幂,没有任何混合倍数。因此,保证流中没有重复,nub 不是必需的。当然它是不完整的。

但让我们换个角度来看。在 cmets 中建议使用这些数字创建一个 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  ...
  .......     
-}

现在我们正在取得进展。至少现在没有一个被跳过。我们只需要了解如何将它们加入到一个有序的、递增的数字流中。简单的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,我们将有一个失控的递归,因为每个merge 都想知道它的“右”(第二个)参数流的头元素。

为了防止这种情况,我们立即生成最左边的元素。

                x : merge xs ys

就是这样。

【讨论】:

  • 宾果游戏!那行得通。别搞错了,我写的列表不是你一开始就指出的,mults23_2D也是这样,但我没能做到那种排序!如果我想在等式中添加 5^z,我该如何处理?( 2^x*3^y*5^z)
  • 要像上面的注释那样添加 5^z,我们只需要一个双嵌套的 foldr... result = foldr g [] [foldr g....]
【解决方案2】:

工具使用

我需要一个无限笛卡尔积函数。无限函数必须采用表格的对角线。 对角线遍历的pair pattern是

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 将返回 7。tri 7 将返回 28,take 的参数。 revttri

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

在您学习前 10 个左右的三角形数字之前,制作和使用 taket 是很好的选择。

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。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-10
    • 1970-01-01
    • 2017-02-10
    • 1970-01-01
    • 1970-01-01
    • 2020-02-07
    • 2017-09-28
    • 2022-01-08
    相关资源
    最近更新 更多