How to set the initial value Nil using /: (Not the foldRight) - scala

The code below doesn't compile because of the type mismatch, and I suppose this can be solved by explicitly giving the type parameter List[Int] to Nil but I couldn't figure it out how.
(there are some info about the foldRight method but I would like to use /: here)
val li = List.range(1, 10)
(Nil /: li)((a, b) => b :: a) // doesn't compile
(List(0): li)((a, b) => b :: a) // compiles
<pastie>:14: error: type mismatch;
found : List[Int]
required: scala.collection.immutable.Nil.type
(Nil /: li)((a, b) => b :: a)
^
Could anyone tell how to fix this?

How about using:
scala> val li = List.range(1, 10)
li: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> (List.empty[Int] /: li)((a, b) => b :: a)
res20: List[Int] = List(9, 8, 7, 6, 5, 4, 3, 2, 1)

Its because, when you provide Nil as Initial value, you are providing Nil.type as type parameter and hence you are getting error.
def /:[B](z: B)(op: (B, A) => B): B
If you see the /: method definition, it is a higher order function that take function op as parameter. If you look at the function type for op i.e. (B, A) => B, the return type is B. When you invoke /: as Nil /: li, the type parameter passed is Nil.type i.e. Nil /:[Nil.type] li. Hence, B is Nil.type.
Now, lets look at your function literal for parameter op:
(Nil /: li)((a, b) => b :: a)
Here, you are returning b::a in your function literal. If you look closely, the type of b is Int since li is List[Int] and a is List() (i.e. value of Nil). Hence, b :: a will return type of List[Int]. However, function type op expect B as return type which is Nil.type as explained above but you are returning List[Int] type. Hence you are getting error.
When you provide List(0) as initial value instead of Nil, you are passing List[Int] as type of B and in your function literal the returned type of b::a is List[Int], hence it worked.
(List(0): li)((a, b) => b :: a) ~~ (List(0)/[List[Int]] li)((a, b) => b :: a)
To avoid this issue, you need to explicitly provide type parameter in /: method.
(Nil /:[List[Int]] li)((a, b) => b :: a)

It's not lovely but...
scala> val li = List.range(1, 10)
li: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> ((Nil : List[Int]) /: li)((a, b) => b :: a)
res0: List[Int] = List(9, 8, 7, 6, 5, 4, 3, 2, 1)

Related

scala - swapping first 2 elements in a List

I'm trying to swap first 2 elements in a List using the below function.
def swap_list(a:List[Int]):List[Int]={
a match {
case x::y::Nil => List(y,x)
case List(x,y,rest # _*) => List(y,x)
case _ => a
}
}
swap_list(List(10,20,30))
This works. However, If I try to include the rest I'm getting a error like
case List(x,y,rest # _*) => List(y,x) +: rest
Error below
Error:(27, 50) type mismatch;
found : Seq[Any]
required: List[Int]
case List(x,y,rest # _*) => List(y,x) +: rest
when I'm specifying the function result type in the definition, why am I getting Seq[Any] in the error message?
I need to return List(20,10,30). How to resolve this?.
Apparently operators in scala List are confusing. You need to concat lists using ++,
def swap_list(a:List[Int]):List[Int]={
a match {
case x::y::Nil => List(y,x)
case List(x,y,rest # _*) => List(y,x) ++ rest
case _ => a
}
}
val newList = swap_list(List(10, 20, 30))
println(newList) //List(20, 10, 30)
Summary of List operators,
1) prepend on List using +: or ::
scala> 1000 +: List(1, 2, 3)
res1: List[Int] = List(1000, 1, 2, 3)
scala> 1000 :: List(1, 2, 3)
res4: List[Int] = List(1000, 1, 2, 3)
2) append on List using :+
scala> List(1, 2, 3) :+ 100
res2: List[Int] = List(1, 2, 3, 100)
3) concat Lists using ++, same as in haskell
scala> List(1, 2, 3) ++ List(4, 5, 6)
res3: List[Int] = List(1, 2, 3, 4, 5, 6)
Well, while prayagupd solution works, and clearly explains the problem (and should be the accepted answer IMHO).
I think is worth sharing a "better" solution to this problem, since concatenating lists is expensive, it is better to just prepend elements to them.
def swapList[T](l: List[T]): List[T] = l match {
case Nil => Nil
case x :: Nil => x :: Nil
case x :: y :: xs => y :: x :: xs
}
swapList(List(10,20,30)) // res0: List[Int] = List(20, 10, 30).
You need to ++ instead of +: as the latter is for single element.
The simplest implementation is this:
def swap_list(a: List[Int]): List[Int] =
a match {
case x :: y :: tail => y :: x :: tail
case _ => a
}

scala: how scala converts foldLeft as currying function

Could someone explain how currying happens in foldLeft for the below example:
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
>numbers: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val numberFunc = numbers.foldLeft(List[Int]())_
>numberFunc: ((List[Int], Int) => List[Int]) => List[Int]
My Understanding is:
(List[Int], Int) - (accumulator which in this case is empty List, each element of the numbers list)
=> List[Int] - which is the output numberFunc list.
=> List[Int] - what does this represent?
Thanks.
Step by step:
foldLeft on a List[A] has a signature foldLeft[B](b: B)(f: (B, A) => B): B
therefore, in general, for a list: List[A] and b: B, the curried expression list.foldLeft(b) _ would have type ((B, A) => B) => B
numbers has type List[Int], thus A is inferred to be Int
List[Int]() has type List[Int], thus B is inferred to be List[Int]
Substituting Int for A and List[Int] for B in ((B, A) => B) => B, you obtain (List[Int], Int) => List[Int]) => List[Int]. That's exactly what the compiler gives you.
In words:
(numberFunc : // `numberFunc` is a function that
( // given a function that
(List[Int], Int) // takes an accumulator and an int
=> // and produces
List[Int] // an updated list of ints
)
=> // produces
List[Int] // a list of ints
)

