learn-ocaml
learn-ocaml copied to clipboard
Grab student code at a polymorphic type
The functions lookup
, lookup_student
and lookup_solution
in module Test_lib
expect an argument of type 'a Ty.ty
, that is, a runtime representation of the type 'a
. This allows grabbing a value at an arbitrary, monomorphic type. Is there a way of grabbing a value at a polymorphic type?
So far, I have not found a way of doing this. I am forced to work around the problem by grabbing a finite number of monomorphic instances of the polymorphic type I have in mind, but this is unpleasant and does not work at all if I need an unbounded number of monomorphic instances.
(By the way, why are there three functions lookup
, lookup_student
and lookup_solution
? I understand lookup_student
versus lookup_solution
, but not lookup
. Some documentation would be welcome.)
We have been able to grab functions at a polymorphic type simply by supplying a type such as 'a list -> 'a
to the grader. Mostly we use this just to verify that an implementation is indeed polymorphic, since it isn't that useful when used with the functions test_function_n_against_solution
, etc.: the outputs in the grading reports are just written as <poly>
. If you are manually constructing reports then I don't think there would be an issue, though.
Hi Aliya, thanks for your comment. You are right, it is possible to look up a value and insist that its type must be polymorphic, as follows:
T.lookup_student [%ty : 'a -> 'a] "id" ()
However, as far as I understand, this piece of code has monomorphic type ('a -> 'a) lookup
. (This is probably imposed by the value restriction.) So, the value that I get can be used at any one monotype, but cannot be used in a polymorphic manner. Is there a way around this problem?
Ah, I see what you're saying. It looks like, since values are passed around in the datatypes 'a value
(introspection.mli) and 'a lookup
(test_lib.mli), there probably is not a straightforward way to do this using the lookup
functions.
However, something that I think will work for you is using the function test_student_code
in Test_lib
. https://github.com/ocaml-sf/learn-ocaml/blob/bd002531a99a0f682e06a64e328b8e9fec8932e4/src/grader/test_lib.mli#L549
As I understand it, you can use this function to package (part of) the student code into a module according to a module signature that you provide, and then you have direct access to that module in your grader code. The following grader compiles for me (although I have not actually tested it in the browser):
open Test_lib
module type Has_Id = sig
val id: 'a -> 'a
end
let my_test () =
test_student_code
[%ty: (module Has_Id)]
(fun (m: (module Has_Id)) ->
let module M = (val m: Has_Id) in
let x = M.id 1 in
let y = M.id "a" in
[] (* resulting report; here it's just empty *))
let () =
set_result @@
ast_sanity_check code_ast my_test
A drawback is that the error messages from test_student_code
may be harder for students to understand, since they are in the form of module type mismatches.
Indeed, this works. Great! It would be nice if this trick could be documented somewhere. Other than that, I believe that this issue can be closed.