Overview

Jabz provides the following abstractions

Jabz provides the following implementations of the abstractions.

Name Semigroup Monoid Functor Applicative Monad Foldable Traversable
Maybe ✔︎ ✔︎ ✔︎ ✔︎ ✔︎
Either ✔︎ ✔︎
Cons ✔︎ ✔︎ ✔︎ ✔︎ ✔︎ ✔︎ ✔︎
InfiniteList ✔︎ ✔︎ ✔︎ ✔︎ ✔︎
Writer ✔︎
Identity ✔︎ ✔︎ ✔︎ ✔︎ ✔︎
Const ✔︎ ✔︎ ✔︎ ✔︎ ✔︎

API

API documentation for Jabz.

§Semigroup

Import with.

import {combine} from "jabz/semigroup";
§combine<A extends Semigroup<A>>(...m: A): A

Combines two or more members of the same semigroup by using their combine method.

combine(sum(3), sum(5)); //=> Sum(8)
combine("Hello ", "over ", "there"); //=> "Hello over there"
combine([1], [2], [3], [4, 5]); //=> [1, 2, 3, 4, 5]

§Monoid

Import with.

import * as Monoid from "jabz/monoid";
§identity<M extends Monoid<M>>(m: MonoidDictionary<M>): M

Takes a monoid dictionary and returns the identity element of the monoid. Alternatively it takes a constructor of one of the native monoid instances.

identity(Sum); //=> Sum(0)
identity(Array); //=> []
identity(String); //=> ""

§Functor

Import with.

import * as Functor from "jabz/functor";
§map<F extends Functor, A, B>(f: (a: A) => B, a: F<A>): F<B>

Maps a function over a functor.

map((n) => n * n, just(3)); //=> just(9)
map((n) => n * n, [1, 2, 3]); //=> [1, 4, 9]
§mapTo<F extends Functor, A, B>(b: B, as: F<A>): F<B>

Replaces each value inside the functor with b.

mapTo(2, just(3)); //=> just(2)
mapTo(4, [1, 2, 3]); //=> [4, 4, 4]
§mapMap<F extends Functor, A, B>(f: (a: A) => B, as: F<F<A>>): F<F<B>>

map composed with map. A convenience function for applying a function to a functor inside another functor.

mapMap((n) => n * n, just([1, 2, 3])); //=> just([1, 4, 9])

§Applicative

Import with.

import * as Applicative from "jabz/applicative";
§of<A, F extends Applicative>(d: ApplicativeDictionary, a: A): F<A>

Wraps a value in an applicative. This function is also known as pure and return.

of(Maybe, 12); //=> just(12)
of(Array, 12); //=> [12]
§ap<A, B, F extends Applicative>(fa: F<(a: A) => B>, ba: F<A>): F<B>

Takes two applicatives of the same type. The first must contain a function from A and the second an A. The function is then applied to the value and a new applicative is returned.

§lift<F extends Applicative>(f: (?) => R, ...args: F<?>[]): F<A>

Takes a function from n arguments, n applicatives with values matching the function and applies the function inside the applicatives.

lift((a, b, c) => a * b + c, just(4), just(2), just(3)); //=> just(11)
lift((a, b, c) => a * b + c, just(4), nothing, just(3)); //=> nothing
§seq<A, B, F extends Applicative>(a: F<A>, b: F<B>): F<B>

Sequences actions from left to right, i.e. a before b, discarding the value of a.

§Monad

Import with.

import * as Monad from "jabz/monad";
§flatten<A, M extends Monad>(m: M<M<A>): M<A>

Removes one level of nesting from a monad inside a monad.

flatten(just(just(1))); //=> just(1)
§chain<A, B, M extends Monad>(f: (a: A) => M<B>, m: M<A>): M<B>

Values in m are passed to f and f returns a new monadic value that is joined with the former. This operation is sometimes called flatMap and other times >>=.

m.chain(f) is equal to m.map(f).flatten().

chain((m) => safeDiv(12, m), just(3)); // just(4)
§go<M extends Monad>(gen: () => Iterator<M<any>>): M<any>

Do-notation powered by generator functions.

The example below demonstrates the use of go-notation with the Maybe monad. Note that the yielded values are all in the monad and that the variables becomes bound to the value inside the monad.

const safeDiv = (n, m) => m === 0 ? nothing : just(n / m);
go(function*() {
  const a = yield find(isEven, list1);
  const b = yield find(isEven, list2);
  const c = yield safeDiv(a, b)
  return a + b + c;
});
§fgo<M extends Monad>(gen: (..args) => Iterator<M<any>>): (..args) => M<any>

A nifty shortcut for creating a function that uses go-notation. The arguments to the function are passed directly to the generator function.

const fgoExample = fgo(function*(x, y, z) {
  const a = yield just(x);
  const b = yield just(y);
  const c = yield just(z)
  return a + b + c;
});
fgoExample(1, 2, 3); //=> just(6)

§Foldable

