First, is there comprehensive documentation available for utop? I can’t seem to find any. I am using the CS3110 book (2.1. The OCaml Toplevel — OCaml Programming: Correct + Efficient + Beautiful) and information I glean from various blog posts such as opam - UTop: a much improved interface to the OCaml toplevel and Introduction to the OCaml Toplevel · OCaml Documentation.
I want to use a workflow like the #use "code.ml" one described in the CS3110 book, but for more complex code that depends on a few libraries and multiple ppx. Currently if I #use my .ml files in utop they bug out with various errors related to ppx processing and missing libraries.
I haven’t successfully figured out how to get utop loading this code in a way that is all of these things:
- convenient (in the sense that the incantations required to load my code come from
duneusing at most one command) - functional (in the sense that the code loads at all)
- allows me to interact with the code as if I were in the unsealed module (in the way you can after using
#useinutop)
I have been able to load my module using dune’s integration with utop, but this seems to load the sealed module. For example, I can’t call functions that aren’t exported. This is inconvenient, because my goal is to interactively explore and debug the module.
Taking it down a level, I can reproduce my problem with a minimal test case, using instructions from Command-Line Interface — Dune documentation
$ dune init project --kind=l myproj
$ cd myproj
$ echo 'let i = 42' > lib/code.ml
$ dune build
Now, I’d like to use something like dune utop to load this library such that entering i;; into utop will print the value 42.
Following Command-Line Interface — Dune documentation I try:
$ dune lib
but…
utop # module S = Myproj;;
modle S = Myproj
…in other words, it looks like Myproj doesn’t export i. I’ve also tried dune lib -- -implicit-bindings but it makes no difference. The dune docs say -implicit-bindings means there will “implicit bindings for toplevel expressions” but I’m not sure what that means.
The alternative also produces the same problem:
$ utop
utop # #use_output "dune ocaml top-module lib/code.ml";;
utop # i;;
Error: Unbound value i
utop # module S = Myproj;;
module S = Myproj
This makes sense to me. utop is loading my module, but the module, having no .mli, is apparently completely sealed.
Of course, with an example as simple as this, I can #use "code.ml" in utop. In my actual use case my dune file is non-trivial, and so the utop setup is also non-trivial. For example:
(library
(name day07)
(inline_tests)
(libraries str)
(preprocess (pps ppx_jane ppx_deriving.show)))