Ramda Adjunct 5.0.0

fantasy-land/Identity.js

import { empty as emptyR } from 'ramda';

import * as fl from './mapping.js';
import {
  applyTrait,
  functorTrait,
  setoidTrait,
  semigroupTrait,
  chainTrait,
  ordTrait,
} from './traits.js';

/**
 * The simplest {@link https://github.com/fantasyland/fantasy-land|fantasy-land}
 * compatible monad which attaches no information to values.
 *
 * The Identity type is a very simple type that has no interesting side effects and
 * is effectively just a container of some value. So why does it exist ?
 * The Identity type is often used as the base monad of a monad
 * transformer when no other behaviour is required.
 *
 * @memberOf RA
 * @implements
 * {@link https://github.com/fantasyland/fantasy-land#apply|Apply},
 * {@link https://github.com/fantasyland/fantasy-land#applicative|Applicative},
 * {@link https://github.com/fantasyland/fantasy-land#functor|Functor},
 * {@link https://github.com/fantasyland/fantasy-land#setoid|Setoid},
 * {@link https://github.com/fantasyland/fantasy-land#semigroup|Semigroup},
 * {@link https://github.com/fantasyland/fantasy-land#chain|Chain},
 * {@link https://github.com/fantasyland/fantasy-land#monad|Monad},
 * {@link https://github.com/fantasyland/fantasy-land#ord|Ord},
 * {@link https://github.com/fantasyland/fantasy-land#monoid|Monoid*},
 * {@link https://github.com/fantasyland/fantasy-land#contravariant|Contravariant}
 * @since {@link https://char0n.github.io/ramda-adjunct/1.8.0|v1.8.0}
 */
class Identity {
  /**
   * Fantasy land {@link https://github.com/fantasyland/fantasy-land#applicative|Applicative} specification.
   *
   * @static
   * @sig of :: Applicative f => a -> f a
   * @param {*} value
   * @returns {RA.Identity}
   * @example
   *
   * const a = Identity.of(1); //=> Identity(1)
   */
  static [fl.of](value) {
    return new Identity(value);
  }

  static of(value) {
    return new Identity(value);
  }

  /**
   * @static
   */
  static get ['@@type']() {
    return 'RA/Identity';
  }

  /**
   * Private constructor. Use {@link RA.Identity.of|Identity.of} instead.
   *
   * @param {*} value
   * @return {RA.Identity}
   */
  constructor(value) {
    this.value = value;
  }

  /**
   * Catamorphism for a value.
   * @returns {*}
   * @example
   *
   * const a = Identity.of(1);
   * a.get(); //=> 1
   */
  get() {
    return this.value;
  }

  /**
   * Fantasy land {@link https://github.com/fantasyland/fantasy-land#apply|Apply} specification.
   *
   * @sig ap :: Apply f => f a ~> f (a -> b) -> f b
   * @param {RA.Identity} applyWithFn
   * @return {RA.Identity}
   * @example
   *
   * const a = Identity.of(1);
   * const b = Identity.of(1).map(a => b => a + b);
   *
   * a.ap(b); //=> Identity(2)
   */
  [fl.ap](applyWithFn) {
    return applyTrait[fl.ap].call(this, applyWithFn);
  }

  ap(applyWithFn) {
    return this[fl.ap](applyWithFn);
  }

  /**
   * Fantasy land {@link https://github.com/fantasyland/fantasy-land#functor|Functor} specification.
   *
   * @sig map :: Functor f => f a ~> (a -> b) -> f b
   * @param {Function} fn
   * @return {RA.Identity}
   * @example
   *
   * const a = Identity.of(1);
   * a.map(a => a + 1); //=> Identity(2)
   */
  [fl.map](fn) {
    return functorTrait[fl.map].call(this, fn);
  }

  map(fn) {
    return this[fl.map](fn);
  }

  /**
   * Fantasy land {@link https://github.com/fantasyland/fantasy-land#setoid|Setoid} specification.
   *
   * @sig equals :: Setoid a => a ~> a -> Boolean
   * @param {RA.Identity} setoid
   * @return {boolean}
   * @example
   *
   * const a = Identity.of(1);
   * const b = Identity.of(1);
   * const c = Identity.of(2);
   *
   * a.equals(b); //=> true
   * a.equals(c); //=> false
   */
  [fl.equals](setoid) {
    return setoidTrait[fl.equals].call(this, setoid);
  }

