I'm new to scala and when study the pattern match part, i got confused.
val hd::tail = List(1,2,3,4,5)
After execute this code, hd will be Int = 1 , and tail will be List[Int] = List(2, 3, 4, 5).
And this code equals to:
val ::(hd,tail) = List(1,2,3,4,5)
I learned that this code is pattern match and it calls unapply method actually.
But when I write code in this way, compiled error:
val result = ::.unapply(List(1,2,3,4,5))
It says method parameter type mismatch. The unapply method of "::" need a "::[?]"
Does anyone know the reason?
The type mismatch error is because ::.unapply takes an instance of ::[T] rather than an instance of the more general type List[T].
Scala will automatically add the matching against the actual type.
In other words, my understanding is that when you do this:
val list = List(1,2,3,4,5)
val hd::tail = list
the compiler generates something akin to this:
val list = List(1,2,3,4,5)
val (hd, tail) =
::.unapply(
// First match to test against input type
// (necessary as the static type of `list` is `List[Int]`
// so we don't know until runtime if it is an instance of `::[Int]`
// or an instance of `Nil`)
list match {
case nonEmptyList: ::[Int] => nonEmptyList
case _ => throw new MatchError
}
) match { // Second match to test against result of `::`.unapply
case Some( result ) => result
case _ => throw new MatchError
}
The method signature you have is incorrect. :: is a case class, so unapply takes an instance of ::. Here's something closer to what you might be looking for, though typically I don't call unapply in code as it's done in a pattern matching scenario:
//Note the type returned by unapply
val unappliedOption:Option[(Int, List[Int])] = ::.unapply(::(1, List(2, 3, 4, 5)))
val (hd, tail) = unappliedOption.getOrElse((1, Nil))
In pattern matching unapply is called automatically for you. Also note that :: is a non-empty list though it still returns an option. So for an instance of List we have two options :: or Nil:
List(1, 2, 3, 4, 5) match {
case hd :: tail => println(hd, tail) // calls ::.unapply and returns hd tail if the option is Some
case hd => println(hd) //Default case Nil
}
Related
Why it's impossible to compile this code
IndexedSeq(1, 2, 3) match {
case a :: b :: c => println("toto");
}
But it's possible with a Seq ?
IndexedSeq(1, 2, 3).toSeq match {
case a :: b :: c => println("toto");
}
The IndexedSeq.toSeq method is just a cast !
I'm not sure why the second one compiles, but I do know that it doesn't work!
scala> IndexedSeq(1,2, 3).toSeq match {
case a :: b :: c :: nil => println("toto");
}
| | scala.MatchError: Vector(1, 2, 3) (of class scala.collection.immutable.Vector)
If you want to pattern match a sequence, you either need to use +: as the joining operator, or use Seq(a,b,c) as the pattern to match. See this answer
The following all work as desired:
IndexedSeq(1,2, 3).toSeq match {
case Seq(a, b, c) => println("toto");
}
IndexedSeq(1,2, 3) match {
case Seq(a, b, c) => println("toto");
}
IndexedSeq(1,2, 3).toSeq match {
case a +: b +: c => println("toto");
}
IndexedSeq(1,2, 3) match {
case a +: b +: c => println("toto");
}
To add to #ladams 's answer. Calling toSeq on IndexedSeq is just referring to the super as the latter inherits from the former. On the side note, you could also extract the values the following way:
IndexedSeq(1, 2, 3) match {
case IndexedSeq(head, tail # _*) => println("got match")
case _ => println("sth else")
}
Also, Seq is just a trait that returns appropriate collection, e.g.
val s: Seq[Int] = 1 :: 2 :: 3 :: Nil
s: Seq[Int] = List(1, 2, 3)
Therefore, you can match it with Cons. Whereas IndexedSeq returns a Vector, that does not define a Cons operator.
val s: IndexedSeq[Int] = IndexedSeq(1, 2, 3)
s: IndexedSequence[Int] = Vector(1, 2, 3)
The first example doesn't compile because the type of the pattern a :: b :: c is List[something] and the type of the selector IndexedSeq(1, 2, 3) is IndexedSeq[Int]. Because List isn't a subtype of IndexedSeq, the compiler knows that the match can't possibly succeed and produces an error. As described in the language specification (rephrased slightly to remove the formulas):
Every pattern can be typed in two ways. First, it is attempted to type the pattern with the selector's type as its expected type. If this fails, it is instead typed with a modified expected type which results by replacing every occurrence of a type parameter by undefined. If this second step fails also, a compile-time error results.
In the second case, the type of the selector is Seq[Int], so as far as the compiler is concerned, it could turn out to be a List[Int] at runtime, in which case it would succeed. It could give a warning that the match could fail (as in fact it does), but the Scala designers decided otherwise: such a warning is given only when the selector's type is sealed.
In the sample below, there is a function seqResult that pattern matches against a Seq. Another function that accepts variable arguments calls seqResult and passes in an ArrayBuffer. This causes the pattern match result to be different when called with a Seq or with an ArrayBuffer.
With a Seq the matcher hits case head :: rest => ..., with an ArrayBuffer the matcher hits case Seq(one, two) => ....
Is this a bug? Is there anyway to safeguard against this?
If it's not a bug, what is a safe way to match a list of 1 or more entries that would work for Seq(a,b) and ArrayBuffer(a,b)?
def seqResult(arr:Seq[String]) = arr match {
case Nil => "Nil"
case head :: Nil => "head :: Nil"
case head :: rest => "head :: rest"
case Seq(one, two) => "one, two"
case _ => "other"
}
def varArgResult(args:String*) = seqResult(args)
val ab = varArgResult("one", "two")
val se = seqResult(Seq("one", "two"))
println(ab) //=> "one, two"
println(se) //=> "head :: rest"
:: is an extractor object for Lists. Since lists are the default implementation of Seq, this is what you're seeing when you use Seq(a, b, ...).
The extractor for Seqs is +:.
args: String* is actually Array
Seq() constructor uses builder based on ListBuffer so as the result we have List data type.
object Seq extends SeqFactory[Seq] {
def newBuilder[A]: Builder[A, Seq[A]] = new mutable.ListBuffer
}
...
println(Seq("one", "two"))
List(one, two)
head::rest is syntax sugar for List matching and can be represented as List(head, rest) which is match se in your case.
I am new to scala and I can not understand the following function
val L = List(List(1, 1), 2, List(3, List(5, 8)))
def flatten(l: List[Any]): List[Any] = l flatMap {
case ms:List[_] => flatten(ms)
case l => List(l)
}
flatten(L) // res2: List[Any] = List(1, 1, 2, 3, 5, 8)
In particular I do not understand the combination of flatMap and pattern matching and also the meaning of the first case ms:List[_]
Can someone explain that and maybe provide a simpler example to clarify the concept?
map and flatMap
First of all flatMap is a higher-order function.
map is also a higher order function which will convert a List to a new List by applying a function on all elements of that List. For example if you have
val l = List(1,2,3)
you can map it to a new list by using
val doubled = l.map(_ * 2) // List(2,4,6)
So what is flatMap? flatMap is useful when your function gets an Int but returns a List[Int]. In this case if you pass this function to map what you get will be a List[List[Int]] but sometimes you want to get a List[Int] instead.
What you can do is to use flatMap instead. Mathematically it is equivalent to first map and then flatten the result but in action it could be the flatten function which is defined based on flatMap not the other way around.
Technical details aside, flatten means that if you have a List[List[List...[Int]]], if you flatten it, you will get a List[Int].
When we look at
def flatten(l: List[Any]): List[Any] = l flatMap {
case ms:List[_] => flatten(ms)
case l => List(l)
}
we first need to know what does this mean. We already know that we have to pass a function to flatMap. In this case the function we are passing is
{
case ms:List[_] => flatten(ms)
case l => List(l)
}
which at first does not seem like a function but it is! It is actually a partial function which you can consider as a function with some nuances!
What is a partial function?
We could achieve (almost) the same result with:
def flatten(l: List[Any]): List[Any] = l flatMap { _ match {
case ms:List[_] => flatten(ms)
case l => List(l)
}
}
The difference between an ordinary function and a partial function is that partial functions may be undefined for some specific inputs. So the compiler will automatically generate a partial function from a body which starts with case keyword (It's not that simple but for the sake of simplicity I skip the details here).
Pattern matching by Type
A pattern like ms:List[_] is called a type pattern. It means that the type of ms will be checked in runtime against the List[_]. _ is a wild card and means any type so ms:List[_] literally means a List of any type (Due to type erasure you can not use a pattern like ms:List[Int], refer to this thread for more info).
So the whole pattern match on this code snippets means that
If ms is a list the result will be flatten(ms), other wise the result will be List(l).
The flatten function defined like this is recursive function which unwraps the lists and do this until there is no more list, then it will wrap the result again in a List! This way List[List[List.......[_]]] will be converted to List[_].
An additional example for type-patterns:
def hello(o: Any) = o match {
case _:Int => "Hi, I am an Int and I'm proud of it!"
case _:List[_] => "I have many things to tell you! I am a list after all!"
case b:Boolean => s"I'm simply a flag and my value is $b"
case _ => "I'm everything else you can imagine :D"
}
Disambiguation
By the way partial function is totally different from partially applied function and partial application!
The concept of partial function in Scala is the same as partial function in mathematics: A function which may be undefined for some of the values of its domain.
I have been learning Scala these days, and today I ran into some issue that I cannot understand.
Suppose we have the following parametric function definition:
def filter[T](source: List[T], predicate: T=>Boolean): List[T] = {
source match {
case Nil => Nil
case x::xs => if(predicate(x)) x::filter(xs, predicate)
else filter(xs, predicate)
}
}
Now, this works just fine if I invoke it as follows:
filter(List(1,2,3,4,5,6), ( (n:Int) => n % 2 == 0))
But if remove the type tag, it appears Scala cannot infer that the type of T is Int.
filter(List(1,2,3,4,5,6), ( n => n % 2 == 0))
So, I am forced to provide explicit type information in this call.
Does anybody know why Scala is not capable of inferring the type of T in this call. The list is evidently a List of Ints, I cannot see why it cannot infer that the type of n is also Int.
Scala's type inference works per parameter list, not per parameter, so it hasn't resolved T to Int by the time it gets to the predicate in your second example. You can, however, get what you want by using two parameter lists:
def filter[T](source: List[T])(predicate: T => Boolean): List[T] =
source match {
case Nil => Nil
case x :: xs =>
if (predicate(x))
x :: filter(xs)(predicate)
else
filter(xs)(predicate)
}
Now the following will work just fine:
scala> filter(List(1, 2, 3, 4, 5, 6))((n => n % 2 == 0))
res0: List[Int] = List(2, 4, 6)
See my answer here for some additional discussion.
You need to put the predicate in an other group of parameters to get inference to work:
def filter[T](source: List[T])(predicate: T=>Boolean): List[T] = {
source match {
case Nil => Nil
case x::xs => if(predicate(x)) x::filter(xs)(predicate)
else filter(xs)(predicate)
}
}
filter(List(1,2,3,4,5,6))(_ % 2 == 0)
Unfortunately it's a limitation of scala.
I am trying to understand the Scala quicksort example from Wikipedia. How could the sample be disassembled step by step and what does all the syntactic sugar involved mean?
def qsort: List[Int] => List[Int] = {
case Nil => Nil
case pivot :: tail =>
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
}
As much as I can gather at this stage qsort is a function that takes no parameters and returns a new Function1[List[Int],List[Int]] that implements quicksort through usage of pattern matching, list manipulation and recursive calls. But I can't quite figure out where the pivot comes from, and how exactly the pattern matching syntax works in this case.
UPDATE:
Thanks everyone for the great explanations!
I just wanted to share another example of quicksort implementation which I have discovered in the Scala by Example by Martin Odersky. Although based around arrays instead of lists and less of a show-off in terms of varios Scala features I personally find it much less convoluted than its Wikipedia counterpart, and just so much more clear and to the point expression of the underlying algorithm:
def sort(xs: Array[Int]): Array[Int] = {
if (xs.length <= 1) xs
else {
val pivot = xs(xs.length / 2)
Array.concat(
sort(xs filter (pivot >)),
xs filter (pivot ==),
sort(xs filter (pivot <)))
}
}
def qsort: List[Int] => List[Int] = {
case Nil => Nil
case pivot :: tail =>
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
}
let's pick apart a few bits.
Naming
Operators (such as * or +) are valid candidates for method and class names in Scala (hence you can have a class called :: (or a method called :: for that matter - and indeed both exist). Scala appears to have operator-overloading but in fact it does not: it's merely that you can declare a method with the same name.
Pattern Matching
target match {
case p1 =>
case p2 =>
}
Where p1 and p2 are patterns. There are many valid patterns (you can match against Strings, types, particular instances etc). You can also match against something called an extractor. An extractor basically extracts arguments for you in the case of a match, so:
target match {
case MyExtractor(arg1, arg2, arg3) => //I can now use arg1, arg2 etc
}
In scala, if an extractor (of which a case class is an example) exists called X, then the pattern X(a, b) is equivalent to a X b. The case class :: has a constructor taking 2 arguments and putting this together we get that:
case x :: xs =>
case ::(x, xs) =>
Are equivalent. This match says "if my List is an instance of :: extract the value head into x and tail into xs". pattern-matching is also used in variable declaration. For example, if p is a pattern, this is valid:
val p = expression
This why we can declare variables like:
val x :: xs = List(1, 2, 3)
val (a, b) = xs.partition(_ % 2 == 0 ) //returns a Tuple2 which is a pattern (t1, t2)
Anonymous Functions
Secondly we have a function "literal". tail is an instance of List which has a method called partition which takes a predicate and returns two lists; one of those entries satisfying the predicate and one of those entries which did not.
val pred = (el: Int) => e < 2
Declares a function predicate which takes an Int and returns true iff the int value is less than 2. There is a shorthand for writing functions inline
tail.partition(_ < pivot) // _ is a placeholder for the parameter
tail.partition( (e: Int) => e < pivot )
These two expressions mean the same thing.
Lists
A List is a sealed abstract class with only two implementations, Nil (the empty list) and :: (also called cons), which is a non-empty list consisting of a head and a tail (which is also a list). You can now see that the pattern match is a match on whether the list is empty or not. a List can be created by cons-ing it to other lists:
val l = 1 :: 2 :: Nil
val m = List(1, 2, 3) ::: List(4, 5, 6)
The above lines are simply method calls (:: is a valid method name in scala). The only difference between these and normal method calls is that, if a method end in a colon : and is called with spaces, the order of target and parameter is reversed:
a :: b === b.::(a)
Function Types
val f: A => B
the previous line types the reference f as a function which takes an A and returns a B, so I could then do:
val a = new A
val b: B = f(a)
Hence you can see that def qsort: List[Int] => List[Int] declares a method called qsort which returns a function taking a List[Int] and returning a List[Int]. So I could obviously do:
val l = List(2, 4, 1)
val m = qsort.apply(l) //apply is to Function what run is to Runnable
val n = qsort(l) //syntactic sugar - you don't have to define apply explicitly!
Recursion
When a method call is tail recursive, Scala will optimize this into the iterator pattern. There was a msitake in my original answer because the qsort above is not tail-recursive (the tail-call is the cons operator)
def qsort: List[Int] => List[Int] = {
case Nil => Nil
case pivot :: tail =>
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
}
Let's rewrite that. First, replace the function literal with an instance of Function1:
def qsort: List[Int] => List[Int] = new Function1[List[Int], List[Int]] {
def apply(input: List[Int]): List[Int] = input match {
case Nil => Nil
case pivot :: tail =>
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
}
}
Next, I'm going to replace the pattern match with equivalent if/else statements. Note that they are equivalent, not the same. The bytecode for pattern matches are more optimized. For instance, the second if and the exception throwing below do not exist, because the compile knows the second match will always happen if the first fails.
def qsort: List[Int] => List[Int] = new Function1[List[Int], List[Int]] {
def apply(input: List[Int]): List[Int] = if (input == Nil) {
Nil
} else if (input.isInstanceOf[::[_]] &&
scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]) != None) {
val unapplyResult = scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]).get
val pivot = unapplyResult._1
val tail = unapplyResult._2
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
} else {
throw new scala.MatchError(input)
}
}
Actually, val (smaller, rest) is pattern match as well, so Let's decompose it as well:
def qsort: List[Int] => List[Int] = new Function1[List[Int], List[Int]] {
def apply(input: List[Int]): List[Int] = if (input == Nil) {
Nil
} else if (input.isInstanceOf[::[_]] &&
scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]) != None) {
val unapplyResult0 = scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]).get
val pivot = unapplyResult0._1
val tail = unapplyResult0._2
val tmp0 = tail.partition(_ < pivot)
if (Tuple2.unapply(tmp0) == None)
throw new scala.MatchError(tmp0)
val unapplyResult1 = Tuple2.unapply(tmp0).get
val smaller = unapplyResult1._1
val rest = unapplyResult1._2
qsort(smaller) ::: pivot :: qsort(rest)
} else {
throw new scala.MatchError(input)
}
}
Obviously, this is highly unoptmized. Even worse, there are some function calls being done more than once, which doesn't happen in the original. Unfortunately, to fix that would require some structural changes to the code.
There's still some syntactic sugar here. There is an anonymous function being passed to partition, and there is the syntactic sugar for calling functions. Rewriting those yields the following:
def qsort: List[Int] => List[Int] = new Function1[List[Int], List[Int]] {
def apply(input: List[Int]): List[Int] = if (input == Nil) {
Nil
} else if (input.isInstanceOf[::[_]] &&
scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]) != None) {
val unapplyResult0 = scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]).get
val pivot = unapplyResult0._1
val tail = unapplyResult0._2
val func0 = new Function1[Int, Boolean] {
def apply(input: Int): Boolean = input < pivot
}
val tmp0 = tail.partition(func0)
if (Tuple2.unapply(tmp0) == None)
throw new scala.MatchError(tmp0)
val unapplyResult1 = Tuple2.unapply(tmp0).get
val smaller = unapplyResult1._1
val rest = unapplyResult1._2
qsort.apply(smaller) ::: pivot :: qsort.apply(rest)
} else {
throw new scala.MatchError(input)
}
}
For once, the extensive explanations about each syntactic sugar and how it works are being done by others. :-) I hope this complements their answers. Just as a final note, the following two lines are equivalent:
qsort(smaller) ::: pivot :: qsort(rest)
qsort(rest).::(pivot).:::(qsort(smaller))
The pivot in this pattern matching example is the first element of the list:
scala> List(1,2,3) match {
| case x :: xs => println(x)
| case _ => println("empty")
| }
1
The pattern matching is based on extractors and the cons is not part of the language. It uses the infix syntax. You can also write
scala> List(1,2,3) match {
| case ::(x,xs) => println(x)
| case _ => println("empty")
| }
1
as well. So there is a type :: that looks like the cons operator. This type defines how it is extracted:
final case class ::[B](private var hd: B, private[scala] var tl: List[B]){ ... }
It's a case class so the extractor will be generated by the Scala compiler. Like in this example class A.
case class A(x : Int, y : Int)
A(1,2) match { case x A y => printf("%s %s", x, y)}
-> 1 2
Based on this machinary patterns matching is supported for Lists, Regexp and XML.