How can I avoid always putting
case _ =>
at the end in Scala matching? It is sometimes possible that other values will be matched, but I only want to do something with the cases above the
"case _ =>"
case.
A match is a function like most things in Scala, so it returns a value and you need to return something for every possible case. If you are not doing anything in case _ then you are returning Unit which, in turn, means that the code is relying on side effects and is non-functional.
So the best way to reduce the use of empty case _ => in your code is to make it more functional, since this isn't used in functional code.
The alternative is to use a different mechanism for a multi-way branch, such as chained if, or chains of Option/orElse, or find/collectFirst on a list of operations.
This doesn't work:
val res = myOption flatMap (value => Seq(value, “blo”))
But this yes:
val res = myOption.toSeq flatMap (value => Seq(value, “blo”))
Don't you think flatMap on Options should take a GenTraversableOnce just like Seq does?
Or this code is bad for the readability and I should use a match or a map/getOrElse?
Edit: We also get the same issue on for/yield.
Cheers
Option.flatMap returns an Option, which is "like" a sequence, but cannot contain more than one element. If it was allowed to take a function, that returned a Seq, and it returned a Seq containing more than one element, what would be the return value of flatMap (remember, it needs to be an Option)?
Why does flatMap need to return an option in the first place? Well, all flatMap implementations return the same type they started with. It makes sense: if I have an Option of something, and want to transform the contents somehow, the most common use case is that I want to end up with another Option. If flatMap returned me a Seq, would would I do? .headOption? That is not a very good idea, because it would potentially silently discard data. if(seq.size < 2) seq.headOption else throw ....? Well, this is a little bit better, but looks ugly, and isn't enforceable at compile time.
Converting an Option to a Seq when you need it on the other hand, is very easy and entirely safe: just do .toSeq.
Overall semantic of flatMap is to work like monadic bind method, that means it tends to have signature like
[A]this:T[A].flatMap[B](f: A => T[B]): T[B]
Sometimes (SeqLike) this signature is generalized to
[A]this:T[A].flatMap[B](f: A => F[B]): T[B]
where F[B] is something easily convertible to T[B]
So not only Option, but also concurrent.Future, util.Try and BindOps - extension syntax for scalaz monads have method flatMap that does not accept any traversable, but only the same wrapper type .
I.e. flatMap is more a thing from monads world, not from collections
I have been looking into FP languages (off and on) for some time and have played with Scala, Haskell, F#, and some others. I like what I see and understand some of the fundamental concepts of FP (with absolutely no background in Category Theory - so don't talk Math, please).
So, given a type M[A] we have map which takes a function A=>B and returns a M[B]. But we also have flatMap which takes a function A=>M[B] and returns a M[B]. We also have flatten which takes a M[M[A]] and returns a M[A].
In addition, many of the sources I have read describe flatMap as map followed by flatten.
So, given that flatMap seems to be equivalent to flatten compose map, what is its purpose? Please don't say it is to support 'for comprehensions' as this question really isn't Scala-specific. And I am less concerned with the syntactic sugar than I am in the concept behind it. The same question arises with Haskell's bind operator (>>=). I believe they both are related to some Category Theory concept but I don't speak that language.
I have watched Brian Beckman's great video Don't Fear the Monad more than once and I think I see that flatMap is the monadic composition operator but I have never really seen it used the way he describes this operator. Does it perform this function? If so, how do I map that concept to flatMap?
BTW, I had a long writeup on this question with lots of listings showing experiments I ran trying to get to the bottom of the meaning of flatMap and then ran into this question which answered some of my questions. Sometimes I hate Scala implicits. They can really muddy the waters. :)
FlatMap, known as "bind" in some other languages, is as you said yourself for function composition.
Imagine for a moment that you have some functions like these:
def foo(x: Int): Option[Int] = Some(x + 2)
def bar(x: Int): Option[Int] = Some(x * 3)
The functions work great, calling foo(3) returns Some(5), and calling bar(3) returns Some(9), and we're all happy.
But now you've run into the situation that requires you to do the operation more than once.
foo(3).map(x => foo(x)) // or just foo(3).map(foo) for short
Job done, right?
Except not really. The output of the expression above is Some(Some(7)), not Some(7), and if you now want to chain another map on the end you can't because foo and bar take an Int, and not an Option[Int].
Enter flatMap
foo(3).flatMap(foo)
Will return Some(7), and
foo(3).flatMap(foo).flatMap(bar)
Returns Some(15).
This is great! Using flatMap lets you chain functions of the shape A => M[B] to oblivion (in the previous example A and B are Int, and M is Option).
More technically speaking; flatMap and bind have the signature M[A] => (A => M[B]) => M[B], meaning they take a "wrapped" value, such as Some(3), Right('foo), or List(1,2,3) and shove it through a function that would normally take an unwrapped value, such as the aforementioned foo and bar. It does this by first "unwrapping" the value, and then passing it through the function.
I've seen the box analogy being used for this, so observe my expertly drawn MSPaint illustration:
This unwrapping and re-wrapping behavior means that if I were to introduce a third function that doesn't return an Option[Int] and tried to flatMap it to the sequence, it wouldn't work because flatMap expects you to return a monad (in this case an Option)
def baz(x: Int): String = x + " is a number"
foo(3).flatMap(foo).flatMap(bar).flatMap(baz) // <<< ERROR
To get around this, if your function doesn't return a monad, you'd just have to use the regular map function
foo(3).flatMap(foo).flatMap(bar).map(baz)
Which would then return Some("15 is a number")
It's the same reason you provide more than one way to do anything: it's a common enough operation that you may want to wrap it.
You could ask the opposite question: why have map and flatten when you already have flatMap and a way to store a single element inside your collection? That is,
x map f
x filter p
can be replaced by
x flatMap ( xi => x.take(0) :+ f(xi) )
x flatMap ( xi => if (p(xi)) x.take(0) :+ xi else x.take(0) )
so why bother with map and filter?
In fact, there are various minimal sets of operations you need to reconstruct many of the others (flatMap is a good choice because of its flexibility).
Pragmatically, it's better to have the tool you need. Same reason why there are non-adjustable wrenches.
The simplest reason is to compose an output set where each entry in the input set may produce more than one (or zero!) outputs.
For example, consider a program which outputs addresses for people to generate mailers. Most people have one address. Some have two or more. Some people, unfortunately, have none. Flatmap is a generalized algorithm to take a list of these people and return all of the addresses, regardless of how many come from each person.
The zero output case is particularly useful for monads, which often (always?) return exactly zero or one results (think Maybe- returns zero results if the computation fails, or one if it succeeds). In that case you want to perform an operation on "all of the results", which it just so happens may be one or many.
The "flatMap", or "bind", method, provides an invaluable way to chain together methods that provide their output wrapped in a Monadic construct (like List, Option, or Future). For example, suppose you have two methods that produce a Future of a result (eg. they make long-running calls to databases or web service calls or the like, and should be used asynchronously):
def fn1(input1: A): Future[B] // (for some types A and B)
def fn2(input2: B): Future[C] // (for some types B and C)
How to combine these? With flatMap, we can do this as simply as:
def fn3(input3: A): Future[C] = fn1(a).flatMap(b => fn2(b))
In this sense, we have "composed" a function fn3 out of fn1 and fn2 using flatMap, which has the same general structure (and so can be composed in turn with further similar functions).
The map method would give us a not-so-convenient - and not readily chainable - Future[Future[C]]. Certainly we can then use flatten to reduce this, but the flatMap method does it in one call, and can be chained as far as we wish.
This is so useful a way of working, in fact, that Scala provides the for-comprehension as essentially a short-cut for this (Haskell, too, provides a short-hand way of writing a chain of bind operations - I'm not a Haskell expert, though, and don't recall the details) - hence the talk you will have come across about for-comprehensions being "de-sugared" into a chain of flatMap calls (along with possible filter calls and a final map call for the yield).
Well, one could argue, you don't need .flatten either. Why not just do something like
#tailrec
def flatten[T](in: Seq[Seq[T], out: Seq[T] = Nil): Seq[T] = in match {
case Nil => out
case head ::tail => flatten(tail, out ++ head)
}
Same can be said about map:
#tailrec
def map[A,B](in: Seq[A], out: Seq[B] = Nil)(f: A => B): Seq[B] = in match {
case Nil => out
case head :: tail => map(tail, out :+ f(head))(f)
}
So, why are .flatten and .map provided by the library? Same reason .flatMap is: convenience.
There is also .collect, which is really just
list.filter(f.isDefinedAt _).map(f)
.reduce is actually nothing more then list.foldLeft(list.head)(f),
.headOption is
list match {
case Nil => None
case head :: _ => Some(head)
}
Etc ...
I often find myself wanting to clump multiple matchers / extractors into the one line, but this doesn't seem to be allowed. e.g.:
text match {
case regex1(a) | regex2(a) => a + "-"
}
(even though a is the same type for both matchers)
so I'm forced to refactor like this (which can get ugly when there are several of these, all handling different matches, mixed with inline responses)
text match {
case regex1(a) => op(a)
case regex2(a) => op(a)
}
def op(a: String) = a + "-"
is there a cleaner way? And will this be supported in Scala in the future?
No, this is not possible in the general case. However, there are a few workaround that might be use to combine pattern matching cases:
Match on a super class of the cases you are willing to group
Use the case a # _ if boolexpr(a) or boolexpr(a) => construction
Factorize the common code in a function, like you did in your example
And probably others. I don't think this is going to change any time soon as it would encourage writing cryptic mach/cases.
I found a blog post today that mention's scalaz's sequence function.
Couldn't you do something as simple as:
if (l contains None) None else l
If so, what would this function signature look like? contains is in SeqLike, right?
Also, from the blog post I thought sequence was going to be something similar to map, but one that would break once None is encountered. Is there something like this?
Yes, you could, but it should be:
if (l contains None) None else Some(l.map(_.get))
The code in the blog post tries to write that function as general as possible (using scalaz' abstractions), so it will work not only for Options in a Seq.
[Edit] Corrected
Yes you can definitely write the sequence function specialized to some specific data structure. The Scalaz version, however is as general as possible. So it will work for any combination of F and G for which F[G[A]] => G[F[A]] is possible.
The other function you're looking for is called traverse. It has the signature
def traverse[F[_]:Traverse,G[_]:Applicative,A,B](m: F[A], f: A => G[B]): G[F[B]]
x.traverse(f) is equivalent to x.map(f).sequence.
x.sequence is equivalent to x.traverse(a => a)