Skip to content
Higher-Order Functions
step 1/7

Reading — step 1 of 7

Learn

~3 min readHigher-Order, Exceptions, Imperative

Functions are first-class in OCaml. Pass them around, return them, store them — the foundation of functional style.

Functions as values

let double x = x * 2
let f = double                       (* alias the function *)
let () = Printf.printf "%d\n" (f 5)  (* 10 *)

Functions have types like values: double : int -> int.

Anonymous functions (lambdas)

let f = fun x -> x * 2
let g = fun x y -> x + y

fun args -> body. Multi-arg lambdas can be written fun x y -> ... (which is really fun x -> fun y -> ... — currying).

Currying — partial application

All OCaml functions are curried by default:

let add x y = x + y                   (* int -> int -> int *)
let add5 = add 5                       (* int -> int — partially applied *)
let () = Printf.printf "%d\n" (add5 10)  (* 15 *)

Calling add 5 with only one argument returns a function expecting the second. No special syntax needed — just call with fewer args.

map, filter, fold

List.map (fun x -> x * 2) [1; 2; 3]              (* [2; 4; 6] *)
List.filter (fun x -> x > 2) [1; 2; 3; 4]        (* [3; 4] *)
List.fold_left (+) 0 [1; 2; 3]                    (* 6 *)
List.fold_left (fun acc x -> x :: acc) [] [1; 2; 3]   (* [3; 2; 1] — manual reverse *)

Pipe operator |> — readable pipelines

let result =
    [1; 2; 3; 4; 5]
    |> List.filter (fun x -> x mod 2 = 1)
    |> List.map (fun x -> x * x)
    |> List.fold_left (+) 0
(* 1*1 + 3*3 + 5*5 = 35 *)

x |> f is f x. Chains of single-arg applications read top-to-bottom. Idiomatic for pipelines.

Function composition

let (>>) f g x = g (f x)

let pipeline = (fun x -> x + 1) >> (fun x -> x * 2) >> string_of_int
let () = print_endline (pipeline 5)   (* "12" *)

No built-in compose operator in stdlib — define it or use Fun.compose from the stdlib (recent versions).

Useful higher-order helpers

Fun.id x                      (* x — identity *)
Fun.const 42 x                (* 42 — constant function *)
Fun.flip f a b                (* f b a — argument swap *)

List.iter print_int [1; 2; 3]
List.exists (fun x -> x > 5) [1; 2; 3]    (* false *)
List.for_all (fun x -> x > 0) [1; 2; 3]    (* true *)
List.find (fun x -> x > 2) [1; 2; 3]       (* 3; throws if no match *)
List.find_opt (fun x -> x > 5) [1; 2; 3]   (* None *)

Common mistakes

  • Using == for function equality — function equality is undefined / generally false; comparing functions doesn't make sense.
  • Forgetting |> — newcomers write nested calls. The pipe makes flow obvious.
  • Currying surpriseadd 5 returns a function. If you meant to call it, you forgot the second arg.
  • fun arity confusionfun x y -> ... is two-arg. fun (x, y) -> ... takes a TUPLE.
  • Reaching for compose when pipe works — for value flow, pipe. compose is for building reusable compositions.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…