From ac1fe7d7abba32ef0c83ca1a22092bab9de5f171 Mon Sep 17 00:00:00 2001 From: Ryan Kavanagh Date: Thu, 13 Sep 2018 16:29:29 -0400 Subject: SML example import --- examples/sml/checks.sml | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 examples/sml/checks.sml (limited to 'examples/sml/checks.sml') diff --git a/examples/sml/checks.sml b/examples/sml/checks.sml new file mode 100644 index 0000000..d5b7262 --- /dev/null +++ b/examples/sml/checks.sml @@ -0,0 +1,87 @@ +(* Copyright (C) 2017-2018 Ryan Kavanagh *) +(* Distributed under the ISC license, see COPYING for details. *) + +(* This is a hypothetical assignment where students have to *) +(* implement addition. There are two Autolab problems testing *) +(* their implementation on "easy" and "hard" pairs of input. *) +(* The scoreboard just keeps track of how many bonuses problems *) +(* their implementation solves. *) +(* Because addition can be very lengthy, we timeout the execution *) +(* after a fixed amount of time. *) + +functor ChecksHelper (structure H : HELPER) : CHECKS where type checks = H.checks = +struct + +datatype checks = datatype H.checks + +(*****************************************************) +(********** CONFIGURE ME HERE *******) +(*****************************************************) + +structure Student : ADDER = Adder + +(* Run function f with arguments a with timeout of n seconds. *) +fun try n f a = Timeout.runWithTimeout (Time.fromSeconds n) f a + +(* test data is of the form *) +(* ("autolab exercise name", maxScore, [(input,expected),...]) *) +val testSums = [("easy", 4, [((1,1),2), ((1,2),3), ((2,2),4), ((3,5),8)]), + ("hard", 8, [((152,203),355), ((1212,2121),3333)])] + +(* Bonus problems that get used for score board *) +val bonusSums = [((10,~10),0)] +(* Pretty print problem input *) +fun inputToString (x,y) = (Int.toString x) ^ " + " ^ (Int.toString y) + +(* Compare student output to expected output with a timeout, and *) +(* compute the % of correct answers. *) +fun compare tests = + let fun c (input,expected) = + let val testStr = inputToString input in + case try 10 Student.add input of + (* No timeout *) + SOME b => if b = expected then + ( H.printLn ("Passed: " ^ testStr) + ; (1, 0)) + else + ( H.printLn ("Failed: " ^ testStr) + ; H.printLn (" Expected " + ^ (Int.toString expected) + ^ " but got " ^ (Int.toString b)) + ; (0, 1) ) + | NONE => ( H.printLn ("Timed out after 10s on " ^ testStr) + ; (0, 1)) + end + fun addp (a, b) (c, d) = (a + c, b + d) + val (same,diff) = List.foldl (fn (p,acc) => addp (c p) acc) + (0, 0) + tests + in real same / real (same + diff) end + +val checks = List.map (fn (name,max,tests) => + H.Problem (name, fn _ => real max * compare tests)) + testSums + +fun scoreboard score = + ( H.printLn "Checking bonuses..." + ; SOME [List.foldl + (fn ((p,b),acc) => + if try 2 Student.add p = SOME b then + ( H.printLn ("Got bonus " ^ (inputToString p)) + ; H.printLn ("Well done!") + ; acc + 1 + ) + else + ( H.printLn ("Failed to add bonus " ^ (inputToString p)) + ; H.printLn ("in under 2 seconds. Skipping.") + ; acc + ) + ) + 0 + bonusSums] ) + +(*****************************************************) +(********** END CONFIGURATION *******) +(*****************************************************) + +end -- cgit v1.2.3