kotlin-functional-programming
npx machina-cli add skill msewell/agent-stuff/kotlin-functional-programming --openclawKotlin Functional Programming
Workflow
- Read the relevant reference file(s) from
references/before advising (see References section below for which file covers which topics). - Identify which principles apply to the user's code or question (see Summary of Principles in the reference).
- Apply the relevant best practices; cite section numbers when explaining trade-offs.
- Prefer Kotlin built-in features over third-party libraries unless the user explicitly asks otherwise.
- Validate suggestions against the Kotlin 2.0–2.2+ feature set described in the reference.
- When refactoring existing code, make the smallest change that moves toward the functional core, imperative shell architecture.
Key Principles (quick reference)
- Default to
val; treatvaras a code smell requiring justification. - Write pure functions for all domain logic; push I/O and mutation to the edges.
- Use
if,when,tryas expressions that return values assigned toval. - Model variants with
sealed interface; never addelseto an exhaustivewhen. - Wrap primitives in
@JvmInline value classto prevent argument-order bugs at zero runtime cost. - Handle expected failures with
T?,Result<T>, or sealed error hierarchies — not exceptions. - Compose behavior with higher-order functions; use
inlineon lambda-taking utilities to eliminate allocation overhead. - Build data pipelines with collection operators (
map,filter,fold,flatMap, …). - Default to eager collections; switch to
Sequenceonly for large datasets with multiple chained operations. - Use
tailrecfor linear recursion,DeepRecursiveFunctionfor tree/graph recursion. - Model async work with
suspendfunctions andFlowpipelines; prefercoroutineScopeoverGlobalScope. - Use context parameters (Kotlin 2.2+) sparingly for cross-cutting concerns (
Raise, logging, transaction scope).
Common Tasks
Writing pure domain logic
Follow §2 (Pure Functions), §3 (Immutability), §17 (Functional Core, Imperative Shell).
Pass all dependencies as parameters; return new values instead of mutating inputs.
Modeling a domain with types
Follow §5 (Sealed Types), §6 (Value Classes).
Prefer sealed interface over sealed class unless subtypes share state.
Add validation in value class init blocks ("parse, don't validate").
Error handling
Follow §7 (Functional Error Handling).
- Absence/not-found → nullable
T? - Wrapping throwing APIs →
Result<T>+runCatching - Typed domain errors → custom sealed hierarchy + minimal
Either<L, R>
Collection pipelines
Follow §12 (Collections) and §13 (Sequences).
Prefer named operations over manual loops.
Use fold over reduce when an initial value is needed or the result type differs.
Testing
Follow §18 (Testing).
- Test pure core with direct assertions — no mocks needed.
- Test sealed branches exhaustively.
- Use Kotest
checkAllwithArbfor property-based testing of validators and transformations; prefercheckAlloverforAllfor matcher-based assertions and clearer failures. - Reserve integration tests (MockK, Testcontainers) for the imperative shell.
References
- references/01-foundations.md — §1–4: Why FP, Pure Functions, Immutability, Expressions
- references/02-type-system.md — §5–7: Sealed Types, Value Classes, Error Handling
- references/03-functions-and-composition.md — §8–11: HOFs, Inline, Extensions, Scope Functions
- references/04-collections-and-sequences.md — §12–13: Collection Pipelines, Sequences
- references/05-advanced-patterns.md — §14–16: DSLs, Recursion, Coroutines
- references/06-architecture-testing-context.md — §17–19: Architecture, Testing, Context Parameters
- references/07-summary.md — §20: Summary of all 17 principles
Source
git clone https://github.com/msewell/agent-stuff/blob/main/skills/kotlin-functional-programming/SKILL.mdView on GitHub Overview
This skill teaches writing idiomatic, functional-style Kotlin by leveraging built-in language features. It covers immutability, pure functions, sealed types, functional error handling, collection pipelines, coroutines, and functional architecture patterns to help you build robust, testable code.
How This Skill Works
Follow the workflow: read relevant references, map applicable principles to your code, and apply Kotlin’s built-in features. Emphasize val over var, use sealed interfaces for variants, and handle errors with Result, T?, or sealed hierarchies; compose behavior with map/flatMap/fold and prefer eager collections unless sequences are beneficial.
When to Use It
- You want a pure, testable domain logic without side effects.
- You’re refactoring existing code toward a functional core and an imperative shell.
- You need strong type safety with sealed types for domain variants.
- You’re handling errors functionally (using Result, nullable types, or sealed error hierarchies) instead of exceptions.
- You’re building data pipelines with collection operators (map, filter, fold, flatMap) and deciding when to use List vs. Sequence.
Quick Start
- Step 1: Identify the pure core vs. IO/side-effect edges in your codebase.
- Step 2: Refactor domain logic into pure functions that take inputs and return new values.
- Step 3: Introduce functional error handling (Result, T?, or sealed errors) and fold in coroutines/Flow as needed.
Best Practices
- Prefer val over var and push mutation toward the edges of the system.
- Write pure domain logic; pass all dependencies as parameters and return new values.
- Model variants with sealed interfaces; avoid else branches in exhaustive when expressions.
- Use collection operators to build pipelines; use fold when an initial value or differing result type is needed.
- Default to eager collections; switch to Sequence only for large datasets with multiple chained operations.
Example Use Cases
- A domain service that computes discounts using pure functions, independent of IO.
- Modeling a user action hierarchy with a sealed interface to represent all possible events.
- Wrapping a legacy IO API with Result and runCatching to expose a safe, functional surface.
- Transforming streaming data with map/flatMap to produce a clean data pipeline.
- Tail-recursive traversal of a tree using @tailrec to safely compute aggregates.
Frequently Asked Questions
Related Skills
creating-c4-diagrams
msewell/agent-stuff
Creates, reviews, and interprets C4 software architecture diagrams (System Context, Container, Component, Dynamic, Deployment). Produces Structurizr DSL or Mermaid diagram code following C4 model best practices. Use when creating architecture diagrams for a system, reviewing existing C4 diagrams for correctness and anti-patterns, generating Structurizr DSL workspaces, producing Mermaid C4 diagrams for READMEs, or using C4 diagrams as context for design decisions, code generation, risk analysis, or onboarding.
arazzo-specification
msewell/agent-stuff
Guides writing, reviewing, and modifying Arazzo workflow specifications (OpenAPI Initiative standard for multi-step API workflows). Use when creating Arazzo documents from scratch, adding steps or workflows to existing specs, reviewing Arazzo files for correctness, or generating API workflow definitions. Covers document structure, runtime expressions, success criteria, control flow, data threading, reusable components, workflow composition, AI agent integration, and validation.
property-based-testing-with-kotest
msewell/agent-stuff
Writes property-based tests using Kotest's kotest-property module. Identifies testable properties, designs generators, and configures PBT for Kotlin/JVM projects. Use when writing property-based tests, creating custom Arb generators, choosing property patterns (roundtrip, invariant, idempotence, oracle), debugging shrunk counterexamples, or integrating PBT into a Kotlin test suite alongside example-based tests.
reducing-coupling
msewell/agent-stuff
Analyzes a codebase scope for coupling issues, diagnoses coupling types using the Connascence framework, and proposes a comprehensive refactoring plan with concrete code changes. Use when asked to find coupling, reduce dependencies, decouple modules, or improve modularity in a codebase.
mermaid-sequence-diagrams
msewell/agent-stuff
Generates, reviews, and fixes Mermaid sequence diagrams following syntax rules and best practices. Use when creating sequence diagrams from system descriptions, reviewing existing Mermaid sequence diagrams for correctness, fixing parse errors, or refactoring large diagrams into focused sub-diagrams. Covers participants, arrows, activations, control flow, notes, styling, and common anti-patterns.
making-invalid-states-unrepresentable
msewell/agent-stuff
Analyzes existing code and guides new type design to make invalid states unrepresentable using type system techniques such as sum types, newtypes, typestate, branded types, and parse-don't-validate. Use when reviewing code for invalid-state bugs, refactoring types to eliminate impossible states, designing domain models, or applying compile-time correctness patterns. Language-agnostic.