WeBWorK Problems

Re: parserOneOf feedback messages

by Davide Cervone -
Number of replies: 0
The issue is coming from the fact that OneOf() does not actually call the answer checkers on the individual answer, but rather does the equivalent of doing a == between the various correct answers and the students answer. This makes a difference because while the answer checker will use == internally, it often also does much more in order to provide additional feedback to students about their answer.

For example, If two vectors with different lengths are compared via ==, the result will be false with no messages of any kind (you would not want such a comparison to throw an error, which is the only mechanism for providing additional messages in that situation). But when a student's answer is compared to a correct answer of ta different length, you do want additional information. So the answer checking is more extensive than just comparisons in general.

The fact that OneOf() does only comparison, not answer checking, means your extra answer messages are never even being produced (unless the messages are produced within the compare() method if you class).

You can subclass the OneOf object to replace the method that does the comparison so that it actually does call the answer checkers rather than just doing comparisons internally. Here is an example:

package my::OneOf;
our @ISA = ('parser::OneOf');

sub cmp_compare {
my ($self,$other,$ans) = @_; foreach$answer (@{$self->{data}}) { if ($answer->typeMatch($other)) { my$result = $answer->cmp->evaluate($other);
if ($result->{score}) {$ans->score($result->{score});$ans->{ans_message} = $result->{ans_message}; return$ans->{score};
}
if ($result->{ans_message}) {$ans->{ans_message} = $result->{ans_message} if !$ans->{ans_message} || length($ans->{ans_message}) > length($result->{ans_message});
}
}
}
return 0;
}

package main;

sub myOneOf {my::OneOf->(@_)}

Here, we loop through the possible correct answers and check if the student answer was the correct type to make a comparison with it. (This is because the correct answers could be of different types, e.g., OneOf("<1,2>", "x"), and you don't want to compare the student's answer of x with the vector, as that would generate a type-mismatch error.) If the type is OK, we do the answer checker to see if the student answer is the correct answer. If it is, we record the score, set the answer message to the one for this answer (in case we had one save from a previous incorrect check) and return the score. (If you can give partial credit, you may want to continue looping to see if there is a better answer, but you would have to handle keeping track of incorrect and messages differently).

If the answer isn't correct, then we check if there was an answer message for the incorrect answer. If so, we check if it is shorter than the previous answer message (if there was one), and save it as the answer message if so. That means we will end up with the shortest answer message in the end, unless there was a correct answer, in which case you get the correct answer's message.

It would also be possible simply to record all the answer messages and pas them back through the answer hash so that you could use a post-filter to handle them (or do some extra processing at the end of the cmp_compare() method) to determine the final answer message. Something like

sub cmp_compare {
my ($self,$other,$ans) = @_;$ans->{messages} = [];
foreach $answer (@{$self->{data}}) {
if ($answer->typeMatch($other)) {
my $result =$answer->cmp->evaluate($other); push (@{$ans->{messages}}, $result->{ans_message} || ''); if ($result->{score}) {
$ans->score($result->{score});
$ans->{ans_message} =$result->{ans_message};
return $ans->{score}; } } else { push (@{$ans->{messages}}, '');
}
}
return 0;
}

which uses \$ans->{message} to store a reference to an array of the answer messages produced (up until the correct answer is found). You can take it from there.

To use the new class, call myOnOf() instead of OneOf().

I hope that does what you need!