Skip to content
AgileLogics
5 min read

Currying and Partial Application

Prerequisites: Pipelines and composition

Every F# function really takes one argument. A function "with two parameters" is a function that takes the first argument and returns a function waiting for the second. This is called currying, and it's why the signature is written int -> int -> int — which means int -> (int -> int).

Partial application

Call a function with fewer arguments than it expects, and you get back a function waiting for the rest:

let add a b = a + b

let add10 = add 10       // int -> int
printfn "%d" (add10 5)
printfn "%d" (add10 32)

let multiply a b = a * b
let triple = multiply 3
printfn "%A" (List.map triple [1; 2; 3])
15
42
[3; 6; 9]

Why it matters: pipelines

List.map triple is itself a partial application: List.map is waiting for its list. That's exactly what |> supplies:

let applyDiscount percent price = price - price * percent / 100.0
let addTax rate price = price * (1.0 + rate)

let finalPrice =
    100.0
    |> applyDiscount 20.0
    |> addTax 0.1

printfn "%.2f" finalPrice
88.00

applyDiscount 20.0 is a function float -> float, and so is addTax 0.1 — which is why they chain so neatly. This is the payoff of putting the data parameter last.

Partial application with printf

let logInfo = printfn "[INFO] %s"
logInfo "Server started"
logInfo "Listening on port 8080"
[INFO] Server started
[INFO] Listening on port 8080

Tupled parameters

If you write parameters in parentheses with commas, the function takes one tuple and can't be partially applied. .NET methods (like System.Math.Max(3, 7)) are called this way:

let addTupled (a, b) = a + b
printfn "%d" (addTupled (2, 3))
printfn "%d" (System.Math.Max(3, 7))
5
7

Prefer curried parameters for your own F# functions; tupled ones are mainly for .NET interop and methods on classes.

  • let f a b = ... is curried: f 1 is a valid function.
  • Order parameters from "most fixed" to "most variable" (data last).
  • Too few arguments by accident? The compiler will tell you that you have a function where it expected a value.