有一种模式会反复出现,而我还无法完全理解它,例如下面的code计算isPrime
class S99Int(val start: Int) {
import S99Int._
def isPrime: Boolean =
(start > 1) && (primes takeWhile ( _ <= Math.sqrt(start) ) forall ( start % _ != 0 ))
}
object S99Int {
implicit def int2S99Int(i: Int): S99Int = new S99Int(i)
val primes = Stream.cons(2, Stream.from(3, 2) filter { _.isPrime })
}
import S99Int._
24 isPrime //returns false
我不明白的是:
primes
中的filter
使用isPrime
。但是,def isPrime
再次使用相同的primes
来获取元素。难道不是像一个无限循环,其中一件事要问另一件事,然后又把那件事再次问给自己。虽然代码可以完美运行。 最佳答案
懒惰地评估Scala中的流。这意味着仅计算直到您实际需要的最后一个值。这对于您的主要示例意味着什么:isPrime
不使用整个primes
流,而仅使用其中一部分:
(primes takeWhile ( _ <= Math.sqrt(start) )
它仅使用小于您要测试的数字平方根的部分(以及下一个,因为您必须对其进行评估才能看到它太大)。现在,
primes
再次为这些较小的数字之一调用isPrime
时,primes
的所需部分甚至更小。这一直持续到您达到初始2。将其视为相互递归的函数:
isPrime
和primes
可被视为primesUpTo(n: Int)
接着:
class S99Int(val start: Int) {
import S99Int._
def isPrime: Boolean =
(start > 1) && (S99Int.primesUpTo(math.sqrt(start).toInt) forall ( start % _ != 0 ))
}
object S99Int {
implicit def int2S99Int(i: Int): S99Int = new S99Int(i)
def primesUpTo(n: Int): IndexedSeq[Int] = {
if (n >= 2) 2 +: (3 to n) filter { _.isPrime }
else IndexedSeq.empty
}
}
Stream
唯一为您实现的功能是从primesUpTo(n: Int)
缓存值,以便仅计算一次,并使函数程序员更加了解UpTo
表达式。关于scala - 了解流,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16153826/