Install any skill in seconds. Free to start, no credit card required.
Get Started Free →A practical, jargon-free guide to functional programming - the 80/20 approach that gets results without the academic overhead
.claude/skills/fp-pragmatic/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-19 | ✗→✓ | ▲ Improved | — | — |
| case-12 | ✗→✓ | ▲ Improved | — | — |
| case-07 | ✗→✓ | ▲ Improved | — | — |
| case-16 | ✗→✓ | ▲ Improved | — | — |
| case-14 | ✗→✓ | ▲ Improved | — | — |
Read this first. This guide cuts through the academic jargon and shows you what actually matters. No category theory. No abstract nonsense. Just patterns that make your code better.
Read the detailed guide before executing this skill. It retains the complete procedure and reference material. Treat its safety, prerequisites, and validation requirements as mandatory. For focused work, load the relevant sections; for end-to-end work, read the guide completely.
Functional programming is not always the answer. Here's when to keep it simple.
typescript// Just use optional chaining - it's built into the language const city = user?.address?.city ?? 'Unknown' // DON'T overcomplicate it const city = pipe( O.fromNullable(user), O.flatMap(u => O.fromNullable(u.address)), O.flatMap(a => O.fromNullable(a.city)), O.getOrElse(() => 'Unknown') )
typescript// A for loop is fine when you need early exit or complex logic function findFirst(items: Item[], predicate: (i: Item) => boolean): Item | null { for (const item of items) { if (predicate(item)) return item } return null } // DON'T force FP when it doesn't help const result = pipe( items, A.findFirst(predicate), O.toNullable )
typescript// For hot paths, imperative is faster (no intermediate arrays) function sumLarge(numbers: number[]): number { let sum = 0 for (let i = 0; i < numbers.length; i++) { sum += numbers[i] } return sum } // fp-ts creates intermediate structures const sum = pipe(numbers, A.reduce(0, (acc, n) => acc + n))
If you're the only one who can read the code, it's not good code.
typescript// If your team knows this pattern async function getUser(id: string): Promise<User | null> { try { const response = await fetch(`/api/users/${id}`) if (!response.ok) return null return await response.json() } catch { return null } } // Don't force this on them const getUser = (id: string): TE.TaskEither<Error, User> => pipe( TE.tryCatch(() => fetch(`/api/users/${id}`), E.toError), TE.flatMap(r => r.ok ? TE.right(r) : TE.left(new Error('Not found'))), TE.flatMap(r => TE.tryCatch(() => r.json(), E.toError)) )
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-19 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-23 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +35 percentage points is the difference between those two pass rates over the 23 comparable cases.
The publisher has shipped newer versions since this run, so these numbers describe v1, not the version currently listed.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.