Let us now move to the development a basic grader. We ask the student
to implement the identity function and provide the following template.ml
:
let identity x = "Put your code here"
Our goal is to check that this function is modified by the student
in such a way that it behaves as our solution.ml
:
let identity x = x
To that end, the grader will compare the outputs of the student function with the function of the solution. We must provide inputs of a ground type (i.e. of non polymorphic type), execute the two functions and compare their outputs. Each time the outputs match, the student gets one point.
Assuming that we choose int
for this ground type, the behavior described
in the previous paragraph is implemented as follows:
open Test_lib
open Report
let exercise_1 =
test_function_1_against_solution
[%ty: int -> int] (* Type of the tested function *)
"identity" (* Identifier of the tested function *)
~gen:0 (* Number of automatically generated tests *)
[0] (* List of tested inputs *)
let () =
set_result @@
ast_sanity_check code_ast @@ fun () ->
[exercise_1]
The function Test_lib.test_function_1_against_solution
is the key
here. Let us take a moment to understand how it is called:
The argument [%ty: int -> int]
is written in a PPX extension of
OCaml: it reifies the type int -> int
as a first-class value. With
that information in its hands, test_function_1_against_solution
can check that the student has written a function of the right type.
The string "identity"
is the identifier of the function to be tested.
The optional argument gen
is set to 0
because we are not willing to
automatically generate inputs. (This will be the topic of another step
of this tutorial.)
The final argument [0]
is the unique input on which we want to test
the function.
This function also determines the text written in the header of the
corresponding report. For a function called my_function
, it will be
“Function: my_function”.
Copy this exercise source to your own exercise directory.
Update your index.json
file.
Run learn-ocaml build && learn-ocaml serve
Open http://localhost:8080
in your browser.
Check that the template does not get the point.
Modify the code, get your point!
Change the argument ~gen:0
to gen:41
for instance and
rebuild your learn-ocaml instance.
Grade your answer and observe the effect of the previous change. This is the topic of the next step of this tutorial!
The next steps will bring you progressively to understand most of the possibilities of grading functions. However, if you want to have a better overview right now, you can go directly to step 5 where you will:
test_function_1_against_solution
To grade a function with multiple arguments you simply need to use the
corresponding grading function which follows this pattern :
Test_lib.test_function_<function arity>_against_solution
and give
the inputs as n-uplets:
open Test_lib
open Report
let exercise_1 =
test_function_2_against_solution
[%ty: int -> int -> int] "op"
~gen:5
[ (1,2) ; (0,1) ]
let () =
set_result @@
ast_sanity_check code_ast @@ fun () ->
[ exercise_1 ]
You can find this example in the
exercises/grade-function-multiple_args
directory (branch: step-2).
For a polymorphic functions, you may want to test the function with
different types. To do so, you can concat the result of numerous grading
functions and encapsulate it in a Section
which has two arguments :
some text and a list of items produced by grading functions.
open Test_lib
open Report
let exercise_1 =
Section ([ Text "Function: "; Code "identity" ; Text " with multiple tested input types." ],
[ test_function_1_against_solution
[%ty: int -> int] (* [identity] tested with integer *)
"identity"
~gen:0 [1 ; 2];
test_function_1_against_solution
[%ty: char -> char] (* [identity] tested with char *)
"identity"
~gen:0 ['c' ; 'a'];
test_function_1_against_solution
[%ty: float -> float] (* [identity] tested with float *)
"identity"
~gen:0 [1.1 ; 2.4]]
)
let () =
set_result @@
ast_sanity_check code_ast @@ fun () ->
[ exercise_1 ]
You can find this example in the
exercises/grade-function-polymorphism
directory (branch: step-2).