WeBWorK Problems

extra parens when a function outputis negated

extra parens when a function outputis negated

by Alex Jordan -
Number of replies: 3

The observed issue:


If I set
$a = Formula("-sqrt(x)");

and then when I print `$a`, what comes out is

{-\left(\sqrt{x}\right)}


The parentheses are undesirable. The same happens with -sin(x), -ln(x), etc. so this is not specific to sqrt.

What I've been able to turn up so far:

I have tracked this down to:
https://github.com/openwebwork/pg/blob/5083fea21171623bb649b68ecaebd03176ff9af8/lib/Parser/Function.pm#L310

In this situation, the unary minus has a property `precedence` that  is 6 and the function sqrt has a property called `parenPrecedence` that is 5. Because the 6 is greater than the 5, parentheses are inserted. Also worth noting, the function also has a property `precedence` that is 2.9, but that is not relevant for inserting the parens.

These properties are set at:
https://github.com/openwebwork/pg/blob/5083fea21171623bb649b68ecaebd03176ff9af8/lib/Parser/Context/Default.pm#L84

There are some things I do not understand. Maybe the most fundamental is why is the precedence for a function so low (2.9)? If I make Formula("sqrt4^3"), I get 8. So it is giving the sqrt higher precedence than the ^, which is what I would expect. And yet sqrt has precedence 2.9 and ^ has precedence 7. So I do not understand something fundamental there.

But the underlying question is, could we change things so that Formula("-sqrt(x)") comes out by default without extra parens? Is there some reason that would have a bad side effect? If I understood Function.pm#L310 better, that would help.

In reply to Alex Jordan

Re: extra parens when a function output is negated

by Davide Cervone -

The precedence situations is a but complicated. The precedences listed in the Context/Default.pm file are not actually the ones used in WeBWorK. They were experimental ones that I was using to try to make things like sin 2x produce sin(2*x) rather than sin(2)*x (which is why the function precedence is slightly lower than multiplication). It's also the reason that there are definitions for ' *', '* ', ' /', and '/ ', since spacing made a difference in that setting (e.g., sin 2x / 3 was parsed as sin(2*x)/3 while sin 2x/3 was sin(2x/3).

This turned out to be too complicated, and since it didn't correspond to the original WeBWorK parser (now long retired, but still in use when mathObjects were developed), I added the ability to switch all the precedences to match the original WeBWorK parser. That is done by the usePrecedence() call at line 268. That method is defined here. So the actual precedence of function application is 7.5, and of multiplication and division is 3 (while negation is precedence 6, as you indicate).

On the other hand, the function precedence is really only used for function application where the argument is not contained in parentheses, like sin x, as sin(x) is parsed without the need of precedence values. Since functions are always displayed with parentheses, the precedence of 7.5 is really meaningless, as you indicate. So parentheses around functions are controlled by a separate parentheses, the parenPrecedence, which is set to 5 by default, as you point out. Since 6 is bigger than 5, the unary minus shows parentheses for -[sin(x)] to make it absolutely clear what is being negated, as you note.

If you don't want these to show, you can change the function application's parenthesis precedence:

Context()->operators->set(fn => {parenPrecedence => 6.5});

This will display -sin(x) rather than -[sin(x)], but still show [sin(x)]^2 rather than sin(x)^2 (the precedence of ^ is 7).

So long story short, you can change the parentheses with the line above.

In reply to Davide Cervone

Re: extra parens when a function output is negated

by Alex Jordan -
Thanks Davide for that explanation. I get it now.

I'm wondering if you can think of any reason not to change that parenPrecedence value globally. Other than an abundance of caution. On our server, maybe I will make that change to Parser/Context/Default.pm and see if it leads to bad side effects. But then I wonder if it would make sense to change it in the distribution too.
In reply to Alex Jordan

Re: extra parens when a function output is negated

by Davide Cervone -

It should not lead to any problems, and should only affect unary plus and minus. The parser tries to make student answers painfully unambiguous, so that is why it was set up this way. There are other places where parentheses are used when not specifically necessary, for that reason. But if you want to change it, it should not be a problem.