export interface Merger { merge(b: Merger): T } export function merge>(a: T, b: T): T { return a.merge(b) } export interface Equaler { equal(b: Equaler): boolean } export function equal( a: Equaler, b: Equaler): boolean { return a.equal(b); } export interface Comparer { compare(b: Comparer): number } export function compare(a: Comparer, b: Comparer): number { return a.compare(b); } export interface Concater { concat(b: Concater): Concater } export function concat(a: Concater, b: Concater): Concater { return a.concat(b) } export interface Applicator { apply(b: T2): T1 } export function applyOperation(operation: Applicator, data: T2): T1 { return operation.apply(data); } export interface CRDT extends Merger, Equaler { } export type AssertFunc = (boolean, string) => void export function axioms>(assert: AssertFunc, a: T, b: T, c: T): void { // commutative a + c = c + a i.e: 1 + 2 = 2 + 1 assert( equal(merge(a, b), merge(b, a)), 'is not commutative' ); // associative a + (b + c) = (a + b) + c i.e: 1 + (2 + 3) = (1 + 2) + 3 assert( equal(merge(a, merge(b, c)), merge(merge(a, b), c)), 'is not associative' ); // idempotent f(f(a)) = f(a) i.e: ||a|| = |a| assert( equal(merge(a, a), a), 'is not idempotent' ); }