ribs_core 1.0.0-dev.16
ribs_core: ^1.0.0-dev.16 copied to clipboard
Functional programming (FP) kernel. Provides common FP datatypes like Option, Either, State, Validated, as well as collection hierarchy inspired by the Scala programming language.
ribs_core #
Functional programming (FP) kernel for Dart. Provides common FP datatypes like Option, Either, State, and Validated, as well as a comprehensive immutable collection hierarchy inspired by the Scala programming language.
Full documentation is available at the ribs website.
Core Data Types #
Option #
Option represents optional values. Instances of Option are either a Some or None. It brings a wide variety of combinators not available on standard nullable types.
import 'package:ribs_core/ribs_core.dart';
final Option<int> someValue = Some(42);
final Option<int> noValue = none();
// Map and flatMap allow safe transformations
final result = someValue
.map((v) => v * 2)
.filter((v) => v > 50)
.getOrElse(() => 0); // 84
Either #
Either represents one of two possible values (a disjoint union). It is right-biased, meaning methods like map and flatMap operate on the Right value. It is usually used for safe error handling.
Either<String, int> parse(String str) {
try {
return Right(int.parse(str));
} catch (_) {
return Left('Not a number');
}
}
final valid = parse("42").map((n) => n + 1); // Right(43)
final invalid = parse("foo").map((n) => n + 1); // Left('Not a number')
Validated #
Unlike Either, Validated does not form a Monad (has no flatMap), but it supports error accumulation, usually in the form of ValidatedNel (a Validated instance where errors are collected in a NonEmptyIList).
ValidatedNel<String, User> validateUser(String name, int age) {
final vName = name.isEmpty ? "Name cannot be empty".invalidNel<String>() : name.validNel<String>();
final vAge = age < 18 ? "Must be 18 or older".invalidNel<int>() : age.validNel<String>();
return vName.product(vAge).map((t) => User(t.$1, t.$2));
}
State #
State models state transitions of type S, yielding a value of type A. It allows for pure functional representations of state mutation.
final nextInt = State<int, int>((seed) {
final next = (seed * 1103515245 + 12345) & 0x7FFFFFFF;
return (next, next);
});
final (finalState, value) = nextInt.run(42);
Tuple Extensions #
ribs_core provides extensive syntax extensions for tuples up to 22 elements, adding utility methods like appended, prepended, map, head, tail, last, and more.
final t2 = (1, "A");
final t3 = t2.appended(true); // (1, "A", true)
final first = t3.head; // 1
final last = t3.last; // true
Collections Library #
ribs_core offers an immutable collections hierarchy inspired by Scala. These provide safer, more flexible alternatives to built-in collections.
IList: Immutable linked list, perfect for fast prepends and recursive algorithms.IVector: Immutable vector, providing fast random access and updates.IMap: Immutable key-value map.IChain: Constant time append/prepend connection.NonEmptyIList: AnIListguaranteed to contain at least one element.ILazyList: A lazy, potentially infinite linked list.IMultiDict: Immutable map that associates keys with multiple values.- Many More!
Mutable variants also exist (ListBuffer, Array, HashMap, etc.) for use when performance dictates mutability under the hood.
Small Snippets #
// IList: standard linked list
final list = ilist([1, 2, 3]);
final more = list.prepended(0).appended(4); // IList(0, 1, 2, 3, 4)
// IVector: ideal for random lookups
final vec = ivec(["a", "b", "c"]);
final updatedVec = vec.updated(1, "z"); // IVector("a", "z", "c")
// IMap: immutable mapping
final map = imap({"test": 1});
final newMap = map.updated("other", 2); // IMap({"test": 1, "other": 2})
// Collection traversals
final evens = list.filter((x) => x % 2 == 0);
Rich Collections API #
The collections API includes hundreds of methods for transforming, filtering, and aggregating data, many of which are not available in the standard Dart SDK:
foldLeft/foldRight: Explicitly ordered reductions.zip/zipWithIndex: Combine collections or pair elements with their indices.partition: Split a collection into two based on a predicate.collect: Filter and transform elements in a single pass.groupBy: Organize elements into a map based on a key selector.sliding/grouped: Windowed or chunked iteration.distinctBy: Filter for unique elements based on a specific property.- Many More!
final items = ilist([1, 2, 3, 4, 5]);
// Partition into evens and odds
final (evens, odds) = items.partition((x) => x % 2 == 0);
// Sliding window of size 2
final windows = items.sliding(2); // [[1, 2], [2, 3], [3, 4], [4, 5]]
In-Depth Examples #
For a more comprehensive look at ribs_core features working together to solve problems robustly, check out the example located at example/example.dart in the package source.