Functions
6.1 Defining functions
Calling — no parentheses or commas:
let square x = x * x
(* val square : int -> int *)
let add x y = x + y
(* val add : int -> int -> int *)
let greet name = "Hello, " ^ name ^ "!"square 5 (* 25 *)
add 2 3 (* 5 *)
add 2 (square 3) (* 11 — parentheses group arguments *)
square (-3) (* parenthesise negative literals! square -3 means square - 3 *)6.2 Anonymous functions (lambdas)
fun x -> x * 2
(fun x y -> x + y) 3 4 (* 7 *)
let square = fun x -> x * x (* same as let square x = x * x *)6.3 Currying & partial application
Every multi-argument function is a chain of single-argument functions: int -> int -> int means int -> (int -> int).
let add x y = x + y
let add5 = add 5 (* int -> int *)
add5 10 (* 15 *)
let increment_all = List.map (add 1)
increment_all [1;2;3] (* [2;3;4] *)6.4 Tupled vs curried
Prefer curried style — it enables partial application.
let add_tupled (x, y) = x + y (* (int * int) -> int — one argument, a pair *)
let add_curried x y = x + y (* int -> int -> int *)6.5 Operators are functions
(+) 2 3 (* 5 *)
List.fold_left (+) 0 [1;2;3]
( * ) 3 4 (* note spaces: (* would start a comment *)6.6 Defining custom operators
Allowed characters: ! $ % & * + - . / : < = > ? @ ^ | ~.
let ( |>> ) x f = f (f x)
let ( +/ ) a b = (a + b) / 2
let ( let* ) = Option.bind (* binding operators: see chapter 33 *)
5 |>> (fun x -> x * 2) (* 20 *)6.7 Pipeline & application operators
let ( |> ) x f = f x (* built-in *)
let ( @@ ) f x = f x (* built-in, right-assoc, low precedence *)
[1;2;3;4]
|> List.filter (fun x -> x mod 2 = 0)
|> List.map (fun x -> x * x)
|> List.fold_left (+) 0 (* 20 *)
print_endline @@ string_of_int @@ 426.8 Labeled arguments
let divide ~num ~den = num / den
divide ~num:10 ~den:2 (* 5 *)
divide ~den:2 ~num:10 (* order doesn't matter *)
let num = 10 and den = 2 in
divide ~num ~den (* label punning *)
let f ~x:renamed = renamed + 1 (* rename inside the body *)6.9 Optional arguments
Rule: An optional argument must be followed by at least one positional argument, otherwise it can never be "erased" (warning 16).
let greet ?(greeting = "Hello") name = greeting ^ ", " ^ name
greet "Ann" (* "Hello, Ann" *)
greet ~greeting:"Hi" "Ann" (* "Hi, Ann" *)
let log ?prefix msg = (* prefix : string option inside *)
match prefix with
| None -> print_endline msg
| Some p -> print_endline (p ^ msg)
let opt = Some "[x] " in log ?prefix:opt "hello" (* pass an option directly *)6.10 Function composition
let compose f g x = f (g x)
let ( % ) f g x = f (g x)
let inc_then_double = (fun x -> x * 2) % (fun x -> x + 1)
inc_then_double 3 (* 8 *)
(* Stdlib 5.2+: Fun.compose *)6.11 function keyword (match on the last argument)
let describe = function
| 0 -> "zero"
| n when n < 0 -> "negative"
| _ -> "positive"6.12 The Fun module
Fun.id 5 (* 5 *)
Fun.const 1 "ignored" (* 1 *)
Fun.flip (-) 1 10 (* 9 *)
Fun.negate (fun x -> x > 0) 5 (* false *)
Fun.protect ~finally:(fun () -> print_endline "cleanup") (fun () -> 42)6.13 Closures
let make_multiplier n = fun x -> x * n
let triple = make_multiplier 3
triple 7 (* 21 — n is captured in the closure *)