Sub-project of Funfix exposing type classes inspired by Haskell's standard library and by Typelevel Cats.
Summary of type classes:
| Eq | type class for determining equality between instances of the same type and that obeys the laws defined in EqLaws |
| Functor | type class exposing map and that obeys the laws defined in FunctorLaws |
| Apply | type class that extends Functor, exposing ap and that obeys the laws defined in ApplyLaws |
| Applicative | type class that extends Functor and Apply, exposing pure and that obeys the laws defined in ApplicativeLaws |
| ApplicativeError | type class that extends Applicative, for applicative types that can raise errors or recover from them and that obeys the laws defined in ApplicativeErrorLaws |
| FlatMap | type class that extends Functor and Apply, exposing flatMap and tailRecM and that obeys the laws defined in FlatMapLaws |
| Monad | type class that extends Applicative and FlatMap and that obeys the laws defined in MonadLaws |
| MonadError | type class that extends ApplicativeError and Monad, for monads that can raise or recover from errors and that obeys the laws defined in MonadErrorLaws |
| CoflatMap | type class that extends Functor, the dual of FlatMap, obeying the laws defined in CoflatMapLaws |
| Comonad | type class that extends CoflatMap, the dual of Monad, for data types that providing extract, obeying the laws defined in ComonadLaws |
More is coming 😉
You can depend on the whole funfix library, by adding it to
package.json:
npm install --save funfix
In this case imports are like:
import { Monad } from "funfix"
Or for finer grained dependency management, the project can depend
only on funfix-types:
npm install --save funfix-types
In this case imports are like:
import { Monad } from "funfix-types"
The library has been compiled using UMD (Universal Module Definition), so it should work with CommonJS and AMD.
But it also provides a module definition in package.json, thus
providing compatibility with
ECMAScript 2015 modules, for usage when used with a modern JS engine,
or when bundling with a tool chain that understands ES2015 modules,
like Rollup or Webpack.
Alias used for encoding higher-kinded types when implementing type class instances.
Alias used for encoding higher-kinded types when implementing type class instances.
Alias used for encoding higher-kinded types when implementing type class instances.
Alias used for encoding higher-kinded types when implementing type class instances.
Alias used for encoding higher-kinded types when implementing type class instances.
Alias used for encoding higher-kinded types when implementing type class instances.
The TypeClass interface is to be implemented by type class
definitions, exposing IDs needed for discovery management.
Only of interest to type class authors.
Given a Constructor reference, returns its associated
ApplicativeError instance if it exists, or throws a NotImplementedError
in case there's no such association.
import { Eval, ApplicativeError, applicativeErrorOf } from "funfix"
const F: ApplicativeError<Option<any>> = applicativeErrorOf(Eval)
Given a Constructor reference, returns its associated
Applicative instance if it exists, or throws a NotImplementedError
in case there's no such association.
import { Option, Applicative, applicativeOf } from "funfix"
const F: Applicative<Option<any>> = applicativeOf(Option)
Given a Constructor reference, returns its associated
Apply instance if it exists, or throws a NotImplementedError
in case there's no such association.
import { Option, Apply, applyOf } from "funfix"
const F: Apply<Option<any>> = applyOf(Option)
Given a Constructor reference, returns its associated
CoflatMap instance if it exists, or throws a NotImplementedError
in case there's no such association.
import { Option, CoflatMap, coflatMapOf } from "funfix"
const F: CoflatMap<Option<any>> = coflatMapOf(Option)
Given a Constructor reference, returns its associated
Comonad instance if it exists, or throws a NotImplementedError
in case there's no such association.
import { Option, Comonad, comonadOf } from "funfix"
const F: Comonad<Option<any>> = comonadOf(Option)
Given a Constructor reference, returns its associated
Eq instance if it exists, or throws a NotImplementedError
in case there's no such association.
import { Option, Eq, eqOf } from "funfix"
const F: Eq<Option<any>> = eqOf(Option)
Given a Constructor reference, returns its associated
FlatMap instance if it exists, or throws a NotImplementedError
in case there's no such association.
import { Option, FlatMap, flatMapOf } from "funfix"
const F: FlatMap<Option<any>> = flatMapOf(Option)
Given a Constructor reference, returns its associated
Functor instance if it exists, or throws a NotImplementedError
in case there's no such association.
import { Option, Functor, functorOf } from "funfix"
const F: Functor<Option<any>> = functorOf(Option)
Given a Constructor reference, returns its associated
MonadError instance if it exists, or throws a NotImplementedError
in case there's no such association.
import { IO, MonadError, monadErrorOf } from "funfix"
const F: MonadError<IO<any>> = monadErrorOf(IO)
Given a Constructor reference, returns its associated
Monad instance if it exists, or throws a NotImplementedError
in case there's no such association.
import { Option, Monad, monadOf } from "funfix"
const F: Monad<Option<any>> = monadOf(Option)
Given an ApplicativeError instance, returns the ApplicativeErrorLaws associated with it.
Given an Applicative instance, returns the ApplicativeLaws associated with it.
Given an CoflatMap instance, returns the CoflatMapLaws associated with it.
Given an Comonad instance, returns the ComonadLaws associated with it.
Given an FlatMap instance, returns the FlatMapLaws associated with it.
Given an Functor instance, returns the FunctorLaws associated with it.
Given a TypeClass instance and a Constructor reference,
returns its associated type class implementation if it exists, or throws
a NotImplementedError in case there's no such association.
import { Option, Functor, getTypeClass } from "funfix"
const F: Functor<Option<any>> = getTypeClass(Functor, Option)
Given an MonadError instance, returns the MonadErrorLaws associated with it.
Given a TypeClass definition in tc, register an instance
for the given Constructor specified by c that implements the
given type class.
Example:
registerTypeClassInstance(Functor)(Box, new BoxFunctorInstance())
Data types can have only one implementation for a given type class. Multiple implementations are not allowed, therefore registration needs to happen at most once. If registration happens multiple times for instances of the same data type and type class, then an exception is going to be raised:
// Ok
registerTypeClassInstance(Functor)(Box, new FunctorInstance1())
// IllegalArgumentError: Type class coherence issue,
// Functor<Box> is already defined!
registerTypeClassInstance(Functor)(Box, new FunctorInstance1())
Note that type classes can have super types. So for example registering
a Monad instance will also register a Functor instance, along with
Applicative. The registration of supertypes however does not trigger
coherence errors. In this example, if you try registering a Monad,
but a Functor was already registered, then that the given Monad
will simply not be registered as a Functor for that data type.
This is legal:
// Ok
registerTypeClassInstance(Functor)(Box, new FunctorInstance())
// Ok, even though a Monad is also a Functor
registerTypeClassInstance(Functor)(Box, new MonadInstance())
Generated using TypeDoc
Given a type
Trepresenting instances of a classC, the typeConstructor<T>is the type of the classC.This type emulates Class from Flow .
Note that in TypeScript constructors can also be
protectedorprivateand unfortunately specifying{ new(): T }is thus insufficient. Which is why, for classes without a public constructor, we have to specify a_funErasure(static) member as a property, to help the compiler infer typeT.Example:
class NumBox { constructor(public num: number) {} } class GenBox<A> { constructor(public a: A) {} } function getDefault<F>(ref: Constructor<F>): Option<F> { if ((ref as any)._default) return Some(ref._default) return None } (NumBox as any)._default = new NumBox(10) (GenBox as any)._default = new GenBox("value") const r1: Option<NumBox> = getDefault(NumBox) const r2: Option<GenBox<any>> = getDefault(GenBox)And for classes with a private constructor:
class PrivateBox<A> { private constructor(public a: A) {} static _funErasure: PrivateBox<any> // leaving undefined } const F = PrivateBox as any F._default = new F("hello") const r: Option<PrivateBox<any>> = getDefault(NumBox)