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";
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";
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";
Maps a function over a functor.
map((n) => n * n, just(3)); //=> just(9)
map((n) => n * n, [1, 2, 3]); //=> [1, 4, 9]
Replaces each value inside the functor with b.
mapTo(2, just(3)); //=> just(2)
mapTo(4, [1, 2, 3]); //=> [4, 4, 4]
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";
Wraps a value in an applicative. This function is also known as pure
and return
.
of(Maybe, 12); //=> just(12)
of(Array, 12); //=> [12]
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.
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
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";
Removes one level of nesting from a monad inside a monad.
flatten(just(just(1))); //=> just(1)
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)
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;
});
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.
Performs a strict right fold over a foldable.
Performs a strict left fold over a foldable.
Returns the number of elements in the foldable.
Returns true if the foldable contains no elements and true otherwise.
Returns an array of the first n
elements in the foldable.
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
Returns the last element in the foldable that satisfies the predicate.
findLast(isEven, fromArray([1, 3, 4, 5, 6, 7])); //=> just(6)
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
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)
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
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
Converts a foldable to an array.
toArray(fromArray([1, 2, 3])); //=> [1, 2, 3]
Sequences applicatives in the foldable from left to right discarding the result.
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
Returns the maximum number in a foldable.
Returns the minimum number in a foldable.
Returns the sum of numbers in a foldable.
§Traversable
code.language-javascript. import * as Traversable from "jabz/traversable";
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.
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";
Type of maybe values.
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 :(`
});
Creates a Maybe with just the value a
.
map(double, just(4)); //=> just(8)
A Maybe with no value inside
map(double, nothing); //=> nothing
Returns true
if m
is empty.
isNothing(nothing); //=> true
isNothing(just(3)); //=> false
Returns true
if m
is contains a value.
isJust(nothing); //=> false
isJust(just(3)); //=> true
Extracts a the potential value from m
with a
as a fallback.
fromMaybe(5, nothing); //=> 5
fromMaybe(5, just(3)); //=> 3
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.
Type of either values.
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}`
});
Returns an Either
that is left and contains a
.
Returns an Either
that is right and contains b
.
Return true
is either
is left.
Return true
is either
is right.
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.
The sentinel value at the end of the list indicating the end. Alternatively it can be though of as the empty list.
Prepend the element a
to the beginning of the list as
.
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
An infinite list of the natural numbers. [0, 1, 2, ...]
.
An infinite list of a
s. [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];
Creates a writer monad from a monoid dictionary.
Returns a Writer
action that produces no value but combines the
shared monoid with w
.
Listen.
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 |