I am studying some scala code and found this method which baffles me. In the match statement, what is the sublist# construct? what kind of value does it contains? when I printed it its no diff than tail, but if I replace it with tail, the function returns diff result. Can somebody explain what it is and point me to a right resource to understand it? (I know I can search in google, but don't know what to look for..)
def flatMapSublists[A, B](ls: List[A])(f: (List[A]) => List[B]): List[B] =
ls match {
case Nil => Nil
case sublist#(_ :: tail) => f(sublist) ::: flatMapSublists(tail)(f)
}
I would call it the "eat your cake and have it too operator". At any level in pattern matching, you can give a part a name (before the #) and deconstruct it further (after the #). For instance imagine you want to match against a List with 3 elements, you need the second element, but you want to log the whole list:
something match {
case list#List(_,elem,_) => log("matching:" + list); elem
case _ => error("not found")
}
Without this feature, you had to write something like
something match {
case List(a,elem,b) => log("matching:" + List(a,elem,b)); elem
case _ => error("not found")
}
As you can see, we need to name the first and third element, just because we need them to get a list with the same structure on the right side, which is boilerplate. It is much easier and clearer if you can give the whole thing a name (list), and parts deeper in the structure as well (elem), when you need both on the right side.
In this instance, sublist becomes a named variable for the entire list (_ :: tail). tail is the, well, tail of the list. I'm not sure if there is a proper name for '#' here.
I don't really see the purpose of sublist here, since you can just reference ls directly.
Disclaimer: I'm new to scala. I hope I got this right.
Related
I recently fell over a scala pattern match, that looked more or less like this:
def func (li :List[Int]): List[Int] = li match {
case Nil => Nil
case start :+ tail => start
case List() => li
}
Now, what these three different cases return is not so much what I am in interesed about.
I wondering whether a pattern match like this would ever have any effect? Is there any case at all, where third case could ever reached?
My initial thought is no, since all lists with more than 0 elements will always match on the first case, and therefore the second case could never be reached
You can read the post: Scala: Nil vs List(). From the point of view of pattern matching, they are the same. The third case will never hit.
In Scala source code you can find that case object Nil extends List[Nothing], and that empty list is Nil.
The third case is redundant, because as far as I know, an empty list can only ever be Nil. List is sealed, so there won't be classes other than :: and the object Nil extending it.
However, a list with more than 0 elements will always match on the second case. A list with no elements would match the first case (and the third case, if the first were not present).
Is there any reason that matching an empty list should be done using a case/match instead of if/else, other than style? For example:
val a: List
def compute: Int =
if (a.isEmpty) 0
else a.sum
versus
def compute: Int =
a match {
case Nil => 0
case _ => a.sum // This is bad. For sake of illustration only.
}
If you are just testing empty/not empty then there is little to choose from and if is perhaps more meaningful. match comes in to play when there are multiple options:
a match {
case Nil => 0
case hd::Nil => 1
case hd::tl => 2
}
It is also often the case that you can avoid or at least defer this test by using appropriate methods. For example, take(1) works on an empty list whereas head will fail. And headOption.map(...) can be used to safely process the first element, if present.
Tim already has a good answer, but I'd like put a slightly different angle on it.
For lists (or other collections), .head and .tail are unsafe and if makes it easy to accidentally use them in the wrong branch (or to forget to test at all), while case avoids need to call these functions.
If your function doesn't need to call them and doesn't need to check more complex conditions, you can as well go with if.
Given a list, what is the best way to return a value depending on the empty-ness of that list?
Using match?
xs match {
case Nil => a
case _ => b
}
Or an if statement?
if (xs.isEmpty) a else b
It seems that pattern matching triggered a lot of a boilerplate in this case. Is there an idiomatic solution for this case?
"Preference" is subjective, but the simple if has a few advantages:
there doesn't seem to be a need to use pattern matching in this case, since you're not really exploiting its functionality (no extraction for example).
the second approach tells you explicitly that you check whether the list is empty, and hence is immediately readable.
In summary: pattern matching in Scala is a powerful tool, and because of its power it adds complexity to your code, both in terms of machine- and human-readability. In other words: not everything is a nail ;).
The pattern match syntax is preferred when you need recursion or head :: tail. List in Scala is inspired by older ML languages(Cons(head, tail)) and you get a nice head :: tail pair to match:
someList match {
case head :: tail => // this will actually be someList.head and someList.tail
case Nil => // ..
}
I wouldn't say it's nicer, but an alternative is:
xs.headOption.fold(a)(_ => b)
In this case, it looks a little bit weird because you're ignoring the head element and returning b instead, but if you actually wanted to use it as return value, the following is quite elegant:
xs.headOption.getOrElse(a) //will return the head element or a if none
My favourite would be adding some scalaz:
import scalaz._
import Scalaz._
xs.headOption ? b | a // if defined 'b' else 'a'
I need to make a sequence that, given a list containing optional list of strings, concatenates all of them to make a new list. This how my code looks like:
res.foldLeft(Seq[Option[Seq[String]]]())((acc, v) => v match {
case Some(x) => acc ++: Some(x)
case None => acc
})
where res is a list containing optional list elements such as :
List(Some(Seq(foo)), Some(Seq(bar)), None, Some(Seq(baz, blah)))
I get a compilation error at the sign ++: saying:
type mismatch; found : Iterable[Equals] required: Seq[Option[Seq[String]]]
What am I doing wrong here?
Why don't you just do:
res.flatten.flatten
first flatten will get rid of Nones and expose the Options and second one will perform the expected flattening operation on the Seqs
I don't have scala installed on this box, but you could try using the 'map' function to remove the options out of the equation, then flatten the list of seq down to a single iterable.
Something like this:
res.map.flatten
As I understand it you would then end up with a Iterable containing 'foo', 'bar', 'sez', 'bar'.
I'll check this out a little later to test the syntax is correct and what I've written actually works..
Cheers, Aaron
EDIT: Got access to my scala terminal and this works:
res.map(s => s).flatten.flatten
Your types in case Some(x) => acc ++: Some(x) part is wrong.
++: operator expects a parameter of type Seq[Option[Seq[String]]] but you are providing a parameter of type Option[Seq[String]].
ps: If you can tell exactly the result you expect. I can improve this answer to help you to write the correct code you need.
In Scala I have a List with an optional Option. This arises for example when you use for comprehension on a List and your yield returns an Option. In my case I was processing a JSON object and using for comprehension on the list of fields (List[JField]).
What's the best way to open up the list and map List() to None and List(Some(a)) to Some(a)?
A first approach would be
def headOrNone[A](list:List[Option[A]]) =
list match {
case Nil => None
case a::Nil => a
}
Another approach
def headOrNone[A](list:List[Option[A]]) = list.headOption.getOrElse(None)
A third approach (a variation on the headOption implementation)
def headOrNone[A](list:List[Option[A]]) = if (list.isEmpty) None else list.head
I personally prefer the third approach. Is there a better name for this function than headOrNone and what is the idiomatic scala way to write it?
You're solving a problem that probably shouldn't have been created. Instead, you probably want
for (x <- list) yield f(x) // Yields Option
to be
list.flatMap(f)
and then you'll have either zero or one things in your list to begin with (which you can extract using headOption).
How about this:
def headOrNone[A](list: List[Option[A]]) = list.flatten.headOption
headOrNone(List(Some(4))) // Some(4)
headOrNone(List()) // None
Though the first choice has the advantage of giving you an error if you happen to have list with more than one item, which, according to your description, seems like an error condition.
But personally, I would re-evaluate the code that produces the List[Option[A]] and see if there's a way to just have it return the right thing in the first place!