Scala Tail Recursion From a Flatmap - scala

I have a recursive call as defined below:
def getElems[A](a: A)(f: A => List[A]): List[A] = {
f(a)
}
def parse[A](depth: Int, elems: List[A], f: A => List[A]): List[A] = {
elems.flatMap(elem => {
if (depth > 0) {
parse(depth - 1, getElems(elem)(f), f)
} else elems
})
}
As it can be seen that for every elem in the elems, I run a function that in turn gives me back another List. I do this until I reach the depth 0. So for example., I start with a certain elems and a certain depth like:
parse(depth = 2, elems = List("1", "2"), someFnThatGivesBackAListOfString)
What I'm doing with my code above is that for each element in elems, I check the depth value and if the depth is > 0, I run the function for that elem and go over the same process until I hit a depth of 0. This works as expected, but as it can be seen that it is not stack safe, I'm thiking of getting a tail recursive implementation. To my understanding tail recursion is about reduction, but here it is not the case. So how do I make it stack safe or how can I do a tail recursive logic here?
I started with something like this, but this is not quite right:
def firstAttempt[A](ls: List[A], depthOrig: Int)(f: (A => List[A])): List[A] = {
#annotation.tailrec
def helper(acc: List[A], ls: List[A], depth: Int): List[A] =
ls match {
case Nil => acc
case sublist # (head :: tail) =>
// Check if the entry is available in the bloom filter
if (depth > 0)
helper(acc ::: f(head), tail, depth - 1)
else
helper(acc.appended(head), tail, depthOrig)
}
helper(Nil, ls, depthOrig)
}

I got this to work by attaching the current depth to each element.
def parse[A](depth:Int, elems:List[A], f:A => List[A]): List[A] = {
#annotation.tailrec
def loop(todo:List[(A,Int)], acc:List[A]): List[A] = todo match {
case Nil => acc
case (_,dpth)::_ if dpth < 1 =>
val (zs, td) = todo.span(_._2 < 1)
loop(td, acc ++ zs.flatMap(_ => zs.map(_._1)))
case (elm,dpth)::tl =>
loop(f(elm).map(_ -> (dpth-1)) ++ tl, acc)
}
loop(elems.map(_ -> depth), Nil)
}

Related

What to set as default when the type is A (Scala)

I have an exercise in Scala in which I have to transform that kind of list (a,a,a,b,c,d,d,e,a,a) into
((a,3),(b,1),(c,1),(d,2),(e,1),(a,2)).
I obviously know that my algorithm is not correct yet, but I wanted to start with anything.
The problem is that I don't know how to turn on the function (last line), because the error is that whatever I take as previous' argument, it says that required: A, found: Int/String etc.
The previous was meant to be as a head of the previous iteration.
def compress[A](l: List[A]): List[(A, Int)] = {
def compressHelper(l: List[A], acc: List[(A, Int)], previous: A, counter: Int): List[(A, Int)] = {
l match {
case head::tail => {
if (head == previous) {
compressHelper(tail, acc :+ (head, counter+1), head, counter+1)
}
else {
compressHelper(tail, acc :+ (head, counter), head, 1)
}
}
case Nil => acc
}
}
compressHelper(l, List(), , 1)
}
You don't need to pass previous explicitly, just look at the accumulator:
def compress[A](l: List[A], acc: List[(A, Int)]=Nil): List[(A, Int)] =
(l, acc) match {
case (Nil, _) => acc.reverse
case (head :: tail, (a, n) :: rest) if a == head =>
compress(tail, (a, n+1) :: rest)
case (head :: tail, _) => compress (tail, (head, 1) :: acc)
}

Scala Recursively Count Elements Given Predicate

