type ReduceFunc = (aggregator: R, item: T) => R interface Item { compare(b: Item): number } interface Tuple { result: A value: B } interface Set { add(item: T): Tuple,T> reduce(fn: ReduceFunc, accumulator: R): R size(): number } interface Map { set(key: K, value:V): Map get?(key: K): V } export class Indexed> implements Item { value: T index: number constructor(value: T, index: number) { this.value = value; this.index = index; } compare(b: Indexed): number { return this.value.compare(b.value); } } export class SetMap,V> { constructor(private keys?: Set>, private values?: Map) {} set(key: K, value: V): SetMap { const result = this.keys.add(new Indexed(key, this.keys.size())) return new SetMap( result.result, this.values.set(result.value.index, value) ); } get?(key: K): V { const result = this.keys.add(new Indexed(key, this.keys.size())) if (result.result !== this.keys) { return null; } return this.values.get(result.value.index); } merge(b: SetMap): SetMap { return b.reduce((aggregator: SetMap, item: V, key: K) => { return aggregator.set(key, item); }, this); } reduce(fn: (aggregator: R, values: V, key: K) => R, aggregator: R): R { return this.keys.reduce((aggregator, key) => { return fn(aggregator, this.values.get(key.index), key.value); }, aggregator) } }