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)
}
Related
I'm working on question P07 of Ninety-Nine Scala Problems:
P07 (**) Flatten a nested list structure.
Example:
scala> flatten(List(List(1, 1), 2, List(3, List(5, 8))))
res0: List[Any] = List(1, 1, 2, 3, 5, 8)
My initial attempt at a solution was:
def flatten[A](ls : List[A]): List[A] = {
def flattenRec[A](ls: List[A], flatList: List[A]): List[A] = ls match {
case Nil => flatList
case head: List[A] :: tail => flattenRec(head ::: flatten(tail), flatList)
case head :: tail => flattenRec(tail, flatList :+ head)
}
flattenRec(ls, List[A]())
}
however this doesn't compile as I'm not allowed to specify a type for head in the second case statement. Is there a way for me to do this?
As an aside, the recommended solution uses flatMap instead of match, but I'm not sure why it even needs pattern matching in that case...
You can just bracket the declaration of head:
def flatten[A](ls : List[A]): List[A] = {
def flattenRec[A](ls: List[A], flatList: List[A]): List[A] = ls match {
case Nil => flatList
case (head: List[A]) :: tail => flattenRec(head, flatList)
case head :: tail => flattenRec(tail, flatList :+ head)
}
flattenRec(ls, List[A]())
}
Note that you will get a warning about the type pattern being unchecked (because the fact that head needs to be a list of A and not anything else will be lost at runtime due to erasure), which you will need to assure yourself you can ignore (or run through some hijinks involving TypeTags).
Nice problem and an alternate solution below:
def flatten(a:List[Any]):List[Any] =
a.flatMap{
case l:List[Any] => flatten(l)
case l => List(l)
}
When pattern matching a list, it seems common to return an empty list when given an empty list. We can match an empty list to Nil or List(), but we can return empty as Nil, List() or by returning the given list argument itself.
What's the convention here?
When would you choose one method over another?
Examples:
def givenEmptyNumsReturnsNil(nums: List[Int]): List[Int] = nums match {
case List() => Nil
case x :: xs => ???
}
def givenEmptyNumsReturnsEmptyList(nums: List[Int]): List[Int] = nums match {
case List() => List()
case x :: xs => ???
}
def givenEmptyNumsReturnsNums(nums: List[Int]): List[Int] = nums match {
case List() => nums
case x :: xs => ???
}
I'm scala beginner and don't know any existing convention about it. My things about it:
The last one isn't intuitive
I prefer return that I match. If I have case List(), so I return List().
You can also match Nil:
-
def givenEmptyNumsReturnsNil(nums: List[Int]): List[Int] = nums match {
case Nil => Nil
case x :: xs => ???
}
But Nil and List() are the same.
For choice better way, just clarify what inside:
case N1:
def givenEmptyNumsReturnsEmptyList(nums: List[Int]): List[Int] = nums match {
case List() => List()
case x :: xs => ???
}
Will call unaplay method from object List, after will call apply method of object List.
case N2:
def givenEmptyNumsReturnsNil(nums: List[Int]): List[Int] = nums match {
case Nil => Nil
case x :: xs => ???
}
Will compare value before match with object Nil and will return object Nil
And in case of choice I prefer case N2 because it is little bit optimal.
i'm new to Scala and i'm struggling sometimes with method signatures.
Lets take this code, i'm especially interested in naming the parameters to do further operations on them.
def divide(xs: List[Int]): List[Int] = {
val mid = xs.length/2
(xs take mid, xs drop mid)
}
Here I defined the input list named as "xs", I've seen this convention on many web pages. But in university we had another method signature definition method (I am missing the name, sorry) in which we didn't name the input parameter(s) but pattern matching takes place:
def mylength: List[Any] => Int = {
case Nil => 0
case x::xs => mylength(xs)+1
}
In this case, it is very trivial to identify the input parameter because there is just a single one. How could I use the same style as in the code below with 2 or more input parameters in the coding style shown above?
def myConcat(xs: List[Any], ys: List[Any]) = {
xs ++ ys
}
Sorry for my English. I didn't find anything on google because I didn't relly have a clue what terms to search for...
Edit: I have to stick to an interface. I make another example with which you could help me.
myAppend1 and myAppend2 shall behave the same way, putting a new element in the front of the list.
def myAppend1(xs: List[Any], y: Any): List[Any] = {
y :: xs
}
My problem is now the naming of my inputs in myAppend2...
def myAppend2: List[Any] => Any => List[Any] = {
/* how can i do this here, when no names y/xs are given?*/
}
To use the same style with 2 or more parameters, just treat the parameters as a tuple of two:
def myConcat: (List[Any], List[Any]) => List[Any] = {
case (Nil, Nil) => List()
case (xs,ys) => ...
}
Let's take the myAppend example:
def myAppend2: (List[Any], Any) => List[Any] = {
case (xs, y) => y :: xs
}
This has (more or less) the same signature as:
def myAppend1(xs: List[Any], y: Any): List[Any] = {
y :: xs
}
Usage:
scala> myAppend1(List(1,2,3), 4)
res3: List[Any] = List(4, 1, 2, 3)
scala> myAppend2(List(1,2,3), 4)
res4: List[Any] = List(4, 1, 2, 3)
If you had a higher-order function that wanted a function argument of (List[Any], Any) = List[Any], then both will work and are (for most practical purposes) equivalent.
Note that by defining it like
def myAppend3: List[Any] => Any => List[Any] = {
xs => y => y::xs
}
you will be creating a curried function, which in scala has a different signature
(from what you want):
myAppend3(List(1,2,3), 4) // won't compile
myAppend3(List(1,2,3))(4) // need to do this
def myAppend2: List[Any] => Any => List[Any] = { xs => y =>
y :: xs
}
with full form of function literal syntax:
def myAppend2: List[Any] => Any => List[Any] = {
(xs: List[Any]) => {
(y: Any) => {
y :: xs
}
}
}
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)
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 // :)