PREP 2014 Question Authoring - Archived

Strings and Error Messages

Strings and Error Messages

by Chrissy Safranski -
Number of replies: 6
I was writing an introductory "Welcome to WeBWorK" type homework set, and I wanted to have them enter a String and get a sensible error message if they entered something else.  I think I figured out how to do this, almost, using contextString.pl.

However, entering anything but the correct answer gives the message "Your answer should be one of or Go Bearcats!" and I'd like it to just be "Your answer should be "Go Bearcats!".  I think that I'm more than a little fuzzy on how to modify error messages/feedback in general, and how to pass variables and student answers to a custom checker/message.  Below I've copied the important parts of my code, and left in a few things that I'd tried before commented out.  

Thanks for any help!
--------------------------------------------------------------
loadMacros(
   "PGstandard.pl",     # Standard macros for PG language
   "MathObjects.pl",
   "answerHints.pl",
   "contextString.pl",
 # "parserAutoStrings.pl",
   #"source.pl",        # allows code to be displayed on certain sites.
   #"PGcourse.pl",      # Customization file for the course
);
# AutoStrings();

# DefineStrings("Go Bearcats!","string2");

------------------------------------------------------

Context("String");
Context()->strings->add("Go Bearcats!"=>{});

$bearcats = String("Go Bearcats!");
------------------------------------------------------
BEGIN_TEXT

This is an answer blank.  Enter "Go Bearcats!" in it and hit Submit Answer.  It's not case sensitive, but don't forget the exclamation mark. $BR

\{$bearcats->ans_rule\}

END_TEXT
Context()->normalStrings;
--------------------------------------------------------------

#ANS($bearcats->cmp);

ANS($bearcats->cmp->withPostFilter(sub { 
  my $ans = shift; 
  $ans->{ans_message} = "Your answer should be Go Bearcats!" 
    if $ans->{ans_message} eq "Your answer should be one of or Go Bearcats!";
  return $ans; 
}));

# ANS($bearcats->cmp->withPostFilter(sub { 
#  my $ans = shift; 
#  $ans->{ans_message} = "Your answer should be 'Go Bearcats!' " 
#    if $ans!=$bearcats;
#  return $ans; 
#}));
In reply to Chrissy Safranski

Re: Strings and Error Messages

by Chrissy Safranski -
Also, when I'm using a List math object, either explicitly or with Compute, but I enter the answer purposely wrong with parentheses or braces, like (1,2,3) or {1,2,3}, then the error message I get says "Your answer isn't a number.  It looks like a list of numbers."  But it's supposed to be a list of numbers!  Can I do something to change that?

-----------------------------------------------

ANS(List("1, 2, 3" ) ->cmp);
In reply to Chrissy Safranski

Re: Strings and Error Messages

by Davide Cervone -
The situation with lists is a bit complicated, and you have identified one of the troublesome cases. The source of the problem is how to handle lists with explicit delimiters versus lists with no delimiters, as in your case. Should (1,2,3) be considered the same as 1,2,3? That is, should the delimiters matter? Both are lists consisting of the numbers 1, 2, and 3, so they should be the same, right?

The problem comes when you consider lists of lists; how should you represent a list of one list?. Is (1,2,3) a list of one item (a list), or is it a list of three items (the three numbers)?

For example, if the correct answer is the list (1,2,3),(4,5,6), and the student enters (1,2,3), we would want this to be interpreted as a list consisting of a single item, the list of three numbers, rather than a list consisting of three numbers. If we considered (1,2,3) to be a list of three numbers (rather than a list consisting of a single item, a list of three numbers), then there would be no way to enter a list consisting of a single list, and the treatment of (1,2,3) and (1,2,3),(4,5,6) would create (1,2,3) very differently in those to cases for the same answer blank.

Because of this case (the singleton list of lists), by default MathObjects considers an explicitly delimited list (when entered for a list answer) as a singleton list consisting of a single list. If you look carefully at the error message, it is suggesting that there is a list where a number was expected. That is, you asked for a list of numbers, but you got a list of lists (consisting of a single list). It is a subtle difference, and a hard one to make very clear.

This behavior is controlled by the implicitList flag for the List answer checker. If you did

   ANS(List("1,2,3")->cmp(implicitList=>0));
