WeBWorK Problems

parserMultiAnswer: checkTypes checking types (when it shouldn't?)

parserMultiAnswer: checkTypes checking types (when it shouldn't?)

by Gavin LaRose -
Number of replies: 2
Hi all,

This is a fairly specific question about parserMultiAnswer.pl (see also the problem techniques page). I have a problem that is using this, and is checking six numeric answers. I'm finding that if someone enters an answer in one answer blank (the last, in particular) that isn't of numeric type the checker isn't being called even when I include checkTypes=>0 in the call to create the MultiAnswer object.

This is with the trunk version of WeBWorK, revision 6925, as well as revision 7044.

This is evident in the following very stripped down version of the problem as well.

DOCUMENT();
loadMacros(
"PG.pl",
"PGbasicmacros.pl",
"PGanswermacros.pl",
"MathObjects.pl",
"parserMultiAnswer.pl",
);

Context("Numeric");

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

@yvals = ( Compute(3.9625), Compute(0.0003) );

$mp = MultiAnswer( @yvals )->with(
    singleResult => 0,
    allowBlankAnswers => 1,
    checkTypes => 0,
    checker => sub {
	my ( $correct, $student, $self ) = @_;
	my @stu = @{$student};
	my @cor = @{$correct};

	return [ (ref($cor[0]) eq ref($stu[0]) && $cor[0] == $stu[0]),
		 (ref($cor[1]) eq ref($stu[1]) && $cor[1] == $stu[1]) ];
    }
);

Context()->texStrings;
BEGIN_TEXT

Copy the values to the lower row:
$BR
\{ begintable(4) \}
\{ row( @yvals ) \}
\{ row( $mp->ans_rule(8), $mp->ans_rule(8) ) \}
\{ endtable() \}

END_TEXT
Context()->normalStrings;

ANS( $mp->cmp() );

COMMENT( 'Uses MathObjects' );

ENDDOCUMENT();

Am I missing something in how checkTypes should be working? Is there something else that I'm missing here?

Thanks,
Gavin

In reply to Gavin LaRose

Re: parserMultiAnswer: checkTypes checking types (when it shouldn't?)

by Paul Pearson -
Hi Gavin,

I recently asked Davide Cervone a similar question. Davide would probably suggest that instead of using ref:
(ref($cor[0]) eq ref($stu[0]) && $cor[0] == $stu[0])
you should use typeMatch:

($cor[0]->typeMatch($stu[0]) && $cor[0] == $stu[0])

What I found is that instead of defining the objects using Real or Compute:

@yvals = ( Compute(3.9625), Compute(0.0003) );
you should probably use Formula to avoid generating unnecessary error messages

@yvals = ( Formula("3.9625"), Formula("0.0003") );

Good luck!

Paul Pearson
In reply to Gavin LaRose

Re: parserMultiAnswer: checkTypes checking types (when it shouldn't?)

by Davide Cervone -
Gavin:

Am I missing something in how checkTypes should be working?

Yes. The checkTypes parameter controls whether the object types must match exactly or not. Some typechecking is always performed. This is as described in the POD documentation for parserMultiPart.pl.

For example, for a numeric answer, if the student types an infinity or a word (like "DNE" or "None") there is no warning issued about mismatched types, even though these types are not an exact match. They are "compatible" types, which means it makes sense to simply report "incorrect" rather than give a warning about the wrong kind of answer. On the other hand, if the student typed a list of numbers, or a formula, rather than a number, then the warning message is issued.

This is the always the case, no matter whether checkTypes is 1 or 0. When checkTypes=>1 this means that the answer checker will only be called when the student's answer is exactly the same type as the correct answer (not just a compatible one). That means your checker can use the student answer without having to worry about whether it is the right type or not. For example, for a numeric answer, you can do arithmetic with the student answer without having to check whether they actually entered "DNE" or an infinity. But some type-checking is always performed. I suppose the parameter is badly named and should probably have been "exactTypes" or "matchingTypes" or something like that.

I don't recommend using Paul's suggestion of using Formula objects here, as that will only eliminate a few of the type-match errors, and will produce inappropriate errors in other cases. For example, if the student answers 1,2 for the second answer, you will get a type warning indicating that the problem was expected a formula returning a number, but you are really looking for a number, not a formula.

Currently there is no option to prevent the MultiAnswer object from doing any typechecking. The only thing I can think of to accomplish that is to make a subclass of the Real class and override the typeMatch method so that is always returns true. For example

    package user::Real;
    our @ISA = ('Value::Real');
    sub typeMatch {1;}
    package main;
    sub UserReal {user::Real->new(@_)}
defines a new subclass of Real, and you can then use
    @yvals = (UserReal(3.962), UserReal(0.0003));
to get instances of this new class for use in the MultiAnswer. You should then use
    Real(0)->typeMatch($stu[0]) && $cor[0] == $stu[0]
to check if the student's answer is a Real object (since $cor[0] is a UserReal, where typeMatch will always return 1) and equals the correct answer.

Davide