Fast and elegant functional programming toolkit for Python
Project description
Thyrse
A fast and elegant functional programming toolkit for Python
Thyrse is a comprehensive toolkit for functional programming in Python. It provides lambda calculus combinators, higher-order functions, algebraic data types, lenses, and many other tools to help you write elegant, functional Python code.
Features
- Pure Functional: Based on lambda calculus and functional programming principles
- Combinators: Classic S, K, I combinators and more for function abstraction
- Function Utilities: Composition, piping, currying, memoization, and more
- Algebraic Data Types: Optional, Result, and other ADTs for safer code
- Async Support: First-class support for async/await patterns
- Type Hints: Full type annotation support for better IDE experience
- Type Safe: Optional, Result, and Safe types for handling errors elegantly
- Zero Dependencies: Pure Python implementation, no external dependencies
- Pythonic: Leverages Python's language features naturally
Installation
pip install thyrse
Quick Start
Basic Combinators
from thyrse import I, K, S, curry, pipe, tap
# Identity combinator
assert I(42) == 42
# Constant combinator
greet = K("Hello")
assert greet("World") == "Hello"
# Function currying and composition
add = curry(lambda x, y: x + y)
add5 = add(5)
assert add5(3) == 8
# Pipeline data processing
pipeline = pipe(
[1, 2, 3],
lambda x: map(lambda i: i * 2, x),
list,
)
assert pipeline == [2, 4, 6]
# Debug output with tap
result = pipe(
42,
tap(print), # prints 42
lambda x: x + 1, # returns 43
)
Working with Optional and Result
from thyrse import Some, Nothing, Ok, Err
# Optional type
opt_value = Some(5)
result = opt_value.map(lambda x: x * 2).map(lambda x: x + 1)
# Result: Some(11)
# Result type
computation = Ok(10).map(lambda x: x / 2).map(lambda x: x - 1)
# Result: Ok(4.0)
# Chain operations safely
def safe_divide(x, y):
return Ok(x / y) if y != 0 else Err("Division by zero")
result = (
Ok(20)
.flat_map(lambda x: safe_divide(x, 2))
.flat_map(lambda x: safe_divide(x, 4))
)
# Result: Ok(2.5)
Function Composition
from thyrse import compose, curry
# Compose functions right-to-left
add_one = lambda x: x + 1
double = lambda x: x * 2
triple = lambda x: x * 3
# Result is: triple(double(add_one(x)))
f = compose(triple, double, add_one)
assert f(2) == 18 # triple(double(3)) = triple(6) = 18
# Or use pipe for left-to-right
from thyrse import pipe
assert pipe(2, add_one, double, triple) == 18
Predicates and Data Access
from thyrse import prop, get, get_in, has, is_type
data = {"user": {"name": "Alice", "age": 30}}
# Property access
age = get_in(data, ["user", "age"])
assert age == 30
# Type checking
is_user = is_type(dict)
assert is_user(data) == True
# Property extraction
get_name = prop("name")
assert get_name({"name": "Bob", "age": 25}) == "Bob"
Lenses for Data Manipulation
from thyrse import lens, view, set_, over
# Create a lens for a nested property
user_age = lens().user.age
data = {"user": {"name": "Alice", "age": 30}}
# View through the lens
assert view(user_age, data) == 30
# Set a new value
new_data = set_(user_age, 31, data)
assert view(user_age, new_data) == 31
# Transform with a function
incremented = over(user_age, lambda x: x + 1, data)
assert view(user_age, incremented) == 31
Async Support
import asyncio
from thyrse import async_pipe, async_compose
async def fetch_user(user_id):
# Simulated async operation
await asyncio.sleep(0.1)
return {"id": user_id, "name": "Alice"}
async def fetch_posts(user):
# Simulated async operation
await asyncio.sleep(0.1)
return [{"title": "Post 1", "author_id": user["id"]}]
async def main():
# Compose async functions
get_user_posts = async_pipe(
fetch_user,
lambda user: fetch_posts(user),
)
posts = await get_user_posts(1)
print(posts) # [{"title": "Post 1", "author_id": 1}]
asyncio.run(main())
Core Modules
Combinators (thyrse.combinators)
Classic lambda calculus combinators for building higher-order abstractions:
- I: Identity combinator
I(x) = x - K: Constant combinator
K(x)(y) = x - S: Substitution combinator
S(f)(g)(x) = f(x)(g(x)) - B: Composition combinator
B(f)(g)(x) = f(g(x)) - C: Flip combinator
C(f)(x)(y) = f(y)(x) - W: Duplicate combinator
W(f)(x) = f(x)(x) - Y: Fixed-point combinator (for recursion)
- Omega: Self-replicating combinator
Function Utilities (thyrse.func)
High-order functions and functional programming utilities:
curry/uncurry: Currying and uncurrying functionscompose/pipe: Function composition (right-to-left/left-to-right)tap: Side-effect debugging (pass-through)peek: Like tap, but for inspectionalways: Constant value factoryflip: Swap argument ordercomplement: Logical negation of predicatesretry: Function wrapper with retry logicmemoize: Caching function resultslog: Logging wrapperpartition/groupby: Collection operationsasync_compose/async_pipe: Async function compositionfork/branch: Parallel processing of functions
Predicates (thyrse.predicates)
Type checking and data access predicates:
prop: Property accessorget/get_in: Safe property accesshas: Check property existenceis_type: Type checking predicatesand_/or_/not_: Logical predicatestruthy/falsy: Truthiness checks
Algebraic Data Types (thyrse.adts)
Type-safe error handling with algebraic data types:
Optional/Some/Nothing: Optional valuesResult/Ok/Err: Result type for error handlingAsyncResult/AsyncOk/AsyncErr: Async results- All support
map(),flat_map(), and other functional operations
Lenses (thyrse.lens)
Composable getters/setters for nested data structures:
lens(): Create lenses for nested accessview(): Get value through lensset_(): Set value through lensover(): Transform value through lens- Works with any nested data structure
Lazy Evaluation (thyrse.lazy)
Deferred computation and memoization:
Lazy: Lazy computations with cachingAsyncLazy: Async lazy evaluationthunk()/force(): Quick lazy evaluation
Control Flow (thyrse.declarative_flow, thyrse.inline_flow)
Declarative and inline control flow constructs:
iif: Inline if-then-elseattempt: Try-catch wrappermatch: Pattern matchingusing: Resource management
Safe Evaluation (thyrse.safe)
Safe function wrapping and execution:
Safe: Safe function wrappersafe: Decorator for safe function execution
API Documentation
For detailed API documentation, visit the GitHub repository.
Examples
Data Processing Pipeline
from thyrse import pipe, partition, groupby, prop, map
users = [
{"name": "Alice", "age": 30, "active": True},
{"name": "Bob", "age": 25, "active": False},
{"name": "Carol", "age": 35, "active": True},
]
# Group active users by age and get their names
active_users = pipe(
users,
lambda us: filter(prop("active"), us),
groupby(prop("age")),
lambda groups: {age: [u["name"] for u in users] for age, users in groups.items()},
)
print(active_users)
# {30: ["Alice"], 35: ["Carol"]}
Error Handling
from thyrse import Ok, Err, Result
def parse_int(s):
try:
return Ok(int(s))
except ValueError:
return Err(f"Cannot parse '{s}' as integer")
def divide(x, y):
if y == 0:
return Err("Division by zero")
return Ok(x / y)
result = (
parse_int("20")
.flat_map(lambda x: divide(x, 4))
.map(lambda x: round(x, 2))
)
print(result) # Ok(5.0)
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the CC0 1.0 Universal License - See the LICENSE file for details.
CC0 1.0 Universal means this work is in the public domain. You can copy, modify, distribute and use the work, even for commercial purposes, all without asking permission.
Changelog
0.1.0 (2026-03-16)
- Initial release
- Core combinators (I, K, S, B, C, W, Y, Omega)
- Function utilities (compose, pipe, curry, etc.)
- Algebraic data types (Optional, Result)
- Lenses for data manipulation
- Async support
- Lazy evaluation
- Predicates and property access
- Error handling with Result type
Support
For issues, questions, or suggestions, please open an issue on the GitHub repository.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file thyrse-0.1.0.tar.gz.
File metadata
- Download URL: thyrse-0.1.0.tar.gz
- Upload date:
- Size: 25.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dccf3b49396c2c40d1c804fc1bd32135db333c526a67ec3d1f0bec3458676c9b
|
|
| MD5 |
477ed416ba928374f9019ccda592ac52
|
|
| BLAKE2b-256 |
2318593a3e515b523b02645413284880eb9c1094f4ac346848b35d825d0788a1
|
Provenance
The following attestation bundles were made for thyrse-0.1.0.tar.gz:
Publisher:
python-publish.yml on kagami-meika/thyrse
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
thyrse-0.1.0.tar.gz -
Subject digest:
dccf3b49396c2c40d1c804fc1bd32135db333c526a67ec3d1f0bec3458676c9b - Sigstore transparency entry: 1109801345
- Sigstore integration time:
-
Permalink:
kagami-meika/thyrse@36a0e7472552ef63e6dda556b8770972cb85aef1 -
Branch / Tag:
refs/tags/0.1.3 - Owner: https://github.com/kagami-meika
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@36a0e7472552ef63e6dda556b8770972cb85aef1 -
Trigger Event:
release
-
Statement type:
File details
Details for the file thyrse-0.1.0-py3-none-any.whl.
File metadata
- Download URL: thyrse-0.1.0-py3-none-any.whl
- Upload date:
- Size: 25.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b7f33851ac3a8be9f3e9e3ccf4173796bcdbd219fa8cc99b5a839853916b71a
|
|
| MD5 |
3a2844bade9c9bac4d3441e42a39e991
|
|
| BLAKE2b-256 |
fa996163843448a3d0268292ec128f8c6175afd631481aa667514eea72c22729
|
Provenance
The following attestation bundles were made for thyrse-0.1.0-py3-none-any.whl:
Publisher:
python-publish.yml on kagami-meika/thyrse
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
thyrse-0.1.0-py3-none-any.whl -
Subject digest:
3b7f33851ac3a8be9f3e9e3ccf4173796bcdbd219fa8cc99b5a839853916b71a - Sigstore transparency entry: 1109801347
- Sigstore integration time:
-
Permalink:
kagami-meika/thyrse@36a0e7472552ef63e6dda556b8770972cb85aef1 -
Branch / Tag:
refs/tags/0.1.3 - Owner: https://github.com/kagami-meika
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@36a0e7472552ef63e6dda556b8770972cb85aef1 -
Trigger Event:
release
-
Statement type: