Tired of the OCaml setup rabbit hole?
In 5 minutes, you’ll build your first OCaml program.
Just copy, paste, run.
Index
🟣 Use Modules and Libraries
Let's add some modules, interface files, tests, and more!
Create a Module
In OCaml the concept of module is similar to the one in Python or JavaScript where every file is considered an independent unit of work with its own namespace.
Create a calc.ml file in the lib/ folder and add the following functions:
(* lib/calc.ml *)
let add x y = x + y
let sub x y = x - y
Create a dune File
In Dune it's not enough to create a file to use it as a module, you need to explicitly say it through adding metadata in a dune file.
But before setting the metadata it's important to differentiate between a module and a library in OCaml:
- Module = single unit of code organization. They form what it's called a compilation unit, a fully independent program from the compiler's perspective
- Library = packaged collection of modules for distribution
In this occasion you will define everything inside the lib/ folder as a library named math so you could later call the Calc module through it.
Create a dune file in lib/:
; lib/dune
(library
(name math))
Libraries in OCaml are similar to index files in JavaScript; they expose modules.
Register a Library
In a similar way, if you want to consume a library in another .ml file you need to register it in its adjacent dune file to make it accessible, let's make it accessible to the bin/main.ml file:
In the bin/ folder open the dune file and register the library by its name:
; bin/dune
(executable
(public_name ocaml_dune)
(name main)
(libraries math)) ; Include your module here
Use a Library
Use the open keyword to access the library in main.ml:
(* bin/main.ml *)
open Math
let () = (* in other programming languages this would be to your main function equivalent *)
let result = Calc.add 2 3 in
print_endline (Int.to_string result); (* Output: 5 *)
Notice that you also use the Int module from the standard library to convert a number to a string.
Run the Project
Compile and execute your project in watch mode:
dune exec -w my_project
🟣 Create an Interface File
In Dune it's possible to separate your interfaces from your implementation through .mli files. They serve as a way for:
- Encapsulation: helps define the public interface of a module.
- Hide implementation details: makes possible to change module internals without affecting other dependent parts.
- Documentation: it's a good practice to include specifications for clarity.
In the lib/ folder create an .mli file with the same name as its corresponding module, calc.mli in this case:
(* lib/calc.mli *)
val add : int -> int -> int
(** [add x y] returns the sum of x and y. *)
Run the Project
Run:
dune exec -w my_project
Add the sub function to the main.ml file
(* bin/main.ml *)
open Math
let () = (* in other programming languages this would be to your main function equivalent *)
let result = Calc.add 2 3 in
print_endline (Int.to_string result); (* Output: 5 *)
let result = Calc.sub 3 1 in
print_endline (Int.to_string result) (* Output: 2 *)
As you see if you attempt to use sub it will result in an error, it's because the sub function has not been exposed yet, to solve it add the sub interface in calc.mli:
(* lib/calc.mli *)
val add : int -> int -> int
(** [add x y] returns the sum of x and y. *)
val sub : int -> int -> int
(** [sub x y] returns the difference of x and y. *)
Congratulations! You have created your first code in OCaml!
Happy coding with OCaml! 🚀
Next Steps
Did this help?
- Give it a ❤️
- Follow for Part 3: OCaml Dependencies
- If you want to dig into OCaml I wrote Basic OCaml and its second part Practical OCaml
- Share with one friend learning systems programming
Have a question? Comment below — I reply to all!
Top comments (1)
Great article! BTW I didn't know the OCaml Verse, it looks an amazing resource. I'll create a PR to add it in Awesome OCaml and maybe in official OCaml website :)