forked from cbowdon/TsMonad
-
Notifications
You must be signed in to change notification settings - Fork 1
/
writer.ts
198 lines (183 loc) · 6.01 KB
/
writer.ts
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
module TsMonad {
'use strict';
/**
* @name WriterPatterns
* @description Define a contract to unwrap Writer object using a
* callback.
* @see Writer#
*/
export interface WriterPatterns<S,T,U> {
/**
* @name writer
* @description Function to handle the Writer content.
* @type {(story: S[], value: T) => U}
*/
writer: (story: S[], value: T) => U;
}
/**
* @name writer
* @description Build a Writer object.
* @function
* @param {S[]} story The collection to store logs.
* @param {T} value The object to wrap.
* @returns {Writer<S, T>} A Writer object containing the log collection
* and the wrapped value.
* @see Writer#
*/
export function writer<S,T>(story: S[], value: T) {
return Writer.writer(story, value);
}
/**
* @name Writer
* @class Allow to do computations while making sure that all the log
* values are combined into one log value that then gets attached to
* the result.
*/
export class Writer<S,T> implements Monad<T>, Eq<Writer<S,T>> {
/**
* @description Build a Writer object. For internal use only.
* @constructor
* @methodOf Writer#
* @param {S[]} story The collection of logs.
* @param {T} value The object to wrap.
*/
constructor(private story: S[], private value: T) {}
/**
* @name writer
* @description Helper function to build a Writer object.
* @methodOf Writer#
* @static
* @param {S[]} story The collection of logs.
* @param {T} value The object to wrap.
* @returns {Writer<S, T>} A Writer object containing the collection of logs
* and the wrapped value.
*/
static writer<S,T>(story: S[], value: T) {
return new Writer(story, value);
}
/**
* @name writer
* @description Helper function to build a Writer object with the log
* passed in input only.
* @methodOf Writer#
* @static
* @param {S} s A log to store.
* @returns {Writer<S, number>} A Writer object containing the collection of logs
* and a zeroed value.
*/
static tell<S>(s: S) {
return new Writer([s], 0);
}
/**
* @name unit
* @description Wrap an object inside a Writer.
* @public
* @methodOf Writer#
* @param {U} u The object to wrap.
* @returns {Monad<U>} A Writer with the value wrapped inside and an
* empty collection of logs.
* @see Monad#unit
*/
unit<U>(u: U) {
return new Writer([], u);
}
/**
* @name bind
* @description Apply the function passed as parameter on the object.
* @methodOf Writer#
* @public
* @param {(t: T) => Writer<S, U>} f Function applied on the Writer content.
* @returns {Writer<S, U>} The result of the function f append to the
* Writer object.
* @see Monad#bind
*/
bind<U>(f: (t: T) => Writer<S,U>): Writer<S,U> {
var wu = f(this.value),
newStory = this.story.concat(wu.story);
return new Writer(newStory, wu.value);
}
/**
* @name of
* @description Alias for unit.
* @methodOf Writer#
* @public
* @see Writer#unit
* @see Monad#of
*/
of = this.unit;
/**
* @name chain
* @description Alias for bind
* @methodOf Writer#
* @public
* @see Writer#unit
* @see Monad#of
*/
chain = this.bind;
/**
* @name fmap
* @description Apply the function passed as parameter on the object.
* @methodOf Writer#
* @public
* @param {(t: T) => U} f Function applied on the wrapped value.
* @returns {Writer<S, U>} The result of the function f wrapped inside
* an Writer object. It has an empty collection of logs.
* @see Functor#fmap
*/
fmap<U>(f: (t: T) => U) {
return this.bind(v => this.unit<U>(f(v)));
}
/**
* @name lift
* @description Alias for fmap
* @methodOf Writer#
* @public
* @see Writer#fmap
* @see Monad#of
*/
lift = this.fmap;
/**
* @name map
* @description Alias for fmap
* @methodOf Writer#
* @public
* @see Writer#fmap
* @see Monad#of
*/
map = this.fmap;
/**
* @name caseOf
* @description Execute a function on the Writer content. It allows to
* unwrap the object.
* @methodOf Writer#
* @public
* @param {WriterPatterns<S, T, U>} pattern Object containing the
* functions to applied on the Writer content.
* @return {U} The returned value of the function specified in the
* WriterPatterns interface.
* @see WriterPatterns#
*/
caseOf<U>(patterns: WriterPatterns<S,T,U>) {
return patterns.writer(this.story, this.value);
}
/**
* @name equals
* @description Compare the type and the content of two Writer
* objects.
* @methodOf Writer#
* @public
* @param {Writer<S, T>} other The Writer to compare with.
* @return {boolean} True if the collection of logs and content value
* are equals, false otherwise.
* @see Eq#equals
*/
equals(other: Writer<S,T>) {
var i: number,
sameStory: boolean = true;
for (i = 0; i < this.story.length; i += 1) {
sameStory = sameStory && this.story[i] === other.story[i];
}
return sameStory && this.value === other.value;
}
}
}