scala pattern matching - scala

It seems the type of Nil is not polymorphic. How do I correct this function:
scala> def last[A](a:List[A]) : A =
| a match {
| case _ :: tail => last(tail)
| case Nil => Nil[A]
| }
<console>:8: error: object Nil does not take type parameters.
case Nil => Nil[A]
UPDATE:
scala> def last[A](a : List[A] ) : Option[A] =
| a match {
| case head :: Nil => Some(head)
| case _ :: tail => last(tail)
| case Nil => None
| }

Nil is an object, not a type. So Nil[A] doesn't make any sense.
An empty list does not have a last element. As such invoking last on Nil should throw an error.
def last[A](l: List[A]): A = l match {
case x :: Nil => x
case _ :: tail => last(tail)
case Nil => sys.error("An empty list")
}
Alternatively you could have last return an Option[A] as shown below:
def last[A](l: List[A]): Option[A] = l match {
case x :: Nil => Some(x)
case _ :: tail => last(tail)
case Nil => None
}

The error is that you've declared the method to return A:
def last[A](a:List[A]) : A
^^^
and the empty list, Nil is not an A.
(And (as a side-note), as the error message says, Nil does not take type parameters.)
A better return type for a last function is probably Option[A]. Your method definition, but with Option[A] would look like:
scala> def last[A](a: List[A]): Option[A] =
| a match {
| case x :: Nil => Some(x)
| case _ :: tail => last(tail)
| case Nil => None
| }
last: [A](a: List[A])Option[A]

When you need to tell the compiler what type Nil should be, you can use type ascription, like this:
Nil: List[A]
But, as aioobe pointed out, this won't solve your problem. Nil is an empty list, not the last element of a list.

The object Nil extends List[Nothing]. Nothing is a sub-type of everything (similar as Any is the super-type of everything), and List is covariant (denoted as List[+A]), which means that Nil will fit as endpoint for every list.
However, as a result of this construction, there are situations where the compiler can't infer the correct type of an empty list, and you need to give a hint (as shown by Ben James). BTW, the same applies to the object None as sub-class of Option.

Related

Scala - head of empty list - removing all None's from a list of Options

