diff --git a/tsmonad/tests/either-tests.ts b/tsmonad/tests/either-tests.ts new file mode 100644 index 000000000..1530562be --- /dev/null +++ b/tsmonad/tests/either-tests.ts @@ -0,0 +1,45 @@ +/// + +class User { + + private age: number; + + constructor(age?: number) { + this.age = age ? age : 0; + } + + public getAge(): TsMonad.Either { + if (this.age > 0) { + return TsMonad.Either.right(this.age); + } else { + return TsMonad.Either.left('Information withheld'); + } + } +} + +module Station { + + export class BusPass { + + public isValidForRoute(route: string): boolean { + return true; + } + } + + export function getBusPass(age: number): TsMonad.Either { + if (age > 18) { + return TsMonad.Either.right(new BusPass()); + } else { + return TsMonad.Either.left('Too young for a bus pass'); + } + } +} + +var user = new User(42) + +var canRideForFree = user.getAge() + .bind(age => Station.getBusPass(age)) + .caseOf({ + right: busPass => busPass.isValidForRoute('Weston'), + left: errorMessage => { console.log(errorMessage); return false; } + }); diff --git a/tsmonad/tests/maybe-tests.ts b/tsmonad/tests/maybe-tests.ts new file mode 100644 index 000000000..76f0a7256 --- /dev/null +++ b/tsmonad/tests/maybe-tests.ts @@ -0,0 +1,20 @@ +/// + +var turns_out_to_be_100 = TsMonad.Maybe.just(10) + .caseOf({ + just: n => n * n, + nothing: () => -1 + }); + +var turns_out_to_be_nothing = TsMonad.Maybe.nothing() + .caseOf({ + just: n => n * n, + nothing: () => -1 + }); + +var turns_out_to_be_true = TsMonad.Maybe.just(123) + .lift(n => n * 2) + .caseOf({ + just: n => n === 246, + nothing: () => false + }); \ No newline at end of file diff --git a/tsmonad/tests/writer-tests.ts b/tsmonad/tests/writer-tests.ts new file mode 100644 index 000000000..fd8200aeb --- /dev/null +++ b/tsmonad/tests/writer-tests.ts @@ -0,0 +1,8 @@ +/// + +var is_true = TsMonad.Writer.writer(['Started with 0'], 0) + .bind(x => TsMonad.Writer.writer(['+ 8'], x + 8)) + .bind(x => TsMonad.Writer.writer(['- 6', '* 8'], 8 * (x - 6))) + .caseOf({ + writer: (s, v) => v === 16 && s.join(', ') === 'Started with 0, + 8, - 6, * 8' + }); \ No newline at end of file diff --git a/tsmonad/tsmonad-tests.ts b/tsmonad/tsmonad-tests.ts new file mode 100644 index 000000000..8959950d9 --- /dev/null +++ b/tsmonad/tsmonad-tests.ts @@ -0,0 +1,3 @@ +/// +/// +/// diff --git a/tsmonad/tsmonad.d.ts b/tsmonad/tsmonad.d.ts new file mode 100644 index 000000000..081c446c3 --- /dev/null +++ b/tsmonad/tsmonad.d.ts @@ -0,0 +1,640 @@ +// Type definitions for TsMonad +// Project: https://github.com/cbowdon/TsMonad +// Definitions by: Chris Bowdon +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +declare module TsMonad { + /** + * @name EitherType + * @description Enumerate the different types contained by an Either object. + */ + enum EitherType { + Left = 0, + Right = 1, + } + /** + * @name EitherPatterns + * @description Define a contract to unwrap Either object using callbacks + * for Left and Right. + * @see Either# + */ + interface EitherPatterns { + /** + * @name left + * @description Function to handle the Left. + * @type {(l: L) => T} + */ + left: (l: L) => T; + /** + * @name right + * @description Function to handle the Right. + * @type {(r: R) => T} + */ + right: (r: R) => T; + } + /** + * @name either + * @description Build an Either object. + * @function + * @param l The object as a Left (optional). + * @param r The object as a Right (optional). + * @returns {Either} Either object containing the input. + * @throws {TypeError} If there are both or none of left and right + * parameter. + * @see Either# + */ + function either(l?: L, r?: R): Either; + /** + * @name Either + * @class Either has exactly two sub types, Left (L) and Right (R). If an + * Either object contains an instance of L, then the Either is a + * Left. Otherwise it contains an instance of R and is a Right. By + * convention, the Left constructor is used to hold an error value and + * the Right constructor is used to hold a correct value. + */ + class Either implements Monad, Functor, Eq> { + private type; + private l; + private r; + /** + * @description Build an Either object. For internal use only. + * @constructor + * @methodOf Either# + * @param {EitherType} type Indicates if the Either content is a Left or a Right. + * @param {L} l The Left value (optional). + * @param {R} l The Right value (optional). + */ + constructor(type: EitherType, l?: L, r?: R); + /** + * @name left + * @description Helper function to build an Either with a Left. + * @methodOf Either# + * @static + * @param {L} l The Left value. + * @returns {Either} Either object containing a Left. + */ + static left(l: L): Either; + /** + * @name right + * @description Helper function to build an Either with a Right. + * @methodOf Either# + * @static + * @param {R} r The Right value. + * @returns {Either} Either object containing a Right. + */ + static right(r: R): Either; + /** + * @name unit + * @description Wrap a value inside an Either Right object. + * @methodOf Either# + * @public + * @param {T} t + * @returns {Either} Either object containing a Right. + * @see Monad#unit + */ + public unit(t: T): Either; + /** + * @name bind + * @description Apply the function passed as parameter on the object. + * @methodOf Either# + * @public + * @param {(r: R) => Either} f Function applied on the Right. + * @returns {Either} The result of the function f wrapped inside + * an Either object. + * @see Monad#bind + */ + public bind(f: (r: R) => Either): Either; + /** + * @name of + * @description Alias for unit. + * @methodOf Either# + * @public + * @see Either#unit + * @see Monad#of + */ + public of: (t: T) => Either; + /** + * @name chain + * @description Alias for bind. + * @methodOf Either# + * @public + * @see Either#bind + * @see Monad#chain + */ + public chain: (f: (r: R) => Either) => Either; + /** + * @name fmap + * @description Apply the function passed as parameter on the object. + * @methodOf Either# + * @public + * @param {(r: R) => T} f Function applied on the Right. + * @returns {Either} The result of the function f wrapped inside + * an Either object. + * @see Functor#fmap + */ + public fmap(f: (r: R) => T): Either; + /** + * @name lift + * @description Alias for fmap. + * @methodOf Either# + * @public + * @see Either#fmap + * @see Functor#lift + */ + public lift: (f: (r: R) => T) => Either; + /** + * @name map + * @description Alias for fmap. + * @methodOf Either# + * @public + * @see Either#fmap + * @see Functor#map + */ + public map: (f: (r: R) => T) => Either; + /** + * @name caseOf + * @description Execute a function depending on the Either content. + * It allows to unwrap the object for Left or Right types. + * @methodOf Either# + * @public + * @param {EitherPatterns} pattern Object containing the + * functions to applied on each Either types. + * @return {T} The returned value of the functions specified in the + * EitherPatterns interface. + * @see EitherPatterns# + */ + public caseOf(pattern: EitherPatterns): T; + /** + * @name equals + * @description Compare the type and the content of two Either + * objects. + * @methodOf Either# + * @public + * @param {Either} other The Either to compare with. + * @return {boolean} True if the type and content value are equals, + * false otherwise. + * @see Eq#equals + */ + public equals(other: Either): any; + } +} +declare module TsMonad { + /** + * @name eq + * @description Compare two objects : + * 1. if objects implement Eq, defer to their .equals + * 2. if are arrays, iterate and recur + * @function + * @param {any} a Any object. + * @param {any} b Any object. + * @returns {boolean} In case 1, the `.equals()` function returned value. + * In case 2, true if each elements are equals, false otherwise. + */ + function eq(a: any, b: any): any; + /** + * @name Eq + * @description Define a contract to compare (in)equalities between + * objects. + */ + interface Eq { + /** + * @name equals + * @description Determine if two objects are equals. + * @methodOf Eq + * @public + * @param {T} The object to compare with. + * @returns {boolean} True if the objects are equals, false otherwise. + */ + equals(t: T): boolean; + } + interface Monad { + /** + * @name unit + * @description Wrap an object inside a monad. + * @methodOf Monad# + * @public + * @param {U} t The object to wrap. + * @returns {Monad} A Monad with the value wrapped inside. + */ + unit(t: U): Monad; + /** + * @name bind + * @description Apply the function passed as parameter on the object. + * @methodOf Monad# + * @public + * @param {(t: T) => Monad} f Function applied on the Monad content. + * @returns {Monad} The result of the function f wrapped inside + * a Monad object. + */ + bind(f: (t: T) => Monad): Monad; + /** + * @name of + * @description Alias for unit. Fantasy Land Monad conformance. + * @methodOf Monad# + * @public + * @see Monad#unit + */ + of(t: U): Monad; + /** + * @name chain + * @description Alias for bind. Fantasy Land Monad conformance. + * @methodOf Monad# + * @public + * @see Monad#bind + */ + chain(f: (t: T) => Monad): Monad; + } + /** + * @name Functor + * @description Define a contract to add basic functor functions to an + * object. + */ + interface Functor { + /** + * @name fmap + * @description Apply the function passed as parameter on the object. + * @methodOf Functor# + * @public + * @param {(t: T) => U} f Function applied on the functor content. + * @returns {Functor} The result of the function f wrapped inside + * an Functor object. + * @see Functor#fmap + */ + fmap(f: (t: T) => U): Functor; + /** + * @name lift + * @description Alias for fmap. + * @methodOf Functor# + * @public + * @see Functor#fmap + */ + lift(f: (t: T) => U): Functor; + /** + * @name map + * @description Alias for fmap. Fantasy Land Monad conformance. + * @methodOf Functor# + * @public + * @see Functor#fmap + */ + map(f: (t: T) => U): Functor; + } +} +declare module TsMonad { + /** + * @name MaybeType + * @description Enumerate the different types contained by an Maybe object. + * @see Maybe# + */ + enum MaybeType { + Nothing = 0, + Just = 1, + } + /** + * @name MaybePatterns + * @description Define a contract to unwrap Maybe object using callbacks + * for Just and Nothing. + * @see Maybe# + */ + interface MaybePatterns { + /** + * @name just + * @description Function to handle the Just. + * @type {(t: T) => U} + */ + just: (t: T) => U; + /** + * @name nothing + * @description Function to handle the Nothing. + * @type {() => U} + */ + nothing: () => U; + } + /** + * @name maybe + * @description Build a Maybe object. + * @function + * @param {T} t The object to wrap. + * @returns {Maybe} A Maybe object containing the input. If t is null + * or undefined, the Maybe object is filled with Nothing. + * @see Maybe# + */ + function maybe(t: T): Maybe; + /** + * @name Maybe + * @class Encapsulates an optional value. A value of type Maybe a either + * contains a value of type a (represented as Just a), or it is empty + * (represented as Nothing). + */ + class Maybe implements Monad, Functor, Eq> { + private type; + private value; + /** + * @description Build a Maybe object. For internal use only. + * @constructor + * @methodOf Maybe# + * @param {MaybeType} type Indicates if the Maybe content is a Just or a Nothing. + * @param {T} value The value to wrap (optional). + */ + constructor(type: MaybeType, value?: T); + /** + * @name maybe + * @description Helper function to build a Maybe object. + * @methodOf Maybe# + * @static + * @param {T} t The value to wrap. + * @returns {Maybe} A Maybe object containing the value passed in input. If t is null + * or undefined, the Maybe object is filled with Nothing. + */ + static maybe(t: T): Maybe; + /** + * @name just + * @description Helper function to build a Maybe object filled with a + * Just type. + * @methodOf Maybe# + * @static + * @param {T} t The value to wrap. + * @returns {Maybe} A Maybe object containing the value passed in input. + * @throws {TypeError} If t is null or undefined. + */ + static just(t: T): Maybe; + /** + * @name nothing + * @description Helper function to build a Maybe object filled with a + * Nothing type. + * @methodOf Maybe# + * @static + * @returns {Maybe} A Maybe with a Nothing type. + */ + static nothing(): Maybe; + /** + * @name unit + * @description Wrap an object inside a Maybe. + * @public + * @methodOf Maybe# + * @param {U} u The object to wrap. + * @returns {Monad} A Monad with the value wrapped inside. + * @see Monad#unit + */ + public unit(u: U): Maybe; + /** + * @name bind + * @description Apply the function passed as parameter on the object. + * @methodOf Maybe# + * @public + * @param {(t: T) => Maybe} f Function applied on the Maybe content. + * @returns {Maybe} The result of the function f wrapped inside + * a Maybe object. + * @see Monad#bind + */ + public bind(f: (t: T) => Maybe): Maybe; + /** + * @name of + * @description Alias for unit. + * @methodOf Maybe# + * @public + * @see Maybe#unit + * @see Monad#of + */ + public of: (u: U) => Maybe; + /** + * @name chain + * @description Alias for bind. + * @methodOf Maybe# + * @public + * @see Maybe#unit + * @see Monad#of + */ + public chain: (f: (t: T) => Maybe) => Maybe; + /** + * @name fmap + * @description Apply the function passed as parameter on the object. + * @methodOf Maybe# + * @public + * @param {(t: T) => U} f Function applied on the Maybe content. + * @returns {Maybe} The result of the function f wrapped inside + * an Maybe object. + * @see Functor#fmap + */ + public fmap(f: (t: T) => U): Maybe; + /** + * @name lift + * @description Alias for fmap. + * @methodOf Maybe# + * @public + * @see Maybe#fmap + * @see Monad#of + */ + public lift: (f: (t: T) => U) => Maybe; + /** + * @name map + * @description Alias for fmap. + * @methodOf Maybe# + * @public + * @see Maybe#fmap + * @see Monad#of + */ + public map: (f: (t: T) => U) => Maybe; + /** + * @name caseOf + * @description Execute a function depending on the Maybe content. It + * allows to unwrap the object for Just or Nothing types. + * @methodOf Maybe# + * @public + * @param {MaybePatterns} pattern Object containing the + * functions to applied on each Maybe types. + * @return {U} The returned value of the functions specified in the + * MaybePatterns interface. + * @see MaybePatterns# + */ + public caseOf(patterns: MaybePatterns): U; + /** + * @name equals + * @description Compare the type and the content of two Maybe + * objects. + * @methodOf Maybe# + * @public + * @param {Maybe} other The Maybe to compare with. + * @return {boolean} True if the type and content value are equals, + * false otherwise. + * @see Eq#equals + */ + public equals(other: Maybe): any; + } +} +declare module TsMonad { + /** + * @name WriterPatterns + * @description Define a contract to unwrap Writer object using a + * callback. + * @see Writer# + */ + interface WriterPatterns { + /** + * @name writer + * @description Function to handle the Writer content. + * @type {(story: S[], value: T) => U} + */ + writer: (story: S[], value: T) => U; + } + /** + * @name writer + * @description Build a Writer object. + * @function + * @param {S[]} story The collection to store logs. + * @param {T} value The object to wrap. + * @returns {Writer} A Writer object containing the log collection + * and the wrapped value. + * @see Writer# + */ + function writer(story: S[], value: T): Writer; + /** + * @name Writer + * @class Allow to do computations while making sure that all the log + * values are combined into one log value that then gets attached to + * the result. + */ + class Writer implements Monad, Eq> { + private story; + private value; + /** + * @description Build a Writer object. For internal use only. + * @constructor + * @methodOf Writer# + * @param {S[]} story The collection of logs. + * @param {T} value The object to wrap. + */ + constructor(story: S[], value: T); + /** + * @name writer + * @description Helper function to build a Writer object. + * @methodOf Writer# + * @static + * @param {S[]} story The collection of logs. + * @param {T} value The object to wrap. + * @returns {Writer} A Writer object containing the collection of logs + * and the wrapped value. + */ + static writer(story: S[], value: T): Writer; + /** + * @name writer + * @description Helper function to build a Writer object with the log + * passed in input only. + * @methodOf Writer# + * @static + * @param {S} s A log to store. + * @returns {Writer} A Writer object containing the collection of logs + * and a zeroed value. + */ + static tell(s: S): Writer; + /** + * @name unit + * @description Wrap an object inside a Writer. + * @public + * @methodOf Writer# + * @param {U} u The object to wrap. + * @returns {Monad} A Writer with the value wrapped inside and an + * empty collection of logs. + * @see Monad#unit + */ + public unit(u: U): Writer; + /** + * @name bind + * @description Apply the function passed as parameter on the object. + * @methodOf Writer# + * @public + * @param {(t: T) => Writer} f Function applied on the Writer content. + * @returns {Writer} The result of the function f append to the + * Writer object. + * @see Monad#bind + */ + public bind(f: (t: T) => Writer): Writer; + /** + * @name of + * @description Alias for unit. + * @methodOf Writer# + * @public + * @see Writer#unit + * @see Monad#of + */ + public of: (u: U) => Writer; + /** + * @name chain + * @description Alias for bind + * @methodOf Writer# + * @public + * @see Writer#unit + * @see Monad#of + */ + public chain: (f: (t: T) => Writer) => Writer; + /** + * @name fmap + * @description Apply the function passed as parameter on the object. + * @methodOf Writer# + * @public + * @param {(t: T) => U} f Function applied on the wrapped value. + * @returns {Writer} The result of the function f wrapped inside + * an Writer object. It has an empty collection of logs. + * @see Functor#fmap + */ + public fmap(f: (t: T) => U): Writer; + /** + * @name lift + * @description Alias for fmap + * @methodOf Writer# + * @public + * @see Writer#fmap + * @see Monad#of + */ + public lift: (f: (t: T) => U) => Writer; + /** + * @name map + * @description Alias for fmap + * @methodOf Writer# + * @public + * @see Writer#fmap + * @see Monad#of + */ + public map: (f: (t: T) => U) => Writer; + /** + * @name caseOf + * @description Execute a function on the Writer content. It allows to + * unwrap the object. + * @methodOf Writer# + * @public + * @param {WriterPatterns} pattern Object containing the + * functions to applied on the Writer content. + * @return {U} The returned value of the function specified in the + * WriterPatterns interface. + * @see WriterPatterns# + */ + public caseOf(patterns: WriterPatterns): U; + /** + * @name equals + * @description Compare the type and the content of two Writer + * objects. + * @methodOf Writer# + * @public + * @param {Writer} other The Writer to compare with. + * @return {boolean} True if the collection of logs and content value + * are equals, false otherwise. + * @see Eq#equals + */ + public equals(other: Writer): boolean; + } +} +declare var module: { + exports: any; + require(id: string): any; + id: string; + filename: string; + loaded: boolean; + parent: any; + children: any[]; +}; +/** +* @name tsmonad +* @namespace Hold functionalities related to TsMonad library. +*/ +declare module 'tsmonad' { + export = TsMonad; +}