Getting a type error in a recursive flatten method implementation

I am trying to learn scala. Today I am attempting to write a simple recursive method that flattens a nested list. I know that there is a flatten function I could call but I am trying to do it from scratch.
I get a type mismatch error and I am trying to understand why. What type of variable is 'A'.
def flatten[A](lst:List[List[A]):List[A] = lst match{
case Nil=> Nil
case (h:List[A])::tail=> flatten(h)::flatten(tail)
case h :: tail=> flatten(tail)
}
flatten(h) is a compiler error because h is a List[A] but flatten is expecting a nested List[List[A]]. Try simply concatenating h with the result of flattening tail:
def flatten[A](lst: List[List[A]]): List[A] = lst match {
case Nil => Nil
case h :: tail => h ::: flatten(tail)
}
Examples:
scala> flatten(List(List("a", "b"), List("c", "d")))
res0: List[String] = List(a, b, c, d)
scala> flatten(List(List(1, 2), List(3, 4)))
res1: List[Int] = List(1, 2, 3, 4)

error: not found: value :::

I can create a list like so:
val value = List(1) ::: 2 :: List(3)
Now I am trying to decompose that list like so:
value match { case a ::: b :: c => (a, b, c) }
but I get error: not found: value :::.
Why I am getting this error. Why doesn't this pattern work, and what should I use instead?
Suppose you have
val xs = List(1, 2, 3, 4)
and suppose there is an extractor object that could extract a collection prefix. What should be matched for
case a ::: b :: c => (a, b, c)
Is it (choose all that apply)
(List(1, 2, 3), 4, Nil)
(List(1, 2), 3, List(4))
(List(1), 2 , List(3, 4))
(Nil, 1, List(2, 3, 4))
Because there is more than one way of matching the pattern, the above extractor cannot exist. Instead you could use the following.
value match { case a :: b :: c => (List(a), b, c) }

Why different behaviors for list concatenation?

What is the difference between a ::: b and a.:::(b) ?
scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)
scala> val b = List(5)
b: List[Int] = List(5)
scala> a.:::(b)
res6: List[Int] = List(5, 1, 2, 3, 4)
scala> a ::: b
res7: List[Int] = List(1, 2, 3, 4, 5)
All functions in Scala which end with a : are right-associative and, thus, the expression a ::: b evaluates to b.:::(a).
When you use infix notation, methods (or operators) that end with : are right associative - in other words, the method is called on the object to its right, and the object to its left is passed as an argument.
So 1 :: Nil is the same as Nil.::(1). Just as a ::: b is the same as b.:::(a).
Because when you type
a ::: b
the last ':' makes the function right associative.
Thus, you are calling ::: on b not a:
b.:::(a)