Scala method optimization - scala

I'm having a def that is recursively called and I'm using a bunch of cases.
I'm wondering is there is any nice solution to get rid of that cases, without losing the readability of the definition.
#tailrec
def getElements(existent:List[List[String]], proposed: List[List[String]], result: List[(String,List[String])]): List[(String, List[String])]= {
proposed match {
case head :: tail => {
existent.find(element => identicalOfMatch(element, head)) match {
case Some(elem) => getElements(existent.filterNot(e => e == elem), tail, ("Same", elem) :: result)
case None => {
existent.find(element => noneOfMatch(element, head) && canDelete(proposed, element)) match {
case Some(elem) => getElements(existent.filterNot(e => e == elem), head::tail, ("Delete", elem) :: result)
case None => {
existent.find(element => firstOfMatch(element, head)) match {
case Some(elem) => getElements(existent.filterNot(e => e == elem), tail, ("Update", head) :: result)
case None => {
existent.find(element => anyOfMatch(element, head) && firstOfNotPresent(proposed, head.head) && firstOfNotPresent(existent, head.head)) match {
case Some(elem) => getElements(existent.filterNot(e => e == elem), tail, ("Update", head) :: result)
case None => getElements(Nil, Nil, existent.map(element => ("Deleted", element)) ::: proposed.map(element => ("Created", element)) ::: result)
}
}
}
}
}
}
}
}
case Nil => result
}
}

Your method readability would benefit greatly if you could split it into several methods.
Unfortunately, you can't do that if you want your function to be tail-recursive.
But there is a solution which is called trampoline, which would allow you to create an arbitrarily deep chain of function recursive calls which are stack-safe.
Trampolines are implemented in Scala standard library in package scala.util.control.TailCalls. I reimplemented your method to take advantage of it.
First thing I did was removing an accumulator parameter from getElements, we won't need it anymore.
Then I split getElements into three functions. I called nested functions ifNoneMatched and ifNoneMatched2 but you could probably come up with more meaningful names.
Then I wrapped every call to a function which is in the chain into tailcall and every constant into done (in our case Nil). When I needed to append something to list returned from a recursive call I used flatMap from TailRec.
import scala.util.control.TailCalls._
def getElements(existent:List[List[String]], proposed: List[List[String]]): TailRec[List[(String, List[String])]]= {
proposed match {
case head :: tail => {
existent.find(element => identicalOfMatch(element, head)) match {
case Some(elem) => tailcall(getElements(existent.filterNot(e => e == elem), tail).map(("Same", elem) :: _))
case None => tailcall(ifNoneMatched(head, tail, existent, proposed))
}
}
case Nil => done(Nil)
}
}
def ifNoneMatched(head: List[String], tail: List[List[String]], existent:List[List[String]], proposed: List[List[String]]): TailRec[List[(String, List[String])]] = {
existent.find(element => noneOfMatch(element, head) && canDelete(proposed, element)) match {
case Some(elem) => tailcall(getElements(existent.filterNot(e => e == elem), proposed)).map(("Delete", elem) :: _)
case None => tailcall(ifNoneMatched2(head, tail, existent, proposed))
}
}
def ifNoneMatched2(head: List[String], tail: List[List[String]], existent:List[List[String]], proposed: List[List[String]]): TailRec[List[(String, List[String])]] = {
existent.find(element => firstOfMatch(element, head)) match {
case Some(elem) => getElements(existent.filterNot(e => e == elem), tail).map(("Update", head) :: _)
case None => {
existent.find(element => anyOfMatch(element, head) && firstOfNotPresent(proposed, head.head) && firstOfNotPresent(existent, head.head)) match {
case Some(elem) => tailcall(getElements(existent.filterNot(e => e == elem), tail)).map(("Update", head) :: _)
case None => getElements(Nil, Nil).map(existent.map(element => ("Deleted", element)) ::: proposed.map(element => ("Created", element)) ::: _)
}
}
}
}
getElements returns now TailRec[List[(String, List[String])]], but you can unwrap it by just calling result.
Of course, you can nest methods even deeper. Until you wrap your method calls into tailcall your stack is safe.
I didn't reimplement your methods like identicalOfMatch etc. so I couldn't really test if my implementation works. If something breaks please let me know ;)

