Scala's Stream and StackOverflowError - scala

Consider this code (taken from "Functional programming principles in Scala" course by Martin Odersky):
def sieve(s: Stream[Int]): Stream[Int] = {
s.head #:: sieve(s.tail.filter(_ % s.head != 0))
}
val primes = sieve(Stream.from(2))
primes.take(1000).toList
It works just fine. Notice that sieve is in fact NOT tail recursive (or is it?), even though Stream's tail is lazy.
But this code:
def sieve(n: Int): Stream[Int] = {
n #:: sieve(n + 1).filter(_ % n != 0)
}
val primes = sieve(2)
primes.take(1000).toList
throws StackOverflowError.
What is the problem with the second example? I guess filter messes things up, but I can't understand why. It returns a Stream, so it souldn't make evaluation eager (am I right?)

You can highlight the problem with a bit of tracking code:
var counter1, counter2 = 0
def sieve1(s: Stream[Int]): Stream[Int] = {
counter1 += 1
s.head #:: sieve1(s.tail.filter(_ % s.head != 0))
}
def sieve2(n: Int): Stream[Int] = {
counter2 += 1
n #:: sieve2(n + 1).filter(_ % n != 0)
}
sieve1(Stream.from(2)).take(100).toList
sieve2(2).take(100).toList
We can run this and check the counters:
scala> counter1
res2: Int = 100
scala> counter2
res3: Int = 540
So in the first case the depth of the call stack is the number of primes, and in the second it's the largest prime itself (well, minus one).

Neither one of these are tail recursive.
Using the tailrec annotation will tell you whether or not a function is tail recursive.
Adding #tailrec to the two functions above gives:
import scala.annotation.tailrec
#tailrec
def sieve(s: Stream[Int]): Stream[Int] = {
s.head #:: sieve(s.tail.filter(_ % s.head != 0))
}
#tailrec
def sieve(n: Int): Stream[Int] = {
n #:: sieve(n + 1).filter(_ % n != 0)
}
Loading this shows that both definitions are not tail recursive:
<console>:10: error: could not optimize #tailrec annotated method sieve: it contains a recursive call not in tail position
s.head #:: sieve(s.tail.filter(_ % s.head != 0))
^
<console>:10: error: could not optimize #tailrec annotated method sieve: it contains a recursive call not in tail position
n #:: sieve(n + 1).filter(_ % n != 0)

Related

Code to compute Stream of primes in Scala

I have slightly modified Daniel Sobral's prime Stream function from this SO post:
def primeStream: Stream[Int] => Stream[Int] =
s => s.head #:: primeStream(s.tail filter(_ % s.head != 0))
I'm using it with:
primeStream(Stream.from(2)).take(100).foreach(println)
and it works fine enough, but I'm wondering if I could get rid of that pesky Stream.from(2) with the following:
def primeStream: def primeStream: () => Stream[Int] =
() => Stream.from(2)
def primeStream: Stream[Int] => Stream[Int] =
s => s.head #:: primeStream(s.tail filter(_ % s.head != 0))
to achieve:
primeStream().take(100).foreach(println)
But that doesn't work. What am I missing?
I tried also:
def primeStream: Stream[Int] => Stream[Int] = {
() => Stream.from(2)
s: Stream[Int] => s.head #:: primeStream(s.tail filter(_ % s.head != 0))
}
which doesn't work.
This works:
def primeStream2(s: Stream[Int] = Stream.from(2)): Stream[Int] =
s.head #:: primeStream2(s.tail filter(_ % s.head != 0))
But I wanted to understand what I missed to make the syntax work for the more symmetric syntax above with 2 parallel definitions of primeStream .
The 1st attempt doesn't work because you're trying to define 2 different methods with the same name. Methods can't be differentiated by their return types. Also, other than their names they appear to be totally unrelated so if you were able to invoke one of them the existence of the other would be immaterial.
The 2nd attempt tries to put 2 unrelated, and unnamed, functions in the same code block. It will compile if you wrap the 1st function in parentheses but the result isn't what you're after.
I completely understand your desire to make Stream.from(2) automatic because if you pass anything else, like Stream.from(13), you don't get a Stream of prime integers.
There are a few different ways to get a lazy sequence of prime numbers with only one Stream invocation. This one is a little complicated because it tries to reduce the number of inner iterations when searching for the next prime.
val primeStream: Stream[Int] = 2 #:: Stream.iterate[Int](3)(x =>
Stream.iterate(x+2)(_+2).find(i => primeStream.takeWhile(p => p*p <= i)
.forall(i%_ > 0)).get)
You can also use the new (Scala 2.13) unfold() method to create the Stream.
val primes = Stream.unfold(List(2)) { case hd::tl =>
Option((hd, Range(hd+1, hd*2).find(n => tl.forall(n % _ > 0)).get::hd::tl))
}
Note that Stream has been deprecated since Scala 2.13 and should be replaced with the new LazyList.

Scala Tail Recursion

