functional-patterns

Functional programming patterns that promote testability, composability, and maintainability.

25 stars

Best use case

functional-patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Functional programming patterns that promote testability, composability, and maintainability.

Teams using functional-patterns should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/functional-patterns/SKILL.md --create-dirs "https://raw.githubusercontent.com/ComeOnOliver/skillshub/main/skills/aiskillstore/marketplace/doubleslashse/functional-patterns/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/functional-patterns/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How functional-patterns Compares

Feature / Agentfunctional-patternsStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Functional programming patterns that promote testability, composability, and maintainability.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Functional Patterns for Node.js/TypeScript

## Overview
Functional programming patterns that promote testability, composability, and maintainability.

## Pure Functions

### Definition
A pure function:
- Always returns the same output for the same input
- Has no side effects (no I/O, no mutation)

### Examples

```typescript
// Pure: Deterministic, no side effects
const add = (a: number, b: number): number => a + b;

const calculateTotal = (items: OrderItem[]): number =>
  items.reduce((sum, item) => sum + item.price * item.quantity, 0);

const filterActiveUsers = (users: User[]): User[] =>
  users.filter((user) => user.isActive);

// Impure: Has side effects
const saveUser = async (user: User): Promise<void> => {
  await database.save(user); // I/O side effect
};

const logMessage = (msg: string): void => {
  console.log(msg); // Side effect
};

const generateId = (): string => {
  return crypto.randomUUID(); // Non-deterministic
};
```

### Pure Core, Impure Shell

```typescript
// Pure core - all business logic
const validateOrder = (order: Order): Result<Order, ValidationError> => {
  if (!order.items.length) return Result.fail({ code: 'EMPTY_ORDER' });
  if (order.total < 0) return Result.fail({ code: 'INVALID_TOTAL' });
  return Result.ok(order);
};

const calculateDiscount = (order: Order, user: User): number => {
  const baseDiscount = user.isPremium ? 0.15 : 0;
  const volumeDiscount = order.items.length > 10 ? 0.05 : 0;
  return baseDiscount + volumeDiscount;
};

const applyDiscount = (order: Order, discountRate: number): Order => ({
  ...order,
  total: order.total * (1 - discountRate),
});

// Impure shell - handles I/O
const processOrderHandler = (deps: Dependencies) => async (order: Order) => {
  const validation = validateOrder(order);
  if (validation.isFailure) return validation;

  const user = await deps.userRepo.findById(order.userId); // I/O
  const discount = calculateDiscount(validation.value, user);
  const discounted = applyDiscount(validation.value, discount);

  await deps.orderRepo.save(discounted); // I/O
  await deps.notifier.send(user.email, 'Order confirmed'); // I/O

  return Result.ok(discounted);
};
```

## Immutability

### Immutable Updates

```typescript
// Bad: Mutation
const addItemToCart = (cart: Cart, item: Item) => {
  cart.items.push(item);
  cart.total += item.price;
  return cart;
};

// Good: Immutable update
const addItemToCart = (cart: Cart, item: Item): Cart => ({
  ...cart,
  items: [...cart.items, item],
  total: cart.total + item.price,
});

// Good: Nested immutable update
const updateUserAddress = (user: User, address: Partial<Address>): User => ({
  ...user,
  address: {
    ...user.address,
    ...address,
  },
});

// Good: Using readonly types
type ReadonlyUser = {
  readonly id: string;
  readonly email: string;
  readonly addresses: readonly Address[];
};

// Good: Immutable array operations
const addItem = <T>(arr: readonly T[], item: T): readonly T[] => [...arr, item];
const removeAt = <T>(arr: readonly T[], index: number): readonly T[] =>
  arr.filter((_, i) => i !== index);
const updateAt = <T>(arr: readonly T[], index: number, item: T): readonly T[] =>
  arr.map((existing, i) => (i === index ? item : existing));
```

## Function Composition

### Pipe and Compose

```typescript
// Pipe: left to right
type Fn<A, B> = (a: A) => B;

const pipe = <A, B, C>(
  f: Fn<A, B>,
  g: Fn<B, C>
): Fn<A, C> => (a) => g(f(a));

const pipe3 = <A, B, C, D>(
  f: Fn<A, B>,
  g: Fn<B, C>,
  h: Fn<C, D>
): Fn<A, D> => (a) => h(g(f(a)));

// Usage
const processInput = pipe3(
  trim,
  toLowerCase,
  validateEmail
);

// Variadic pipe
const pipeAll = <T>(...fns: Array<(x: T) => T>) =>
  (initial: T): T => fns.reduce((acc, fn) => fn(acc), initial);

const processString = pipeAll(
  (s: string) => s.trim(),
  (s: string) => s.toLowerCase(),
  (s: string) => s.replace(/\s+/g, '-')
);
```

### Higher-Order Functions

