NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #783 most downloaded on pub.dev
Functional programming in Dart and Flutter. All the main functional programming types and patterns fully documented, tested, and with examples.
Last release 11 months ago
29 Oct 2025
Release timing varies
gaps range from 1 weeks to 12 months
Nearly every release is documented
notes for 25 of 26 stable releases
Nothing withdrawn
no release was ever pulled
5 years old
31 releases · first in 2021
One column per quarter.
Nothing published for this version
Nothing published for this version
Nothing published for this version
Added toTaskOptionFlat, toTaskEitherFlat, fromTaskFlatten to TaskOption and TaskEither
toTaskOptionFlat, toTaskEitherFlat, fromTaskFlatten to TaskOption and TaskEithersingleOption, elementAtOption, singleWhereOption, lastWhereOptionFixed broken documentation links
Improved performance of some iterable based functions in Iterable and Map extension (thanks to @lrhn 🎉)
Improved performance of some iterable based functions in Iterable and Map extension (thanks to @lrhn 🎉)
Added lookupEq and dropRight on Iterable extension
[].lookupEq(Eq.eqInt, 5) // None()
[1, 2, 3, 4].lookupEq(Eq.eqInt, 5) // None()
[1, 2, 3, 4].lookupEq(Eq.eqInt, 3) // Some(3)
[1, 6, 4, 3, 2].lookupEq(Eq.by((n) => n % 3, Eq.eqInt), 0) // Some(6)
[1, 2].dropRight(3) // []
[1, 2, 3, 4].dropRight(1) // [1, 2, 3]lookupKeyEq on Map extension<String, int>{'a': 1, 'b': 2, 'c': 3, 'd': 4}.lookupKeyEq(Eq.eqString, 'b'); // Some('b')
<String, int>{'a': 1, 'b': 2, 'c': 3, 'd': 4}.lookupKeyEq(Eq.eqString, 'e'); // None()Improved performance of some iterable based functions in Iterable and Map extension (thanks to lrhn 🎉)
Added lookupEq and dropRight on Iterable extension
[].lookupEq(Eq.eqInt, 5) // None()
[1, 2, 3, 4].lookupEq(Eq.eqInt, 5) // None()
[1, 2, 3, 4].lookupEq(Eq.eqInt, 3) // Some(3)
[1, 6, 4, 3, 2].lookupEq(Eq.by((n) => n % 3, Eq.eqInt), 0) // Some(6)
[1, 2].dropRight(3) // []
[1, 2, 3, 4].dropRight(1) // [1, 2, 3]
lookupKeyEq on Map extension<String, int>{'a': 1, 'b': 2, 'c': 3, 'd': 4}.lookupKeyEq(Eq.eqString, 'b'); // Some('b')
<String, int>{'a': 1, 'b': 2, 'c': 3, 'd': 4}.lookupKeyEq(Eq.eqString, 'e'); // None()
Minimum environment dart sdk to 3.0.0 ⚠️ (Dart 3️⃣)
3.0.0 ⚠️ (Dart 3️⃣)environment:
sdk: ">=3.0.0 <4.0.0"ReaderTaskEither type
ReaderTaskEither models a complete program using Reader for dependency injection, Task to perform asynchronous computation, and Either to handle errors 🎯ReaderTask typeEither as sealed class (Dart 3️⃣)
Left or Right)/// Pattern matching
final match = right.match(
(l) => print('Left($l)'),
(r) => print('Right($r)'),
);
/// or use Dart's pattern matching as well 🤝
final dartMatch = switch (right) {
Left(value: final l) => 'Left($l)',
Right(value: final r) => 'Right($r)',
};Option as sealed class (Dart 3️⃣)
None or Some)/// Pattern matching
final match = option.match(
() => print('None'),
(a) => print('Some($a)'),
);
/// or use Dart's pattern matching as well 🤝
final dartMatch = switch (option) {
None() => 'None',
Some(value: final a) => 'Some($a)',
};final (no extends nor implements) (Dart 3️⃣)
UnitReaderStateStateAsyncIOIORefIOOptionIOEitherTaskTaskOptionTaskEitherReaderTaskReaderTaskEitherTuple2, use Dart 3 Records instead (Tuple2(a, b) becomes simply (a, b) 🎯) ⚠️ (Dart 3️⃣)
Tuple2Iterable and List extension methods
Iterable and List) (#65)prependAll (Iterable)intersperse (Iterable)difference (Iterable)filterWithIndex (Iterable)takeWhileRight: Resulting List now in reversed order as expecteddropWhileRight: Resulting List now in reversed order as expectedfoldRight, foldRightWithIndex (List): Changed parameter order in combine functionzipWith (Iterable): Changed parameters definition, no more curriedplus → concat (Iterable)concat → flatten (on Iterable<Iterable<T>>)concatMap (use flatMap instead)bind (use flatMap instead)bindWithIndex (use flatMapWithIndex instead)concatMapWithIndex (use flatMapWithIndex instead)Map extension methods
lookupEqlookupWithKeyEqmember (use containsKey instead)elem (use containsValue instead)toIterable (use toSortedList instead)toIterable renamed to toSortedList (return a List instead of Iterable)modifyAt changed parameter order and no more curriedmodifyAtIfPresent changed parameter order and no more curriedupdateAt no more curriedupdateAtIfPresent no more currieddeleteAt no more curriedupsertAt no more curriedpop no more curriedfoldLeft no more curriedfoldLeftWithKey no more curriedfoldLeftWithIndex no more curriedfoldLeftWithKeyAndIndex no more curriedfoldRight no more curriedfoldRightWithKey no more curriedfoldRightWithIndex no more curriedfoldRightWithKeyAndIndex no more curriedunion no more curriedintersection no more curriedisSubmap no more curriedcollect no more currieddifference no more curriedString to num, int, double, and bool using Option and Either (both as extension methods on String and as functions) (#80)
toNumOptiontoIntOptiontoDoubleOptiontoBoolOptiontoNumEithertoIntEithertoDoubleEithertoBoolEither/// As extension on [String]
final result = "10".toNumOption; /// `Some(10)`
final result = "10.5".toNumOption; /// `Some(10.5)`
final result = "0xFF".toIntOption; /// `Some(255)`
final result = "10.5".toDoubleOption; /// `Some(10.5)`
final result = "NO".toBoolEither(() => "left"); /// `Left("left")`
/// As functions
final result = toNumOption("10"); /// `Some(10)`
final result = toNumOption("10.5"); /// `Some(10.5)`
final result = toIntOption("0xFF"); /// `Some(255)`
final result = toDoubleOption("10.5"); /// `Some(10.5)`
final result = toBoolEither("NO", () => "left"); /// `Left("left")`dateNow, now, random, and randomBool to getter functions/// Before
Option<T> getRandomOption<T>(T value) => randomBool()
.map((isValid) => isValid ? some(value) : none<T>())
.run();
/// Now
Option<T> getRandomOption<T>(T value) => randomBool
.map((isValid) => isValid ? some(value) : none<T>())
.run();Predicate class and added extension methods in its place ⚠️bool isEven(int n) => n % 2 == 0;
bool isDivisibleBy3(int n) => n % 3 == 0;
final isOdd = isEven.negate;
final isEvenAndDivisibleBy3 = isEven.and(isDivisibleBy3);
final isEvenOrDivisibleBy3 = isEven.or(isDivisibleBy3);
final isStringWithEvenLength = isEven.contramap<String>((n) => n.length);curry to curryAll for functions with 3, 4, 5 parameterscurry to curry only the first parameteruncurry and curry extension to getter functioncurry and uncurry as functions (use extension method instead)curryLast (curry last parameter)int Function(int) subtractCurried(int n1) => (n2) => n1 - n2;
/// Before
subtractCurried.uncurry()(10, 5);
final addFunction = (int a, int b) => a + b;
final add = curry2(addFunction);
[1, 2, 3].map(add(1)); // returns [2, 3, 4]
/// New
subtractCurried.uncurry(10, 5);
final addFunction = (int a, int b) => a + b;
final add = addFunction.curry;
[1, 2, 3].map(add(1)); // returns [2, 3, 4]
[1, 2, 3].map(addFunction.curry(1)); // returns [2, 3, 4]Eq static constructors to methods
orandxor method to EqDateTime instances of Eq as Eq static members/// Before
final eq = dateEqYear; // Global
/// Now
final eq = Eq.dateEqYear;Eq instances for num, int, double, String, and bool[1, 2, 3].difference(Eq.eqInt, [2, 3, 4]); /// `[1]`Eq
contramapclass Parent {
final int value1;
final double value2;
const Parent(this.value1, this.value2);
}
/// Equality for values of type [Parent] based on their `value1` ([int]).
final eqParentInt = Eq.eqInt.contramap<Parent>(
(p) => p.value1,
);
/// Equality for of type [Parent] based on their `value2` ([double]).
final eqParentDouble = Eq.eqDouble.contramap<Parent>(
(p) => p.value2,
);reverse in Order from static constructor to getter method/// Before
final reversed = Order.reverse(instance);
/// Now
final reversed = instance.reverse;DateTime instances of Order as Order static membersOrder instances for num, int, doubleOrder
betweenclampcontramapclass Parent {
final int value1;
final double value2;
const Parent(this.value1, this.value2);
}
/// Order values of type [Parent] based on their `value1` ([int]).
final orderParentInt = Order.orderInt.contramap<Parent>(
(p) => p.value1,
);
/// Order values of type [Parent] based on their `value2` ([double]).
final orderParentDouble = Order.orderDouble.contramap<Parent>(
(p) => p.value2,
);bool extension (match and fold), use the ternary operator or pattern matching instead ⚠️final boolValue = Random().nextBool();
/// Before
final result = boolValue.match<int>(() => -1, () => 1);
final result = boolValue.fold<int>(() => -1, () => 1);
/// Now
final result = boolValue ? 1 : -1;
final result = switch (boolValue) { true => 1, false => -1 };id and idFuture, use identity and identityFuture instead ⚠️idFirst and idSecond functions ⚠️Compose class and extension methods ⚠️Magma typedef ⚠️toOption, toEither, toTaskOption, toIOEither, toTaskEither, toTaskEitherAsync) ⚠️extension folderNothing published for this version
Do notation #97 (Special thanks to @tim-smart 🎉)
Do() constructor used to initialize a Do notation chain/// Without the Do notation
String goShopping() => goToShoppingCenter()
.alt(goToLocalMarket)
.flatMap(
(market) => market.buyBanana().flatMap(
(banana) => market.buyApple().flatMap(
(apple) => market.buyPear().flatMap(
(pear) => Option.of('Shopping: $banana, $apple, $pear'),
),
),
),
)
.getOrElse(
() => 'I did not find 🍌 or 🍎 or 🍐, so I did not buy anything 🤷♂️',
);/// Using the Do notation
String goShoppingDo() => Option.Do(
($) {
final market = $(goToShoppingCenter().alt(goToLocalMarket));
final amount = $(market.buyAmount());
final banana = $(market.buyBanana());
final apple = $(market.buyApple());
final pear = $(market.buyPear());
return 'Shopping: $banana, $apple, $pear';
},
).getOrElse(
() => 'I did not find 🍌 or 🍎 or 🍐, so I did not buy anything 🤷♂️',
);IOOption typeIO, IOOption, IOEither, Task, TaskOption, TaskEither)
toTask in IOEither (use toTaskEither instead) ⚠️fpdart's sortBy list extension #101 (thanks to @hbock-42 🎉)pokeapi_functional example to Riverpod v2 #99 (thanks to @utamori 🎉)Nothing published for this version
Updates to Option type #92 [ ⚠️ BREAKING CHANGE ]
Option type #92 [⚠️ BREAKING CHANGE]
const factory constructor for None (fixes #95)Alt and Foldable type classes, the following methods are not available anymore
foldLeftfoldRightfoldMapfoldRightWithIndexfoldLeftWithIndexlengthanyallconcatenateplusprependappendNew methods for Option type (thanks to tim-smart 🎉)
Option type (thanks to tim-smart 🎉)
flatMapNullableflatMapThrowablefinal option = Option.of(10);
option.flatMapNullable((a) => a + 1); /// 👈 `Some(11)`
option.flatMapThrowable((a) => a + 1); /// 👈 `Some(11)`
option.flatMapNullable<int>((a) => null); /// 👈 `None()`
option.flatMapThrowable<int>((a) => throw "fail"); /// 👈 `None()`fromJson for Option type (thanks [again] to tim-smart 🎉)
fromJson constructors)/// `fromJson` on `DateTime` with `Option` type
final now = DateTime.now();
Option<DateTime>.fromJson(now.toIso8601String(), (a) => DateTime.parse(a as String)); /// 👈 `Some(now)`
Option<DateTime>.fromJson("fail", (a) => DateTime.parse(a as String)); /// 👈 `None()`Map (thanks [once again] to tim-smart 🎉)
extractextractMapfinal map = <String, dynamic>{'a': 1, 'b': 2, 'c': 3, 'd': 4};
map.extract<int>('b'); /// 👈 `Some(2)`
map.extract<String>('b'); /// 👈 `None()`, not of type `String` ⚠️
final map = <String, dynamic>{'a': 1};
map.extractMap('a'); /// 👈 `None()`, not a `Map`
final map = <String, dynamic>{'a': {'b': 2} };
map.extractMap('a'); /// 👈 `Some({'b': 2})`Option.of and Option.none factories const (thanks to f-person 🎉)Note: People who have the prefer_const_constructors lint enabled will notice a warning to use
const🤝
managing_imports example (thanks to RandalSchwartz 🎉)Option type (thanks to tim-smart 🎉)
flatMapNullableflatMapThrowablefinal option = Option.of(10);
option.flatMapNullable((a) => a + 1); /// 👈 `Some(11)`
option.flatMapThrowable((a) => a + 1); /// 👈 `Some(11)`
option.flatMapNullable<int>((a) => null); /// 👈 `None()`
option.flatMapThrowable<int>((a) => throw "fail"); /// 👈 `None()`
fromJson for Option type (thanks [again] to tim-smart 🎉)
fromJson constructors)/// `fromJson` on `DateTime` with `Option` type
final now = DateTime.now();
Option<DateTime>.fromJson(now.toIso8601String(), (a) => DateTime.parse(a as String)); /// 👈 `Some(now)`
Option<DateTime>.fromJson("fail", (a) => DateTime.parse(a as String)); /// 👈 `None()`
Map (thanks [once again] to tim-smart 🎉)
extractextractMapfinal map = <String, dynamic>{'a': 1, 'b': 2, 'c': 3, 'd': 4};
map.extract<int>('b'); /// 👈 `Some(2)`
map.extract<String>('b'); /// 👈 `None()`, not of type `String` ⚠️
final map = <String, dynamic>{'a': 1};
map.extractMap('a'); /// 👈 `None()`, not a `Map`
final map = <String, dynamic>{'a': {'b': 2} };
map.extractMap('a'); /// 👈 `Some({'b': 2})`
Option.of and Option.none factories const (thanks to f-person 🎉)Note: People who have the prefer_const_constructors lint enabled will notice a warning to use
const🤝
managing_imports example (thanks to RandalSchwartz 🎉)Removed parameter from Either fromNullable [ ⚠️ BREAKING CHANGE ]
T?)
T? to fpdart's types
toOptiontoEithertoTaskOptiontoIOEithertoTaskEithertoTaskEitherAsyncfromNullable (Either, IOEither, TaskOption TaskEither)fromNullableAsync (TaskEither)fpdart's types to T?
toNullable (Either)/// [Option] <-> `int?`
int? value1 = 10.toOption().map((t) => t + 10).toNullable();
bool? value2 = value1?.isEven;
/// `bool?` -> [Either] -> `int?`
int? value3 = value2
.toEither(() => "Error")
.flatMap((a) => a ? right<String, int>(10) : left<String, int>("None"))
.toNullable();
/// `int?` -> [Option]
Option<int> value4 = (value3?.abs().round()).toOption().flatMap(Option.of);toIOEither to EitherEither fromNullable [⚠️ BREAKING CHANGE]final either = Either<String, int>.fromNullable(value, (r) => 'none');
/// 👆 Removed the value `(r)` (it was always null anyway 💁🏼♂️) 👇
final either = Either<String, int>.fromNullable(value, () => 'none');chainEither to TaskEithersafeCast (Either and Option)safeCastStrict (Either and Option)int intValue = 10;
/// Unhandled exception: type 'int' is not a subtype of type 'List<int>' in type cast
final waitWhat = intValue as List<int>;
final first = waitWhat.first;
/// Safe 🎯
final wellYeah = Either<String, List<int>>.safeCast(
intValue,
(dynamic value) => 'Not a List!',
);
final firstEither = wellYeah.map((list) => list.first);T?)
T? to fpdart's types
toOptiontoEithertoTaskOptiontoIOEithertoTaskEithertoTaskEitherAsyncfromNullable (Either, IOEither, TaskOption TaskEither)fromNullableAsync (TaskEither)fpdart's types to T?
toNullable (Either)/// [Option] <-> `int?`
int? value1 = 10.toOption().map((t) => t + 10).toNullable();
bool? value2 = value1?.isEven;
/// `bool?` -> [Either] -> `int?`
int? value3 = value2
.toEither(() => "Error")
.flatMap((a) => a ? right<String, int>(10) : left<String, int>("None"))
.toNullable();
/// `int?` -> [Option]
Option<int> value4 = (value3?.abs().round()).toOption().flatMap(Option.of);
toIOEither to EitherEither fromNullable [⚠️ BREAKING CHANGE]final either = Either<String, int>.fromNullable(value, (r) => 'none');
/// 👆 Removed the value `(r)` (it was always null anyway 💁🏼♂️) 👇
final either = Either<String, int>.fromNullable(value, () => 'none');
chainEither to TaskEithersafeCast (Either and Option)safeCastStrict (Either and Option)int intValue = 10;
/// Unhandled exception: type 'int' is not a subtype of type 'List<int>' in type cast
final waitWhat = intValue as List<int>;
final first = waitWhat.first;
/// Safe 🎯
final wellYeah = Either<String, List<int>>.safeCast(
intValue,
(dynamic value) => 'Not a List!',
);
final firstEither = wellYeah.map((list) => list.first);
Inverted onSome and onNone functions parameters in match method of Option [ ⚠️ BREAKING CHANGE ] ( Read more on why 👉 #56 )
onSome and onNone functions parameters in match method of Option [⚠️ BREAKING CHANGE] (Read more on why 👉 #56)/// Everywhere you are using `Option.match` you must change this:
final match = option.match(
(a) => print('Some($a)'),
() => print('None'), // <- `None` second 👎
);
/// to this (invert parameters order):
final match = option.match(
() => print('None'), // <- `None` first 👍
(a) => print('Some($a)'),
);traverse and sequence methods (#55)
traverseListtraverseListWithIndexsequenceListtraverseListSeqtraverseListWithIndexSeqsequenceListSeq/// "a40" is invalid 💥
final inputValues = ["10", "20", "30", "a40"];
/// Verify that all the values can be converted to [int] 🔐
///
/// If **any** of them is invalid, then the result is [None] 🙅♂️
final traverseOption = inputValues.traverseOption(
(a) => Option.tryCatch(
/// If `a` does not contain a valid integer literal a [FormatException] is thrown
() => int.parse(a),
),
);bindEither method in TaskEither (#58)/// Chain [Either] to [TaskEither]
TaskEither<String, int> binding =
TaskEither<String, String>.of("String").bindEither(Either.of(20));lefts, rights, and partitionEithers methods to Either (#57)final list = [
right<String, int>(1),
right<String, int>(2),
left<String, int>('a'),
left<String, int>('b'),
right<String, int>(3),
];
final result = Either.partitionEithers(list);
expect(result.first, ['a', 'b']);
expect(result.second, [1, 2, 3]);bimap method to Either, IOEither, and Tuple2 (#57)mapLeft method to IOEither (#57)fold method to Option (same as match) (#56)chainFirst for Either, TaskEither, and IOEither when chaining on a failure (Left) (#47) by DevNico 🎉const to all constructors in which it was missing (#59)2.17.0 ⚠️environment:
sdk: ">=2.17.0 <3.0.0"Updated README and documentation
Testing improvements (internal)
gladosmatch() method by adding fail in unexpected matched branchContribution improvements
onSome and onNone functions parameters in match method of Option [⚠️ BREAKING CHANGE] (Read more on why 👉 #56)/// Everywhere you are using `Option.match` you must change this:
final match = option.match(
(a) => print('Some($a)'),
() => print('None'), // <- `None` second 👎
);
/// to this (invert parameters order):
final match = option.match(
() => print('None'), // <- `None` first 👍
(a) => print('Some($a)'),
);
traverse and sequence methods (#55)
traverseListtraverseListWithIndexsequenceListtraverseListSeqtraverseListWithIndexSeqsequenceListSeq/// "a40" is invalid 💥
final inputValues = ["10", "20", "30", "a40"];
/// Verify that all the values can be converted to [int] 🔐
///
/// If **any** of them is invalid, then the result is [None] 🙅♂️
final traverseOption = inputValues.traverseOption(
(a) => Option.tryCatch(
/// If `a` does not contain a valid integer literal a [FormatException] is thrown
() => int.parse(a),
),
);
bindEither method in TaskEither (#58)/// Chain [Either] to [TaskEither]
TaskEither<String, int> binding =
TaskEither<String, String>.of("String").bindEither(Either.of(20));
lefts, rights, and partitionEithers methods to Either (#57)final list = [
right<String, int>(1),
right<String, int>(2),
left<String, int>('a'),
left<String, int>('b'),
right<String, int>(3),
];
final result = Either.partitionEithers(list);
expect(result.first, ['a', 'b']);
expect(result.second, [1, 2, 3]);
bimap method to Either, IOEither, and Tuple2 (#57)mapLeft method to IOEither (#57)fold method to Option (same as match) (#56)chainFirst for Either, TaskEither, and IOEither when chaining on a failure (Left) (#47) by DevNico 🎉const to all constructors in which it was missing (#59)2.17.0 ⚠️environment:
sdk: ">=2.17.0 <3.0.0"
Updated README and documentation
Testing improvements (internal)
gladosmatch() method by adding fail in unexpected matched branchContribution improvements
Refactoring for mixin breaking change ( #42 ) by TimWhiting 🎉
chainFirst method for the following classes (#39)
TaskEitherEitherIOIOEitherStateStateAsyncReaderAdded idFuture and identityFuture methods ( #38 by f-person 🎉)
idFuture and identityFuture methods (#38) by f-person 🎉mapBoth method to Tuple2 (#30)upsert method for Map (#37) ⚠️2.16.0 ⚠️environment:
sdk: ">=2.16.0 <3.0.0"
Updated package linting to `lints`
lintsNew methods to TaskEither, TaskOption, Either, and Option
TaskEither, TaskOption, Either, and Option
mapLeft (TaskEither)bimap (TaskEither)toTaskEither (Either)toTaskOption (Option)README
Completed IORef type implementation, documentation, and testing
IORef type implementation, documentation, and testing
Fixed major issue in State and StateAsync implementation [BREAKING CHANGE]
State and StateAsync implementation [BREAKING CHANGE]
flatMap, map, map2, map3, ap, andThen, call, and flatten had an implementation issue that has been now fixedReleased introduction to Practical Functional Programming
StateAsync type implementation, documentation, and testingAlt typeclass (#21)call method to more easily chain functions in Monad and Monad2Released two new tutorials on the Option type:
Option type:
toJson and fromJson methods to Option to use json_serializable to convert Option type to and from Json (using @JsonSerializable)MapPredicate type (and &, or |, not ~, xor ^) (#18)Released Part 3 of Fpdart, Functional Programming in Dart and Flutter
pokeapi_functional)flatMapTask and toTask methods to IO to lift and chain IO with TaskflatMapTask and toTask methods to IOEither to lift and chain IOEither with TaskEitherbool (boolean.dart)int, double, and bool in a functional way (using IO) (random.dart)Ord, and Eq instances to DateTime (date.dart)Released Part 2 of Fpdart, Functional Programming in Dart and Flutter
Compose and Compose2, used to easily compose functions in a chaincurry and uncurry extensions on functions up to 5 parametersTaskOption type implementation, documentation, and testingTaskEither.tryCatchK and Either.tryCatchK, by tim-smart (#10, #11) 🎉Released Part 1 of Fpdart, Functional Programming in Dart and Flutter
Iterable (List)IOEither type implementation, documentation, and testingconstF functionoption and optionOf (same as dartz)Either.right(r) factory constructor to Either class (same as Either.of(r)) (#3)TaskEither (read_write_file)Completed State type implementation, documentation, and testing
State type implementation, documentation, and testingReader type implementation, documentation, and testingIO type implementation, documentation, and testingright and left functions to create instance of Eitherid function (same as identity)fold method to Either (same as match)bind method to Either (same as flatMap)bindFuture method to Either, which returns TaskEitherCompleted implementation, documentation, and testing of Foldable instance on Option and Either [BREAKING CHANGE]
Unit type documentationTask type implementation, documentation, and testingTaskEither type implementation, documentation, and testingFoldable instance on Option and Either [BREAKING CHANGE]Tuple2 type implementation, documentation, and testing [BREAKING CHANGE]fold method of Foldable to foldLeft [BREAKING CHANGE]foldRight, foldLeft, etc.) of Foldable instances (Option, Either, Tuple) [BREAKING CHANGE]IList not longer working correctly (waiting for a better solution for immutable collections) [BREAKING CHANGE]Changed name of type Maybe to Option to be inline with fp-ts, cats, and dartz [BREAKING CHANGE]
Maybe to Option to be inline with fp-ts, cats, and dartz [BREAKING CHANGE]First major release: ### Types - Either - IList - Maybe - Reader - State - Task - TaskEither - Tuple - Unit ### Typeclasses - Alt - Applicative - Band
First major release:
EitherIListMaybeReaderStateTaskTaskEitherTupleUnitAltApplicativeBandBoundedSemilatticeCommutativeGroupCommutativeMonoidCommutativeSemigroupEqExtendFilterableFoldableFunctorGroupHashHKTMonadMonoidOrderPartialOrderSemigroupSemilatticeEithercurryMaybeReaderStateNothing published for this version
- Eq - Hash - PartialOrder
EqHashPartialOrderYour coding agent can read these notes before it upgrades. Set up the MCP server →