So I have this recursive function that multiplies two numbers, simple enough.
def mul(n: Int, m: Int):Int =
if(m > 1) n + mul(n, dec(m))
else n
Now I'm trying to turn it into a tail recursive function, and I tried this:
def mulWithTail(n: Int, m: Int):Int = {
#tailrec
def iter(result: Int, x: Int):Int =
if(x == 0) result
else result + iter(result, dec(x))
iter(n, m)
}
However I get the following error:
error: could not optimize #tailrec annotated method iter: it contains
a recursive call not in tail position
else result + iter(result, dec(x))
Question: Can you explain to me why this error is occurring? How should I refactor my code?
You can make your function tail recursive simply adding an extra parameter acting like an accumulator. Like this.
def mul(n: Int, m: Int, acc: Int): Int =
if (m > 1) mul(n, m - 1, n + acc)
else acc
To make a function tail recursive you must not perform any other operation in the recursion step but calling the function recursively. In your code samples you're performing an addition in the recursion step.
n + mul(n, dec(m))
result + iter(result, dec(x))

Passing a Set[List[Int]] typed value instead of List[Int] - why does that work?

I have difficulties to understand the following when I look at the signatures and the function calls.
In my worksheet I have the following (taken from a Coursera lecture):
object nqueens {
def queens(n: Int) : Set[List[Int]] = {
def placeQueens(k: Int) : Set[List[Int]] =
if (k == 0) Set(List())
else
for {
queens <- placeQueens(k - 1)
col <- 0 until n
if isSafe(col, queens)
} yield col :: queens
placeQueens(n)
}
def isSafe(col: Int, queens: List[Int]) : Boolean = {
val row = queens.length
val queensWithRow = (row - 1 to 0 by -1) zip queens
queensWithRow forall {
case (r, c) => col != c && math.abs(col - c) != row -r
}
}
def show(queens: List[Int]) = {
val lines =
for (col <- queens.reverse)
yield Vector.fill(queens.length)("* ").updated(col, "X ").mkString
"\n" + (lines mkString "\n")
}
(queens(4) map show) mkString "\n"
}
Considering the signatures of placeQueen and isSafe:
def placeQueens(k: Int) : Set[List[Int]]
def isSafe(col: Int, queens: List[Int]) : Boolean
I wonder why it works. We call placeQueens and save the result in queens (in the for loop).
The result should be of type Set[List[Int]]. Then we call isSafe with two parameters of Int and Set[List[Int]] - but I don't see why that works because queens should be of type Set[List[Int]] and the parameter for isSafe should List[Int].
We call placeQueens and save the result in queens
Your code is not saving the result of placeQueens into queens.
for {
queens <- placeQueens(k - 1)
col <- 0 until n
if isSafe(col, queens)
} yield col :: queens
This code is actually using for comprehension. The particular line in question:
queens <- placeQueens(k-1)
is storing a List[Int] into queens, since it is iterating over the Set[List[Int]] returned from placeQueens. To give a simpler example that might help illustrate what's going on, consider:
val a = Set(1,2,3)
val b = for (x <- a) yield x + 2
After executing this code, b will be Set(3,4,5). This is because at each iteration in the for loop, x is first 1, then 2, then 3.
We call placeQueens and save the result in queens (in the for loop).
No, you're calling placeQueens and iterating over the result. At each iteration queens refers to the current element.

JVM OOM Error - Finding prime numbers using scala stream

I am using Scala Stream to find out prime numbers between two numbers, but it is throwing Java OutofMemoryError. Can someone tell me why is it happening so?
def sieve(nums: Stream[Int]): Stream[Int] = {
nums.head #:: sieve(nums.tail filter (_ % nums.head != 0))
}
def listPrimesinRange(start: Int, end: Int): List[Int] = {
sieve(Stream.from(2)).filter(x => (x >= start && x <= end)).toList
}

Scala functional solution for spoj "Prime Generator"

I worked on the Prime Generator problem for almost 3 days.
I want to make a Scala functional solution(which means "no var", "no mutable data"), but every time it exceed the time limitation.
My solution is:
object Main {
def sqrt(num: Int) = math.sqrt(num).toInt
def isPrime(num: Int): Boolean = {
val end = sqrt(num)
def isPrimeHelper(current: Int): Boolean = {
if (current > end) true
else if (num % current == 0) false
else isPrimeHelper(current + 1)
}
isPrimeHelper(2)
}
val feedMax = sqrt(1000000000)
val feedsList = (2 to feedMax).filter(isPrime)
val feedsSet = feedsList.toSet
def findPrimes(min: Int, max: Int) = (min to max) filter {
num => if (num <= feedMax) feedsSet.contains(num)
else feedsList.forall(p => num % p != 0 || p * p > num)
}
def main(args: Array[String]) {
val total = readLine().toInt
for (i <- 1 to total) {
val Array(from, to) = readLine().split("\\s+")
val primes = findPrimes(from.toInt, to.toInt)
primes.foreach(println)
println()
}
}
}
I'm not sure where can be improved. I also searched a lot, but can't find a scala solution(most are c/c++ ones)
Here is a nice fully functional scala solution using the sieve of eratosthenes: http://en.literateprograms.org/Sieve_of_Eratosthenes_(Scala)#chunk def:ints
Check out this elegant and efficient one liner by Daniel Sobral: http://dcsobral.blogspot.se/2010/12/sieve-of-eratosthenes-real-one-scala.html?m=1
lazy val unevenPrimes: Stream[Int] = {
def nextPrimes(n: Int, sqrt: Int, sqr: Int): Stream[Int] =
if (n > sqr) nextPrimes(n, sqrt + 1, (sqrt + 1)*(sqrt + 1)) else
if (unevenPrimes.takeWhile(_ <= sqrt).exists(n % _ == 0)) nextPrimes(n + 2, sqrt, sqr)
else n #:: nextPrimes(n + 2, sqrt, sqr)
3 #:: 5 #:: nextPrimes(7, 3, 9)
}