Related

Scala - head of empty list - removing all None's from a list of Options

Been trying to solve this for a while now. I need a recursive function that removes all None's from a list of Option[Int]'s, without using if-statements or using other functions.
def RemoveNone2(input: List[Option[Int]]) : List[Int] = {
input.head match {
case None => RemoveNone2(input.tail)
case _ => (input.head.get::RemoveNone2(input.tail))
}
}
val optional: List[Option[Int]] = List(Some(13), None, Some(32), None, Some(51), None, Some(17), None)
RemoveNone2(optional)
But when trying to execute the code, I get the following error:
java.util.NoSuchElementException: head of empty list
I suck at Scala, could anyone offer some insight?
You want headOption:
def RemoveNone2(input: List[Option[Int]]) : List[Int] = input.headOption match {
case None => RemoveNone2(input.tail)
case Some(head) => head :: RemoveNone2(input.tail)
}
A better way to write this is:
def removeNone(input: List[Option[Int]]) : List[Int] = input match {
case Nil => Nil
case Some(head) :: tail => head :: removeNone(tail)
case None :: tail => removeNone(tail)
An even better way is to use an accumulator, so that you can take advantage of tail-recursion:
def removeNone(input: List[Option[Int]], out: List[Int]=Nil) : List[Int] = input match {
case Nil => out.reverse
case Some(head) :: tail => removeNone(tail, head :: out)
case None :: tail => removeNone(tail, out)
}
You need to check that input list is empty to break the recursion. One of the options is to match against the list itself:
def RemoveNone2(input: List[Option[Int]]) : List[Int] = input match {
case head :: tail => head match {
case Some(value) => value :: RemoveNone2(tail)
case _ => RemoveNone2(tail)
}
case _ => Nil
}
Also note, that this implementation is not tail-recursive, whcih can lead to errors or poor performance for big collections. Tail-recursive implementation can look like that:
def RemoveNone2(input: List[Option[Int]]) : List[Int] = {
#annotation.tailrec
def inner(innerInput: List[Option[Int]], acc: List[Int]): List[Int] = innerInput match {
case head :: tail => head match {
case Some(value) => inner(tail, value::acc)
case _ => inner(tail, acc)
}
case _ => acc
}
inner(input, Nil)
}

how can I write a function in scala called Order that takes one arguement: a list of Ints. And returns the same List of Ints from least to greatest

I've got a base case and a recursive call but I don't know where to go from there.I do also need to use pattern matching
def order(ls:List[Int]):List[Int] = ls match {
case Nil => Nil
case h::t => order(t)
I'm pretty sure you are looking for a recursive sort algorithm.
You can take a look at merge sort for example. This is a simplified Non generic version
def mergeSort(ls: List[Int]): List[Int] = {
def merge(l: List[Int], r: List[Int]): List[Int] = (l, r) match {
case (Nil, _) => r
case (_, Nil) => l
case (lHead :: lTail, rHead :: rTail) =>
if (lHead < rHead) {
lHead :: merge(lTail, r)
} else {
rHead :: merge(l, rTail)
}
}
val n = ls.length / 2
if (n == 0)
ls
else {
val (a, b) = ls splitAt n
merge(mergeSort(a), mergeSort(b))
}
}
Try This
def order(ls:List[Int]):List[Int] = ls match {
case Nil => Nil
case h => h.sorted
}
OR
def order(ls:List[Int]):List[Int] = ls match {
case Nil => Nil
case h => h.sortWith(_ < _)
}

could not optimize #tailrec annotated method loop: it contains a recursive call not in tail position

I have the following recursive function which I want to use tail recursion on it. But compiler complains about my implementation with this error:Error:(79, 7) could not optimize #tailrec annotated method loop: it contains a recursive call not in tail position
n match {
^
is it because of for loop that it assumes it's not in tail position?
def dsl[N,E](qNodes:QNodeLike[N,E]*) = {
val markers = scala.collection.mutable.Map.empty[String, N]
#tailrec
def loop(n:QNodeLike[N,E]):Unit = {
n match {
case QNode(head, kids:Seq[HalfEdgeLike[E,N]]) => {
for(kid <- kids){
kid match {
case EmptyHalfEdge() =>
case HalfEdge(e, n) => loop(n)
}
}
}
case QNodeMarker(head, marker, kids:Seq[HalfEdgeLike[E,N]]) => {
markers.update(marker,head)
for(kid <- kids){
kid match {
case EmptyHalfEdge() =>
case HalfEdge(e, n) => loop(n)
}
}
}
}
}
loop(qNodes.head)
}
Yes, that's right. To make it tail recursive, you should use an explicit accumulator which is passed into the recursion.
However, unless you have very deep and narrow trees, you are unlikely to need tail recursive optimization, as the run time will grow very large well before you end up with a stack overflow.
Here's a rough idea of how to make it tail optimized:
#tailrec
def loop(n:List[QNodeLike[N,E]]):Unit = {
n match {
case QNode(head, kids:Seq[HalfEdgeLike[E,N]]) :: rem => {
kids match {
case Nil =>
case EmptyHalfEdge() :: rem2 => loop(rem2 ::: rem)
case HalfEdge(e, n) :: rem2 => loop(n :: rem2 ::: rem)
}
}
case QNodeMarker(head, marker, kids:Seq[HalfEdgeLike[E,N]]) :: rem => {
markers.update(marker,head)
kids match {
case Nil =>
case EmptyHalfEdge() :: rem2 => loop(rem2 ::: rem)
case HalfEdge(e, n) :: rem2 => loop(n :: rem2 ::: rem)
}
}
case Nil =>
}
}
Yes it is because of the loop. The result of a tailrec funtion has to be the result of the recursive call. In your case the result is the result of the for statement.

Checking Members for Nil

Let's say I have a Tree object with 2 member objects, right and left.
What's the idiomatic/right way to check if tree's "right" and "left" fields are Nil?
def count(tree: Tree, acc: Int) : Int = tree match {
case tree .right != Nil && tree .left != Nil => countLeftAndRight(...)
case tree .right != Nil => countOnlyRight(...)
case tree .left != Nil => countOnlyLeft(...)
_ => acc
}
Your example isn't valid Scala, but the idiomatic way to match the Tree is with an extractor (look it up). You get this for free if Tree is a case class. Assuming it is, you can write
tree match {
case Tree(Nil, Nil) => acc
case Tree(Nil, x) => ...
case Tree(x, Nil) => ...
case Tree(x, y) => ...
}
Or, if you'd prefer to work with your non-case-class Tree as-is, then you might try this variation of Luigi's solution:
(tree.left, tree.right) match {
case (Nil, Nil) => acc
case (Nil, x) => ...
case (x, Nil) => ...
case (x, y) => ...

How can i transform this scala function in order to be optimized

Code to determine the lat element of a list, using pattern matching:
#tailrec
def last_rec[A](list : List[A]) : A = {
list match {
case (x :: Nil) => x
case (_ :: xs) => last_rec(xs)
case Nil => throw new NoSuchElementException
}
}
I want to compile the code, I am getting "yelled" by the compiler:
PS D:\workspace\scala\P99> scalac .\P01.scala
.\P01.scala:18: error: could not optimize #tailrec annotated method last2: it contains a recursive call not in tail position
case Nil => throw new NoSuchElementException
^
one error found
If I remove the #tailrec annotation - the code compiles . How can I modify the code in order to do the tail rec optimization ?
You got a typo their. Your method is called last_rec and you are calling last which is clearly undefined. So just rename it to last. And by the way you should return Option[A] instead of A. That way you can return None when nothing is found instead of throwing the ugly NoSuchElementException.
After removing the typo and adding agilesteel's suggestion:
#tailrec
def last_rec[A](list : List[A]) : Option[A] = {
list match {
case (x :: Nil) => Some(x)
case Nil => None
case (_ :: xs) => last_rec(xs)
}
}
In this case I would do what agilesteel suggested.
However, if you really wanted to throw an exception (in another different use case), you could do it in a statically typed way:
#tailrec
def last_rec[A](list : List[A]) : Either[NoSuchElementException,A] = {
list match {
case (x :: Nil) => Right(x)
case (_ :: xs) => last_rec(xs)
case Nil => Left(new NoSuchElementException)
}
}
where later you could:
last_rec(Nil) match {
case Right(s) => println("Got a value")
case Left(e) => println("Got an exception")
}