for comprehension in scala for implementing flatMap - scala

Prof. Odersky in Coursera course has implemented flatMap using for loops as following:
def flatMap[T, U](xs: List[T], f: T => Iterable[U]) = for (x <- xs; y <- f(x)) yield y
And here's some application on the two functions (result as expected):
val xs = List(1, 2, 3, 4, 5)
flatMap[Int, Int](xs, x=> List(x /2))
However, When I try implement the flatMap as:
for (x <- xs) yield f(x)
It does not return the correct answer, it returns a List of Lists (it should return one big list contains all elements of the inner lists)
My question is, What is the different that make flatMap works as expected; between both:
for (x <- xs; y <- f(x)) yield y
//And
for (x <- xs) yield f(x)
And Why for (x <- xs; y <- x * x) yield y not compiling?

Your second version doesn't involve a call to flatMap at all. You can use reify to de-sugar the for comprehension and see:
scala> import reflect.runtime.universe._
import reflect.runtime.universe._
scala> val f: Int => Iterable[Int] = null
f: Int => Iterable[Int] = null
scala> val xs = List(1, 2, 3, 4, 5)
xs: List[Int] = List(1, 2, 3, 4, 5)
scala> reify { for (x <- xs; y <- f(x)) yield y }
res0: reflect.runtime.universe.Expr[List[Int]] = Expr[List[Int]]($read.xs.flatMap(((x) => $read.f.apply(x).map(((y) => y))(Iterable.canBuildFrom)))(List.canBuildFrom))
scala> reify { for (x <- xs) yield f(x) }
res1: reflect.runtime.universe.Expr[List[Iterable[Int]]] = Expr[List[scala.Iterable[Int]]]($read.xs.map(((x) => $read.f.apply(x)))(List.canBuildFrom))
the first can be simplified to:
xs.flatMap(x => f(x).map(identity))
which is equivalent to:
xs.flatMap(f)
and the second can be simplified to:
xs.map(f)

Related

Sort elements as part of concatenating elements of 2 Lists

Here is a function I wrote for concatenating elements of a List using an accumulator with tail recursion :
val l1 = List(1, 2, 3) //> l1 : List[Int] = List(1, 2, 3)
val l2 = List(1, 2, 3) //> l2 : List[Int] = List(1, 2, 3)
def func(l1: List[Int], l2: List[Int], acc: List[Int]): List[Int] = {
(l1, l2) match {
case (Nil, Nil) => acc.reverse
case (h1 :: t1, h2 :: t2) => {
func(t1, t2, h1 :: h2 :: acc)
}
}
} //> func: (l1: List[Int], l2: List[Int], acc: List[Int])List[Int]
func(l1, l2, List()) //> res0: List[Int] = List(1, 1, 2, 2, 3, 3)
This is my understanding of the call order
func( 1 :: 1 :: () )
func( 2 :: 2 :: 1 :: 1 : () )
func( 3 :: 3 :: 2 :: 2 :: 1 :: 1 : () )
So the call order is the reason why I must call reverse on base call of acc so that the List is ordered in same ordering initial List elements. To try to minimize the steps required to concatenate the lists I have tried to add the elements like this :
func(t1, t2, acc :: h1 :: h2)
instead of
func(t1, t2, h1 :: h2 :: acc)
but receive compile time error :
value :: is not a member of Int
So it seems I cannot prepend these elements to this List ?
When you write x :: y, y must be a list and x the element you want to prepend.
You can use acc :+ h1 :+ h2 to append h1 and h2 to acc, but note that adding elements to the end of the list is a relatively expensive operation (linear with the length of the list).

2 FoldLefts are Equal

Why do both of the following foldLeft's result in the same output?
#1
scala> List(1,2,3).foldLeft(List[Int]())( (acc, el) => acc :+ el)
res114: List[Int] = List(1, 2, 3)
And, now using _ :+ _ as the (B, A) => B argument.
#2
scala> List(1,2,3).foldLeft(List[Int]())(_ :+ _)
res115: List[Int] = List(1, 2, 3)
In particular, the lack of explicitly appending to the accumulator in the second case confuses me.
_ :+ _ is simply a shorthand for (x1, x2) => x1 :+ x2, just as list.map(_.toString) is simply list.map(x => x.toString).
See more on the placeholder syntax here.

Why does Option require explicit toList inside for loops?

Using a for loop with a simple Option works:
scala> for (lst <- Some(List(1,2,3))) yield lst
res68: Option[List[Int]] = Some(List(1, 2, 3))
But looping over the contents of the Option does not:
scala> for (lst <- Some(List(1,2,3)); x <- lst) yield x
<console>:8: error: type mismatch;
found : List[Int]
required: Option[?]
for (lst <- Some(List(1,2,3)); x <- lst) yield x
^
...unless the Option is explicitly converted to a List:
scala> for (lst <- Some(List(1,2,3)).toList; x <- lst) yield x
res66: List[Int] = List(1, 2, 3)
Why is the explicit list conversion needed? Is this the idiomatic solution?
for (lst <- Some(List(1,2,3)); x <- lst) yield x
is translated to
Some(List(1,2,3)).flatMap(lst => lst.map(x => x))
The flatMap method on Option expects a function that returns an Option, but you're passing a function that returns a List and there is no implicit conversion from List to Option.
Now if you convert the Option to a list first, the flatMap method of List will be called instead, which expects a function returning a List, which is what you are passing to it.
In this particular case, I think the most idiomatic solution is
Some(List(1,2,3)).flatten.toList

scala: yield pairwise combinations of two loops

I would like to create a collection with tuples containing all pairwise combinations of two lists. Something like:
for ( x <- xs )
for ( y <- ys )
yield (x,y)
In Python this would work, in Scala apparently for yields only for the last loop (so this evaluates to Unit)
What is the cleanest way to implement it in Scala?
You were almost there:
scala> val xs = List (1,2,3)
xs: List[Int] = List(1, 2, 3)
scala> val ys = List (4,5,6)
ys: List[Int] = List(4, 5, 6)
scala> for (x <- xs; y <- ys) yield (x,y)
res3: List[(Int, Int)] = List((1,4), (1,5), (1,6), (2,4), (2,5), (2,6), (3,4), (3,5), (3,6))
A little bit more explicit according to Nicolas:
In Scala you can use multiple generators in a single for-comprehension.
val xs = List(1,2,3)
val ys = List(4,5)
for {
x <- xs
y <- ys
} yield (x,y)
res0: List[(Int, Int)] = List((1,4), (1,5), (2,4), (2,5), (3,4), (3,5))
You can even evaluate in the comprehension.
for {
x <- xs
y <- ys
if (x + y == 6)
} yield (x,y)
res1: List[(Int, Int)] = List((1,5), (2,4))
Or make an assignment.
for {
x <- xs
y <- ys
val z = x + y
} yield (x,y,z)
res2: List[(Int,Int,Int)] = List((1,4,5), (1,5,6), (2,4,6), (2,5,7), (3,4,7), (3,5,8))

Scala permutation of Factorials

How can I find the n! permutations of certain letters on Scala?
Scala 2.9 RC1:
scala> "abc".permutations.toList
res58: List[String] = List(abc, acb, bac, bca, cab, cba)
scala> def permutations[T](xs: List[T]): List[List[T]] = xs match {
| case Nil => List(Nil)
| case _ => for(x <- xs;ys <- permutations(xs diff List(x))) yield x::ys
| }
permutations: [T](xs: List[T])List[List[T]]
scala> permutations("abc".toList) foreach println
List(a, b, c)
List(a, c, b)
List(b, a, c)
List(b, c, a)
List(c, a, b)
List(c, b, a)