You cannot pass parameters to a match, except implicitly, and the extractor should know what it needs to extract.
It is not possible to significantly simplify the solution. Here's an alternative way to record, but this is more a matter of preference than anything else.
object :>>: { def unapply(xs: List[Int])(implicit size: Int): Option[(List[Int], List[Int])] = if (xs.size >= size) Some(xs splitAt size) else None } object :<<: { def unapply(xs: List[Int]): Option[(List[Int], List[Int])] = xs match { case size :: rest => implicit val len = size rest match { case payload :>>: tail => Some((payload, tail)) case _ => None } case _ => None } } object Message { def unapplySeq(xs: List[Int]): Option[List[Int]] = xs match { case 0xFC :: payload :<<: 0x0A :: 0x0D :: Nil => Some(payload) case _ => None } }
Edit: Note the colons on the methods :<<: and :>>: They are not needed for the latter in this code, but they are necessary for the former.
The colon at the end of the identifier refers to left and right associativity. This is important because the argument to the right of :: and :<<: must be a List , but 0x0A and 0x0D are not lists. However, right associativity means that the rightmost operator is applied first, and the left ones are applied to the result. In other words. 0x0A :: (0x0D :: Nil) instead of (0x0A :: 0x0D) :: Nil .
The colon at the beginning of the identifier is required due to priority. Even with the correct associativity, the wrong priority would turn 0xFC :: payload <<: ... into (0xFC :: payload) <<: ...
Note that I use unapplySeq to return the results in Message , so they can be retrieved, as in List . This means, however, that you need @ _* to get the whole sequence:
scala> List(0xFC, 0x03, 0x01, 0x02, 0x03, 0x0A, 0x0D) match { | case Message(z @ _*) => println (z) | case _ => println("No match") | } List(1, 2, 3)