A Simple Value
Let's start with the basics. In OCaml, we define values with let. Here we create a simple shape type and a variable holding a circle with radius 5.
OCaml is statically typed, but the compiler infers types for us — no annotations needed.
Defining a Variant Type
OCaml's type keyword lets us define algebraic data types. Each variant can carry different data — a Circle has a radius, a Rectangle has width and height.
This is like an enum on steroids. Each case is a distinct constructor with its own payload shape.
Your First Pattern Match
The match expression is where the magic happens. We destructure each variant and compute the area differently depending on the shape.
The compiler checks that every case is handled — miss one and you get a warning. No runtime surprises.
Adding More Shapes
Adding a new variant is easy — just extend the type and add a new match arm. Here we add Triangle with base and height.
If we forget to handle Triangle in our match expression, the compiler will tell us immediately.
Nested Patterns & Guards
Patterns can include when guards for additional conditions. Here we handle degenerate shapes (zero dimensions) as a special case.
Guards let you add arbitrary boolean conditions to any pattern arm — combining structure and logic.
Putting It All Together
Finally, we create a list of shapes and map our area function over them. The List.map higher-order function applies area to every element.
Pattern matching, variant types, and higher-order functions — the building blocks of expressive OCaml code.