Behavior of flatMap when applied to List[Option[T]] - scala

Let's take a look at this code:
scala> val a = List(Some(4), None)
a: List[Option[Int]] = List(Some(4), None)
scala> a.flatMap( e=> e)
List[Int] = List(4)
Why would applying flatMap with the function { e => e } on a List[Option[T]] returns a List[T] with the None elements removed?
Specifically, what is the conceptual reasoning behind it -- is it based on some existing theory in functional programming? Is this behavior common in other functional languages?
This, while indeed useful, does feel a bit magical and arbitrary at the same time.
EDIT:
Thank you for your feedbacks and answer.
I have rewritten my question to put more emphasis on the conceptual nature of the question. Rather than the Scala specific implementation details, I'm more interested in knowing the formal concepts behind it.

Let's first look at the Scaladoc for Option's companion object. There we see an implicit conversion:
implicit def option2Iterable[A](xo: Option[A]): Iterable[A]
This means that any option can be implicitly converted to an Iterable, resulting in a collection with zero or one elements. If you have an Option[A] where you need an Iterable[A], the compiler will add the conversion for you.
In your example:
val a = List(Some(4), None)
a.flatMap(e => e)
We are calling List.flatMap, which takes a function A => GenTraversableOnce[B]. In this case, A is Option[Int] and B will be inferred as Int, because through the magic of implicit conversion, e when returned in that function will be converted from an Option[Int] to an Iterable[Int] (which is a subtype of GenTraversableOnce).
At this point, we've essentially done the following:
List(List(1), Nil).flatMap(e => e)
Or, to make our implicit explicit:
List(Option(1), None).flatMap(e => e.toList)
flatMap then works on Option as it does for any linear collection in Scala: take a function of A => List[B] (again, simplifying) and produce a flattened collection of List[B], un-nesting the nested collections in the process.