```typescript
// Function that returns a function
const withLogging = <T extends (...args: any[]) => any>(fn: T) =>
  (...args: Parameters<T>): ReturnType<T> => {
    console.log('Calling with:', args);
    const result = fn(...args);
    console.log('Result:', result);
    return result;
  };

// Function that takes a function
const retry = <T>(
  fn: () => Promise<T>,
  attempts: number = 3
): Promise<T> =>
  fn().catch((error) =>
    attempts > 1 ? retry(fn, attempts - 1) : Promise.reject(error)
  );

// Currying
const multiply = (a: number) => (b: number): number => a * b;
const double = multiply(2);
const triple = multiply(3);

// Partial application
const createLogger = (prefix: string) =>
  (message: string): void => console.log(`[${prefix}] ${message}`);

const infoLog = createLogger('INFO');
const errorLog = createLogger('ERROR');
```

## Result Pattern (Monadic Error Handling)

### Basic Result Type

```typescript
type Result<T, E> =
  | { readonly _tag: 'Ok'; readonly value: T }
  | { readonly _tag: 'Err'; readonly error: E };

const ok = <T>(value: T): Result<T, never> => ({ _tag: 'Ok', value });
const err = <E>(error: E): Result<never, E> => ({ _tag: 'Err', error });

const isOk = <T, E>(result: Result<T, E>): result is { _tag: 'Ok'; value: T } =>
  result._tag === 'Ok';

const isErr = <T, E>(result: Result<T, E>): result is { _tag: 'Err'; error: E } =>
  result._tag === 'Err';
```

### Result Operations

```typescript
// Map: transform success value
const map = <T, U, E>(
  result: Result<T, E>,
  fn: (value: T) => U
): Result<U, E> =>
  isOk(result) ? ok(fn(result.value)) : result;

// MapError: transform error value
const mapError = <T, E, F>(
  result: Result<T, E>,
  fn: (error: E) => F
): Result<T, F> =>
  isErr(result) ? err(fn(result.error)) : result;

// FlatMap (chain): compose Result-returning functions
const flatMap = <T, U, E>(
  result: Result<T, E>,
  fn: (value: T) => Result<U, E>
): Result<U, E> =>
  isOk(result) ? fn(result.value) : result;

// Match: exhaustive handling
const match = <T, E, R>(
  result: Result<T, E>,
  handlers: { ok: (value: T) => R; err: (error: E) => R }
): R =>
  isOk(result) ? handlers.ok(result.value) : handlers.err(result.error);
```

### Chaining Results

```typescript
type ValidationError = { field: string; message: string };
type ProcessingError = { code: string; details: string };
type AppError = ValidationError | ProcessingError;

const validateInput = (input: unknown): Result<ValidInput, ValidationError> => {
  // ...
};

const processData = (input: ValidInput): Result<ProcessedData, ProcessingError> => {
  // ...
};

const formatOutput = (data: ProcessedData): Output => {
  // ...
};

// Compose the pipeline
const handleRequest = (input: unknown): Result<Output, AppError> => {
  const validated = validateInput(input);
  if (isErr(validated)) return validated;

  const processed = processData(validated.value);
  if (isErr(processed)) return processed;

  return ok(formatOutput(processed.value));
};

// Or with flatMap
const handleRequestFunctional = (input: unknown): Result<Output, AppError> =>
  flatMap(validateInput(input), (valid) =>
    map(processData(valid), formatOutput)
  );
```

## Option/Maybe Pattern

```typescript
type Option<T> =
  | { readonly _tag: 'Some'; readonly value: T }
  | { readonly _tag: 'None' };

const some = <T>(value: T): Option<T> => ({ _tag: 'Some', value });
const none: Option<never> = { _tag: 'None' };

const isSome = <T>(opt: Option<T>): opt is { _tag: 'Some'; value: T } =>
  opt._tag === 'Some';

const isNone = <T>(opt: Option<T>): opt is { _tag: 'None' } =>
  opt._tag === 'None';

// Operations
const mapOption = <T, U>(opt: Option<T>, fn: (value: T) => U): Option<U> =>
  isSome(opt) ? some(fn(opt.value)) : none;

const getOrElse = <T>(opt: Option<T>, defaultValue: T): T =>
  isSome(opt) ? opt.value : defaultValue;

const fromNullable = <T>(value: T | null | undefined): Option<T> =>
  value != null ? some(value) : none;

// Usage
const findUser = (id: string): Option<User> => {
  const user = users.find((u) => u.id === id);
  return fromNullable(user);
};

const getUserEmail = (id: string): string =>
  getOrElse(
    mapOption(findUser(id), (user) => user.email),
    'unknown@example.com'
  );
```

## Dependency Injection via Functions

```typescript
// Define dependencies as a type
type Dependencies = {
  userRepo: UserRepository;
  orderRepo: OrderRepository;
  logger: Logger;
  clock: () => Date; // Even time can be injected
};

// Create service factory
const createOrderService = (deps: Dependencies) => ({
  createOrder: async (data: CreateOrderData): Promise<Result<Order, OrderError>> => {
    const user = await deps.userRepo.findById(data.userId);
    if (!user) {
      return err({ code: 'USER_NOT_FOUND', userId: data.userId });
    }

    const order: Order = {
      id: generateId(),
      ...data,
      createdAt: deps.clock(),
      status: 'pending',
    };

    deps.logger.info({ orderId: order.id }, 'Creating order');
    await deps.orderRepo.save(order);

    return ok(order);
  },
});

// Test with fake dependencies
describe('OrderService', () => {
  it('should create order', async () => {
    const deps: Dependencies = {
      userRepo: { findById: jest.fn().mockResolvedValue({ id: '1' }) },
      orderRepo: { save: jest.fn() },
      logger: { info: jest.fn() },
      clock: () => new Date('2024-01-01'),
    };

    const service = createOrderService(deps);
    const result = await service.createOrder({ userId: '1', items: [] });

    expect(isOk(result)).toBe(true);
  });
});
```

