Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
haskell中的无限列表与fold*donds';不算数_Haskell_Map_Infinite_Fold - Fatal编程技术网

haskell中的无限列表与fold*donds';不算数

haskell中的无限列表与fold*donds';不算数,haskell,map,infinite,fold,Haskell,Map,Infinite,Fold,假设我想得到一个所有素数幂的排序无限列表,直到指数n 我有一个合并两个排序列表的函数和一个给我素数的函数 merge :: Ord t => [t] -> [t] -> [t] merge (x:xs) (y:ys) | (x <= y) = x : merge xs (y:ys) | otherwise = y : merge (x:xs) ys merge xs [] = xs merge [] ys = ys primes :: [Integer]

假设我想得到一个所有素数幂的排序无限列表,直到指数
n

我有一个合并两个排序列表的函数和一个给我素数的函数

merge :: Ord t => [t] -> [t] -> [t]
merge (x:xs) (y:ys)
    | (x <= y) = x : merge xs (y:ys)
    | otherwise = y : merge (x:xs) ys
merge xs [] = xs
merge [] ys = ys

primes :: [Integer]
primes = sieve [2..]
    where
        sieve [] = []
        sieve (p:xs) = p : sieve (filter (\x -> x `mod` p /= 0) xs)
一个提供了正确的结果,另一个没有。唯一的区别是,第一个版本以类似于
[[2,3,5,7,…],[4,9,25,…]
的方式映射素数幂,而第二个版本以类似于
[[2,4,8],[3,9,27],[5,25125],…]的方式映射素数幂。你看,无限在列表的另一个层次


您有没有解释为什么第二个函数不产生任何输出?

您的两个函数都不会终止

首先,
素数
是一个无限列表。这意味着对程序的理解取决于它的惰性评估

对于第一个函数

primepowers :: Integer -> [Integer]
primepowers n = foldr (merge) [] (listOfPrimepowers n)    

listOfPrimepowers n = map (\x -> (map (\y -> y ^ x) primes)) [1..n]
不会因为而终止。即使外部映射应用于有限列表[1..n],内部映射所消耗的每个
\x
也应用于无限列表
素数

第二个功能

primepowers :: Integer -> [Integer]
primepowers n = foldl (merge) [] (listOfPrimepowers n)

listOfPrimepowers n = map(\x -> (map(\y -> x ^ y) [1..n])) primes

不会终止,因为外部
映射
直接应用于无限列表
素数

这是由于
foldr merge
必须查看所有列表以在其中一个列表的开头找到最小元素造成的。如果给
foldr merge
一个有限列表的无限列表,
foldr merge
永远无法计算列表的第一个元素-它一直在寻找列表其余部分的最小元素,然后才能将其与第一个列表的第一个元素进行比较-
2
。另一方面,如果给
foldr merge
一个无限列表的有限列表,则
foldr merge
可以确定合并列表的第一个元素,并移动到下一个元素。这样,在第一种情况下可以生成任意数量的元素,但在第二种情况下不能生成单个元素


让我们展开
foldr merge[]

foldr merge [] (xs0:xs1:xs2:...:[]) =
merge xs0 (merge xs1 (merge xs2 (merge xs3 ... [])))
显然,如果
(xs0:xs1:xs2:…:[])
是无限的,那么对merge的“嵌套”调用将形成一个无限链。但是哈斯克尔“懒惰”呢<代码>素数
本身也有定义,但它会产生输出吗?实际上,
foldr
有一条规则:只有当传递给
foldr
的函数在第二个参数中不严格时,它才能为无限列表生成输出,也就是说,有时它可以生成输出,而不必对列表的其余部分求值
foldr


merge
模式与第二个参数匹配(单独使用该参数可能导致不终止),并使用严格的函数
第二个版本不提供任何输出,因为输入是无限列表。仔细想想,
foldr merge[]
从列表列表中创建一个排序列表,因此结果列表的head元素将是列表中所有head元素的最小值。当然,从无限列表中取最小值是不终止的,因此函数甚至不会到达结果的第一个元素可用的点

您可以相当容易地使这两种变体都工作。所涉及的技术值得了解

您的代码相当于

primepowers n = 
  foldr merge [] 
      -- terminating:
 --   [[p^k | p <- primes]  | k <- [1..n]]  -- n infinite lists

      -- non terminating:
      [[p^k | k <- [1..n]]  | p <- primes]  -- infinite list of n-length lists
(如理查德·伯德的《代码》中所示)。现在这两种变体都可以工作了
imerge
在其第二个参数中是不严格的,并且自然地与
foldr
一起使用,甚至与有限的列表一起使用

使用
foldl
而不是
foldr
对于第二个变量来说显然是错误的,因为无限列表上的
foldl
是非终止的

foldl
与第一个变量一起使用,虽然可能(因为列表本身是有限的),但在这里并不理想:它将把更频繁的生产流放在整个合并链的底部,即,它将比使用
foldr
的运行慢


另请参见:.

可能重复@ScarletAmaranth对不起,我的意思是在第二次代码提取中使用foldr。。。但还是一样,我明白你的意思。但我对终止不感兴趣,我对一些(无限)输出感兴趣。第一个版本生成输出,而第二个版本不返回任何输出。谢谢,这完美地回答了我的问题
foldr
foldl'
是次要的。这两种方法对第二种方法都没有帮助,而对于第一种方法,还不清楚哪种方法更好-
foldr
将使用更多的堆栈来开始生产,但将构建一个更好的结构,该结构运行速度更快,开销更少。@WillNess是什么使得由
foldr
构建的结构更好?我在我的回答(最后)中写道:)@我想我确实提到了
foldl'
必须仅用于无限列表的有限列表(即不能与变体2一起使用),所以我希望我们对此有明确的认识。我在你的回答中增加了关于效率的问题你是什么意思——“在整个合并链的底部”?如果合并必须检查所有列表的标题,那么“最频繁生成流”在哪里又有什么关系呢?我从你的答案中学到了,尽管我意识到它是按两种方式排序的,但是问题是关于现存的<代码>合并<代码>,所以我没有考虑其他的方法。每个新的数字必须在所有的二进制代码< >合并< /代码>节点上“渗透”到顶端节点。由于懒惰,在生成第一个数字后,每个二进制
merge
节点都会记住其参数的头部,该参数在上一步中没有生成数字。我不确定您的意思。你能举例说明吗?在我看来,在这两种情况下,
merge
都将使用“the”列表中的一个列表,以及由前面或后面的折叠构造的一个列表。在这两种情况下,人们都需要在某个地方用最少的元素“渗透”列表的开头
primepowers n = 
  foldr merge [] 
      -- terminating:
 --   [[p^k | p <- primes]  | k <- [1..n]]  -- n infinite lists

      -- non terminating:
      [[p^k | k <- [1..n]]  | p <- primes]  -- infinite list of n-length lists
imerge (x:xs) ys = x : merge xs ys