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
Eqare 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,Readerand all) - No need of conversion function (everything is
Effect) - No more jargon: removed methods like
purein 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 π€©
Every week I dive headfirst into a topic, uncovering every hidden nook and shadow, to deliver you the most interesting insights
Not convinced? Well, let me tell you more about it
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 π
