Haskell 双流进料防止不必要的记忆?
我是Haskell的新手,我正在尝试以流处理方式实现Euler筛 当我检查时,我发现了一些神秘的流优化技术。 在该wiki的3.8线性合并中: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
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..]