-
Notifications
You must be signed in to change notification settings - Fork 45
/
io.dart
117 lines (96 loc) · 3.77 KB
/
io.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
import 'package:fpdart/fpdart.dart';
/// Tag the [HKT] interface for the actual [Option].
abstract class _IOHKT {}
/// `IO<A>` represents a **non-deterministic synchronous** computation that
/// can **cause side effects**, yields a value of type `A` and **never fails**.
///
/// If you want to represent a synchronous computation that may fail, see [IOEither].
class IO<A> extends HKT<_IOHKT, A>
with Functor<_IOHKT, A>, Applicative<_IOHKT, A>, Monad<_IOHKT, A> {
final A Function() _run;
/// Build an instance of [IO] from `A Function()`.
const IO(this._run);
/// Flat a [IO] contained inside another [IO] to be a single [IO].
factory IO.flatten(IO<IO<A>> io) => io.flatMap(identity);
/// Build a [IO] that returns `a`.
factory IO.of(A a) => IO(() => a);
/// Used to chain multiple functions that return a [IO].
@override
IO<B> flatMap<B>(covariant IO<B> Function(A a) f) => IO(() => f(run()).run());
/// Chain a [Task] with an [IO].
///
/// Allows to chain a function that returns a `R` ([IO]) to
/// a function that returns a `Future<B>` ([Task]).
Task<B> flatMapTask<B>(Task<B> Function(A a) f) => f(run());
/// Lift this [IO] to a [Task].
///
/// Return a `Future<A>` ([Task]) instead of a `R` ([IO]).
Task<A> toTask() => Task(() async => run());
/// Return an [IO] that returns the value `b`.
@override
IO<B> pure<B>(B b) => IO(() => b);
/// Change the value of type `A` to a value of type `B` using function `f`.
@override
IO<B> map<B>(B Function(A a) f) => ap(pure(f));
/// Apply the function contained inside `a` to change the value of type `A` to
/// a value of type `B`.
@override
IO<B> ap<B>(covariant IO<B Function(A a)> a) =>
a.flatMap((f) => flatMap((v) => pure(f(v))));
/// Change type of this [IO] based on its value of type `A` and the
/// value of type `C` of another [IO].
@override
IO<D> map2<C, D>(covariant IO<C> mc, D Function(A a, C c) f) =>
flatMap((a) => mc.map((c) => f(a, c)));
/// Change type of this [IO] based on its value of type `A`, the
/// value of type `C` of a second [IO], and the value of type `D`
/// of a third [IO].
@override
IO<E> map3<C, D, E>(covariant IO<C> mc, covariant IO<D> md,
E Function(A a, C c, D d) f) =>
flatMap((a) => mc.flatMap((c) => md.map((d) => f(a, c, d))));
/// Chain multiple [IO] functions.
@override
IO<B> call<B>(covariant IO<B> chain) => flatMap((_) => chain);
/// Chain the result of `then` to this [IO].
@override
IO<B> andThen<B>(covariant IO<B> Function() then) => flatMap((_) => then());
/// Execute the IO function.
A run() => _run();
/// {@template fpdart_traverse_list_io}
/// Map each element in the list to an [IO] using the function `f`,
/// and collect the result in an `IO<List<B>>`.
/// {@endtemplate}
///
/// Same as `IO.traverseList` but passing `index` in the map function.
static IO<List<B>> traverseListWithIndex<A, B>(
List<A> list,
IO<B> Function(A a, int i) f,
) =>
IO<List<B>>(() {
final resultList = <B>[];
for (var i = 0; i < list.length; i++) {
resultList.add(f(list[i], i).run());
}
return resultList;
});
/// {@macro fpdart_traverse_list_io}
///
/// Same as `IO.traverseListWithIndex` but without `index` in the map function.
static IO<List<B>> traverseList<A, B>(
List<A> list,
IO<B> Function(A a) f,
) =>
traverseListWithIndex<A, B>(list, (a, _) => f(a));
/// {@template fpdart_sequence_list_io}
/// Convert a `List<IO<A>>` to a single `IO<List<A>>`.
/// {@endtemplate}
static IO<List<A>> sequenceList<A>(
List<IO<A>> list,
) =>
traverseList(list, identity);
@override
bool operator ==(Object other) => (other is IO) && other._run == _run;
@override
int get hashCode => _run.hashCode;
}