Import with.

import * as Foldable from "jabz/foldable";

In the examples below a hypothetical function fromArray will be used. It converts an array into some foldable.

§foldr<A, B>(f: (a: A, b: B) => B, init: B, a: Foldable<A> | A[]): B

Performs a strict right fold over a foldable.

§foldl<A, B>(f: (acc: B, a: A) => B, init: B, a: Foldable<A> | A[]): B

Performs a strict left fold over a foldable.

§size(t: Foldable<any>): number

Returns the number of elements in the foldable.

§isEmpty(f: Foldable<any>): boolean

Returns true if the foldable contains no elements and true otherwise.

§take(n: number, t: Foldable<A>): A[]

Returns an array of the first n elements in the foldable.

§find(f: (a: A) => boolean, t: Foldable<A>): Maybe<A>

Returns the first element in the foldable that satisfies the predicate.

const isEven = (n) => n % 2 === 0;
find(isEven, fromArray([1, 3, 4, 5, 6, 7])); //=> just(4)
find(isEven, fromArray([1, 3, 5, 7])); //=> nothing
§findLast(f: (a: A) => boolean, t: Foldable<A>): Maybe<A>

Returns the last element in the foldable that satisfies the predicate.

findLast(isEven, fromArray([1, 3, 4, 5, 6, 7])); //=> just(6)
§findIndex(f: (a: A) => boolean, t: Foldable<A>): Maybe<number>

Returns the index of the first element in the foldable that satisfies the predicate.

findIndex(isEven, fromArray([1, 3, 4, 5, 6, 7])); //=> just(2)
findIndex(isEven, fromArray([1, 3, 5, 7])); //=> nothing
§findLastIndex(f: (a: A) => boolean, t: Foldable<A>): Maybe<number>

Returns the index of the last element in the foldable that satisfies the predicate.

findLastIndex(isEven, fromArray([1, 3, 4, 5, 6, 7])); //=> just(4)
§all(pred: (a: A) => boolean, foldable: Foldable<A>): boolean

Returns true if the predicate function returns true for all elements in the foldable. This function short-circuits as soon a false value is encountered.

all(isEven, fromArray([2, 4, 6])); //=> true
all(isEven, fromArray([2, 4, 7])); //=> false
all(isEven, fromArray([])); //=> true
§any(pred: (a: A) => boolean, foldable: Foldable<A>): boolean

Returns true if the predicate function returns true for any elements in the foldable. This function short-circuits as soon a true value is encountered.

any(isEven, fromArray([1, 3, 7])); //=> false
any(isEven, fromArray([1, 3, 6])); //=> true
any(isEven, fromArray([])); //=> false
§toArray(t: Foldable<A>): A[]

Converts a foldable to an array.

toArray(fromArray([1, 2, 3])); //=> [1, 2, 3]
§sequence_<A extends Applicative>(d: ApplicativeDictionary, t: Foldable<A<any>>): A<{}>

Sequences applicatives in the foldable from left to right discarding the result.

§foldrM<A, B, M extends Monad>(f: (a: A, b: B) => M<B>, mb: M<B>, t: Foldable<A>): M<B>

Monadic right fold. This function is similar to foldr. The difference is that the accumulator function returns a monadic value and that the final result is in the same monad.

const divide = (a, b) => a === 0 ? nothing : just(b / a);
foldrM(divide, just(100), fromArray([10, 5])); //=> just(2)
foldrM(divide, just(100), fromArray([5, 0])); //=> nothing
§maximum(t: Foldable<number>): number

Returns the maximum number in a foldable.

§minimum(t: Foldable<number>): number

Returns the minimum number in a foldable.

§sum(t: Foldable<number>): number

Returns the sum of numbers in a foldable.

§Traversable

code.language-javascript. import * as Traversable from "jabz/traversable";

§sequence<A, T extends Traversable, F extends Applicative>(a: ApplicativeDictionary, t: T<F<A>>): F<T<A>>

Takes a traversable with applicatives inside and "flips" the nesting so that the applicative ends up on the outside and the traversable on the inside.

In the example below the applicative Maybe the traversable created by fromArray. Sequence turns them inside out so that just floats from the inside to the outside.

sequence(Maybe, fromArray([just(1), just(2), just(3)])); //=> just(fromArray([1, 2, 3]))
§traverse<A, B, T extends Traversable, F extends Applicative>(a: ApplicativeDictionary, f: (a: A) => F<B>, t: T<A>): F<T<B>>

Traverse.

traverse(Maybe, just, fromArray([1, 2, 3])); //=> just(fromArray([1, 2, 3]))

Instances

§Maybe

Maybe is a container that may contain one or zero elements.

Maybe is an instance of the following abstractions: functor, applicative, monad, foldable and traversable.

Import with.

import {just, nothing, ...} from "jabz/maybe";
§Maybe<A>class

Type of maybe values.

§Maybe#match<K>(m: MaybeMatch<A, K>): K

