了解流

时间:2013-04-22 18:10:43

标签: scala

有一种模式一次又一次地重现,我无法完全理解它,例如下面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来获取元素。这不是一个无限循环,其中一件事情要求另一件事,然后那件事又一件事。虽然代码很完美。

1 个答案:

答案 0 :(得分:6)

Scala中的Strecas被懒惰地评估了。这意味着只计算实际需要的最后一个值。这对你的主要例子意味着什么:

isPrime不使用整个primes流,而只使用其中的一部分:

(primes takeWhile ( _ <= Math.sqrt(start) ) 

它仅使用小于您要测试的数字的平方根的部分(而下一个,因为您必须对其进行评估才能看到它太大)。现在,primes再次为这些较小的号码之一调用isPrimeprimes所需的部分甚至更小。这种情况一直持续到你达到最初的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>