  equals(setoid) {
    return this[fl.equals](setoid);
  }

  /**
   * Fantasy land {@link https://github.com/fantasyland/fantasy-land#semigroup|Semigroup} specification.
   *
   * @sig concat :: Semigroup a => a ~> a -> a
   * @param {RA.Identity} semigroup
   * @return {RA.Identity}
   * @example
   *
   * const a = Identity.of(1);
   * const b = Identity.of(1);
   * a.concat(b); //=> 2
   *
   * const c = Identity.of('c');
   * const d = Identity.of('d');
   * c.concat(d); //=> 'cd'
   *
   * const e = Identity.of(['e']);
   * const f = Identity.of(['f']);
   * e.concat(f); //=> ['e', 'f']
   */
  [fl.concat](semigroup) {
    return semigroupTrait[fl.concat].call(this, semigroup);
  }

  concat(semigroup) {
    return this[fl.concat](semigroup);
  }

  /**
   * Fantasy land {@link https://github.com/fantasyland/fantasy-land#chain|Chain} specification.
   *
   * @sig chain :: Chain m => m a ~> (a -> m b) -> m b
   * @param {Function} fn Function returning the value of the same {@link https://github.com/fantasyland/fantasy-land#semigroup|Chain}
   * @return {RA.Identity}
   * @example
   *
   * const a = Identity.of(1);
   * const fn = val => Identity.of(val + 1);
   *
   * a.chain(fn).chain(fn); //=> Identity(3)
   */
  [fl.chain](fn) {
    return chainTrait[fl.chain].call(this, fn);
  }

  chain(fn) {
    return this[fl.chain](fn);
  }

  /**
   * Fantasy land {@link https://github.com/fantasyland/fantasy-land#ord|Ord} specification.
   *
   * @sig lte :: Ord a => a ~> a -> Boolean
   * @param {RA.Identity} ord
   * @return {boolean}
   * @example
   *
   * const a = Identity.of(1);
   * const b = Identity.of(1);
   * const c = Identity.of(2);
   *
   * a.lte(b); //=> true
   * a.lte(c); //=> true
   * c.lte(a); //=> false
   */
  [fl.lte](ord) {
    return ordTrait[fl.lte].call(this, ord);
  }

  lte(ord) {
    return this[fl.lte](ord);
  }

  /**
   * Fantasy land {@link https://github.com/fantasyland/fantasy-land#monoid|Monoid*} specification.
   * Partial implementation of Monoid specification. `empty` method on instance only, returning
   * identity value of the wrapped type. Using `R.empty` under the hood.
   *
   *
   * @sig empty :: Monoid m => () -> m
   * @return {RA.Identity}
   * @example
   *
   * const a = Identity.of('test');
   * const i = a.empty();
   *
   * a.concat(i); //=> Identity('string');
   * i.concat(a); //=> Identity('string');
   */
  [fl.empty]() {
    return this.constructor.of(emptyR(this.value));
  }

  empty() {
    return this[fl.empty]();
  }

  /**
   * Fantasy land {@link https://github.com/fantasyland/fantasy-land#contravariant|Contravariant} specification.
   *
   * @sig contramap :: Contravariant f => f a ~> (b -> a) -> f b
   * @param {Function} fn
   * @return {RA.Identity}
   * @example
   *
   * const identity = a => a;
   * const add1 = a => a + 1;
   * const divide2 = a => a / 2;
   *
   * Identity.of(divide2).contramap(add1).get()(3); //=> 2
   * Identity.of(identity).contramap(divide2).contramap(add1).get()(3); //=> 2
   * Identity.of(identity).contramap(a => divide2(add1(a))).get()(3); //=> 2
   */
  [fl.contramap](fn) {
    return this.constructor.of((value) => this.value(fn(value)));
  }

  contramap(fn) {
    return this[fl.contramap](fn);
  }
}

export default Identity;