Now Reading: Functional Programming: The Good, The Bad, and Why You Should Care

Loading

Functional Programming: The Good, The Bad, and Why You Should Care

svgSeptember 13, 2024UncategorizedCodeStackGuide

Functional Programming: The Good, The Bad, and Why You Should Care

Functional programming is amazing, but let’s face it: functional programmers can be bad marketers. You throw around terms like currying, monads, functors, and expect the world to be dazzled. But the truth is, many people don’t fully grasp what these words mean, and that’s because they exist somewhere between category theory, lambda calculus, and how they’re implemented in programming languages.

Yet, beneath all the jargon, there’s undeniable beauty in functional programming. It simplifies the concept of a pure function, a function that always returns the same output for the same input without side effects. Let’s unpack why this matters, where functional programming can suck, and why adopting a bit of it could improve your code.

What is Functional Programming?

At its core, functional programming is about writing software using only functions—no state, no mutable variables. Functions take inputs and return outputs, and the same input always results in the same output. In this pure world, you avoid objects and mutable structures. Here’s an example:

const add = (x, y) => x + y;
console.log(add(2, 3)); // Outputs: 5

Pure functional programming means no changing variables and no loops like for or while. That might sound restrictive, but it leads to more predictable, easier-to-debug code. So how do we loop without mutating variables?

Recursion: The Functional For Loop

Since traditional loops require a changing variable (like an index), functional programming replaces loops with recursion. Instead of incrementing an index in a loop, you simply call the function with a new argument. Here’s a simple example of recursion:

const printNumbers = (n) => {
  if (n > 5) return;
  console.log(n);
  printNumbers(n + 1);
};

printNumbers(1); 
// Outputs: 1, 2, 3, 4, 5

Recursion replaces iteration. You define a base case (when to stop) and a recursive case (what to do in each step).

Why Functional Programming Sucks (Sort Of)

Pure functional programming can feel restrictive. You can’t mutate state, which is awkward because real-world applications have state—users interact, things change. A 100% functional approach ignores the fact that computers do change state. The von Neumann architecture literally relies on changing memory states.

Pure functional programming also introduces concepts that can be difficult for beginners to grasp, like monads and functors, which attempt to handle state in purely functional systems. But these concepts are often too theoretical for practical, day-to-day coding needs.

That said, you don’t need to go fully functional to reap the benefits.

Why Functional Programming is Still Awesome

The beauty of functional programming lies in its ability to reduce state and simplify data pipelines. Even in non-functional languages like JavaScript, you can apply some functional principles to write more maintainable code.

For example, instead of using loops and mutable variables, you can use built-in JavaScript array methods like map, filter, and reduce:

const receipts = [
  { userId: 1, merchant: 'Store A', total: 10 },
  { userId: 2, merchant: 'Store B', total: 15 },
  { userId: 1, merchant: 'Store C', total: 20 },
];

const userReceipts = receipts
  .filter(receipt => receipt.userId === 1)
  .map(receipt => receipt.merchant);

console.log(userReceipts); 
// Outputs: ['Store A', 'Store C']

Here, we’ve used filter to grab all receipts for a specific user and map to extract the merchant names. No loops, no mutable state. It’s clean, declarative, and easy to reason about.

Currying: More Than Just a Fancy Name

Functional programming also introduces a concept called currying, where instead of taking multiple arguments at once, you return a series of functions that each take one argument. This technique allows functions to remember some state.

const userIdEquals = userId => receipt => receipt.userId === userId;

const filterByUserId = (receipts, userId) => {
  return receipts.filter(userIdEquals(userId));
};

const result = filterByUserId(receipts, 1);
console.log(result);
// Outputs receipts with userId: 1

Currying is powerful because it allows you to create reusable functions, with logic broken down into small, composable pieces.

Building Functional Data Pipelines

One of the best uses of functional programming is in creating data pipelines. You take input, apply transformations, and output the result—all in a declarative, readable way. In JavaScript, this can be achieved with array methods.

Imagine you’re building a financial app that checks if a tip on a restaurant receipt was fraudulently altered. Here’s a procedural way to handle that:

const checkDiscrepancy = (receipts) => {
  let results = [];
  for (let i = 0; i < receipts.length; i++) {
    if (receipts[i].finalTotal !== receipts[i].tip + receipts[i].subtotal) {
      results.push(receipts[i]);
    }
  }
  return results;
};

Here’s the same logic, rewritten in a functional style:

const discrepancies = receipts
  .filter(receipt => receipt.finalTotal !== (receipt.tip + receipt.subtotal))
  .map(receipt => ({
    receipt,
    discrepancy: receipt.finalTotal - (receipt.tip + receipt.subtotal),
  }));

console.log(discrepancies);

This pipeline is shorter, more readable, and easier to debug.

Functional Programming for Real-World Applications

While pure functional programming is not always practical, selectively applying its principles can improve your code quality. By adopting techniques like immutable data, recursion, currying, and functional data pipelines, you can simplify your code while making it more maintainable and easier to debug.

In modern JavaScript, you already have access to tools that make functional programming easy, such as higher-order functions like map, filter, reduce, and lambda functions.

Conclusion

Functional programming isn’t about religiously adhering to academic principles like monads or currying. It’s about finding balance—using functional techniques to write cleaner, more maintainable code while not going so far that you make your code unreadable.

Embrace functional programming when it makes sense. Use data pipelines and reduce state where possible, and you’ll find that your code becomes easier to manage, debug, and scale. Try integrating a few of these concepts, and you might just fall in love with deleting for loops.


0 People voted this article. 0 Upvotes - 0 Downvotes.
svg

What do you think?

Show comments / Leave a comment

Leave a reply

svg
Quick Navigation
  • 01

    Functional Programming: The Good, The Bad, and Why You Should Care