I have an enum defined as follows
enum Operator[T](val expr: String, val tag: T):
case Plus(override val tag: T) extends Operator(" ", tag)
case Minus(override val tag: T) extends Operator("-", tag)
case Multiply(override val tag: T) extends Operator("*", tag)
Next is a function call that checks whether the passed list of operators starts with a certain operator or not
def extract[A](expect: Operator[A], operators: List[Operator[A]]): Either[Error[A], (Operator[A], List[Operator[A]])] =
operators match {
case `expect` :: tail => Right(expect, operators.tail)
case _ =>
expect match {
case Plus(_) => Left(Error.ExpectPlus(operators))
case Minus(_) => Left(Error.ExpectMinus(operators))
case Multiply(_) => Left(Error.ExpectMultiply(operators))
}
}
But when I call the function with the following parameter, I get the error as below
extract(Plus(_), operators)
^^^^^^^^^^^^^^^
[error] | Found: Any => Operator[Any]
[error] | Required: Operator[Any]
Can anyone help me explain why using _ as a parameter is interpreted as Any => [Any], is there any way to solve this error?
Here is the snippet: https://scastie.scala-lang.org/XLrcrUBvSneJs60w87k43A
CodePudding user response:
What you wrote is the same as below:
extract(x => Plus(x), operators)
// Same as:
extract(Plus(_), operators)
Meaning Plus(_)
defines a function, which is not what extract
expects.
CodePudding user response:
This is actually a complement to @Luis Miguel Mejía Suárez's comment and @Gaël J's answer. As stated earlier in the comments and answers, you're actually passing a function, not an Operator
instance to your extract function. I think what you intended to do, was to use a wildcard for the tag in Plus
(of course this is not a wildcard, this results in a function). And based on these assumptions, I think what you're looking for is type matching. So this needs a little bit of refactoring, now this code is written in Scala 2, but the concepts should be pretty much applicable to Scala 3 as well:
// I have defined the Operator as sealed abstract class earlier, and all the subtypes
sealed trait Err[OP <: Operator[_]]
object Err {
def apply[T <: Operator[_]]: Err[T] = new Err[T] {} // In Scala3 you can easily do type matching here
}
import scala.reflect.ClassTag
def extract[A, OperatorType <: Operator[A] : ClassTag](operators: List[Operator[A]]): Either[Err[OperatorType], (Operator[A], List[Operator[A]])] = {
operators match {
case (head : OperatorType) :: tail =>
Right(head, tail)
case _ => Left(Err[OperatorType])
}
}
val ops: List[Operator[Int]] = List(Plus(2), Minus(4), Multiply(7))
val shouldFail = extract[Int, Minus[Int]](ops) // fails since first element is not of type Minus
val shouldSucceed = extract[Int, Plus[Int]](ops) // succeeds
On scastie.