¿Por qué no puedo encadenar varias llamadas al método infijo de Scala?
-
29-10-2019 - |
Pregunta
Estoy trabajando en un DSL y me he encontrado con un problema al usar métodos como operadores infijos en una cadena.Intentaré explicarlo con algún código.Tengo un rasgo Term
y clases de caso Literal
y Variable
extendiéndolo.Quiero construir una lista de instancias de términos usando algunos operadores.
case class Expr(val terms: List[Term]) {
def +(v: String) = Expr(Literal(v) :: terms)
def -->(func: List[String] => List[String]) = terms match {
case Literal(v) :: ts => Expr(Variable(v, func) :: ts)
case _ => throw new Exception("Can only apply function on literal")
}
}
object foo {
def bar(name: String) = Expr(Literal(name) :: Nil)
}
// some functions
val one = ...
val all = ...
// works
foo bar "x"
// res1: Expr = Expr(List(Literal(x)))
// works not
foo bar "x" --> all
// error: value --> is not a member of java.lang.String
// works
(foo bar "x") --> all
// res1: Expr = Expr(List(Variable(x,<function1>)))
Esperaría que esto fuera equivalente a foo.bar("x").-->(all)
, pero el intérprete parece verlo como foo.bar("x".-->(all))
.
Solución
Puede encontrar precedencia de operadores aquí:
Precedencia del operador en Scala
De acuerdo con la primera respuesta -
tiene mayor prioridad en comparación con las letras.Entonces, los grupos de compiladores expresan como esta:
foo bar ("x" --> all)
Si reemplaza -->
con algo de menor prioridad (por ejemplo, letras), entonces debería compilarse.Por ejemplo:
foo bar "x" to all
También puede elegir un operador de mayor prioridad en lugar de bar
.Algo como ~~>
lo hará, porque ~
es un carácter especial y tiene la máxima prioridad:
foo ~~> "x" --> all