parserMultiAnswer.pl - Represents mathematical objects with interrelated answers
The MultiAnswer
class is designed to represent MathObjects with interrelated answers. It provides functionality to tie several answer rules to a single answer checker, allowing one answer to influence another. You can choose to produce either a single result in the answer table or a separate result for each rule.
Create a new MultiAnswer
item by passing a list of answers to the constructor.
The answers may be provided as MathObjects
, AnswerEvaluators
, or as strings (which will be converted into MathObjects
).
MultiAnswer
objects have the following attributes:
A coderef to be called to check student answers. This is the only required attribute.
The checker
routine receives four parameters: a reference to the array of correct answers, a reference to the array of student answers, a reference to the MultiAnswer
object itself, and a reference to the checker's answer hash. The routine should return either a score or a reference to an array of scores (one for each answer).
# this checker will give full credit for any answers
sub always_right {
my ($correct,$student,$multi_ans,$ans_hash) = @_; # get the parameters
return [ (1) x scalar(@$correct) ]; # return an array of scores
}
$multianswer_obj = $multianswer_obj->with(checker=>~~&always_right);
Indicates whether to show only one entry in the results table (singleResult => 1
) or one for each answer rule (singleResult => 0
). Default: 0.
Indicates whether to use named rules or default rule names. Use named rules (namedRules => 1
) if you need to intersperse other rules with the ones for the MultiAnswer
. In this case, you must use NAMED_ANS
instead of ANS
. Default: 0.
Specifies whether the types of the student and professor's answers must match exactly (checkTypes => 1
) or just pass the usual type-match error checking (in which case, you should check the types before you use the data). Default: 1.
Indicates whether to remove the blank-check prefilter from the answer checkers used for type checking the student's answers. Default: 0.
An sprintf-style string used to format the students' answers for the results table when singleResult
is true. If undefined, the separator
parameter (below) is used to form the string. Default: undef.
An sprintf-style string used to format the students' answer previews when singleResult
mode is in effect. If undefined, the tex_separator
(below) is used to form the string. Default: undef.
The string to use between entries in the results table when singleResult
is set and format
is not. Default: semicolon.
The string to use as a separator between entries in the preview area when singleResult
is set and tex_format
is not. Default: semicolon followed by thinspace.
$multianswer_obj->setCmpFlags($which_rule, %flags)
Configure a specific comparison object within the MathObject
instance by setting various flags and their corresponding values.
$which_rule
begins counting at 1.
If the specified $which_rule
does not correspond to an existing comparison object within the MultiAnswer
instance, this method will throw an error with the message "Answer $which_rule is not defined."
$ma_obj = MultiAnswer($fraction_obj);
$ma_obj->setCmpFlags(1, studentsMustReduceFractions => 1); # succeeds
$ma_obj->setCmpFlags(2, studentsMustReduceFractions => 1); # fails
$multianswer_obj->setMessage($which_rule, $message_string)
Meant for use in checker
, setMessage provides feedback targeting the specified answer rule.
Note that using Value::Error("message")
will halt the answer checker and return early with your message. This message will not be tied to any specific answer rule.
This method sets the provided message and does not return early -- allowing an answer checker to return a non-zero value for partial credit.
$which_rule
begins counting at 1.
If the specified $which_rule
does not correspond to an existing answer rule, this method will throw an error with the message "Answer $which_rule is not defined."
$ma_obj = MultiAnswer($math_obj1, $math_obj2);
$ma_obj->setMessage(2, "It's like a jungle sometimes..."); # succeeds
$ma_obj->setMessage(3, "It's like a jungle sometimes..."); # fails
$multianswer_obj->addMessage($message_string)
Meant for use in checker
when using singleResult
to add feedback messages for the combined answer rules. This will add the message to a message array, which will be all joined together to create the final message. These messages are then attached to any answer rule messages to be displayed to the user.
Note that unlike setMessage
, these messages are not tied to any answer rules, and unlike Value::Error("message")
, this will not halt the answer checker allowing both partial credit and other messages to also be shown.
To create a MultiAnswer pass a list of answers to MultiAnswer() in the order they will appear in the problem. These answers may be provides as strings, as MathObjects
, or as AnswerEvaluators
. For example:
$multipart_ans = MultiAnswer("x^2",-1,1);
or
$multipart_ans = MultiAnswer(Vector(1,1,1),Vector(2,2,2));
or
$multipart_ans = MultiAnswer($math_obj1->cmp(),$math_obj2->cmp());
In PGML, use the MultiAnswer
object as you would any other with the only difference that the MultiAnswer
is used multiple times:
Give the first part of the answer: [__]{$multipart_ans}{15}
Give the second part of the answer: [__]{$multipart_ans}{15}
Properties of a MultiAnswer
object can be set by chaining the with
method to the constructor during the initial assignment. For example, here we configure the results table to include only one entry for our $multipart_ans
, and then pass in our answer checker:
$multipart_ans = MultiAnswer("x^2",1,-1)->with(
singleResult => 1,
checker => sub {
my ($correct,$student,$multi_ans,$ans_hash) = @_; # get the parameters
my ($f,$x1,$x2) = @{$student}; # extract the student answers
return $f->eval(x=>$x1) == $f->eval(x=>$x2);
},
);
ANS($mp->cmp);
We can also make use of named subroutines. If using with
after assigning the MultiAnswer
to a variable, note that the with
method returns a shallow copy of the MultiAnswer
object. If you do not store the result when calling with
, your parameters will not be applied.
sub check {
my ($correct,$student,$multi_ans,$ans_hash) = @_; # get the parameters
my ($f,$x1,$x2) = @{$student}; # extract the student answers
if ($f->class ne 'Formula' || $f->isConstant) {
# use setMessage so that partial credit can be given
$multi_ans->setMessage(1,"For full-credit, find a non-trivial \(f(x)\).");
return 0.25;
}
# no partial credit for this error, and a specific answer rule is not targeted
Value::Error("It's not fair to use the same x-value twice") if ($x1 == $x2);
return $f->eval(x=>$x1) == $f->eval(x=>$x2);
};
$mp = MultiAnswer("x^2",1,-1);
$mp = $mp->with(singleResult=>1, checker=>~~&check);