Skip to main content

Koka

Algebraic Effects for Python - A lightweight library for effect-based programming inspired by the Koka language.

Koka enables:

  • 🎯 Type-safe dependency injection using effect handlers
  • 🚨 Typed error handling with pattern matching (no exceptions!)
  • 🔗 Effect composition - effects can call other effects
  • 🎨 Functional style - immutable handlers, pure functions

Requires Python 3.13+ (uses modern type parameter syntax)

Quick Start

from koka import Dep, Err, Koka

# Define a dependency
class Database:
    def get_user(self, id: str):
        return {"id": id, "name": "Alice"}
# Define an error type
class UserNotFound(Exception): pass

# Write an effect that uses dependencies and can fail
def get_user_name(user_id: str):
    if not user_id:
        return (yield from Err(UserNotFound("Empty ID")))
    db = yield from Dep(Database)  # Request dependency
    user = db.get_user(user_id)
    return user["name"]

# Set up dependencies and run the effect
result = Koka().provide(Database()).run(get_user_name("123"))

# Pattern match is statically typed
match result:
    case UserNotFound() as e:
        print(f"Error: {e}")
    case name:
        print(f"User: {name}")  # Output: User: Alice

Installation

# Note: Not yet published to PyPI
# For now, install from source:
git clone https://github.com/HerringtonDarkholme/koka
cd koka
uv sync --all-extras

Core Concepts

Effects

An effect is a generator function that can yield from effect objects to request capabilities:

def my_effect():
    config = yield from Dep(Config)  # Request a dependency
    if config.invalid:
        return (yield from Err(ValidationError()))  # Signal an error
    return config.value

Effect Types

Dep[T] - Dependency injection effect

db = yield from Dep(Database)  # Request a Database instance

Err[E] - Error effect (alternative to exceptions)

return (yield from Err(NotFoundError("Resource not found")))

Effect Handlers

The Koka class provides and handles effects:

result = (
    Koka()
    .provide(Database())      # Provide a Database instance
    .provide(AuthService())   # Provide an AuthService instance
    .run(my_effect())        # Run the effect
)

Returns either the success value or an error, which you can pattern match:

match result:
    case ValidationError():
        print("Validation failed")
    case NotFoundError():
        print("Not found")
    case value:
        print(f"Success: {value}")

Examples

See the examples/ directory for complete examples:

Run examples:

uv run python examples/01_basic_di.py

Development Setup

This project uses uv for package management.

# Install dependencies
uv sync --all-extras

# Activate virtual environment
source .venv/bin/activate  # On Unix/macOS
# or
.venv\Scripts\activate  # On Windows

Development Commands

Linting

# Run linting checks
uv run ruff check .

# Auto-fix linting issues
uv run ruff check --fix .

Formatting

# Format code
uv run ruff format .

# Check formatting without making changes
uv run ruff format --check .

Type Checking

# Run type checking
uv run pyright

# Run type checking on specific files
uv run pyright src/koka/example.py

# Check types in watch mode
uv run pyright --watch

Testing

# Run tests
uv run pytest

# Run tests with coverage report
uv run pytest --cov=koka --cov-report=html

# Run specific test file
uv run pytest tests/test_example.py

Run All Checks

# Run all checks (linting, type checking, and tests)
uv run ruff check . && uv run pyright && uv run pytest

Why Koka?

The answer can be found in effect.ts homepage. To summarize, make as much type checked and compiler managed as possible.

Project Structure

koka/
├── src/
│   └── koka/           # Main package
│       └── __init__.py # Core effect system
├── tests/              # Test files
│   ├── test_koka.py    # Integration example
│   └── test_unit.py    # Unit tests
├── examples/           # Example scripts
│   ├── 01_basic_di.py
│   ├── 02_error_handling.py
│   └── 03_composition.py
├── pyproject.toml      # Project configuration
├── LICENSE
└── README.md

API Reference

Koka[K]

Effect handler runtime.

Methods:

  • provide[N](instance: N) -> Koka[Dep[N] | K] - Register a dependency
  • run[E, T](eff: Eff[K | E, T]) -> T | E - Execute an effect computation

Dep[T]

Dependency injection effect.

Usage: value = yield from Dep(MyClass)

Err[E: Exception]

Error effect for typed error handling.

Usage: return (yield from Err(MyError()))

Eff[K, R]

Type alias for effect computations: Generator[K, Never, R]

Inspiration & Credits

This project draws inspiration from several excellent projects in the algebraic effects and functional programming space:

🌟 Primary Inspirations

  • Koka Language - The pioneering research language for algebraic effect handlers by Daan Leijen. Koka's elegant design of effect types and handlers is the foundation for this library's approach to effects in Python.

  • Effect-TS - A powerful effect system for TypeScript that brings functional programming patterns to the JavaScript ecosystem. Effect-TS demonstrates how algebraic effects can be practical and ergonomic in mainstream languages.

💡 Related Projects

  • koka-ts - TypeScript implementation of Koka-style effect handlers, showing how these concepts can be adapted to languages with different type systems.

  • stateless - A Python library for building type-safe, composable state machines and effects. Demonstrates how generator-based effects can work elegantly in Python.

🙏 Acknowledgments

Special thanks to:

  • Daan Leijen for the groundbreaking research on algebraic effects in Koka
  • The Effect-TS team for showing how effects can be practical and developer-friendly
  • The maintainers of koka-ts and stateless for exploring effect systems in TypeScript and Python

This project stands on the shoulders of giants. While it's a toy implementation for learning and fun, it aims to bring some of the elegance of Koka-style effects to modern Python.

Contributing

This is a toy project for fun and learning! Feel free to:

  • Open issues with questions or ideas
  • Submit PRs with improvements
  • Fork and experiment

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

koka-0.0.1.tar.gz (6.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

koka-0.0.1-py3-none-any.whl (7.0 kB view details)

Uploaded Python 3

File details

Details for the file koka-0.0.1.tar.gz.

File metadata

  • Download URL: koka-0.0.1.tar.gz
  • Upload date:
  • Size: 6.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.10

File hashes

Hashes for koka-0.0.1.tar.gz
Algorithm Hash digest
SHA256 446194e98d03193c779120ca6f296ba3935e898f720ce868efda0881cb411db9
MD5 b206fae97274554cd052e11d28717cca
BLAKE2b-256 02eb50ba98fa9dd8199ae9f5a421fad69ec5dc6b4a7db806207fe4c7dbba150f

See more details on using hashes here.

File details

Details for the file koka-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: koka-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 7.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.10

File hashes

Hashes for koka-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 dbeb18567c4f6ad2d1a717789809067bfed617ee2c84f938e35563c1988d0865
MD5 3b60f52474bb60a264b01f4b4cb763e7
BLAKE2b-256 890d3ff3d3ef9ecf87178836a6b0a2854a72d12078499e3fa1179ec0a66aa90c

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page