Functional Programming
What is functional programming?
Wikipedia (Functional Programming):
In computer science, functional programming is a programming paradigm—a style of building the structure and elements of computer programs—that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. It is a declarative programming paradigm, which means programming is done with expressions or declarations instead of statements.
What is functional programming?
- Programming Paradigm
- "a style of programming"
- "a rule set for our code"
- Express programs as a composition of functions
- Avoid mutating data
- Declarative programming
The goal of functional programming is to simplify
our code.
How do we get there?
- Break logic down into smaller functions
- Write Declarative and Composable Code
- Mutation in Isolation and Moderation
const greeting = "Hi, I'm "
const name = "Clayton"
console.log(greeting + name)
=> "Hi, I'm Clayton"
function greet(name) {
return "Hi, I'm " + name
}
console.log(greet("Clayton"))
=> "Hi, I'm Clayton"
function checkCarStatus(driver, car) {
let assembled;
if(car.isTotaled) {
if(driver.isMechanic) {
assembled = true;
}
else {
assembled = false;
}
}
else {
assembled = true;
}
return assembled && car.hasGas;
}
function isAssembled(driver, car) {
return !car.isTotalled || driver.isMechanic
}
function checkCarStatus(driver, car) {
return isAssembled(driver, car) && car.hasGas
}Immutability
Most bugs are caused by mutation issues.
What if we could eliminate unnecessary mutation and isolate the mutation that is needed from the logic of our program?
Pure Functions
A pure function is a function that satisfies two properties:
-
The function's output is deterministic based on the function's input.
- No side-effects take place inside the function.
Pure Functions
-
The function's output is deterministic based on the function's input.
- The same input to the function ALWAYS
provides the same output
-
No side-effects take place inside the function.
- No state external to the function is changed inside the
function.
ex. global variables, writing to streams, etc.
// Impure Function Example
let count = 0;
function incrementCountBy(x){
count += x
console.log('Incremeneted by: ', x)
return Math.random()
}
// Impure Function Example
let count = 0;
function incrementCountBy(x){
// side effect: mutating state outside the function
count += x
// side effect: writing to IO stream
console.log('Incremeneted by: ', x)
// return value is non-deterministic
return Math.random()
}
// Pure Function Example
function double(x) {
return x * 2
}Higher-Order Functions
(HOFs)
-
Accepts one or more functions as arguments
-
Returns a function
A higher-order function is a function does either of the following:
// inovke is a higher-order function
function invoke(f) {
return f()
}
function dummyFunction() {
return "I'm a dummyFunction"
}
const value = invoke(dummyFunction)
value
=> "I'm a dummyFunction"
function greetWith(greeting) {
return function(name) {
return greeting + name
}
}
const morningGreeting = greetWith("Good morning, ")
const students = ["Samantha", "Kunal", "George"]
let morningGreetings = [];
for(let i = 0; i < students.length; i++) {
morningGreetings.push(morningGreeting(students[i]))
}
morningGreetings
=> [ "Good morning, Samanatha",
"Good morning, Kunal",
"Good morning, George" ]
Avoid List Iteration with HOFs
Looping through lists is some of the most common code you'll write day-to-day.
Let's take a look at three higher-order functions that will let us avoid writing the same list iterations over and over again.
Map
The map function creates a new array with the results of calling a provided function on every element in the calling array.
const words = ['dog', 'plant', 'bike']
function makePlural(word) {
return word + 's'
}
const plurals = words.map(makePlural)
words
=> ['dog', 'plant', 'bike']
plurals
=> ['dogs', 'plants', 'bikes']
Usage:
Map
Exercise: Write a function whose goal is to take a list of numbers and increment each number in the list by 1.
Map
function incrementEntries(list) {
let res = [];
for(let i = 0; i < list.length; i++) {
res[i] = list[i] + 1
}
return res
}
const nums = [1, 2, 3]
const numsPlusOne = incrementEntries(nums)
numsPlusOne
=> [2, 3, 4]
Exercise: Write a function whose goal is to take a list of numbers and increment each number in the list by 1.
Map
function incrementEntries(list) {
return list.map(function(x) {
return x + 1
})
}
const nums = [1, 2, 3]
const numsPlusOne = incrementEntries(nums)
numsPlusOne
=> [2, 3, 4]Reduce
const nums = [1, 2, 3]
const sum = nums.reduce(function(accumulator, currentValue) {
return accumulator + currentValue
}, 0)The reduce function executes a reducer function (that you provide) on each member of the array resulting in a single output value.
Usage:
Reduce
Exercise: Find the max element in a list of numbers
Reduce
Exercise: Find the max element in a list of numbers
const counts = [23, 15, 6, 79, 12]
let maxCount = -Infinity
for(let i = 0; i < counts.length; i++) {
if(counts[i] > maxCount) {
maxCount = counts[i]
}
}
maxCount
=> 79Reduce
function max(x, y) {
if(x > y) {
return x
}
return y
}
const counts = [23, 15, 6, 79, 12]
const maxCount = counts.reduce(max, -Infinity)
maxCount
=> 79Filter
The filter function creates a new array with all elements that pass the test implemented by the provided function.
function isEven(num) {
return num % 2 == 0
}
const nums = [1,2,3,4,5]
const evens = nums.filter(isEven)
evens
=> [2, 4]Usage:
Writing Declarative Code
Imperative - describes how it is done.
Declarative - describes what is done.
const counts = [1,2,3,4,5,6,7,8,9,10]
let double_counts = []
for(let i = 0; i < counts.length; i++) {
double_counts[i] = counts[i] * 2
}vs.
const counts = [1,2,3,4,5,6,7,8,9,10]
function double(x) {
return x * 2
}
const double_counts = counts.map(double)Writing Declarative Code
- Easier to reason about
- You don't need to "be" the computer to understand what the code is doing.
- You don't need to "be" the computer to understand what the code is doing.
- Less Repetitive Code
- Easier debugging and testing
What do we get from writing declarative code?
Functional Refactoring Examples
function greetWith(greeting) {
return function(name) {
return greeting + name
}
}
const morningGreeting = greetWith("Good morning, ")
const students = ["Samantha", "Kunal", "George"]
let morningGreetings = [];
for(let i = 0; i < students.length; i++) {
morningGreetings.push(morningGreeting(students[i]))
}
morningGreetings
=> [ "Good morning, Samanatha",
"Good morning, Kunal",
"Good morning, George" ]Functional Refactoring Examples
function greetWith(greeting) {
return function(name) {
return greeting + name
}
}
const morningGreeting = greetWith("Good morning, ")
const students = ["Samantha", "Kunal", "George"]
const morningGreetings = students.map(morningGreeting)
morningGreetings
=> [ "Good morning, Samanatha",
"Good morning, Kunal",
"Good morning, George" ]Functional Refactoring Examples
Exercise: Create a new list containing incremented versions of the even numbers in the original list
const old_nums = [1, 2, 3, 4, 5];
let new_nums = [];
for (let i = 0; i < old_nums.length; i++) {
if (i % 2 == 0) {
new_nums.push(old_nums[i] + 1);
}
}
new_nums
=> [3, 5]Imperative Solution:
Functional Refactoring Examples
Exercise: Create a new list containing incremented versions of the even numbers in the original list
function increment(x) { return x + 1 }
function isEven(x) { return x % 2 == 0 }
const old_nums = [1, 2, 3, 4, 5]
const new_nums = old_nums.filter(isEven).map(increment);
new_nums
=> [3, 5]Declarative Solution:
Summary
Functional programming:
- Paradigm of programming whose goal is to simplify our code.
- How we do it
- Express our programs in terms of small composable functions.
- Write declarative code
- Avoiding data mutation when possible
Our goal is not to write functional code - our goal is simplicity, and functional programming is the tool we're using to achieve it.
Links to the slides, script, and other resources can be found in the Github Repo:
https://bit.ly/2SshXKX
Functional Programming
By clayton_m12
Functional Programming
- 183