WeBWorK Problems

MultiAnswer.pl: Changing an error message

MultiAnswer.pl: Changing an error message

by Robin Cruz -
Number of replies: 2

Hi,

I'm using MultiAnswer.pl and I want to change the error message a student gets if they enter a string instead of a number from "In answer 1: Variable 't' is not defined in this context" to something like "Your answer must be a number."  I've tried the suggestions in the documentation for MultiAnswer.pl, I've been able to change the error message in other situations, but not for this case (String answer when a number is expected.).  The problem I'm writing asks the student to enter dimensions for two matrices which will *not* produce a product. The code is at the end of this note.  

Thanks--rac

---------Code-------------------------------------


loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"parserMultiAnswer.pl",
"answerHints.pl",
);

TEXT(beginproblem());
$showPartialCorrectAnswers = 1;

$multians2 = MultiAnswer(2,2,3,2)->with( #Correct answer not really used
  singleResult => 1,
  checkTypes => 0,
  checker => sub {
      my ( $correct, $student, $self ) = @_;
      my ( $sm1,$sn1,$sm2,$sn2 ) = @{$student};
      if ( is_a_number($sm1) && is_a_number($sn1)
          && is_a_number($sm2) && is_a_number($sn2) ) {
          if ( $sn1!=$sm2 ) { return 1; } else {return 0;}
     } else {
       $self->{ans_message}='Your answers must be numbers.';
       Value::Error("Enter numbers for your answers.");
       $self->setMessage(2,"Enter a number.") if (~(is_a_number($sn1)));          ###NOTE:  I tried various permutations like the three lines above.###
### I had one for each answer like the last one--left one for reference.
        return 0;
      }
  }
);

BEGIN_TEXT
State the dimensions for a pair of matrices, \(C\) and \(D\), which cannot be multipled together.  In other words, \(CD\) cannot be calculated.
$BR $BR
\(C\): \{$multians2->ans_rule(5)\} rows, \{$multians2->ans_rule(5)\} columns,
\(D\): \{$multians2->ans_rule(5)\} rows, \{$multians2->ans_rule(5)\} columns
END_TEXT

ANS( $multians2->cmp);#->withPostFilter(AnswerHints(
#sub {
#  my ($correct,$student,$ans) = @_;
# return $ans->{ans_message} =~ /not defined/;
#} =>["Note: Your answers must be numbers.", Score => 0, replaceMessage => 1])));

##Using AnswerHints produced an error: Can't call method "withPostFilter" without a package or object reference at line 143 of (eval 2480)

##The line number is off since this was part of a longer problem.

ENDDOCUMENT();        # This should be the last executable line in the problem.

In reply to Robin Cruz

Re: MultiAnswer.pl: Changing an error message

by Davide Cervone -
There are a couple of issues here.

First, your checker is only called if there are no syntax errors in any of the answers. Since "Variable 't' is not defined in this context" is a syntax error, your checker never runs, so you are not able to replace the message from within the checker.

One way around this would be to use the Context's error message structure to redefine the error, e.g.:

    Context()->{error}{msg}{"Variable '%s' is not defined in this context"} =
       "Your answer must be a number";

    $multians2 = MultiAnswer(2,2,3,2)->with(
      singleResult => 1,
      checker => sub {
          my ($correct, $student, $self) = @_;
          my ($sm1,$sn1,$sm2,$sn2) = @{$student};
          return ($sn1 != $sm2 ? 1 : 0);
      }
    );
There is no need for the type-checking here, since that is all handled by the MultiAnswer object. The key to the message translation is to use the message as it appears before the variable name is substituted into it (the %s is replaced by the variable name).

Note that this will still use the "In answer x:" part of the message, and each entry blank can produce its own message. So there are potentially four messages possible, here.

The reason your withPostFilter doesn't work is that MultiAnswer's cmp() routine actually produces an array of answer checkers, and the array is not an object that has a withPostFilter method. When singleResult is 1, however, there is only one answer checker in the array (otherwise there is one for each blank), so you could use ($multians2->cmp)[0]to get access to that answer evaluator.

There is still a problem, however, which is that AnswerHints can only be used with MathObject answer evaluators, and the one returned by MultiAnswer isn't one of those, so you would get an error if you tried to attach it to the answer checker from ($multians2->cmp)[0]. Instead, you have to use a custom post filter of your own. Here is one way:

    ANS(($multians2->cmp)[0]->withPostFilter(
      sub { 
        my $ans = shift;
        if ($ans->{ans_message} =~ /not defined|it looks like/) {
          $ans->{ans_message} = "Note: Your answers must be numbers";
          $ans->score(0);
        }
        return $ans;
      }
    ));
Note that I have checked for both "not defined' and "it looks like" messages in order to handle errors from entering things like points rather than numbers.

Note that this will only produce one error message if any of the them has a variable in them. If one of the other answers had a syntax error, for example, the message about that would be lost (though the syntax highlighting in the student answer would be retained, and might be confusing).

Hope that helps.

Davide

In reply to Davide Cervone

Re: MultiAnswer.pl: Changing an error message

by Robin Cruz -

Davide,

I used the post filter example you sent and it addressed the problem very nicely.  I really appreciate you taking the time to explain how this all works.  I now have a better understanding of how to work with MultiAnswer.pl.

Thank you --rac