fpdart
Functional programming in Dart and Flutter. All the main functional programming types and patterns fully documented, tested, and with examples.
1.2.0
265K downloads/mo
#739 most downloaded on pub.dev
SandroMaglione/fpdart
What this package is like to depend on
Last release 9 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
1 release in the last 12 months
see the full history below
Release timeline
31 releases · May 2021 to Oct 2025Releases
latest 31-
2.0.0-dev.303 Apr 2024 pre-releaseNothing published for this version
-
2.0.0-dev.228 Mar 2024 pre-releaseNothing published for this version
-
2.0.0-dev.123 Mar 2024 pre-releaseNothing published for this version
-
1.2.029 Oct 2025Release notes
Open source →- Added
toTaskOptionFlat,toTaskEitherFlat,fromTaskFlattentoTaskOptionandTaskEither - Added new iterable extension functions
singleOption,elementAtOption,singleWhereOption,lastWhereOption - Minor internal improvements
- Status update for fpdart v2 (full discussion here)
- Added
-
1.1.107 Nov 2024 -
1.1.013 Aug 2023Release notes
Open source →-
Improved performance of some iterable based functions in
IterableandMapextension (thanks to @lrhn 🎉) -
Added
lookupEqanddropRightonIterableextension
[].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]
- Added
lookupKeyEqonMapextension
<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()
Release notes
Open source →-
Improved performance of some iterable based functions in
IterableandMapextension (thanks to lrhn 🎉) -
Added
lookupEqanddropRightonIterableextension
[].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]- Added
lookupKeyEqonMapextension
<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() -
-
1.0.026 Jul 2023Release notes
Open source →- Minimum environment dart sdk to
3.0.0⚠️ (Dart 3️⃣)
environment: sdk: ">=3.0.0 <4.0.0"
- Added new
ReaderTaskEithertypeReaderTaskEithermodels a complete program usingReaderfor dependency injection,Taskto perform asynchronous computation, andEitherto handle errors 🎯
- Added new
ReaderTasktype Eitherassealedclass (Dart 3️⃣)- You can now use exhaustive pattern matching (
LeftorRight)
- You can now use exhaustive pattern matching (
/// 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)', };
Optionassealedclass (Dart 3️⃣)- You can now use exhaustive pattern matching (
NoneorSome)
- You can now use exhaustive pattern matching (
/// 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)', };
- Types marked as
final(noextendsnorimplements) (Dart 3️⃣)UnitReaderStateStateAsyncIOIORefIOOptionIOEitherTaskTaskOptionTaskEitherReaderTaskReaderTaskEither
- Removed
Tuple2, use Dart 3 Records instead (Tuple2(a, b)becomes simply(a, b)🎯) ⚠️ (Dart 3️⃣)- Updated all internal APIs to use records instead of
Tuple2
- Updated all internal APIs to use records instead of
- Major refactoring of
IterableandListextension methods- Improved performance
- Correct return types (
IterableandList) (#65) - Added the following methods
prependAll(Iterable)intersperse(Iterable)difference(Iterable)filterWithIndex(Iterable)
- Fixed the following methods ⚠️
takeWhileRight: ResultingListnow in reversed order as expecteddropWhileRight: ResultingListnow in reversed order as expected
- Updated the following methods ⚠️
foldRight,foldRightWithIndex(List): Changed parameter order incombinefunctionzipWith(Iterable): Changed parameters definition, no more curried
- Renamed the following methods ⚠️
plus→concat(Iterable)concat→flatten(onIterable<Iterable<T>>)
- Removed the following methods ⚠️
concatMap(useflatMapinstead)bind(useflatMapinstead)bindWithIndex(useflatMapWithIndexinstead)concatMapWithIndex(useflatMapWithIndexinstead)
- Refactoring of
Mapextension methods- Improved performance
- Added the following methods
lookupEqlookupWithKeyEq
- Removed the following methods ⚠️
member(usecontainsKeyinstead)elem(usecontainsValueinstead)toIterable(usetoSortedListinstead)
- Updated the following methods ⚠️
toIterablerenamed totoSortedList(return aListinstead ofIterable)modifyAtchanged parameter order and no more curriedmodifyAtIfPresentchanged parameter order and no more curriedupdateAtno more curriedupdateAtIfPresentno more currieddeleteAtno more curriedupsertAtno more curriedpopno more curriedfoldLeftno more curriedfoldLeftWithKeyno more curriedfoldLeftWithIndexno more curriedfoldLeftWithKeyAndIndexno more curriedfoldRightno more curriedfoldRightWithKeyno more curriedfoldRightWithIndexno more curriedfoldRightWithKeyAndIndexno more curriedunionno more curriedintersectionno more curriedisSubmapno more curriedcollectno more currieddifferenceno more curried
- Added conversions helpers from
Stringtonum,int,double, andboolusingOptionandEither(both as extension methods onStringand 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")`
- Changed
dateNow,now,random, andrandomBoolto 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();
- Removed
Predicateclass 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);
- Updated curry / uncarry extensions ⚠️
- Renamed
currytocurryAllfor functions with 3, 4, 5 parameters - Changed definition of
curryto curry only the first parameter - Changed
uncurryandcurryextension to getter function - Removed
curryanduncurryas functions (use extension method instead) - Added
curryLast(curry last parameter)
- Renamed
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]
- Changed
Eqstatic constructors to methodsorand
- Added
xormethod toEq - Moved
DateTimeinstances ofEqasEqstatic members
/// Before final eq = dateEqYear; // Global /// Now final eq = Eq.dateEqYear;
- Added
Eqinstances fornum,int,double,String, andbool
[1, 2, 3].difference(Eq.eqInt, [2, 3, 4]); /// `[1]`
- Added new method to
Eqcontramap
class 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, );
- Changed
reverseinOrderfrom static constructor to getter method
/// Before final reversed = Order.reverse(instance); /// Now final reversed = instance.reverse;
- Moved
DateTimeinstances ofOrderasOrderstatic members - Added
Orderinstances fornum,int,double - Added new methods to
Orderbetweenclampcontramap
class 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, );
- Removed
boolextension (matchandfold), 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 };
- Removed global
idandidFuture, useidentityandidentityFutureinstead ⚠️ - Removed global
idFirstandidSecondfunctions ⚠️ - Removed
Composeclass and extension methods ⚠️ - Removed
Magmatypedef ⚠️ - Removed extension methods on nullable types (
toOption,toEither,toTaskOption,toIOEither,toTaskEither,toTaskEitherAsync) ⚠️ - Organized all extensions inside internal
extensionfolder - Updated README
Release notes
Open source →- Minimum environment dart sdk to
3.0.0⚠️ (Dart 3️⃣)
environment: sdk: ">=3.0.0 <4.0.0"- Added new
ReaderTaskEithertypeReaderTaskEithermodels a complete program usingReaderfor dependency injection,Taskto perform asynchronous computation, andEitherto handle errors 🎯
- Added new
ReaderTasktype Eitherassealedclass (Dart 3️⃣)- You can now use exhaustive pattern matching (
LeftorRight)
- You can now use exhaustive pattern matching (
/// 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)', };Optionassealedclass (Dart 3️⃣)- You can now use exhaustive pattern matching (
NoneorSome)
- You can now use exhaustive pattern matching (
/// 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)', };- Types marked as
final(noextendsnorimplements) (Dart 3️⃣)UnitReaderStateStateAsyncIOIORefIOOptionIOEitherTaskTaskOptionTaskEitherReaderTaskReaderTaskEither
- Removed
Tuple2, use Dart 3 Records instead (Tuple2(a, b)becomes simply(a, b)🎯) ⚠️ (Dart 3️⃣)- Updated all internal APIs to use records instead of
Tuple2
- Updated all internal APIs to use records instead of
- Major refactoring of
IterableandListextension methods- Improved performance
- Correct return types (
IterableandList) (#65) - Added the following methods
prependAll(Iterable)intersperse(Iterable)difference(Iterable)filterWithIndex(Iterable)
- Fixed the following methods ⚠️
takeWhileRight: ResultingListnow in reversed order as expecteddropWhileRight: ResultingListnow in reversed order as expected
- Updated the following methods ⚠️
foldRight,foldRightWithIndex(List): Changed parameter order incombinefunctionzipWith(Iterable): Changed parameters definition, no more curried
- Renamed the following methods ⚠️
plus→concat(Iterable)concat→flatten(onIterable<Iterable<T>>)
- Removed the following methods ⚠️
concatMap(useflatMapinstead)bind(useflatMapinstead)bindWithIndex(useflatMapWithIndexinstead)concatMapWithIndex(useflatMapWithIndexinstead)
- Refactoring of
Mapextension methods- Improved performance
- Added the following methods
lookupEqlookupWithKeyEq
- Removed the following methods ⚠️
member(usecontainsKeyinstead)elem(usecontainsValueinstead)toIterable(usetoSortedListinstead)
- Updated the following methods ⚠️
toIterablerenamed totoSortedList(return aListinstead ofIterable)modifyAtchanged parameter order and no more curriedmodifyAtIfPresentchanged parameter order and no more curriedupdateAtno more curriedupdateAtIfPresentno more currieddeleteAtno more curriedupsertAtno more curriedpopno more curriedfoldLeftno more curriedfoldLeftWithKeyno more curriedfoldLeftWithIndexno more curriedfoldLeftWithKeyAndIndexno more curriedfoldRightno more curriedfoldRightWithKeyno more curriedfoldRightWithIndexno more curriedfoldRightWithKeyAndIndexno more curriedunionno more curriedintersectionno more curriedisSubmapno more curriedcollectno more currieddifferenceno more curried
- Added conversions helpers from
Stringtonum,int,double, andboolusingOptionandEither(both as extension methods onStringand 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")`- Changed
dateNow,now,random, andrandomBoolto 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();- Removed
Predicateclass 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);- Updated curry / uncarry extensions ⚠️
- Renamed
currytocurryAllfor functions with 3, 4, 5 parameters - Changed definition of
curryto curry only the first parameter - Changed
uncurryandcurryextension to getter function - Removed
curryanduncurryas functions (use extension method instead) - Added
curryLast(curry last parameter)
- Renamed
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]- Changed
Eqstatic constructors to methodsorand
- Added
xormethod toEq - Moved
DateTimeinstances ofEqasEqstatic members
/// Before final eq = dateEqYear; // Global /// Now final eq = Eq.dateEqYear;- Added
Eqinstances fornum,int,double,String, andbool
[1, 2, 3].difference(Eq.eqInt, [2, 3, 4]); /// `[1]`- Added new method to
Eqcontramap
class 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, );- Changed
reverseinOrderfrom static constructor to getter method
/// Before final reversed = Order.reverse(instance); /// Now final reversed = instance.reverse;- Moved
DateTimeinstances ofOrderasOrderstatic members - Added
Orderinstances fornum,int,double - Added new methods to
Orderbetweenclampcontramap
class 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, );- Removed
boolextension (matchandfold), 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 };- Removed global
idandidFuture, useidentityandidentityFutureinstead ⚠️ - Removed global
idFirstandidSecondfunctions ⚠️ - Removed
Composeclass and extension methods ⚠️ - Removed
Magmatypedef ⚠️ - Removed extension methods on nullable types (
toOption,toEither,toTaskOption,toIOEither,toTaskEither,toTaskEitherAsync) ⚠️ - Organized all extensions inside internal
extensionfolder - Updated README
- Minimum environment dart sdk to
-
1.0.0-beta.127 May 2023 pre-releaseNothing published for this version
-
0.6.006 May 2023Release notes
Open source →- Do notation #97 (Special thanks to @tim-smart 🎉)
- All the main types now have a
Do()constructor used to initialize a Do notation chain - Updated examples to use Do notation (new recommended API 🎯)
- All the main types now have a
/// 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 🤷♂️', );
- Added new
IOOptiontype - Added conversion methods from and to all classes (
IO,IOOption,IOEither,Task,TaskOption,TaskEither)- Removed
toTaskinIOEither(usetoTaskEitherinstead) ⚠️
- Removed
- Improved performance of
fpdart'ssortBylist extension #101 (thanks to @hbock-42 🎉) - Updated
pokeapi_functionalexample to Riverpod v2 #99 (thanks to @utamori 🎉) - Updated repository folder structure #105
Release notes
Open source →- Do notation #97 (Special thanks to @tim-smart 🎉)
- All the main types now have a
Do()constructor used to initialize a Do notation chain - Updated examples to use Do notation (new recommended API 🎯)
- All the main types now have a
/// 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 🤷♂️', );- Added new
IOOptiontype - Added conversion methods from and to all classes (
IO,IOOption,IOEither,Task,TaskOption,TaskEither)- Removed
toTaskinIOEither(usetoTaskEitherinstead) ⚠️
- Removed
- Improved performance of
fpdart'ssortBylist extension #101 (thanks to @hbock-42 🎉) - Updated
pokeapi_functionalexample to Riverpod v2 #99 (thanks to @utamori 🎉) - Updated repository folder structure #105
- Do notation #97 (Special thanks to @tim-smart 🎉)
-
0.6.0-dev.108 Mar 2023 pre-releaseNothing published for this version
-
0.5.004 Mar 2023Release notes
Open source →- Updates to
Optiontype #92 [⚠️ BREAKING CHANGE]- Added
const factoryconstructor forNone(fixes #95) - Removed
AltandFoldabletype classes, the following methods are not available anymorefoldLeftfoldRightfoldMapfoldRightWithIndexfoldLeftWithIndexlengthanyallconcatenateplusprependappend
- Added
- Updated examples and fixed lint warnings #93 (thanks to tim-smart 🎉)
Release notes
Open source →- Updates to
Optiontype #92 [⚠️ BREAKING CHANGE]- Added
const factoryconstructor forNone(fixes #95) - Removed
AltandFoldabletype classes, the following methods are not available anymorefoldLeftfoldRightfoldMapfoldRightWithIndexfoldLeftWithIndexlengthanyallconcatenateplusprependappend
- Added
- Updated examples and fixed lint warnings #93 (thanks to tim-smart 🎉)
- Updates to
-
0.4.125 Feb 2023Release notes
Open source →- New methods for
Optiontype (thanks to tim-smart 🎉)flatMapNullableflatMapThrowable
final 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()`
- Improved support
fromJsonforOptiontype (thanks [again] to tim-smart 🎉)- Allow for decoding of non-primitive types (with custom
fromJsonconstructors)
- Allow for decoding of non-primitive types (with custom
/// `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()`
- New extension methods for
Map(thanks [once again] to tim-smart 🎉)extractextractMap
final 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.ofandOption.nonefactoriesconst(thanks to f-person 🎉)
Note: People who have the prefer_const_constructors lint enabled will notice a warning to use
const🤝- New
managing_importsexample (thanks to RandalSchwartz 🎉) - Updated README introduction
Release notes
Open source →- New methods for
Optiontype (thanks to tim-smart 🎉)flatMapNullableflatMapThrowable
final 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()`- Improved support
fromJsonforOptiontype (thanks [again] to tim-smart 🎉)- Allow for decoding of non-primitive types (with custom
fromJsonconstructors)
- Allow for decoding of non-primitive types (with custom
/// `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()`- New extension methods for
Map(thanks [once again] to tim-smart 🎉)extractextractMap
final 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.ofandOption.nonefactoriesconst(thanks to f-person 🎉)
Note: People who have the prefer_const_constructors lint enabled will notice a warning to use
const🤝- New
managing_importsexample (thanks to RandalSchwartz 🎉) - Updated README introduction
- New methods for
-
0.4.016 Dec 2022Release notes
Open source →- Added extension methods to work with nullable types (
T?)- From
T?tofpdart's typestoOptiontoEithertoTaskOptiontoIOEithertoTaskEithertoTaskEitherAsyncfromNullable(Either,IOEither,TaskOptionTaskEither)fromNullableAsync(TaskEither)
- From
fpdart's types toT?toNullable(Either)
- From
/// [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);
- Added
toIOEithertoEither - Removed parameter from
EitherfromNullable[⚠️ 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');
- Added
chainEithertoTaskEither - Added
safeCast(EitherandOption) - Added
safeCastStrict(EitherandOption)
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);
- Added Open API Meteo example (from imperative to functional programming)
- Added new articles
- Option type and Null Safety in dart
- Either - Error Handling in Functional Programming
- Future & Task: asynchronous Functional Programming
- Flutter Supabase Functional Programming with fpdart
- Open Meteo API - Functional programming with fpdart (Part 1)
- Open Meteo API - Functional programming with fpdart (Part 2)
Release notes
Open source →- Added extension methods to work with nullable types (
T?)- From
T?tofpdart's typestoOptiontoEithertoTaskOptiontoIOEithertoTaskEithertoTaskEitherAsyncfromNullable(Either,IOEither,TaskOptionTaskEither)fromNullableAsync(TaskEither)
- From
fpdart's types toT?toNullable(Either)
- From
/// [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);- Added
toIOEithertoEither - Removed parameter from
EitherfromNullable[⚠️ 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');- Added
chainEithertoTaskEither - Added
safeCast(EitherandOption) - Added
safeCastStrict(EitherandOption)
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);- Added Open API Meteo example (from imperative to functional programming)
- Added new articles
- Option type and Null Safety in dart
- Either - Error Handling in Functional Programming
- Future & Task: asynchronous Functional Programming
- Flutter Supabase Functional Programming with fpdart
- Open Meteo API - Functional programming with fpdart (Part 1)
- Open Meteo API - Functional programming with fpdart (Part 2)
- Added extension methods to work with nullable types (
-
0.3.011 Oct 2022Release notes
Open source →- Inverted
onSomeandonNonefunctions parameters inmatchmethod ofOption[⚠️ 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)'), );
- Added
traverseandsequencemethods (#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), ), );
- Added
bindEithermethod inTaskEither(#58)
/// Chain [Either] to [TaskEither] TaskEither<String, int> binding = TaskEither<String, String>.of("String").bindEither(Either.of(20));
- Added
lefts,rights, andpartitionEithersmethods toEither(#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]);
- Added
bimapmethod toEither,IOEither, andTuple2(#57) - Added
mapLeftmethod toIOEither(#57) - Added
foldmethod toOption(same asmatch) (#56) - Fixed
chainFirstforEither,TaskEither, andIOEitherwhen chaining on a failure (Left) (#47) by DevNico 🎉 - Added
constto all constructors in which it was missing (#59) - Minimum environment dart sdk to
2.17.0⚠️
environment: sdk: ">=2.17.0 <3.0.0"
-
Updated README and documentation
-
Testing improvements (internal)
- Added testing utils
- Added Property-based testing using
glados - Fixed tests for
match()method by addingfailin unexpected matched branch
-
Contribution improvements
- Added testing workflow with Github actions (#54)
Release notes
Open source →- Inverted
onSomeandonNonefunctions parameters inmatchmethod ofOption[⚠️ 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)'), );- Added
traverseandsequencemethods (#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), ), );- Added
bindEithermethod inTaskEither(#58)
/// Chain [Either] to [TaskEither] TaskEither<String, int> binding = TaskEither<String, String>.of("String").bindEither(Either.of(20));- Added
lefts,rights, andpartitionEithersmethods toEither(#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]);- Added
bimapmethod toEither,IOEither, andTuple2(#57) - Added
mapLeftmethod toIOEither(#57) - Added
foldmethod toOption(same asmatch) (#56) - Fixed
chainFirstforEither,TaskEither, andIOEitherwhen chaining on a failure (Left) (#47) by DevNico 🎉 - Added
constto all constructors in which it was missing (#59) - Minimum environment dart sdk to
2.17.0⚠️
environment: sdk: ">=2.17.0 <3.0.0"-
Updated README and documentation
-
Testing improvements (internal)
- Added testing utils
- Added Property-based testing using
glados - Fixed tests for
match()method by addingfailin unexpected matched branch
-
Contribution improvements
- Added testing workflow with Github actions (#54)
- Inverted
-
0.2.016 Jul 2022Release notes
Open source →- Refactoring for mixin breaking change (#42) by TimWhiting 🎉
- Added
chainFirstmethod for the following classes (#39)TaskEitherEitherIOIOEitherStateStateAsyncReader
Release notes
Open source →- Refactoring for mixin breaking change (#42) by TimWhiting 🎉
- Added
chainFirstmethod for the following classes (#39)TaskEitherEitherIOIOEitherStateStateAsyncReader
-
0.1.017 Jun 2022Release notes
Open source →- Added
idFutureandidentityFuturemethods (#38 by f-person 🎉) - Added
mapBothmethod toTuple2(#30) - Fixed linting warnings
- Fixed issue with
upsertmethod forMap(#37) ⚠️ - Minimum environment dart sdk to
2.16.0⚠️
environment: sdk: ">=2.16.0 <3.0.0"
Release notes
Open source →- Added
idFutureandidentityFuturemethods (#38) by f-person 🎉 - Added
mapBothmethod toTuple2(#30) - Fixed linting warnings
- Fixed issue with
upsertmethod forMap(#37) ⚠️ - Minimum environment dart sdk to
2.16.0⚠️
environment: sdk: ">=2.16.0 <3.0.0" - Added
-
0.0.1431 Jan 2022 -
0.0.1326 Jan 2022Release notes
Open source →- New methods to
TaskEither,TaskOption,Either, andOptionmapLeft(TaskEither)bimap(TaskEither)toTaskEither(Either)toTaskOption(Option)
- New Blog posts and tutorials section in
README- New blog post How to map an Either to a Future in fpdart
- New methods to
-
0.0.1224 Oct 2021Release notes
Open source →- Completed
IOReftype implementation, documentation, and testing- Merged PR (#25) by purplenoodlesoop 🎉
- Completed
-
0.0.1122 Sep 2021Release notes
Open source →- Fixed major issue in
StateandStateAsyncimplementation [BREAKING CHANGE]- Methods
flatMap,map,map2,map3,ap,andThen,call, andflattenhad an implementation issue that has been now fixed
- Methods
- Fixed major issue in
-
0.0.1013 Aug 2021Release notes
Open source →- Released introduction to Practical Functional Programming
- Completed
StateAsynctype implementation, documentation, and testing - Fixed problem with
Alttypeclass (#21) - Added
callmethod to more easily chain functions inMonadandMonad2
-
0.0.903 Aug 2021Release notes
Open source →- Released two new tutorials on the
Optiontype: - Added
toJsonandfromJsonmethods toOptionto usejson_serializableto convertOptiontype to and from Json (using@JsonSerializable) - Added functional extension methods on
Map - Added composable
Predicatetype (and&, or|, not~, xor^) (#18)
- Released two new tutorials on the
-
0.0.813 Jul 2021Release notes
Open source →- Released Part 3 of Fpdart, Functional Programming in Dart and Flutter
- Added Pure Functional Flutter app example (
pokeapi_functional) - Added
flatMapTaskandtoTaskmethods toIOto lift and chainIOwithTask - Added
flatMapTaskandtoTaskmethods toIOEitherto lift and chainIOEitherwithTaskEither - Added pattern matching extension methods to
bool(boolean.dart) - Added functions to get random
int,double, andboolin a functional way (usingIO) (random.dart) - Added functions, extension methods,
Ord, andEqinstances toDateTime(date.dart)
-
0.0.706 Jul 2021Release notes
Open source →- Released Part 2 of Fpdart, Functional Programming in Dart and Flutter
- Added
ComposeandCompose2, used to easily compose functions in a chain - Added
curryanduncurryextensions on functions up to 5 parameters - Completed
TaskOptiontype implementation, documentation, and testing - Expanded documentation and examples
- Added
TaskEither.tryCatchKandEither.tryCatchK, by tim-smart (#10, #11) 🎉
-
0.0.629 Jun 2021Release notes
Open source →- Released Part 1 of Fpdart, Functional Programming in Dart and Flutter
- Added functional extension methods on
Iterable(List) - Completed
IOEithertype implementation, documentation, and testing - Added
constFfunction - Added
optionandoptionOf(same as dartz) - Added
Either.right(r)factory constructor toEitherclass (same asEither.of(r)) (#3) - Added example on reading local file using
TaskEither(read_write_file) - Added more examples
- Added constant constructors to Eq and variants, by mateusfccp (#4) 🎉
-
0.0.520 Jun 2021Release notes
Open source →- Completed
Statetype implementation, documentation, and testing - Completed
Readertype implementation, documentation, and testing - Completed
IOtype implementation, documentation, and testing - Merged PR (#2) by jacobaraujo7 🎉
- Added
rightandleftfunctions to create instance ofEither - Added
idfunction (same asidentity) - Added
foldmethod toEither(same asmatch) - Added
bindmethod toEither(same asflatMap) - Added
bindFuturemethod toEither, which returnsTaskEither
- Added
- Completed
-
0.0.415 Jun 2021Release notes
Open source →- Completed
Unittype documentation - Completed
Tasktype implementation, documentation, and testing - Completed
TaskEithertype implementation, documentation, and testing - Completed implementation, documentation, and testing of
Foldableinstance onOptionandEither[BREAKING CHANGE] - Completed
Tuple2type implementation, documentation, and testing [BREAKING CHANGE] - Renamed
foldmethod ofFoldabletofoldLeft[BREAKING CHANGE] - Updated methods API (
foldRight,foldLeft, etc.) ofFoldableinstances (Option,Either,Tuple) [BREAKING CHANGE] IListnot longer working correctly (waiting for a better solution for immutable collections) [BREAKING CHANGE]
- Completed
-
0.0.313 Jun 2021Release notes
Open source →- Changed name of type
MaybetoOptionto be inline with fp-ts, cats, and dartz [BREAKING CHANGE]
- Changed name of type
-
0.0.213 Jun 2021Release notes
Open source →First major release:
Types
EitherIListMaybeReaderStateTaskTaskEitherTupleUnit
Typeclasses
AltApplicativeBandBoundedSemilatticeCommutativeGroupCommutativeMonoidCommutativeSemigroupEqExtendFilterableFoldableFunctorGroupHashHKTMonadMonoidOrderPartialOrderSemigroupSemilattice
Examples
EithercurryMaybeReaderState
-
0.0.2+113 Jun 2021Nothing published for this version
-
0.0.128 May 2021