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:
- Appear in expressions.
- Be assigned to a variable.
- Be passed as an argument to another function.
- 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 \)).