If the last statement in a function is func(x,tailList):
def func(x:Int):List[Int]...
case head :: tailList => head :: func(x,tailList)
converting this function to tail recursion requires accumulator to be added as a third parameter (and to keep it clean adding a local function inside func() ).
insertTail(x,tailList,head::acc)
doesn't seem to work correctly. shouldn't "acc" hold the computation in progress?
Am I missing something here to make it tail recursive work with accumulator?
Adding a more complete example
def funcTailTest(x:Int,xs:List[Int]):List[Int] = {
#tailrec
def inner(x:Int,xs:List[Int],acc:List[Int]) : List[Int] = xs match {
case head::tailList => {
inner(x,tailList,head::acc)
}
}
inner(x,xs,Nil)
}
basically head should be added to the output of inner() function so w/o an attempt to make it tail recursive last statement in a case will look
head::inner(x,tailList)
Assuming that reverse is also tail recursively implemented (which it definitely can be), the following is a tail recursive append:
def append[T](y: T, xs: List[T]): List[T] = {
#tailrec
def appendAcc[T](y: T, xs: List[T], acc: List[T]): List[T] = xs match {
case Nil => y :: acc
case x :: xs => appendAcc(y, xs, x :: acc)
}
appendAcc(y, xs, Nil).reverse
}
Following is a scala function to implement Tail recursion using cons operator
def reverseUtility(ele: List[Int], res: List[Int]):List[Int] ={
ele match {
case Nil => Nil
case x :: Nil => x :: res
case x :: y => reverseUtility(y, (x::res))
}}
Pass a list of Int and an empty list called res(result) as parameters for the function. Time complexity for the function is O(N)
Related
I'm supposed to write a recursive functional concatenation function in Scala without using standard list operators.
def myConcat: (List[Any],List[Any]) => List[Any] = {
case (xs,Nil) => xs
case (xs,y::ys) => myConcat(xs::y,ys)
}
which throws the error
case (xs,y::ys) => myConcat(xs::y,ys)
^
Recursion.scala:3: error: value :: is not a member of Any
I am rather confident that this would, but that I am misunderstanding something about the syntax/typing. To the best of my knowledge xs::y should be of type List[Any].
I assume, you cannot use List.reverse either, so, start with implementing that:
#tailrec
def reverse(in: List[Any], out: List[Any]): List[Any] = in match {
case Nil => out
case head::tail => reverse(tail, head::out)
}
Now, for concat:
#tailrec
def concatReversed(x: List[Any], y: List[Any]): List[Any] = x match {
case Nil => y
case head::tail => concatReversed(tail, head::y)
}
def concat(x: List[Any], y: List[Any]) =
concatReversed(reverse(x, List.empty[Any]), y)
If you are not looking for the solution to be tail-recursive, it makes things simpler (albeit less efficient):
def concat(x: List[Any], y: List[Any]): List[Any] = x match {
case Nil => y
case head :: tail => head :: concat(tail, y)
}
I have the following snippet of scala code:
def append(as: List[Int], bs: List[Int]): List[Int] = as match {
case Nil => bs
case x::xs => x::append(xs, bs)
}
I don't understand the x:: in the line where x::append(xs, bs) is. I know that when the list as is empty then bs will be returend (with an appended as when as was not empty before). But how does scala know in the mentioned line that is should append as to bs with x::(..,..)
Perhaps it would help if we desugar append a bit
def append(as: List[Int], bs: List[Int]): List[Int] =
as match {
case Nil => bs
case ::(x, xs) =>
val list = append(xs, bs)
list.::(x)
}
Note how :: appears twice, however the first one in
case ::(x, xs)
is actually a case class, even though its symbolic name seems strange, and its declaration looks a bit like this
case class :: (head: A, next: List[A])
whilst, on the other hand, the second :: in
list.::(x)
is actually a right-associative method which Adds an element at the beginning of this list and looks something like so
def :: (elem: B): List[B]
Note how x :: list is equivalent to list.::(x) and not x.::(list) meaning :: is invoked on the right argument.
I am having a real tough time with tail recursion...
My current function filters out values less than 'n' from list 'l'
def filter(n: Int, l: List): List = l match {
case Nil => Nil
case hd :: tl => {
if (hd < n) filter(n, tl)
else hd :: filter(n, tl)
}
}
When using large lists, this causes the stack to overflow.
Can someone please help me understand how to convert this to a tail recursive function?
Thanks for any input!
This is usually done with a helper function that accumulates the results. filterR has an additional parameter acc that we add values that are greater than n to.
def filter(n: Int, l: List[Int]): List[Int] = {
#scala.annotation.tailrec
def filterR(n: Int, l: List[Int], acc: List[Int]): List[Int] = l match {
case Nil => acc
case hd :: tl if(hd < n) => filterR(n, tl, acc)
case hd :: tl => filterR(n, tl, hd :: acc)
}
filterR(n, l, List[Int]())
}
With the suggestion from #jwvh:
#scala.annotation.tailrec
def filter(n: Int, l: List[Int], acc: List[Int] = List[Int]()): List[Int] = l match {
case Nil => acc.reverse
case hd :: tl if(hd < n) => filter(n, tl, acc)
case hd :: tl => filter(n, tl, hd :: acc)
}
#Brian's answer is nice but it reverses the input list. That's generally not the intended behaviour.
#jwvh's recommendation is pass the accumulator in a 3rd parameter to the function but that leaks private API to public API.
Either solution would necessitate reversing the accumulator before returning the answer – effectively iterating thru your input list twice. That's an insane implementation, especially considering you're trying to implement this to facilitate large lists.
Consider this tail-recursive implementation which does not expose private API and does not require the accumulator to be reversed after filtering.
disclaimer: this is the first scala procedure I have ever written. Feedback on any implementation style or detail is welcomed.
def filter(n: Int, xs: List[Int]): List[Int] = {
#scala.annotation.tailrec
def aux(k: List[Int] => List[Int], xs: List[Int]): List[Int] = xs match {
case Nil => k(Nil)
case x :: xs if (x < n) => aux(k, xs)
case x :: xs => aux((rest: List[Int]) => k(x :: rest), xs)
}
aux(identity, xs)
}
filter(5, List(1,2,3,4,5,6,7,8,9,0)))
// => List(5, 6, 7, 8, 9)
I have a code in scala that I wrote but I would like to eliminate ++ from it. The code runs fine but I'm trying not to use ++ or any built in functions or operators (not even :::).
Is it just better to create a val, or are there better ways around it.
Here's a sample of that code.
def partitionAux[A](f: A => Boolean, lst: List[A],
rslt: (List[A], List[A]) ):(List[A], List[A]) = {
lst match {
case Nil => return result
case head :: rest => {
if (f(head))
return partitionHelper(f, rest, (result._1 ++ List[A](head), rslt._2))
else ...
Given that you have only a single element as a second arg of ++, you could implement it yourself:
def concat[A](lst: List[A], a: A): List[A] =
lst match {
case Nil => a :: Nil
case head :: tail => head :: concat(tail, a)
}
println(concat(1 :: 2 :: 3 :: 4 :: Nil, 100)) // 1 :: 2 :: 3 :: 4 :: 100
Also given that you mentioned that partitionAux should split the list into two, it sounds like you should have just head :: result._1, instead of result._1 ++ List[A](head), and then reverse the list in the end. It is easy to write the reverse function yourself, like:
#tailRec
def reverse[A](list: List[A], result: List[A] = Nil): List[A] =
list match {
case Nil => result
case head :: tail => reverse(tail, head :: result)
}
P.S. And you don't need to put return keyword in scala. It doesn't do anything in you case
I am trying to do some examples programs in scala to get more familiar with the language, For that I am trying to re-implement some of the built in methods in Haskell, Most of these methods I am sure are also implemented in Scala too, But these are just for my practice. I think I can post some of code snippets (not all of them) to get a better way of doing things and to validate my understanding of scala. So please let me know if this is not the place to do these things.
Here is my scala implementation to get the last element of any list. Is this the right way of doing things, By using Any am I loosing the type of the object containing in the list? Is this how this kind of things implemented in scala?
def getLast(xs: List[Any]): Any = xs match {
case List() => null
case x :: List() => x
case _ :: ys => getLast(ys)
}
Parameterize the type of your function and use "Nil" instead of List() like so:
def getLast[T](xs: List[T]): T = xs match {
case Nil => null.asInstanceOf[T]
case x :: Nil => x
case _ :: ys => getLast(ys)
}
Also, consider making it return an Option type:
def getLast[T](xs: List[T]): Option[T] = xs match {
case Nil => None
case x :: Nil => Some(x)
case _ :: ys => getLast(ys)
}
Usage:
val listOfInts = List(1,2,3)
assert(getLast(listOfInts).isInstanceOf[Int])
val listOfStrings = List("one","two","three")
assert(getLast(listOfStrings).isInstanceOf[String])
Firstly, avoid the null, and especially null.asInstanceOf[T]. Observe the danger with primitives:
scala> null.asInstanceOf[Int]
res19: Int = 0
scala> null.asInstanceOf[Boolean]
res20: Boolean = false
So the signature should either be List[T] => T, whereby last on an empty iterator throws an exception:
def last[T](ts: List[T]): T = ts match {
case Nil => throw new NoSuchElementException
case t :: Nil => t
case t :: ts => last(ts)
}
Or instead: List[T] => Option[T]
def lastOption[T](ts: List[T]): Option[T] = ts match {
case Nil => None
case t :: Nil => Some(t)
case t :: ts => lastOption(ts)
}
def lastOption1[T](ts: List[T]): Option[T] = ts.reverse.headOption
def lastOptionInScala28[T](ts: List[T]): Option[T] = ts.lastOption // :)