3
votes

I'm currently playing around with Scala's pattern matching. What I know so far is, that an extractor named like an operator gets left associative and an extractor named like a method or type is right associative.

My current approach looks something like this:

object Foo {
  def unapply(tokens: Seq[String]): Option[(Seq[String], String)] = // do something
}

// ...

object Main extends App {
  Seq("hi", "bye") match {
    case xs Foo foo2 Foo foo1 => // do something with result
    case _ => // handle error
  }
}

This is somewhat unpleasuring as it requires me to write my matches reverse or matching them reverse due to the right associativity. I would prefer if I could write something like this:

object Foo {
   def unapply(tokens: Seq[String]): Option[(String, Seq[String])] = // do something
}

// ...

object Main extends App {
  Seq("hi", "bye") match {
    case foo1 Foo foo2 xs => // do something with result
    case _ => // handle error
  }
}

Is there any way to keep some readable name for an extractor and make it left associative?

Thanks in advance.

2

2 Answers

5
votes

You need to end your class' name with an :.
From the Scala Specifications (Infix Operations, 6.12.3) :

The associativity of an operator is determined by the operator’s last character. Operators ending in a colon ‘:’ are right-associative. All other operators are left-associative.

This way:

scala> object `Foo:` {
         def unapply(tokens: Seq[String]): Option[(String, Seq[String])] =
           Some((tokens.head, tokens.tail))
       }
defined object Foo$colon

scala> Seq("hi", "bye", "world") match {
         case foo1 `Foo:` foo2 `Foo:` foo3 =>  println(s"$foo1 $foo2 $foo3")
       }
hi bye List(world)

Unfortunately you need to use backticks, as Foo: is not a valid identifier.

0
votes

I am not sure if I get the question right, but I think you are asking for something like this:

object Foo {
  def unapply(tokens: Seq[String]): Option[(String, Seq[String])] =
      Some((tokens.head, tokens.tail))
  }

// ...

object Main extends App {
  Seq("hi", "bye") match {
    case foo1 Foo foo2 =>  println(s">> $foo1 $foo2")
    case _ => println("error") // handle error
  }
}