I recently wrote a parser using scala's parser combinator library. I decided I was curious about the implementation, and went digging.
While reading through the code, I saw that ~ sequencing used a case class to hold the left and right values.
Attached is the following comment:
/** A wrapper over sequence of matches.
*
* Given `p1: Parser[A]` and `p2: Parser[B]`, a parser composed with
* `p1 ~ p2` will have type `Parser[~[A, B]]`. The successful result
* of the parser can be extracted from this case class.
*
* It also enables pattern matching, so something like this is possible:
*
* {{{
* def concat(p1: Parser[String], p2: Parser[String]): Parser[String] =
* p1 ~ p2 ^^ { case a ~ b => a + b }
* }}}
*/
case class ~[+a, +b](_1: a, _2: b) {
override def toString = "("+ _1 +"~"+ _2 +")"
}
Given that such code as mentioned is certainly possible, and that parsers defined using a ~ b can be extracted into values via { case a ~ b => ... }, how exactly does this un-application work? I am aware of the unapply method in scala, but none is provided here. Do case classes provide one by default (I think yes)? If so, how does this particular case class become case a ~ b and not case ~(a,b)? Is this a pattern that can be exploited by scala programmers?
This differs from objects with unapply in this question because no unapply method exists–or does it? Do case classes auto-magically receive unapply methods?