Wednesday, September 17, 2025

OCAML CURRIED FUNCTIONS

 REVISED: Saturday, September 20, 2025                                     





1.  INTRODUCTION

Let's think about OCaml's special functions, called curried functions, using the process of baking a cake. 
 
What is a Curried Function?

Imagine a magical baking machine. Instead of putting all your ingredients in at once (like flour, sugar, and eggs), this machine takes them one at a time.

You put in flour. The machine doesn't give you a cake yet. Instead, it hums and gives you back a new machine that has the flour inside and is now waiting for sugar.

You give that new machine sugar. It still doesn't give you a cake! It gives you a third machine that has both flour and sugar and is now waiting for eggs.

You give that final machine eggs. Pop! Out comes your cake.

That's exactly how a curried function works! It's a function that takes its inputs (we call them arguments) one by one. Each time you give it an argument, it gives you back a new, more specialized function until it has all the arguments it needs to give you the final answer.

Why is This Useful?

This "one at a time" method is super useful because it lets you create new tools from your old ones very easily. This is called partial application.

Let's go back to our baking machine. What if you always make cakes that start with flour and sugar? You can give the machine flour, then give the next machine sugar, and then stop.

The machine you have now is a special "flour-and-sugar" machine. You can save it! Now, whenever you want to make a vanilla cake, you just add vanilla. If you want to make a chocolate cake, you use the same "flour-and-sugar" machine and just add cocoa powder.

You made a more specific tool from a general one. This makes your code smaller, easier to read, and lets you reuse work you've already done.

Let's See it in OCaml Code

Here is how we would write our baking machine idea in OCaml.

(*  ocaml C:\AI2025\baking_machine.ml  *)

(* This is our main function to "make" things. *)
(* It takes three ingredients one by one: ingredient1, ingredient2, and ingredient3. *)
(* Notice how we list the arguments with spaces, not commas in parentheses. *)
(* This is the OCaml way of saying "this is a curried function!" *)
let make_a_thing ingredient1 ingredient2 ingredient3 =
  (* This line just combines the three ingredients into a final string. *)
  ingredient1 ^ ", " ^ ingredient2 ^ ", and " ^ ingredient3;;

