// Copyright (c) 2013-2014 Quildreen Motta <quildreen@gmail.com> // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation files // (the "Software"), to deal in the Software without restriction, // including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, // and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /** * @module lib/future */ module.exports = Future // -- Dependencies ----------------------------------------------------- var memoisedFork = require('./memoised').memoisedFork // -- Implementation --------------------------------------------------- /** * The `Future[α, β]` structure represents values that depend on time. This * allows one to model time-based effects explicitly, such that one can have * full knowledge of when they're dealing with delayed computations, latency, * or anything that can not be computed immediately. * * A common use for this structure is to replace the usual Continuation-Passing * Style form of programming, in order to be able to compose and sequence * time-dependent effects using the generic and powerful monadic operations. * * @class * @summary * ((α → Void), (β → Void) → Void) → Future[α, β] * * Future[α, β] <: Chain[β] * , Monad[β] * , Functor[β] * , Show */ function Future(f) { this.fork = f } /** * Creates a `Future[α, β]` that computes the action at most once. * * Since this function will remember the resolved value of the future, **it's * expected to be used only for pure actions,** otherwise you may not be able * to observe the effects. * * @summary ((α → Void), (β → Void) → Void) → Future[α, β] */ Future.prototype.memoise = function _memoise(f) { var future = new Future() future.fork = memoisedFork(f, future) return future } Future.memoise = Future.prototype.memoise /** * Constructs a new `Future[α, β]` containing the single value `β`. * * `β` can be any value, including `null`, `undefined`, or another * `Future[α, β]` structure. * * @summary β → Future[α, β] */ Future.prototype.of = function _of(b) { return new Future(function(_, resolve){ return resolve(b) }) } Future.of = Future.prototype.of // -- Functor ---------------------------------------------------------- /** * Transforms the successful value of the `Future[α, β]` using a regular unary * function. * * @summary @Future[α, β] => (β → γ) → Future[α, γ] */ Future.prototype.map = function _map(f) { return this.chain(function(a){ return Future.of(f(a)) }) } // -- Chain ------------------------------------------------------------ /** * Transforms the succesful value of the `Future[α, β]` using a function to a * monad. * * @summary @Future[α, β] => (β → Future[α, γ]) → Future[α, γ] */ Future.prototype.chain = function _chain(f) { return new Future(function(reject, resolve) { return this.fork( function(a){ return reject(a) } , function(b){ return f(b).fork(reject, resolve) }) }.bind(this)) } // -- Show ------------------------------------------------------------- /** * Returns a textual representation of the `Future[α, β]` * * @summary @Future[α, β] => Void → String */ Future.prototype.toString = function _toString() { return 'Future' } // -- Extracting and recovering ---------------------------------------- /** * Transforms a failure value into a new `Future[α, β]`. Does nothing if the * structure already contains a successful value. * * @summary @Future[α, β] => (α → Future[γ, β]) → Future[γ, β] */ Future.prototype.orElse = function _orElse(f) { return new Future(function(reject, resolve) { return this.fork( function(a){ return f(a).fork(reject, resolve) } , function(b){ return resolve(b) }) }.bind(this)) } // -- Folds and extended transformations ------------------------------- /** * Catamorphism. Takes two functions, applies the leftmost one to the failure * value, and the rightmost one to the successful value, depending on which one * is present. * * @summary @Future[α, β] => (α → γ), (β → γ) → Future[δ, γ] */ Future.prototype.fold = function _fold(f, g) { return new Future(function(reject, resolve) { return this.fork( function(a){ return resolve(f(a)) } , function(b){ return resolve(g(b)) }) }.bind(this)) } /** * Swaps the disjunction values. * * @summary @Future[α, β] => Void → Future[β, α] */ Future.prototype.swap = function _swap() { return new Future(function(reject, resolve) { return this.fork( function(a){ return resolve(a) } , function(b){ return reject(b) }) }.bind(this)) } /** * Maps both sides of the disjunction. * * @summary @Future[α, β] => (α → γ), (β → δ) → Future[γ, δ] */ Future.prototype.bimap = function _bimap(f, g) { return new Future(function(reject, resolve) { return this.fork( function(a){ return reject(f(a)) } , function(b){ return resolve(g(b)) }) }.bind(this)) } /** * Maps the left side of the disjunction (failure). * * @summary @Future[α, β] => (α → γ) → Future[γ, β] */ Future.prototype.rejectedMap = function _rejectedMap(f) { return new Future(function(reject, resolve) { return this.fork( function(a){ return reject(f(a)) } , function(b){ return resolve(b) }) }.bind(this)) }