Welcome to the World of Functional Programming!

In most of your programming so far, you have probably used the imperative paradigm—telling the computer exactly how to do something step-by-step (like a recipe). In this chapter, we explore the functional programming paradigm. Instead of a list of instructions, we treat programs like a series of mathematical transformations.

Don't worry if this seems a bit "maths-heavy" at first! We are going to break it down using simple ideas you already know, like vending machines and Lego blocks.

4.12.1.1 Function Type

In functional programming, a function is a rule that maps a set of inputs to a set of outputs. We write this using the notation:
\( f: A \rightarrow B \)

What does this notation mean?

  • \( f \): This is just the name of the function.
  • \( A \): This is the Domain. It is the set of all possible input values.
  • \( B \): This is the Co-domain. It is the set from which the output values are chosen.

The Rule: For every input in the Domain, the function assigns exactly one output from the Co-domain. However, notice that not every value in the Co-domain has to be used!

Example: Imagine a function that tells you the position of a letter in the alphabet.
Domain: {a, b, c... z}
Co-domain: {0, 1, 2... 25}
If you input 'a', the function maps it to 0. If you input 'b', it maps to 1.

Quick Review: Domain vs. Co-domain

Think of a Vending Machine:
The Domain is the buttons you can press (A1, B2, etc.).
The Co-domain is all the snacks inside the machine. Even if the machine is out of Crisps, "Crisps" are still part of the Co-domain because they could be an output.

Key Takeaway: The Domain is where your data comes from; the Co-domain is the "pool" of possible results.

4.12.1.2 First-class Objects

In functional programming, functions are first-class objects. This is a fancy way of saying that functions are treated exactly like any other data type (like integers or strings).

If something is a first-class object, it can:

  1. Appear in expressions.
  2. Be assigned to a variable.
  3. Be passed as an argument to another function.
  4. Be returned as the result of a function call.

Did you know? In languages like Python or Haskell, you can literally set a variable equal to a function, like: my_function = print. Now, my_function("Hello") will work just like the print command!

Key Takeaway: A first-class object is a "VIP" citizen of the programming language—it can go anywhere and be used in any way that a normal piece of data can.

4.12.1.3 Function Application

Function application is simply the process of giving a function its inputs (arguments).
Example: If you have a function called add, then add(3, 4) is the application of that function to the arguments 3 and 4.

The "One Argument" Secret

Even though we might say a function like add(x, y) takes two arguments, functional programming technically views it as taking only one argument: a pair of numbers.
In maths, we write this as: \( f: \text{integer} \times \text{integer} \rightarrow \text{integer} \)
The \( \times \) symbol represents the Cartesian product, which is just a fancy way of saying "a pair of integers."

Key Takeaway: Applying a function means "triggering" it with real data.

4.12.1.4 Partial Function Application

This is where things get really cool! Since functions are first-class objects, we can give a function some of its arguments, but not all of them. This returns a new, specialized function that is waiting for the remaining arguments.

Analogy: Imagine a coffee machine.
1. You apply the "Coffee Pod" argument.
2. The machine doesn't give you a drink yet; it is now a specialized machine waiting for the "Water" argument.
3. Once you add water, the process is complete.

The Notation

Let's look at an add function:
Normally: add(x, y)
In partial application: add: integer \( \rightarrow \) (integer \( \rightarrow \) integer)

If we call add 4, it returns a new function that adds 4 to whatever you give it. If you then give that new function a 6, the final result is 10.

Common Mistake to Avoid:

Don't confuse Partial Application with a regular function call. In a regular call, you want a final answer (like 10). In partial application, you are intentionally creating a new, simpler function to use later.

Key Takeaway: Partial application takes a function that needs several arguments and turns it into a series of functions that take one argument at a time.

4.12.1.5 Composition of Functions

Functional composition is the process of combining two functions to create a brand-new function. You take the output of the first function and use it as the input for the second.

If we have two functions:
\( f: A \rightarrow B \)
\( g: B \rightarrow C \)
We can combine them into a new function: \( g \circ f \)

Important: In the notation \( g \circ f \), the function on the right (\( f \)) happens first! Its result is then passed to the function on the left (\( g \)).

Real-World Example:

Imagine two functions:
1. f(x): Add 2 to a number.
2. g(x): Cube the number (\( x^3 \)).

The composition \( g \circ f \) would be: \( (x + 2)^3 \).
If you input 1: First add 2 (result: 3), then cube it (final result: 27).

Memory Aid: The "Fog" Rule

When you see \( g \circ f \), read it backwards or think of it as "g of f". It’s like a production line—data flows from the right-hand function into the left-hand one.

Key Takeaway: Composition is like snapping Lego bricks together. The output of one "brick" must fit perfectly into the input of the next to build something bigger.

Chapter Summary - Quick Review

  • Function Type: Defined by its Domain (inputs) and Co-domain (possible outputs).
  • First-class Object: Functions can be treated like any other variable (passed around, returned, etc.).
  • Function Application: Using a function with specific inputs.
  • Partial Application: Giving only some arguments to create a new, specialized function.
  • Composition: Combining two functions (\( f \) and \( g \)) so that the output of one becomes the input of the other (\( g \circ f \)).