Crates.io | rustica |
lib.rs | rustica |
version | 0.10.0 |
created_at | 2025-02-04 14:29:41.662843+00 |
updated_at | 2025-09-21 09:17:04.470432+00 |
description | Rustica is a functional programming library for the Rust language. |
homepage | |
repository | https://github.com/but212/rustica |
max_upload_size | |
id | 1542005 |
size | 1,904,900 |
Rustica is a comprehensive functional programming library for Rust, bringing powerful abstractions from category theory and functional programming to the Rust ecosystem. It provides a rich set of type classes, data types, and utilities commonly found in functional programming languages.
This library prioritizes correctness and learning over performance. Current implementations have 20-100x overhead compared to direct Rust code, making them unsuitable for production performance-critical applications.
Rustica enables idiomatic functional programming in Rust by providing:
Functor
, Applicative
, and Monad
Maybe
, Either
, Choice
, and IO
StateT
, ReaderT
, and moreExcellent for:
Avoid for:
Whether you're coming from Haskell, Scala, or other functional languages, or just want to explore functional programming in Rust, Rustica provides the tools you need for learning and experimentation.
Add Rustica to your Cargo.toml
:
[dependencies]
rustica = "0.10.0"
If you want to use async features, add the async
feature:
[dependencies]
rustica = { version = "0.10.0", features = ["async"] }
Persistent vector collections are now included by default in Rustica 0.10.0.
You can combine multiple features as needed:
[dependencies]
rustica = { version = "0.10.0", features = ["full"] }
Then import the prelude to get started:
use rustica::prelude::*;
Rustica implements a wide range of type classes from category theory:
Basic Abstractions
Functor
- For mapping over contained valuesApplicative
- For applying functions in a contextMonad
- For sequential computationsPure
- For lifting values into a contextIdentity
- For accessing values inside contextsAlternative
- For choice between computationsAlgebraic Structures
Semigroup
- Types with an associative binary operationMonoid
- Semigroups with an identity elementFoldable
- For reducing structuresTraversable
- For structure-preserving transformationsAdvanced Concepts
Bifunctor
- For mapping over two type parametersContravariant
- For reversing function applicationCategory
- For abstract compositionArrow
- For generalized computationComonad
- For context-aware computationsMonadError
- For error handling in monadic contextsRustica provides a rich collection of functional data types:
Core Types
Maybe<T>
- For optional values (like Option<T>
)Either<L, R>
- For values with two possibilitiesId<T>
- The identity monadValidated<E, T>
- For accumulating validation errorsChoice<T>
- For representing non-deterministic computations with alternativesEffect Types
IO<A>
- For pure I/O operationsState<S, A>
- For stateful computations with thread-safe implementationsReader<E, A>
- For environment-based computationsWriter<W, A>
- For logging operationsCont<R, A>
- For continuation-based programmingAsyncMonad<A>
- For asynchronous operationsSpecial Purpose
First
, Last
, Min
, Max
, etc.)Persistent Collections
PersistentVector<T>
- An efficient immutable vector with structural sharing and small vector optimizationTransformers
StateT<S, M, A>
- State monad transformer for combining state with other effectsReaderT<E, M, A>
- Reader monad transformer for combining environment with other effectsWriterT<W, M, A>
- Writer monad transformer for combining logging with other effectsOptics
Lens
- For focusing on parts of structuresPrism
- For working with sum typesIsoLens
- Lawful, composable lenses based on isomorphisms for deep focusingIsoPrism
- Lawful, composable prisms based on isomorphisms for sum typesRustica provides standardized error handling utilities that work across different functional types:
Core Functions
sequence
- Combines a collection of Result
values into a single Result
containing a collectiontraverse
- Applies a function that produces a Result
to a collection, returning a single Result
traverse_validated
- Like traverse
but collects all errors instead of failing fastType Conversion
ResultExt
trait - Extends Result
with methods like to_validated()
and to_either()
WithError
trait - Generic trait for any type that can represent error statesResult
, Either
, and Validated
Error Types
AppError<M, C>
- A structured error type that provides both a message and optional contexterror()
and error_with_context()
Rustica provides an immutable persistent vector (RRB-Tree) for functional programming patterns. This is included by default in Rustica 0.10.0.
Example Usage
use rustica::pvec::PersistentVector;
use rustica::pvec::pvec;
let v1: PersistentVector<i32> = pvec![1, 2, 3, 4, 5];
let v2 = v1.push_back(6);
let v3 = v1.update(0, 10);
assert_eq!(v1.get(0), Some(&1));
assert_eq!(v2.get(5), Some(&6));
assert_eq!(v3.get(0), Some(&10));
Rustica uses GitHub Actions for continuous integration, formatting, linting, and automated publishing to crates.io on tagged releases.
v0.9.0
) is pushed, the version is checked and, if not already published, is automatically uploaded to crates.io.See CHANGELOG.md for a complete list of recent changes and enhancements.
use rustica::prelude::*;
use rustica::datatypes::id::Id;
use rustica::traits::identity::Identity;
// Create Id values
let x = Id::new(5);
let y = Id::new(3);
let z = Id::new(2);
// Access the inner value using Identity trait's value() method
assert_eq!(*x.value(), 5);
// Using Functor to map over Id
let doubled = x.fmap(|n| n * 2);
assert_eq!(*doubled.value(), 10);
// Using Pure to lift a value into Id context
let pure_value = Id::<i32>::pure(&42);
assert_eq!(*pure_value.value(), 42);
// Using Applicative to apply functions
// 1. Apply a function wrapped in Id
let add_one = Id::new(|x: &i32| x + 1);
let result = add_one.apply(&x);
assert_eq!(*result.value(), 6);
// 2. Combine two Id values with lift2
let add = |a: &i32, b: &i32| a + b;
let sum = Id::<i32>::lift2(add, &x, &y);
assert_eq!(*sum.value(), 8);
// 3. Combine three Id values with lift3
let multiply = |a: &i32, b: &i32, c: &i32| a * b * c;
let product = Id::<i32>::lift3(multiply, &x, &y, &z);
assert_eq!(*product.value(), 30);
// Working with different types
let greeting = Id::new("Hello");
let count = Id::new(3_usize);
let repeat = |s: &&str, n: &usize| s.repeat(*n);
let repeated = Id::<&str>::lift2(repeat, &greeting, &count);
assert_eq!(*repeated.value(), "HelloHelloHello");
// Chaining operations
let result = x
.fmap(|n| n + 1) // 5 -> 6
.fmap(|n| n * 2) // 6 -> 12
.fmap(|n| n.to_string());
assert_eq!(*result.value(), "12");
use rustica::datatypes::cont::Cont;
// Create a simple continuation
let cont = Cont::return_cont(42);
// Run the continuation with a handler
let result = cont.clone().run(|x| x * 2);
assert_eq!(result, 84);
// Chain continuations
let cont2 = cont.bind(|x| Cont::return_cont(x + 1));
let result2 = cont2.run(|x| x * 2);
assert_eq!(result2, 86);
use rustica::datatypes::cont::Cont;
// A function that uses continuations to implement early return
fn safe_divide(a: i32, b: i32) -> Cont<i32, i32> {
if b == 0 {
// Early return with a default value
Cont::new(|_| -1)
} else {
// Continue with the division
Cont::return_cont(a / b)
}
}
// Run with different inputs
let result1 = safe_divide(10, 2).run(|x| x);
let result2 = safe_divide(10, 0).run(|x| x);
assert_eq!(result1, 5);
assert_eq!(result2, -1);
use rustica::datatypes::cont::Cont;
// Create two continuations
let cont1 = Cont::return_cont(5);
let cont2 = Cont::return_cont(-1);
// Run the continuations with an identity continuation
let result1 = cont1.run(|x| x);
let result2 = cont2.run(|x| x);
assert_eq!(result1, 5);
assert_eq!(result2, -1);
Rustica is inspired by functional programming libraries in other languages:
Contributions are welcome! Check the TODO list for areas that need work.
Rustica is licensed under the Apache License, version 2.0. See the LICENSE file for details.
For detailed documentation, please visit docs.rs/rustica