Non-exhaustive Pattern Match Warning with Tuple - scala

Given the following sealed trait:
scala> sealed trait Parent
defined trait Parent
scala> case object Boy extends Parent
defined object Boy
scala> case object Girl extends Parent
defined object Girl
And given xs:
scala> val xs: (Parent, (Seq[Int], Seq[Int])) = (Boy, (Nil, Nil))
xs: (Parent, (Seq[Int], Seq[Int])) = (Boy,(List(),List()))
scala> xs match {
| case (Boy, (Nil, Nil)) => 1
| case (Boy, (ys, a :: as)) => 2
| case (Boy, (ys, Nil)) => 3
| case (Girl, (Nil, Nil)) => 4
| case (Girl, (a :: as, ys)) => 5
| case (Girl, (Nil, ys)) => 6
| }
<console>:15: warning: match may not be exhaustive.
It would fail on the following inputs: (Boy, _), (Girl, _)
xs match {
^
res1: Int = 1
I don't understand this inexhaustive match warning. What do (Boy, _) and (Girl, _) mean?
I'm not sure how the (Seq[Int], Seq[Int]) could have any other match than what I have on the right-hand side.

I'm not sure why, but it seems Scala has trouble with the unapply (or is it apply) for Seq which is the magic that makes the pattern matching possible. Apparently the cons in your matches is an issue with Seq. If you changes your xs to use List, it would work:
val xs: (Parent, (List[Int], List[Int])) = (Boy, (Nil, Nil))
EDIT:
It may be that you can use Seq but just have to pattern match on the construction slightly differently, like this:
xs match {
case (Boy, (Nil, Nil)) => 1
case (Boy, (_, Seq(x, _))) => 2
case (Boy, (_, Nil)) => 3
case (Girl, (Nil, Nil)) => 4
case (Girl, (Seq(x, _), _)) => 5
case (Girl, (Nil, _)) => 6
}

Related

Scala linked list

Making my first steps in Scala, I have run into the first misunderstanding.
I took a classic example of a linked list.
sealed trait List[+A] // `List` data type, parameterized on a type, `A`
case object Nil extends List[Nothing] // A `List` data constructor representing the empty list
/* Another data constructor, representing nonempty lists. Note that `tail` is another `List[A]`,
which may be `Nil` or another `Cons`.
*/
case class Cons[+A](head: A, tail: List[A]) extends List[A]
object List { // `List` companion object. Contains functions for creating and working with lists.
def sum(ints: List[Int]): Int = ints match { // A function that uses pattern matching to add up a list of integers
case Nil => 0 // The sum of the empty list is 0.
case Cons(x,xs) => x + sum(xs) // The sum of a list starting with `x` is `x` plus the sum of the rest of the list.
}
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] = // Variadic function syntax
if (as.isEmpty) Nil
else Cons(as.head, apply(as.tail: _*))
val x = List(1,2,3,4,5) match {
case Cons(x, Cons(2, Cons(4, _))) => x
case Nil => 42
case Cons(x, Cons(y, Cons(3, Cons(4, _)))) => x + y
case Cons(h, t) => h + sum(t)
case _ => 101
}
}
There are a few questions:
1) why custom linked List class doesn't conflict with built-in scala.collection.immutable.List.type
2) why a piece of code is supposed to be correct when we are matching built-in List to the custom linked list?
val x = List(1,2,3,4,5) match {
case Cons(x, Cons(2, Cons(4, _))) => x
case Nil => 42
case Cons(x, Cons(y, Cons(3, Cons(4, _)))) => x + y
case Cons(h, t) => h + sum(t)
case _ => 101
}
The custom linked-list class doesn't conflicts with the built-in scala.collection.immutable.List.type because local declarations, such as your custom List type, has higher precedence than an import (even non-explicit ones such as Scala's built-in List). See Chapter 2 of the Scala Specification for the full precedence order.
The referred matching code is not matching the built-in List, but your own locally declared List. You can see it yourself, by renaming your List to something like CustomList and see that some errors will appear, or to fully qualify the built-in List as the following code.
The following code actually matches the built-in List with your custom List structures and won't compile:
val x = scala.collection.immutable.List(1,2,3,4,5) match {
case Cons(x, Cons(2, Cons(4, _))) => x
case Nil => 42
case Cons(x, Cons(y, Cons(3, Cons(4, _)))) => x + y
case Cons(h, t) => h + sum(t)
case _ => 101
}
Your question is really about scope, I believe. You have defined your own List which is unrelated to that in scala.collection.immutable... The same with Cons and Nil.
When you instantiate the List in part 2), you are instantiating your List, not the one in the Scala library.
Or am I missing something?

Scala Pattern match on a list with at `#` symbol an extractor

