smithery.ai

cache-recursive-calls

For dynamic programming: overlapping subproblems, recursive solutions with repeated computations, memoization to avoid redundant work.

First seen Apr 20, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 2,568 B
  • docs SUMMARY.md 163 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

cache-recursive-calls

When to Use

  • Recursive function computes same inputs multiple times
  • Overlapping subproblems (DP)
  • Fibonacci-like recurrence relations
  • Tree/graph traversal with revisits
  • Expensive pure functions called repeatedly

When NOT to Use

  • Function has side effects
  • Inputs aren't hashable
  • Cache would grow too large
  • Each input computed only once

The Pattern

Use @functools.cache (Python 3.9+) or @functools.lru_cache(None) to memoize.

from functools import cache

@cache
def fib(n):
    """Fibonacci with memoization: O(n) instead of O(2^n)."""
    if n <= 1:
        return n
    return fib(n - 1) + fib(n - 2)

# Or with size limit
from functools import lru_cache

@lru_cache(maxsize=1000)
def expensive_lookup(key):
    # ... expensive computation
    return result

Example (from pytudes)

from functools import cache

# TSP with dynamic programming (TSP.ipynb)
@cache
def shortest_segment(A, Bs, C):
    """Shortest path from A through all cities in Bs to C."""
    if not Bs:
        return [A, C]
    return min(
        (shortest_segment(A, Bs - {B}, B) + [C] for B in Bs),
        key=segment_length
    )

# Key insight: Bs must be frozenset (hashable)
cities = frozenset(['NYC', 'LA', 'CHI', 'HOU'])
tour = shortest_segment('START', cities, 'START')

# Expression counting (Countdown.ipynb)
@cache
def expressions(numbers):
    """All expressions makeable from numbers."""
    if len(numbers) == 1:
        return {numbers[0]: str(numbers[0])}

    table = {}
    for Lnums, Rnums in splits(numbers):
        for L, R in product(expressions(Lnums), expressions(Rnums)):
            for op in ops:
                # Combine L and R with op
                ...
    return table

# Word segmentation (ngrams.py)
@cache
def segment(text):
    """Best word segmentation of text."""
    if not text:
        return []
    candidates = ([first] + segment(rest)
                  for first, rest in splits(text))
    return max(candidates, key=word_probability)

Key Principles

  1. Pure functions only: Same input must give same output
  2. Hashable arguments: Use tuples/frozensets, not lists/sets
  3. cache vs lrucache: cache is unbounded, lrucache has size limit
  4. Inspect cache: func.cache_info() shows hits/misses
  5. Clear when done: func.cache_clear() frees memory