is there any way to have a tail-recursive function inside CPS not throwing a StackOverflow?
import scala.util.continuations._
object CPSStackOverflow {
def main(args: Array[String]) = {
reset {
def recurse(i: Int): Unit #suspendable = {
println(i)
shift { k: (Unit => Unit) =>
k( () ) // just continue
}
recurse(i + 1)
}
recurse(1)
}
}
}
results in following StackOverflowError:
1298
1299
1300
Exception in thread "main" java.lang.StackOverflowError
at java.nio.CharBuffer.wrap(CharBuffer.java:350)
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:246)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:106)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:190)
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:111)
at java.io.PrintStream.write(PrintStream.java:476)
at java.io.PrintStream.print(PrintStream.java:619)
at java.io.PrintStream.println(PrintStream.java:773)
at scala.Console$.println(Console.scala:198)
at scala.Predef$.println(Predef.scala:182)
at test.CPSStackOverflow$$anonfun$main$1.recurse$1(CPSStackOverflow.scala:9)
at test.CPSStackOverflow$$anonfun$main$1$$anonfun$recurse$1$2.apply(CPSStackOverflow.scala:13)
at test.CPSStackOverflow$$anonfun$main$1$$anonfun$recurse$1$2.apply(CPSStackOverflow.scala:10)
at scala.util.continuations.ControlContext$$anonfun$flatMap$2$$anonfun$apply$2.apply(ControlContext.scala:71)
at test.CPSStackOverflow$$anonfun$main$1$$anonfun$recurse$1$1.apply(CPSStackOverflow.scala:11)
at test.CPSStackOverflow$$anonfun$main$1$$anonfun$recurse$1$1.apply(CPSStackOverflow.scala:10)
at scala.util.continuations.package$$anonfun$shiftR$1.apply(package.scala:58)
at scala.util.continuations.package$$anonfun$shiftR$1.apply(package.scala:58)
at scala.util.continuations.ControlContext$$anonfun$flatMap$2.apply(ControlContext.scala:68)
at scala.util.continuations.ControlContext$$anonfun$flatMap$2.apply(ControlContext.scala:67)
at scala.util.continuations.ControlContext$$anonfun$flatMap$2$$anonfun$apply$2.apply(ControlContext.scala:73)
at test.CPSStackOverflow$$anonfun$main$1$$anonfun$recurse$1$1.apply(CPSStackOverflow.scala:11)
at test.CPSStackOverflow$$anonfun$main$1$$anonfun$recurse$1$1.apply(CPSStackOverflow.scala:10)
at scala.util.continuations.package$$anonfun$shiftR$1.apply(package.scala:58)
at scala.util.continuations.package$$anonfun$shiftR$1.apply(package.scala:58)
etc...
Any way to circumvent this error? trampolining? stack-unwinding by throwing exceptions?
Thanks!
You are calling another function inside the continuation. Scala doesn't support cross-method tail recursion, because the JVM doesn't.
You can run Java with -Xss2M, however that error might occur only a thousand iterations later. As long as your method is not tail recursive you will not be able to get around this problem.
Related
Is there any more functional alternative in Scala for an infinite loop?
while(true) {
if (condition) {
// Do something
} else {
Thread.sleep(interval);
}
}
You can do it recursively
#tailrec
def loop(): Nothing = {
if (condition) {
// Do something
} else {
Thread.sleep(interval);
}
loop()
}
One thing that you can do is using higher-order functions like Stream.continually and pair it up with a for comprehension:
import scala.util.Random
import scala.collection.immutable.Stream.continually
def rollTheDice: Int = Random.nextInt(6) + 1
for (n <- continually(rollTheDice)) {
println(s"the dice rolled $n")
}
This example itself is not purely functional due to the non-referentially transparent nextInt method, but it's a possible construct that may help you think about function composition rather then using side effects.
EDIT (2020-12-24)
As correctly point out in a recent comment, "[a]s of 2.13, Stream is deprecated. But the same method does exist in LazyList(import scala.collection.immutable.LazyList.continually)".
The following will work from 2.13 onward:
import scala.util.Random
import scala.collection.immutable.LazyList.continually
def rollTheDice: Int = Random.nextInt(6) + 1
for (n <- continually(rollTheDice)) {
println(s"the dice rolled $n")
}
You can see it in action and play around with it here on Scastie.
I guess infinite tail recursion:
#tailrec
def loop(): Nothing = {
if (condition) {
// Do something
} else {
Thread.sleep(interval);
}
loop()
}
Just to add to Stefano's great answer, in case someone is looking to a use-case like mine:
I was working on tasks from Kafka Streams course and needed to create an infinite stream of mock events to Kafka with some fields being completely random(amounts), but others rotated within a specific list(names).
The same approach with continually can be used passing a method(via ETA expansion) to it and traversing the bounded variable afterwards:
for {record <- continually(newRandomTransaction _)
name <- List("John", "Stephane", "Alice")} {
producer.send(record(name))
}
where the signature of newRandomTransaction is as follows:
def newRandomTransaction(name: String): ProducerRecord[String, String] = {
...
}
According to the Scala Language Specification (ยง6.19), "An enumerator sequence always starts with a generator". Why?
I sometimes find this restriction to be a hindrance when using for-comprehensions with monads, because it means you can't do things like this:
def getFooValue(): Future[Int] = {
for {
manager = Manager.getManager() // could throw an exception
foo <- manager.makeFoo() // method call returns a Future
value = foo.getValue()
} yield value
}
Indeed, scalac rejects this with the error message '<-' expected but '=' found.
If this was valid syntax in Scala, one advantage would be that any exception thrown by Manager.getManager() would be caught by the Future monad used within the for-comprehension, and would cause it to yield a failed Future, which is what I want. The workaround of moving the call to Manager.getManager() outside the for-comprehension doesn't have this advantage:
def getFooValue(): Future[Int] = {
val manager = Manager.getManager()
for {
foo <- manager.makeFoo()
value = foo.getValue()
} yield value
}
In this case, an exception thrown by foo.getValue() will yield a failed Future (which is what I want), but an exception thrown by Manager.getManager() will be thrown back to the caller of getFooValue() (which is not what I want). Other possible ways of handling the exception are more verbose.
I find this restriction especially puzzling because in Haskell's otherwise similar do notation, there is no requirement that a do block should begin with a statement containing <-. Can anyone explain this difference between Scala and Haskell?
Here's a complete working example showing how exceptions are caught by the Future monad in for-comprehensions:
import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Try, Success, Failure}
class Foo(val value: Int) {
def getValue(crash: Boolean): Int = {
if (crash) {
throw new Exception("failed to get value")
} else {
value
}
}
}
class Manager {
def makeFoo(crash: Boolean): Future[Foo] = {
if (crash) {
throw new Exception("failed to make Foo")
} else {
Future(new Foo(10))
}
}
}
object Manager {
def getManager(crash: Boolean): Manager = {
if (crash) {
throw new Exception("failed to get manager")
} else {
new Manager()
}
}
}
object Main extends App {
def getFooValue(crashGetManager: Boolean,
crashMakeFoo: Boolean,
crashGetValue: Boolean): Future[Int] = {
for {
manager <- Future(Manager.getManager(crashGetManager))
foo <- manager.makeFoo(crashMakeFoo)
value = foo.getValue(crashGetValue)
} yield value
}
def waitForValue(future: Future[Int]): Unit = {
val result = Try(Await.result(future, Duration("10 seconds")))
result match {
case Success(value) => println(s"Got value: $value")
case Failure(e) => println(s"Got error: $e")
}
}
val future1 = getFooValue(false, false, false)
waitForValue(future1)
val future2 = getFooValue(true, false, false)
waitForValue(future2)
val future3 = getFooValue(false, true, false)
waitForValue(future3)
val future4 = getFooValue(false, false, true)
waitForValue(future4)
}
Here's the output:
Got value: 10
Got error: java.lang.Exception: failed to get manager
Got error: java.lang.Exception: failed to make Foo
Got error: java.lang.Exception: failed to get value
This is a trivial example, but I'm working on a project in which we have a lot of non-trivial code that depends on this behaviour. As far as I understand, this is one of the main advantages of using Future (or Try) as a monad. What I find strange is that I have to write
manager <- Future(Manager.getManager(crashGetManager))
instead of
manager = Manager.getManager(crashGetManager)
(Edited to reflect #RexKerr's point that the monad is doing the work of catching the exceptions.)
for comprehensions do not catch exceptions. Try does, and it has the appropriate methods to participate in for-comprehensions, so you can
for {
manager <- Try { Manager.getManager() }
...
}
But then it's expecting Try all the way down unless you manually or implicitly have a way to switch container types (e.g. something that converts Try to a List).
So I'm not sure your premises are right. Any assignment you made in a for-comprehension can just be made early.
(Also, there is no point doing an assignment inside a for comprehension just to yield that exact value. Just do the computation in the yield block.)
(Also, just to illustrate that multiple types can play a role in for comprehensions so there's not a super-obvious correct answer for how to wrap an early assignment in terms of later types:
// List and Option, via implicit conversion
for {i <- List(1,2,3); j <- Option(i).filter(_ <2)} yield j
// Custom compatible types with map/flatMap
// Use :paste in the REPL to define A and B together
class A[X] { def flatMap[Y](f: X => B[Y]): A[Y] = new A[Y] }
class B[X](x: X) { def map[Y](f: X => Y): B[Y] = new B(f(x)) }
for{ i <- (new A[Int]); j <- (new B(i)) } yield j.toString
Even if you take the first type you still have the problem of whether there is a unique "bind" (way to wrap) and whether to doubly-wrap things that are already the correct type. There could be rules for all these things, but for-comprehensions are already hard enough to learn, no?)
Haskell translates the equivalent of for { manager = Manager.getManager(); ... } to the equivalent of lazy val manager = Manager.getManager(); for { ... }. This seems to work:
scala> lazy val x: Int = throw new Exception("")
x: Int = <lazy>
scala> for { y <- Future(x + 1) } yield y
res8: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise#fedb05d
scala> Try(Await.result(res1, Duration("10 seconds")))
res9: scala.util.Try[Int] = Failure(java.lang.Exception: )
I think the reason this can't be done is because for-loops are syntactic sugar for flatMap and map methods (except if you are using a condition in the for-loop, in that case it's desugared with the method withFilter). When you are storing in a immutable variable, you can't use these methods. That's the reason you would be ok using Try as pointed out by Rex Kerr. In that case, you should be able to use map and flatMap methods.
I'm new on Scala and I'm trying to pass a function/method as parameter to another by using unit, but it gives me the following error:
Timer.<error: >
My code is the following:
object Timer {
def oncePerSecond(callback: () => unit) {
while (true) {
callback(); Thread sleep 1000
}
}
def timeFlies() {
println("The time passes...")
}
def main(args: Array[String]) {
oncePerSecond(timeFlies)
}
}
But I'm certainly my code is correct and I don't understand why I'm getting this. Can someone help me to find this bug?
The error seems to be in the word "unit" on line 2.
Unit with a capital U fixes the error. Classes in Scala begin with a capital letter.
In the following example of a Scala function:
#tailrec def someFunction( ... ): Unit = {
Is the #tailrec annotation doing anything useful or is it just nice to know that this is a tail recursion?
#tailrec - will produce a compilation error if a tail call optimization cannot be performed by the compiler in the annotated method.
so yes it does do something ....
check out - http://blog.richdougherty.com/2009/04/tail-calls-tailrec-and-trampolines.html
Nimrod007' answer is sufficient, But I also like to add some points.
Adding #tailrec definitely clears a benefit of doubt in code.
You IDE might detect function as tail recursive but Scala might not, This is why it is better to add #tailrec to the function.
You can refer the code below.
import scala.annotation.tailrec
object Application extends App {
println("Hello World")
val i = 60000
// val i = 1000
GetSum().trueTailRecursion(i)
println("\nCompleted")
GetSum().maybeTrueTailRecursion(i)
}
case class GetSum() {
def maybeTrueTailRecursion(i: Int): Int = {
print(".")
if(i==1) 1
else maybeTrueTailRecursion(i - 1)
}
#tailrec
final def trueTailRecursion(i: Int): Int = {
print(".")
if(i==1) 1
else trueTailRecursion(i - 1)
}
}
In the above example,
trueTailRecursion will be able to print dotted line but
maybeTrueTailRecursion will crash with StackOverFlowError.
Although the function is same.
I am new to Akka and making several test files to practice Akka concepts. The following test seemed simple enough, but for whatever reason I am unable to obtain the value of the future if I receive the future from an Actor. I based all my assumptions on the few examples from the akka documentation ( http://akka.io/docs/akka/1.3-RC2/scala/futures.html#futures-scala ) For example:
This works like a wizard:
val f = Future{ 1 + 4 }
f onComplete
{
_.value.get.fold(
v => throw new Exception("My Exception"),
println(_)
)
}
This does not:
class FutureDemo extends Actor
{
def receive =
{
case (a: Int, b: Int) =>
a + b
}
}
val fa1 = actorOf[FutureDemo].start()
val future = fa1 ? (1, 2)
future onComplete
{
_.value.get.fold(
v => throw new Exception("My Exception"),
println(_)
)
}
I was very pleased to know I was the only one that has ever had this issue due to the extreme simplicity of futures (lucky me). Would anyone assist in opening my eyes to the violently obvious issue?
I should note that I had tried to process both inside another actor, and in a simple main method. Each of which failed in the same awesome way which included no notification whatsoever. If the onComplete is replaced with a simple println(future.get) I eventually get a timeout exception (Exception in thread "main" akka.dispatch.FutureTimeoutException: Futures timed out after [4996] milliseconds). I should also note that I did attempt to try with the 1.1 and 1.2 released versions of akka as well.
Thanks!
It is indeed but one tiny detail you are missing: your actor does not reply! May I suggest the following:
class FutureDemo extends Actor {
def receive = {
case (a: Int, b: Int) => self.reply(a + b)
}
}