forked from functionaljava/functionaljava
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNatural.java
More file actions
329 lines (291 loc) · 8.74 KB
/
Natural.java
File metadata and controls
329 lines (291 loc) · 8.74 KB
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
package fj.data;
import static fj.Bottom.error;
import fj.F;
import fj.F2;
import static fj.Monoid.naturalAdditionMonoid;
import static fj.Monoid.naturalMultiplicationMonoid;
import static fj.Function.curry;
import fj.data.vector.V2;
import fj.data.vector.V;
import java.math.BigInteger;
/**
* Represents a natural number (zero, one, two, etc.)
*/
public final class Natural extends Number {
private final BigInteger value;
private static final long serialVersionUID = -588673650944359682L;
private Natural(final BigInteger i) {
if (i.compareTo(BigInteger.ZERO) < 0)
throw error("Natural less than zero");
value = i;
}
/**
* Returns the natural number equal to the given BigInteger
*
* @param i A given BigInteger
* @return An optional natural number, or none if the given BigInteger is less than zero.
*/
public static Option<Natural> natural(final BigInteger i) {
return i.compareTo(BigInteger.ZERO) < 0
? Option.<Natural>none()
: Option.some(new Natural(i));
}
/**
* A function that returns the natural number equal to a given BigInteger
*/
public static final F<BigInteger, Option<Natural>> fromBigInt =
new F<BigInteger, Option<Natural>>() {
public Option<Natural> f(final BigInteger i) {
return natural(i);
}
};
/**
* Returns the natural number equal to the given long
*
* @param i A given long
* @return An optional natural number, or none if the given long is less than zero.
*/
public static Option<Natural> natural(final long i) {
return natural(BigInteger.valueOf(i));
}
/**
* The natural number zero
*/
public static final Natural ZERO = natural(0).some();
/**
* The natural number one
*/
public static final Natural ONE = natural(1).some();
/**
* Return the successor of this natural number
*
* @return the successor of this natural number
*/
public Natural succ() {
return add(ONE);
}
/**
* First-class successor function.
*
* @return A function that returns the successor of a given natural number.
*/
public static F<Natural, Natural> succ_() {
return new F<Natural, Natural>() {
public Natural f(final Natural natural) {
return natural.succ();
}
};
}
/**
* Return the predecessor of this natural number
*
* @return the predecessor of this natural number
*/
public Option<Natural> pred() {
return subtract(ONE);
}
/**
* First-class predecessor function.
*
* @return A function that returns the predecessor of a given natural number, or None if it's zero.
*/
public static F<Natural, Option<Natural>> pred_() {
return new F<Natural, Option<Natural>>() {
public Option<Natural> f(final Natural natural) {
return natural.pred();
}
};
}
/**
* Add two natural numbers together.
*
* @param n A natural number to add to this one.
* @return the sum of the two natural numbers.
*/
public Natural add(final Natural n) {
return natural(n.value.add(value)).some();
}
/**
* A function that adds two natural numbers.
*/
public static final F<Natural, F<Natural, Natural>> add = curry(new F2<Natural, Natural, Natural>() {
public Natural f(final Natural n1, final Natural n2) {
return n1.add(n2);
}
});
/**
* Subtract a natural number from another.
*
* @param n A natural number to subtract from this one.
* @return The difference between the two numbers, if this number is larger than the given one. Otherwise none.
*/
public Option<Natural> subtract(final Natural n) {
return natural(n.value.subtract(value));
}
/**
* A function that subtracts its first argument from its second.
*/
public static final F<Natural, F<Natural, Option<Natural>>> subtract =
curry(new F2<Natural, Natural, Option<Natural>>() {
public Option<Natural> f(final Natural o, final Natural o1) {
return o1.subtract(o);
}
});
/**
* Multiply a natural number by another.
*
* @param n A natural number to multiply by this one.
* @return The product of the two numbers.
*/
public Natural multiply(final Natural n) {
return natural(n.value.multiply(value)).some();
}
/**
* A function that multiplies a natural number by another.
*/
public static final F<Natural, F<Natural, Natural>> multiply = curry(new F2<Natural, Natural, Natural>() {
public Natural f(final Natural n1, final Natural n2) {
return n1.multiply(n2);
}
});
/**
* A function that divides its second argument by its first.
*/
public static final F<Natural, F<Natural, Natural>> divide =
curry(new F2<Natural, Natural, Natural>() {
public Natural f(final Natural n1, final Natural n2) {
return n2.divide(n1);
}
});
/**
* Divide a natural number by another.
*
* @param n A natural number to divide this one by.
* @return The quotient of this number and the highest number, less than or equal to the given number,
* that divides this number.
*/
public Natural divide(final Natural n) {
return natural(value.divide(n.value)).some();
}
/**
* Take the remainder of a natural number division.
*
* @param n A natural number to divide this one by.
* @return The remainder of division of this number by the given number.
*/
public Natural mod(final Natural n) {
return natural(value.mod(n.value)).some();
}
/**
* A function that yields the remainder of division of its second argument by its first.
*/
public static final F<Natural, F<Natural, Natural>> mod =
curry(new F2<Natural, Natural, Natural>() {
public Natural f(final Natural n1, final Natural n2) {
return n2.mod(n1);
}
});
/**
* Divide a natural number by another yielding both the quotient and the remainder.
*
* @param n A natural number to divide this one by.
* @return The quotient and the remainder, in that order.
*/
public V2<Natural> divmod(final Natural n) {
final BigInteger[] x = value.divideAndRemainder(n.value);
return V.v(natural(x[0]).some(), natural(x[1]).some());
}
/**
* A function that divides its second argument by its first, yielding both the quotient and the remainder.
*/
public static final F<Natural, F<Natural, V2<Natural>>> divmod =
curry(new F2<Natural, Natural, V2<Natural>>() {
public V2<Natural> f(final Natural n1, final Natural n2) {
return n2.divmod(n1);
}
});
/**
* Return the BigInteger value of this natural number.
*
* @return the BigInteger value of this natural number.
*/
public BigInteger bigIntegerValue() {
return value;
}
/**
* Return the long value of this natural number.
*
* @return the long value of this natural number.
*/
public long longValue() {
return value.longValue();
}
/**
* Return the float value of this natural number.
*
* @return the float value of this natural number.
*/
public float floatValue() {
return value.floatValue();
}
/**
* Return the double value of this natural number.
*
* @return the double value of this natural number.
*/
public double doubleValue() {
return value.doubleValue();
}
/**
* Return the int value of this natural number.
*
* @return the int value of this natural number.
*/
public int intValue() {
return value.intValue();
}
/**
* A function that returns the BigInteger value of a given Natural.
*/
public static final F<Natural, BigInteger> bigIntegerValue = new F<Natural, BigInteger>() {
public BigInteger f(final Natural n) {
return n.bigIntegerValue();
}
};
/**
* Sums a stream of natural numbers.
*
* @param ns A stream of natural numbers.
* @return The sum of all the natural numbers in the stream.
*/
public static Natural sum(final Stream<Natural> ns) {
return naturalAdditionMonoid.sumLeft(ns);
}
/**
* Takes the product of a stream of natural numbers.
*
* @param ns A stream of natural numbers.
* @return The product of all the natural numbers in the stream.
*/
public static Natural product(final Stream<Natural> ns) {
return naturalMultiplicationMonoid.sumLeft(ns);
}
/**
* Sums a list of natural numbers.
*
* @param ns A list of natural numbers.
* @return The sum of all the natural numbers in the list.
*/
public static Natural sum(final List<Natural> ns) {
return naturalAdditionMonoid.sumLeft(ns);
}
/**
* Takes the product of a list of natural numbers.
*
* @param ns A list of natural numbers.
* @return The product of all the natural numbers in the list.
*/
public static Natural product(final List<Natural> ns) {
return naturalMultiplicationMonoid.sumLeft(ns);
}
}