Effect systems: Functional Programming to the next level

Sandro Maglione

Sandro Maglione

Mobile development

The future belongs to Effect systems.

Effect systems are used to provide compile-time check of the possible effects of the program

This week I worked on a prototype of an effect system in dart, aka fpdart v2 ๐Ÿ—๏ธ

This is how it all looks like ๐Ÿ‘‡

If this works I expect fpdart code to be reduced a lot โœ… Easier to read โœ… Easier to maintain โœ… Easier to navigate documentation โœ… Easier to contribute Working on it ๐Ÿ—๏ธ

Sandro Maglione
Sandro Maglione

๐Ÿ› ๏ธ fpdart <> @EffectTS_ update ๐Ÿ› ๏ธ Remove confusion with TaskEither, TaskOption, Task, IO, and all ๐Ÿฅด Instead use a single Effect class and a single Do notation ๐Ÿ’ก Work in progress ๐Ÿ—๏ธ


Effect systems over functional programming

Functional programming is hard for 2 reasons:

  • Different paradigm from "usual" OOP
  • Jargon ๐Ÿฅด

Combine something different with mystic terms (e.g. Monad ๐Ÿ‘ป) makes people justified to run away

What we want instead:

  • Use both OOP and functional programming at their best
  • No Jargon, but solutions to real-world problems

Welcome to Effect systems ๐Ÿ’๐Ÿผโ€โ™‚๏ธ

Problems with fpdart (v1)

  • API surface: too many different classes, hard to understand what to use (Task, TaskEither, IO, Reader)
  • Interoperability: too many conversion functions (toTask, toTaskEither, toReaderTaskEither)
  • Jargon (from functional programming): things like Reader, Task, State
  • Not OOP friendly: classes like Eq are more useful in pure fp languages, less in dart

New Effect class

Solution: a single Effect class to handle all effects (dependencies, errors, success).

  • Remove all other classes (Task, IO, Reader and all)
  • No need of conversion function (everything is Effect)
  • No more jargon: removed methods like pure in favor of clear terms like succeed
  • Embrace dart OOP features

Furthermore, this allows to have a single Do notation function that handles all, Option and Either included.

There is more.

Every week I build a new open source project, with a new language or library, and teach you how I did it, what I learned, and how you can do the same. Join me and other 600+ readers.

How this works

A single interface and a single Effect class:

abstract interface class IEffect<E, L, R> {
  final UnsafeRun<E, L, R> _unsafeRun;
  const IEffect._(this._unsafeRun);
  Future<Exit<L, R>> _runEffect(E env) async => _unsafeRun(env);
  /// ...
final class Effect<E, L, R> extends IEffect<E, L, R> {
  /// ...

This substitutes all other classes:

  • ReaderTaskEither: Effect<E, L, R>
  • TaskEither: Effect<dynamic, L, R>
  • Task (same as IO): Effect<dynamic, dynamic, R>

There is no distinction between sync and async code in the API.

This is achieved by using FutureOr:

typedef UnsafeRun<E, L, R> = FutureOr<Exit<L, R>> Function(E env);

In practice the usage is the same:

/// Create an [Effect] (same as [TaskEither])
final effect = Effect.tryCatch(
  () => Future.value(10),
  (error, stackTrace) => "Error",
/// Use the Do notation for all [Effect], [Option], [Either]
final doing = doEffect<int, String, int>(
  (_) async {
    final env = await _(Effect.ask());
    /// Use `withEnv` to provide a valid dependency value
    final mapped = await _(effect.map((r) => r + 10).withEnv(identity));
    /// Same for [Either] and [Option]
    final eitherValue = await _(Right<String, int>(10).withEnv<int>());
    final optionValue = await _(Some<int>(10).withEnv(() => "Some"));
    return mapped + eitherValue + optionValue;

So, when?

This is still in the experimentation phase (not even alpha ๐Ÿ’๐Ÿผโ€โ™‚๏ธ). You can view and follow the progress on Github:

This would be a radical change for fpdart: the most breaking change ever ๐Ÿ˜…

If this works I am going to open a discussion with the community to discuss how and if to move in this direction for fpdart v2

Stay tuned ๐Ÿ”œ

If you want a peek in how powerful effect system are take a look at Effect (typescript).

My goal is to provide something similar also in dart, but all adapted to the dart language and its features ๐Ÿ”ฅ

Working on it ๐Ÿ—๏ธ

See you next ๐Ÿ‘‹

Start here.

Every week I build a new open source project, with a new language or library, and teach you how I did it, what I learned, and how you can do the same. Join me and other 600+ readers.