I would like to access a reference of the first element
List(Some(1), None) match {
case x#Some(1) :: xs => x
case _ => None
}
res0: java.io.Serializable = List(Some(1), None)
The pattern matches correctly.
However I expected x to be the Some(1), that is the head of the list, and NOT the list itself.
How can I both use the extractors AND have a reference to the element?
I made it work just wrapping the element in parentheses
val lst = List(Option(1), None)
lst match {
case (x#Some(1)) :: xs => x
case _ => None
}
res0: Option[Int] = Some(1)
And it works also for multiple extractors!
val lst = List(Option(1),Option(2), None)
lst match {
case (x#Some(1)) :: (y#Some(2)) :: xs => y
case _ => None
}

Found error on using list in scala

I am using Scala for studying purpose
I wrote this code to sort the elements in list
def isort(xs:List[Int]):List[Int]=
xs match{
case List() => xs
case y::ys => insert(y,isort(ys))
}
def insert(x:Int,xs:List[Int]):List[Int]=
xs match{
case List() => List(x)
case y::ys => if(x<y) x::xs else y :: insert(x,ys)
}
but I am getting the following error:
Constructor can not be instantiated to expected type found Scala.collection.Immutable required List[Int]
in
`y::ys => insert(y,isort(ys))`
and similar error where I use ::
I refer tutorial : https://class.coursera.org/progfun-005/lecture
Try using the paste mode of the REPL. This will allow you to define the two defs in the same context:
scala> :paste
// Entering paste mode (ctrl-D to finish)
def isort(xs:List[Int]):List[Int]=
xs match{
case List() => xs
case y::ys => insert(y,isort(ys))
}
def insert(x:Int,xs:List[Int]):List[Int]=
xs match{
case List() => List(x)
case y::ys => if(x<y) x::xs else y :: insert(x,ys)
}
// Exiting paste mode, now interpreting.
isort: (xs: List[Int])List[Int]
insert: (x: Int, xs: List[Int])List[Int]

Return a different type according to an input parameter

Let's see an example (it's a naive example but sufficient to illustrate the problem).
def produce(l: List[Int]) : Any =
l match {
case List(x) => x
case List(x, y) => (x, y)
}
val client1 : Int = produce(List(1)).asInstanceOf[Int]
Drawback : client need to cast !
def produce2[A](l: List[Int])(f: List[Int] => A) = {
f(l)
}
val toOne = (l: List[Int]) => l.head
val toTwo = (l: List[Int]) => (l.head, l.tail.head)
val client2 : Int = produce2(List(1))(toOne)
Drawback : type safety, i.e. we can call toTwo with a singleton List.
Is there a better solution ?
If you only have two possible return values you could use Either:
def produce(l : List[Any]) : Either[Any, (Any, Any)] = l match {
case List(x) => Left(x)
case List(x, y) => Right((x, y))
}
If you don't want to create an Either, you could pass a function to transform each case:
def produce[A](l : List[Int])(sf: Int => A)(pf: (Int, Int) => A): A = l match {
case List(x) => sf(x)
case List(x, y) => pf(x, y)
}
Will this work?
def produce(l: List[Int]) = {
l match {
case List(x) => (x, None)
case List(x,y) => (x,y)
case Nil => (None, None)
}
}
or even better, to avoid match errors on lists longer than 2 elements:
def produce(l: List[Int]) =
l match {
case x :: Nil => (x, None)
case x :: xs => (x,xs.head)
case Nil => (None, None)
}

Generic type inference in Scala

I've written the following code, which is actually a dumb merge-sort implementation in scala:
import scala.collection.immutable.List
object MergeSort {
def sort[T,E]( comparator: (E,E) => Int ) (l: List[T]): List[T] = {
def merge[T](first: List[T], second: List[T]): List[T] = (first, second) match {
case (_, List()) => first
case (List(), _) => second
case (f::restFirst, s::restSecond) if comparator(f.asInstanceOf[E],s.asInstanceOf[E]) < 0 => f :: merge(restFirst, second)
case (f::restFirst, s::restSecond) => s :: merge(first, restSecond)
}
l match {
case List() => return l
case List(x) => return l
case _ => {
val (first, second) = l.splitAt( l.length / 2 )
merge( sort(comparator)(first), sort(comparator)(second) )
}
}
}
}
This is instead of the following, more elegant, solution:
import scala.collection.immutable.List
object MergeSort {
def sort[T]( comparator: (T,T) => Int ) (l: List[T]): List[T] = {
def merge[T](first: List[T], second: List[T]): List[T] = (first, second) match {
case (_, List()) => first
case (List(), _) => second
case (f::restFirst, s::restSecond) if comparator(f,s) < 0 => f :: merge(restFirst, second)
case (f::restFirst, s::restSecond) => s :: merge(first, restSecond)
}
l match {
case List() => return l
case List(x) => return l
case _ => {
val (first, second) = l.splitAt( l.length / 2 )
merge( sort(comparator)(first), sort(comparator)(second) )
}
}
}
}
Which doesn't compile, giving me the following error message:
MergeSort.scala:10: type mismatch;
[error] found : f.type (with underlying type T)
[error] required: T
[error] case (f::restFirst, s::restSecond) if comparator(f,s) < 0 => f :: merge(restFirst, second)
Why is the explicit cast necessary since the underlying type is T ?
This is one of the most annoying Scala gotchas I can think of (maybe after semicolon inference-related issues with operators). You're three characters from the correct answer.
The problem is the type parameter on merge. It introduces a new T that shadows the T type parameter on sort. The compiler therefore doesn't know that comparator can be applied to instances of that new T. You can boss it around with a cast, which is why your first version works, but otherwise it sees that T as a blank slate.
Just write def merge(first: List[T], ... and you'll be fine.