@sweet-monads/interfaces
Collection of interfaces which describe functional programming abstractions.
This library belongs to sweet-monads project
sweet-monads — easy-to-use monads implementation with static types definition and separated packages.
Usage
npm install @sweet-monads/interfaces
import { Functor } from "@sweet-monads/interfaces";
class Container<T> implements Functor<T> {
map<A>(fn: (i: T) => A): Container<A> {
return new Container<A>();
}
}
Available Interfaces
Functor
https://wiki.haskell.org/Functor
An abstract datatype Functor<A>
, which has the ability for it's value(s) to be mapped over can become an instance of the Functor interface. That is to say, a new Functor, Functor<B>
can be made from Functor<A>
by transforming all of it's value(s), whilst leaving the structure of f itself unmodified.
Functors are required to obey certain laws in regards to their mapping. Ensuring instances of Functor obey these laws means the behaviour of fmap remains predictable.
Methods:
Functor#map
function map<A, B>(f: (x: A) => B): Functor<B>;
Minimal Complete Definition
map<A, B>(f: (x: A) => B): Functor<B>;
Functor Laws
Functors must preserve identity morphisms
const f = new SomeFunctorImplementation();
const id = x => x;
expect(f.map(id)).toEqual(f);
Functors preserve composition of morphisms
declare function twice(x: number): number;
declare function toString(x: number): string;
const f = new SomeFunctorImplementation<number>();
expect(f.map(x => toString(twice(x)))).toEqual(f.map(twice).map(toString));
AsyncFunctor
Async version of Functor
, which provides async version of the map
method.
Methods:
AsyncFunctor#asyncMap
function asyncMap<A, B>(f: (x: A) => Promise<B>): Promise<AsyncFunctor<B>>;
Minimal Complete Definition
Functor
implementation.
asyncMap<A, B>(f: (x: A) => Promise<B>): Promise<AsyncFunctor<B>>;
AsyncFunctor Laws
All the Functor Laws
should be applied to the async version, so:
AsyncFunctors must preserve identity morphisms
const f = new SomeAsyncFunctorImplementation();
const id = x => Promise.resolve(x);
expect(await f.asyncMap(id)).toEqual(f);
AsyncFunctors preserve composition of morphisms
declare function twice(x: number): Promise<number>;
declare function toString(x: number): Promise<string>;
Promise.resolve(toString(twice(x)))
const f = new SomeAsyncFunctorImplementation<number>();
expect(await f.asyncMap(x => twice(x).then(toString))).toEqual(await f.asyncMap(twice).then(f => f.asyncMap(toString)));
Alternative
https://en.wikibooks.org/wiki/Haskell/Alternative_and_MonadPlus
Several classes (Applicative, Monad) have "monoidal" subclasses, intended to model computations that support "failure" and "choice" (in some appropriate sense).
The basic intuition is that empty
represents some sort of "failure", and or
represents a choice between alternatives. (However, this intuition does not fully capture the nuance possible; see the section on Laws below.) Of course, or
should be associative and empty
should be the identity element for it. Instances of Alternative must implement empty
and or
; some and many have default implementations but are included in the class since specialized implementations may be more efficient than the default.
Current implementation is not fully port of Alternative
from Haskell, because we don't make the interface an child interface of Applicative
and dropped empty
static member for ability to implement Alternative
for classes like Either
.
Methods:
Alternative#or
function or<T>(arg: Alternative<T>): Alternative<T>;
Applicative
https://wiki.haskell.org/Applicative_functor
This module describes a structure intermediate between a functor and a monad (technically, a strong lax monoidal functor). Compared with monads, this interface lacks the full power of the binding operation chain
.
Methods:
Applicative.from
function from<A>(x: A): Applicative<A>;
Applicative#apply
function apply<A, B>(this: Applicative<(a: A) => B>, arg: Applicative<A>): Applicative<B>;
function apply<A, B>(this: Applicative<A>, fn: Applicative<(a: A) => B>): Applicative<B>;
Minimal Complete Definition
Functor
implementation.
static from<A>(x: A): Applicative<A>;
apply<A, B>(this: Applicative<(a: A) => B>, arg: Applicative<A>): Applicative<B>;
apply<A, B>(this: Applicative<A>, fn: Applicative<(a: A) => B>): Applicative<B>;
Applicative Laws
Identity Law
declare var x: Applicative<unknown>;
const id = x => x;
expect(SomeApplicative.from(id).apply(x)).toEqual(x);
Homomorphism Law
declare var x: unknown;
declare var f: (x: unknown) => unknown;
expect(SomeApplicative.from(f).apply(x)).toEqual(SomeApplicative.from(f(x)));
AsyncApplicative
Async version of Applicative
, which provides async version of the apply
method.
Methods:
AsyncApplicative#asyncApply
function asyncApply<A, B>(this: AsyncApplicative<(a: A) => Promise<B>>, arg: AsyncApplicative<Promise<A> | A>): Promise<AsyncApplicative<B>>;
function asyncApply<A, B>(this: AsyncApplicative<Promise<A> | A>, fn: AsyncApplicative<(a: A) => Promise<B>>): Promise<AsyncApplicative<B>>;
Minimal Complete Definition
Applicative
implementation.
AsyncFunctor
implementation.
asyncApply<A, B>(this: AsyncApplicative<(a: A) => Promise<B>>, arg: AsyncApplicative<Promise<A> | A>): Promise<AsyncApplicative<B>>;
asyncApply<A, B>(this: AsyncApplicative<Promise<A> | A>, fn: AsyncApplicative<(a: A) => Promise<B>>): Promise<AsyncApplicative<B>>;
AsyncApplicative Laws
All the Applicative Laws
should be applied to the async version, so:
Identity Law
declare var x: AsyncApplicative<unknown>;
const id = x => Promise.resolve(x);
expect(await SomeAsyncApplicative.from(id).asyncApply(x)).toEqual(x);
Homomorphism Law
declare var x: unknown;
declare var f: (x: unknown) => Promise<unknown>;
expect(await SomeAsyncApplicative.from(f).asyncApply(x)).toEqual(SomeAsyncApplicative.from(await f(x)));
Monad
https://wiki.haskell.org/Monad
Monads can be thought of as composable computation descriptions. The essence of monad is thus separation of composition timeline from the composed computation's execution timeline, as well as the ability of computation to implicitly carry extra data, as pertaining to the computation itself, in addition to its one (hence the name) output, that it will produce when run (or queried, or called upon). This lends monads to supplementing pure calculations with features like I/O, common environment, updatable state, etc.
Methods:
Monad#chain
function chain<A, B>(f: (x: A) => Monad<B>): Monad<B>;
Monad#join
function join<T>(this: Monad<Monad<T>>): Monad<T>;
Minimal Complete Definition
Applicative
implementation.
chain<A, B>(f: (x: A) => Monad<B>): Monad<B>;
join<T>(this: Monad<Monad<T>>): Monad<T>;
Monad Laws
Left identity Law
declare var x: unknown;
declare function f(x: unknown): Monad<unknown>;
expect(SomeMonad.from(x).chain(f)).toEqual(f(x));
Right identity Law
declare var mx: Monad<unknown>;
declare function f(x: unknown): Monad<unknown>;
expect(mx.chain(SomeMonad.from)).toEqual(mx);
Associativity Law
declare var mx: Monad<unknown>;
declare function f(x: unknown): Monad<unknown>;
declare function g(x: unknown): Monad<unknown>;
expect(mx.chain(x => f(x).chain(g))).toEqual(mx.chain(f).chain(g));
AsyncMonad
Async version of Monad
, which provides async version of the chain
method.
Methods:
Monad#chain
function asyncChain<A, B>(f: (x: A) => Promise<AsyncMonad<B>>): Promise<AsyncMonad<B>>;
Minimal Complete Definition
Monad
implementation.
AsyncApplicative
implementation.
asyncChain<A, B>(f: (x: A) => Promise<AsyncMonad<B>>): Promise<Monad<B>>;
AsyncMonad Laws
All the Monad Laws
should be applied to the async version, so:
Left identity Law
declare var x: unknown;
declare function f(x: unknown): Promise<AsyncMonad<unknown>>;
expect(await SomeAsyncMonad.from(x).asyncChain(f)).toEqual(await f(x));
Right identity Law
declare var mx: AsyncMonad<unknown>;
declare function f(x: unknown): Promise<AsyncMonad<unknown>>;
expect(await mx.asyncChain(x => Promise.resolve(SomeAsyncMonad.from(x)))).toEqual(mx);
Associativity Law
declare var ax: AsyncMonad<unknown>;
declare function f(x: unknown): Promise<AsyncMonad<unknown>>;
declare function g(x: unknown): Promise<AsyncMonad<unknown>>;
expect(await ax.asyncChain(x => f(x).then(fx => fx.asyncChain(g)))).toEqual(await ax.asyncChain(f).then(fx => fx.asyncChain(g)));
AsyncChainable
Static interface which give an ability to use AsyncMonad
more comfortable with Promise
.
Should be used with ClassImplements
decorator
Methods:
AsyncChainable<M>#chain
function chain<A, B>(f: (v: A) => Promise<M & AsyncMonad<B>>): (m: M & AsyncMonad<A>) => Promise<M & AsyncMonad<B>>;
Usage
@ClassImplements<IdentityMonad<unknown>>
class IdentityMonad<T> extends AsyncMonad<T> { }
declare function getAsyncValue(): Promise<IdentityMonad<number>>
declare function sendToServer(value: number): Promise<IdentityMonad<void>>
const value = await getAsyncValue().then(chain(sendToServer));
License
MIT (c) Artem Kobzar see LICENSE file.