I have this iterative function which counts the number of Boolean values in a list.
def countBoolIter[A](test: A=>Boolean, a: List[A]) = {
var count = 0
for(elem <- a){
if(test(elem)) count += 1
}
count
}
The first parameter passed in is an isBool function:
def isBool(i: Any) = i match {
case _: Boolean => true
case _ => false
}
Calling the function looks like this:
countBoolIter(isBool, List(1, true, 3, true, false, "hi"))
// Output: 3
Now, I tried converting it into a tail recursive function like this:
def countBoolRec[A](test: A=>Boolean, a: List[A], acc: Int = 0): Int = a match {
case Nil => acc
case h :: t if(test(h)) => countBoolRec(test, a, acc+1)
case h :: t => countBoolRec(test, a, acc)
}
However, I'm getting a runtime error because the function doesn't return anything; no errors are thrown. I presume that it is stuck in an infinite loop that's why nothing is being returned.
Question: How should I fix my attempted recursive implementation?
There is an error in the function countBoolRec:
#tailrec
def countBoolRec[A](test: A=>Boolean, a: List[A], acc: Int = 0): Int = a match {
case Nil => acc
case h :: t if(test(h)) => countBoolRec(test, t, acc+1)
case h :: t => countBoolRec(test, t, acc)
}
In the recursive call, use t as the parameter and no again a. If not, basically, you are in an infinite loop.
Also, better to use the #tailrec annotation to be sure that the implementation is "tail recursive".
You're repeatedly recursing with the same list as input.
Consider the case where a.head passes the test:
countBoolRec(test, a, 0)
countBoolRec(test, a, 1)
countBoolRec(test, a, 2)
... and so on
#scala.annotation.tailrec // Not that your original code wasn't tail-recursive, but it's a generally good practice to mark code that isn't tail recursive with this annotation
def countBoolRec[A](test: A=>Boolean, a: List[A], acc: Int = 0): Int = a match {
case Nil => acc
case h :: t if (test(h)) => countBoolRec(test, t, acc + 1)
case h :: t => countBoolRec(test, t, acc)
}
Though you could also just as well write:
(0 /: a) { (acc, v) => acc + (if (test(v)) 1 else 0) }

Tail-recursive Implementation of Scala's List partition method

