REVISED: Tuesday, September 23, 2025
1. OCAML FUNCTION COMPOSITION
(* ocaml C:\AI2025\func_comp.ml *)
(* Examples *)
(* Let's define a few simple functions to work with. *)
(* add_one: int -> int
This function takes an integer 'x' and returns 'x + 1'. *)
let add_one x = x + 1
(* square: int -> int
This function takes an integer 'x' and returns its square. *)
let square x = x * x
(* to_string_pretty: int -> string
This function takes an integer and converts it into a descriptive string. *)
let to_string_pretty x = "The final result is: " ^ string_of_int x
(* ---- Method 1: Nested Function Calls (Without Composition) ---- *)
(* This is the traditional way to apply one function's result to another.
We start with a number, say 5. *)
let initial_value = 5
(* First, we apply add_one to our initial_value. *)
let result1 = add_one initial_value (* result1 is 6 *)
(* Then, we apply square to the result of the previous step. *)
let result2 = square result1 (* result2 is 36 *)
(* Finally, we format the result as a string. *)
let final_string_nested = to_string_pretty result2 (* final_string_nested is "The final result is: 36" *)
(* We can write this more compactly by nesting the calls.
This can become hard to read from inside-out. *)
let final_string_nested_compact = to_string_pretty (square (add_one 5))
(* ---- Method 2: Using a Custom Composition Operator ---- *)
(* In OCaml, we can define our own infix operators. Let's create one for
forward function composition, which is a common practice. We'll call it |>
(the pipe operator), which is now standard in the OCaml ecosystem. *)
(* The 'let (|>) x f = f x' definition creates an infix operator '|>'.
- 'x' is the value on the left-hand side of the operator.
- 'f' is the function on the right-hand side.
- 'f x' applies the function 'f' to 'x'.
So, '5 |> add_one' is exactly equivalent to 'add_one 5'. *)
let (|>) x f = f x
(* Now, let's perform the same sequence of operations using our pipe operator.
This creates a data pipeline that is read from left to right, which is
very natural and intuitive. *)
let final_string_piped =
5 (* Start with the initial value 5. *)
|> add_one (* Pipe 5 into add_one, the result is 6. *)
|> square (* Pipe 6 into square, the result is 36. *)
|> to_string_pretty (* Pipe 36 into to_string_pretty. *)
(* The final result is "The final result is: 36", same as before. *)
(* ---- Method 3: Creating a New Composed Function ---- *)
(* Sometimes you want to create a new function by combining others, without
applying it to an initial value right away. *)
(* Let's define a standard backward composition operator '>>'.
'(f >> g) x' means 'g(f(x))'. It first applies f, then g. *)
let (>>) f g x = g (f x)
(* Here, we create a new function 'add_one_then_square_then_format'.
This function represents the entire sequence of operations.
The definition reads as: apply add_one, then apply square, then apply to_string_pretty. *)
let add_one_then_square_then_format = add_one >> square >> to_string_pretty
(* Now we can use this new, composed function with any integer. *)
let result_from_composed_function = add_one_then_square_then_format 5
(* This will also produce "The final result is: 36" *)
let another_result = add_one_then_square_then_format 10
(* This will compute to_string_pretty(square(add_one(10)))
-> to_string_pretty(square(11))
-> to_string_pretty(121)
-> "The final result is: 121" *)
(* ---- Printing the results to verify ---- *)
(* We use Printf.printf to print the results to the console. *)
let () =
Printf.printf "Nested compact result: %s\n" final_string_nested_compact;
Printf.printf "Piped result: %s\n" final_string_piped;
Printf.printf "Composed fn result: %s\n" result_from_composed_function;
Printf.printf "Composed fn another: %s\n" another_result
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows
OCaml version: The OCaml toplevel, version 5.3.0
Coq-LSP version: 0.2.3
Loading personal and system profiles took 5468ms.
PS C:\Users\User> ocaml C:\AI2025\func_comp.ml
Nested compact result: The final result is: 36
Piped result: The final result is: 36
Composed fn result: The final result is: 36
Composed fn another: The final result is: 121
PS C:\Users\User>
2. CONCLUSION
There are two main operations we can do with function values: apply them, and compose them.
The nesting of two or more functions to form a single new function is known as composition.
f (g x) = (f . g) x
Read as f of g is the composition of f with g.
The composition of f and g is a function that first applies g to its argument, then f to the value returned by g. It then returns the return value of f.
The primary purpose of the OCaml function composition . dot operator is to chain functions of the same type. It lets us tie the output of whatever appears on the right of the dot operator to the input of whatever appears on the left of the dot operator as long as they are of the same type.
3. REFERENCES
Bird, R. (2015). Thinking Functionally with Haskell. Cambridge, England: Cambridge University Press.
Davie, A. (1992). Introduction to Functional Programming Systems Using Haskell. Cambridge, England: Cambridge University Press.
Goerzen, J. & O'Sullivan, B. & Stewart, D. (2008). Real World Haskell. Sebastopol, CA: O'Reilly Media, Inc.
Hutton, G. (2007). Programming in Haskell. New York: Cambridge University Press.
Lipovača, M. (2011). Learn You a Haskell for Great Good!: A Beginner's Guide. San Francisco, CA: No Starch Press, Inc.
Thompson, S. (2011). The Craft of Functional Programming. Edinburgh Gate, Harlow, England: Pearson Education Limited.