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 ๐๏ธ
๐ ๏ธ 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).
๐ ๏ธ 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 ๐๏ธ
- 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 likesucceed
- Embrace dart OOP features
Furthermore, this allows to have a single Do notation function that handles all, Option
and Either
included.
Do notation to the next level ๐ฅ Effect in fpdart allows a single Do function for everything Even for Option and Either ๐ Write readable step-by-step functional code ๐
There is more ๐คฉ
Timeless coding principles, practices, and tools that make a difference, regardless of your language or framework, delivered in your inbox every week.
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 asIO
):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 ๐