Help getting started with OCaml


#1

Hi All,

I’m trying to learn OCaml from Real World OCaml online book. When I type

“open Core.Std;;” into the utop, it says “Unbound module Core”.

I installed OCaml from sources (version 4.05). Then installed OPAM by running the command(taken from the OPAM website):

“wget https://raw.github.com/ocaml/opam/master/shell/opam_installer.sh -O - | sh -s /usr/local/bin”

And then I ran the following commands:

$ opam init
$ opam install core
$ opam install utop

No able to get the examples work as yet. Can you guys help me out?
I’m running Ubuntu 16.04

Thanks,
Balaji


#2

Hi, have you seen this tutorial?


#3

I think the short answer is you need a “require” directive before the open statement:

#require "core";;
open Core;;

#4

Oh btw, you can put these directives in your ~/.ocamlinit file that probably already was created by opam. I.e. add all the packages that contain modules you frequently want to use in utop there. Mine looks like this currently:

(* Added by OPAM. *)                                                                                                                                                                                                                                                                      let () =                                                                                                                                                                                                                                                                                  
  try Topdirs.dir_directory (Sys.getenv "OCAML_TOPLEVEL_PATH")
  with Not_found -> ()
;;

#require "yojson";;
#require "core_extended";;

#5

Oh thank you!
That worked


#6

I’m seeing the below warning now. It’s ok to ignore it, isn’t it?

Warning 3: deprecated: module Core.Std [since 2017-02] Use Core. The Std sub-module is no longer needed


#7

Afaict this is harmless, but it also seems it is exactly the same as simply “open Core”:


#8

For technical reasons, the entry point to Core’s API used to be Core.Std. They now use module aliases, which makes the Std sub-module unnecessary. You should now do open Core instead of open Core.Std.


#9

I’m sure this will also be addressed in the second edition of Real World OCaml.


#10
─( 23:41:57 )─< command 0 >────────────────────────{ counter: 0 }─
utop # #require "core";;
─( 23:41:57 )─< command 1 >────────────────────────{ counter: 0 }─
utop # open Core;;
─( 23:42:10 )─< command 2 >────────────────────────{ counter: 0 }─
utop # Time.to_sec_string ~zone:Time.Zone.local Time.now();;
Error: This function has type Time.t -> zone:Time.Zone.t -> string                                                                                                                       It is applied to too many arguments; maybe you forgot a `;'.

#11

You’re missing parens! Try:

Time.to_sec_string ~zone:Time.Zone.local (Time.now ())

It’s easy to miss that when you’re getting used to OCaml’s syntax.

y


#12

thanks for your reply! but no lucky!

Error: This expression has type Time.Zone.t lazy_t but an expression was expected of type Time.Zone.t

I am using core v0.9.1; ocaml 4.05.0


#13

You’re getting closer. Turns out you need to call Lazy.force, or simply force to get the contents of a lazy value.

So:

Time.to_sec_strong ~zone:(force Time.Zone.local) (Time.now ())

#14

thanks, it is really cool; but also difficult for the newbies


#15

I think one of the things that you should know is that the function application syntax (other languages call that invocation) is quite different. You don’t write down the function name and then surround the arguments with parens as in foo(a, b). Instead you just write foo a b which means that you apply a to foo, which gives you a new (unnamed) function, which you apply to b. The fact that Time.now () has () is due to the fact that every function must take 1 argument even if it doesn’t really need any arguments, so there is a special value, (), pronounced “unit” that can be passed to that function.

I personally think this syntax is incredibly neat and elegant but opinions differ.


#16

thanks @Leonidas; but I did not mean about the func call but force or Lazy.force is so early for a newbie when he starts;


#17

Agreed. I’m not even sure why a value such as Time.Zone.local needs to be lazy anyway. I’m sure there’s a reason, but it really doesn’t feel right.


#18

A look at the source in https://github.com/janestreet/core in src/core_time.ml shows that there is a non-trivial amount of work to calculate the timezone data from the filesystem:

    let local = lazy
      begin match Sys.getenv "TZ" with
      | Some zone_name ->
        find_exn zone_name
      | None ->
        let localtime_t =
          input_tz_file ~zonename:"/etc/localtime" ~filename:"/etc/localtime"
        in
        (* load the matching zone file from the real zone cache so that we can serialize
           it properly.  The file loaded from /etc/localtime won't have a name we can use
           on the other side to find the right zone. *)
        match Zone_cache.find_or_load_matching localtime_t with
        | Some t -> t
        | None   -> localtime_t
      end

Unix does not make timezone handling simple or efficient, sadly…


#19

Yeah, this was the best of some not-excellent options…


#20

I struggled with that too, and sadly, the code in github is not up to date.
Thank you for the answer