3

So I read about right-associative operators like the cons operator in Scala. I'm wondering why they work in case statements. It seems like you can pattern match using the cons statement here?

def findKth1[A](k:Int, l:List[A]):A = (k, l) match {
    case (0, h::_) => h
    case(k, _::tail) if k > 0 => findKth1(k - 1, tail)
    case _ => throw new NoSuchElementException
}

findKth1(2, List(3,4,5,6))  

res1: Int = 5

What is the placeholder doing here? I've only seen placeholders used in functions like this: <SomeList>.map(_.doThing). Is it the same concept?

The only difference with :: and ::: is that ::: is used for 2 Lists right?

Jwan622
  • 11,015
  • 21
  • 88
  • 181
  • 1
    What do you mean by "placeholder" exactly? `_` ? That just means you don't actually want to bind what would go there to an actual named binding. The first case there is matching only on the head; the second is matching only on the tail, and the last case is the default case. – Ricky Mutschlechner May 08 '18 at 18:30
  • 1
    Is this pattern matching on a tuple actually? – Jwan622 May 08 '18 at 18:31
  • 1
    Possible duplicate of [What are all the uses of an underscore in Scala?](https://stackoverflow.com/questions/8000903/what-are-all-the-uses-of-an-underscore-in-scala) – Andy Hayden May 08 '18 at 18:36
  • 1
    @Jwan622 yes. Looks like it. I can't edit my original comment but "only on the head" was referring to the 2nd element in the tuple. – Ricky Mutschlechner May 08 '18 at 18:39

1 Answers1

5

tl;dr It isn't pattern matching the operator, it's pattern matching a case class called ::

There are a couple of things happening at the same time. First of all, there may be a bit of confusion, because :: is a method on List:

val x: List[Int] = 1 :: 2 :: 3 :: Nil

But there is also a case class :: that, according to the docs is:

A non empty list characterized by a head and a tail.

More info here

Scala's case classes automatically come with extractor methods(unapply), which allow pattern matching, as in case User(name, age) => ....

You are also allowed to use the case class name in an infix position (although you shouldn't do so, except when the case class is used like an operator, such as in this case). So case head :: tail => ... is the same as case ::(head, tail) => .... More info here

When pattern matching, you can use _ to mean that there will be a value there, but you don't care about it, so you aren't providing it a name.

So the three cases you provided are roughly:

  • A tuple where the first value is 0, and the second value is a list with a head to be called h, and a tail which we will ignore.
  • A tuple with some integer to be called k, and a list with a head that we don't care about, and a tail, which we will call tail. Also, k must be greater than 0
  • Anything else, then throw a NoSuchElementException
GatorCSE
  • 158
  • 5
  • quick question, I didn't realize the case statements here were the same thing as case classes... – Jwan622 May 09 '18 at 18:37
  • yeah, the `case` keyword having multiple uses _can_ be a little confusing, but it looks good when you are using it to match on a case class. – GatorCSE May 14 '18 at 16:30