【问题标题】:Haskell - Prime Powers Excercise - Infinite mergesHaskell - Prime Powers Excercise - 无限合并
【发布时间】:2011-11-04 23:19:45
【问题描述】:

在大学我的任务如下:

定义如下函数:

primepowers :: Integer -> [Integer]

计算给定参数 n 的素数的前 n 次幂的无限列表,按 asc 排序。 那是, primepowers n 包含按升序排列的元素

{p^i | p 是素数,1≤i≤n}。

完成这项任务后,我走到了死胡同。我有以下四个功能:

merge :: Ord t => [t] -> [t] -> [t]
merge [] b = b
merge a [] = a
merge (a:ax) (b:bx)
  | a <= b    = a : merge ax (b:bx)
  | otherwise = b : merge (a:ax) bx

primes :: [Integer] 
primes = sieve [2..]
    where sieve [] = []
          sieve (p:xs) = p : sieve (filter (not . multipleOf p) xs)
            where multipleOf p x = x `mod` p == 0   

powers :: Integer -> Integer -> [Integer] 
powers n num = map (\a -> num ^ a) [1..n]

primepowers :: Integer -> [Integer]
primepowers n = foldr merge [] (map (powers n) primes)

我认为它们是独立工作的,因为我已经使用一些示例输入进行了测试。 merge 将两个有序列表合并为一个有序列表 primes 返回无限的素数列表 powers 计算 num 的 n 次幂(即 num^1 , num^2 ... num^n)

我尝试合并所有的primepowers,但函数没有被评估什么都没有发生,分别有某种无限循环。

我对素数或幂的优化不感兴趣。只是我不明白为什么这不起作用。还是我的方法不好,不实用,不是haskell?

【问题讨论】:

  • 问题陈述自相矛盾。 “前 n 个素数的无限次幂列表”和“{p^i | p是素数,1≤i≤n}”完全不同。
  • 是的。我纠正了它。这是一个翻译错误

标签: haskell recursion infinity


【解决方案1】:

我怀疑问题是:primes 是一个无限列表。因此,map (powers n) primes 是(有限)列表的无限列表。当您尝试将foldr merge [] 全部放在一起时,merge 必须评估每个列表的头部...

由于列表的数量是无限的,所以这是一个无限循环。


我建议转换结构,例如:

primepowers n = foldr merge [] [map (^i) primes | i <- [1..n]]

【讨论】:

    【解决方案2】:

    虽然您可能无法将其用于您的作业,但可以使用 Hackage 中的 primesdata-ordlist 包非常优雅地解决此问题。

    import Data.List.Ordered
    import Data.Numbers.Primes
    
    primePowers n = mergeAll [[p^k | k <- [1..n]] | p <- primes]
    

    请注意,mergeAll 能够合并无限数量的列表,因为它假定列表的头部是有序的,除了列表本身是有序的。因此,我们也可以轻松地将这项工作用于无限次幂:

    allPrimePowers = mergeAll [[p^k | k <- [1..]] | p <- primes]
    

    【讨论】:

    • 感谢您的指点。我数不清我重新实现了多少次mergeAll
    • 这无关紧要,但如果您需要大量素数,NumberSieves 和特别是(无耻的插头)arithmoi 可以使用更少的内存提供更快的筛子。
    • @DanielFischer:太好了!我得更仔细地检查一下。
    【解决方案3】:

    您的程序运行到无限循环的原因是您试图仅通过使用每个列表按升序排序的不变量来合并无限多个列表。在程序可以输出“2”之前,它必须知道没有一个列表包含小于 2 的任何内容。这是不可能的,因为有无限多个列表。

    【讨论】:

      【解决方案4】:

      您需要以下功能:

      mergePrio (h : l) r = h : merge l r
      

      【讨论】:

        猜你喜欢
        • 2012-06-16
        • 2014-11-26
        • 2021-01-04
        • 1970-01-01
        • 2016-01-27
        • 2016-09-11
        • 2023-03-27
        • 2017-09-28
        • 1970-01-01
        相关资源
        最近更新 更多