The task is to realise recursive method, which returns Future
def recursive (result:List[Result], attempt: Int):Future[Seq[Result]] = attempt match {
case a if a < 3 => {
for {
res <- retrive()
} yield {
if ((result:::res).size > 20) res
else recursive (result:::res, attempt + 1)
}
}
case => Future(Seq.empty)
}
And due to this part ("else recursive (result:::res, attempt + 1)" ) code failed with error, as it expects Future[Seq[Result]], but in fact return Future[Object].
As I understand, the problem is that expression inside yield-block must return Seq[Result] for the subsequent wrapping by Monad in Future. But "recursive (result:::res, attempt + 1)" return Future. So, instead of the expected Seq[Result] yield contain Future[Seq[Result]].
It there any way to work around this problem?
The trick is to wrap the value you are returning in the terminal case into a future, so that the types match for both cases.
You don't really need a for-comprehension here, it would read a lot better without it IMO:
retrieve.flatMap {
case r if r.size + result.size > 20 => Future.successful(result:::r) // you are not prepending result in your snippet, I think, it's a bug ...
case r => recursive (result:::r, attempt + 1)
}
If you are partial to for-comprehension for some reason, you can still use it, just need to move most of the yield clause inside the for:
for {
res <- retrieve()
out <- if (res.size() + result.size() > 20) Future.successful(result:::res)
else recursive (result:::res, attempt + 1)
} yield out
Related
I'm very new to Scala, and tried to write a simple Scala program that gets the maximum value. I found something weird (probably a language-specific feature). Here it is:
def max(xs: List[Int]): Int = {
if (xs.isEmpty) {
throw new java.util.NoSuchElementException
}
def maxAux(x: List[Int], curMax: Int): Int = {
if (x.isEmpty) {
curMax
}
if (x.head > curMax) {
maxAux(x.tail, x.head)
}
else {
maxAux(x.tail, curMax)
}
}
maxAux(xs.tail, xs.head)
}
}
For some reason, inside of maxAux function, the return of the first if statement gives me an IntelliJ warning that it is an "unused expression". Turns out it is correct because that line doesn't seem to return. To get around that issue, the second if statement in maxAux I changed to an else if, and then everything worked as intended. The other fix would be to add a return statement before curMax, but apparently using return is bad style/practice.
TL;DR: Can anyone explain why in the code above curMax doesn't return?
The immediate problem is that Scala returns the value of the last expression in a block which is the second if/else expression. So the value of the first if is just discarded. This can be fixed by making the second if an else if so that it is a single expression.
A better solution is to use match, which is the standard way of unpicking a List:
def maxAux(x: List[Int], curMax: Int): Int =
x match {
case Nil =>
curMax
case max :: tail if max > curMax =>
maxAux(tail, max)
case _ :: tail =>
maxAux(tail, curMax)
}
In def maxAux, the control-flow can enter the first if-branch, whose body yields curMax. But that if-statement is not the last statement in maxAux, another if- or else-branch will follow, and they determine the result.
If you test your function (note that your code currently doesn't compile!), e.g. via println(max(List(1,3,2,5,0))), then you'll get a NoSuchElementException, which is a consequence of your current (incorrect) implementation.
You have various options now, e.g. the following two, which only minimally change your code:
Fix the if-else cascade (which you could also rewrite into a pattern matching block):
if (x.isEmpty) {
curMax
} else if (x.head > curMax) {
maxAux(x.tail, x.head)
} else {
maxAux(x.tail, curMax)
}
Use a return statement (though you should be careful with the use of return in Scala. See the comments under this answer):
if (x.isEmpty) {
return curMax
}
val LIST = scala.collection.mutable.MutableList[String]()
val filterF = new Function[Path, Boolean] {
def apply(x: Path): Boolean = {
println("looking into " + x)
val flag = if (x.toString.split("/").last.split("_").last.toLong < System.currentTimeMillis) {
println("considered " + x)
LIST += x.toString
return true
} else {
println("NOT considered " + x)
return false
}
return flag
}
}
I am trying to update the external variable LIST inside the function filterF. But the problem is that after the println("looking into "+x)
line the rest of the code is unreachable.
val flag = if (x.toString.split("/").last.split("_").last.toLong < System.currentTimeMillis) {
println("considered " + x)
LIST += x.toString
return true
} else {
println("NOT considered " + x)
return false
}
return flag
I can't understand why this code is unreachable. Is there some character in the code that is actually reason for this?
Do not use return
When you use return control of execution will leave the function and all code after the return statement will not be reachable
code after return will be unreachable
def foo: Int = {
return 1
2 + 3 //unreachable
}
In case of if expression
def bar: Int = {
if (true) {
return 1
} else {
return 2
}
1 + 2 //unreachable
}
In Scala return statement is optional and not recommended as its not consider functional coding practice.
The value of last expression in the code block is the return value in Scala. So don't worry about explicit return just leave it to the program
val flag = if (x.toString.split("/").last.split("_").last.toLong < System.currentTimeMillis) {
println("considered " + x)
LIST += x.toString
true //removed return
} else {
println("NOT considered " + x)
false // removed return
}
Halting the program executing by throwing an exception or by returning value or by explicitly calling exit is not functional way of doing things. Unfortunately Scala does allow it. But if you want to be a good citizen of functional world. You better avoid it.
Avoid mutable collections
Use mutable collections if you have a strong need for it. There are advantages of immutable collections
1) They are thread safe.
2) Bug free (no surprises by accidental mutations and no blocking).
3) Referential transparency.
4) Reasonable performance.
Use immutable list instead of mutable list.
Use Scala lambda notation and Syntactic sugar
Syntactic sugar is there for a reason. Syntactic sugar reduces the boilerplate code. So that your code looks clear, cleaner and better. Helps in code maintainability. Code remains bug free for longer time.
Instead of Function1 trait use lambda notation.
scala> val f = new Function1[String, String] { def apply(str: String): String = str}
f: String => String = <function1>
scala> val f = {str: String => str}
f: String => String = <function1>
So your code becomes
val paths = List[Path]() //assume you have Paths in it.
val filter = {path: Path => path.toString.split("/").last.split("_").last.toLong < System.currentTimeMillis }
val resultList = paths.filter(filter)
This is caused the flag is val not def, but your statement is using the return to return true or false. the return keywords is only for method not for function.
The correct way maybe like:
val flag = if (x.toString.split("/").last.split("_").last.toLong < System.currentTimeMillis) {
println("considered " + x)
LIST += x.toString
true
}
else {
println("NOT considered " + x)
false
}
I have implemented a recursive method to check if number of parenthesis in a string is valid or not. Here is the code
def balance(chars: List[Char]): Boolean = {
#tailrec
def isValid(newChars: List[Char], difference: Int): Boolean = {
if (newChars.isEmpty) difference == 0
else if (difference < 0) false
else {
var newDifference = difference // Scala IDE gives warning here
if (newChars.head == '(') newDifference = difference + 1
else if (newChars.head == ')') newDifference = difference - 1
isValid(newChars.tail, newDifference)
}
}
isValid(chars, 0)
}
I tested the above code for the following test cases and it works fine So I am only looking for improving the if/else ladder.
println("Testing parenthesis balancing")
assert(balance("(Sachin is learning (scala) and (spark))".toList))
assert(!balance("(Invalid))(expression)".toList))
assert(balance("".toList))
assert(balance("()()".toList))
assert(!balance("{())}{()}".toList))
As mentioned in the code, Scala IDE complains on that line saying
Avoid mutable local variables
I am not really sure how to compute the value of newDifference without using if/else. Other option I could see is directly call isValid method in if/else ladder with computed values of newDifference.
I am still learning Scala So I want to know what could be the best possible way to write this code without mutating the local variable (or any other warning).
People use pattern match for that. That way you can avoid both mutable variables and the "if/else ladder", that makes for horrible "spaghetti code".
def isValid(chars: List[Char], ps: Int = 0) = (chars, ps) match {
case (Nil, _) => ps == 0
case (_, _) if ps < 0 => false
case ('(' :: tail, ps) => isValid(tail, ps + 1)
case (')' :: tail, ps) => isValid(tail, ps - 1)
case (_ :: tail, ps) => isValid(tail, ps)
}
You can write:
val newDifference =
if (newChars.head == '(') difference + 1
else if (newChars.head == ')') difference - 1
else difference;
as if in Scala is an expression, or use match, which would be considered more idiomatic in this case:
val newDifference = newChars.head match {
case '(' => difference + 1
case ')' => difference - 1
case _ => difference
}
The whole function can be converted into a single match on newChars, but I'll leave that to you. See the first example here for some ideas.
I am struggling to understand how this code 'strips out' the Future.
getFutureResult() returns a Future[String]. So how come the return from the yield is only a String?
def getFutureResult:Future[String] = { ... }
def getMyResult:String = {
for {
myFutureResult <- getFutureResult()
} yield {
myFutureResult
}
}
It is translated according to Scala for-comprehension translation rules:
for (x <- <expr>) yield f(x)
becomes:
<expr>.map(x => f(x))
This is a desugaring done by the compiler irregardless if <expr> has the type of a collection, a future or something else.
Future in Scala has a method map, so it uses the myFutureResult String from above to construct another Future[String].
You never know if the resulting future getMyResult is completed -- you should install an onComplete callback that will be called by the resulting future once it completes:
getMyResult onComplete {
case Success(x) => println("Yes! " + x)
case Failure(t) => println("An error: " + t)
}
The code for the onComplete method is executed asynchronously -- it might happen on a different thread, much later or simultaneously.
If you really need to know if the Future has completed, use the:
Await(getMyResult, 0 nanos)
pattern to block the calling thread until the getMyResult future is completed. In general, you should avoid this and compose your Future code using for-comprehensions and callback.
I've got a nested block of a condition, a for loop and try/catch block to return a tuple:
val (a, b) = {
if (...) {
for (...) {
try {
getTuple(conf)
} catch {
case e: Throwable => println(...)
}
}
sys.exit
} else {
try {
getTuple(userConf)
} catch {
case e: Throwable => println(...); sys.exit
}
}
}
If the if condition matches I would like to try x different conf configurations. When getTuple throws an exception, try the next one. When getTuple does not throw an exception, fill the tuple with the result. getTuple returns the tuple (a,b).
Problem: However, the for loop does not exit when getTuple does not throw an exception. I also tried break but that does not work as it should return the tuple and not just exit the for loop.
How can I get this to work?
Instead of throwing Exception, getTuple should evaluate as a Option[Tuple2[T,U]], it has more meaning and does not break the flow of the program.
This way, you can have a for like this:
val tuples: List[Option[Tuple2[T,U]] = for {
c <- configs
} yield getTuple(c)
val firstWorkingConfig: Option[Tuples2[T,U]] = tuples.flatten.headOption
// Exit the program if no config is okay
firstWorkingConfig.getOrElse {
sys.exit
}
Hope this helps
I'd suggest to use more functional features of Scala instead of dealing with loops and exceptions.
Suppose we have a function that throws an exception on some inputs:
def myfn(x: Double): Double =
if (x < 0)
throw new Exception;
else
Math.sqrt(x);
We can either refactor it to return Option:
def optMyfn(x: Double): Option[Double] =
if (x < 0)
None;
else
Some(Math.sqrt(x));
Or if we don't want to (or cannot modify the original code), we can simply wrap it using Exception.Catcher:
def optMyfn(x: Double): Option[Double]
= scala.util.control.Exception.allCatch.opt(myfn(x));
Now let's have a sequence of numbers and we want to find the first one on which the function succeeds:
val testseq: Seq[Double] = Seq(-3.0, -2.0, 2.0, 4.0, 5.0);
We can use Scala's functional features to apply the function to all the elements and find the first Some result as
testseq.toStream.map(optMyfn _).flatten.headOption
It'd work as well without using toStream, but we'd call optMyfn unnecessarily on all the element, instead of just those we need to find the first successful result - streams make the computation lazy.
(Another option would be to use views, like
testseq.view.map(optMyfn _).collectFirst({ case Some(x) => x })
.)
The sys.exit call is kinda misplaced in the if statement. It should be inside the catch clause to allow for a return of tupe if try is successful.
If you want to loop until you get a working tuple a while loop makes more sense. The semantics of a for loop is to evalute the body for all elements you are iterating. Since your goal is to stop after the first which satisfies a condition, a while loop seems much more natural. Of course there would be some more functional alternatives, for instance:
wrap your getTuple in an Option, where None corresponds to an exception.
put the calls to getTuple in some iterable/traversable collection
get the first element which is not None
While I was explaining the concept, Romain Sertelon gave a nice example of the idea...
Another solution is to just wrap the whole block into a method and use return like:
val (a: Type, b: Type) = setup(...)
def setup(...) : (Type, Type) = {
if (...) {
for (...) {
try {
return getTuple(...)
} catch {
...
}
}
sys.exit
} else {
try {
return getTuple(...)
} catch {
case e: Throwable => println(...); sys.exit
}
}
}
I think I should learn more basics of Scala, but that works now for the moment.
Thanks for your answers.