It
is possible to use the new Parser to handle this, as Mike suggests. It
is a little subtle, however, so here are the main ideas:
The hardest part is to trap errors that occur during the function
evaluation so that you can ignore them. This is not so easy to do in
WW, since the problem is executed in a limited subset of perl, and that
subset does not include the commands for trapping errors. There are
some special cases, however, where WW will trap errors for you. The
Parser provides one of these with the Parser::Evaluate() function. This takes a Formula object and a list of substitions (e.g., x=>5,y=>-2 ) and substitutes those values into the formula (just like the Formula's eval
method), but traps errors so that they will not produce error messages
or stop the code from running. Instead, if an error is detected, Parser::Evaluate returns an undefined value, and the error message is in the Formula's context's {error} object.
This is useful in this case, because the graphics plotting routine
looks for undefined values and skips over them, so if we can get it to
wrap Parser::Evaluate around the formula that it is plotting, we will be able to not worry about the domain. The problem is that plot_functions()
uses AlgParser to evaluate the formula to be plotted, so we are
restricted to using only the functions that AlgParser knows about
(which doesn't include Parser::Evaluate ).
Fortunately, we can bypass plot_functions and go to a slightly lower level of code and insert our own functions into the graph directly. This is done using a Fun object (short for Function). When a Fun object is created, it accepts a perl subroutine reference, not a string representing the function like plot_functions , so we can include calls to anything we want in that subroutine.
So here's the plan: parse the student's answer into a Parser Formula object, then create a Fun object whose subroutine calls Parser::Evaluate on the student's answer, thereby ignoring error messages. For example, suppose you have a variable $G that is the graphic object created via init_graph() earlier, and the student answer is in $student_ans . Then you can plot the student answer using $F = Formula($student_ans); $f = new Fun(sub {Parser::Evaluate($F,x=>shift)},$G);
This assumes the variable in the student's formula is x , but you can change x=>shift to be whatever variable is appropriate for you.
If you want to set the color or weight for the plot, you can use something like $f->color("red"); $f->weight(2);
to do that. If you think there will be gaps in the student's function,
you may want to plot more points than the default 20 in order to make
the endpoints of the gaps more accurate. You can use $f->steps(100);
for example, but the number of points might need to be more (or less)
depending on the size of the final graph that you are producing.
Note that if the student has made a syntax error, the $F = Formula($student_ans);
line may cause an error. You probably want to trap this error and
report it in the answer message area rather than get the pink warning
screen or some other error condition. The parser has a function to help
you with that as well: Parser::Formula() . This parses the
string passed to it and returns an undefined value if there was an
error, with the error message stored in the context's {error} object. You can then call Value->cmp_error()
to clean up and format that error (e.g., hilight the location of the
error) and insert it into the answer-hash's message field. For example,
if the answer hash is $ans , $F = Parser::Formula($student_ans); if (defined($F)) { $f = new Fun(sub {Parser::Evaluate($F,x=>shift)},$G); $f->color("red"); $f->weight(2); $f->steps(100); } else { Value->cmp_error($ans); }
would parse the student answer and either plot the student's function
(no matter what it's domain) or report an error if the student's answer
didn't parse.
Note that the plot might not show anything if the student's function is
not defined on the domain of the graph, or if the values of the
function are outside the vertical range of the graph.
Anyway, hope that does what you want.
Davide
<| Post or View Comments |>
|