David:
I don't know anything about MapleTA, but if you are writing your
modespecific code in Perl, then you might consider using the new
parser code that I wrote for WeBWorK. It is actually a standalone
library (actually two libraries) that you could incoporate into other
Perl programs, as all the WeBWorKspecific material has been isolated
in one file that you would not load. That would save you a lot of work
(unless you have already written your own). To do this, you would need
to the Parser and Value directory trees from the webwork pg/lib
directory, plus Value.pl and Parser.pl from the pg/macros directory.
You would need to modify these latter slightly to remove a few WeBWorK
items (and put back a few commented out items), but that part is not
hard. The parser already implements interval notation and unions of
intervals, vectors and points, matrices, complex numbers, and
infinities, but it doesn't do set notation, though that could probably
be added.
One of the design goals for the new parser was to allow it to be
extendable, so you can add (or remove) operators, functions, types of
parentheses, and so on, and can crete specialized subclasses of the
predefined object classes. You can also adjust the operator precedences
and associativity to suit your needs.
For example, you mention x^y^z. The usual rules of precedence say that
raising to a power is rightassociative, meaning it should be
interpreted as x^(y^z), as WeBWorK currently does. If you wanted it to
be (x^y)^z, however, you could do that by changing an entry in the
precednece table, and that could be done on a problembyproblem or
coursebycourse basis.
The issue of how to handle function calls that do not include explict
parentheses is most subtle, and there is no really good solution to it.
As you note, we have had some discussions of this in the past, and
there is some disagreement among the WeBWorK developers about what the
"right" approach is. While the rules of precendence of operators are
pretty clear, there is no recognized standard for handling function
calls with missing parens.
Your example of sinx^2 is an important one, and illustrates some of
the subtley involved. Here, sine is trying to bind to the first operand
to the right of it, but since the rules of precedence say that x^2 is
interpreted as (x^2) not (x)^2, this makes the "first operand to the
right" is all of (x^2). So you get sin((x^2)). The same thing is true
of your second example for sine: x^2 is ((x^2)), not (x)^2, so I
think it is reasonable to make sinx^2 return sin(((x^2))). [In my
opinion, the problem is really with sin x^2 returning sin(x)^2 rather
than sin(x^2), but I don't want to reopen that debate at this point.]
The solution that the new parser uses is to consider "function apply"
(with no explicit parens) as an operator similar to implicit
multiplication. This operator gets a precedence like any other, and the
setting of that precedence affects how it interacts with other
operators. For example, setting the precedence of function apply to be
equal to that of implied multiplication would make sin x^2 be
interpretted as sin(x^2) while ln x+2 would still be ln(x)+2. (In this
case sin 2x would be sin(2)*x, just as it is now; setting the
precedence to between that of multiplication and exponentiation would
make sin 2x become sin(2x).) Setting the precendence to be higher than
exponentiation would make sin x^2 become (sin(x))^2.
The default settings of the precedences in the new parser mimic those
of WeBWorK 1.9, but there is an experimental set of precedences that
try to make a more "natural" set of interpretations. It is not entirely
successful, but has promise. The parser is also set up to allow issues
of spacing to be considered when deciding on precedence, but this is
somewhat controvercial, and I won't get into it here. I only mention it
so that if you want to use the new parser in your own code, you can use
those features if you wish. The nice thing about it is that it is all
based on precedence rules, so there are no new ideas or special cases
involved; it's just that there are more operators than usual (like the
function apply operation, or the fact that implied multiplication via a
space is a separate operator from explicit multiplication with *, and
so they can have different precedences).
Anyway, good luck with the project.
Davide
< Post or View Comments >
