Functional programming is based on the simplest of models, namely that of finding
the value of an expression. This we meet in our first years at school, when we learn
to work out expressions like `8+(3-2)` by evaluating the two halves, `8`
and `(3-2)`, and adding the results together. Functional programming consists
of our defining for ourselves functions like `+` which we can then use to form
expressions.

We define these functions by means of equations, like

addD a b = 2*(a+b) (1)

which we use to calculate the value of an expression like
`addD 2 (addD 3 4)`.
We evaluate this using `(1)` to replace occurrences of `addD` with
their values, so that we can write down a calculation of its value

addD 2 (addD 3 4) = 2*(2 + (addD 3 4)) = 2*(2 + 2*(3 + 4)) = 32

As well as using `(1)` to calculate, we can read it as a logical description of how
the function `addD` behaves on any values `a` and `b`; on the basis of
this we can reason about how it behaves. For instance, for any values `
a` and `b`,

addD a b = 2*(a+b) = 2*(b+a) = addD b a

This equation holds for *all* possible input values, in contrast to the
information we gain from testing a function at a selection of inputs.

On top of this simple model we can build a variety of facilities, which give the functional approach its distinctive flavour. These include higher-order functions, whose arguments and results are themselves functions; polymorphism, which allows a single definition to apply simultaneously to a collection of types; and infinite data structures which are used to model a variety of data objects.

The Miranda language also has support for larger-scale programming, including user-defined algebraic types, such as lists, trees and so on; abstract data types and modules. These contribute to separating complex tasks into smaller sub-tasks, making the components of systems independent of each other, as well as supporting software re-use.

Next Up