Extractors in for vs extractors in assignment - scala

I have this doubt with extractors.
If I can do this:
val a :: b = List(1, 2, 3)
why I cannot do this:
val c = for ( a :: b <- List(1, 2, 3) } yield a

The translation of a for-yield expression in Scala (without using guards) is the map function. If you try and use map instead, it'll seem a little clear as to the quirk with the code:
List(1, 2, 3).map((x: Int) => ???)
When you map over a List[+A], you project each value, one at a time. You don't have the entire list at your disposable inside the higher order function.
On the contrary, when using pattern matching on the list itself, the compiler will translate your first example into (after some cleanup):
def main(args: Array[String]): Unit = {
private[this] val x$1: (Int, List[Int]) = List(1, 2, 3) match {
case (head: Int, tl: List[Int])scala.collection.immutable.::[Int]((a # _), (b # _)) => Tuple2[Int, List[Int]](a, b)
};
val a: Int = x$1._1;
val b: List[Int] = x$1._2;
()
Which is a pattern match on the List[Int], matching the case of a head and tail. It's simply syntatic sugar for regular pattern matching, same as for-yield is syntatic sugar for a map. They simply do different things.

After Yuval answer, I've understood why it doesn't work.
Equivalent syntax if interested in 1st value:
val first = for (a <- List(1, 2, 3).headOption) yield a

Related

get tuple as arguments from zipWithIndex in scala

I can pass and use values from tuple like this in for
for ((v,i) <- in.zipWithIndex) {
println(s"$i is $v")
}
But in foreach it's used only like
in.zipWithIndex.foreach {
case(v, i) => println(s"$i is $v")
}
How can I make something like function
val f: (Int,Int) => Unit = (v,i) => {println(s"$i is $v")}
and then pass it into .foreach(). AND (it's important just for me) without using pattern matching case.
P.S. .tupled works only for methods (def). not for function defined as val
The argument to your function needs to be a Tuple.
scala> val l = List(1,2,3).zipWithIndex
l: List[(Int, Int)] = List((1,0), (2,1), (3,2))
scala> val f = (t: (Int, Int)) => println(s"${t._1} ${t._2}")
f: ((Int, Int)) => Unit = <function1>
scala> l.foreach(f)
1 0
2 1
3 2
Personally I hate the ._1, ._n syntax and prefer to pattern match on tuples.
BTW your for comprehension example is also using pattern matching...

Scala: Append element to list using cons method

While reading Programming in Scala, 3rd Edition, it says
Class List does offer an "append" operation—it's written :+ But this
operation is rarely used, because the time it takes to append to a
list grows linearly with the size of the list, whereas prepending with
:: takes constant time.
If you want to build a list efficiently by appending elements, you can
prepend them and when you're done call reverse.
I am trying to understand, what is Scala idiomatic way of doing this? Is calling List.reverse twice acceptable and efficient vs ListBuffer (since ListBuffer is mutable)?
// Scala Recommended way - but reverse twice?
val alist = List("A", "B")
// cons is O(1)
// This will print (A, B, C)
println(("C" :: alist.reverse).reverse)
// Scala also Recommended: Use ListBuffer
val alb = ListBuffer("A", "B")
alb.append("C")
val clist2 = alb.toList
// This will print (A, B, C)
println(clist2)
// DO NOT do this, its O(n)
val clist3 = alist :+ "C"
// This will print (A, B, C)
println(clist3)
P.S: I'm not referring to code optimization here. Which one is generally recommended and will not received WTH expression.
Another implementation could be Difference Lists (also Prolog-based explanation available - Understanding Difference Lists).
That's how I implement DList in Scala:
abstract class DiffList[A](calculate: List[A] => List[A]) {
def prepend(s: List[A]): DiffList[A]
def append(s: List[A]): DiffList[A]
def result: List[A]
}
final class DiffListImpl[A](listFunc: List[A] => List[A])
extends DiffList[A](listFunc) {
def prepend(s: List[A]): DiffListImpl[A] =
new DiffListImpl[A](listFunc andThen (s ++ _))
def append(s: List[A]): DiffListImpl[A] =
new DiffListImpl[A](listFunc andThen (_ ++ s))
def result: List[A] = listFunc(Nil)
}
And use it:
val l1 = List(1, 2)
val l2 = List(6, 7)
val l3 = List(3, 4, 5)
val dl = new DiffListImpl[Int](Nil)
val result = dl.prepend(l1).prepend(l2).append(l3).result
Result: List(6, 7, 1, 2, 3, 4, 5)

What does dot colon colon (.::) mean in Scala?

Below code adds element to res list. My question is how scala internally translates .:: symbols?
Code snippet:
var res = List[(Int, Int)]()
res .::= (1, 2)
res .::= (3, 4)
res
output:
res56: List[(Int, Int)] = List((1,2),(3,4))
There are a few things going on in that snippet. Before diving into it let's talk about the difference between var and val. Namely, that a variable declared using the val keyword is immutable, i.e. its value cannot be changed:
scala> val x = 1
x: Int = 1
scala> x = 2
<console>:13: error: reassignment to val
x = 2
^
On the other hand, var keyword is used to declare a mutable variable, i.e. its value can be changed:
scala> var y = "bar"
y: String = bar
scala> y = "foo"
y: String = foo
What if we wanted to compute a new value of y by appending to its current value?
scala> y = y + "bar"
y: String = foobar
Sure that works, but it turns out there's a shorthand for doing that:
scala> y += "bar"
scala> y
res10: String = foobar
By the way, in Scala, + is just a name of a method, so y + "bar" is the same as y.+("bar"). Ugly, but valid. Similarly, y.+=("bar") is also a valid replacement of y += "bar".
Great, let's remember that for later. Next, as others have already pointed out, :: is just a method for prepending elements to a list (from Java it can be invoked as someList.$colon$colon(someElement)). The important thing to note is that the :: method returns a new list:
scala> var letters = List("b", "c")
letters: List[String] = List(b, c)
scala> letters.::("a")
res1: List[String] = List(a, b, c)
scala> letters
res2: List[String] = List(b, c)
What if we wanted to set letters to the list which contains the letter "a"?
scala> letters = letters.::("a")
letters: List[String] = List(a, b, c)
Notice that this looks awfully similar to the previous example with strings. Does the shorthand work here too?
scala> letters ::= "a"
scala> letters
res6: List[String] = List(a, b, c)
Yes, it does. letters.::=("a") works as well.
Now, let's break down the original snippet:
Step 1
Create a variable named res and assign it an empty, immutable list. This empty list is intended to contain pairs of integers (Int, Int).
var res = List[(Int, Int)]()
Here's an alternative way of doing the same thing:
var res = List.empty[(Int, Int)]
(which, in my opinion, is a bit easier to read)
Step 2
Prepend a new element (1, 2) to list res and reassign the resulting list back to res.
res .::= (1, 2)
Or, without spaces:
res.::=(1, 2)
Looks familiar? We could've also written it out as:
res = res.::(1, 2)
Step 3
Prepend (3, 4) following the logic in step 2
Step 4
Print out current value of res, which should be: List((3,4), (1,2))
Side note
Confusingly, the compiler is lenient enough to allow us to specify only a single set of parentheses when calling ::, though we really ought to have two sets: one for the method invocation and another one for indicating a pair of integers. So, there happens to be yet another valid
way of writing the same thing res.::=((1, 2)).
More generally:
scala> def first(p:(Int, Int)):Int = p._1
first: (p: (Int, Int))Int
scala> first(6,7)
res0: Int = 6
scala> first((6,7))
res1: Int = 6
scala> first(6 -> 7) //lolz! another one using implicit conversion
res2: Int = 6
The implicit conversion is ever-present since it's defined in Predef.ArrowAssoc
mind = blown
I also recommend taking a look at What are all the instances of syntactic sugar in Scala?
Just method invocation
. (dot) used for method invocation on instance of a class.
:: is a method defined on the List
:: is a method declared in the List class which creates instance of scala.collection.immutable.:: class.
Notice that :: is a method in List class and also :: is a final class in the package scala.collection.immutable
Scala Standard library
Here is the implementation of the :: function in the List class
#SerialVersionUID(-6084104484083858598L) // value computed by serialver for 2.11.2, annotation added in 2.11.4
sealed abstract class List[+A] extends AbstractSeq[A]
with LinearSeq[A]
with Product
with GenericTraversableTemplate[A, List]
with LinearSeqOptimized[A, List[A]]
with Serializable {
override def companion: GenericCompanion[List] = List
import scala.collection.{Iterable, Traversable, Seq, IndexedSeq}
def isEmpty: Boolean
def head: A
def tail: List[A]
// New methods in List
/** Adds an element at the beginning of this list.
* #param x the element to prepend.
* #return a list which contains `x` as first element and
* which continues with this list.
*
* #usecase def ::(x: A): List[A]
* #inheritdoc
*
* Example:
* {{{1 :: List(2, 3) = List(2, 3).::(1) = List(1, 2, 3)}}}
*/
def ::[B >: A] (x: B): List[B] =
new scala.collection.immutable.::(x, this)
.....
}
Here is how scala.collection.immutable.:: is defined.
#SerialVersionUID(509929039250432923L) // value computed by serialver for 2.11.2, annotation added in 2.11.4
final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] {
override def tail : List[B] = tl
override def isEmpty: Boolean = false
}
The output of
var res = List[(Int, Int)]()
res .::= (1, 2)
res .::= (3, 4)
res
should be
List((3,4), (1,2))
because the colon colon method :: adds an element to the front of a list.
The dot . is totally optional in this case - this is just for specifically stating, that you are calling method :: on the list object res. This means that your code is equivalent to this one:
var res = List[(Int, Int)]()
res ::= (1, 2)
res ::= (3, 4)
res
Internally colon colon :: is implemented like this:
/** Adds an element at the beginning of this list.
* #param x the element to prepend.
* #return a list which contains `x` as first element and
* which continues with this list.
*
* #usecase def ::(x: A): List[A]
* #inheritdoc
*
* Example:
* {{{1 :: List(2, 3) = List(2, 3).::(1) = List(1, 2, 3)}}}
*/
def ::[B >: A] (x: B): List[B] =
new scala.collection.immutable.::(x, this)
A new list is created (because of the immutability) with the argument as a first element and the current list content as the rest

Higher order operations with flattened tuples in scala

I've recently come across a problem. I'm trying to flatten "tail-nested" tuples in a compiler-friendly way, and I've come up with the code below:
implicit def FS[T](x: T): List[T] = List(x)
implicit def flatten[T,V](x: (T,V))(implicit ft: T=>List[T], fv: V=>List[T]) =
ft(x._1) ++ fv(x._2)
This above code works well for flattening tuples I am calling "tail-nested" like the ones below.
flatten((1,2)) -> List(1,2)
flatten((1,(2,3))) -> List(1,2,3)
flatten((1,(2,(3,4)))) -> List(1,2,3,4)
However, I seek to make my solution more robust. Consider a case where I have a list of these higher-kinded "tail-nested" tuples.
val l = List( (1,2), (1,(2,3)), (1,(2,(3,4))) )
The inferred type signature of this would be List[(Int, Any)] and this poses a problem for an operation such as map, which would fail with:
error: No implicit view available from Any => List[Int]
This error makes sense to me because of the nature of my recursive implicit chain in the flatten function. However, I was wondering: is there any way I can make my method of flattening the tuples more robust so that higher order functions such as map mesh well with it?
EDIT:
As Bask.ws pointed out, the Product trait offers potential for a nice solution. The below code illustrates this:
def flatten(p: Product): List[_] = p.productIterator.toList.flatMap {x => x match {
case pr: Product => flatten(pr)
case _ => List(x)
}}
The result type of this new flatten call is always List[Any]. My problem would be solved if there was a way to have the compiler tighten this bound a bit. In parallel to my original question, does anyone know if it is possible to accomplish this?
UPD Compile-time fail solution added
I have one solution that may suit you. Types of your first 3 examples are resolved in compile time: Int, Tuple2[Int, Int], Tuple2[Int, Tuple2[Int, Int]]. For you example with the list you have heterogeneous list with actual type List[(Int, Any)] and you have to resolve the second type in runtime or it maybe can be done by macro. So you may want to actually write implicit def flatten[T](x: (T,Any)) as your error advises you
Here is the fast solution. It gives a couple of warnings, but it works nicely:
implicit def FS[T](x: T): List[T] = List(x)
implicit def FP[T](x: Product): List[T] = {
val res = (0 until x.productArity).map(i => x.productElement(i) match {
case p: Product => FP[T](p)
case e: T => FS(e)
case _ => sys.error("incorrect element")
})
res.toList.flatten
}
implicit def flatten[T](x: (T,Any))(implicit ft: T=>List[T], fp: Product =>List[T]) =
ft(x._1) ++ (x._2 match {
case p: Product => fp(p)
case t: T => ft(t)
})
val l = List( (1,2), (1,(2,3)), (1,(2,(3,4))) )
scala> l.map(_.flatten)
res0: List[List[Int]] = List(List(1, 2), List(1, 2, 3), List(1, 2, 3, 4))
UPD
I have researched problem a little bit more, and I have found simple solution to make homogeneus list, which can fail at compile time. It is fully typed without Any and match and looks like compiler now correctly resolves nested implicits
case class InfiniteTuple[T](head: T, tail: Option[InfiniteTuple[T]] = None) {
def flatten: List[T] = head +: tail.map(_.flatten).getOrElse(Nil)
}
implicit def toInfiniteTuple[T](x: T): InfiniteTuple[T] = InfiniteTuple(x)
implicit def toInfiniteTuple2[T, V](x: (T, V))(implicit ft: V => InfiniteTuple[T]): InfiniteTuple[T] =
InfiniteTuple(x._1, Some(ft(x._2)))
def l: List[InfiniteTuple[Int]] = List( (1,2), (1,(2,3)), (1,(2,(3,4)))) //OK
def c: List[InfiniteTuple[Int]] = List( (1,2), (1,(2,3)), (1,(2,(3,"44"))))
//Compile-time error
//<console>:11: error: No implicit view available from (Int, (Int, java.lang.String)) => InfiniteTuple[Int]
Then you can implement any flatten you want. For example, one above:
scala> l.map(_.flatten)
res0: List[List[Int]] = List(List(1, 2), List(1, 2, 3), List(1, 2, 3, 4))

Function type definition and type erasure in Scala

Given the following type and instance:
type operation = (Int, Int) => Int
def add: operation = _ + _
If I try to match an operation in a case statement, Scala complains about unchecked typing due to type erasure:
for (a <- elements) a match {
case o: operation => // do stuff
}
Is there a way to achieve this kind of function-based typing while being erasure-friendly in case statements?
Note, this is similar to this thread.
One easy way to deal with type erasure is to create an unparamaterized class. It's not perfect, but it works. Make it a case class that extends Function2 and it's not even too clunky to use either directly or in a pattern match
scala> case class Operation(f : (Int,Int) => Int) extends ((Int,Int) => Int) {
| def apply(x : Int, y : Int) = f(x,y)
| }
defined class Operation
scala> def add = Operation(_ + _)
add: Operation
scala> val y = add(7,3)
y: Int = 10
scala> val elements = List(1, add, 2)
elements: List[Any] = List(1, <function2>, 2)
scala> for (a <- elements) yield a match {
| case Operation(f) => f(1,2)
| case x : Int => x
| }
res0: List[Int] = List(1, 3, 2)
The limitation is that you have to have "boxed" the operation before you lose its type, not after. Also, you end up with one class per concrete function type.
Another, arguably much better, solution is to not lose the type information. Use an Either to retain the static type info.
scala> val elements : List[Either[Int, (Int, Int) => Int]] = List(Left(1), Right(_ + _), Left(2))
elements: List[Either[Int,(Int, Int) => Int]] = List(Left(1), Right(<function2>), Left(2))
scala> for (a <- elements) yield a match {
| case Right(f) => f(1,2)
| case Left(x) => x
| }
res1: List[Int] = List(1, 3, 2)
The limitation here is that it gets clunky if your List can have more than 2 types. But it effectively avoids forcing Scala to be a dynamically typed language, unlike the previous solution.
If you can wrap a into an Option, then this will work:
scala> val a:Option[Any] = Some(add)
a: Option[Any] = Some(<function2>)
scala> a match { case o:Some[operation] => println ("found"); case _ => }
found