有一种模式一次又一次地重现,我无法完全理解它,例如下面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
来获取元素。这不是一个无限循环,其中一件事情要求另一件事,然后那件事又一件事。虽然代码很完美。
答案 0 :(得分:6)
Scala中的Strecas被懒惰地评估了。这意味着只计算实际需要的最后一个值。这对你的主要例子意味着什么:
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
对函数式程序员更直观。< / p>