then entering (1,2,3) would cause the student's answer to be treated as the list of three numbers rather than a list of one list, and the answer would be marked incorrect silently, since the delimiters don't match the ones you entered (since your list had no delimiters).

If you want to have (1,2,3) to be marked correct, then you need to use

   ANS(List("1,2,3")->cmp(implicitList=>0,parensMustMatch=>0));
so that the parentheses won't have to match the ones from your list.

If neither of those is what you were after, then you will need to be more explicit about the behavior that you are looking for before I can tell you how to get it.

Hope that clarifies things.

In reply to Davide Cervone

Re: Strings and Error Messages

by Chrissy Safranski -
That does help, thank you!  I understand the ambiguity: is it a list of numbers or a (singleton) list of lists?  And different problems would want to handle that differently.

In this case, I don't think I want to mark it right - I'd just like to make the error message clearer for the students.  I tried the same thing that worked in the other String problem case (thank you very much!), but I can't get it to change the error message again.  Is there a way to access/return the error message (or a list somewhere or all the possible error messages?), so that I can be sure I'm not missing a space or something?  I tried copy-and-pasting from the feedback on an incorrect answer, but the message was unchanged the next time.  

------------------------------------------
Context()->{error}{msg}{"Your answer isn't a number (it looks like a list of numbers)"} =
    "Your answer should be numbers, separated by commas if there is more than one.  Have you used any parentheses or brackets that aren't needed?";
-------------------------------------------

And thank you again for the help on the other problem.  I was so close!  I used setOrientation (with minor edits) this past Spring, but I wanted something shorter this time.  I did start from ASU's 5 or 6 orientation problems and added and changed a few things. 

In reply to Chrissy Safranski

Re: Strings and Error Messages

by Davide Cervone -
You really are hitting all the known difficulties with MathObjects. Most people don't find them all in one day!

Unfortunately, there are some messages that don't go through the {error}{msg} translation process (but should -- there certainly are still improvements to be made to MathObjects). It turns out that the type-check message is one of them. For that, you would have to use your original idea of supplying a PostFilter to change the message. Sorry!
In reply to Davide Cervone

Re: Strings and Error Messages

by Chrissy Safranski -
That made it work just like I wanted.  Thank you!  I really appreciate the help you are providing.  

I've got another problem now, but I'll put it in a different thread since it's not related to error messages.  
In reply to Chrissy Safranski

Re: Strings and Error Messages

by Davide Cervone -
I was writing an introductory "Welcome to WeBWorK" type homework set

Note that the setOrientation set is such a homework set (it instructs the student about the student interface and how to enter answers into WeBWorK of various types). You might want to look at that as a starting point. We have found that it really helped reduce the questions and frustration level at Union.

In terms of the error message, you have done very well to get this far, and also to be concerned about what the errors will be. It looks like the String context needs to be fixed to use a better message when only one string is defined (though to be fair, this is a pretty unusual situation, since the only thing you can enter in the context is one of the strings, and since there is only one, that means there is only one possible answer that can be entered, not something that a normal problem would include).

The reason your code didn't work is a subtle one: the actual string used in the original message has two space between "one of" and "or Go", and you have only used one space in your test for it, so that turns out not to be true, and the messages is not changed. The reason there are two spaces is that (had there been more strings in the context), you would have had the list of them at that location in the string (with a space before and after the list). The list was empty, leaving just the two spaces next to each other.

If you take that into account, the problem will work as expected.

ANS($bearcats->cmp->withPostFilter(sub { 
  my $ans = shift; 
  $ans->{ans_message} = 'Your answer should be "Go Bearcats!"' 
    if $ans->{ans_message} eq "Your answer should be one of  or Go Bearcats!";
  return $ans; 
}));
There is another way to go about it, though. There is a mechanism in the Context object that allows the error messages to be customized. You could use that to replace the message automatically:
Context("String");
Context()->strings->add("Go Bearcats!"=>{});
Context()->{error}{msg}{"Your answer should be one of  or Go Bearcats!"} =
    'Your answer should be "Go Bearcats!";
Again, note the two spaces in the original message.

Hope that clears it up for you.