diff --git a/src/ConstraintGrader.fun b/src/ConstraintGrader.fun new file mode 100644 index 0000000..5880e64 --- /dev/null +++ b/src/ConstraintGrader.fun @@ -0,0 +1,49 @@ +functor ConstraintGrader ( + (* Constraint Grader should return 1.0 if no constraint was violated *) + structure Constraint : GRADER + structure Correctness : GRADER + val description : string + (* deduction is the fraction of the total points that will be deducted, this + * should be Rational.one, as violating constraints deducts all points + *) + val deduction : Rational.t + val deductionMessage : string +) :> GRADER = + struct + structure Rubric = + struct + val description = description + + type t = Correctness.Rubric.t * Constraint.Rubric.t + + fun toString (correctness, constraint) = + let + val passes = Rational.eq (Rational.one, Constraint.Rubric.score constraint) + val deductionPercent = + showPercentsUnweighted (if passes then Rational.zero else Rational.~ deduction, Rational.zero) + val deductionMessage = if passes then "" else deductionMessage + in + String.concat [ + Correctness.Rubric.toString correctness, + deductionPercent ^ " " ^ Constraint.Rubric.description ^ "\n", + FormatUtil.indent (Constraint.Rubric.toString constraint), + FormatUtil.indent deductionMessage + ] + end + + fun score (correctness, constraint) = + let + val correctnessScore = Correctness.Rubric.score correctness + val deduction = + if Rational.eq (Rational.one, Constraint.Rubric.score constraint) + then Rational.zero + else deduction + in + case (Rational.compare (correctnessScore, deduction)) of + LESS => Rational.zero + | _ => Rational.- (correctnessScore, deduction) + end + end + + fun process () = (Correctness.process (), Constraint.process ()) + end diff --git a/src/FormatUtil.sml b/src/FormatUtil.sml index 8653e7a..9c2db16 100644 --- a/src/FormatUtil.sml +++ b/src/FormatUtil.sml @@ -3,11 +3,14 @@ structure FormatUtil = local val padded = StringCvt.padLeft #" " 4 o Rational.percent in - val showPercents = fn (score,weight) => - "(" ^ padded (Rational.* (weight,score)) ^ - "/" ^ padded weight ^ "):" + val showPercentsUnweighted = fn (numerator, denominator) => + "(" ^ padded numerator ^ + "/" ^ padded denominator ^ "):" end + val showPercents = fn (score,weight) => + showPercentsUnweighted (Rational.* (weight, score), weight) + val indentWith = fn s0 => let val spaces = String.implode (List.tabulate (String.size s0, Fn.const #" ")) diff --git a/src/sources.cm b/src/sources.cm index 8d2c025..a03ea3d 100644 --- a/src/sources.cm +++ b/src/sources.cm @@ -19,6 +19,8 @@ Library functor EquivGraderBucketList functor EquivGraderList + functor ConstraintGrader + functor Preamble structure FormatUtil @@ -49,6 +51,8 @@ is EquivGraderBucket.fun EquivGrader.fun + ConstraintGrader.fun + Preamble.fun FormatUtil.sml