Eratosthenes的Sieve可以在Haskell中非常巧妙地实现,使用懒惰生成无限列表,然后从尾部删除列表头部的所有倍数:
primes :: [Int]
primes = sieve [2..]
sieve (x:xs) = x : sieve [y | y <- xs,y `mod` x > 0]
我正在尝试学习如何在Java 8中使用流,但我想出是否有一种方法可以在Java中实现与上面的Haskell代码相同的结果.如果我将Haskell惰性列表视为等同于Java流,似乎我需要使用以2为首的流并生成一个删除了所有2的倍数的新流,然后获取该流并生成所有流的新流删除3的倍数,并…
我不知道如何继续.
有没有办法做到这一点,或者当我试图将Java流视为与Haskell列表相当时,我是在欺骗自己?
最佳答案
当然,有可能,但由于Java流没有简单的方法被分解到它们的头部和它们的尾部(你可以很容易地获得其中任何一个,但不是两个都可以,因为流已经被消费了然后 – 听起来有人可以使用线性类型……).
解决方案是保持可变变量.例如,该可变变量可以是测试数字是否是目前为止看到的任何其他数字的倍数的谓词.
import java.util.stream.*;
import java.util.function.IntPredicate;
public class Primes {
static IntPredicate isPrime = x -> true;
static IntStream primes = IntStream
.iterate(2,i -> i + 1)
.filter(i -> isPrime.test(i))
.peek(i -> isPrime = isPrime.and(v -> v % i != 0));
public static void main(String[] args) {
// Print out the first 10 primes.
primes.limit(10)
.forEach(p -> System.out.println(p));
}
}
然后,您得到预期的结果:
$javac Primes.java
$java Primes
2
3
5
7
11
13
17
19
23
29