Been trying to solve this for a while now. I need a recursive function that removes all None's from a list of Option[Int]'s, without using if-statements or using other functions.
def RemoveNone2(input: List[Option[Int]]) : List[Int] = {
input.head match {
case None => RemoveNone2(input.tail)
case _ => (input.head.get::RemoveNone2(input.tail))
}
}
val optional: List[Option[Int]] = List(Some(13), None, Some(32), None, Some(51), None, Some(17), None)
RemoveNone2(optional)
But when trying to execute the code, I get the following error:
java.util.NoSuchElementException: head of empty list
I suck at Scala, could anyone offer some insight?
You want headOption:
def RemoveNone2(input: List[Option[Int]]) : List[Int] = input.headOption match {
case None => RemoveNone2(input.tail)
case Some(head) => head :: RemoveNone2(input.tail)
}
A better way to write this is:
def removeNone(input: List[Option[Int]]) : List[Int] = input match {
case Nil => Nil
case Some(head) :: tail => head :: removeNone(tail)
case None :: tail => removeNone(tail)
An even better way is to use an accumulator, so that you can take advantage of tail-recursion:
def removeNone(input: List[Option[Int]], out: List[Int]=Nil) : List[Int] = input match {
case Nil => out.reverse
case Some(head) :: tail => removeNone(tail, head :: out)
case None :: tail => removeNone(tail, out)
}
You need to check that input list is empty to break the recursion. One of the options is to match against the list itself:
def RemoveNone2(input: List[Option[Int]]) : List[Int] = input match {
case head :: tail => head match {
case Some(value) => value :: RemoveNone2(tail)
case _ => RemoveNone2(tail)
}
case _ => Nil
}
Also note, that this implementation is not tail-recursive, whcih can lead to errors or poor performance for big collections. Tail-recursive implementation can look like that:
def RemoveNone2(input: List[Option[Int]]) : List[Int] = {
#annotation.tailrec
def inner(innerInput: List[Option[Int]], acc: List[Int]): List[Int] = innerInput match {
case head :: tail => head match {
case Some(value) => inner(tail, value::acc)
case _ => inner(tail, acc)
}
case _ => acc
}
inner(input, Nil)
}

Required return keyword

So I am relatively new to Scala and working through Functional Programming in Scala and just ran across something new in one of the practice problems. In hasSequences, I am required to place the return keyword in front of my return value or else nothing will return and the next line will execute. Why is this required?
def hasSubsequence[A](list: List[A], subList: List[A]) : Boolean = {
def matcher(l: List[A], sl: List[A]): List[A] = {
if (sl.isEmpty) return Nil
l match {
case Nil => Nil
case head :: tail if (head == sl.head) => head :: matcher(tail, sl.tail)
case head :: tail => matcher(tail, sl)
case _ => Nil
}
}
if (matcher(list, subList) == subList) true else false
}
It's required because Scala treats the return value as either the last value in the function, or a value following the return keyword. Since your example isn't the last thing in the function, how would Scala know you wanted to return it? Imagine a situation where you use a function with side effects which also has a return value. If you call the function without assigning the result to anything, there would be no way to determine if you wanted to return that value or not without these restrictions.
You could modify your function like this:
def hasSubsequence[A](list: List[A], subList: List[A]) : Boolean = {
def matcher(l: List[A], sl: List[A]): List[A] = {
if (sl.isEmpty) Nil
else l match {
case Nil => Nil
case head :: tail if (head == sl.head) => head :: matcher(tail, sl.tail)
case head :: tail => matcher(tail, sl)
case _ => Nil
}
}
if (matcher(list, subList) == subList) true else false
}
to avoid the return. Since this makes the match part of the same if statement as the return, it all becomes part of the latest statement, and you no longer need to explicitly return.

Difference between any and parametric polymorphism scala?

I know that parametric polymorphism is what actually works, but I'm curious why using Any in it's place does not. For example how is the first function
def len[T] (l:List[T]):Int =
l match {
case Nil => 0
case _ :: t => 1 + len(t)
}
different from this one?
def len (l:List[Any]):Int =
l match {
case Nil => 0
case _ :: t => 1 + len(t)
}
What do you mean it doesn't work? This seems fine:
len(List('a,'b,'c))
// res0: Int = 3
Your in your example, there really isn't a difference, since you're not actually using the contents of the list for anything, but imagine a slightly different function:
def second[T](l: List[T]): Option[T] =
l match {
case Nil => None
case _ :: Nil => None
case _ :: x :: _ => Some(x)
}
println(second(List(1,2,3)).map(_ + 5)) // Some(7)
println(second(List(List('a,'b,'c), List('d,'e))).map(_.head)) // Some('d)
If you tried this with Any, you wouldn't be able to get anything except Option[Any] in return, so the compiler wouldn't let you do anything useful with the result (like add it to an Int or call .head, as in the examples, respectively).
In this case there really isn't a difference, because you aren't relying on the contained type at all, just the structure of List itself. It doesn't matter what T is, the length will be the same either way.
The type parameter would be important if you wanted to return another List[T]. For example:
def takeEveryOther[T](l: List[T]): List[T] =
l.zipWithIndex.collect { case (a, i) if(i % 2 == 0) => a }

How to make Scala's type system catch this MatchError?

I've defined an ordering for Seq[Seq[T]] such that it's a normal lexicographic ordering except all items (sub-sequences) are reversed first (so that C,B,A comes before A,B,C but after A,B,A):
implicit def ReverseListOrdering[T: Ordering] = new Ordering[Seq[T]] {
override def compare(xs1: Seq[T], xs2: Seq[T]) =
doCompare(xs1.reverse, xs2.reverse)
private def doCompare(xs1: Seq[T], xs2: Seq[T]): Int = (xs1, xs2) match {
case (Nil, Nil) => 0
case (x :: _, Nil) => 1
case (Nil, x :: _) => -1
case (x :: xs, y :: ys) =>
val a = implicitly[Ordering[T]].compare(x, y)
if (a != 0) a else doCompare(xs, ys)
}
}
This used to be defined on List[List[T]] at first but I later realized I want it for all Seq[Seq[T]]; this is why I initially left in the Nils in the pattern matching block, while failing to realize Nil never matches e.g. an empty Array.
Later I tried to run this block of code:
// the Seq[String] declarations are needed; otherwise sample` will be Array[Object] for some reason
val sample = List(
List("Estonia"): Seq[String],
Array("Tallinn", "Estonia"): Seq[String],
List("Tallinn", "Harju", "Estonia"): Seq[String])
println(sample.sorted)
This compiles just fine but results in the following error at runtime:
scala.MatchError: (WrappedArray(Estonia, Tallinn),List(Estonia)) (of class scala.Tuple2)
— while I understand the cause of the error perfectly well, what I fail to understand (or at least accept) is, if the Ordering is successfully defined on all Seq[Seq[T]], yet a superficially valid but obviously incompatible (in terms of how doCompare is defined) Seq[Seq[T]] (i.e. Array[List[String] | Array[String]]) attempt to use that ordering results in no static type errors or even warnings whatsoever.
Is this caused by the fact that the pattern matching code is not statically verified to cover all possible "instances" of Seq[Seq[T]] and that it only handles the List case? If yes, what are the currently available workarounds to achieving type safety in such cases? Is Scalaz something to be looked at yet again for a decent solution?
P.S. I'm aware I could easily do away with a solution that works for all Seq[Seq[T]] by not using pattern matching and resorting to head and tail with an if-else block (or case statements if guards, which is only superficially nicer), but I'm keen to learn how to make the most of out Scala's type capabilities (AFAIK F# and Haskell catch these errors for breakfast); not to mention pattern matching is by far more elegant and readable.
This might be closer:
scala> def cmp[A, B[_] <: Seq[_]](xs: B[A], ys: B[A]) = (xs, ys) match { case (Nil, Nil) => true }
<console>:7: error: pattern type is incompatible with expected type;
found : scala.collection.immutable.Nil.type
required: B[?A1] where type ?A1 (this is a GADT skolem)
def cmp[A, B[_] <: Seq[_]](xs: B[A], ys: B[A]) = (xs, ys) match { case (Nil, Nil) => true }
^
There is a known syndrome when the type parameter is on the class instead of the method.
It has surfaced on the ML recently. Here.
Comparing to:
scala> (null: Seq[_]) match { case _: Nil.type => true }
scala.MatchError: null
... 33 elided
scala> (null: List[_]) match { case _: Nil.type => true }
<console>:8: warning: match may not be exhaustive.
It would fail on the following input: List(_)
(null: List[_]) match { case _: Nil.type => true }
^
scala.MatchError: null
... 33 elided
scala> (null: List[_]) match { case Nil => true }
<console>:8: warning: match may not be exhaustive.
It would fail on the following input: List(_)
(null: List[_]) match { case Nil => true }
^
scala.MatchError: null
... 33 elided
Sorry to be lazy, but off to bed.
Scala compiler produces non-exhaustive match warnings only for sealed types, which Seq isn't. AFAIK, there is no way to force it to check, like there is for tail recursion.
(AFAIK F# and Haskell catch these errors for breakfast)
Haskell doesn't have an equivalent to Seq; the code you used to have with List is the one which is equivalent to Haskell (modulo laziness), and Scala does catch the error in this case. I don't know F# well, but looking at http://msdn.microsoft.com/en-us/library/dd547125.aspx it seems that pattern matching a general IEnumerable<T> isn't supported.
Use code:
implicit def ReverseListOrdering[T: Ordering] = new Ordering[Seq[T]] {
override def compare(xs1: Seq[T], xs2: Seq[T]) =
doCompare(xs1.reverse, xs2.reverse)
private def doCompare(xs1: Seq[T], xs2: Seq[T]): Int = (xs1, xs2) match {
case (Seq(), Seq()) => 0
case (x +: _, Seq()) => 1
case (Seq(), x +: _) => -1
case (x +: xs, y +: ys) =>
val a = implicitly[Ordering[T]].compare(x, y)
if (a != 0) a else doCompare(xs, ys)
}
}
As I mention is comment Nil is not the same type as Seq(). For example WrappedArray is not a List. And when you use x :: xs - it is matched as List. Array("Tallinn", "Estonia") is converted to WrappedArray. Always use +: in pattern matching when you use Seq

How can i transform this scala function in order to be optimized

Code to determine the lat element of a list, using pattern matching:
#tailrec
def last_rec[A](list : List[A]) : A = {
list match {
case (x :: Nil) => x
case (_ :: xs) => last_rec(xs)
case Nil => throw new NoSuchElementException
}
}
I want to compile the code, I am getting "yelled" by the compiler:
PS D:\workspace\scala\P99> scalac .\P01.scala
.\P01.scala:18: error: could not optimize #tailrec annotated method last2: it contains a recursive call not in tail position
case Nil => throw new NoSuchElementException
^
one error found
If I remove the #tailrec annotation - the code compiles . How can I modify the code in order to do the tail rec optimization ?
You got a typo their. Your method is called last_rec and you are calling last which is clearly undefined. So just rename it to last. And by the way you should return Option[A] instead of A. That way you can return None when nothing is found instead of throwing the ugly NoSuchElementException.
After removing the typo and adding agilesteel's suggestion:
#tailrec
def last_rec[A](list : List[A]) : Option[A] = {
list match {
case (x :: Nil) => Some(x)
case Nil => None
case (_ :: xs) => last_rec(xs)
}
}
In this case I would do what agilesteel suggested.
However, if you really wanted to throw an exception (in another different use case), you could do it in a statically typed way:
#tailrec
def last_rec[A](list : List[A]) : Either[NoSuchElementException,A] = {
list match {
case (x :: Nil) => Right(x)
case (_ :: xs) => last_rec(xs)
case Nil => Left(new NoSuchElementException)
}
}
where later you could:
last_rec(Nil) match {
case Right(s) => println("Got a value")
case Left(e) => println("Got an exception")
}