Trying to make a DSL for algebraic equations. Operator precedence not cooperating


#1

I’m trying to make a DSL for defining algebraic equations. Given that this is the order of infix operation precedence in scala:

(all letters)
|
^
&
= !
< >
:
+ -
* / %
(all other special characters)

This doesn’t work well for algebraic equations as:

  1. ^ is defined with lower precedence than + and *. So using it for exponentiation results in a lot of parenthesis.
  2. If I wanted to use ** for exponentiation, it seems to have equal precedence to *. Again resulting in a lot of parenthesis.
  3. I also tried /\ but this seems like it also has the same precedence as *.

This kind of destroys the elegance of having a DSL, if you have to parenthesize everything.

So is there anything I can do to get around this infix operator precedence?

If nothing can be done in current scala; I did have one idea for a future version. Perhaps making it so an operator of the same symbol repeated would have higher precedence than one of the same symbol repeated fewer times.

So ** would have higher precedence than *, for example.

Please let me know what you think. Thanks.


#2

AFAICT, there’s nothing you can do now. Your idea for the future is also unrealistic, as it would inevitably silently break existing code.


#3

Plus I’m sure there are people with usecases for e.g. ++ to have lower precedence than +.


#4

Isn’t there something in the “(all other special characters)” category you can use?


#5

You can use a pretty unicode arrow to point the exponent to its place.

scala> implicit class PowSyntax(n: Int) { def ⬑(x: Int) = math.pow(n, x) }
defined class PowSyntax

scala> 4*3⬑2
res0: Double = 36.0

#6

Looks like an extremely dirty hack around synonymity in real life (like a tradition of denoting both power and bitwise xor with ^) and fact that operators naming rules in the language declare that synonymity is unwanted for operators.


#7

It seems like the united states keyboard layout does not contain such symbol.

It would be pretty funny…
Of cause if you use
https://autohotkey.com/
and keyboard stickers
:))


#8

or maybe and

implicit class PowerDouble(d: Double)  {
  def ⁺(that: Double) = math.pow(d, that)
  def ⁻(that: Double) = math.pow(d, - that)
}

4*3⁺2 //36.0
4*3⁻2 //0.4444444444444444

#9

Have you already considered Macros?


#10

I’m not familiar with macros so no. How could they help in this situation?


#11

You could use quasiquotes. So you write dsl" $a * $b ** $c " and inside the quote you can define your own parsing rules and precedences. If the types of things inserted into the quote are homogenous and the quote always returns the same type, you don’t even need a macro.