about summary refs log tree commit diff stats
path: root/bash/talk-to-computer/corpus/programming/functional_programming.md
diff options
context:
space:
mode:
Diffstat (limited to 'bash/talk-to-computer/corpus/programming/functional_programming.md')
-rw-r--r--bash/talk-to-computer/corpus/programming/functional_programming.md234
1 files changed, 234 insertions, 0 deletions
diff --git a/bash/talk-to-computer/corpus/programming/functional_programming.md b/bash/talk-to-computer/corpus/programming/functional_programming.md
new file mode 100644
index 0000000..2572442
--- /dev/null
+++ b/bash/talk-to-computer/corpus/programming/functional_programming.md
@@ -0,0 +1,234 @@
+# Functional Programming - A paradigm for declarative, predictable code
+
+## Introduction
+
+**Functional Programming (FP)** is a programming paradigm where software is built by composing **pure functions**, avoiding shared state, mutable data, and side-effects. It treats computation as the evaluation of mathematical functions. Instead of describing *how* to achieve a result (imperative programming), you describe *what* the result is (declarative programming).
+
+This paradigm has gained significant traction because it helps manage the complexity of modern applications, especially those involving concurrency and complex state management. Programs written in a functional style are often easier to reason about, test, and debug.
+
+## Core Concepts
+
+### Pure Functions
+
+A function is **pure** if it adheres to two rules:
+
+1.  **The same input always returns the same output.** The function's return value depends solely on its input arguments.
+2.  **It produces no side effects.** A side effect is any interaction with the "outside world" from within the function. This includes modifying a global variable, changing an argument, logging to the console, or making a network request.
+
+<!-- end list -->
+
+```javascript
+// Pure function: predictable and testable
+const add = (a, b) => a + b;
+add(2, 3); // Always returns 5
+
+// Impure function: has a side effect (console.log)
+let count = 0;
+const incrementWithLog = () => {
+  count++; // And mutates external state
+  console.log(`The count is ${count}`);
+  return count;
+};
+```
+
+### Immutability
+
+**Immutability** means that data, once created, cannot be changed. If you need to modify a data structure (like an object or array), you create a new one with the updated values instead of altering the original. This prevents bugs caused by different parts of your application unexpectedly changing the same piece of data.
+
+```javascript
+// Bad: Mutating an object
+const user = { name: "Alice", age: 30 };
+const celebrateBirthdayMutable = (person) => {
+  person.age++; // This modifies the original user object
+  return person;
+};
+
+// Good: Returning a new object
+const celebrateBirthdayImmutable = (person) => {
+  return { ...person, age: person.age + 1 }; // Creates a new object
+};
+
+const newUser = celebrateBirthdayImmutable(user);
+// user is still { name: "Alice", age: 30 }
+// newUser is { name: "Alice", age: 31 }
+```
+
+### First-Class and Higher-Order Functions
+
+In FP, functions are **first-class citizens**. This means they can be treated like any other value:
+
+  * Assigned to variables
+  * Stored in data structures
+  * Passed as arguments to other functions
+  * Returned as values from other functions
+
+A function that either takes another function as an argument or returns a function is called a **Higher-Order Function**. Common examples are `map`, `filter`, and `reduce`.
+
+```javascript
+const numbers = [1, 2, 3, 4];
+const isEven = (n) => n % 2 === 0;
+const double = (n) => n * 2;
+
+// `filter` and `map` are Higher-Order Functions
+const evenDoubled = numbers.filter(isEven).map(double); // [4, 8]
+```
+
+## Key Principles
+
+  - **Declarative Style**: Focus on *what* the program should accomplish, not *how* it should accomplish it. An SQL query is a great example of a declarative style.
+  - **No Side Effects**: Isolate side effects from the core logic of your application. This makes your code more predictable.
+  - **Function Composition**: Build complex functionality by combining small, reusable functions.
+  - **Referential Transparency**: An expression can be replaced with its value without changing the behavior of the program. This is a natural outcome of using pure functions and immutable data.
+
+## Implementation/Usage
+
+The core idea is to create data transformation pipelines. You start with initial data and pass it through a series of functions to produce the final result.
+
+### Basic Example
+
+```javascript
+// A simple pipeline for processing a list of users
+const users = [
+  { name: "Alice", active: true, score: 90 },
+  { name: "Bob", active: false, score: 80 },
+  { name: "Charlie", active: true, score: 95 },
+];
+
+/**
+ * @param {object[]} users
+ * @returns {string[]}
+ */
+const getHighScoringActiveUserNames = (users) => {
+  return users
+    .filter((user) => user.active)
+    .filter((user) => user.score > 85)
+    .map((user) => user.name.toUpperCase());
+};
+
+console.log(getHighScoringActiveUserNames(users)); // ["ALICE", "CHARLIE"]
+```
+
+### Advanced Example
+
+A common advanced pattern is to use a reducer function to manage application state, a core concept in The Elm Architecture and libraries like Redux.
+
+```javascript
+// The state of our simple counter application
+const initialState = { count: 0 };
+
+// A pure function that describes how state changes in response to an action
+const counterReducer = (state, action) => {
+  switch (action.type) {
+    case 'INCREMENT':
+      return { ...state, count: state.count + 1 };
+    case 'DECREMENT':
+      return { ...state, count: state.count - 1 };
+    case 'RESET':
+      return { ...state, count: 0 };
+    default:
+      return state;
+  }
+};
+
+// Simulate dispatching actions
+let state = initialState;
+state = counterReducer(state, { type: 'INCREMENT' }); // { count: 1 }
+state = counterReducer(state, { type: 'INCREMENT' }); // { count: 2 }
+state = counterReducer(state, { type: 'DECREMENT' }); // { count: 1 }
+
+console.log(state); // { count: 1 }
+```
+
+## Common Patterns
+
+### Pattern 1: Functor
+
+A **Functor** is a design pattern for a data structure that can be "mapped over." It's a container that holds a value and has a `map` method for applying a function to that value without changing the container's structure. The most common example is the `Array`.
+
+```javascript
+// Array is a Functor because it has a .map() method
+const numbers = [1, 2, 3];
+const addOne = (n) => n + 1;
+const result = numbers.map(addOne); // [2, 3, 4]
+```
+
+### Pattern 2: Monad
+
+A **Monad** is a pattern for sequencing computations. Think of it as a "safer" functor that knows how to handle nested contexts or operations that can fail (like Promises or the `Maybe` type). `Promise` is a good practical example; its `.then()` method (or `flatMap`) lets you chain asynchronous operations together seamlessly.
+
+```javascript
+// Promise is a Monad, allowing chaining of async operations
+const fetchUser = (id) => Promise.resolve({ id, name: "Alice" });
+const fetchUserPosts = (user) => Promise.resolve([ { userId: user.id, title: "Post 1" } ]);
+
+fetchUser(1)
+  .then(fetchUserPosts) // .then acts like flatMap here
+  .then(posts => console.log(posts))
+  .catch(err => console.error(err));
+```
+
+## Best Practices
+
+  - **Keep Functions Small**: Each function should do one thing well.
+  - **Use Function Composition**: Use utilities like `pipe` or `compose` to build complex logic from simple building blocks.
+  - **Embrace Immutability**: Use `const` by default. Avoid reassigning variables. When updating objects or arrays, create new ones.
+  - **Isolate Impurity**: Side effects are necessary. Keep them at the boundaries of your application (e.g., in the function that handles an API call) and keep your core business logic pure.
+
+## Common Pitfalls
+
+  - **Accidental Mutation**: JavaScript objects and arrays are passed by reference, making it easy to mutate them accidentally. Be vigilant, especially with nested data.
+  - **Over-Abstraction**: Don't use complex FP concepts like monad transformers if a simple function will do. Prioritize readability.
+  - **Performance Misconceptions**: While creating many short-lived objects can have a performance cost, modern JavaScript engines are highly optimized for this pattern. Don't prematurely optimize; measure first.
+
+## Performance Considerations
+
+  - **Object/Array Creation**: In performance-critical code (e.g., animations, large data processing), the overhead of creating new objects/arrays in a tight loop can be significant.
+  - **Structural Sharing**: Libraries like `Immer` and `Immutable.js` use a technique called structural sharing. When you "change" an immutable data structure, only the parts that changed are created anew; the rest of the structure points to the same old data, saving memory and CPU time.
+  - **Recursion**: Deep recursion can lead to stack overflow errors. While some languages support **Tail Call Optimization (TCO)** to prevent this, JavaScript engines have limited support. Prefer iteration for very large data sets.
+
+## Integration Points
+
+  - **UI Frameworks**: FP concepts are central to modern UI libraries. **React** encourages pure components and uses immutable state patterns with Hooks (`useState`, `useReducer`).
+    \-- **State Management**: Libraries like **Redux** and **Zustand** are built entirely on FP principles, particularly the use of pure reducer functions.
+  - **Data Processing**: FP is excellent for data transformation pipelines. It's often used in backend services for processing streams of data.
+  - **Utility Libraries**: Libraries like **Lodash/fp** and **Ramda** provide a rich toolkit of pre-built, curried, and pure functions for everyday tasks.
+
+## Troubleshooting
+
+### Problem 1: Debugging composed function pipelines
+
+**Symptoms:** A chain of `.map().filter().reduce()` produces an incorrect result, and it's hard to see where it went wrong.
+**Solution:** Break the chain apart. Log the intermediate result after each step to inspect the data as it flows through the pipeline.
+
+```javascript
+const result = users
+  .filter((user) => user.active)
+  // console.log('After active filter:', resultFromActiveFilter)
+  .filter((user) => user.score > 85)
+  // console.log('After score filter:', resultFromScoreFilter)
+  .map((user) => user.name.toUpperCase());
+```
+
+### Problem 2: State changes unexpectedly
+
+**Symptoms:** A piece of state (e.g., in a React component or Redux store) changes when it shouldn't have, leading to bugs or infinite re-renders.
+**Solution:** This is almost always due to accidental mutation. Audit your code to ensure you are not modifying state directly. Use the spread syntax (`...`) for objects and arrays (`[...arr, newItem]`) to create copies. Libraries like `Immer` can make this process safer and more concise.
+
+## Examples in Context
+
+  - **Frontend Web Development**: The **Elm Architecture** (Model, Update, View) is a purely functional pattern for building web apps. It has heavily influenced libraries like Redux.
+  - **Data Analysis**: Running a series of transformations on a large dataset to filter, shape, and aggregate it for a report.
+  - **Concurrency**: Handling multiple events or requests simultaneously without running into race conditions, because data is immutable and shared state is avoided.
+
+## References
+
+  - [MDN Web Docs: Functional Programming](https://www.google.com/search?q=https://developer.mozilla.org/en-US/docs/Glossary/Functional_programming)
+  - [Professor Frisby's Mostly Adequate Guide to Functional Programming](https://mostly-adequate.gitbook.io/mostly-adequate-guide/)
+  - [Ramda Documentation](https://ramdajs.com/docs/)
+
+## Related Topics
+
+  - Immutability
+  - Functional Reactive Programming (FRP)
+  - The Elm Architecture
+  - Algebraic Data Types
\ No newline at end of file