Haskell 双流进料防止不必要的记忆?

Haskell 双流进料防止不必要的记忆?,haskell,primes,sieve-of-eratosthenes,lazy-sequences,space-leak,pointfree,Haskell,Primes,Sieve Of Eratosthenes,Lazy Sequences,Space Leak,Pointfree,我是Haskell的新手,我正在尝试以流处理方式实现Euler筛 当我检查时,我发现了一些神秘的流优化技术。 在该wiki的3.8线性合并中: primesLME = 2 : ([3,5..] `minus` joinL [[p*p, p*p+2*p..] | p <- primes']) where primes' = 3 : ([5,7..] `minus` joinL [[p*p, p*p+2*p..] | p <- primes']) joinL ((x:xs

我是Haskell的新手,我正在尝试以流处理方式实现Euler筛

当我检查时,我发现了一些神秘的流优化技术。 在该wiki的3.8线性合并中:

primesLME = 2 : ([3,5..] `minus` joinL [[p*p, p*p+2*p..] | p <- primes']) 
  where
    primes' = 3 : ([5,7..] `minus` joinL [[p*p, p*p+2*p..] | p <- primes'])

joinL ((x:xs):t) = x : union xs (joinL t)

primesLME=2:([3,5..]`减去'joinL[[p*p,p*p+2*p..]| p通常,Richard Bird关于埃拉托斯烯筛的公式中的primes流的定义是自参考的:

import Data.List.Ordered (minus, union, unionAll)

ps = ((2:) . minus [3..] . foldr (\p r -> p*p : union [p*p+p, p*p+2*p..] r) []) ps
由该定义产生的素数
ps
用作输入。为防止恶性循环,该定义使用初始值2进行素数。这与埃拉托斯烯筛的数学定义相对应,即在复合材料之间的间隙中寻找素数,通过以步数的方式计算每个素数pp、 p={2}U({3,4,…}U{p2,p2+p,p2+2p,…}p在p})

生成的流在其自己的定义中用作输入。这会导致整个素数流保留在内存中(或者至少保留其中的大部分)。这里的固定点是共享,corecursive:


这个想法(由梅丽莎·奥尼尔提出)是将其分成两个流,一个内环流入“上面”的第二个素数流:

因此,当
ps2
产生一些素数
p
时,其“核心”素数的内部流
xs
只需实例化大约
sqrt p
,然后系统可以立即丢弃和回收由
ps2
产生的任何素数:

\ \ <- ps2 <-. \ \ <- xs <-. / \ \_________/ 事实上,在Ideone进行测试时,内存消耗几乎是恒定的


这是埃拉托什尼的筛子,而不是欧拉的筛子。

最初的定义是:

eratos (x:xs) = x : eratos (minus xs $ map (*x) [x..] )    -- ps = eratos [2..]
eulers (x:xs) = x : eulers (minus xs $ map (*x) (x:xs))    -- ps = eulers [2..]
由于过早处理倍数,这两种方法都非常低效。通过将
映射
和枚举融合到一个移动得更远的枚举中(从
x
x*x
,即
[x*x,x*x+x..]
),可以很容易地纠正第一种定义,这样它的处理可以被推迟,因为这里每个素数的倍数都是独立地生成的(以固定的间隔枚举):


感谢您的解释。
primesLME
必须重新评估
primes
所评估的内容,因此这种解耦将增加时间复杂性,并根据流的性质将
primesme
从持久性数据变为短暂性数据?我知道这是埃拉托什尼的筛选。我很好奇为什么没有效果Icent stream processing style sieve of Euler?Euler's sieve的实现速度比wiki中的其他sieve慢数百倍。关于Euler's:我们尝试过,但没有成功。我知道你问过,Daniel回答过,需要阅读它。关于双重计算:是的,但它增加了一个较低复杂性的术语(比如,sqrt(N)到N)所以总体复杂性不会改变。关于短暂性:这就是目标。流可以两者兼而有之。双重计算:有一个从高点计算高流,所以不重新计算低部分。 \ \ <- ps2 <-. \ \ <- xs <-. / \ \_________/
main = getLine >>= (read >>> (+(-1)) >>> (`drop` ps2) >>> print . take 5)
eratos (x:xs) = x : eratos (minus xs $ map (*x) [x..] )    -- ps = eratos [2..]
eulers (x:xs) = x : eulers (minus xs $ map (*x) (x:xs))    -- ps = eulers [2..]
eratos (p:ps) xs | (h,t) <- span (< p*p) xs =                 -- ps = 2 : eratos ps [2..]
                    h ++ eratos ps (minus t [p*p, p*p+p..])   -- "postponed sieve"
ps = 2 : [n | (r:q:_, px) <- (zip . tails . (2:) . map (^2) <*> inits) ps,
              n           <- [r+1..q-1] `minus` foldr union [] 
                               [[s+p, s+2*p..q-1] | p <- px, let s = r`div`p*p]]
primes = 2 : _Y ((3:) . sieve 5 . unionAll . map (\p -> [p*p, p*p+2*p..]))
  where
    _Y g = g (_Y g)                                   -- == g . g . g . g . ....

    sieve k s@(x:xs) | k < x = k : sieve (k+2) s      -- == [k,k+2..] \\ s,
                     | True  =     sieve (k+2) xs     --    when s ⊂ [k,k+2..]