Install
$ agentstack add skill-mickeyyaya-refactoring-skills-refactor-functional-patterns ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Refactor: Functional Programming Patterns
Overview
FP patterns produce code that is predictable, testable, and composable by eliminating shared mutable state and side effects.
When to use: State mutation bugs, hidden dependencies, untestable functions, complex data pipelines, repeated null-check boilerplate, functions mixing computation and I/O.
Quick Reference
| Pattern | Core Idea | Primary Red Flag | |---------|-----------|-----------------| | Pure Functions | Same input → same output, no side effects | Accessing global state inside business logic | | Immutability | Never mutate, always create new | push, pop, or property assignment on existing objects | | Map/Filter/Reduce | Declarative collection transforms | Manual loops accumulating results | | Function Composition | Build pipelines from small functions | Deeply nested function calls f(g(h(x))) | | Higher-Order Functions | Functions that take/return functions | Copy-pasted blocks differing by one operation | | Currying / Partial Application | Fix some arguments, defer the rest | Repeatedly passing the same first argument | | Functors / Monads | Chainable containers for optional/error values | Nested null checks, try-catch pyramids | | Pattern Matching | Destructure and branch on data shape | instanceof chains or long type-checking conditionals |
Patterns in Detail
1. Pure Functions
Red Flags: Reading global/process.env in computation; I/O mixed into business logic; parameter mutation (arr.push(x)); Date.now()/Math.random() in deterministic functions.
// BEFORE — reads global state + side effect
let taxRate = 0.2;
function calculateTotal(price: number): number {
const total = price * (1 + taxRate);
console.log(`total: ${total}`);
return total;
}
// AFTER — pure: only uses arguments
function calculateTotal(price: number, taxRate: number): number {
return price * (1 + taxRate);
}
# Python equivalent
def calculate_total(price: float, tax_rate: float) -> float:
return price * (1 + tax_rate)
2. Immutability
Red Flags: .push()/.pop()/.splice()/.sort() mutate in place; object.field = value; Object.assign on original; shallow spread missing nested immutability; missing readonly.
// BEFORE — mutates caller's array
function addItem(cart: CartItem[], item: CartItem): CartItem[] {
cart.push(item);
return cart;
}
// AFTER — new array, original untouched
function addItem(cart: readonly CartItem[], item: CartItem): readonly CartItem[] {
return [...cart, item];
}
# Python — tuples are immutable
def add_item(cart: tuple, item) -> tuple:
return (*cart, item)
Cross-reference: refactor-composing-methods — "Remove Assignments to Parameters".
3. Map / Filter / Reduce
Red Flags: Loop building accumulator → map; with condition → filter; single value → reduce; nested loops → flatMap; index used only to access element.
// BEFORE
function getActiveUserEmails(users: User[]): string[] {
const result: string[] = [];
for (let i = 0; i u.active).map(u => u.email.toLowerCase());
}
# Python — list comprehension
def get_active_user_emails(users: list[User]) -> list[str]:
return [u.email.lower() for u in users if u.active]
4. Function Composition
Red Flags: Nested calls f(g(h(x))); variables named temp/step1/result1; single function doing three things separated by comments.
// BEFORE
function processUserInput(raw: string): string {
const trimmed = raw.trim();
const lower = trimmed.toLowerCase();
return lower.replace(/\s+/g, '_');
}
// AFTER — pipeline
const pipe = (...fns: Array T>) => (x: T): T =>
fns.reduce((acc, fn) => fn(acc), x);
const processUserInput = pipe(
(s: string) => s.trim(),
(s: string) => s.toLowerCase(),
(s: string) => s.replace(/\s+/g, '_'),
);
from functools import reduce
def pipe(*fns):
return lambda x: reduce(lambda acc, f: f(acc), fns, x)
process_user_input = pipe(str.strip, str.lower, lambda s: s.replace(' ', '_'))
5. Higher-Order Functions
Red Flags: Two functions identical except one operation; callback code abstractable into retry/cache/log wrapper.
// BEFORE — duplicated sort logic
function sortByName(users: User[]): User[] {
return [...users].sort((a, b) => a.name.localeCompare(b.name));
}
function sortByAge(users: User[]): User[] {
return [...users].sort((a, b) => a.age - b.age);
}
// AFTER — parameterized
function sortBy(key: (item: T) => number | string) {
return (items: readonly T[]): readonly T[] =>
[...items].sort((a, b) => {
const ka = key(a), kb = key(b);
return ka kb ? 1 : 0;
});
}
const sortByName = sortBy((u: User) => u.name);
const sortByAge = sortBy((u: User) => u.age);
6. Currying / Partial Application
Red Flags: Repeated calls like formatDate(locale, date1), formatDate(locale, date2); config objects threaded when only the last arg varies.
// BEFORE — caller repeatedly specifies locale and currency
formatCurrency('en-US', 'USD', 9.99);
formatCurrency('en-US', 'USD', 19.99);
// AFTER — curried
const formatCurrency =
(locale: string) => (currency: string) => (amount: number): string =>
new Intl.NumberFormat(locale, { style: 'currency', currency }).format(amount);
const formatUSD = formatCurrency('en-US')('USD');
formatUSD(9.99);
formatUSD(19.99);
from functools import partial
format_usd = partial(format_currency, 'en-US', 'USD')
format_usd(9.99)
7. Functors / Monads (Optional, Result, Promise)
Red Flags: if (a !== null && a.b !== null && ...) chains; nested try-catch; functions returning null | undefined | T without a container type.
// BEFORE — null pyramid
function getCity(user: User | null): string | null {
if (user !== null) {
if (user.address !== null) {
if (user.address.city !== null) {
return user.address.city.toUpperCase();
}
}
}
return null;
}
// AFTER — optional chaining
function getCity(user: User | null): string | null {
return user?.address?.city?.toUpperCase() ?? null;
}
// Result type for error handling
type Result = { ok: true; value: T } | { ok: false; error: E };
function parseAge(raw: string): Result {
const n = Number(raw);
if (isNaN(n) || n Ok | Err:
try:
n = int(raw)
return Ok(n) if n >= 0 else Err(f"Negative age: {raw}")
except ValueError:
return Err(f"Not a number: {raw}")
8. Pattern Matching
Red Flags: instanceof chains — use discriminated unions; type conditionals without exhaustiveness check; switch on union with no default.
// BEFORE — instanceof chain
function area(shape: Circle | Rectangle | Triangle): number {
if (shape instanceof Circle) return Math.PI * shape.radius ** 2;
if (shape instanceof Rectangle) return shape.width * shape.height;
if (shape instanceof Triangle) return 0.5 * shape.base * shape.height;
throw new Error('Unknown shape');
}
// AFTER — discriminated union with exhaustiveness
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'rectangle'; width: number; height: number }
| { kind: 'triangle'; base: number; height: number };
function area(shape: Shape): number {
switch (shape.kind) {
case 'circle': return Math.PI * shape.radius ** 2;
case 'rectangle': return shape.width * shape.height;
case 'triangle': return 0.5 * shape.base * shape.height;
default: {
const _exhaustive: never = shape;
throw new Error(`Unhandled shape: ${JSON.stringify(_exhaustive)}`);
}
}
}
# Python 3.10+
def area(shape: dict) -> float:
match shape:
case {'kind': 'circle', 'radius': r}: return 3.14159 * r ** 2
case {'kind': 'rectangle', 'width': w, 'height': h}: return w * h
case {'kind': 'triangle', 'base': b, 'height': h}: return 0.5 * b * h
case _: raise ValueError(f"Unknown shape: {shape}")
FP Anti-Patterns
| Anti-Pattern | Description | Fix | |-------------|-------------|-----| | Impure function masquerading as pure | Reads a closure variable that changes over time | Make mutable dependency an explicit parameter | | Shallow-copy illusion | {...obj} — nested objects still shared | Deep-clone or use Immer/Immutable.js | | Point-free everything | Removing all named parameters hurts readability | Use point-free only when it clarifies | | Monadic overkill | Full Maybe monad for simple null check | Prefer optional chaining for shallow checks | | Impure reduce | Accumulator mutated inside callback | Return new accumulator each iteration | | Shared state in curried functions | Captures mutable outer scope value | Ensure captured values are constants |
Shallow-copy illusion — example:
// WRONG — nested address object is still shared
const updated = { ...user, name: 'Alice' };
updated.address.city = 'Boston'; // mutates original user.address!
// CORRECT — spread nested objects too, or use structuredClone
const updated = { ...user, name: 'Alice', address: { ...user.address, city: 'Boston' } };
Cross-References
refactor-composing-methods— "Remove Assignments to Parameters" (immutability); "Substitute Algorithm" (loops → declarative)refactor-simplifying-conditionals— Simplifyingif/elsechains that pattern matching replacesreview-solid-clean-code— SRP aligns with pure functions; OCP aligns with HOFsdetect-code-smells— "Data Clumps" → missing algebraic data types; "Long Method" → missing composition
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: mickeyyaya
- Source: mickeyyaya/refactoring-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.