I am trying to write a recursive program for comparing a int to each value in a list. Problem is I keep getting a unreachable error, and I really don't know why. My code is
def isIn(x : Int, l : List[Int]) : Boolean = l match {
case Nil => false
case x => true
case h :: t => isIn(x, t)
}
I really don't understand why this doesn't work. Or i guess, I am wondering how to compare x to the head using case.
The issue is that when you use a variable that starts with a lowercase character, the pattern matcher thinks that you are trying to assign to a new variable. Of course, a pattern that is simply an assignable variable will match anything, so any subsequent case will be unreachable.
To solve this, you need to use a "stable identifier". This can be done by putting the lowercased variable in backticks:
def isIn(x: Int, l: List[Int]): Boolean =
l match {
case Nil => false
case `x` :: t => true
case h :: t => isIn(x, t)
}
or renaming the variable so that it starts with an uppercase character:
def isIn(X: Int, l: List[Int]): Boolean =
l match {
case Nil => false
case X :: t => true
case h :: t => isIn(X, t)
}
Note that since each case must be a List, you need to have the :: t after x to show that x should be matching the head of the List.
Related
Say you wish to use pattern matching when calling a method with varargs like so:
def foo(bar: Int*) = ???
val x = false
foo(x match {
case true => 1
case _ =>
})
Running the above code results in type mismatch error, since foo requires an argument of type Int but found Unit instead in the default case. Removing the default case, on the other hand, results in a warning that the match may not be exhaustive, and rightfully so.
My question is, how do I supply an empty default case for the match (which would result in calling foo() without any arguments)?
You could capture the match result in a sequence and represent the lack of arguments as an empty one. Then just splat the result into the parameter:
val x = true
foo((x match {
case true => Seq(1)
case _ => Seq.empty
}):_*)
One option would be to use an Option[Int] instead of an Int:
def foo(bar: Option[Int]*) = ???
val x = false
foo(x match {
case true => Some(1)
case _ => None
})
I think an if-else expression would be less verbose here:
foo(if (x) Some(1) else None)
I'd argue though that if you're matching over a single Boolean there's no point in passing varargs at all.
While practicing scala, I am trying to insertion-sort an integer list using pattern matching. Previously, the following code for printing the list worked absolutely fine:
object PrintList {
def iPrint(xs: List[Int]):Unit = xs match {
case x :: ys => {
print(x+" -> ")
iPrint(ys)
}
case _ => println("Nil")
}
def main(args: Array[String]) {
//val l = Nil.::(1).::(2).::(3).::(4)
val l = 4 :: 3 :: 2 :: 1 :: Nil
iPrint(l)
}
}
However, the following code to sort a list doesn't compile:
def insert(x : Int, l1 : List[Int]):List = {
//stubbed
List()
}
def iSort(l : List[Int]):List = l match {
case x :: ys => insert(x , iSort(ys))
case Nil => Nil
}
Am I missing something really trivial here??
EDIT:
Modified the code as below:
def insert(x : Int , l1 : List[Int]):List[Int] = {
//stubbed
List(0)
}
def iSort(l : List[Int]):List[Int] = l match {
case (x:Int) :: (ys:List[Int]) => insert(x , iSort(ys))
case _ => List(0)
}
Still getting error in the first case statement - Pattern type is incompatible with expected type. Found: ::[B], expected: List[Int]
Using Intellij Idea with scala plugin - 2.11.7.
Looking at your screenshot, you are defining your own List class in that same package Week04. It's visible in your project browser on the left-hand side. So in your code
def iSort(l: List[Int]) = ???
you have an argument of type Week04.List[Int]. You try to destructure that using the :: list-cons class. I presume you have not defined your version of ::, least I don't remember that this was defined the Coursera class. So you have a scala.:: here which is a sub-type of scala.List. So you are trying to pattern match against some completely different type. If you replaced every occurance of List with scala.List you would use Scala's standard list class instead and it should work. If you want that to work with your own list implementation, you need to define your own extractor.
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 }
Trying to create a method that determines if a set is a subset of another set, both given as parameters. When I tried to test it the console printed out
scala.MatchError : (List(1, 2, 3, 4, 5, 6, 7),List(1, 2, 3, 4)) (of class scala.Tuple2),
the two lists given are what I was using as parameters to test it. Also, scala was making me type out return in front of true and false, any ideas what led to this either?
def subset(a: List[Int], b: List[Int]): Boolean ={
(a,b) match {
case (_,Nil)=> return true
}
b match {
case h::t if (a.contains(h)) => subset(a,t)
case h::t => return false
}}
The other answers don't really answer exactly why your code is incorrect. It appears that you're handling the case when list b is empty and non-empty and that everything should be okay, but in fact you're actually not. Let's look at your code again, with some formatting fixes.
def subset(a: List[Int], b: List[Int]): Boolean = {
(a, b) match {
case (_, Nil) => return true
} // we can never make it past here, because either we return true,
// or a MatchError is raised.
b match {
case h :: t if (a.contains(h)) => subset(a,t)
case h :: t => return false
}
}
The real problem here is that you have two completely disconnected match statements. So when b is non-empty, the first match will fail, because it only handles the case when b is Nil.
As pointed out in the other solutions, the proper way to do this is to merge the two match statements together into one.
def subset(a: List[Int], b: List[Int]): Boolean = {
(a, b) match {
case (_, Nil) => true
case (xs, head :: tail) if(xs contains head) => subset(xs, tail)
case _ => false
}
}
Notice how the return statements are no longer needed. In scala you should avoid using return as much as possible, as it's likely that your way of thinking around return actually lead you into this trap. Methods that return early are likely to lead to bugs, and are difficult to read.
A cleaner way to implement this could use diff. b can be considered a subset of a if the set of elements of b minus the elements of a is empty.
def subset(a: List[Int], b: List[Int]): Boolean = (b.distinct diff a.distinct).nonEmpty
distinct is only required if it's possible for a and b to contain duplicates, because we're trying a List like a Set when it's actually not.
Better yet, if we convert the Lists to Sets, then we can use subsetOf.
def subset(a: List[Int], b: List[Int]): Boolean = b.toSet.subsetOf(a.toSet)
Scala match expression should match to at least one case expression. Otherwise the MatchError is raised.
You should have used the following cases:
(a, b) match {
case (_, Nil) => true
case (aa, h :: t) if aa contains h => subset(aa, t)
case _ => false
}
An alternative way could be to call methods in standard library.
For each element in 'b', check if 'a' contains that element.
Here is the simple code:
def subset(a: List[Int], b: List[Int]): Boolean = {
(b.forall(a.contains(_)))
}
MatchError - This class implements errors which are thrown whenever an object doesn't match any pattern of a pattern matching expression.
Obviously the second list having elements in it will cause this error, as no pattern will match. You should just add another branch to the first match like so:
def subset(a: List[Int], b: List[Int]): Boolean = {
(a, b) match {
case (_, List()) => return true
case _ => b match {
case h :: t if (a.contains(h)) => subset(a, t)
case h :: t => return false
}
}
}
MatchError occurs whenever an object doesn't match any pattern of a pattern matching expression.
An alternative way is by using dropWhile or takeWhile
def subsets(a:List[Int], b:List[Int]):Boolean = {
return b.dropWhile { ele => a.contains(ele)}.size==0
}
OR
def subsets(a:List[Int], b:List[Int]):Boolean = {
return b.takeWhile { ele => a.contains(ele)}.size==b.size
}
I have to find if an element is inside a list using scala, and I am only allowed to use recursion. Why is the following code not working, as the match statement seems to be correct to me. My IDE gives me an error on all three case statements and it says type, mistmatch, boolean required.
def isInN(x: Int, l: List[Int]): Boolean = (l,l.head) match {
case Nil,_ => false
case _,x => true
case _,_ => isInN (x,l.tail)
}
You're matching a tuple, so you need to use a proper tuple extractor. i.e. just add parenthesis:
def isInN(x: Int, l: List[Int]): Boolean = (l, l.head) match {
case (Nil, _) => false
case (_, x) => true
case (_, _) => isInN (x, l.tail)
}
This compiles, but won't quite work like you want it to. l.head will throw an exception if the list is empty. And x within the match will eagerly match anything, so the last case can never be reached. To match against an identifier, you need to surround it with backticks, otherwise it will just be a placeholder matcher.
To use a similar pattern match without calling l.head, you can pattern match on the List itself:
def isInN(x: Int, l: List[Int]): Boolean = l match {
case Nil => false
case `x` :: _ => true
case head :: tail => isInN (x, tail)
}
Though this is all trumped by contains in the standard collections library:
scala> List(1, 2, 3, 4).contains(2)
res5: Boolean = true