Question

I have a recursive function count in Scala 2.9.2 that looks like this

def count(traces: Seq[(Char, Char)], acc: (TP, TN, FP, FN)): (TP, TN, FP, FN) = {
  val (tp, tn, fp, fn) = acc
  traces match {
    case Nil => acc
    case ('(', '(')::rest => count(rest, (tp + 1, tn, fp, fn))
    case (')', ')')::rest => count(rest, (tp + 1, tn, fp, fn))
    case ('(', ')')::rest => count(rest, (tp, tn + 1, fp, fn))
    // ... exhaustive set of cases ...
  }
}

On input Seq(('(', '(')) the function throws the following MatchError:

scala.MatchError: Vector(((,()) (of class scala.collection.immutable.Vector)

I investigated this by playing around with the code in the Scala console.

scala> val t = Seq(('a', 'b'), ('b', 'c'))
t: Seq[(Char, Char)] = List((a,b), (b,c))

scala> t match { case Nil => "h"; case ('a', 'b')::rest => rest }
res6: java.lang.Object = List((b,c))

scala> t1 match { case Nil => "h"; case ('a', 'b')::rest => rest }
scala.MatchError: List((b,c)) (of class scala.collection.immutable.$colon$colon)

It seems as if matching ('a', 'b')::rest (the second line) doesn't return an object of the correct type, since the Seq[(Char, Char)] is suddenly of type java.lang.Object which Scala then doesn't know how to match on.

What explains this behavior?

Was it helpful?

Solution

The problem with your pattern matching is that you use extractors defined only for List class but passing to them Vector.

If you really need to match against every possible Seq, you may want to use general syntax:

   foo match {
     case Seq('(' -> ')',rest@ _* ) => println("The tail is" + rest)
   }

(Don't be confused with -> arrow, 1 -> 2 is essentially the same as (1,2), but in this particular case much more readable: you will not mess usual braces with '(' and ')' like in Seq(('(',')'), ... ))

Otherwise, just strict your argument type to List[(Char, Char)].

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top