lambda-calculus-interpreter
Skill17 starsChanged 9 months agoApache-2.0View on GitHub
Implements untyped and simply-typed lambda calculus interpreters. Use
In this repository98 other files it gives its agents.
- abstract-interpretation-engineSkill
- abstract-machineSkill
- acsl-annotation-assistantSkill
- actor-model-implementerSkill
- algebraic-effectsSkill
- alias-and-points-to-analysisSkill
- axiomatic-semanticsSkill
- bidirectional-type-checkingSkill
- bisimulation-checkerSkill
- capability-systemSkill
- closure-converterSkill
- common-subexpression-eliminatorSkill
- concurrency-verifierSkill
- constant-propagation-passSkill
- contextual-equivalenceSkill
- control-flow-analysisSkill
- coq-proof-assistantSkill
- cps-transformerSkill
- dafny-verifierSkill
- dataflow-analysis-frameworkSkill
- dead-code-eliminatorSkill
- defunctionalizationSkill
- denotational-semantics-builderSkill
- dependent-type-implementerSkill
- dsl-embeddingSkill
- effect-handlers-implementerSkill
- effect-systemSkill
- effect-type-systemSkill
- escape-analysisSkill
- existential-typesSkill
- ffi-designerSkill
- fuzzer-generatorSkill
- gadt-implementerSkill
- garbage-collector-implementerSkill
- graalvm-truffle-implementerSkill
- gradual-typing-implementerSkill
- higher-order-abstract-syntaxSkill
- hoare-logic-verifierSkill
- incremental-computationSkill
- information-flow-analyzerSkill
- inline-expanderSkill
- interprocedural-analysisSkill
- invariant-generatorSkill
- jit-compiler-builderSkill
- language-server-protocolSkill
- lean-proverSkill
- lexer-generatorSkill
- linear-type-implementerSkill
- liveness-analysisSkill
- llvm-backend-generatorSkill
- lock-free-data-structureSkill
- loop-optimizerSkill
- loop-termination-proverSkill
- macro-expanderSkill
- memory-allocatorSkill
- message-passing-systemSkill
- mlir-dialect-designerSkill
- model-checkerSkill
- module-systemSkill
- monad-transformerSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
11 rules. About 0 are common, 11 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈11
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 53
Use these prompts directly:
- Distinctive: line 89
Compares strategies: - Call-by-value, call-by-name, etc.
- Distinctive: line 213
Use de Bruijn indices to avoid alpha-renaming
- Distinctive: line 215
Consider sharing (pointers) for efficiency
- Distinctive: line 216
Add letrec for recursion (fixed-point)
- Distinctive: line 335
When implementing de Bruijn indices, common bugs include:
- Distinctive: line 338
Capture in substitution: Must check free variable sets
- Distinctive: line 379
For practical languages: Add concrete syntax, recursion (Y combinator), constants
- Distinctive: line 380
For performance-critical code: Consider closure conversion, compilation to bytecode
- Distinctive: line 381
For verification: Use simply-typed or linear variants for stronger guarantees
- Distinctive: line 386
No recursion: Must use fixed-point combinator (Y = λf.(λx.f(x x))(λx.f(x x)))
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Lambda Calculus Interpreter
Status: Ready to use | Auto-trigger: Yes | Script:
python examples/interpreter.py
Triggers
This skill activates when user mentions:
- Implementing lambda calculus interpreters
- Building functional language interpreters
- Understanding beta reduction, closures
- Learning evaluation strategies (CBV, CBN)
Action Prompts
Use these prompts directly:
Implement a call-by-value lambda calculus interpreter with:
- Var, Abs, App AST nodes using dataclasses
- Environment-based closure implementation
- Beta reduction with proper substitution
- Support for Church numeralsAdd call-by-name lazy evaluation to existing interpreter:
- Implement Thunk class for delayed evaluation
- Memoize forced thunks
- Compare performance with call-by-valueExtend interpreter with:
- Fixed-point combinator (Y combinator) for recursion
- Simple type system (Bool, Int, Fun types)
- Type inference using bidirectional checkingWhen to Use
- Learning functional programming foundations
- Implementing interpreters for functional languages
- Studying evaluation strategies (CBV, CBN, parallel)
- Exploring meta-programming concepts
What This Skill Does
- Parses lambda terms - Concrete → abstract syntax
- Implements reductions - β-reduction, η-reduction
- Handles closures - Captures lexical environment
- Compares strategies - Call-by-value, call-by-name, etc.
Church Encoding Implementation
def church_to_int(n):
"""Convert Church numeral to integer"""
# Church numeral n is λf. λx. f^n(x)
# Apply to successor function and zero
succ = lambda x: x + 1
return n(succ)(0)
def int_to_church(n):
"""Convert integer to Church numeral"""
# Build: λf. λx. f(f(...f(x)...)) with n applications
return lambda f: lambda x: f**n(x) if hasattr(f, '__pow__') else None
# Church arithmetic
church_add = Abs("m", Abs("n",
Abs("f", Abs("x",
App(App(Var("m"), Var("f")),
App(App(Var("n"), Var("f")), Var("x")))))))
church_mult = Abs("m", Abs("n",
Abs("f",
App(Var("m"), App(Var("n"), Var("f"))))))
church_pred = Abs("n",
Abs("f", Abs("x",
App(
App(App(Var("n"),
Abs("g", Abs("h", App(Var("h"), App(Var("g"), Var("f")))))),
Abs("u", Var("x"))),
Abs("u", Var("u"))))))Simply-Typed Lambda Calculus (STLC)
# Types
TInt = "int"
TBool = "bool"
TFun = lambda t1, t2: ("fun", t1, t2)
def type_check(t: Term, env: dict) -> Type:
"""Simply-typed lambda calculus type checker"""
match t:
case Var(x):
return env[x]
case Abs(param, body):
# Analyzed from context
pass
case App(func, arg):
tf = type_check(func, env)
if not isinstance(tf, tuple) or tf[0] != "fun":
raise TypeError(f"Cannot apply non-function: {tf}")
_, dom, cod = tf
ta = type_check(arg, env)
if ta != dom:
raise TypeError(f"Argument type mismatch: {ta} ≠ {dom}")
return cod
raise ValueError(f"Unknown term: {t}")
# STLC with type inference (bidirectional)
def synth(t: Term, env: dict) -> tuple[Type, list[Constraint]]:
"""Synthesize type"""
match t:
case Var(x):
return (env[x], [])
case App(e1, e2):
a = fresh_tvar()
t1, c1 = synth(e1, env)
t2, c2 = check(e2, t1[1], env) # Check arg against domain
return (t1[2], c1 + c2 + [(t1, ("fun", t2, a))])
# ... more cases
def check(t: Term, expected: Type, env: dict) -> tuple[None, list[Constraint]]:
"""Check term has expected type"""
match t, expected:
case Abs(param, body), ("fun", dom, cod):
return check(body, cod, {**env, param: dom})
case _:
t, c = synth(t, env)
return (None, c + [(t, expected)])Test Cases
| Input Term | Expected Result | Description |
(λx. x) (λy. y) | Closure(λy. y, {}) | Identity applied to identity |
(λx. λy. x) (λz. z) | Closure(λy. x, {x: Closure(λz.z)}) | Constant function |
(λx. x x) (λx. x x) | Diverges | Omega combinator (Ω = ω ω, where ω = λx. x x) |
(λf. λx. f x) (λy. succ y) | Closure(λx. f x, {f: Closure(λy. succ y)}) | Function application |
Using the Script
# Run the interpreter
cd lambda-calculus-interpreter
python examples/interpreter.py --help
# Run with custom input
python examples/interpreter.py --input "(λx. x) (λy. y)" --strategy cbvEvaluation Strategies
| Strategy | Description | Example |
| Normal order | Reduce leftmost-outermost first | CBN |
| Applicative order | Reduce arguments first | CBV |
| Weak reduction | Don't reduce under lambdas | Most implementations |
| Plotkin's strategies | CBV, CBN, parallel | Research |
Tips
- Use de Bruijn indices to avoid alpha-renaming
- Implement environments as immutable maps
- Consider sharing (pointers) for efficiency
- Add letrec for recursion (fixed-point)
- Trace reductions for debugging
Reduction Semantics
# Explicit substitution
def subst(t: Term, x: str, s: Term) -> Term:
"""Substitute s for x in t"""
match t:
case Var(y) if y == x:
return s
case Var(y):
return t
case Abs(y, body) if y != x:
return Abs(y, subst(body, x, s))
case App(e1, e2):
return App(subst(e1, x, s), subst(e2, x, s))
case _:
return t
# β-reduction step
def beta_step(t: Term) -> Term:
"""One step of β-reduction"""
match t:
case App(Abs(x, body), arg):
return subst(body, x, arg) # β-redex
# ... add congruence rulesRelated Skills
operational-semantics-definer- Language semanticstype-inference-engine- Hindley-Milnersimply-typed-lambda-calculus- STLC with types
Canonical References
| Reference | Why It Matters |
| Barendregt, "The Lambda Calculus" | Definitive reference on λ-calculus variants |
| Pierce, "Types and Programming Languages" | Chapters 5-7 cover untyped and simply-typed λ-calculus |
| Plotkin, "Call-by-Name, Call-by-Value and the λ-calculus" | Formalizes evaluation strategies |
| Reynolds, "Theories of Programming Languages" | Comparative study of λ-calculus semantics |
| Wadsworth, "Semantics and Pragmatics of the Lambda Calculus" | Original CBV normalization theory |
Research Tools & Artifacts
For lambda calculus implementations, these are the gold-standard references:
| Implementation | What to Learn |
| Standard ML of New Jersey | Efficient CBV, lazy compilation |
| OCaml's lambda IR | Practical intermediate representation |
| GHC Core | Optimization-oriented lambda calculus |
| Lamping/Gonthier optimal reduction | Optimal graph reduction via interaction nets |
| Lispkit Lisp | SECD machine implementation |
Interactive Lambda Calculus Environments
- Lambda Calculi Tool (Cambridge) - Visualization of reductions
- Proof assistants: Coq, Agda, Lean for formalizing lambda calculus
- LEAP (Lambda, Evaluation, Application, Programming) - Educational framework
Research Frontiers
1. Optimal Reduction
- Goal: Reduce to normal form with minimal work
- Key technique: Sharing via graphs, not trees
- Paper: "An Algorithm for Optimal Lambda Calculus Reduction" (Lamping, POPL 1990)
- Implementation: Interaction nets, Gonthier et al. refinement
2. Explicit Substitutions
- Goal: Formalize substitution as a computational step
- Key technique: Environments, stacks, closures
- Paper: "Explicit Substitutions" (Abadi, Cardelli, Curien, 1991)
- Why it matters: Foundation for implementing functional languages
3. Normalization by Evaluation (NbE)
- Goal: Efficiently compute normal forms
- Key technique: Interpret in a continuation-based meta-language
- Paper: "Normalization by Evaluation" (Berger & Schwichtenberg, 1991)
- Implementation: Agda, Coq, Dedukti
4. Abstract Machines
- Goal: Bridge lambda calculus and real execution
- Key technique: SECD, Krivine, CAM
- Paper: "The Mechanical Evaluation of Expressions" (Landin, 1964), "A call-by-name lambda-calculus machine" (Krivine, 1985; published 2007)
- Implementation: Most functional language compilers
Implementation Pitfalls
The following traps have caused real bugs in production systems:
| Pitfall | Real Consequence | Solution |
| Capture-avoiding substitution | Subtle bugs with alpha-equivalence | Use de Bruijn indices or nominals |
| Closure over wrong environment | Wrong semantics for first-class functions | Deep copy or proper escaping |
| Space leaks in closures | Memory bloat in long-running programs | Implement thunks carefully |
| Incorrect η-reduction | Breaks observational equivalence | Disable or implement correctly |
| Weak head normal form confusion | Lazy vs eager semantics mixing | Choose strategy explicitly |
| Infinite loops on diverging terms | Non-termination without feedback | Add step limits, detect loops |
The "Omega Combinator" Problem
The classic omega combinator Ω = (λx. x x) (λx. x x) diverges. Implementations must handle this:
# Safe evaluation with step limiting
def eval_with_limit(term, env, max_steps=10000):
for _ in range(max_steps):
if is_value(term):
return term
term = step(term, env)
raise RuntimeError("Non-termination detected")De Bruijn Index Pitfalls
When implementing de Bruijn indices, common bugs include:
- Index shifting during substitution:
liftmust adjust indices correctly - Capture in substitution: Must check free variable sets
- Weak vs strong reduction: Whether to reduce under lambdas
# Correct de Bruijn substitution
def subst(term, index, replacement):
match term:
case DB(index') if index' == index:
return replacement
case DB(index') if index' > index:
return DB(index' - 1) # Shift down
case Abs(body):
return Abs(subst(body, index + 1, replacement.lift(1)))
# ... more casesConnections to Real Systems
Lambda calculus implementations connect to major systems:
| Real System | Lambda Calculus Connection |
| JavaScript V8 | Closures, scope chains trace to λ-calculus |
| Python | lambda is literal lambda calculus |
| React hooks | Closure semantics are core |
| Functional languages | All compile to variants of lambda calculus |
| WebAssembly | Function references are closure-like |
Tradeoffs and Limitations
Evaluation Strategy Tradeoffs
| Strategy | Pros | Cons |
| Call-by-Value (CBV) | Efficient, matches eager languages | May duplicate work, diverges from math |
| Call-by-Name (CBN) | Simple, matches lazy languages | May duplicate thunks |
| Call-by-Need | Shares work, optimal for laziness | Complex implementation |
| Parallel | Fast on multicore | Nondeterministic results |
When NOT to Use Pure λ-Calculus
- For practical languages: Add concrete syntax, recursion (Y combinator), constants
- For performance-critical code: Consider closure conversion, compilation to bytecode
- For verification: Use simply-typed or linear variants for stronger guarantees
Limitations
- Encoding overhead: Natural numbers, booleans require Church encodings (inefficient)
- No recursion: Must use fixed-point combinator (Y = λf.(λx.f(x x))(λx.f(x x)))
- α-equivalence: Variables are not identical under renaming; requires care
- Normalization: Untyped λ-calculus is not strongly normalizing (may diverge)
Assessment Criteria
A high-quality λ-calculus interpreter should have:
| Criterion | What to Look For |
| Correctness | Implements β-reduction correctly |
| Efficiency | Reasonable performance for typical terms |
| Evaluation strategy | Configurable CBV/CBN/need |
| Error handling | Clear errors for stuck terms |
| Alpha equivalence | Handles renaming correctly |
| De Bruijn | Correct index arithmetic |
Quality Indicators
✅ Good: Correct β-reduction, handles closures, configurable strategies ⚠️ Warning: Missing η-reduction, inefficient environments ❌ Bad: Capture-avoidance bugs, infinite loops on normal terms
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