Related Skills

exa-sdk-patterns

25
from ComeOnOliver/skillshub

Apply production-ready exa-js SDK patterns with type safety, singletons, and wrappers. Use when implementing Exa integrations, refactoring SDK usage, or establishing team coding standards for Exa. Trigger with phrases like "exa SDK patterns", "exa best practices", "exa code patterns", "idiomatic exa", "exa wrapper".

exa-reliability-patterns

25
from ComeOnOliver/skillshub

Implement Exa reliability patterns: query fallback chains, circuit breakers, and graceful degradation. Use when building fault-tolerant Exa integrations, implementing fallback strategies, or adding resilience to production search services. Trigger with phrases like "exa reliability", "exa circuit breaker", "exa fallback", "exa resilience", "exa graceful degradation".

evernote-sdk-patterns

25
from ComeOnOliver/skillshub

Advanced Evernote SDK patterns and best practices. Use when implementing complex note operations, batch processing, search queries, or optimizing SDK usage. Trigger with phrases like "evernote sdk patterns", "evernote best practices", "evernote advanced", "evernote batch operations".

elevenlabs-sdk-patterns

25
from ComeOnOliver/skillshub

Apply production-ready ElevenLabs SDK patterns for TypeScript and Python. Use when implementing ElevenLabs integrations, refactoring SDK usage, or establishing team coding standards for audio AI applications. Trigger: "elevenlabs SDK patterns", "elevenlabs best practices", "elevenlabs code patterns", "idiomatic elevenlabs", "elevenlabs typescript".

documenso-sdk-patterns

25
from ComeOnOliver/skillshub

Apply production-ready Documenso SDK patterns for TypeScript and Python. Use when implementing Documenso integrations, refactoring SDK usage, or establishing team coding standards for Documenso. Trigger with phrases like "documenso SDK patterns", "documenso best practices", "documenso code patterns", "idiomatic documenso".

deepgram-sdk-patterns

25
from ComeOnOliver/skillshub

Apply production-ready Deepgram SDK patterns for TypeScript and Python. Use when implementing Deepgram integrations, refactoring SDK usage, or establishing team coding standards for Deepgram. Trigger: "deepgram SDK patterns", "deepgram best practices", "deepgram code patterns", "idiomatic deepgram", "deepgram typescript".

databricks-sdk-patterns

25
from ComeOnOliver/skillshub

Apply production-ready Databricks SDK patterns for Python and REST API. Use when implementing Databricks integrations, refactoring SDK usage, or establishing team coding standards for Databricks. Trigger with phrases like "databricks SDK patterns", "databricks best practices", "databricks code patterns", "idiomatic databricks".

customerio-sdk-patterns

25
from ComeOnOliver/skillshub

Apply production-ready Customer.io SDK patterns. Use when implementing typed clients, retry logic, event batching, or singleton management for customerio-node. Trigger: "customer.io best practices", "customer.io patterns", "production customer.io", "customer.io architecture", "customer.io singleton".

customerio-reliability-patterns

25
from ComeOnOliver/skillshub

Implement Customer.io reliability and fault-tolerance patterns. Use when building circuit breakers, fallback queues, idempotency, or graceful degradation for Customer.io integrations. Trigger: "customer.io reliability", "customer.io resilience", "customer.io circuit breaker", "customer.io fault tolerance".

coreweave-sdk-patterns

25
from ComeOnOliver/skillshub

Production-ready patterns for CoreWeave GPU workload management with kubectl and Python. Use when building inference clients, managing GPU deployments programmatically, or creating reusable CoreWeave deployment templates. Trigger with phrases like "coreweave patterns", "coreweave client", "coreweave Python", "coreweave deployment template".

cohere-sdk-patterns

25
from ComeOnOliver/skillshub

Apply production-ready Cohere SDK patterns for TypeScript and Python. Use when implementing Cohere integrations, refactoring SDK usage, or establishing team coding standards for Cohere API v2. Trigger with phrases like "cohere SDK patterns", "cohere best practices", "cohere code patterns", "idiomatic cohere", "cohere wrapper".

coderabbit-sdk-patterns

25
from ComeOnOliver/skillshub

Apply production-ready CodeRabbit automation patterns using GitHub API and PR comments. Use when building automation around CodeRabbit reviews, processing review feedback programmatically, or integrating CodeRabbit into custom workflows. Trigger with phrases like "coderabbit automation", "coderabbit API patterns", "automate coderabbit", "coderabbit github api", "process coderabbit reviews".