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 (
std_num_cmp(), for example), or through a parameter more like you are suggesting (
num_cmp($x)). There were several other modes like
fracfor allowing a fraction but no other operations, or
arithfor 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
NoDecimalsin order to require integers, and disable the
!operator in order to avoid answers like
5!. This would allow
5*4*3*2*1as an accepted answer, but if you wanted to prevent that, you could start with the LimitedNumeric context, apply
NoDecimalsand 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.plto share it.
sin(pi/3)example, one could disable all the functions and then re-enable just
NoDecimalsto 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
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
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.