/** * Created by tc on 1/May/2014. */ // An implementation of functional lists. interface IFList { first: T; rest: IFList ; isEmpty (): boolean; } class EmptyFList implements IFList { get first (): T { return undefined; } get rest (): IFList { return this; } isEmpty (): boolean { return true; } toString (): string { return '[]'; } } class FList implements IFList { constructor (public first: T, public rest: IFList ) {} isEmpty (): boolean { return false; } toString (): string { var result = '[', separator = ''; var remainder: IFList = this; while (remainder.first) { result += separator + remainder.first; separator = ', '; remainder = remainder.rest; } result += ']'; return result; } } function flist (... members: T[]) { var result = new EmptyFList (); for (var i = members.length - 1; i >= 0; --i) { result = new FList(members[i], result); } return result; } // An inefficient implementation of functional maps. interface IPair { key: K; value: V; } interface IFMap { // These two memebers do not really belong in this interface; but since I // am not developing a general purpose library here, I'll opt for the // simpler implementation that this interface provides. first: IPair ; rest: IFMap ; // Returns true, if `key' is contained in the map, false otherwise. contains (key: K): boolean; // Returns the value for `key', or `undefined' if `key' is not contained in // the map. value (key: K): V; // REturn a map containing the mappings of `this' and mapping `key' to // `value'. If a value for `key' is already in the map it is shadowed by // the new value. add (key: K, value: V): IFMap ; } class EmptyFMap implements IFMap { get first (): IPair { return undefined; } get rest (): IFMap { return this; } contains (key: K): boolean { return false; } value (key: K): V { return undefined; } add (key: K, value: V) { return new FMap({key: key, value: value}, this); } toString (): string { return '<>'; } } class FMap implements IFMap { constructor (public first: IPair , public rest: IFMap ) {} contains (key: K): boolean { if (this.first.key === key) { return true; } return this.rest.contains(key); } value (key: K): V { if (this.first.key === key) { return this.first.value; } return this.rest.value(key); } add (key: K, value: V) { return new FMap({key: key, value: value}, this); } toString (): string { var result = '<', separator = ''; var remainder: IFMap = this; while (remainder.first) { result += separator + remainder.first.key + ' = ' + remainder.first.value; separator = ', '; remainder = remainder.rest; } result += '>'; return result; } } function fmap (... members: IPair []) { var result = new EmptyFMap (); for (var i = members.length - 1; i >= 0; --i) { result = new FMap(members[i], result); } return result; } // An extremely inefficient implementation of functional sets. interface Choice { element: T; newSet: IFSet ; } // The interface IFSet describes functional sets with members of type `T'. // No operation in this interface modifies the original set; they all return a // new set (that may share structure with the original set). interface IFSet { // These two memebers do not really belong in this interface; but since I // am not developing a general purpose library here, I'll opt for the // simpler implementation that this interface provides. first: T; rest: IFSet ; // True if the set is empty. isEmpty (): boolean; // Returns a new set that contains all elements of `this' and `newElement'. add (newElement: T): IFSet ; // Returns a new set that contalins all elements of `this' except `element'. remove (element: T): IFSet ; // Returns true if `this' contains `element', false otherwise. contains (element: T): boolean; // Chooses a random element from `this' and returns a choice consisiting of // that element and a set consisiting of all members of `this' except // `element'. pickElement (): Choice ; // Returns the union of `this' and `otherSet'. union (otherSet: IFSet ): IFSet ; // Returns true of `this' is a (non-strict) subset of `otherSet', false // otherwise. subset (otherSet: IFSet ): boolean; // Returns true if `this' and `otherSet' contain the same members. equals (otherSet: IFSet ): boolean; // Evaluate a function (for effect) for each member of the set. forEach (f: (t: T) => void): void; } class EmptyFSet implements IFSet { constructor () {} get first (): T { return undefined; } get rest (): IFSet { return this; } isEmpty (): boolean { return true; } add (newElement: T): IFSet { if (this.contains(newElement)) { return this; } else { return new FSet(newElement, this); } } remove (element: T): IFSet { return this; } contains (element: T): boolean { return false; } pickElement (): Choice { throw('Cannot choose an element from the empty set.'); } union (otherSet: IFSet ): IFSet { return otherSet; } subset (otherSet: IFSet ): boolean { return true; } equals (otherSet: IFSet ): boolean { return otherSet.subset(this); } forEach (f: (t: T) => void): void { // Do nothing. } toString (): string { return '{}'; } } class FSet implements IFSet { constructor (public first: T, public rest: IFSet ) {} isEmpty () { return false; } add (newElement: T): IFSet { if (this.contains(newElement)) { return this; } else { return new FSet (newElement, this); } } remove (element: T): IFSet { if (!this.contains(element)) { return this; } if (this.first === element) { return this.rest; } else { return new FSet (element, this.rest.remove(element)); } } contains (element: T): boolean { if (this.first === element) { return true; } else { return this.rest.contains(element); } } pickElement (): Choice { return {element: this.first, newSet: this.rest}; } union (otherSet: IFSet ): IFSet { return new FSet (this.first, this.rest.union(otherSet)); } subset (otherSet: IFSet ): boolean { return otherSet.contains(this.first) && this.rest.subset(otherSet); } equals (otherSet: IFSet ): boolean { return this.subset(otherSet) && otherSet.subset(this); } forEach (f: (t: T) => void): void { f(this.first); this.rest.forEach(f); } toString (): string { var result = '{', separator = ''; var remainingSet: IFSet = this; while (remainingSet.first) { result += separator + remainingSet.first; separator = ', '; remainingSet = remainingSet.rest; } result += '}'; return result; } } function fset (... elements: T[]): IFSet { var result = new EmptyFSet (); for (var i = elements.length - 1; i >= 0; --i) { result = new FSet(elements[i], result); } return result; } var myFset: IFSet = fset(1, 2, 3, 4); var yourFset: IFSet = fset(2, 4, 6, 8);