F1 · Algebra
What a function really is
Before any syntax: a function is a rule that assigns to every input exactly one output. That one sentence is the whole foundation the rest of the course is built on.
The word is overloaded in everyday programming, where a “function” might print, mutate, or return something different each time it runs. Here we use the mathematical meaning, recover the three sets that define it, and then meet it again as an ordinary Elixir value. Get this right and composition, purity, and higher-order code all follow.
A function is a mapping
A function f connects two sets. It takes each element of a domain and assigns it a single element of a codomain. Nothing in the domain is left unassigned, and nothing is assigned twice. The subset of the codomain that actually gets used — the outputs that some input reaches — is the range.
Two different inputs may land on the same output; that is allowed. What is not allowed is one input reaching two outputs. Select a function below and watch where each element of the domain is sent.
- domain
- the set of inputs the function accepts; every one must be assigned.
- codomain
- the set the outputs are drawn from — the declared type of the result.
- range
- the outputs actually reached, also called the image; a subset of the codomain.
The mapping · choose a function
[-2, -1, 0, 1, 2] |> Enum.map(&(&1 * &1)) # => [4, 1, 0, 1, 4]
Algebra
f sends each element of the domain to one element of the codomain; the outputs it reaches are the range.
Elixir
Enum.map/2 applies the function across a collection — the same mapping, one input to one output.
Two inputs can share an output, but no input has two. That single-valued rule is what every later idea depends on.
Exactly one output
The defining property has a picture. Draw a relation on the plane and sweep a vertical line across it: if the line ever meets the curve more than once, some input has more than one output, and the relation is not a function. This is the vertical line test.
Compare two curves. y = x² is a function — every vertical line meets it once. x = y² is the same parabola turned on its side, and a vertical line through it meets it twice, so it fails. Move the line and read the count.
The vertical line test · count the outputs
Algebra
One input, one output — so f(a) names a single, definite value.
Elixir
A pure function returns the same result for the same argument, every time — the basis of F1.02.
Single-valued is not a technicality. It is the property that lets you replace f(a) with its value and never be wrong — the substitution model comes next.
Functions are values
In algebra a function is itself an object: you can name it, hand it to another function, and get one
back. Elixir takes this literally. A function is a value — written with
fn or captured with & — that you can bind to a name,
pass as an argument, and return as a result. Functions that take or return functions are
higher-order.
Below, a function is stored in a name and applied with .(). A second function,
apply_twice, takes that function as an argument and runs it on its own output —
the same composition idea you will formalise in F1.03.
First-class · store, pass, apply
Algebra
A function is an object — it can be named, passed to another function, and returned.
Elixir
f = fn x -> ... end, then f.(x); pass f to a higher-order function.
Because functions are values, programs are built by combining them. That is the move F1.07 generalises into map, filter, and reduce, and F2 makes into a way of working.
What this lands
One definition did the work: a function assigns to every input exactly one output, across a domain, a codomain, and the range it reaches. Single-valuedness makes f(a) a definite value you can substitute — the subject of F1.02. Treating functions as values makes them things you can combine — composition in F1.03 and the higher-order operators of F1.07. Everything in F1 grows from here.
Next: F1.02 — The substitution model — equals for equals, and why a pure function lets you reason by replacement.