在大学,我的任务如下:
定义以下函数:
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将两个有序列表合并到一个有序列表中 素数返回无限的素数列表 powers计算num的num次幂(即num ^ 1,num ^ 2 ... num ^ n)
我尝试合并primepowers中的所有内容,但是函数没有被评估,没有任何事情发生,分别是某种无限循环。
我对素数或权力的优化不感兴趣。只是我不明白为什么这不起作用。或者我的方法不好,不起作用,不是哈斯克尔?
答案 0 :(得分:6)
我怀疑问题是:primes
是一个无限列表。因此,map (powers n) primes
是(有限)列表的无限列表。当您尝试foldr merge []
所有这些时,merge
必须评估每个列表的头部...
由于列表数量无限,因此这是一个无限循环。
我建议改变结构,例如:
primepowers n = foldr merge [] [map (^i) primes | i <- [1..n]]
答案 1 :(得分:6)
虽然你可能不能将它用于你的作业,但使用Hackage的primes和data-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]
答案 2 :(得分:1)
您的程序进入无限循环的原因是您尝试仅使用每个列表按升序排序的不变量来合并无限多个列表。在程序输出“2”之前,它必须知道没有列表包含任何小于2的内容。这是不可能的,因为有无限多的列表。
答案 3 :(得分:0)
您需要以下功能:
mergePrio (h : l) r = h : merge l r