For exercise purposes I've been trying to implement a couple of Scala's List methods in a functional manner, one of them being partition. Assume the following signature:
def partition[T](l: List[T], f: T => Boolean): (List[T], List[T])
It returns a tuple consisting of two lists - the first one contains all the elements from l that fulfill the passed predicate f and another one which contains all the other elements.
I came up with the following recursive solution which is unfortunately not tail-recursive:
def partition[T](l: List[T], f: T => Boolean): (List[T], List[T]) = {
l match {
case Nil => (Nil, Nil)
case head :: rest => {
val (left, right) = partition(rest, f)
if (f(head))
(head :: left, right)
else
(left, head :: right)
}
}
}
In this stack overflow question (Can all recursive functions be re-written as tail-recursions?) it is made clear that an accumulator could be used in some cases. In the given one I would claim that this is not possible since it would return the final lists in a reversed manner.
Could you please give me a tail-recursive solution? Maybe even with continuation passing (I haven't really understood how it works and how it could be applied)?
You can keep a tuple as the accumulator, and make sure to reverse the lists before returning them:
def partition[T](l: List[T])(f: T => Boolean): (List[T], List[T]) = {
#tailrec
def partitionInternal(l: List[T])(acc: (List[T], List[T])): (List[T], List[T]) = {
l match {
case Nil => acc
case head :: tail =>
if (f(head)) partitionInternal(tail)(head :: acc._1, acc._2)
else partitionInternal(tail)(acc._1, head :: acc._2)
}
}
val (lf, r) = partitionInternal(l)((List.empty[T], List.empty[T]))
(lf.reverse, r.reverse)
}
An alternative solution would be to append (:+) instead of prepending (::), but then you pay the price of O(n) for every entry.
Another idea would be to use a ListBuffer[T] instead of List[T] for the internal recursive implementation which has constant time append. All you need to do is call .toList at the end:
def partition[T](l: List[T])(f: T => Boolean): (List[T], List[T]) = {
#tailrec
def partitionInternal(l: List[T])(acc: (ListBuffer[T], ListBuffer[T])): (ListBuffer[T], ListBuffer[T]) = {
l match {
case Nil => acc
case head :: tail =>
val (leftAcc, rightAcc) = acc
if (f(head)) partitionInternal(tail)((leftAcc += head, rightAcc))
else partitionInternal(tail)((leftAcc, rightAcc += head))
}
}
val (lf, r) = partitionInternal(l)((ListBuffer.empty[T], ListBuffer.empty[T]))
(lf.toList, r.toList)
}
Additionaly, notice that I create a separate argument list for the List[T] and the function from T => Boolean. That is in order to help the compiler infer the right type argument when applying the method since type inference flows between parameter lists.
You need to keep two accumulators, one for left and one for right. When you're done going through the input list, simply return both accumulators (reversing them to get back to the original order):
def partition[T](l: List[T], f: T => Boolean): (List[T], List[T]) = {
#annotation.tailrec
def aux(tl: List[T], left: List[T], right: List[T]): (List[T], List[T]) = tl match {
case Nil => (left.reverse, right.reverse)
case head :: rest => {
if (f(head))
aux(rest, head :: left, right)
else
aux(rest, left, head :: right)
}
}
aux(l, List(), List())
}
Using it:
scala> def partition[T](l: List[T], f: T => Boolean): (List[T], List[T]) = {
| #annotation.tailrec
| def aux(tl: List[T], left: List[T], right: List[T]): (List[T], List[T]) = tl match {
| case Nil => (left.reverse, right.reverse)
| case head :: rest => {
| if (f(head))
| aux(rest, head :: left, right)
| else
| aux(rest, left, head :: right)
| }
| }
|
| aux(l, List(), List())
| }
partition: [T](l: List[T], f: T => Boolean)(List[T], List[T])
scala> partition(List(1, 2, 3, 4, 5), (i: Int) => i%2 == 0)
res1: (List[Int], List[Int]) = (List(2, 4),List(1, 3, 5))

Recursively iterate through a Scala list

I'm trying to recursively iterate through a list in Scala using pattern matching. I cannot use any list functions, or while/for loops. What I need to do is iterate through the list, and remove an element if it matches to be '4'. I'm new to Scala and I cannot find the answer in the textbook I have nor on google. Everyone else uses the filter method, or some other list method.
Here's what I tried to do (which is wrong)
def removeFours(lst: List[Int]): List[Int] = {
val newLst = lst
lst match {
case Nil => Nil
case a if a == 4 => newLst -= 0
case n => removeFours(newLst)
}
newLst
}
See if this works for you.
def removeFours(lst: List[Int], acc: List[Int] = List.empty): List[Int] = {
lst match {
case Nil => acc.reverse
case 4 :: t => removeFours( t, acc )
case h :: t => removeFours( t, h :: acc )
}
}
Usage:
scala> removeFours( List(3,7,4,9,2,4,1) )
res84: List[Int] = List(3, 7, 9, 2, 1)
Using an inner function and pattern matching to de-structure the list. If the head in the list is 4, then do not add it to the accumulator. If it is, append it to the accumulator.
def removeFours(lst: List[Int]): List[Int] = {
def loop(lst: List[Int], acc: List[Int]): List[Int] = lst match {
case Nil => acc
case h :: t =>
if (h == 4) {
loop(t, acc)
}else{
loop(t, acc :+ h)
}
}
loop(lst, List())
}
The preferred way to do this is with guards in the pattern match but the if else statement may look more familiar if you're just getting started with scala.
def removeFours(lst: List[Int]): List[Int] = {
def loop(lst: List[Int], acc: List[Int]): List[Int] = lst match {
case Nil => acc
case h :: t if (h == 4) => loop(t, acc)
case h :: t => loop(t, acc :+ h)
}
loop(lst, List())
}
I am not sure about the execution time. I am also new to scala but I am taking bollean approach to filter any list.
object Main extends App {
//fun that will remove 4
def rm_4(lst: List[Int]) : List[Int] = {
val a = lst.filter(kill_4)
a
}
// boolean fun for conditions
def kill_4(n: Int) : Boolean = {
if (n ==4) false
else true
}
println(rm_4(List(1,2,4,5,4))) // outpur List(1,2,5)
}

How can I make this Scala function (a "flatMap" variant) tail recursive?

I'm having a look at the following code
http://aperiodic.net/phil/scala/s-99/p26.scala
Specifically
def flatMapSublists[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] =
ls match {
case Nil => Nil
case sublist#(_ :: tail) => f(sublist) ::: flatMapSublists(tail)(f)
}
I'm getting a StackOverflowError for large values presumably because the function is not tail recursive. Is there a way to transform the function to accommodate large numbers?
It is definitely not tail recursive. The f(sublist) ::: is modifying the results of the recursive call, making it a plain-old-stack-blowing recursion instead of a tail recursion.
One way to ensure that your functions are tail recursive is to put the #annotation.tailrec on any function that you expect to be tail recursive. The compiler will report an error if it fails to perform the tail call optimization.
For this, I would add a small helper function that's actually tail recursive:
def flatMapSublistsTR[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] = {
#annotation.tailrec
def helper(r: List[B], ls: List[A]): List[B] = {
ls match {
case Nil => r
case sublist#(_ :: tail) => helper(r ::: f(sublist), tail)
}
}
helper(Nil, ls)
}
For reasons not immediately obvious to me, the results come out in a different order than the original function. But, it looks like it works :-) Fixed.
Here is another way to implement the function:
scala> def flatMapSublists[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] =
| List.iterate(ls, ls.size)(_.tail).flatMap(f)
flatMapSublists: [A, B](ls: List[A])(f: List[A] => List[B])List[B]
A simply comparison between dave's flatMapSublistsTR and mine:
scala> def time(count: Int)(call : => Unit):Long = {
| val start = System.currentTimeMillis
| var cnt = count
| while(cnt > 0) {
| cnt -= 1
| call
| }
| System.currentTimeMillis - start
| }
time: (count: Int)(call: => Unit)Long
scala> val xs = List.range(0,100)
scala> val fn = identity[List[Int]] _
fn: List[Int] => List[Int] = <function1>
scala> time(10000){ flatMapSublists(xs)(fn) }
res1: Long = 5732
scala> time(10000){ flatMapSublistsTR(xs)(fn) }
res2: Long = 347232
Where the method flatMapSublistsTR is implemented as:
def flatMapSublistsTR[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] = {
#annotation.tailrec
def helper(r: List[B], ls: List[A]): List[B] = {
ls match {
case Nil => r
case sublist#(_ :: tail) => helper(r ::: f(sublist), tail)
}
}
helper(Nil, ls)
}
def flatMapSublists2[A,B](ls: List[A], result: List[B] = Nil)(f: (List[A]) => List[B]): List[B] =
ls match {
case Nil => result
case sublist#(_ :: tail) => flatMapSublists2(tail, result ++ f(sublist))(f)
}
You generally just need to add a result result parameter to carry from one iteration to the next, and spit out the result at the end instead of adding the end to the list.
Also that confusting sublist# thing can be simplified to
case _ :: tail => flatMapSublists2(tail, result ++ f(ls))(f)
Off-topic: here's how I solved problem 26, without the need for helper methods like the one above. If you can make this tail-recursive, have a gold star.
def combinations[A](n: Int, lst: List[A]): List[List[A]] = n match {
case 1 => lst.map(List(_))
case _ => lst.flatMap(i => combinations (n - 1, lst.dropWhile(_ != i).tail) map (i :: _))
}