UNPKG

55.4 kBPlain TextView Raw
1/*!
2 * Copyright (c) 2017-2018 by The Funfix Project Developers.
3 * Some rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18import { Setoid, Monad } from "funland"
19import * as std from "./std"
20import { HK, HK2 } from "./kinds"
21import { Throwable, NoSuchElementError } from "./errors"
22import { fantasyLandRegister } from "./internals"
23
24/**
25 * Represents a value of one of two possible types (a disjoint union).
26 *
27 * A common use of Either is as an alternative to [[Option]] for dealing
28 * with possible missing values. In this usage [[Option.none]] is replaced
29 * with [[Either.left]] which can contain useful information and
30 * [[Option.some]] is replaced with [[Either.right]].
31 *
32 * Convention dictates that `left` is used for failure and `right` is used
33 * for success. Note that this `Either` type is right-biased, meaning that
34 * operations such as `map`, `flatMap` and `filter` work on the `right` value
35 * and if you want to work on the `left` value, then you need to do a `swap`.
36 *
37 * For example, you could use `Either<String, Int>` to detect whether an
38 * input is a string or an number:
39 *
40 * ```typescript
41 * function tryParseInt(str: string): Either<string, number> {
42 * const i = parseInt(value)
43 * return isNaN(i) ? Left(str) : Right(i)
44 * }
45 *
46 * const result = tryParseInt("not an int")
47 * if (result.isRight()) {
48 * console.log(`Increment: ${result.get}`)
49 * } else {
50 * console.log(`ERROR: could not parse ${result.swap.get}`)
51 * }
52 * ```
53 *
54 * @final
55 */
56export class Either<L, R> implements std.IEquals<Either<L, R>>, HK2<"funfix/either", L, R> {
57 public readonly value: L | R
58 private readonly _isRight: boolean
59
60 protected constructor(value: L | R, tag: "left" | "right") {
61 this._isRight = tag === "right"
62 this.value = value
63 }
64
65 /**
66 * Returns `true` if this is a `left`, `false` otherwise.
67 *
68 * ```typescript
69 * Left("hello").isLeft() // true
70 * Right(10).isLeft() // false
71 * ```
72 */
73 isLeft(): this is TLeft<L> { return !this._isRight }
74
75 /**
76 * Returns `true` if this is a `right`, `false` otherwise.
77 *
78 * ```typescript
79 * Left("hello").isRight() // false
80 * Right(10).isRight() // true
81 * ```
82 */
83 isRight(): this is TRight<R> { return this._isRight }
84
85 /**
86 * Returns true if this is a Right and its value is equal to `elem`
87 * (as determined by the `equals` protocol), returns `false` otherwise.
88 *
89 * ```typescript
90 * // True
91 * Right("something").contains("something")
92 *
93 * // False because the values are different
94 * Right("something").contains("anything") // false
95 *
96 * // False because the source is a `left`
97 * Left("something").contains("something") // false
98 * ```
99 */
100 contains(elem: R): this is TRight<R> {
101 return this._isRight && std.is(this.value, elem)
102 }
103
104 /**
105 * Returns `false` if the source is a `left`, or returns the result
106 * of the application of the given predicate to the `right` value.
107 *
108 * ```typescript
109 * // True, because it is a right and predicate holds
110 * Right(20).exists(n => n > 10)
111 *
112 * // False, because the predicate returns false
113 * Right(10).exists(n => n % 2 != 0)
114 *
115 * // False, because it is a left
116 * Left(10).exists(n => n == 10)
117 * ```
118 */
119 exists(p: (r: R) => boolean): this is TRight<R> {
120 return this._isRight && p(this.value as R)
121 }
122
123 /**
124 * Filters `right` values with the given predicate, returning
125 * the value generated by `zero` in case the source is a `right`
126 * value and the predicate doesn't hold.
127 *
128 * Possible outcomes:
129 *
130 * - Returns the existing value of `right` if this is a `right` value and the
131 * given predicate `p` holds for it
132 * - Returns `Left(zero())` if this is a `right` value
133 * and the given predicate `p` does not hold
134 * - Returns the current "left" value, if the source is a `Left`
135 *
136 * ```typescript
137 * Right(12).filterOrElse(x => x > 10, () => -1) // Right(12)
138 * Right(7).filterOrElse(x => x > 10, () => -1) // Left(-1)
139 * Left(7).filterOrElse(x => false, () => -1) // Left(7)
140 * ```
141 */
142 filterOrElse<LL>(p: (r: R) => boolean, zero: () => LL): Either<L | LL, R> {
143 return this._isRight
144 ? (p(this.value as R) ? this as any : Left(zero()))
145 : this as any
146 }
147
148 /**
149 * Binds the given function across `right` values.
150 *
151 * This operation is the monadic "bind" operation.
152 * It can be used to *chain* multiple `Either` references.
153 */
154 flatMap<S>(f: (r: R) => Either<L, S>): Either<L, S> {
155 return this._isRight ? f(this.value as R) : (this as any)
156 }
157
158 /** Alias for [[flatMap]]. */
159 chain<S>(f: (r: R) => Either<L, S>): Either<L, S> {
160 return this.flatMap(f)
161 }
162
163 /**
164 * `Applicative` apply operator.
165 *
166 * Resembles {@link map}, but the passed mapping function is
167 * lifted in the `Either` context.
168 */
169 ap<S>(ff: Either<L, (a: R) => S>): Either<L, S> {
170 return ff.flatMap(f => this.map(f))
171 }
172
173 /**
174 * Applies the `left` function to [[Left]] values, and the
175 * `right` function to [[Right]] values and returns the result.
176 *
177 * ```typescript
178 * const maybeNum: Either<string, number> =
179 * tryParseInt("not a number")
180 *
181 * const result: string =
182 * maybeNum.fold(
183 * str => `Could not parse string: ${str}`,
184 * num => `Success: ${num}`
185 * )
186 * ```
187 */
188 fold<S>(left: (l: L) => S, right: (r: R) => S): S {
189 return this._isRight ? right(this.value as R) : left(this.value as L)
190 }
191
192 /**
193 * Returns true if the source is a `left` or returns
194 * the result of the application of the given predicate to the
195 * `right` value.
196 *
197 * ```typescript
198 * // True, because it is a `left`
199 * Left("hello").forAll(x => x > 10)
200 *
201 * // True, because the predicate holds
202 * Right(20).forAll(x => x > 10)
203 *
204 * // False, it's a right and the predicate doesn't hold
205 * Right(7).forAll(x => x > 10)
206 * ```
207 */
208 forAll(p: (r: R) => boolean): boolean {
209 return !this._isRight || p(this.value as R)
210 }
211
212 /**
213 * Returns the `Right` value, if the source has one,
214 * otherwise throws an exception.
215 *
216 * WARNING!
217 *
218 * This function is partial, the `Either` must be a `Right`, otherwise
219 * a runtime exception will get thrown. Use with care.
220 *
221 * @throws [[NoSuchElementError]] in case the the `Either` is a `Left`
222 */
223 get(): R {
224 if (this._isRight) return this.value as R
225 throw new NoSuchElementError("left.get()")
226 }
227
228 /**
229 * Returns the value from this `right` or the given `fallback`
230 * value if this is a `left`.
231 *
232 * ```typescript
233 * Right(10).getOrElse(27) // 10
234 * Left(10).getOrElse(27) // 27
235 * ```
236 */
237 getOrElse<RR>(fallback: RR): R | RR {
238 return this._isRight ? this.value as R : fallback
239 }
240
241 /**
242 * Returns the value from this `right` or a value generated
243 * by the given `thunk` if this is a `left`.
244 *
245 * ```typescript
246 * Right(10).getOrElseL(() => 27) // 10
247 * Left(10).getOrElseL(() => 27) // 27
248 * ```
249 */
250 getOrElseL<RR>(thunk: () => RR): R | RR {
251 return this._isRight ? this.value as R : thunk()
252 }
253
254 /**
255 * Transform the source if it is a `right` with the given
256 * mapping function.
257 *
258 * ```typescript
259 * Right(10).map(x => x + 17) // right(27)
260 * Left(10).map(x => x + 17) // left(10)
261 * ```
262 */
263 map<C>(f: (r: R) => C): Either<L, C> {
264 return this._isRight
265 ? Right(f(this.value as R))
266 : (this as any)
267 }
268
269 /**
270 * Executes the given side-effecting function if the
271 * source is a `right` value.
272 *
273 * ```typescript
274 * Right(12).forAll(console.log) // prints 12
275 * Left(10).forAll(console.log) // silent
276 * ```
277 */
278 forEach(cb: (r: R) => void): void {
279 if (this._isRight) cb(this.value as R)
280 }
281
282 /**
283 * If this is a `left`, then return the left value as a `right`
284 * or vice versa.
285 *
286 * ```typescript
287 * Right(10).swap() // left(10)
288 * Left(20).swap() // right(20)
289 * ```
290 */
291 swap(): Either<R, L> {
292 return this._isRight
293 ? Left(this.value as R)
294 : Right(this.value as L)
295 }
296
297 /**
298 * Returns an `Option.some(right)` if the source is a `right` value,
299 * or `Option.none` in case the source is a `left` value.
300 */
301 toOption(): Option<R> {
302 return this._isRight ? Some(this.value as R) : None
303 }
304
305 /**
306 * Implements {@link IEquals.equals}.
307 *
308 * @param that is the right hand side of the equality check
309 */
310 equals(that: Either<L, R>): boolean {
311 // tslint:disable-next-line:strict-type-predicates
312 if (that == null) return false
313 return this._isRight === that._isRight && std.is(this.value, that.value)
314 }
315
316 /** Implements {@link IEquals.hashCode}. */
317 hashCode(): number {
318 return this._isRight
319 ? std.hashCode(this.value as R) << 2
320 : std.hashCode(this.value as L) << 3
321 }
322
323 // Implements HK<F, A>
324 /** @hidden */ readonly _URI!: "funfix/either"
325 /** @hidden */ readonly _A!: R
326 /** @hidden */ readonly _L!: L
327
328 // Implements Constructor<T>
329 /** @hidden */ static readonly _Class: Either<any, any>
330
331 /**
332 * Builds a pure `Either` value.
333 *
334 * This operation is the pure `Applicative` operation for lifting
335 * a value in the `Either` context.
336 */
337 static pure<A>(value: A): Either<never, A> {
338 return new TRight(value)
339 }
340
341 /**
342 * Builds a left value, equivalent with {@link Left}.
343 */
344 static left<L, R>(value: L): Either<L, R> {
345 return Left(value)
346 }
347
348 /**
349 * Builds a right value, equivalent with {@link Right}.
350 */
351 static right<L, R>(value: R): Either<L, R> {
352 return Right(value)
353 }
354
355 /**
356 * Maps 2 `Either` values by the mapping function, returning a new
357 * `Either` reference that is a `Right` only if both `Either` values are
358 * `Right` values, otherwise it returns the first `Left` value noticed.
359 *
360 * ```typescript
361 * // Yields Right(3)
362 * Try.map2(Right(1), Right(2),
363 * (a, b) => a + b
364 * )
365 *
366 * // Yields Left, because the second arg is a Left
367 * Try.map2(Right(1), Left("error"),
368 * (a, b) => a + b
369 * )
370 * ```
371 *
372 * This operation is the `Applicative.map2`.
373 */
374 static map2<A1, A2, L, R>(
375 fa1: Either<L,A1>, fa2: Either<L,A2>,
376 f: (a1: A1, a2: A2) => R): Either<L, R> {
377
378 if (fa1.isLeft()) return fa1
379 if (fa2.isLeft()) return fa2
380 return Right(f(fa1.value as A1, fa2.value as A2))
381 }
382
383 /**
384 * Maps 3 `Either` values by the mapping function, returning a new
385 * `Either` reference that is a `Right` only if all 3 `Either` values are
386 * `Right` values, otherwise it returns the first `Left` value noticed.
387 *
388 * ```typescript
389 * // Yields Right(6)
390 * Try.map3(Right(1), Right(2), Right(3),
391 * (a, b, c) => a + b + c
392 * )
393 *
394 * // Yields Left, because the second arg is a Left
395 * Try.map3(Right(1), Left("error"), Right(3),
396 * (a, b, c) => a + b + c
397 * )
398 * ```
399 */
400 static map3<A1, A2, A3, L, R>(
401 fa1: Either<L, A1>, fa2: Either<L, A2>, fa3: Either<L, A3>,
402 f: (a1: A1, a2: A2, a3: A3) => R): Either<L, R> {
403
404 if (fa1.isLeft()) return fa1
405 if (fa2.isLeft()) return fa2
406 if (fa3.isLeft()) return fa3
407 return Right(f(fa1.value as A1, fa2.value as A2, fa3.value as A3))
408 }
409
410 /**
411 * Maps 4 `Either` values by the mapping function, returning a new
412 * `Either` reference that is a `Right` only if all 4 `Either` values are
413 * `Right` values, otherwise it returns the first `Left` value noticed.
414 *
415 * ```typescript
416 * // Yields Right(10)
417 * Try.map4(Right(1), Right(2), Right(3), Right(4),
418 * (a, b, c, d) => a + b + c + d
419 * )
420 *
421 * // Yields Left, because the second arg is a Left
422 * Try.map4(Right(1), Left("error"), Right(3), Right(4),
423 * (a, b, c, d) => a + b + c + d
424 * )
425 * ```
426 */
427 static map4<A1, A2, A3, A4, L, R>(
428 fa1: Either<L,A1>, fa2: Either<L,A2>, fa3: Either<L,A3>, fa4: Either<L,A4>,
429 f: (a1: A1, a2: A2, a3: A3, a4: A4) => R): Either<L, R> {
430
431 if (fa1.isLeft()) return fa1
432 if (fa2.isLeft()) return fa2
433 if (fa3.isLeft()) return fa3
434 if (fa4.isLeft()) return fa4
435 return Right(f(fa1.value as A1, fa2.value as A2, fa3.value as A3, fa4.value as A4))
436 }
437
438 /**
439 * Maps 5 `Either` values by the mapping function, returning a new
440 * `Either` reference that is a `Right` only if all 5 `Either` values are
441 * `Right` values, otherwise it returns the first `Left` value noticed.
442 *
443 * ```typescript
444 * // Yields Right(15)
445 * Try.map5(Right(1), Right(2), Right(3), Right(4), Right(5),
446 * (a, b, c, d, e) => a + b + c + d + e
447 * )
448 *
449 * // Yields Left, because the second arg is a Left
450 * Try.map5(Right(1), Left("error"), Right(3), Right(4), Right(5),
451 * (a, b, c, d, e) => a + b + c + d + e
452 * )
453 * ```
454 */
455 static map5<A1, A2, A3, A4, A5, L, R>(
456 fa1: Either<L,A1>, fa2: Either<L,A2>, fa3: Either<L,A3>, fa4: Either<L,A4>, fa5: Either<L,A5>,
457 f: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5) => R): Either<L, R> {
458
459 if (fa1.isLeft()) return fa1
460 if (fa2.isLeft()) return fa2
461 if (fa3.isLeft()) return fa3
462 if (fa4.isLeft()) return fa4
463 if (fa5.isLeft()) return fa5
464 return Right(f(fa1.value as A1, fa2.value as A2, fa3.value as A3, fa4.value as A4, fa5.value as A5))
465 }
466
467 /**
468 * Maps 6 `Either` values by the mapping function, returning a new
469 * `Either` reference that is a `Right` only if all 6 `Either` values are
470 * `Right` values, otherwise it returns the first `Left` value noticed.
471 *
472 * ```typescript
473 * // Yields Right(21)
474 * Try.map5(Right(1), Right(2), Right(3), Right(4), Right(5), Right(6),
475 * (a, b, c, d, e, f) => a + b + c + d + e + f
476 * )
477 *
478 * // Yields Left, because the second arg is a Left
479 * Try.map5(Right(1), Left("error"), Right(3), Right(4), Right(5), Right(6),
480 * (a, b, c, d, e, f) => a + b + c + d + e + f
481 * )
482 * ```
483 */
484 static map6<A1, A2, A3, A4, A5, A6, L, R>(
485 fa1: Either<L,A1>, fa2: Either<L,A2>, fa3: Either<L,A3>, fa4: Either<L,A4>, fa5: Either<L,A5>, fa6: Either<L,A6>,
486 f: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6) => R): Either<L, R> {
487
488 if (fa1.isLeft()) return fa1
489 if (fa2.isLeft()) return fa2
490 if (fa3.isLeft()) return fa3
491 if (fa4.isLeft()) return fa4
492 if (fa5.isLeft()) return fa5
493 if (fa6.isLeft()) return fa6
494 return Right(f(fa1.value as A1, fa2.value as A2, fa3.value as A3, fa4.value as A4, fa5.value as A5, fa6.value as A6))
495 }
496
497 /**
498 * Keeps calling `f` until a `Right(b)` is returned.
499 *
500 * Based on Phil Freeman's
501 * [Stack Safety for Free]{@link http://functorial.com/stack-safety-for-free/index.pdf}.
502 *
503 * Described in `FlatMap.tailRecM`.
504 */
505 static tailRecM<L, A, B>(a: A, f: (a: A) => Either<L, Either<A, B>>): Either<L, B> {
506 let cursor = a
507 while (true) {
508 const result = f(cursor)
509 if (!result.isRight()) return result as any
510
511 const some = result.value
512 if (some.isRight()) return Right(some.value)
513 cursor = some.value as A
514 }
515 }
516}
517
518/**
519 * Result of the [[Left]] data constructor, representing
520 * "left" values in the [[Either]] disjunction.
521 *
522 * @final
523 */
524export class TLeft<L> extends Either<L, never> {
525 public readonly value!: L
526 constructor(value: L) { super(value, "left") }
527}
528
529/**
530 * The `Left` data constructor represents the left side of the
531 * [[Either]] disjoint union, as opposed to the [[Right]] side.
532 */
533export function Left<L>(value: L): TLeft<L> {
534 return new TLeft(value)
535}
536
537/**
538 * Result of the [[Right]] data constructor, representing
539 * "right" values in the [[Either]] disjunction.
540 *
541 * @final
542 */
543export class TRight<R> extends Either<never, R> {
544 public readonly value!: R
545 constructor(value: R) { super(value, "right") }
546}
547
548/**
549 * The `Right` data constructor represents the right side of the
550 * [[Either]] disjoint union, as opposed to the [[Left]] side.
551 */
552export function Right<R>(value: R): TRight<R> {
553 return new TRight(value)
554}
555
556/**
557 * Type enumerating the type-classes that `Either` implements.
558 */
559export type EitherTypes = Setoid<Either<any, any>> & Monad<"funfix/either">
560
561/**
562 * Type-class implementations, compatible with the `static-land`
563 * and `funland` specifications.
564 *
565 * See [funland-js.org](https://funland-js.org).
566 */
567export const EitherModule: EitherTypes = {
568 // Setoid
569 equals: (x, y) => x ? x.equals(y) : !y,
570 // Functor
571 map: <L, A, B>(f: (a: A) => B, fa: Either<L, A>) =>
572 fa.map(f),
573 // Apply
574 ap: <L, A, B>(ff: Either<L, (a: A) => B>, fa: Either<L, A>): Either<L, B> =>
575 fa.ap(ff),
576 // Applicative
577 of: Either.pure,
578 // Chain
579 chain: <L, A, B>(f: (a: A) => Either<L, B>, fa: Either<L, A>): Either<L, B> =>
580 fa.flatMap(f),
581 // ChainRec
582 chainRec: <L, A, B>(f: <C>(next: (a: A) => C, done: (b: B) => C, a: A) => Either<L, C>, a: A): Either<L, B> =>
583 Either.tailRecM(a, a => f(Either.left as any, Either.right as any, a))
584}
585
586// Registers Fantasy-Land compatible symbols
587fantasyLandRegister(Either, EitherModule, EitherModule)
588
589/**
590 * Represents optional values, inspired by Scala's `Option` and by
591 * Haskell's `Maybe` data types.
592 *
593 * Option is an immutable data type, represented as a sum type, being
594 * either a [[Some]], in case it contains a single element, or a [[None]],
595 * in case it is empty.
596 *
597 * The most idiomatic way to use an `Option` instance is to treat it
598 * as a collection or monad and use `map`,`flatMap`, `filter`,
599 * or `forEach`.
600 *
601 * @final
602 */
603export class Option<A> implements std.IEquals<Option<A>>, HK<"funfix/option", A> {
604 // tslint:disable-next-line:variable-name
605 private readonly _isEmpty: boolean
606 public readonly value: undefined | A
607
608 protected constructor(ref: A | undefined, isEmpty?: boolean) {
609 /* tslint:disable-next-line:strict-type-predicates */
610 this._isEmpty = isEmpty != null ? isEmpty : (ref === null || ref === undefined)
611 this.value = ref
612 }
613
614 /**
615 * Returns the option's value.
616 *
617 * WARNING!
618 *
619 * This function is partial, the option must be non-empty, otherwise
620 * a runtime exception will get thrown. Use with care.
621 *
622 * @throws [[NoSuchElementError]] in case the option is empty
623 */
624 get(): A {
625 if (!this._isEmpty) return this.value as A
626 throw new NoSuchElementError("Option.get")
627 }
628
629 /**
630 * Returns the option's value if the option is nonempty, otherwise
631 * return the given `fallback`.
632 *
633 * See [[Option.getOrElseL]] for a lazy alternative.
634 */
635 getOrElse<AA>(fallback: AA): A | AA {
636 if (!this._isEmpty) return this.value as A
637 else return fallback
638 }
639
640 /**
641 * Returns the option's value if the option is nonempty, otherwise
642 * return `null`.
643 * ```
644 */
645 orNull(): A | null {
646 return !this._isEmpty ? this.value as A : null
647 }
648
649 /**
650 * Returns the option's value if the option is nonempty, otherwise
651 * return `undefined`.
652 */
653 orUndefined(): A | undefined {
654 return !this._isEmpty ? this.value : undefined
655 }
656
657 /**
658 * Returns the option's value if the option is nonempty, otherwise
659 * return the result of evaluating `thunk`.
660 *
661 * See [[Option.getOrElse]] for a strict alternative.
662 */
663 getOrElseL<AA>(thunk: () => AA): A | AA {
664 if (!this._isEmpty) return this.value as A
665 else return thunk()
666 }
667
668 /**
669 * Returns this option if it is nonempty, otherwise returns the
670 * given `fallback`.
671 */
672 orElse<AA>(fallback: Option<AA>): Option<A | AA> {
673 if (!this._isEmpty) return this
674 else return fallback
675 }
676
677 /**
678 * Returns this option if it is nonempty, otherwise returns the
679 * given result of evaluating the given `thunk`.
680 *
681 * @param thunk a no-params function that gets evaluated and
682 * whose result is returned in case this option is empty
683 */
684 orElseL<AA>(thunk: () => Option<AA>): Option<A | AA> {
685 if (!this._isEmpty) return this
686 else return thunk()
687 }
688
689 /**
690 * Returns `true` if the option is empty, `false` otherwise.
691 */
692 isEmpty(): this is TNone { return this._isEmpty }
693
694 /**
695 * Returns `true` if the option is not empty, `false` otherwise.
696 */
697 nonEmpty(): this is TSome<A> { return !this._isEmpty }
698
699 /**
700 * Returns an option containing the result of applying `f` to
701 * this option's value, or an empty option if the source is empty.
702 *
703 * NOTE: this is similar with `flatMap`, except with `map` the
704 * result of `f` doesn't need to be wrapped in an `Option`.
705 *
706 * @param f the mapping function that will transform the value
707 * of this option if nonempty.
708 *
709 * @return a new option instance containing the value of the
710 * source mapped by the given function
711 */
712 map<B>(f: (a: A) => B): Option<B> {
713 return this._isEmpty ? None : Some(f(this.value as A))
714 }
715
716 /**
717 * Returns the result of applying `f` to this option's value if
718 * the option is nonempty, otherwise returns an empty option.
719 *
720 * NOTE: this is similar with `map`, except that `flatMap` the
721 * result returned by `f` is expected to be boxed in an `Option`
722 * already.
723 *
724 * Example:
725 *
726 * ```typescript
727 * const opt = Option.of(10)
728 *
729 * opt.flatMap(num => {
730 * if (num % 2 == 0)
731 * Some(num + 1)
732 * else
733 * None
734 * })
735 * ```
736 *
737 * @param f the mapping function that will transform the value
738 * of this option if nonempty.
739 *
740 * @return a new option instance containing the value of the
741 * source mapped by the given function
742 */
743 flatMap<B>(f: (a: A) => Option<B>): Option<B> {
744 if (this._isEmpty) return None
745 else return f(this.value as A)
746 }
747
748 /** Alias for [[flatMap]]. */
749 chain<B>(f: (a: A) => Option<B>): Option<B> {
750 return this.flatMap(f)
751 }
752
753 /**
754 * `Applicative` apply operator.
755 *
756 * Resembles {@link map}, but the passed mapping function is
757 * lifted in the `Either` context.
758 */
759 ap<B>(ff: Option<(a: A) => B>): Option<B> {
760 return ff.flatMap(f => this.map(f))
761 }
762
763 /**
764 * Returns this option if it is nonempty AND applying the
765 * predicate `p` to the underlying value yields `true`,
766 * otherwise return an empty option.
767 *
768 * @param p is the predicate function that is used to
769 * apply filtering on the option's value
770 *
771 * @return a new option instance containing the value of the
772 * source filtered with the given predicate
773 */
774 filter<B extends A>(p: (a: A) => a is B): Option<B>
775 filter(p: (a: A) => boolean): Option<A>
776 filter(p: (a: A) => boolean): Option<A> {
777 if (this._isEmpty || !p(this.value as A)) return None
778 else return this
779 }
780
781 /**
782 * Returns the result of applying `f` to this option's value,
783 * or in case the option is empty, the return the result of
784 * evaluating the `fallback` function.
785 *
786 * This function is equivalent with:
787 *
788 * ```typescript
789 * opt.map(f).getOrElseL(fallback)
790 * ```
791 *
792 * @param fallback is the function to be evaluated in case this
793 * option is empty
794 *
795 * @param f is the mapping function for transforming this option's
796 * value in case it is nonempty
797 */
798 fold<B>(fallback: () => B, f: (a: A) => B): B {
799 if (this._isEmpty) return fallback()
800 return f(this.value as A)
801 }
802
803 /**
804 * Returns true if this option is nonempty and the value it
805 * holds is equal to the given `elem`.
806 */
807 contains(elem: A): boolean {
808 return !this._isEmpty && std.is(this.value, elem)
809 }
810
811 /**
812 * Returns `true` if this option is nonempty and the given
813 * predicate returns `true` when applied on this option's value.
814 *
815 * @param p is the predicate function to test
816 */
817 exists(p: (a: A) => boolean): boolean {
818 return !this._isEmpty && p(this.value as A)
819 }
820
821 /**
822 * Returns true if this option is empty or the given predicate
823 * returns `true` when applied on this option's value.
824 *
825 * @param p is the predicate function to test
826 */
827 forAll(p: (a: A) => boolean): boolean {
828 return this._isEmpty || p(this.value as A)
829 }
830
831 /**
832 * Apply the given procedure `cb` to the option's value if
833 * this option is nonempty, otherwise do nothing.
834 *
835 * @param cb the procedure to apply
836 */
837 forEach(cb: (a: A) => void): void {
838 if (!this._isEmpty) cb(this.value as A)
839 }
840
841 /**
842 * Implements {@link IEquals.equals}.
843 *
844 * @param that is the right hand side of the equality check
845 */
846 equals(that: Option<A>): boolean {
847 // tslint:disable-next-line:strict-type-predicates
848 if (that == null) return false
849 if (this.nonEmpty() && that.nonEmpty()) {
850 return std.is(this.value, that.value)
851 }
852 return this.isEmpty() && that.isEmpty()
853 }
854
855 // Implemented from IEquals
856 hashCode(): number {
857 if (this._isEmpty) return 2433880
858 // tslint:disable-next-line:strict-type-predicates
859 else if (this.value == null) return 2433881 << 2
860 else return std.hashCode(this.value) << 2
861 }
862
863 // Implements HK<F, A>
864 /** @hidden */ readonly _URI!: "funfix/option"
865 /** @hidden */ readonly _A!: A
866
867 // Implements Constructor<T>
868 /** @hidden */ static readonly _Class: Option<any>
869
870 /**
871 * Builds an [[Option]] reference that contains the given value.
872 *
873 * If the given value is `null` or `undefined` then the returned
874 * option will be empty.
875 */
876 static of<A>(value: A | null | undefined): Option<A> {
877 return value != null ? Some(value) : None
878 }
879
880 /**
881 * Builds an [[Option]] reference that contains the given reference.
882 *
883 * Note that `value` is allowed to be `null` or `undefined`, the
884 * returned option will still be non-empty. Use [[Option.of]]
885 * if you want to avoid this problem. This means:
886 *
887 * ```typescript
888 * const opt = Some<number | null>(null)
889 *
890 * opt.isEmpty()
891 * //=> false
892 *
893 * opt.get()
894 * //=> null
895 * ```
896 */
897 static some<A>(value: A): Option<A> {
898 return new Option(value, false)
899 }
900
901 /**
902 * Returns an empty [[Option]].
903 *
904 * NOTE: Because `Option` is immutable, this function returns the
905 * same cached reference is on different calls.
906 */
907 static none<A = never>(): Option<A> {
908 return None
909 }
910
911 /**
912 * Returns an empty [[Option]].
913 *
914 * Similar to [[Option.none]], but this one allows specifying a
915 * type parameter (in the context of TypeScript or Flow or other
916 * type system).
917 *
918 * NOTE: Because `Option` is immutable, this function returns the
919 * same cached reference is on different calls.
920 */
921 static empty<A>(): Option<A> {
922 return None
923 }
924
925 /**
926 * Alias for [[Some]].
927 */
928 static pure<A>(value: A): Option<A> { return Some(value) }
929
930 /**
931 * Maps 2 optional values by the mapping function, returning a new
932 * optional reference that is `Some` only if both option values are
933 * `Some`, otherwise it returns a `None`.
934 *
935 * ```typescript
936 * // Yields Some(3)
937 * Option.map2(Some(1), Some(2),
938 * (a, b) => a + b
939 * )
940 *
941 * // Yields None, because the second arg is None
942 * Option.map2(Some(1), None,
943 * (a, b) => a + b
944 * )
945 * ```
946 *
947 * This operation is the `Applicative.map2`.
948 */
949 static map2<A1,A2,R>(
950 fa1: Option<A1>, fa2: Option<A2>,
951 f: (a1: A1, a2: A2) => R): Option<R> {
952
953 return fa1.nonEmpty() && fa2.nonEmpty()
954 ? Some(f(fa1.value, fa2.value))
955 : None
956 }
957
958 /**
959 * Maps 3 optional values by the mapping function, returning a new
960 * optional reference that is `Some` only if all 3 option values are
961 * `Some`, otherwise it returns a `None`.
962 *
963 * ```typescript
964 * // Yields Some(6)
965 * Option.map3(Some(1), Some(2), Some(3),
966 * (a, b, c) => a + b + c
967 * )
968 *
969 * // Yields None, because the second arg is None
970 * Option.map3(Some(1), None, Some(3),
971 * (a, b, c) => a + b + c
972 * )
973 * ```
974 */
975 static map3<A1,A2,A3,R>(
976 fa1: Option<A1>, fa2: Option<A2>, fa3: Option<A3>,
977 f: (a1: A1, a2: A2, a3: A3) => R): Option<R> {
978
979 return fa1.nonEmpty() && fa2.nonEmpty() && fa3.nonEmpty()
980 ? Some(f(fa1.value, fa2.value, fa3.value))
981 : None
982 }
983
984 /**
985 * Maps 4 optional values by the mapping function, returning a new
986 * optional reference that is `Some` only if all 4 option values are
987 * `Some`, otherwise it returns a `None`.
988 *
989 * ```typescript
990 * // Yields Some(10)
991 * Option.map4(Some(1), Some(2), Some(3), Some(4),
992 * (a, b, c, d) => a + b + c + d
993 * )
994 *
995 * // Yields None, because the second arg is None
996 * Option.map4(Some(1), None, Some(3), Some(4),
997 * (a, b, c, d) => a + b + c + d
998 * )
999 * ```
1000 */
1001 static map4<A1,A2,A3,A4,R>(
1002 fa1: Option<A1>, fa2: Option<A2>, fa3: Option<A3>, fa4: Option<A4>,
1003 f: (a1: A1, a2: A2, a3: A3, a4: A4) => R): Option<R> {
1004
1005 return fa1.nonEmpty() && fa2.nonEmpty() && fa3.nonEmpty() && fa4.nonEmpty()
1006 ? Some(f(fa1.value, fa2.value, fa3.value, fa4.value))
1007 : None
1008 }
1009
1010 /**
1011 * Maps 5 optional values by the mapping function, returning a new
1012 * optional reference that is `Some` only if all 5 option values are
1013 * `Some`, otherwise it returns a `None`.
1014 *
1015 * ```typescript
1016 * // Yields Some(15)
1017 * Option.map5(Some(1), Some(2), Some(3), Some(4), Some(5),
1018 * (a, b, c, d, e) => a + b + c + d + e
1019 * )
1020 *
1021 * // Yields None, because the second arg is None
1022 * Option.map5(Some(1), None, Some(3), Some(4), Some(5),
1023 * (a, b, c, d, e) => a + b + c + d + e
1024 * )
1025 * ```
1026 */
1027 static map5<A1,A2,A3,A4,A5,R>(
1028 fa1: Option<A1>, fa2: Option<A2>, fa3: Option<A3>, fa4: Option<A4>, fa5: Option<A5>,
1029 f: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5) => R): Option<R> {
1030
1031 return fa1.nonEmpty() && fa2.nonEmpty() && fa3.nonEmpty() && fa4.nonEmpty() && fa5.nonEmpty()
1032 ? Some(f(fa1.value, fa2.value, fa3.value, fa4.value, fa5.value))
1033 : None
1034 }
1035
1036 /**
1037 * Maps 6 optional values by the mapping function, returning a new
1038 * optional reference that is `Some` only if all 6 option values are
1039 * `Some`, otherwise it returns a `None`.
1040 *
1041 * ```typescript
1042 * // Yields Some(21)
1043 * Option.map6(Some(1), Some(2), Some(3), Some(4), Some(5), Some(6),
1044 * (a, b, c, d, e, f) => a + b + c + d + e + f
1045 * )
1046 *
1047 * // Yields None, because the second arg is None
1048 * Option.map6(Some(1), None, Some(3), Some(4), Some(5), Some(6),
1049 * (a, b, c, d, e, f) => a + b + c + d + e + f
1050 * )
1051 * ```
1052 */
1053 static map6<A1,A2,A3,A4,A5,A6,R>(
1054 fa1: Option<A1>, fa2: Option<A2>, fa3: Option<A3>, fa4: Option<A4>, fa5: Option<A5>, fa6: Option<A6>,
1055 f: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6) => R): Option<R> {
1056
1057 return fa1.nonEmpty() && fa2.nonEmpty() && fa3.nonEmpty() && fa4.nonEmpty() && fa5.nonEmpty() && fa6.nonEmpty()
1058 ? Some(f(fa1.value, fa2.value, fa3.value, fa4.value, fa5.value, fa6.value))
1059 : None
1060 }
1061
1062 /**
1063 * Keeps calling `f` until a `Right(b)` is returned.
1064 *
1065 * Based on Phil Freeman's
1066 * [Stack Safety for Free]{@link http://functorial.com/stack-safety-for-free/index.pdf}.
1067 *
1068 * Described in `FlatMap.tailRecM`.
1069 */
1070 static tailRecM<A, B>(a: A, f: (a: A) => Option<Either<A, B>>): Option<B> {
1071 let cursor = a
1072 while (true) {
1073 const result = f(cursor)
1074 if (result.nonEmpty()) {
1075 const some = result.value
1076 if (some.isRight()) return Some(some.value)
1077 cursor = some.value as A
1078 } else {
1079 return None
1080 }
1081 }
1082 }
1083}
1084
1085/**
1086 * Result of the [[Some]] data constructor, representing
1087 * non-empty values in the [[Option]] disjunction.
1088 */
1089export class TSome<A> extends Option<A> {
1090 public readonly value!: A
1091 constructor(value: A) { super(value, false) }
1092}
1093
1094/**
1095 * The `Some<A>` data constructor for [[Option]] represents existing
1096 * values of type `A`.
1097 *
1098 * Using this function is equivalent with [[Option.some]].
1099 */
1100export function Some<A>(value: A): TSome<A> {
1101 return new TSome(value)
1102}
1103
1104/**
1105 * Result of the [[Some]] data constructor, representing
1106 * non-empty values in the [[Option]] disjunction.
1107 */
1108export class TNone extends Option<never> {
1109 public readonly value!: undefined
1110 private constructor() { super(undefined, true) }
1111}
1112
1113/**
1114 * The `None` data constructor for [[Option]] represents non-existing
1115 * values for any type.
1116 *
1117 * Using this reference directly is equivalent with [[Option.none]].
1118 */
1119export const None: TNone =
1120 new (TNone as any)()
1121
1122/**
1123 * Type enumerating the type classes implemented by `Option`.
1124 */
1125export type OptionTypes =
1126 Setoid<Option<any>> &
1127 Monad<"funfix/option">
1128
1129/**
1130 * Type-class implementations, compatible with the `static-land`
1131 * and `funland` specification.
1132 *
1133 * See [funland-js.org](https://funland-js.org).
1134 */
1135export const OptionModule: OptionTypes = {
1136 // Setoid
1137 equals: (x, y) => x ? x.equals(y) : !y,
1138 // Functor
1139 map: <A, B>(f: (a: A) => B, fa: Option<A>) =>
1140 fa.map(f),
1141 // Apply
1142 ap: <A, B>(ff: Option<(a: A) => B>, fa: Option<A>): Option<B> =>
1143 fa.ap(ff),
1144 // Applicative
1145 of: Option.pure,
1146 // Chain
1147 chain: <A, B>(f: (a: A) => Option<B>, fa: Option<A>): Option<B> =>
1148 fa.flatMap(f),
1149 // ChainRec
1150 chainRec: <A, B>(f: <C>(next: (a: A) => C, done: (b: B) => C, a: A) => Option<C>, a: A): Option<B> =>
1151 Option.tailRecM(a, a => f(Either.left as any, Either.right as any, a))
1152}
1153
1154// Registers Fantasy-Land compatible symbols
1155fantasyLandRegister(Option, OptionModule, OptionModule)
1156
1157/**
1158 * The `Try` type represents a computation that may either result in an
1159 * exception, or return a successfully computed value. It's similar to,
1160 * but semantically different from the [[Either]] type.
1161 *
1162 * `Try` is a sum type and so instances of `Try` are either instances
1163 * of [[Success]] or of [[Failure]].
1164 *
1165 * For example, `Try` can be used to perform division on a user-defined
1166 * input, without the need to do explicit exception-handling in all of
1167 * the places that an exception might occur.
1168 *
1169 * Example:
1170 *
1171 * ```typescript
1172 * function divide(dividendS: string, divisorS: string): string {
1173 * const dividend = Try(() => parseInt(dividendS))
1174 * .filter(_ => _ === _) // filter out NaN
1175 * const divisor = Try(() => parseInt(divisorS))
1176 * .filter(_ => _ === _) // filter out NaN
1177 *
1178 * // map2 executes the given function only if both results are
1179 * // successful; we could also express this with flatMap / chain
1180 * const result = Try.map2(dividend, divisor,
1181 * (a, b) => a / b
1182 * )
1183 *
1184 * result.fold(
1185 * error => `failure: ${error}`
1186 * result => `result: ${result}`
1187 * )
1188 * }
1189 * ```
1190 *
1191 * An important property of `Try` is its ability to pipeline, or chain,
1192 * operations, catching exceptions along the way. The `flatMap` and `map`
1193 * combinators each essentially pass off either their successfully completed
1194 * value, wrapped in the [[Success]] type for it to be further operated upon
1195 * by the next combinator in the chain, or the exception wrapped in the
1196 * [[Failure]] type usually to be simply passed on down the chain.
1197 * Combinators such as `recover` and `recoverWith` are designed to provide
1198 * some type of global behavior in the case of failure.
1199 *
1200 * NOTE: all `Try` combinators will catch exceptions and return failure
1201 * unless otherwise specified in the documentation.
1202 */
1203export class Try<A> implements std.IEquals<Try<A>>, HK<"funfix/try", A> {
1204 private _isSuccess: boolean
1205 public readonly value: Throwable | A
1206
1207 protected constructor(value: Throwable | A, tag: "failure" | "success") {
1208 this._isSuccess = tag === "success"
1209 this.value = value
1210 }
1211
1212 /**
1213 * Returns `true` if the source is a [[Success]] result,
1214 * or `false` in case it is a [[Failure]].
1215 */
1216 isSuccess(): this is TSuccess<A> { return this._isSuccess }
1217
1218 /**
1219 * Returns `true` if the source is a [[Failure]],
1220 * or `false` in case it is a [[Success]] result.
1221 */
1222 isFailure(): this is TFailure { return !this._isSuccess }
1223
1224 /**
1225 * Returns a Try's successful value if it's a [[Success]] reference,
1226 * otherwise throws an exception if it's a [[Failure]].
1227 *
1228 * WARNING!
1229 *
1230 * This function is partial, the option must be non-empty, otherwise
1231 * a runtime exception will get thrown. Use with care.
1232 */
1233 get(): A {
1234 if (!this._isSuccess) throw this.value
1235 return this.value as A
1236 }
1237
1238 /**
1239 * Returns the value from a `Success` or the given `fallback`
1240 * value if this is a `Failure`.
1241 *
1242 * ```typescript
1243 * Success(10).getOrElse(27) // 10
1244 * Failure("error").getOrElse(27) // 27
1245 * ```
1246 */
1247 getOrElse<AA>(fallback: AA): A | AA {
1248 return this._isSuccess ? this.value as A : fallback
1249 }
1250
1251 /**
1252 * Returns the value from a `Success` or the value generated
1253 * by a given `thunk` in case this is a `Failure`.
1254 *
1255 * ```typescript
1256 * Success(10).getOrElseL(() => 27) // 10
1257 * Failure("error").getOrElseL(() => 27) // 27
1258 * ```
1259 */
1260 getOrElseL<AA>(thunk: () => AA): A | AA {
1261 return this._isSuccess ? this.value as A : thunk()
1262 }
1263
1264 /**
1265 * Returns the current value if it's a [[Success]], or
1266 * if the source is a [[Failure]] then return `null`.
1267 *
1268 * ```typescript
1269 * Success(10).orNull() // 10
1270 * Failure("error").orNull() // null
1271 * ```
1272 *
1273 * This can be useful for use-cases such as:
1274 *
1275 * ```typescript
1276 * Try.of(() => dict.user.profile.name).orNull()
1277 * ```
1278 */
1279 orNull(): A | null {
1280 return this._isSuccess ? this.value as A : null
1281 }
1282
1283 /**
1284 * Returns the current value if it's a [[Success]], or
1285 * if the source is a [[Failure]] then return `undefined`.
1286 *
1287 * ```typescript
1288 * Success(10).orUndefined() // 10
1289 * Failure("error").orUndefined() // undefined
1290 * ```
1291 *
1292 * This can be useful for use-cases such as:
1293 *
1294 * ```typescript
1295 * Try.of(() => dict.user.profile.name).orUndefined()
1296 * ```
1297 */
1298 orUndefined(): A | undefined {
1299 return this._isSuccess ? this.value as A : undefined
1300 }
1301
1302 /**
1303 * Returns the current value if it's a [[Success]], or if
1304 * the source is a [[Failure]] then return the `fallback`.
1305 *
1306 * ```typescript
1307 * Success(10).orElse(Success(17)) // 10
1308 * Failure("error").orElse(Success(17)) // 17
1309 * ```
1310 */
1311 orElse<AA>(fallback: Try<AA>): Try<A | AA> {
1312 if (this._isSuccess) return this
1313 return fallback
1314 }
1315
1316 /**
1317 * Returns the current value if it's a [[Success]], or if the source
1318 * is a [[Failure]] then return the value generated by the given
1319 * `thunk`.
1320 *
1321 * ```typescript
1322 * Success(10).orElseL(() => Success(17)) // 10
1323 * Failure("error").orElseL(() => Success(17)) // 17
1324 * ```
1325 */
1326 orElseL<AA>(thunk: () => Try<AA>): Try<A | AA> {
1327 if (this._isSuccess) return this
1328 return thunk()
1329 }
1330
1331 /**
1332 * Inverts this `Try`. If this is a [[Failure]], returns its exception wrapped
1333 * in a [[Success]]. If this is a `Success`, returns a `Failure` containing a
1334 * [[NoSuchElementError]].
1335 */
1336 failed(): Try<Throwable> {
1337 return this._isSuccess
1338 ? Failure(new NoSuchElementError("try.failed()"))
1339 : Success(this.value as Throwable)
1340 }
1341
1342 /**
1343 * Applies the `failure` function to [[Failure]] values, and the
1344 * `success` function to [[Success]] values and returns the result.
1345 *
1346 * ```typescript
1347 * const maybeNum: Try<number> =
1348 * tryParseInt("not a number")
1349 *
1350 * const result: string =
1351 * maybeNum.fold(
1352 * error => `Could not parse string: ${error}`,
1353 * num => `Success: ${num}`
1354 * )
1355 * ```
1356 */
1357 fold<R>(failure: (error: Throwable) => R, success: (a: A) => R): R {
1358 return this._isSuccess
1359 ? success(this.value as A)
1360 : failure(this.value as Throwable)
1361 }
1362
1363 /**
1364 * Returns a [[Failure]] if the source is a [[Success]], but the
1365 * given `p` predicate is not satisfied.
1366 *
1367 * @throws NoSuchElementError in case the predicate doesn't hold
1368 */
1369 filter<B extends A>(p: (a: A) => a is B): Try<B>
1370 filter(p: (a: A) => boolean): Try<A>
1371 filter(p: (a: A) => boolean): Try<A> {
1372 if (!this._isSuccess) return this
1373 try {
1374 if (p(this.value as A)) return this
1375 return Failure(
1376 new NoSuchElementError(
1377 `Predicate does not hold for ${this.value as A}`
1378 ))
1379 } catch (e) {
1380 return Failure(e)
1381 }
1382 }
1383
1384 /**
1385 * Returns the given function applied to the value if this is
1386 * a [[Success]] or returns `this` if this is a [[Failure]].
1387 *
1388 * This operation is the monadic "bind" operation.
1389 * It can be used to *chain* multiple `Try` references.
1390 *
1391 * ```typescript
1392 * Try.of(() => parse(s1)).flatMap(num1 =>
1393 * Try.of(() => parse(s2)).map(num2 =>
1394 * num1 / num2
1395 * ))
1396 * ```
1397 */
1398 flatMap<B>(f: (a: A) => Try<B>): Try<B> {
1399 if (!this._isSuccess) return this as any
1400 try {
1401 return f(this.value as A)
1402 } catch (e) {
1403 return Failure(e)
1404 }
1405 }
1406
1407 /** Alias for [[flatMap]]. */
1408 chain<B>(f: (a: A) => Try<B>): Try<B> {
1409 return this.flatMap(f)
1410 }
1411
1412 /**
1413 * `Applicative` apply operator.
1414 *
1415 * Resembles {@link map}, but the passed mapping function is
1416 * lifted in the `Either` context.
1417 */
1418 ap<B>(ff: Try<(a: A) => B>): Try<B> {
1419 return ff.flatMap(f => this.map(f))
1420 }
1421
1422 /**
1423 * Returns a `Try` containing the result of applying `f` to
1424 * this option's value, but only if it's a `Success`, or
1425 * returns the current `Failure` without any modifications.
1426 *
1427 * NOTE: this is similar with `flatMap`, except with `map` the
1428 * result of `f` doesn't need to be wrapped in a `Try`.
1429 *
1430 * @param f the mapping function that will transform the value
1431 * of this `Try` if successful.
1432 *
1433 * @return a new `Try` instance containing the value of the
1434 * source mapped by the given function
1435 */
1436 map<B>(f: (a: A) => B): Try<B> {
1437 return this._isSuccess
1438 ? Try.of(() => f(this.value as A))
1439 : ((this as any) as Try<B>)
1440 }
1441
1442 /**
1443 * Applies the given function `cb` if this is a [[Success]], otherwise
1444 * returns `void` if this is a [[Failure]].
1445 */
1446 forEach(cb: (a: A) => void): void {
1447 if (this._isSuccess) cb(this.value as A)
1448 }
1449
1450 /**
1451 * Applies the given function `f` if this is a `Failure`, otherwise
1452 * returns `this` if this is a `Success`.
1453 *
1454 * This is like `map` for the exception.
1455 *
1456 * In the following example, if the `user.profile.email` exists,
1457 * then it is returned as a successful value, otherwise
1458 *
1459 * ```typescript
1460 * Try.of(() => user.profile.email).recover(e => {
1461 * // Access error? Default to empty.
1462 * if (e instanceof TypeError) return ""
1463 * throw e // We don't know what it is, rethrow
1464 * })
1465 *
1466 * Note that on rethrow, the error is being caught in `recover` and
1467 * it still returns it as a `Failure(e)`.
1468 * ```
1469 */
1470 recover<AA>(f: (error: Throwable) => AA): Try<A | AA> {
1471 return this._isSuccess
1472 ? this
1473 : Try.of(() => f(this.value as Throwable))
1474 }
1475
1476 /**
1477 * Applies the given function `f` if this is a `Failure`, otherwise
1478 * returns `this` if this is a `Success`.
1479 *
1480 * This is like `map` for the exception.
1481 *
1482 * In the following example, if the `user.profile.email` exists,
1483 * then it is returned as a successful value, otherwise
1484 *
1485 * ```typescript
1486 * Try.of(() => user.profile.email).recover(e => {
1487 * // Access error? Default to empty.
1488 * if (e instanceof TypeError) return ""
1489 * throw e // We don't know what it is, rethrow
1490 * })
1491 *
1492 * Note that on rethrow, the error is being caught in `recover` and
1493 * it still returns it as a `Failure(e)`.
1494 * ```
1495 */
1496 recoverWith<AA>(f: (error: Throwable) => Try<AA>): Try<A | AA> {
1497 try {
1498 return this._isSuccess ? this : f(this.value as Throwable)
1499 } catch (e) {
1500 return Failure(e)
1501 }
1502 }
1503
1504 /**
1505 * Transforms the source into an [[Option]].
1506 *
1507 * In case the source is a `Success(v)`, then it gets translated
1508 * into a `Some(v)`. If the source is a `Failure(e)`, then a `None`
1509 * value is returned.
1510 *
1511 * ```typescript
1512 * Success("value").toOption() // Some("value")
1513 * Failure("error").toOption() // None
1514 * ```
1515 */
1516 toOption(): Option<A> {
1517 return this._isSuccess ? Some(this.value as A) : None
1518 }
1519
1520 /**
1521 * Transforms the source into an [[Either]].
1522 *
1523 * In case the source is a `Success(v)`, then it gets translated
1524 * into a `Right(v)`. If the source is a `Failure(e)`, then a `Left(e)`
1525 * value is returned.
1526 *
1527 * ```typescript
1528 * Success("value").toEither() // Right("value")
1529 * Failure("error").toEither() // Left("error")
1530 * ```
1531 */
1532 toEither(): Either<Throwable, A> {
1533 return this._isSuccess
1534 ? Right(this.value as A)
1535 : Left(this.value as Throwable)
1536 }
1537
1538 /**
1539 * Implements {@link IEquals.equals} with overridable equality for `A`.
1540 */
1541 equals(that: Try<A>): boolean {
1542 // tslint:disable-next-line:strict-type-predicates
1543 if (that == null) return false
1544 return this._isSuccess
1545 ? that._isSuccess && std.is(this.value as A, that.value as A)
1546 : !that._isSuccess && std.is(this.value, that.value)
1547 }
1548
1549 // Implemented from IEquals
1550 hashCode(): number {
1551 return this._isSuccess
1552 ? std.hashCode(this.value as A)
1553 : std.hashCode(this.value as Throwable)
1554 }
1555
1556 // Implements HK<F, A>
1557 /** @hidden */ readonly _URI!: "funfix/try"
1558 /** @hidden */ readonly _A!: A
1559
1560 // Implements Constructor<T>
1561 /** @hidden */ static readonly _Class: Try<any>
1562
1563 /**
1564 * Evaluates the given `thunk` and returns either a [[Success]],
1565 * in case the evaluation succeeded, or a [[Failure]], in case
1566 * an exception was thrown.
1567 *
1568 * Example:
1569 *
1570 * ```typescript
1571 * let effect = 0
1572 *
1573 * const e = Try.of(() => { effect += 1; return effect })
1574 * e.get() // 1
1575 * ```
1576 */
1577 static of<A>(thunk: () => A): Try<A> {
1578 try {
1579 return Success(thunk())
1580 } catch (e) {
1581 return Failure(e)
1582 }
1583 }
1584
1585 /** Alias of [[Try.success]]. */
1586 static pure<A>(value: A): Try<A> {
1587 return Try.success(value)
1588 }
1589
1590 /**
1591 * Shorthand for `now(undefined as void)`, always returning
1592 * the same reference as optimization.
1593 */
1594 static unit(): Try<void> {
1595 return tryUnitRef
1596 }
1597
1598 /**
1599 * Returns a [[Try]] reference that represents a successful result
1600 * (i.e. wrapped in [[Success]]).
1601 */
1602 static success<A>(value: A): Try<A> {
1603 return Success(value)
1604 }
1605
1606 /**
1607 * Returns a [[Try]] reference that represents a failure
1608 * (i.e. an exception wrapped in [[Failure]]).
1609 */
1610 static failure<A = never>(e: Throwable): Try<A> {
1611 return Failure(e)
1612 }
1613
1614 /**
1615 * Alias for {@link Try.failure} and {@link Failure},
1616 * wrapping any throwable into a `Try` value.
1617 */
1618 static raise<A = never>(e: Throwable): Try<A> {
1619 return Failure(e)
1620 }
1621
1622 /**
1623 * Maps 2 `Try` values by the mapping function, returning a new
1624 * `Try` reference that is a `Success` only if both `Try` values are
1625 * a `Success`, otherwise it returns the first `Failure` noticed.
1626 *
1627 * ```typescript
1628 * // Yields Success(3)
1629 * Try.map2(Success(1), Success(2),
1630 * (a, b) => a + b
1631 * )
1632 *
1633 * // Yields Failure, because the second arg is a Failure
1634 * Try.map2(Success(1), Failure("error"),
1635 * (a, b) => a + b
1636 * )
1637 * ```
1638 *
1639 * This operation is the `Applicative.map2`.
1640 */
1641 static map2<A1,A2,R>(
1642 fa1: Try<A1>, fa2: Try<A2>,
1643 f: (a1: A1, a2: A2) => R): Try<R> {
1644
1645 if (fa1.isFailure()) return fa1
1646 if (fa2.isFailure()) return fa2
1647 try {
1648 return Success(f(fa1.value as A1, fa2.value as A2))
1649 } catch (e) {
1650 return Failure(e)
1651 }
1652 }
1653
1654 /**
1655 * Maps 3 `Try` values by the mapping function, returning a new
1656 * `Try` reference that is a `Success` only if all 3 `Try` values are
1657 * a `Success`, otherwise it returns the first `Failure` noticed.
1658 *
1659 * ```typescript
1660 * // Yields Success(6)
1661 * Try.map3(Success(1), Success(2), Success(3),
1662 * (a, b, c) => {
1663 * return a + b + c
1664 * }
1665 * )
1666 *
1667 * // Yields Failure, because the second arg is a Failure
1668 * Try.map3(
1669 * Success(1),
1670 * Failure("error"),
1671 * Success(3),
1672 *
1673 * (a, b, c) => {
1674 * return a + b + c
1675 * }
1676 * )
1677 * ```
1678 */
1679 static map3<A1,A2,A3,R>(
1680 fa1: Try<A1>, fa2: Try<A2>, fa3: Try<A3>,
1681 f: (a1: A1, a2: A2, a3: A3) => R): Try<R> {
1682
1683 if (fa1.isFailure()) return fa1
1684 if (fa2.isFailure()) return fa2
1685 if (fa3.isFailure()) return fa3
1686 try {
1687 return Success(f(
1688 fa1.value as A1,
1689 fa2.value as A2,
1690 fa3.value as A3
1691 ))
1692 } catch (e) {
1693 return Failure(e)
1694 }
1695 }
1696
1697 /**
1698 * Maps 4 `Try` values by the mapping function, returning a new
1699 * `Try` reference that is a `Success` only if all 4 `Try` values are
1700 * a `Success`, otherwise it returns the first `Failure` noticed.
1701 *
1702 * ```typescript
1703 * // Yields Success(10)
1704 * Try.map4(Success(1), Success(2), Success(3), Success(4),
1705 * (a, b, c, d) => {
1706 * return a + b + c + d
1707 * }
1708 * )
1709 *
1710 * // Yields Failure, because the second arg is a Failure
1711 * Try.map3(
1712 * Success(1),
1713 * Failure("error"),
1714 * Success(3),
1715 * Success(4),
1716 *
1717 * (a, b, c, d) => {
1718 * return a + b + c + d
1719 * }
1720 * )
1721 * ```
1722 */
1723 static map4<A1,A2,A3,A4,R>(
1724 fa1: Try<A1>, fa2: Try<A2>, fa3: Try<A3>, fa4: Try<A4>,
1725 f: (a1: A1, a2: A2, a3: A3, a4: A4) => R): Try<R> {
1726
1727 if (fa1.isFailure()) return fa1
1728 if (fa2.isFailure()) return fa2
1729 if (fa3.isFailure()) return fa3
1730 if (fa4.isFailure()) return fa4
1731 try {
1732 return Success(f(
1733 fa1.value as A1,
1734 fa2.value as A2,
1735 fa3.value as A3,
1736 fa4.value as A4
1737 ))
1738 } catch (e) {
1739 return Failure(e)
1740 }
1741 }
1742
1743 /**
1744 * Maps 5 `Try` values by the mapping function, returning a new
1745 * `Try` reference that is a `Success` only if all 5 `Try` values are
1746 * a `Success`, otherwise it returns the first `Failure` noticed.
1747 *
1748 * ```typescript
1749 * // Yields Success(15)
1750 * Try.map5(
1751 * Success(1),
1752 * Success(2),
1753 * Success(3),
1754 * Success(4),
1755 * Success(5),
1756 *
1757 * (a, b, c, d, e) => {
1758 * return a + b + c + d + e
1759 * }
1760 * )
1761 *
1762 * // Yields Failure, because the second arg is a Failure
1763 * Try.map5(
1764 * Success(1),
1765 * Failure("error"),
1766 * Success(3),
1767 * Success(4),
1768 * Success(5),
1769 *
1770 * (a, b, c, d, e) => {
1771 * return a + b + c + d + e
1772 * }
1773 * )
1774 * ```
1775 */
1776 static map5<A1,A2,A3,A4,A5,R>(
1777 fa1: Try<A1>, fa2: Try<A2>, fa3: Try<A3>, fa4: Try<A4>, fa5: Try<A5>,
1778 f: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5) => R): Try<R> {
1779
1780 if (fa1.isFailure()) return fa1
1781 if (fa2.isFailure()) return fa2
1782 if (fa3.isFailure()) return fa3
1783 if (fa4.isFailure()) return fa4
1784 if (fa5.isFailure()) return fa5
1785 try {
1786 return Success(f(
1787 fa1.value as A1,
1788 fa2.value as A2,
1789 fa3.value as A3,
1790 fa4.value as A4,
1791 fa5.value as A5
1792 ))
1793 } catch (e) {
1794 return Failure(e)
1795 }
1796 }
1797
1798 /**
1799 * Maps 6 `Try` values by the mapping function, returning a new
1800 * `Try` reference that is a `Success` only if all 6 `Try` values are
1801 * a `Success`, otherwise it returns the first `Failure` noticed.
1802 *
1803 * ```typescript
1804 * // Yields Success(21)
1805 * Try.map6(
1806 * Success(1),
1807 * Success(2),
1808 * Success(3),
1809 * Success(4),
1810 * Success(5),
1811 * Success(6),
1812 *
1813 * (a, b, c, d, e, f) => {
1814 * return a + b + c + d + e + f
1815 * }
1816 * )
1817 *
1818 * // Yields Failure, because the second arg is a Failure
1819 * Try.map6(
1820 * Success(1),
1821 * Failure("error"),
1822 * Success(3),
1823 * Success(4),
1824 * Success(5),
1825 * Success(6),
1826 *
1827 * (a, b, c, d, e, f) => {
1828 * return a + b + c + d + e + f
1829 * }
1830 * )
1831 * ```
1832 */
1833 static map6<A1,A2,A3,A4,A5,A6,R>(
1834 fa1: Try<A1>, fa2: Try<A2>, fa3: Try<A3>, fa4: Try<A4>, fa5: Try<A5>, fa6: Try<A6>,
1835 f: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6) => R): Try<R> {
1836
1837 if (fa1.isFailure()) return fa1
1838 if (fa2.isFailure()) return fa2
1839 if (fa3.isFailure()) return fa3
1840 if (fa4.isFailure()) return fa4
1841 if (fa5.isFailure()) return fa5
1842 if (fa6.isFailure()) return fa6
1843 try {
1844 return Success(f(
1845 fa1.value as A1,
1846 fa2.value as A2,
1847 fa3.value as A3,
1848 fa4.value as A4,
1849 fa5.value as A5,
1850 fa6.value as A6
1851 ))
1852 } catch (e) {
1853 return Failure(e)
1854 }
1855 }
1856
1857 /**
1858 * Keeps calling `f` until a `Right(b)` is returned.
1859 *
1860 * Based on Phil Freeman's
1861 * [Stack Safety for Free]{@link http://functorial.com/stack-safety-for-free/index.pdf}.
1862 *
1863 * Described in `FlatMap.tailRecM`.
1864 */
1865 static tailRecM<A, B>(a: A, f: (a: A) => Try<Either<A, B>>): Try<B> {
1866 let cursor = a
1867 while (true) {
1868 try {
1869 const result = f(cursor)
1870 if (result.isFailure()) return result as any
1871
1872 const some = result.get()
1873 if (some.isRight()) return Success(some.value)
1874 cursor = some.value as A
1875 } catch (e) {
1876 return Failure(e)
1877 }
1878 }
1879 }
1880}
1881
1882/**
1883 * Result of the [[Success]] data constructor, representing
1884 * successful values in the [[Try]] disjunction.
1885 *
1886 * @final
1887 */
1888export class TSuccess<A> extends Try<A> {
1889 public readonly value!: A
1890 constructor(value: A) { super(value, "success") }
1891}
1892
1893/**
1894 * The `Success` data constructor is for building [[Try]] values that
1895 * are successful results of computations, as opposed to [[Failure]].
1896 */
1897export function Success<A>(value: A): Try<A> {
1898 return new TSuccess(value)
1899}
1900
1901/**
1902 * The `Success` data constructor is for building [[Try]] values that
1903 * are successful results of computations, as opposed to [[Failure]].
1904 *
1905 * @final
1906 */
1907export class TFailure extends Try<never> {
1908 public readonly value!: Throwable
1909 constructor(value: Throwable) { super(value, "failure") }
1910}
1911
1912/**
1913 * The `Failure` data constructor is for building [[Try]] values that
1914 * represent failures, as opposed to [[Success]].
1915 */
1916export function Failure(e: Throwable): Try<never> {
1917 return new TFailure(e)
1918}
1919
1920/**
1921 * Type enumerating the type classes implemented by `Try`.
1922 */
1923export type TryTypes =
1924 Setoid<Try<any>> &
1925 Monad<"funfix/try">
1926
1927/**
1928 * Type-class implementations, compatible with the `static-land`
1929 * and `funland` specifications.
1930 *
1931 * See [funland-js.org](https://funland-js.org).
1932 */
1933export const TryModule: TryTypes = {
1934 // Setoid
1935 equals: (x, y) => x ? x.equals(y) : !y,
1936 // Functor
1937 map: <A, B>(f: (a: A) => B, fa: Try<A>) =>
1938 fa.map(f),
1939 // Apply
1940 ap: <A, B>(ff: Try<(a: A) => B>, fa: Try<A>): Try<B> =>
1941 fa.ap(ff),
1942 // Applicative
1943 of: Try.pure,
1944 // Chain
1945 chain: <A, B>(f: (a: A) => Try<B>, fa: Try<A>): Try<B> =>
1946 fa.flatMap(f),
1947 // ChainRec
1948 chainRec: <A, B>(f: <C>(next: (a: A) => C, done: (b: B) => C, a: A) => Try<C>, a: A): Try<B> =>
1949 Try.tailRecM(a, a => f(Either.left as any, Either.right as any, a))
1950}
1951
1952// Registers Fantasy-Land compatible symbols
1953fantasyLandRegister(Try, TryModule, TryModule)
1954
1955/**
1956 * Reusable reference, to use in {@link Try.unit}.
1957 *
1958 * @private
1959 * @hidden
1960 */
1961const tryUnitRef: Try<void> = Success(undefined)
1962
\No newline at end of file