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:
01_basic_di.py- Basic dependency injection02_error_handling.py- Typed error handling with pattern matching03_composition.py- Composing effects together
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 dependencyrun[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
Metadata
Release files for koka 0.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| koka-0.0.1.tar.gz | 6.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| koka-0.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 13.4 kB
Release files / koka-0.0.1.tar.gz
| Download URL | koka-0.0.1.tar.gz |
|---|---|
| Size | 6.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
446194e98d03193c779120ca6f296ba3935e898f720ce868efda0881cb411db9
|
|
BLAKE2b-256 checksum How to use checksums |
02eb50ba98fa9dd8199ae9f5a421fad69ec5dc6b4a7db806207fe4c7dbba150f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.6.10
|
Release files / koka-0.0.1-py3-none-any.whl
| Download URL | koka-0.0.1-py3-none-any.whl |
|---|---|
| Size | 7.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dbeb18567c4f6ad2d1a717789809067bfed617ee2c84f938e35563c1988d0865
|
|
BLAKE2b-256 checksum How to use checksums |
890d3ff3d3ef9ecf87178836a6b0a2854a72d12078499e3fa1179ec0a66aa90c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.6.10
|