I am trying to match all binary operators in a single case
clause, but the following code gives the error:
object BinOp is not a case class, nor does it have a valid unapply/unapplySeq member
Note: def unapply(a: AST.this.Expr, b: AST.this.Expr): Option[(AST.this.Expr, AST.this.Expr)] exists in object BinOp, but it cannot be used as an extractor as it has more than one (non-implicit) parameter.
Core code to traverse the tree:
tree match {
case ... other ... cases
case BinOp(a, b) => traverse(a), traverse(b)
}
The AST classes are as follows:
sealed trait Expr
case class Num(value: java.lang.Number) extends Expr
sealed trait BinOp extends Expr {
val a, b: Expr
}
object BinOp {
def unapply(a: Expr, b: Expr): Option[(Expr, Expr)] = Some(a, b)
}
case class Add(a: Expr, b: Expr) extends BinOp
case class Sub(a: Expr, b: Expr) extends BinOp
case class Mul(a: Expr, b: Expr) extends BinOp
case class Div(a: Expr, b: Expr) extends BinOp
The code segments are hugely simplified for illustration purposes.
It looks like you have a misconception about how extractor objects work. You can think of unapply
as the dual of apply
, although it isn't always so.
Suppose instead of having Add
as a case class with the apply
method already made for you, you made it an ordinary class and put the apply
method in a companion object:
object Add {
def apply(a: Expr, b: Expr): Add = ???
}
The unapply
method is just that, but with the input and output types switched (and inside an Option
).
//Could also be a Some[(Expr,Expr)], as far as I can tell
def unapply(add: Add): Option[(Expr, Expr)] = (add.a, add.b)
Since the output of the apply
method is just one value, the input of your unapply
method is a single value, and since the apply
method has multiple inputs, the unapply
method has multiple outputs, or pretends to do so by using a tuple. There's a little more to it, but this page from the documentation will be in more in depth than I.
Edit: @jwvh has pointed out that you don't need to return an Option
from an unapply
method - it can be any type with the methods isEmpty
and get
.
Since you also mentioned that you want to abstract over any sort of node that contains other nodes, I'd like to point out that if you're going to use pattern matching, you'll still have to make your own unapply
method for each sort of node (or make it a case class).