-
Notifications
You must be signed in to change notification settings - Fork 21
/
Tuple2.ts
173 lines (153 loc) · 4.69 KB
/
Tuple2.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
import { Value, inspect } from "./Value";
import { Option } from "./Option";
import { Vector } from "./Vector";
import { LinkedList, ConsLinkedList } from "./LinkedList";
import { WithEquality, areEqual, getHashCode } from "./Comparison";
import { toStringHelper } from "./SeqHelpers";
import { contractTrueEquality } from "./Contract";
/**
* Contains a pair of two values, which may or may not have the same type.
* Compared to the builtin typescript [T,U] type, we get equality semantics
* and helper functions (like mapping and so on).
* @param T the first item type
* @param U the second item type
*/
export class Tuple2<T,U> implements Value {
private constructor(private _fst: T,
private _snd: U) {}
/**
* Build a pair of value from both values.
*/
static of<T,U>(fst: T, snd: U) {
return new Tuple2(fst,snd);
}
/**
* Build a tuple2 from javascript array. Compared to [[Tuple2.ofPair]],
* it checks the length of the array and will return [[None]] in case
* the length isn't two. However the types of the elements aren't checked.
*/
static ofArray<T,U>(pair: Array<T|U>): Option<Tuple2<T,U>> {
if (pair && pair.length === 2) {
return Option.of(new Tuple2<T,U>(<T>pair[0], <U>pair[1]));
}
return Option.none<Tuple2<T,U>>();
}
/**
* Build a tuple2 from javascript pair.
* Also see [[Tuple2.ofArray]]
*/
static ofPair<T,U>(pair: [T, U]): Tuple2<T,U> {
return new Tuple2(pair[0], pair[1]);
}
/**
* @hidden
*/
hasTrueEquality(): boolean {
return Option.of(this.fst()).hasTrueEquality() &&
Option.of(this.snd()).hasTrueEquality();
}
/**
* Extract the first value from the pair
*/
fst(): T {
return this._fst;
}
/**
* Extract the second value from the pair
*/
snd(): U {
return this._snd;
}
/**
* Maps the first component of this tuple to a new value.
*/
map1<V>(fn: (v:T)=>V): Tuple2<V,U> {
return new Tuple2(fn(this._fst), this._snd);
}
/**
* Maps the second component of this tuple to a new value.
*/
map2<V>(fn: (v:U)=>V): Tuple2<T,V> {
return new Tuple2(this._fst, fn(this._snd));
}
/**
* Make a new tuple by mapping both values inside this one.
*/
map<T1,U1>(fn: (a:T,b:U)=> Tuple2<T1,U1>): Tuple2<T1,U1> {
return fn(this._fst, this._snd);
}
/**
* Transform this value to another value type.
* Enables fluent-style programming by chaining calls.
*/
transform<V>(converter:(x:Tuple2<T,U>)=>V): V {
return converter(this);
}
/**
* Two objects are equal if they represent the same value,
* regardless of whether they are the same object physically
* in memory.
*/
equals(other: Tuple2<T&WithEquality,U&WithEquality>): boolean {
if (<any>other === this) {
return true;
}
if (!other || !other._fst) {
return false;
}
contractTrueEquality("Tuple2.equals", this, other);
return areEqual(this._fst, other._fst) &&
areEqual(this._snd, other._snd);
}
/**
* Get a number for that object. Two different values
* may get the same number, but one value must always get
* the same number. The formula can impact performance.
*/
hashCode(): number {
return getHashCode(this._fst)*53 + getHashCode(this._snd);
}
/**
* Convert the tuple to a javascript pair.
* Compared to [[Tuple2.toArray]], it behaves the
* same at runtime, the only difference is the
* typescript type definition.
*/
toPair(): [T,U] {
return [this._fst, this._snd];
}
/**
* Convert the tuple to a javascript array.
* Compared to [[Tuple2.toPair]], it behaves the
* same at runtime, the only difference is the
* typescript type definition.
*/
toArray(): Array<T|U> {
return [this._fst, this._snd];
}
/**
* Convert the tuple to a vector.
*/
toVector(): Vector<T|U> {
return Vector.of<T|U>(this._fst, this._snd);
}
/**
* Convert the tuple to a linked list.
*/
toLinkedList(): ConsLinkedList<T|U> {
return LinkedList.of<T|U>(this._fst, this._snd);
}
/**
* Get a human-friendly string representation of that value.
*/
toString(): string {
return `Tuple2(${toStringHelper(this._fst)}, ${toStringHelper(this._snd)})`;
}
/**
* Used by the node REPL to display values.
* Most of the time should be the same as toString()
*/
[inspect](): string {
return this.toString();
}
}