AgentSkillsCN

write-docstring-first

针对编写整洁函数:以文档字符串为起点,不断迭代,直至代码与文档字符串完全一致,最终实现文档与代码的同构。

SKILL.md
--- frontmatter
name: write-docstring-first
description: "For writing clean functions: start with docstring, iterate until code matches docstring exactly, achieve docstring-code isomorphism."

write-docstring-first

When to Use

  • Writing any new function
  • When clarity of purpose matters
  • Complex logic that needs explanation
  • Functions that will be reused
  • Teaching or educational code

When NOT to Use

  • Trivial one-liners (return x + 1)
  • Private implementation details
  • Rapidly prototyping (add later)

The Pattern

Docstring Fixpoint Theory: Iterate between docstring and code until they are isomorphic - each reads like a translation of the other.

python
# Step 1: Write docstring as specification
def rainfall(numbers):
    """Return the mean of the non-negative values in a list,
    up to the first -999 (if it shows up)."""
    ...

# Step 2: Write code that mirrors the docstring
def rainfall(numbers):
    """Return the mean of the non-negative values in a list,
    up to the first -999 (if it shows up)."""
    return mean(non_negative(upto(-999, numbers)))

# Notice: docstring and code are almost the same sentence!

Example (from pytudes DocstringFixpoint.ipynb)

python
# The Rainfall Problem - evolved through fixpoint iteration

# Version 1: Problem statement as docstring
def rainfall(numbers):
    """Design a program called rainfall that consumes a list of numbers
    representing daily rainfall amounts. The list may contain -999
    indicating end of data. Produce the average of non-negative values
    up to the first -999."""
    ...

# Version 2: Simplified docstring
def rainfall(numbers):
    """Produce the average of the non-negative values in a list,
    up to the first -999 (if it shows up)."""
    ...

# Version 3: Code mirrors docstring
def rainfall(numbers):
    """Return the mean of the non-negative values in a list,
    up to the first -999 (if it shows up)."""
    return mean(non_negative(upto(-999, numbers)))

# Helper functions (each with its own fixpoint)
def upto(sentinel, items):
    """Return items that appear before sentinel,
    or all items if sentinel doesn't appear."""
    return items[:items.index(sentinel)] if sentinel in items else items

def non_negative(numbers):
    """The numbers that are >= 0."""
    return [x for x in numbers if x >= 0]

Key Principles

  1. Docstring first: Specification before implementation
  2. Iterate both ways: Edit docstring, then code, then docstring...
  3. Match vocabulary: Use same words in both
  4. Helpers inherit pattern: Each has its own docstring-code match
  5. Fixpoint = done: When neither needs changing, you're done