Read:09 | Functional Programming
Article: Functional Programming Concepts | Article: Refactoring JS for Readability
Notes from Functional Programming Concepts
Functional programming is the computation of mathematical functions that works to avoid mutable data
Pure functions
- Pure functions will give the same result if given the same arguments repeatedly and do not cause noticeable side effects.
- A function will be impure simply if a global object was not passed as a parameter to the function
- A function can be pure if it doesn’t refer to an external declared object
- Here is an example of a function that is pure because it takes
pias a parameter instead of usingnum:let num = 3.14; const calculateArea = (radius, pi) => radius * radius * pi; calculateArea(10, num); // returns 314.0 - Just like when trying to avoid using a global variable as a parameter when declaring a function, try to avoid reading external variables.
- The definition of a noticeable side-effect from above includes modifying a global object or a parameter that is passed by reference.
-
Here is a impure counter function:
-
Here is the same function, but pure:
-
Typically, we would use a
forloop for iteration but it makes the variables mutable (this is not ideal). Instead, let’s use recursion!!! -
This is an example of writing a counter with mutable variables (not ideal):
-
Use recursion to avoid mutability while iterating (this is better!):
Misc stuff
- When you have pure functions + immutable data = referential transparency.
- First-class entities is what you call a function that is also treated as a value used as data.
- The first-class function can be referred to by constants and variables
- Pass it as a parameter to other functions
- Return it as a result from other functions
-
When functions have similar logic but different operators (like addition vs. subtraction), you can build a function that receives the operator function and uses it inside the other function:
- Higher-order functions take one or more functions as arguments or return a function as its result.
- The
doubleOperatorfunction in the above screenshot is considered higher-order.
- The
Array.filteris a function that expectstrueorfalse. For example, if the callback expression is true, the filter function will include the element in the result.-
The below screenshots will show how to filter even numbers the bad (mutable) way, and then the good (immutable) way:
-
Another example of if you want to filter a given array of integers and output the values that are less than a specified value
x– instead of a for loop in one function, use a pure declarative like the screenshot below: -
The
Array.mapmethod transforms a collection by applying a function to all of its elements and building a new collection from the returned values. -
Here is an example of a higher-order function using
map: reducereceives a function and a collection and returns a value created by combining the items. For example, a way to get the total amount is to composemapandreduceas in the below pure example:getAmountreceives the product object and returns only theamountvalue and thereducecombines all items by adding up:
Here is your ultimate goal when utilizing filter, map, and reduce with pure functionality:
Notes from Refactoring JS for Readability
- It is good to check your code for any possible refactoring before submitting a PR
- Below is an example from the article about some code they refactored to prevent possible issues: ```js // Unrefactored code
const friendlyWords = require(‘friendly-words’);
function randomPredicate() { const choice = Math.floor(Math.random() * friendlyWords.predicates.length); return friendlyWords.predicates[choice]; }
function randomObject() { const choice = Math.floor(Math.random() * friendlyWords.objects.length); return friendlyWords.objects[choice]; }
async function createUser(email) { const user = { email: email }; user.url = randomPredicate() + randomObject() + randomObject(); await db.insert(user, ‘Users’) sendWelcomeEmail(user);
```js
// Refactored code
const friendlyWords = require('friendly-words');
const generateURL = user => {
const pick = arr => arr[Math.floor(Math.random() * arr.length)];
user.url = `${pick(friendlyWords.predicates)}-${pick(friendlyWords.objects)}` +
`-${pick(friendlyWords.objects)}`; // This line would've been too long for linters!
};
async function createUser(email) {
const user = { email: email };
// The URL-creation algorithm isn't important to this function so let's abstract it away
generateURL(user);
await db.insert(user, 'Users')
sendWelcomeEmail(user);
}
- The above example inlined a function called
pickth accept an array and return a random choicethen used a template literaly to build a URL - There are no absolutes for clean code, so it’s case by case.
- Here are general tips:
- Return early from functions
- Cache variables so functions can be read like sentences
- Check for web APIs before implementing your own functionality