How would I check the answer to the following question?

Input a number from the interval (1,4).

-Mike Schroeder

http://wwrk.maa.org/moodle/mod/forum/discuss.php?d=416

Bruce Yoshiwara

Los Angeles Pierce College

NAMED_ANS( part2a => List(-inf, $roots[0])->cmp( checker => ~~&inBetween ),

part2b => List($roots[0],$roots[1])->cmp( checker => ~~&inBetween ),

part2c => List($roots[1],$roots[2])->cmp( checker => ~~&inBetween ),

part2d => List($roots[2], inf)->cmp( checker => ~~&inBetween ) );

And have the students answer be a real value that could be verified by the custom checker. I wrote the routine

sub inBetween

{

my ($correct, $student, $ansHash) = @_;

return $correct->extract(1) < $student->extract(1) && $correct->extract(2) > $student->extract(1);

}

However, this gives me all kinds of errors. Perhaps it's pipe-dreaming, but I was hoping for a uniform solution that I could use multiple times in the same and multiple problems.

What do you all think?

-Mike Schroeder

sub inBetween { my ($correct, $student, $ansHash) = @_; return $correct->[0] < ($student) && $correct->[1] > $student; } TEXT(List(1,3)->cmp( list_checker => ~~&inBetween )->evaluate("2")->pretty_print);use the "testing lab" link on the editor page to get a lab where you can experiment with code fragments like this and discover which types of variables are being passed. It speeds up debugging.

(http://webwork.maa.org/wiki/PGLabs)

Notice two differences --

checker => sub{} when used with a list passes each of the elements of the list in turn to the checker.

list_checker => sub{} passes all of the elements in the list in an anonymous perl array which is more useful in this case.

(->extract(1) doesn't work on perl arrays use ->[0] instead -- and start with 0 :-) )

oh -- and here is another example of using list_checker from Davide

http://wwrk.maa.org/moodle/mod/forum/discuss.php?d=396&parent=7833

Hope this helps.

--Mike

How horribly unconventional would it be for me to do the following:

NAMED_ANS( "part1" => List(@roots)-> cmp(),

part2a => Real(-5)-> cmp( checker => ~~&inBetween, lower_bound=>-10,upper_bound=>$roots[0]),

part2b => Real(0) -> cmp( checker => ~~&inBetween, lower_bound=>$roots[0],upper_bound=>$roots[1]),

part2c => Real(3) -> cmp( checker => ~~&inBetween, lower_bound=>$roots[1],upper_bound=>$roots[2]),

part2d => Real(7) -> cmp( checker => ~~&inBetween, lower_bound=>$roots[2],upper_bound=>20)

);

and have my checker routine be

sub inBetween

{

$correct = shift;

$student = shift;

$ah = shift;

return ($ah->{lower_bound} < $student && $ah->{upper_bound} > $student);

}

It seems to work, but I have no idea if this is safe or not. Please let me know your thoughts.

Mike

To understand whether it will act the way you expect I would need to see the rest of the problem -- what question are you asking the student to answer?

In particular the roots can be entered in any order --since the first answer uses the List object.

After that the student's next answer must be in the first interval, and the next answer in the second interval and so forth. I assume this is what you want.

-- Mike

I recommend using a Real with a custom checker that uses an Interval (see my response below).

Davide

BEGIN_TEXT A number between 2 and 4 is \{ans_rule(5)\}. END_TEXT sub inInterval { my $I = Interval(@_); return sub {$I->contains($_[1])}; # student answer is second parameter to checker } ANS(Real(3)->cmp(checker=>inInterval("(2,4)")));

Here, we use a subroutine to return the actual checker, which is a different subroutine, but it has a closure over the interval that was passed to it, so you don't need to supply additional parameters to the answer checker. (You could certainly do it the other way, but this is a little slicker, so I give it as an example of how to do that.)

The checker uses the MathObject Interval class to do the actual checking, since intervals already have a method to test if an interval contains a value (or other interval, set, or union).

It is also possible to supply the interval as two numbers rather than a string (it will default to an open interval, as I recall), but with the string, you can specify whether the endpoints are included or not.

Hope that helps.

Davide