jonnifyelixir

F2 · Functional Programming

Closures & partial application

A closure is a function bundled with the environment it was defined in. It can read the variables that were in scope when it was created — carrying them along after that scope is gone. That is what lets one function build another, tailored to a value decided earlier.

The folds in F2.05 took small functions as their combiners. Those functions usually need a value from their surroundings — a factor to multiply by, a threshold to compare against. A closure captures that value. Partial application is the same idea pointed at arguments: fix some of a function’s inputs now and supply the rest later. Both are built from one mechanism — a function remembering its environment.

A closure carries its captured environment

build with n = 3 make_multiplier(3) returns closure fn x -> x * n end captured env · n = 3 apply an argument multiplier.(5) awaiting x

make_multiplier(3) returned a closure that captured n = 3.
It is awaiting an argument x.

A function that remembers

A function defined inside another can use the outer function’s variables. Return that inner function and it keeps them. make_adder takes n and returns a function that adds n to whatever it is later given — the n is captured.

Set the captured value and the later argument.

closure
a function together with the variables it captured from its surrounding scope.
capture
remembering a variable’s value from where the function was defined.
partial application
fixing some arguments now and supplying the rest later.
&
Elixir’s capture operator — shorthand for an anonymous function.

make_adder · the returned function captures n

10
5
build make_adder.(10) closure (captures n) fn x -> x + 10 end apply x 15 x + n = 5 + 10 = 15


      
captures n = 10 · apply x = 5 · 5 + 10 = 15

Idea

A function can carry a value decided earlier — the captured environment travels with it.

F2.05 · folds

The combiner a fold takes is often a closure over a factor or threshold.

A closure is a function plus a remembered value. make_adder turns one number into a whole family of adders.

Partial application

Partial application fixes some of a function’s arguments and leaves the rest open. From a two-argument add, fixing the first gives a one-argument function waiting for the second. The fixed value is captured, exactly as before.

Fix the first argument, then supply the second.

fix a, wait for b · from a two-argument add

5
3
two arguments fn a, b -> a + b end fix a fn b -> 5 + b end apply b 8 a + b = 5 + 3 = 8


      
fix a = 5 · apply b = 3 · 5 + 3 = 8

Idea

Specialise a general function by pinning down some of its inputs in advance.

Elixir

Elixir does not curry on its own; you wrap the call in a closure to fix an argument.

Partial application is capture aimed at arguments: fix what you know now, keep the rest open.

The & shorthand

Anonymous functions are common enough that Elixir has a shorthand: the capture operator &. Inside &(…), &1 and &2 stand for the first and second arguments. It is the same function as the fn form, written shorter.

Compare the two forms.

& form and fn form · the same function

& form &(&1 + 1) ≡ fn form fn x -> x + 1 end


      
add one · the & form and the fn form are the same function

F1.07 · higher-order

The functions you pass to map, filter, and reduce are most often written with &.

Elixir

Use & for short, single-expression functions; use fn when it reads clearer.

The & operator is a compact fn. Same function, fewer characters.

Three deep dives

This module continues across three pages: what is captured and when, the capture operator in full, and partial application built up into currying. Read them in order.

F2.06.1
Capturing the environment
What a closure captures and when — the value at definition time, and why immutability makes it stable.
F2.06.2
The capture operator
The & shorthand in full: positional placeholders, and capturing named functions with &Mod.fun/arity.
F2.06.3
Partial application & currying
Fixing arguments to specialise a function, and currying by hand — one argument at a time.

What this lands

A closure is a function carrying the environment it was defined in, so it can use a value decided earlier. That single mechanism gives you function factories like make_adder and partial application, where fixing an argument is itself a capture. The & operator is a short way to write these small functions. The three deep dives above pin down capture semantics, the capture operator, and currying; F2.07 then turns from functions to data, with algebraic data types.

Start with capturing the environment, then the capture operator, then partial application & currying. Next module: F2.07 — Algebraic data types.