Skip to content

Instantly share code, notes, and snippets.

@pablo-meier
Created October 1, 2010 05:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pablo-meier/605808 to your computer and use it in GitHub Desktop.
Save pablo-meier/605808 to your computer and use it in GitHub Desktop.
%% A question is a [[question number,answer], correctness].
%% Example:
%% [[1,a], correct]
%% A test is a list of questions.
%% We create a rule that every correct answer is 10 points.
points([_, correct], 10). points([_, incorrect], 0).
%% Create rules flip solutions and whether or not they are incorrect.
flip(a, b). flip(correct, incorrect).
flip(b, a). flip(incorrect, correct).
%% Given a test, calculates the score based on the correctness.
test_score([], 0).
test_score([H|T], Score) :-
points(H, These_Points),
test_score(T, Rest_of_Points),
Score is These_Points + Rest_of_Points.
%% This is the critical rule: it ensures that all tests are scored
%% by the same answer key. This way, Prolog won't find a binding that
%% works for each individual test, but for all tests that get bound.
%% Two empty tests naturally follow the same grading criteria:
sensible_scores([], []).
%% We investigate tests recursively: if both tests have identical heads
%% (e.g. they agree on an answer and its correctness) then the test is
%% 'sensible' (follows a common rubric) as long as the rest of the test does.
sensible_scores([A|T1], [A|T2]) :-
sensible_scores(T1, T2).
%% If they have the same number but differ in answer, they must also differ
%% in correctness.
sensible_scores([[[A,B],Aye]|T1], [[[A,C],Nay]|T2]) :-
flip(B, C),
flip(Aye, Nay),
sensible_scores(T1, T2).
%% A cheap rule that binds X to Mary's score sheet. Correctness
%% is automagically bound by Prolog!
mary_test(X) :-
X = [ [[1, b], _],
[[2, b], _],
[[3, a], _],
[[4, b], _],
[[5, a], _],
[[6, b], _],
[[7, b], _],
[[8, a], _],
[[9, b], _],
[[10, b], _]].
%% Dan's score sheet.
dan_test(X) :-
X = [ [[1, b], _],
[[2, a], _],
[[3, a], _],
[[4, a], _],
[[5, b], _],
[[6, a], _],
[[7, b], _],
[[8, a], _],
[[9, a], _],
[[10, a], _]].
%% Lisa's score sheet.
lisa_test(X) :-
X = [ [[1, b], _],
[[2, a], _],
[[3, a], _],
[[4, a], _],
[[5, b], _],
[[6, b], _],
[[7, b], _],
[[8, a], _],
[[9, b], _],
[[10, a], _]].
%% And Colin's, whose score we don't know.
colin_test(X) :-
X = [ [[1, b], _],
[[2, b], _],
[[3, a], _],
[[4, a], _],
[[5, a], _],
[[6, b], _],
[[7, b], _],
[[8, a], _],
[[9, a], _],
[[10, a], _]].
%% Finally, the meat! We bind Lisa, Dan, and Mary to their score sheets.
%% We then use sensible_scores to ensure that their sheets follow the same
%% grading rubric. Finally, we ensure that this rubric adheres to the scores
%% that Mary, Dan, and Lisa obtained.
test_integrity(X) :-
lisa_test(Lisa),
dan_test(Dan),
mary_test(Mary),
sensible_scores(Lisa, Dan),
sensible_scores(Dan, Mary),
sensible_scores(Mary, X),
test_score(Mary, 70),
test_score(Dan, 50),
test_score(Lisa, 30).
%% Finally, we bind Score to what Colin's score is by setting
%% it to his test results, ensuring that his score has the same
%% answer key as his peers, then calculating the score with that
%% answer key.
colin_score(Score) :-
colin_test(X),
test_integrity(X),
test_score(X, Score).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment