export type instanceKey = keyof S export type S = typeof Semigroup import { datatype, datatypeOf } from '.' export type SemigroupInstance = keyof typeof Semigroup export type SemigroupInstanceType = typeof Semigroup[SemigroupInstance]['_T'] export interface Semigroup { _T: A concat(a: any, b: any): A } export class NumberSemigroup implements Semigroup { _T: number concat(a: any, b: any): number { return a + b } } export class ObjectSemigroup implements Semigroup { _T: object concat(a: any, b: any): object { return Object.assign({}, a, b) } } export class PromiseSemigroup implements Semigroup> { _T: Promise concat(a: any, b: any): Promise { return Promise.all([a, b]).then(([a, b]) => concat(a, b)) } } export class StringSemigroup implements Semigroup { _T: string concat(a: any, b: any): string { return a + b } } export class ArraySemigroup implements Semigroup> { _T: Array concat(a: Array, b: Array): Array { return a.concat(b) } } export namespace Semigroup { export let Number = new NumberSemigroup export let String = new StringSemigroup export let Array = new ArraySemigroup() export let Object = new ObjectSemigroup export let Promise = new PromiseSemigroup } export function concat(a: A, b: A): A { let instance = (Semigroup)[datatypeOf(a)] return instance.concat(a, b) }