不带“.”的 Scala 函数调用(点)与使用“。” (点)

Scala function call without "." (dot) vs using "." (dot)

谁能帮我理解这里发生了什么。我有这个生成素数的定义:

def primes: Stream[Long] = {
    2 #:: 3 #:: 5 #:: 7 #::Stream.iterate(11L)(_ + 2).filter {
        n => primes takeWhile (p => p*p <= n) forall (n % _ != 0)
    }
}

def primes: Stream[Long] = {
    2 #:: 3 #:: 5 #:: 7 #::Stream.iterate(11L)(_ + 2) filter {
        n => primes takeWhile (p => p*p <= n) forall (n % _ != 0)
    }
}

如您所见,这两个定义完全相似,除了第二个没有 . 过滤器之前,而第一个有。

问题是 运行 第一个按预期运行并给我们质数,但第二个产生 java.lang.WhosebugError。 有人可以阐明这一点吗?在这两种情况下传递给过滤器的是什么?

Scala version: 2.11.6

Java version: 1.8.0_121

这是我用来测试每​​一个的完整程序:

object Main {

    def primes: Stream[Long] = {
        2 #:: 3 #:: 5 #:: 7 #::Stream.iterate(11L)(_ + 2) filter {
            n => primes takeWhile (_ <= sqrt(n)) forall (n % _ != 0)
        }
    }

    def primes2: Stream[Long] = {
        2 #:: 3 #:: 5 #:: 7 #::Stream.iterate(11L)(_ + 2).filter {
            n => primes2 takeWhile (p => p*p <= n) forall (n % _ != 0)
        }
    }

    def main(args: Array[String]): Unit = {
        println(primes.take(args.head.toInt).force)
    }
}

你需要括号:

def primes: Stream[Long] = {
  2 #:: 3 #:: 5 #:: 7 #::(Stream.iterate(11L)(_ + 2) filter {
    n => primes takeWhile (p => p*p <= n) forall (n % _ != 0)
  })
}

根据经验,我通常到处都使用点。它更易于阅读并使此类错误更难出现。

不带 . 的符号与任何自定义中缀的优先级相同。所以第一个只适用于 filter Stream.iterate(11L)(_ + 2) - 第二个适用于 2 #:: 3 #:: 5 #:: 7 #::Stream.iterate(11L)(_ + 2).

第一个起作用的原因是过滤器运行时元素 2、3、5 和 7 已经在 primes 中,因此当过滤器尝试使用 primes 时,那些元素已经在里面了。

在第二个代码中情况并非如此,因为过滤器也应用于这些元素,这意味着它们不会出现在 primes 中,直到过滤器 returned 对它们为真。但是过滤器需要先从素数中获取元素,然后才能 return 任何东西,因此它在尝试获取元素时会在无限递归中迷失自己。