fpdart 1.1.0 copy "fpdart: ^1.1.0" to clipboard
fpdart: ^1.1.0 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.0 - 13 August 2023 #

  • 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]
  • Added 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()

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 type
    • ReaderTaskEither models a complete program using Reader for dependency injection, Task to perform asynchronous computation, and Either to handle errors 🎯
  • Added new ReaderTask type
  • Either as sealed class (Dart 3️⃣)
    • You can now use exhaustive pattern matching (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️⃣)
    • You can now use exhaustive pattern matching (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)',
};
  • Types marked as final (no extends nor implements) (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
  • Major refactoring of Iterable and List extension methods
    • Improved performance
    • Correct return types (Iterable and List) (#65)
    • Added the following methods
      • prependAll (Iterable)
      • intersperse (Iterable)
      • difference (Iterable)
      • filterWithIndex (Iterable)
    • Fixed the following methods ⚠️
      • takeWhileRight: Resulting List now in reversed order as expected
      • dropWhileRight: Resulting List now in reversed order as expected
    • Updated the following methods ⚠️
      • foldRight, foldRightWithIndex (List): Changed parameter order in combine function
      • zipWith (Iterable): Changed parameters definition, no more curried
    • Renamed the following methods ⚠️
      • plusconcat (Iterable)
      • concatflatten (on Iterable<Iterable<T>>)
    • Removed the following methods ⚠️
      • concatMap (use flatMap instead)
      • bind (use flatMap instead)
      • bindWithIndex (use flatMapWithIndex instead)
      • concatMapWithIndex (use flatMapWithIndex instead)
  • Refactoring of Map extension methods
    • Improved performance
    • Added the following methods
      • lookupEq
      • lookupWithKeyEq
    • Removed the following methods ⚠️
      • member (use containsKey instead)
      • elem (use containsValue instead)
      • toIterable (use toSortedList instead)
    • Updated the following methods ⚠️
      • toIterable renamed to toSortedList (return a List instead of Iterable)
      • modifyAt changed parameter order and no more curried
      • modifyAtIfPresent changed parameter order and no more curried
      • updateAt no more curried
      • updateAtIfPresent no more curried
      • deleteAt no more curried
      • upsertAt no more curried
      • pop no more curried
      • foldLeft no more curried
      • foldLeftWithKey no more curried
      • foldLeftWithIndex no more curried
      • foldLeftWithKeyAndIndex no more curried
      • foldRight no more curried
      • foldRightWithKey no more curried
      • foldRightWithIndex no more curried
      • foldRightWithKeyAndIndex no more curried
      • union no more curried
      • intersection no more curried
      • isSubmap no more curried
      • collect no more curried
      • difference no more curried
  • Added conversions helpers from String to num, int, double, and bool using Option and Either (both as extension methods on String 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, 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();
  • 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 to curryAll for functions with 3, 4, 5 parameters
    • Changed definition of curry to curry only the first parameter
    • Changed uncurry and curry extension to getter function
    • Removed curry and uncurry as functions (use extension method instead)
    • Added 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]
  • Changed Eq static constructors to methods
    • or
    • and
  • Added xor method to Eq
  • Moved DateTime instances of Eq as Eq static members
/// Before
final eq = dateEqYear; // Global

/// Now
final eq = Eq.dateEqYear;
  • Added Eq instances for num, int, double, String, and bool
[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 in Order from static constructor to getter method
/// Before
final reversed = Order.reverse(instance);

/// Now
final reversed = instance.reverse;
  • Moved DateTime instances of Order as Order static members
  • Added Order instances for num, 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 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 };

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 🎯)
/// 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 in IOEither (use toTaskEither instead) ⚠️
  • Improved performance of fpdart's sortBy 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 for None (fixes #95)
    • Removed Alt and Foldable type classes, the following methods are not available anymore
      • foldLeft
      • foldRight
      • foldMap
      • foldRightWithIndex
      • foldLeftWithIndex
      • length
      • any
      • all
      • concatenate
      • plus
      • prepend
      • append
  • 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 for Option type (thanks [again] to tim-smart 🎉)
    • Allow for decoding of non-primitive types (with custom 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()`
  • 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 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 🤝

v0.4.0 - 16 December 2022 #

  • Added extension methods to work with nullable types (T?)
    • From T? to fpdart's types
      • toOption
      • toEither
      • toTaskOption
      • toIOEither
      • toTaskEither
      • toTaskEitherAsync
      • fromNullable (Either, IOEither, TaskOption TaskEither)
      • fromNullableAsync (TaskEither)
    • From 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);
  • Added toIOEither to Either
  • 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 to TaskEither
  • Added safeCast (Either and Option)
  • Added 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);

v0.3.0 - 11 October 2022 #

  • Inverted 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)'),
);
  • Added traverse and sequence 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 in TaskEither (#58)
/// Chain [Either] to [TaskEither]
TaskEither<String, int> binding =
    TaskEither<String, String>.of("String").bindEither(Either.of(20));
  • Added 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]);
  • Added bimap method to Either, IOEither, and Tuple2 (#57)
  • Added mapLeft method to IOEither (#57)
  • Added fold method to Option (same as match) (#56)
  • Fixed chainFirst for Either, TaskEither, and IOEither 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"

v0.2.0 - 16 July 2022 #

v0.1.0 - 17 June 2022 #

  • Added idFuture and identityFuture methods (#38) by f-person 🎉
  • Added mapBoth method to Tuple2 (#30)
  • Fixed linting warnings
  • Fixed issue with upsert method for Map (#37) ⚠️
  • Minimum environment dart sdk to 2.16.0 ⚠️
environment:
  sdk: ">=2.16.0 <3.0.0"

v0.0.14 - 31 January 2022 #

  • Updated package linting to lints

v0.0.13 - 26 January 2022 #

  • New methods to TaskEither, TaskOption, Either, and Option
    • mapLeft (TaskEither)
    • bimap (TaskEither)
    • toTaskEither (Either)
    • toTaskOption (Option)
  • New Blog posts and tutorials section in README

v0.0.12 - 24 October 2021 #

  • Completed IORef type implementation, documentation, and testing

v0.0.11 - 22 September 2021 #

  • Fixed major issue in State and StateAsync implementation [BREAKING CHANGE]
    • Methods flatMap, map, map2, map3, ap, andThen, call, and flatten had an implementation issue that has been now fixed

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 in Monad and Monad2

v0.0.9 - 3 August 2021 #

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 and toTask methods to IO to lift and chain IO with Task
  • Added flatMapTask and toTask methods to IOEither to lift and chain IOEither with TaskEither
  • Added pattern matching extension methods to bool (boolean.dart)
  • Added functions to get random int, double, and bool in a functional way (using IO) (random.dart)
  • Added functions, extension methods, Ord, and Eq instances to DateTime (date.dart)

v0.0.7 - 6 July 2021 #

  • Released Part 2 of Fpdart, Functional Programming in Dart and Flutter
  • Added Compose and Compose2, used to easily compose functions in a chain
  • Added curry and uncurry extensions on functions up to 5 parameters
  • Completed TaskOption type implementation, documentation, and testing
  • Expanded documentation and examples
  • Added TaskEither.tryCatchK and Either.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 and optionOf (same as dartz)
  • Added Either.right(r) factory constructor to Either class (same as Either.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 and left functions to create instance of Either
    • Added id function (same as identity)
    • Added fold method to Either (same as match)
    • Added bind method to Either (same as flatMap)
    • Added bindFuture method to Either, which returns TaskEither

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 on Option and Either [BREAKING CHANGE]
  • Completed Tuple2 type implementation, documentation, and testing [BREAKING CHANGE]
  • Renamed fold method of Foldable to foldLeft [BREAKING CHANGE]
  • Updated methods API (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]

v0.0.3 - 13 June 2021 #

  • Changed name of type Maybe to Option 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
769
likes
130
pub points
98%
popularity
screenshot

Publisher

verified publishersandromaglione.com

Functional programming in Dart and Flutter. All the main functional programming types and patterns fully documented, tested, and with examples.

Homepage
Repository (GitHub)
View/report issues

Documentation

Documentation
API reference

License

MIT (LICENSE)

More

Packages that depend on fpdart