I assume you mean the support for mapping and filtering at the same time with flatMap:
scala> List(1, 2).flatMap {
| case i if i % 2 == 0 => Some(i)
| case i => None
| }
res0: List[Int] = List(2)
This works because Option's companion object includes an implicit conversion from Option[A] to Iterable[A], which is a GenTraversableOnce[A], which is what flatMap expects as the return type for its argument function.
It's a convenient idiom, but it doesn't really exist in other functional languages (at least the ones I'm familiar with), since it relies on Scala's weird mix of subtyping, implicit conversions, etc. Haskell for example provides similar functionality through mapMaybe for lists, though.

A short answer to your question is: the flatMap method of the List type is defined to work with a more general function type, not just a function that only produces a List[B] result type.
The general result type is IterableOnce[B], as shown in the faltMap method signature: final def flatMap[B](f: (A) => IterableOnce[B]): List[B]. The flatMap implementation is rather simple in that it applies the f function to each element and iterates over the result in a nested while loop. All results from the nested loop are added to a result of type List[B].
Therefore the flatMap works with any function that produces an IterableOnce[B] result from each list element. The IterableOnce is a trait that defines a minimal interface that is inherited by all iterable classes, including all collection types (Set, Map and etc.) and the Option class.
The Option class implementation returns collection.Iterator.empty for None and collection.Iterator.single(x) for Some(x). Therefore the flatMap method skips None element.
The question uses the identity function. It is better to use flatten method when the purpose is to flat iterable elements.
scala> val a = List(Some(4), None)
a: List[Option[Int]] = List(Some(4), None)
scala> a.flatten
res0: List[Int] = List(4)

Related

Why does Scala Option.tapEach return Iterable, not Option?

The scaladoc of Option.tapEach states "returns: The same logical collection as this" just as expected for an operation named after tap & foreach. However, it does not return an Option but an Iterable backed by a List:
scala> import scala.util.chaining._
scala> Option(5).tap(_.foreach(_ => ()))
val res0: Option[Int] = Some(5)
scala> Option(5).tapEach(_ => ())
val res1: Iterable[Int] = List(5)
(Verified for Scala 2.13.5 and 3.0.0-RC1)
Is there a good reason to return Iterable instead of Option, or has this just been overlooked (and might be fixed eventually)?
It seems whether Option is considered a full collection is a bit of a can of worms as indicated by the discussion at Make Option extend IterableOnce #8038. I think the relevant comment is
So it can definitely be a IterableOnce because you can get an iterator
of zero to one elements. But it can't be a Iterable because you you
can't implement fromSpecific(c: IterableOnce[A]): K without throwing
away data.
however tapEach uses fromSpecific in its definition
override def tapEach[U](f: A => U): C = fromSpecific(new View.Map(this, { (a: A) => f(a); a })
So key to remember is Option since Scala 2.13 is an IterableOnce but not a full Iterable. IterableOnce is smaller compared to Iterable, so if a capability is needed from Iterable it is provided via implicit conversion as per docs
This member is added by an implicit conversion from Option[A]
to Iterable[A] performed by method option2Iterable in scala.Option.
that is
option2iterable(Option(5)).tapEach(_ => ())
hence the Iterable[Int] return type.
Also consider the following note
Many of the methods in here are duplicative with those in the
Traversable hierarchy, but they are duplicated for a reason: the
implicit conversion tends to leave one with an Iterable in situations
where one could have retained an Option.
so contributors would have to bake a specialised version in Option to preserve the type, or perhaps we could provide our own specialised extension implementation, something like
scala> implicit class OptionTapOps[A](v: Option[A]) {
| def tapEach[B](f: A => B): Option[A] = { v.foreach(f); v }
| }
class OptionTapOps
scala> Option(5).tapEach(_ => ())
val res11: Option[Int] = Some(5)

Partial Function Application in Scala

I'm learning Functional Programming, by following the book Functional Programming in Scala by Paul Chiusano and Rúnar Bjarnason. I'm specifically on chapter 3, where I am implementing some companion functions to a class representing a singly-linked list, that the authors provided.
package fpinscala.datastructures
sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]
object List {
def sum(ints: List[Int]): Int = ints match {
case Nil => 0
case Cons(x,xs) => x + sum(xs)
}
def product(ds: List[Double]): Double = ds match {
case Nil => 1.0
case Cons(0.0, _) => 0.0
case Cons(x,xs) => x * product(xs)
}
def apply[A](as: A*): List[A] =
if (as.isEmpty) Nil
else Cons(as.head, apply(as.tail: _*))
def tail[A](ls: List[A]): List[A] = ls match {
case Nil => Nil
case Cons(x,xs) => xs
}
... (more functions)
}
The functions I am implementing go inside the object List, being companion functions.
While implementing dropWhile, whose method signature is:
def dropWhile[A](l: List[A])(f: A => Boolean): List[A]
I came across some questions regarding partial function application:
In the book, the authors say that the predicate, f, is passed in a separate argument group to help the scala compiler with type inference because if we do this, Scala can determine the type of f without any annotation, based on what it knows about the type of the List , which makes the function more convenient to use.
So, if we passed f in the same argument group, scala would force the call to become something like this: val total = List.dropWhile(example, (x:Int) => 6%x==0 ) where we define the type of x explicitly and we would "lose" the possibility of partial function application, am I right?
However, why is partial function application useful in this case? Only to allow for type inference? Does it make sense to "partially apply" a function like dropWhile without applying the predicate f to it? Because it seems to me that the computation becomes "halted" before being useful if we don't apply f...
So... why is partial function application useful? And is this how it's always done or is it only something specific to Scala? I know Haskell has something called "complete inference" but I don't know exactly its implications...
Thanks in advance
There's a couple of questions scattered in there, so I'll try to answer them separately.
About the type inference, yes, separating the parameter lists helps the compile in inferring the type of f.
This is because Scala has linear local type inference (from left to right) and it uses the first parameter list to infer A (from the type of l). Then it can use this information to infer the type of f.
Given for example
dropWhile(List(1, 2, 3))(x => x < 3)
the compiler will perform this steps:
first parameter list
A is unknown.
a List[A] is expected
a List[Int] is provided (this is inferred by the type of the elements in the List)
=> A is an Int
second parameter list
we know A = Int
so we're expecting a function Int => Boolean as f
If you don't separate the two parameter lists, the compiler can't "stop" and decide the type of A before type-checking f. f would be part of the "conversation" while deciding the type of A so you would need to annotate it.
This is something Haskell can do better, since it uses a different type system (Hindley-Milner) that can also use information deriving from the context in which the function is applied. This is why it's also called "complete" or "universal".
Why does Scala doesn't feature an Hindley-Milner type system? Long story short, because Scala also supports sub-typing, which hardly co-exists with such a powerful type system. More on the subject:
Why is Scala's type inference not as powerful as Haskell's?
http://www.codecommit.com/blog/scala/what-is-hindley-milner-and-why-is-it-cool
http://www.scala-lang.org/old/node/4654
About partial application, the question "why is it useful" is definitely too broad to be answered here. However, in the specific dropWhile case, suppose you have a list of functions representing different "drop" conditions. Using a partially applied function you could do:
val list = List(1, 2, 3)
val conditions: List[Int => Boolean] = List(_ < 1, _ < 2, _ < 3)
conditions.map(dropWhile(list)) // List(List(1, 2, 3), List(2, 3), List(3))
Obviously, with a non-curried function (i.e. a single parameter list) you could have achieved the same with
val list = List(1, 2, 3)
val conditions: List[Int => Boolean] = List(_ < 1, _ < 2, _ < 3)
conditions.map(cond => dropWhile(list, cond))
but currying allows for more flexibility while composing functions.
More on the subject:
https://softwareengineering.stackexchange.com/questions/185585/what-is-the-advantage-of-currying
What's the difference between multiple parameters lists and multiple parameters per list in Scala?

Why can't I flatMap a Try?

Given
val strings = Set("Hi", "there", "friend")
def numberOfCharsDiv2(s: String) = scala.util.Try {
if (s.length % 2 == 0) s.length / 2 else throw new RuntimeException("grr")
}
Why can't I flatMap away the Try resulting from the method call? i.e.
strings.flatMap(numberOfCharsDiv2)
<console>:10: error: type mismatch;
found : scala.util.Try[Int]
required: scala.collection.GenTraversableOnce[?]
strings.flatMap(numberOfCharsDiv2)
or
for {
s <- strings
n <- numberOfCharsDiv2(s)
} yield n
<console>:12: error: type mismatch;
found : scala.util.Try[Int]
required: scala.collection.GenTraversableOnce[?]
n <- numberOfCharsDiv2(s)
However if I use Option instead of Try there's no problem.
def numberOfCharsDiv2(s: String) = if (s.length % 2 == 0)
Some(s.length / 2) else None
strings.flatMap(numberOfCharsDiv2) # => Set(1, 3)
What's the rationale behind not allowing flatMap on Try?
Let's look at the signature of flatMap.
def flatMap[B](f: (A) => GenTraversableOnce[B]): Set[B]
Your numberOfCharsDiv2 is seen as String => Try[Int]. Try is not a subclass of GenTraversableOnce and that is why you get the error. You don't strictly need a function that gives a Set only because you use flatMap on a Set. The function basically has to return any kind of collection.
So why does it work with Option? Option is also not a subclass of GenTraversableOnce, but there exists an implicit conversion inside the Option companion object, that transforms it into a List.
implicit def option2Iterable[A](xo: Option[A]): Iterable[A] = xo.toList
Then one question remains. Why not have an implicit conversion for Try as well? Because you will probably not get what you want.
flatMap can be seen as a map followed by a flatten.
Imagine you have a List[Option[Int]] like List(Some(1), None, Some(2)). Then flatten will give you List(1,2) of type List[Int].
Now look at an example with Try. List(Success(1), Failure(exception), Success(2)) of type List[Try[Int]].
How will flatten work with the failure now?
Should it disappear like None? Then why not work directly with Option?
Should it be included in the result? Then it would be List(1, exception, 2). The problem here is that the type is List[Any], because you have to find a common super class for Int and Throwable. You lose the type.
These should be reasons why there isn't an implicit conversion. Of course you are free to define one yourself, if you accept the above consequences.
The problem is that in your example, you're not flatmapping over Try. The flatmap you are doing is over Set.
Flatmap over Set takes a Set[A], and a function from A to Set[B]. As Kigyo points out in his comment below this isn't the actual type signature of flatmap on Set in Scala, but the general form of flat map is:
M[A] => (A => M[B]) => M[B]
That is, it takes some higher-kinded type, along with a function that operates on elements of the type in that higher-kinded type, and it gives you back the same higher-kinded type with the mapped elements.
In your case, this means that for each element of your Set, flatmap expects a call to a function that takes a String, and returns a Set of some type B which could be String (or could be anything else).
Your function
numberOfCharsDiv2(s: String)
correctly takes a String, but incorrectly returns a Try, rather then another Set as flatmap requires.
Your code would work if you used 'map', as that allows you to take some structure - in this case Set and run a function over each element transforming it from an A to a B without the function's return type conforming to the enclosing structure i.e. returning a Set
strings.map(numberOfCharsDiv2)
res2: scala.collection.immutable.Set[scala.util.Try[Int]] = Set(Success(1), Failure(java.lang.RuntimeException: grr), Success(3))
It is a Monad in Scala 2.11:
scala> import scala.util._
import scala.util._
scala> val x: Try[String] = Success[String]("abc")
x: scala.util.Try[String] = Success(abc)
scala> val y: Try[String] = Failure[String](new Exception("oops"))
y: scala.util.Try[String] = Failure(java.lang.Exception: oops)
scala> val z = Try(x)
z: scala.util.Try[scala.util.Try[String]] = Success(Success(abc))
scala> val t = Try(y)
t: scala.util.Try[scala.util.Try[String]] = Success(Failure(java.lang.Exception: oops))
scala> z.flatten
res2: scala.util.Try[String] = Success(abc)
scala> t.flatten
res3: scala.util.Try[String] =
Failure(java.lang.UnsupportedOperationException: oops)
Kigyo explains well why Scala does not do this implicitly. To put it simply, Scala does not want to automatically throw away the exception that is preserved in a Try.
Scala does provide a simple way to explicitly translate a Try into an Option though. This is how you can use a Try in a flatmap:
strings.flatMap(numberOfCharsDiv2(_).toOption)

Implementing `sequence` on a Monad

Working on another exercise to implement Monad.sequence() from Functional Programming in Scala, my answer differs from the official/known-to-be correct answer:
def sequence[A](lma: List[F[A]]): F[List[A]]
Official:
def sequence[A](lma: List[F[A]]): F[List[A]] =
lma.foldRight(unit(List[A]()))((ma, mla) => map2(ma, mla)(_ :: _))
Mine:
def sequence[A](lma: List[F[A]]): F[List[A]] = F(lma.flatten)
Example where F is Option:
scala> val x: List[Option[Int]] = List( Some(1), None)
x: List[Option[Int]] = List(Some(1), None)
scala> Some(x.flatten)
res1: Some[List[Int]] = Some(List(1))
Is my answer (or the spirit of it) legitimate here?
I get the following compile-time exception, but I'm sure if it's related to my lack of understanding of type constructors.
Monad.scala:15: error: not found: value F
F(lma.flatten)
When you write Option(1), what's actually happening is that you're calling the apply method on the Option companion object. This is only very indirectly related to the Option type—specifically, there's no way in general to get the Something companion object (which is a value) if you only have a type variable referring to the Something type. In fact there's no guarantee that the companion object even exists, and even if it does exist, its apply method might return something that's entirely not an instance of the Something type. The fact that X.apply(...) does return an X in the case of List and Option and case classes is entirely a matter of convention.
The other part of the issue here is the call to List.flatten. If you look at the "Full Signature" for flatten in the docs, you'll see that it has an implicit argument:
def flatten[B](implicit asTraversable: (A) => GenTraversableOnce[B]): List[B]
This means that you can only use it on a List[A] if A can be implicitly converted into a GenTraversableOnce of some kind. This isn't the case in general for any old monad.
I'd encourage you to prove these things to yourself, though—try your implementation with some of the other monads from the exercises and see where things break down.

define a function with tuples

How can I define a function that is accepting all the tuples(1 to 22) as argument, I have something as follows in mind:
def foo (v=Tuple) =...
foo((1,2))
foo((1,2,3))
EDIT:
To answer the comment: I am actually trying to create a Tensor class which is a set of values and a set of indices. The indices can be covariant and/or contravariant (cf Wikipedia1 and Wikipedia2). I wanted to have a special syntax like Tensor((1,2),(3,4),values) which would create a tensor with values, two covariant indices having length (2,3) and two contravariant indices with length (3,4). So using this syntax I could also write Tensor((1,2,3),3,values) (with an implicit Int=>Tuple1).
I agree that Tuples are not suitable for this, better to use Lists. However the syntax is not so nice then...
This really isn't what tuples are for (cf. the comments and answers here). Tuples are for doing things like returning multiple values from a method, where in Java you would have to create a lightweight class. If you have an arbitrary number of elements, you should use a collection.
Another way to provide a convenient API to your users (aside from implicit conversion) is to use multiple parameter lists with varargs:
def tensor(cov: Int*)(contrav: Int*)(values: Int*) = // ...
Your examples would be written
tensor(1,2)(3,4)(values)
tensor(1,2,3)(3)(values)
There is no trait specifically for tuples, but you could use a typeclass approach, as demonstrated in this answer.
If your goal is really to have a List but allow callers to pass in tuples (for convenience), you can modify that solution so that the type class produces a List rather than a Product.
In brief, the idea is that you provide implicit conversions from the types that callers can pass to the type you're actually going to use:
def foo(x: IndexList) = x.indices
sealed case class IndexList(indices: List[Int])
object IndexList {
implicit def val2indices(i: Int) = IndexList(List(i))
implicit def tuple2toIndices(t: (Int, Int)): IndexList =
product2indices(t)
// etc
implicit def list2indices(l: List[Int]) = IndexList(l)
private def product2indices(p: Product) =
IndexList(p.productIterator.toList.asInstanceOf[List[Int]])
}
You can then call your method with any type for which you've provided a conversion:
foo(1)
foo((2,3))
foo(List(1,2,3))
All case classes, including Tuples, extend scala.Product but unfortunately there's no marker trait specifically for tuples, so someone could sneak ordinary case classes into your method. Of course, there's no way to treat all arities in a uniform way and still be typesafe, but you can use productElement(n: Int) to extract the nth value, or productIterator to iterate over all the values.
But... This is heresy around here, but have you considered overloading? :)
What you probably want to use is an HList, not a tuple. An HList (heterogenous list) is basically an arbitrary-length, typed tuple.
There are a few examples of HLists in scala (they are not part of the standard library)
http://jnordenberg.blogspot.com/2008/08/hlist-in-scala.html
a great and comprehensive series by Mark Harrah (of SBT fame)
Miles Sabin's github examples, taken from his recent talk at Scala eXchange
Check this out. It actually works better than I expected ;)
scala> def f[T <: Product](x: T) = x
f: [T <: Product](x: T)T
scala> f(1)
<console>:9: error: inferred type arguments [Int] do not conform to method f's type parameter bounds [T <: Product]
scala> f(1, "2") // you don't even need the extra parenthesis
res0: (Int, java.lang.String) = (2,3)
scala> f(1, "2", BigInt("3"))
res1: (Int, java.lang.String, scala.math.BigInt) = (1,2,3)