How would you implement the following problem in WeBWork using MathObjects?
I have put together a Partition context that does this. The attached contextPartition.pl
file contains the context. the idea is to create Partition object that knows how to compare partitions, and make a new implementation for + in the context so that it produces partition objects rather than real numbers.
You are right that you could modify the number pattern to prevent decimals, but I think Alex's suggestion of using Parser::Number::NoDecimals
is better, as this allows the parser to recognize decimal numbers and give appropriate error messages (rather than "Unexpected character '.'
"). This is the kind of thing that I mean by having the context know about other possible answers, not just ones in the correct form.
disable all functions and operators except "+" (which is slightly teadious, since you seem to need to list all operators you want to disable).
The attached file gives one way to do this easier (undefined them all and then redefine the ones you want).
You should also disable delimiters used for various lists.
You could, or you could let the class produce error messages for the lists when they are used in appropriately. Leaving them in lets you create lists of lists, if you need them (like a list of pairs that are a word with a partition).
Then you need to add a custom answer checker that somehow extracts the list of the terms, sorts them and compare to the similar thing extracted from the reference object. ... [One] way would be to traverse the parse tree and collect the values, but I don't know where to put this code.
If you create the Partition class that implements addition of numbers to form partitions, and comparison between partitions (and string and TeX representations of partitions), then you don't have to make a custom checker, as the standard MathObject answer checker will call the object's comparison method automatically. You just have to tell the parser's plus operator to build the Partition object rather than a Real object. That is done by changing the class associated with the +
operator. See the attached code for an example.
Should one override the add method on Value::Real such that it produces a list instead of a number?
Right idea, but wrong method. You don't modify the Real class, you modify the context's definition for +
and what class it is tied to.
As an aside, it is not a good idea to modify the Value::Real
class itself, since WeBWorK uses mod_perl
, so those changes would be persistent and affect later problems that use the same httpd
child process. Instead, you should create a subclass of Value::Real
and override sub add
there, then tell the Context to use your class rather than the standard Real class, e.g.,
Context()->{value}{Real} = "my::Real";
assuming your class is
my::Real
. MathObjects copies the context when you say
Context("Numeric")
and so changes you make to that are not persistent and so don't affect other problems using the same child.
Now the answer preview probably still will show the sum of the elements rather than the partition. I have no idea how to shut this of. Suggestions?
If you have the plus create your Partition object, then the output will be the output from that object rather than from the real number that you would normally get from the sum.
As Alex points out, there is also some additional control over what is put in the "Entered" column. The Context flag formatStudentAnswer
can be set to evaluated
, reduced
, or parsed
. The first will give you the final number (assuming the student entered a formula that returns a number), the third will give the original formula entered by the student. The second form is only pertinent for Formulas, where the result will be simplified by the reduction rules available in the context (removal of "+ 0" or "1*" or "^1" or "/1" and such things).
For a custom object like the Partition object in the attached file, the object's string()
and TeX()
methods provide the strings to be used.
Anyway, this does provide a somewhat simpler example than the Permutation one, which needed two classes, and a new list type for the Parser.