-
Notifications
You must be signed in to change notification settings - Fork 44
/
reader_task.dart
145 lines (124 loc) · 4.46 KB
/
reader_task.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import 'either.dart';
import 'function.dart';
import 'reader_task_either.dart';
import 'typeclass/applicative.dart';
import 'typeclass/functor.dart';
import 'typeclass/hkt.dart';
import 'typeclass/monad.dart';
typedef DoAdapterReaderTask<E> = Future<A> Function<A>(ReaderTask<E, A>);
DoAdapterReaderTask<E> _doAdapter<E>(E env) =>
<A>(ReaderTask<E, A> task) => task.run(env);
typedef DoFunctionReaderTask<E, A> = Future<A> Function(
DoAdapterReaderTask<E> $);
/// Tag the [HKT] interface for the actual [ReaderTask].
abstract final class _ReaderTaskHKT {}
/// [ReaderTask] represents an asynchronous computation that yields a value of type `A`
/// from a context of type `E` and **never fails**.
///
/// If you want to represent an asynchronous computation that may fail, see [ReaderTaskEither].
final class ReaderTask<E, A> extends HKT2<_ReaderTaskHKT, E, A>
with
Functor2<_ReaderTaskHKT, E, A>,
Applicative2<_ReaderTaskHKT, E, A>,
Monad2<_ReaderTaskHKT, E, A> {
final Future<A> Function(E env) _run;
/// Build a [ReaderTask] from a function returning a [Future] given `E`.
const ReaderTask(this._run);
/// Initialize a **Do Notation** chain.
// ignore: non_constant_identifier_names
factory ReaderTask.Do(DoFunctionReaderTask<E, A> f) =>
ReaderTask((env) => f(_doAdapter(env)));
/// Build a [ReaderTask] that returns `a`.
factory ReaderTask.of(A a) => ReaderTask((_) async => a);
/// Flat a [ReaderTask] contained inside another [ReaderTask] to be a single [ReaderTask].
factory ReaderTask.flatten(ReaderTask<E, ReaderTask<E, A>> task) =>
task.flatMap(identity);
/// Apply the function contained inside `a` to change the value of type `A` to
/// a value of type `B`.
@override
ReaderTask<E, B> ap<B>(covariant ReaderTask<E, B Function(A a)> a) =>
ReaderTask(
(env) => a.run(env).then(
(f) => run(env).then(
(v) => f(v),
),
),
);
/// Used to chain multiple functions that return a [ReaderTask].
///
/// You can extract the value inside the [ReaderTask] without actually running it.
@override
ReaderTask<E, B> flatMap<B>(covariant ReaderTask<E, B> Function(A a) f) =>
ReaderTask(
(env) => run(env).then(
(v) => f(v).run(env),
),
);
/// Return a [ReaderTask] returning the value `b`.
@override
ReaderTask<E, B> pure<B>(B a) => ReaderTask((_) async => a);
/// Change the returning value of the [ReaderTask] from type
/// `A` to type `B` using `f`.
@override
ReaderTask<E, B> map<B>(B Function(A a) f) => ap(pure(f));
/// Change type of this [ReaderTask] based on its value of type `A` and the
/// value of type `C` of another [ReaderTask].
@override
ReaderTask<E, D> map2<C, D>(
covariant ReaderTask<E, C> mc, D Function(A a, C c) f) =>
flatMap(
(a) => mc.map(
(c) => f(a, c),
),
);
/// Change type of this [ReaderTask] based on its value of type `A`, the
/// value of type `C` of a second [ReaderTask], and the value of type `D`
/// of a third [ReaderTask].
@override
ReaderTask<E, F> map3<C, D, F>(
covariant ReaderTask<E, C> mc,
covariant ReaderTask<E, D> md,
F Function(A a, C c, D d) f,
) =>
flatMap(
(a) => mc.flatMap(
(c) => md.map(
(d) => f(a, c, d),
),
),
);
/// Run this [ReaderTask] and right after the [ReaderTask] returned from `then`.
@override
ReaderTask<E, B> andThen<B>(covariant ReaderTask<E, B> Function() then) =>
flatMap(
(_) => then(),
);
@override
ReaderTask<E, A> chainFirst<B>(
covariant ReaderTask<E, B> Function(A a) chain,
) =>
flatMap(
(a) => chain(a).map((b) => a),
);
/// Chain multiple [ReaderTask] functions.
@override
ReaderTask<E, B> call<B>(covariant ReaderTask<E, B> chain) => flatMap(
(_) => chain,
);
/// Run the task and return a [Future].
Future<A> run(E env) => _run(env);
/// Convert this [ReaderTask] to [ReaderTaskEither].
ReaderTaskEither<E, L, A> toReaderTaskEither<L>() => ReaderTaskEither(
(env) async => Either.of(
await run(env),
),
);
/// Extract a value `A` given the current dependency `E`.
factory ReaderTask.asks(A Function(E) f) => ReaderTask(
(env) async => f(env),
);
/// Read the current dependency `E`.
static ReaderTask<E, E> ask<E, A>() => ReaderTask(
(env) async => env,
);
}