1
votes

I was writing an assignment from Coursera and I met a problem about Scala Pattern Matching.

The book "Programming in Scala" has the following code:

expr match { 
    case List(0, _ * ) => println("found it") 
    case _ => 
}

So I wrote a similiar code to calculate the frequency of each character in a list:

/**
 * This function computes for each unique character in the list `chars` the number of
 * times it occurs. For example, the invocation
 *
 *   times(List('a', 'b', 'a'))
 *
 * should return the following (the order of the resulting list is not important):
 *
 *   List(('a', 2), ('b', 1)) */
 def times(chars: List[Char]): List[(Char, Int)] = {
   def addTime(char: Char, times: List[(Char, Int)]):List[(Char, Int)] = times match {
     case List(head @ (_*), (c , times), tail @ (_*)) if c == char => List(head, (c, times + 1), tail)
     case _ => List((char, 1))
 }

   if(chars.isEmpty) Nil else addTime(chars.head, times(chars.tail))
}

However, the compiler complains:

Error:(81, 29) bad simple pattern: bad use of _* (sequence pattern not allowed)
    case List(head @ (_*), (c , times), tail @ (_*)) if c == char => List(head, (c, times + 1), tail)

Though I successfully implemented this method in another way, with the help of 2 helper functions, I did not know why does this sequence pattern was not allowed. I tried to Google but I could not find an answer.

Any suggestion will be appreciated. Thanks in advance.

1
I had a bit of a hard time understanding, what your code should express, and I guess I finally found out (the line with 2 times the '@' symbol): match a list where somewhere a tuple (c, n) has a c, matching (char). I'm not really familiar with the @-Syntax and its use cases, but have never seen a multiple, variable length matching like this of head and tail - beside to note, that the data structure does not guarantee for only a single match in c. Since I suspect, that you're more interested in the _* - thingy, I don't post my own solution (foldLeft + pattern matching) - user unknown
@userunknown Thank you, buddy. What you said is exactly what I want to match. The reason is that _* is not allowed to be used at the head, as you suggested. - pikatao

1 Answers

3
votes

Any pattern match only decomposes the original value in at most one way. If case List(head @ (_*), (c , times), tail @ (_*)) was legal, it would allow many options for head, c, times, and tail. Your intention seems to be that all of these ways are tried in order, and matched when the guard c == char becomes true, but this is not how Scala pattern matching works.

In fact, to make rules simple, _* is only allowed at the end. Something like List(_*, c) could be reasonably allowed, but it isn't.