(* Now, let's make a more specific function from our general one. *)
(* We only give 'make_a_thing' its FIRST two ingredients: "flour" and "sugar". *)
let make_cake_base = make_a_thing "flour" "sugar";;

(* The variable 'make_cake_base' is NOT a string. *)
(* It's a NEW function that has "flour" and "sugar" saved inside. *)
(* It's just waiting for the final ingredient to be complete. *)

(* Let's use our new, specialized function to make two different cakes! *)
let vanilla_cake = make_cake_base "vanilla";;
let chocolate_cake = make_cake_base "cocoa";;

(* Now let's see what we made! *)
(* 'vanilla_cake' will hold the string "flour, sugar, and vanilla" *)
(* 'chocolate_cake' will hold the string "flour, sugar, and cocoa" *)

print_endline vanilla_cake;;
print_endline chocolate_cake;;

In OCaml, all functions with more than one argument are automatically curried. It's the default, simple, and powerful way the language works, letting you build new functions out of old ones just by giving them some of their arguments.

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 1609ms.
PS C:\Users\User> ocaml C:\AI2025\baking_machine.ml
flour, sugar, and vanilla
flour, sugar, and cocoa
PS C:\Users\User>

2. OCAML CURRIED FUNCTIONS

In OCaml, curried functions are functions that take multiple arguments one at a time. Instead of taking all arguments at once (like in a tuple), a curried function takes the first argument and returns a new function that waits for the second argument, and so on, until all arguments are supplied and the final result is returned. This is the default way OCaml handles functions with multiple parameters.

The name comes from the logician Haskell Curry, who developed the concept.

Uncurried vs. Curried Functions

Let's compare a standard (uncurried) function that uses a tuple with a curried function to see the difference.

A. The Uncurried Approach (Using Tuples)

An uncurried function takes all its arguments bundled together, typically in a tuple.

(* File:  add1.ml *)

(* Define a function 'add' that takes one argument: a tuple of two integers 
(int * int). *) let add (x, y) =

  (* It returns the sum of the two elements from the tuple. *)
  x + y;;

(* Call the 'add' function by passing it a single argument: the tuple (3, 4). *)
let result = add (3, 4);;

(* Print the result. Printf.printf is used for formatted printing. *)
(* "%d" is a placeholder for an integer. "\n" is a newline character. *)
Printf.printf "The uncurried result is: %d\n" result;;

(* Expected output: The uncurried result is: 7 *)

In this case, add has the type int * int -> int, meaning it takes a tuple of two integers and returns one integer. It must receive both values at the same time.

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 1091ms.

PS C:\Users\User>  ocaml C:\AI2025\add1.ml

The uncurried result is: 7

PS C:\Users\User>

B. The Curried Approach (The OCaml Default)

A curried function is defined to accept its arguments sequentially. This allows for a powerful feature called partial application.

(* File: ad2.ml *)

(* Define a curried function 'add'. It takes an integer 'x' first. *)
(* It then returns a *new* anonymous function that takes an integer 'y'. *)
let add x y =

  (* This inner function's body calculates the sum of x and y. *)
  x + y;;

(* Call the function by supplying the arguments one after another. *)
(* 'add 3' is evaluated first. It returns a new function. *)
(* That new function is then immediately called with the argument '4'. *)
let result = add 3 4;;

(* Print the final result to the console. *)
Printf.printf "The curried result is: %d\n" result;;

(* Expected output: The curried result is: 7 *)

Here, add has the type int -> int -> int. This can be read as int -> (int -> int). It means:

  1. add is a function that takes an int.

  2. It returns a new function of type int -> int (a function that takes an int and returns an int).

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 1091ms.

PS C:\Users\User>  ocaml C:\AI2025\ad2.ml

The curried result is: 7

PS C:\Users\User>

C. The Power of Currying: Partial Application

The real benefit of currying is partial application. This means you can supply some of the arguments to a curried function and get a new, specialized function back.

Let's extend our curried add example.

(* File: par_ap.ml *)

(* Define the same curried 'add' function as before. *)
(* Type: int -> int -> int *)
let add x y =
  x + y;;

(* --- Partial Application in Action --- *)

(* We apply 'add' with only *one* argument: the number 5. *)

(* This doesn't produce an error. Instead, it returns a new function. *)

(* This new function is "waiting" for the final argument, 'y'. *)

(* We bind this new function to the name 'add_five'. *)
let add_five = add 5;;

(* The inferred type of 'add_five' is: int -> int *)
(* It's a function that takes one integer and adds 5 to it. *)


(* Now we can use our new, specialized function 'add_five'. *)
(* Call 'add_five' with the argument 10. *)
let result1 = add_five 10;; (* This is equivalent to `add 5 10` *)

(* Call 'add_five' with the argument 3. *)
let result2 = add_five 3;; (* This is equivalent to `add 5 3` *)


(* Print the results. *)
Printf.printf "Adding 5 to 10 gives: %d\n" result1;;

(* Expected output: Adding 5 to 10 gives: 15 *)

Printf.printf "Adding 5 to 3 gives: %d\n" result2;;

(* Expected output: Adding 5 to 3 gives: 8 *)
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 1082ms.
PS C:\Users\User> ocaml C:\AI2025\par_ap.ml
Adding 5 to 10 gives: 15
Adding 5 to 3 gives: 8
PS C:\Users\User>
3. CONCLUSION 
Currying is fundamental to OCaml because it allows you to easily create specialized functions from more general ones. By providing initial arguments, you "fix" certain parameters, making your code more modular, reusable, and expressive. This is a core concept in functional programming.

 4. 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.