Pattern matching on Maybe values. MaybeMatch<A, K> must be a object with a nothing and just properties containing functions that returns K.

maybeAge.match({
  just: (n) => `You're ${n} years old'`,
  nothing: () => `No age provided :(`
});
§just<A>(a: A): Maybe<A>

Creates a Maybe with just the value a.

map(double, just(4)); //=> just(8)
§nothingMaybe<any>

A Maybe with no value inside

map(double, nothing); //=> nothing
§isNothing(m: Maybe<any>): boolean

Returns true if m is empty.

isNothing(nothing); //=> true
isNothing(just(3)); //=> false
§isJust(m: Maybe<any>): boolean

Returns true if m is contains a value.

isJust(nothing); //=> false
isJust(just(3)); //=> true
§fromMaybe<A>(a: A, m: Maybe<A>): A

Extracts a the potential value from m with a as a fallback.

fromMaybe(5, nothing); //=> 5
fromMaybe(5, just(3)); //=> 3
§maybe(b: B, f: (a: A) => B, m: Maybe<A>)

If m is nothing return b. Otherwise, extract the value, pass it through f and return it.

maybe("--:--", (d) => d.getMinutes() + ":" + d.getSeconds, maybeTime);

§Either

Either is a container that can be either left or right.

Either implements functor and applicative.

§Either<A, B>class

Type of either values.

§Either#match<K>(m: EitherMatch<A, B, K>): K

Pattern matching on Either values. EitherMatch<A, B, K> must be a object with a left and right properties containing functions returning K.

response.match({
  right: (rating) => `User gave the rating ${rating}`,
  left: (message) => `User wrote the message: ${message}`
});
§left<A>(a: A): Either<A, any>

Returns an Either that is left and contains a.

Returns an Either that is right and contains b.

§isLeft(either: Either<any, any>): boolean

Return true is either is left.

§isRight(either: Either<any, any>): boolean

Return true is either is right.

§fromEither<A, B>(either: Either<A, B>): A | B

Extracts the value from an Either.

§Cons

A simple singly linked list. It can be useful in cases where a list is build by repeatedly prepending elements to the front of the this. Cons supports the cons operation in very low constant time.

It implements semigroup, monoid, functor, applicative, monad, foldable and traversable.

§nilCons<any>

The sentinel value at the end of the list indicating the end. Alternatively it can be though of as the empty list.

§cons<A>(a: A, as: Cons<A>)

Prepend the element a to the beginning of the list as.

§fromArray<A>(as: A[]): Cons<A>

Creates a Cons-list from an array

§InfiniteList

A simple lazy infinite list. It can only be created based on naturals.

It implements functor, applicative and foldable. Since it is infinite it only works with the short-circuiting foldable methods.

// Find the first square number larger than 100
find((n) => n > 100, map((n) => n * n, naturals)); //=> 121
§naturalsInfiniteList<number>

An infinite list of the natural numbers. [0, 1, 2, ...].

§repeat(a: A): InfiniteList<A>

An infinite list of as. [a, a, a, ...].

§Writer

The Writer monad represents computation that produces a value and write to a shared state.

The Writer monad is useful in cases where functions produce a "primary" output but alongside that also need to append values to a shared state. This shared state is a monoid.

A value of type Writer<A, B> is a computation that produces a value of type B and produces a monoid value of type A as a secondary output.

In the example below the functions divide and add does arithmetic but besides that they also produce strings for a log.

const {tell} = createWriter(String);
const divide = fgo(function*(n, m) {
  yield tell(`Divide ${n} by ${m}. `);
  return n / m;
});
const add = fgo(function*(n, m) {
  yield tell(`Add ${n} to ${m}. `);
  return n + m;
});
const comp = go(function*() {
  const a = yield add(12, 8);
  const b = yield divide(132, 11);
  return yield add(a, b);
});
runWriter(comp);
//=> ["Add 12 to 8. Divide 132 by 11. Add 20 to 12. ", 32];
§createWriter<M extends Monoid<M>>(mc: MonoidDictionary<M>): WriterFunctions<M>

Creates a writer monad from a monoid dictionary.

§tell<A>(w: W): Writer<W, {}>

Returns a Writer action that produces no value but combines the shared monoid with w.

§listen<A>(w: Writer<W, A>): Writer<W, [A, W]>

Listen.

§runWriter<W extends Monoid<W>, A>(w: Writer<W, A>): [W, A]

Runs the Writer monad and returns a pair of the monoid value and the final result.

Specification

Semigroup

Description

A semigroup represents things that can be combined. That is, two objects of the same semigroups can be combined into one object of the semigroup. In other words semigroups are things that can be composed.

Examples are many. For instance numbers can be combined by adding them together, lists can be combined by concatenating them and images can be combined by overlaying them.

Methods
combine: (a: A) => A

Monoid

Description Monoid extends semigroups with an identity element.
Methods
identity: () => A
Laws m.combine*(m.identity()) === m.identity().combine(m) === m