/*! * Copyright (c) 2017 by The Funfix Project Developers. * Some rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Given a type `T` representing instances of a class `C`, the type * `Constructor` is the type of the class `C`. * * This type emulates * [Class from Flow]{@link https://flow.org/en/docs/types/utilities/#classt-a-classtoc-idtoc-class-hreftoc-classa}. * * Note that in TypeScript constructors can also be `protected` or `private` * and 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 type `T`. * * Example: * * ```typescript * class NumBox { constructor(public num: number) {} } * class GenBox { constructor(public a: A) {} } * * function getDefault(ref: Constructor): Option { * 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 = getDefault(NumBox) * const r2: Option> = getDefault(GenBox) * ``` * * And for classes with a private constructor: * * ```typescript * class PrivateBox { * private constructor(public a: A) {} * * static _funErasure: PrivateBox // leaving undefined * } * * const F = PrivateBox as any * F._default = new F("hello") * * const r: Option> = getDefault(NumBox) * ``` */ export declare type Constructor = { new (...args: any[]): T; } | { readonly _funErasure: T; }; /** * The `TypeClass` interface is to be implemented by type class * definitions, exposing IDs needed for discovery management. * * Only of interest to type class authors. */ export declare type TypeClass = Constructor & { readonly _funTypeId: string; readonly _funSupertypeIds: string[]; }; /** * Lightweight encoding for higher kinded types. * * Inspired by the * [Lightweight higher-kinded polymorphism]{@link https://www.cl.cam.ac.uk/~jdy22/papers/lightweight-higher-kinded-polymorphism.pdf} * paper. * */ export interface HK { /** Trick for achieving nominal typing. */ readonly _funKindF: F; /** Trick for achieving nominal typing. */ readonly _funKindA: A; } /** * Data type for expressing equivalence in type class laws. * * @final */ export declare class Equiv { readonly lh: A; readonly rh: A; private constructor(); static of(lh: A, rh: A): Equiv; } /** * Given a {@link TypeClass} definition in `tc`, register an `instance` * for the given {@link Constructor} specified by `c` that implements the * given type class. * * Example: * * ```typescript * 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: * * ```typescript * // Ok * registerTypeClassInstance(Functor)(Box, new FunctorInstance1()) * * // IllegalArgumentError: Type class coherence issue, * // Functor 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: * * ```typescript * // Ok * registerTypeClassInstance(Functor)(Box, new FunctorInstance()) * * // Ok, even though a Monad is also a Functor * registerTypeClassInstance(Functor)(Box, new MonadInstance()) * ``` * * @throws `IllegalArgumentError` in case such a type class instance * was already specified, thus leading to a coherence issue. */ export declare function registerTypeClassInstance(tc: TypeClass): (c: Constructor, instance: F) => void; /** * Given a {@link TypeClass} instance and a {@link Constructor} reference, * returns its associated type class implementation if it exists, or throws * a `NotImplementedError` in case there's no such association. * * ```typescript * import { Option, Functor, getTypeClass } from "funfix" * * const F: Functor> = getTypeClass(Functor, Option) * ``` */ export declare function getTypeClassInstance(tc: TypeClass): (c: Constructor) => F;