Fpdart

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

Fpdart is fully documented. You do not need to have any previous experience with functional programming to start using fpdart. Give it a try!

Fpdart is inspired by fp-ts, cats, and dartz.

Note: The package is still in early development. The API may change frequently and there will be many breaking changes. The documentation and testing is currently under development, but it is coming soon and fast. Follow my Twitter for daily updates.

📖 Learn functional programming and fpdart

Would you like to know more about functional programming, fpdart, and how to use the package? Check out this series of articles about functional programming with fpdart:

  1. Fpdart, Functional Programming in Dart and Flutter
  2. How to use fpdart Functional Programming in your Dart and Flutter app
  3. Pure Functional app in Flutter – Pokemon app using fpdart and Functional Programming
  4. Functional Programming Option type – Introduction
  5. Chain functions using Option type – Functional Programming
  6. Practical Functional Programming – Part 1
  7. Practical Functional Programming – Part 2
  8. Practical Functional Programming – Part 3

🎯 Types

  • Option
  • Either
  • Unit
  • Task
  • TaskEither
  • State
  • StateAsync
  • Reader
  • Tuple
  • IO
  • Iterable (List) extension
  • Map extension
  • IOEither
  • TaskOption
  • Predicate
  • ReaderEither
  • ReaderTask
  • ReaderTaskEither
  • StateReaderTaskEither
  • Lens
  • Writer

💻 Installation

# pubspec.yaml
dependencies:
  fpdart: ^0.0.11 # Check out the latest version

✨ Examples

Option

/// Create an instance of [Some]
final option = Option.of(10);

/// Create an instance of [None]
final none = Option<int>.none();

/// Map [int] to [String]
final map = option.map((a) => '$a');

/// Extract the value from [Option]
final value = option.getOrElse(() => -1);

/// Pattern matching
final match = option.match(
  (a) => print('Some($a)'),
  () => print('None'),
);

/// Convert to [Either]
final either = option.toEither(() => 'missing');

/// Chain computations
final flatMap = option.flatMap((a) => Option.of(a + 10));

/// Return [None] if the function throws an error
final tryCatch = Option.tryCatch(() => int.parse('invalid'));

Either

/// Create an instance of [Right]
final right = Either<String, int>.of(10);

/// Create an instance of [Left]
final left = Either<String, int>.left('none');

/// Map the right value to a [String]
final mapRight = right.map((a) => '$a');

/// Map the left value to a [int]
final mapLeft = right.mapLeft((a) => a.length);

/// Return [Left] if the function throws an error.
/// Otherwise return [Right].
final tryCatch = Either.tryCatch(
  () => int.parse('invalid'),
  (e, s) => 'Error: $e',
);

/// Extract the value from [Either]
final value = right.getOrElse((l) => -1);

/// Chain computations
final flatMap = right.flatMap((a) => Either.of(a + 10));

/// Pattern matching
final match = right.match(
  (l) => print('Left($l)'),
  (r) => print('Right($r)'),
);

/// Convert to [Option]
final option = right.toOption();

Reader

View the example folder for an explained usecase example.

State

View the example folder for an explained usecase example.

📦 Immutable Collections

Fpdart provides some extension methods on Iterable (List) and Map that extend the methods available by providing some functional programming signatures (safe methods that never mutate the original collection and that never throw exceptions).

Integrations for immutable collections (IList, ISet, IMap, etc.) are still being discussed with the community. fpdart does not want to be another immutable collection solution in the ecosystem. That is why we are working to integrate fpdart with other more mature packages that already implements immutable collections. Stay tuned!

More

Many more examples are coming soon. Check out my website and my Twitter for daily updates.


💡 Motivation

Functional programming is becoming more and more popular, and for good reasons.

Many non-functional languages are slowly adopting patterns from functional languages, dart included. Dart already supports higher-order functions, generic types, type inference. Other functional programming features are coming to the language, like pattern matching, destructuring, multiple return values, higher-order types.

Many packages are bringing functional patterns to dart, like the amazing freezed for unions/pattern matching.

Fpdart aims to provide all the main types found in functional languages to dart. Types like Option (handle missing values without null), Either (handle errors and error messages), Task (composable async computations), and more.

Goal

Differently from many other functional programming packages, fpdart aims to introduce functional programming to every developer. For this reason, every type and method is commented and documented directly in the code.

You do not need to have any previous experience with functional programming to start using fpdart.

Fpdart also provides real-world examples of why a type is useful and how it can be used in your application. Check out my website for blog posts and articles.

Comparison with dartz

One of the major pain points of dartz has always been is lack of documentation. This is a huge issue for people new to functional programming to attempt using the package.

dartz was released in 2016, initially targeting Dart 1.

dartz is also missing some features and types (Reader, TaskEither, and others).

Fpdart is a rewrite based on fp-ts and cats. The main differences are:

  • Fpdart is fully documented.
  • Fpdart implements higher-kinded types using defunctionalization.
  • Fpdart is based on Dart 2.
  • Fpdart is completely null-safe from the beginning.
  • Fpdart has a richer API.
  • Fpdart implements some missing types in dartz.
  • Fpdart (currently) does not provide implementation for immutable collections (ISet, IMap, IHashMap, AVLTree).

🤔 Roadmap

Being documentation and stability important goals of the package, every type will go through an implementation-documentation-testing cycle before being considered as ‘stable’.

The roadmap for types development is highlighted below (breaking changes to ‘stable’ types are to be expected in this early stages):

  1. Option
    • Implementation
    • Documentation
    • Testing
  2. Either
    • Implementation
    • Documentation
    • Testing
  3. Unit
    • Implementation
    • Documentation
    • Testing
  4. Task
    • Implementation
    • Documentation
    • Testing
  5. TaskEither
    • Implementation
    • Documentation
    • Testing
  6. Tuple
    • Implementation
    • Documentation
    • Testing
  7. State
    • Implementation
    • Documentation
    • Testing
  8. Reader
    • Implementation
    • Documentation
    • Testing
  9. IO
    • Implementation
    • Documentation
    • Testing
  10. IOEither
    • Implementation
    • Documentation
    • Testing
  11. TaskOption
    • Implementation
    • Documentation
    • Testing
  12. ReaderEither
    • Implementation
    • Documentation
    • Testing
  13. ReaderTask
    • Implementation
    • Documentation
    • Testing
  14. ReaderTaskEither
    • Implementation
    • Documentation
    • Testing
  15. StateReaderTaskEither
    • Implementation
    • Documentation
    • Testing
  16. Writer
    • Implementation
    • Documentation
    • Testing
  17. Lens
    • Implementation
    • Documentation
    • Testing

The long-term goal is to provide all the main types and typeclasses available in other functional programming languages and packages. All the types should be completely documented and fully tested.

A well explained documentation is the key for the long-term success of the project. Any article, blog post, or contribution is welcome.

In general, any contribution or feedback is welcome (and encouraged!).

👀 License

MIT License, see the LICENSE.md file for details.

GitHub

https://github.com/SandroMaglione/fpdart