fpdart 1.1.1 fpdart: ^1.1.1 copied to clipboard
Functional programming in Dart and Flutter. All the main functional programming types and patterns fully documented, tested, and with examples.
v1.1.1 - 7 November 2024 #
- Fixed broken documentation links
v1.1.0 - 13 August 2023 #
-
Improved performance of some iterable based functions in
Iterable
andMap
extension (thanks to lrhn 🎉) -
Added
lookupEq
anddropRight
onIterable
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]
- Added
lookupKeyEq
onMap
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()
v1.0.0 - 27 May 2023 #
- Minimum environment dart sdk to
3.0.0
⚠️ (Dart 3️⃣)
environment:
sdk: ">=3.0.0 <4.0.0"
- Added new
ReaderTaskEither
typeReaderTaskEither
models a complete program usingReader
for dependency injection,Task
to perform asynchronous computation, andEither
to handle errors 🎯
- Added new
ReaderTask
type Either
assealed
class (Dart 3️⃣)- You can now use exhaustive pattern matching (
Left
orRight
)
- 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)',
};
Option
assealed
class (Dart 3️⃣)- You can now use exhaustive pattern matching (
None
orSome
)
- 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
(noextends
norimplements
) (Dart 3️⃣)Unit
Reader
State
StateAsync
IO
IORef
IOOption
IOEither
Task
TaskOption
TaskEither
ReaderTask
ReaderTaskEither
- 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
Iterable
andList
extension methods- Improved performance
- Correct return types (
Iterable
andList
) (#65) - Added the following methods
prependAll
(Iterable
)intersperse
(Iterable
)difference
(Iterable
)filterWithIndex
(Iterable
)
- Fixed the following methods ⚠️
takeWhileRight
: ResultingList
now in reversed order as expecteddropWhileRight
: ResultingList
now in reversed order as expected
- Updated the following methods ⚠️
foldRight
,foldRightWithIndex
(List
): Changed parameter order incombine
functionzipWith
(Iterable
): Changed parameters definition, no more curried
- Renamed the following methods ⚠️
plus
→concat
(Iterable
)concat
→flatten
(onIterable<Iterable<T>>
)
- Removed the following methods ⚠️
concatMap
(useflatMap
instead)bind
(useflatMap
instead)bindWithIndex
(useflatMapWithIndex
instead)concatMapWithIndex
(useflatMapWithIndex
instead)
- Refactoring of
Map
extension methods- Improved performance
- Added the following methods
lookupEq
lookupWithKeyEq
- Removed the following methods ⚠️
member
(usecontainsKey
instead)elem
(usecontainsValue
instead)toIterable
(usetoSortedList
instead)
- Updated the following methods ⚠️
toIterable
renamed totoSortedList
(return aList
instead ofIterable
)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 curried
- Added conversions helpers from
String
tonum
,int
,double
, andbool
usingOption
andEither
(both as extension methods onString
and as functions) (#80)toNumOption
toIntOption
toDoubleOption
toBoolOption
toNumEither
toIntEither
toDoubleEither
toBoolEither
/// 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
, andrandomBool
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();
- Removed
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);
- Updated curry / uncarry extensions ⚠️
- Renamed
curry
tocurryAll
for functions with 3, 4, 5 parameters - Changed definition of
curry
to curry only the first parameter - Changed
uncurry
andcurry
extension to getter function - Removed
curry
anduncurry
as 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
Eq
static constructors to methodsor
and
- Added
xor
method toEq
- Moved
DateTime
instances ofEq
asEq
static members
/// Before
final eq = dateEqYear; // Global
/// Now
final eq = Eq.dateEqYear;
- Added
Eq
instances fornum
,int
,double
,String
, andbool
[1, 2, 3].difference(Eq.eqInt, [2, 3, 4]); /// `[1]`
- Added new method to
Eq
contramap
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
reverse
inOrder
from static constructor to getter method
/// Before
final reversed = Order.reverse(instance);
/// Now
final reversed = instance.reverse;
- Moved
DateTime
instances ofOrder
asOrder
static members - Added
Order
instances fornum
,int
,double
- Added new methods to
Order
between
clamp
contramap
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
bool
extension (match
andfold
), 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
id
andidFuture
, useidentity
andidentityFuture
instead ⚠️ - Removed global
idFirst
andidSecond
functions ⚠️ - Removed
Compose
class and extension methods ⚠️ - Removed
Magma
typedef ⚠️ - Removed extension methods on nullable types (
toOption
,toEither
,toTaskOption
,toIOEither
,toTaskEither
,toTaskEitherAsync
) ⚠️ - Organized all extensions inside internal
extension
folder - Updated README
v0.6.0 - 6 May 2023 #
- 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
IOOption
type - Added conversion methods from and to all classes (
IO
,IOOption
,IOEither
,Task
,TaskOption
,TaskEither
)- Removed
toTask
inIOEither
(usetoTaskEither
instead) ⚠️
- Removed
- Improved performance of
fpdart
'ssortBy
list extension #101 (thanks to @hbock-42 🎉) - Updated
pokeapi_functional
example to Riverpod v2 #99 (thanks to @utamori 🎉) - Updated repository folder structure #105
v0.5.0 - 4 March 2023 #
- Updates to
Option
type #92 [⚠️ BREAKING CHANGE]- Added
const factory
constructor forNone
(fixes #95) - Removed
Alt
andFoldable
type classes, the following methods are not available anymorefoldLeft
foldRight
foldMap
foldRightWithIndex
foldLeftWithIndex
length
any
all
concatenate
plus
prepend
append
- Added
- Updated examples and fixed lint warnings #93 (thanks to tim-smart 🎉)
v0.4.1 - 25 February 2023 #
- New methods for
Option
type (thanks to tim-smart 🎉)flatMapNullable
flatMapThrowable
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
fromJson
forOption
type (thanks [again] to tim-smart 🎉)- Allow for decoding of non-primitive types (with custom
fromJson
constructors)
- 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 🎉)extract
extractMap
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.of
andOption.none
factoriesconst
(thanks to f-person 🎉)
Note: People who have the prefer_const_constructors lint enabled will notice a warning to use
const
🤝
- New
managing_imports
example (thanks to RandalSchwartz 🎉) - Updated README introduction
v0.4.0 - 16 December 2022 #
- Added extension methods to work with nullable types (
T?
)- From
T?
tofpdart
's typestoOption
toEither
toTaskOption
toIOEither
toTaskEither
toTaskEitherAsync
fromNullable
(Either
,IOEither
,TaskOption
TaskEither
)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
toIOEither
toEither
- Removed parameter from
Either
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');
- Added
chainEither
toTaskEither
- Added
safeCast
(Either
andOption
) - Added
safeCastStrict
(Either
andOption
)
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)
v0.3.0 - 11 October 2022 #
- Inverted
onSome
andonNone
functions parameters inmatch
method 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
traverse
andsequence
methods (#55)traverseList
traverseListWithIndex
sequenceList
traverseListSeq
traverseListWithIndexSeq
sequenceListSeq
/// "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
bindEither
method inTaskEither
(#58)
/// Chain [Either] to [TaskEither]
TaskEither<String, int> binding =
TaskEither<String, String>.of("String").bindEither(Either.of(20));
- Added
lefts
,rights
, andpartitionEithers
methods 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
bimap
method toEither
,IOEither
, andTuple2
(#57) - Added
mapLeft
method toIOEither
(#57) - Added
fold
method toOption
(same asmatch
) (#56) - Fixed
chainFirst
forEither
,TaskEither
, andIOEither
when chaining on a failure (Left
) (#47) by DevNico 🎉 - Added
const
to 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 addingfail
in unexpected matched branch
-
Contribution improvements
- Added testing workflow with Github actions (#54)
v0.2.0 - 16 July 2022 #
- Refactoring for mixin breaking change (#42) by TimWhiting 🎉
- Added
chainFirst
method for the following classes (#39)TaskEither
Either
IO
IOEither
State
StateAsync
Reader
v0.1.0 - 17 June 2022 #
v0.0.13 - 26 January 2022 #
- New methods to
TaskEither
,TaskOption
,Either
, andOption
mapLeft
(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
v0.0.12 - 24 October 2021 #
- Completed
IORef
type implementation, documentation, and testing- Merged PR (#25) by purplenoodlesoop 🎉
v0.0.11 - 22 September 2021 #
- Fixed major issue in
State
andStateAsync
implementation [BREAKING CHANGE]- Methods
flatMap
,map
,map2
,map3
,ap
,andThen
,call
, andflatten
had an implementation issue that has been now fixed
- Methods
v0.0.10 - 13 August 2021 #
- Released introduction to Practical Functional Programming
- Completed
StateAsync
type implementation, documentation, and testing - Fixed problem with
Alt
typeclass (#21) - Added
call
method to more easily chain functions inMonad
andMonad2
v0.0.9 - 3 August 2021 #
- Released two new tutorials on the
Option
type: - Added
toJson
andfromJson
methods toOption
to usejson_serializable
to convertOption
type to and from Json (using@JsonSerializable
) - Added functional extension methods on
Map
- Added composable
Predicate
type (and&
, or|
, not~
, xor^
) (#18)
v0.0.8 - 13 July 2021 #
- Released Part 3 of Fpdart, Functional Programming in Dart and Flutter
- Added Pure Functional Flutter app example (
pokeapi_functional
) - Added
flatMapTask
andtoTask
methods toIO
to lift and chainIO
withTask
- Added
flatMapTask
andtoTask
methods toIOEither
to lift and chainIOEither
withTaskEither
- Added pattern matching extension methods to
bool
(boolean.dart
) - Added functions to get random
int
,double
, andbool
in a functional way (usingIO
) (random.dart
) - Added functions, extension methods,
Ord
, andEq
instances toDateTime
(date.dart
)
v0.0.7 - 6 July 2021 #
- Released Part 2 of Fpdart, Functional Programming in Dart and Flutter
- Added
Compose
andCompose2
, used to easily compose functions in a chain - Added
curry
anduncurry
extensions on functions up to 5 parameters - Completed
TaskOption
type implementation, documentation, and testing - Expanded documentation and examples
- Added
TaskEither.tryCatchK
andEither.tryCatchK
, by tim-smart (#10, #11) 🎉
v0.0.6 - 29 June 2021 #
- Released Part 1 of Fpdart, Functional Programming in Dart and Flutter
- Added functional extension methods on
Iterable
(List
) - Completed
IOEither
type implementation, documentation, and testing - Added
constF
function - Added
option
andoptionOf
(same as dartz) - Added
Either.right(r)
factory constructor toEither
class (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) 🎉
v0.0.5 - 20 June 2021 #
- Completed
State
type implementation, documentation, and testing - Completed
Reader
type implementation, documentation, and testing - Completed
IO
type implementation, documentation, and testing - Merged PR (#2) by jacobaraujo7 🎉
- Added
right
andleft
functions to create instance ofEither
- Added
id
function (same asidentity
) - Added
fold
method toEither
(same asmatch
) - Added
bind
method toEither
(same asflatMap
) - Added
bindFuture
method toEither
, which returnsTaskEither
- Added
v0.0.4 - 15 June 2021 #
- Completed
Unit
type documentation - Completed
Task
type implementation, documentation, and testing - Completed
TaskEither
type implementation, documentation, and testing - Completed implementation, documentation, and testing of
Foldable
instance onOption
andEither
[BREAKING CHANGE] - Completed
Tuple2
type implementation, documentation, and testing [BREAKING CHANGE] - Renamed
fold
method ofFoldable
tofoldLeft
[BREAKING CHANGE] - Updated methods API (
foldRight
,foldLeft
, etc.) ofFoldable
instances (Option
,Either
,Tuple
) [BREAKING CHANGE] IList
not longer working correctly (waiting for a better solution for immutable collections) [BREAKING CHANGE]
v0.0.3 - 13 June 2021 #
- Changed name of type
Maybe
toOption
to be inline with fp-ts, cats, and dartz [BREAKING CHANGE]
v0.0.2 - 13 June 2021 #
First major release:
Types #
Either
IList
Maybe
Reader
State
Task
TaskEither
Tuple
Unit
Typeclasses #
Alt
Applicative
Band
BoundedSemilattice
CommutativeGroup
CommutativeMonoid
CommutativeSemigroup
Eq
Extend
Filterable
Foldable
Functor
Group
Hash
HKT
Monad
Monoid
Order
PartialOrder
Semigroup
Semilattice
Examples #
Either
curry
Maybe
Reader
State
v0.0.1 - 28 May 2021 #
Eq
Hash
PartialOrder