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
|
import type { Mapper, SideEffect, Supplier } from "@emprespresso/pengueno";
// the "thing" every Trace writer must "trace()"
type BaseTraceWith = string;
export type ITraceWith<T> = BaseTraceWith | T;
export interface ITrace<TraceWith> {
addTrace: Mapper<ITraceWith<TraceWith>, ITrace<TraceWith>>;
trace: SideEffect<ITraceWith<TraceWith>>;
}
export type ITraceableTuple<T, TraceWith> = [T, BaseTraceWith | TraceWith];
export type ITraceableMapper<T, _T, TraceWith, W = ITraceable<T, TraceWith>> = (
w: W,
) => _T;
export interface ITraceable<T, Trace = BaseTraceWith> {
readonly trace: ITrace<Trace>;
get: Supplier<T>;
move: <_T>(u: _T) => ITraceable<_T, Trace>;
map: <_T>(mapper: ITraceableMapper<T, _T, Trace>) => ITraceable<_T, Trace>;
bimap: <_T>(
mapper: ITraceableMapper<
T,
ITraceableTuple<_T, Array<Trace> | Trace>,
Trace
>,
) => ITraceable<_T, Trace>;
peek: (peek: ITraceableMapper<T, void, Trace>) => ITraceable<T, Trace>;
flatMap: <_T>(
mapper: ITraceableMapper<T, ITraceable<_T, Trace>, Trace>,
) => ITraceable<_T, Trace>;
flatMapAsync<_T>(
mapper: ITraceableMapper<T, Promise<ITraceable<_T, Trace>>, Trace>,
): ITraceable<Promise<_T>, Trace>;
}
export class TraceableImpl<T, TraceWith> implements ITraceable<T, TraceWith> {
protected constructor(
private readonly item: T,
public readonly trace: ITrace<TraceWith>,
) {}
public map<_T>(mapper: ITraceableMapper<T, _T, TraceWith>) {
const result = mapper(this);
return new TraceableImpl(result, this.trace);
}
public flatMap<_T>(
mapper: ITraceableMapper<T, ITraceable<_T, TraceWith>, TraceWith>,
): ITraceable<_T, TraceWith> {
return mapper(this);
}
public flatMapAsync<_T>(
mapper: ITraceableMapper<T, Promise<ITraceable<_T, TraceWith>>, TraceWith>,
): ITraceable<Promise<_T>, TraceWith> {
return new TraceableImpl(
mapper(this).then((t) => t.get()),
this.trace,
);
}
public peek(peek: ITraceableMapper<T, void, TraceWith>) {
peek(this);
return this;
}
public move<_T>(t: _T): ITraceable<_T, TraceWith> {
return this.map(() => t);
}
public bimap<_T>(
mapper: ITraceableMapper<
T,
ITraceableTuple<_T, Array<TraceWith> | TraceWith>,
TraceWith
>,
) {
const [item, trace] = mapper(this);
const traces = Array.isArray(trace) ? trace : [trace];
return new TraceableImpl(
item,
traces.reduce((trace, _trace) => trace.addTrace(_trace), this.trace),
);
}
public get() {
return this.item;
}
}
|