[Real world Ocaml] How do I import core_unix time?

So, I’ve been following Real World OCaml, the 2nd edition and I hit a block I’m afraid I cannot overcome with google, documentation or AI help.

The code in question:

open Core

let () =
  Out_channel.output_string stdout "Pick a timezone: ";
  Out_channel.flush stdout;
  match In_channel.(input_line stdin) with
  | None -> failwith "No timezone provided"
  | Some zone_string ->
    let zone = Time_unix.Zone.find_exn zone_string in
    let time_string = Time.to_string_abs (Time.now ()) ~zone in
    Out_channel.output_string stdout
      (String.concat
         ["The time in ";Time_unix.Zone.to_string zone;" is ";time_string;".\n"]);
    Out_channel.flush stdout

This example won’t work, first of all because there is no Time_unix in Core. There is Time_float with similar structure: it has Zone.to_string for example. However, it’s deprecated and all the values are set to `Use_Time_unix.
I happened to google up something related: Notes from Real World OCaml, first edition. The article suggests importing core_unix, without going into detail on how to do it.

I went ahead and installed core_unix via opam, and required it in dune as core_unix for my executable. However, there is no way to use any values: there is Core_unix module, but it doesn’t contain anything time-related. I tried opening Core_unix in hopes that it maybe overwrites somehow values in Core.Time_float, but to no avail.

However, I managed to make it work in utop and in dune build/exec.

Utop:

If I run #require "core_unix.time_unix";; , the Time_float_unix.Zone.of_string becomes available, and it’s not the deprecated version. It actually works.
In a similar fashion, I used core_unix.time_unix in my dune file, and now Time_float_unix module is available, with correct implementation. I can run dune exec and the code behaves correctly.
However, the LSP cannot cope with it, and keeps complaining with “Unbound module Time_float_unix”.

So, my questions are:

  1. Is it normal to use the “dot” version of a library? If not, then how do I make the inner time_unix module available?
  2. What kind of mental process should go through my head when I see something like deprecation with `Use_Time_unix value assigned to everything? How do I proceed from this to the working solution?
  3. How do I use documentation to understand how to import and use a library? For example, the time_unix part of the library is documented here: core_unix v0.15.0 · OCaml Package. However, there are no examples on how to import and actually use it. The “parent” part for core_unix doesn’t say anything even about its own parts (can’t put a link due to limitation)
    Am I missing something and looking at the wrong or outdated documentation? There seems to be some leap required between doing opam install and using the code, but I can’t figure out what it is.

You should look more closely core_unix v0.15.0 · OCaml Package

There is a gray lib tag in front of core_unix.time_unix. This means you should include this lib (Typically (libraries core_unix core_unix.time_unix) with dune.

I guess the OCaml ecosystem a bit more complex than Rust. A package (core_unix) can provides multiple libraries (here core_unix.time_unix and others), and each library may provide multiple modules (lwt is such a library).

Note, the RWO notes you link indicates…

If you import Core or Base into the REPL’s namespace, you’ll get this signature:

val destutter : int list -> int list = <fun>

Which is plainly incorrect

The note miss the point. The Base/Core library change the equal sign and make the (=) funtion only deals with integer. Then with this module opened, we have to be more explicit (let open String in s1 = s2 or String.equal s1 s1).

The original OCaml approach is easier to use… the Base/Core approach renders the code more explicit. The original OCaml (=)is still available in the Caml module.

2 Likes