Hello World in OCaml
Your first OCaml program - the classic Hello World example with Docker setup using the OCaml compiler
Every programming journey starts with Hello World. Let’s write our first OCaml program and explore what makes this functional language special.
The Code
Create a file named hello.ml:
| |
That’s it! Just one line for a complete OCaml program.
Understanding the Code
Let’s break down this simple program:
The print_endline Function
| |
print_endline- A built-in function that prints a string followed by a newline"Hello, World!"- The string argument to print
Function Application in OCaml
OCaml uses space for function application, not parentheses:
| |
The Entry Point
Unlike languages like Java or C that require a main function, OCaml executes expressions at the module’s top level. When you run the file, it evaluates each expression in order.
For explicit entry points, the convention is:
| |
The let () = ... pattern makes it clear this is a side-effecting expression that returns unit (similar to void).
Running with Docker
The easiest way to run OCaml without installing anything locally is with Docker:
| |
Understanding the Docker Command
docker run --rm- Run a container and remove it when done-v $(pwd):/app- Mount the current directory to/appin the container-w /app- Set the working directory to/appocaml/opam:alpine- Use the official OCaml Docker image (Alpine-based)ocaml hello.ml- Run the OCaml interpreter on our file
Compiling for Better Performance
The ocaml command interprets your program. For compiled, faster code:
| |
Expected Output
Hello, World!
Alternative Approaches
OCaml provides several ways to output text:
Using print_string (no newline)
| |
Using Printf (formatted output)
| |
The Printf module provides C-style format strings with type safety:
| |
Using Format (pretty printing)
| |
The @. flushes the output buffer and adds a newline.
Multiple statements with semicolons
| |
In OCaml, semicolons separate expressions (they don’t terminate statements like in C).
The Unit Type
In OCaml, every expression has a type. print_endline has the type:
| |
This means:
- It takes a
stringas input - It returns
unit(written())
The unit type is OCaml’s equivalent of void - it represents “no meaningful value.” It’s the return type of functions that exist only for their side effects.
| |
Type Inference
OCaml automatically infers types without explicit annotations:
| |
You can check types in the REPL:
# print_endline;;
- : string -> unit = <fun>
# "Hello";;
- : string = "Hello"
Common Beginner Mistakes
Forgetting the Space
| |
Wrong String Quotes
| |
Missing Semicolons Between Expressions
| |
Mixing Up = and ==
| |
Installing OCaml Locally
If you prefer to run OCaml without Docker:
Using opam (Recommended):
| |
Direct installation:
| |
After installation:
| |
The REPL: utop
OCaml has an interactive environment. The enhanced utop is recommended:
$ utop
────────────────────────────────────┬─────────────────────────────────────
│ Welcome to utop version 2.13.1
────────────────────────────────────┴─────────────────────────────────────
utop # print_endline "Hello, World!";;
Hello, World!
- : unit = ()
utop # 1 + 2;;
- : int = 3
utop # let double x = x * 2;;
val double : int -> int = <fun>
utop # double 21;;
- : int = 42
Note: Lines must end with ;; in the REPL (but not in source files).
Useful REPL commands:
#quit;;or Ctrl+D - Exit#use "file.ml";;- Load a file#show module_name;;- Show module contents
A Bit of History
OCaml evolved from the ML family of languages:
- 1972 - Robin Milner creates ML for the LCF proof assistant
- 1987 - First Caml implementation at INRIA
- 1990 - Caml Light with bytecode compiler
- 1995 - Caml Special Light adds native compilation
- 1996 - Objective Caml adds object system
- 2011 - Renamed from “Objective Caml” to simply “OCaml”
- 2022 - OCaml 5.0 brings multicore support
The name “Caml” originally stood for “Categorical Abstract Machine Language,” referring to its implementation technique.
Why OCaml for Hello World?
Even in this simple program, you see OCaml’s philosophy:
- Conciseness - One line does the job
- No boilerplate - No class definitions, main methods, or imports needed
- Type safety - The compiler ensures
print_endlinereceives a string - Functional style - Functions are the primary building blocks
Next Steps
Continue to Types and Functions to learn about OCaml’s powerful type system and how to define your own functions.
Key Takeaways
print_endlineprints a string with a newline- Function application uses space, not parentheses
let () = ...is the idiomatic entry point patternunit(written()) is OCaml’s void type- Semicolons separate expressions, not terminate them
- Type inference means you rarely need type annotations
;;ends expressions in the REPL (not needed in files)