One thing to remember is that originally WeBWorK was basically for calculus, and the distinction between integers and reals was not crucial to that need. This was still the case when MathObjects were developed, though there was a need at the tome to branch out to include things like intervals and vectors. This is what MathObjects was originally intended to provide.
The traditional answer checkers could do things like the distinction between a real constant and an expression resulting in a real by using different checkers (
strict_num_cmp()
versus std_num_cmp()
, for example), or through a parameter more like you are suggesting (num_cmp($x,mode=>"strict")
versus num_cmp($x)
). There were several other modes like frac
for allowing a fraction but no other operations, or arith
for allowing operators but not function calls.These work well for what they do, but they don't provide much flexibility to customize the actions they perform. For example, you may want to ask for
sin(pi/3)
in terms of square roots, so you need sort()
, so only the standard version would work; but you don't want to allow sin()
, so the standard version doesn't work. This lead to several hacks to provide this type of functionality, but they were not very satisfactory.In order to do what you ask, you would need to provide many distinct "types" that you could ask for. With the Context approach, you have individual control over each function, operator, constant, and so on, so you can get precisely the combination of features you need. The cost is that it can take a bit to configure the context to the way you want it to be. But we've tried to mitigate that by providing pre-defined contexts that are set up for specific needs, plus facilities for modifying them when needed.
For example, to get your factorial question, you could use
NoDecimals
in order to require integers, and disable the !
operator in order to avoid answers like 5!
. This would allow 5*4*3*2*1
as an accepted answer, but if you wanted to prevent that, you could start with the LimitedNumeric context, apply NoDecimals
and use absolute checks with a tolerance of .5 as Alex suggests. One could make these customizations and call the result Context("Integer")
and place it in contextInteger.pl
to share it.For the
sin(pi/3)
example, one could disable all the functions and then re-enable just sqrt()
. Use NoDecimals
to force only integers to be allowed to be entered, so that they can't enter a decimal approximation of the result. Then they could answer the question using sqrt(3)/2
, but not .866025
(though I guess they could enter 866025/1000000
). I don't really see how to accomplish this type of answer with your type-based approach without having to define a new type for this specific situation (something most authors aren't going to want to do).
As an aside, the way
ANS()
works, the first argument is the answer checker, and the remaining arguments are key-value pairs that are attached to the answer checker to provide options. So you would need to us something like ANS($answer,type=>"Real")
or whatever.Since the introduction of MathObjects, people have pushed the parser much further than its original design, in order to check answers that are of quite different types than the original calculus problems it was intended to handle. The idea of an integer class now makes more sense, and probably should be added.