diff --git a/README.md b/README.md index cd3f7f66..568b16ed 100644 --- a/README.md +++ b/README.md @@ -82,10 +82,10 @@ of Fluture's dependencies pre-bundled. or modern browsers. - [Fluture Module Minified][]: A minified EcmaScript module without TypeScript typings. Not recommended for Deno. -[Fluture Script]: https://cdn.jsdelivr.net/gh/fluture-js/Fluture@12.2.1/dist/bundle.js -[Fluture Script Minified]: https://cdn.jsdelivr.net/gh/fluture-js/Fluture@12.2.1/dist/bundle.min.js -[Fluture Module]: https://cdn.jsdelivr.net/gh/fluture-js/Fluture@12.2.1/dist/module.js -[Fluture Module Minified]: https://cdn.jsdelivr.net/gh/fluture-js/Fluture@12.2.1/dist/module.min.js +[Fluture Script]: https://cdn.jsdelivr.net/gh/fluture-js/Fluture@12.3.0/dist/bundle.js +[Fluture Script Minified]: https://cdn.jsdelivr.net/gh/fluture-js/Fluture@12.3.0/dist/bundle.min.js +[Fluture Module]: https://cdn.jsdelivr.net/gh/fluture-js/Fluture@12.3.0/dist/module.js +[Fluture Module Minified]: https://cdn.jsdelivr.net/gh/fluture-js/Fluture@12.3.0/dist/module.min.js ### CommonJS Module diff --git a/dist/bundle.js b/dist/bundle.js index 38665942..4405638e 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -1,5 +1,5 @@ /** - * Fluture bundled; version 12.2.1 + * Fluture bundled; version 12.3.0 */ var Fluture = (function () { diff --git a/dist/module.js b/dist/module.js new file mode 100644 index 00000000..4c05517c --- /dev/null +++ b/dist/module.js @@ -0,0 +1,2144 @@ +/** + * Fluture bundled; version 12.3.0 + */ + +/// + +function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; +} + +var sanctuaryTypeIdentifiers = createCommonjsModule(function (module) { +/* + @@@@@@@ @@@@@@@ @@ + @@ @@ @@ @@ @@@ + @@ @@@ @@ @@ @@ @@@ @@ @@ @@@@@@ @@ @@@ @@ @@@ @@@@ + @@ @@ @@@ @@ @@ @@ @@@ @@ @@@ @@ @@@ @@@ @@ @@@ @@ + @@ @@ @@@ @@ @@ @@ @@@ @@ @@@ @@ @@@ @@@ @@ @@@@@@@@ + @@ @@ @@@ @@ @@ @@ @@@ @@ @@@ @@ @@@ @@@ @@ @@@ + @@ @@@ @@@@@ @@ @@@ @@@@@ @@@ @@@ @@ @@@@@@ @@@@@ + @@ @@ @@ @@ + @@@@@@@ @@@@@@@ @@@@@ @@ + */ +//. # sanctuary-type-identifiers +//. +//. A type is a set of values. Boolean, for example, is the type comprising +//. `true` and `false`. A value may be a member of multiple types (`42` is a +//. member of Number, PositiveNumber, Integer, and many other types). +//. +//. In certain situations it is useful to divide JavaScript values into +//. non-overlapping types. The language provides two constructs for this +//. purpose: the [`typeof`][1] operator and [`Object.prototype.toString`][2]. +//. Each has pros and cons, but neither supports user-defined types. +//. +//. sanctuary-type-identifiers comprises: +//. +//. - an npm and browser -compatible package for deriving the +//. _type identifier_ of a JavaScript value; and +//. - a specification which authors may follow to specify type +//. identifiers for their types. +//. +//. ### Specification +//. +//. For a type to be compatible with the algorithm: +//. +//. - every member of the type MUST have a `@@type` property +//. (the _type identifier_); and +//. +//. - the type identifier MUST be a string primitive and SHOULD have +//. format `'/[@]'`, where: +//. +//. - `` MUST consist of one or more characters, and +//. SHOULD equal the name of the npm package which defines the +//. type (including [scope][3] where appropriate); +//. +//. - `` MUST consist of one or more characters, and SHOULD +//. be the unique name of the type; and +//. +//. - `` MUST consist of one or more digits, and SHOULD +//. represent the version of the type. +//. +//. If the type identifier does not conform to the format specified above, +//. it is assumed that the entire string represents the _name_ of the type; +//. _namespace_ will be `null` and _version_ will be `0`. +//. +//. If the _version_ is not given, it is assumed to be `0`. + +(function(f) { + + /* istanbul ignore else */ + { + module.exports = f (); + } + +} (function() { + + // $$type :: String + var $$type = '@@type'; + + // pattern :: RegExp + var pattern = new RegExp ( + '^' + + '([\\s\\S]+)' // + + '/' // SOLIDUS (U+002F) + + '([\\s\\S]+?)' // + + '(?:' // optional non-capturing group { + + '@' // COMMERCIAL AT (U+0040) + + '([0-9]+)' // + + ')?' // } + + '$' + ); + + //. ### Usage + //. + //. ```javascript + //. const type = require ('sanctuary-type-identifiers'); + //. ``` + //. + //. ```javascript + //. > const Identity$prototype = { + //. . '@@type': 'my-package/Identity@1', + //. . '@@show': function() { + //. . return 'Identity (' + show (this.value) + ')'; + //. . } + //. . } + //. + //. > const Identity = value => + //. . Object.assign (Object.create (Identity$prototype), {value}) + //. + //. > type (Identity (0)) + //. 'my-package/Identity@1' + //. + //. > type.parse (type (Identity (0))) + //. {namespace: 'my-package', name: 'Identity', version: 1} + //. ``` + //. + //. ### API + //. + //# type :: Any -> String + //. + //. Takes any value and returns a string which identifies its type. If the + //. value conforms to the [specification][4], the custom type identifier is + //. returned. + //. + //. ```javascript + //. > type (null) + //. 'Null' + //. + //. > type (true) + //. 'Boolean' + //. + //. > type (Identity (0)) + //. 'my-package/Identity@1' + //. ``` + function type(x) { + return x != null && + x.constructor != null && + x.constructor.prototype !== x && + typeof x[$$type] === 'string' ? + x[$$type] : + (Object.prototype.toString.call (x)).slice ('[object '.length, + -']'.length); + } + + //# type.parse :: String -> { namespace :: Nullable String, name :: String, version :: Number } + //. + //. Takes any string and parses it according to the [specification][4], + //. returning an object with `namespace`, `name`, and `version` fields. + //. + //. ```javascript + //. > type.parse ('my-package/List@2') + //. {namespace: 'my-package', name: 'List', version: 2} + //. + //. > type.parse ('nonsense!') + //. {namespace: null, name: 'nonsense!', version: 0} + //. + //. > type.parse (type (Identity (0))) + //. {namespace: 'my-package', name: 'Identity', version: 1} + //. ``` + type.parse = function parse(s) { + var namespace = null; + var name = s; + var version = 0; + var groups = pattern.exec (s); + if (groups != null) { + namespace = groups[1]; + name = groups[2]; + if (groups[3] != null) version = Number (groups[3]); + } + return {namespace: namespace, name: name, version: version}; + }; + + return type; + +})); + +//. [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof +//. [2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString +//. [3]: https://docs.npmjs.com/misc/scope +//. [4]: #specification +}); + +var FL = { + alt: 'fantasy-land/alt', + ap: 'fantasy-land/ap', + bimap: 'fantasy-land/bimap', + chain: 'fantasy-land/chain', + chainRec: 'fantasy-land/chainRec', + map: 'fantasy-land/map', + of: 'fantasy-land/of', + zero: 'fantasy-land/zero' +}; + +var ordinal = ['first', 'second', 'third', 'fourth', 'fifth']; + +var namespace = 'fluture'; +var name = 'Future'; +var version = 5; + +var $$type = namespace + '/' + name + '@' + version; + +function List(head, tail){ + this.head = head; + this.tail = tail; +} + +List.prototype.toJSON = function(){ + return toArray(this); +}; + +var nil = new List(null, null); +nil.tail = nil; + +function isNil(list){ + return list.tail === list; +} + +// cons :: (a, List a) -> List a +// -- O(1) append operation +function cons(head, tail){ + return new List(head, tail); +} + +// reverse :: List a -> List a +// -- O(n) list reversal +function reverse(xs){ + var ys = nil, tail = xs; + while(!isNil(tail)){ + ys = cons(tail.head, ys); + tail = tail.tail; + } + return ys; +} + +// cat :: (List a, List a) -> List a +// -- O(n) list concatenation +function cat(xs, ys){ + var zs = ys, tail = reverse(xs); + while(!isNil(tail)){ + zs = cons(tail.head, zs); + tail = tail.tail; + } + return zs; +} + +// toArray :: List a -> Array a +// -- O(n) list to Array +function toArray(xs){ + var tail = xs, arr = []; + while(!isNil(tail)){ + arr.push(tail.head); + tail = tail.tail; + } + return arr; +} + +/* c8 ignore next */ +var captureStackTrace = Error.captureStackTrace || captureStackTraceFallback; +var _debug = debugHandleNone; + +function debugMode(debug){ + _debug = debug ? debugHandleAll : debugHandleNone; +} + +function debugHandleNone(x){ + return x; +} + +function debugHandleAll(x, fn, a, b, c){ + return fn(a, b, c); +} + +function debug(x, fn, a, b, c){ + return _debug(x, fn, a, b, c); +} + +function captureContext(previous, tag, fn){ + return debug(previous, debugCaptureContext, previous, tag, fn); +} + +function debugCaptureContext(previous, tag, fn){ + var context = {tag: tag, name: ' from ' + tag + ':'}; + captureStackTrace(context, fn); + return cons(context, previous); +} + +function captureApplicationContext(context, n, f){ + return debug(context, debugCaptureApplicationContext, context, n, f); +} + +function debugCaptureApplicationContext(context, n, f){ + return debugCaptureContext(context, ordinal[n - 1] + ' application of ' + f.name, f); +} + +function captureStackTraceFallback(x){ + var e = new Error; + if(typeof e.stack === 'string'){ + x.stack = x.name + '\n' + e.stack.split('\n').slice(1).join('\n'); + /* c8 ignore next 3 */ + }else { + x.stack = x.name; + } +} + +var sanctuaryShow = createCommonjsModule(function (module) { +//. # sanctuary-show +//. +//. Haskell has a `show` function which can be applied to a compatible value to +//. produce a descriptive string representation of that value. The idea is that +//. the string representation should, if possible, be an expression which would +//. produce the original value if evaluated. +//. +//. This library provides a similar [`show`](#show) function. +//. +//. In general, this property should hold: `eval (show (x)) = x`. In some cases +//. parens are necessary to ensure correct interpretation (`{}`, for example, +//. is an empty block rather than an empty object in some contexts). Thus the +//. property is more accurately stated `eval ('(' + show (x) + ')') = x`. +//. +//. One can make values of a custom type compatible with [`show`](#show) by +//. defining a `@@show` method. For example: +//. +//. ```javascript +//. //# Maybe#@@show :: Maybe a ~> () -> String +//. //. +//. //. ```javascript +//. //. > show (Nothing) +//. //. 'Nothing' +//. //. +//. //. > show (Just (['foo', 'bar', 'baz'])) +//. //. 'Just (["foo", "bar", "baz"])' +//. //. ``` +//. Maybe.prototype['@@show'] = function() { +//. return this.isNothing ? 'Nothing' : 'Just (' + show (this.value) + ')'; +//. }; +//. ``` + +(function(f) { + + /* istanbul ignore else */ + { + module.exports = f (); + } + +} (function() { + + // $$show :: String + var $$show = '@@show'; + + // seen :: Array Any + var seen = []; + + // entry :: Object -> String -> String + function entry(o) { + return function(k) { + return show (k) + ': ' + show (o[k]); + }; + } + + // sortedKeys :: Object -> Array String + function sortedKeys(o) { + return (Object.keys (o)).sort (); + } + + //# show :: Showable a => a -> String + //. + //. Returns a useful string representation of the given value. + //. + //. Dispatches to the value's `@@show` method if present. + //. + //. Where practical, `show (eval ('(' + show (x) + ')')) = show (x)`. + //. + //. ```javascript + //. > show (null) + //. 'null' + //. + //. > show (undefined) + //. 'undefined' + //. + //. > show (true) + //. 'true' + //. + //. > show (new Boolean (false)) + //. 'new Boolean (false)' + //. + //. > show (-0) + //. '-0' + //. + //. > show (NaN) + //. 'NaN' + //. + //. > show (new Number (Infinity)) + //. 'new Number (Infinity)' + //. + //. > show ('foo\n"bar"\nbaz\n') + //. '"foo\\n\\"bar\\"\\nbaz\\n"' + //. + //. > show (new String ('')) + //. 'new String ("")' + //. + //. > show (['foo', 'bar', 'baz']) + //. '["foo", "bar", "baz"]' + //. + //. > show ([[[[[0]]]]]) + //. '[[[[[0]]]]]' + //. + //. > show ({x: [1, 2], y: [3, 4], z: [5, 6]}) + //. '{"x": [1, 2], "y": [3, 4], "z": [5, 6]}' + //. ``` + function show(x) { + if (seen.indexOf (x) >= 0) return ''; + + switch (Object.prototype.toString.call (x)) { + + case '[object Boolean]': + return typeof x === 'object' ? + 'new Boolean (' + show (x.valueOf ()) + ')' : + x.toString (); + + case '[object Number]': + return typeof x === 'object' ? + 'new Number (' + show (x.valueOf ()) + ')' : + 1 / x === -Infinity ? '-0' : x.toString (10); + + case '[object String]': + return typeof x === 'object' ? + 'new String (' + show (x.valueOf ()) + ')' : + JSON.stringify (x); + + case '[object Date]': + return 'new Date (' + + show (isNaN (x.valueOf ()) ? NaN : x.toISOString ()) + + ')'; + + case '[object Error]': + return 'new ' + x.name + ' (' + show (x.message) + ')'; + + case '[object Arguments]': + return 'function () { return arguments; } (' + + (Array.prototype.map.call (x, show)).join (', ') + + ')'; + + case '[object Array]': + seen.push (x); + try { + return '[' + ((x.map (show)).concat ( + sortedKeys (x) + .filter (function(k) { return !(/^\d+$/.test (k)); }) + .map (entry (x)) + )).join (', ') + ']'; + } finally { + seen.pop (); + } + + case '[object Object]': + seen.push (x); + try { + return ( + $$show in x && + (x.constructor == null || x.constructor.prototype !== x) ? + x[$$show] () : + '{' + ((sortedKeys (x)).map (entry (x))).join (', ') + '}' + ); + } finally { + seen.pop (); + } + + case '[object Set]': + seen.push (x); + try { + return 'new Set (' + show (Array.from (x.values ())) + ')'; + } finally { + seen.pop (); + } + + case '[object Map]': + seen.push (x); + try { + return 'new Map (' + show (Array.from (x.entries ())) + ')'; + } finally { + seen.pop (); + } + + default: + return String (x); + + } + } + + return show; + +})); +}); + +/* c8 ignore next */ +var setImmediate = typeof setImmediate === 'undefined' ? setImmediateFallback : setImmediate; + +function noop(){} +function moop(){ return this } +function call(f, x){ return f(x) } + +function setImmediateFallback(f, x){ + return setTimeout(f, 0, x); +} + +function raise(x){ + setImmediate(function rethrowErrorDelayedToEscapePromiseCatch(){ + throw x; + }); +} + +function showArg(x){ + return sanctuaryShow(x) + ' :: ' + sanctuaryTypeIdentifiers.parse(sanctuaryTypeIdentifiers(x)).name; +} + +function error(message){ + return new Error(message); +} + +function typeError(message){ + return new TypeError(message); +} + +function invalidArgument(it, at, expected, actual){ + return typeError( + it + '() expects its ' + ordinal[at] + ' argument to ' + expected + '.' + + '\n Actual: ' + showArg(actual) + ); +} + +function invalidArgumentOf(expected){ + return function(it, at, actual){ + return invalidArgument(it, at, expected, actual); + }; +} + +function invalidArity(f, args){ + return new TypeError( + f.name + '() expects to be called with a single argument per invocation\n' + + ' Saw: ' + args.length + ' arguments' + + Array.prototype.slice.call(args).map(function(arg, i){ + return '\n ' + ( + ordinal[i] ? + ordinal[i].charAt(0).toUpperCase() + ordinal[i].slice(1) : + 'Argument ' + String(i + 1) + ) + ': ' + showArg(arg); + }).join('') + ); +} + +function invalidNamespace(m, x){ + return ( + 'The Future was not created by ' + namespace + '. ' + + 'Make sure you transform other Futures to ' + namespace + ' Futures. ' + + 'Got ' + (x ? ('a Future from ' + x) : 'an unscoped Future') + '.' + + '\n See: https://github.com/fluture-js/Fluture#casting-futures' + ); +} + +function invalidVersion(m, x){ + return ( + 'The Future was created by ' + (x < version ? 'an older' : 'a newer') + + ' version of ' + namespace + '. ' + + 'This means that one of the sources which creates Futures is outdated. ' + + 'Update this source, or transform its created Futures to be compatible.' + + '\n See: https://github.com/fluture-js/Fluture#casting-futures' + ); +} + +function invalidFuture(desc, m, s){ + var id = sanctuaryTypeIdentifiers.parse(sanctuaryTypeIdentifiers(m)); + var info = id.name === name ? '\n' + ( + id.namespace !== namespace ? invalidNamespace(m, id.namespace) + : id.version !== version ? invalidVersion(m, id.version) + : 'Nothing seems wrong. Contact the Fluture maintainers.') : ''; + return typeError( + desc + ' to be a valid Future.' + info + '\n' + + ' Actual: ' + sanctuaryShow(m) + ' :: ' + id.name + (s || '') + ); +} + +function invalidFutureArgument(it, at, m, s){ + return invalidFuture(it + '() expects its ' + ordinal[at] + ' argument', m, s); +} + +function ensureError(value, fn){ + var message; + try{ + if(value instanceof Error) return value; + message = 'A Non-Error was thrown from a Future: ' + sanctuaryShow(value); + }catch (_){ + message = 'Something was thrown from a Future, but it could not be converted to String'; + } + var e = error(message); + captureStackTrace(e, fn); + return e; +} + +function assignUnenumerable(o, prop, value){ + Object.defineProperty(o, prop, {value: value, writable: true, configurable: true}); +} + +function wrapException(caught, callingFuture){ + var origin = ensureError(caught, wrapException); + var context = cat(origin.context || nil, callingFuture.context); + var e = error(origin.message); + assignUnenumerable(e, 'future', origin.future || callingFuture); + assignUnenumerable(e, 'reason', origin.reason || origin); + assignUnenumerable(e, 'stack', e.reason.stack); + return withExtraContext(e, context); +} + +function withExtraContext(e, context){ + assignUnenumerable(e, 'context', context); + assignUnenumerable(e, 'stack', e.stack + contextToStackTrace(context)); + return e; +} + +function contextToStackTrace(context){ + var stack = '', tail = context; + while(tail !== nil){ + stack = stack + '\n' + tail.head.stack; + tail = tail.tail; + } + return stack; +} + +function isFunction(f){ + return typeof f === 'function'; +} + +function isThenable(m){ + return m instanceof Promise || m != null && isFunction(m.then); +} + +function isBoolean(f){ + return typeof f === 'boolean'; +} + +function isNumber(f){ + return typeof f === 'number'; +} + +function isUnsigned(n){ + return (n === Infinity || isNumber(n) && n > 0 && n % 1 === 0); +} + +function isObject(o){ + return o !== null && typeof o === 'object'; +} + +function isIterator(i){ + return isObject(i) && isFunction(i.next); +} + +function isArray(x){ + return Array.isArray(x); +} + +function hasMethod(method, x){ + return x != null && isFunction(x[method]); +} + +function isFunctor(x){ + return hasMethod(FL.map, x); +} + +function isAlt(x){ + return isFunctor(x) && hasMethod(FL.alt, x); +} + +function isApply(x){ + return isFunctor(x) && hasMethod(FL.ap, x); +} + +function isBifunctor(x){ + return isFunctor(x) && hasMethod(FL.bimap, x); +} + +function isChain(x){ + return isApply(x) && hasMethod(FL.chain, x); +} + +function Next(x){ + return {done: false, value: x}; +} + +function Done(x){ + return {done: true, value: x}; +} + +function isIteration(x){ + return isObject(x) && isBoolean(x.done); +} + +/*eslint no-cond-assign:0, no-constant-condition:0 */ + +function alwaysTrue(){ + return true; +} + +function getArgs(it){ + var args = new Array(it.arity); + for(var i = 1; i <= it.arity; i++){ + args[i - 1] = it['$' + String(i)]; + } + return args; +} + +function showArg$1(arg){ + return ' (' + sanctuaryShow(arg) + ')'; +} + +var any = {pred: alwaysTrue, error: invalidArgumentOf('be anything')}; +var func = {pred: isFunction, error: invalidArgumentOf('be a Function')}; +var future = {pred: isFuture, error: invalidFutureArgument}; +var positiveInteger = {pred: isUnsigned, error: invalidArgumentOf('be a positive Integer')}; + +function application(n, f, type, args, prev){ + if(args.length < 2 && type.pred(args[0])) return captureApplicationContext(prev, n, f); + var e = args.length > 1 ? invalidArity(f, args) : type.error(f.name, n - 1, args[0]); + captureStackTrace(e, f); + throw withExtraContext(e, prev); +} + +function application1(f, type, args){ + return application(1, f, type, args, nil); +} + +function Future(computation){ + var context = application1(Future, func, arguments); + return new Computation(context, computation); +} + +function isFuture(x){ + return x instanceof Future || sanctuaryTypeIdentifiers(x) === $$type; +} + +// Compliance with sanctuary-type-identifiers versions 1 and 2. +// To prevent sanctuary-type-identifiers version 3 from identifying 'Future' +// as being of the type denoted by $$type, we ensure that +// Future.constructor.prototype is equal to Future. +Future['@@type'] = $$type; +Future.constructor = {prototype: Future}; + +Future[FL.of] = resolve; +Future[FL.chainRec] = chainRec; + +Future.prototype['@@type'] = $$type; + +Future.prototype['@@show'] = function Future$show(){ + return this.toString(); +}; + +Future.prototype.pipe = function Future$pipe(f){ + if(!isFunction(f)) throw invalidArgument('Future#pipe', 0, 'be a Function', f); + return f(this); +}; + +Future.prototype[FL.ap] = function Future$FL$ap(other){ + var context = captureContext(nil, 'a Fantasy Land dispatch to ap', Future$FL$ap); + return other._transform(new ApTransformation(context, this)); +}; + +Future.prototype[FL.map] = function Future$FL$map(mapper){ + var context = captureContext(nil, 'a Fantasy Land dispatch to map', Future$FL$map); + return this._transform(new MapTransformation(context, mapper)); +}; + +Future.prototype[FL.bimap] = function Future$FL$bimap(lmapper, rmapper){ + var context = captureContext(nil, 'a Fantasy Land dispatch to bimap', Future$FL$bimap); + return this._transform(new BimapTransformation(context, lmapper, rmapper)); +}; + +Future.prototype[FL.chain] = function Future$FL$chain(mapper){ + var context = captureContext(nil, 'a Fantasy Land dispatch to chain', Future$FL$chain); + return this._transform(new ChainTransformation(context, mapper)); +}; + +Future.prototype[FL.alt] = function Future$FL$alt(other){ + var context = captureContext(nil, 'a Fantasy Land dispatch to alt', Future$FL$alt); + return this._transform(new AltTransformation(context, other)); +}; + +Future.prototype.extractLeft = function Future$extractLeft(){ + return []; +}; + +Future.prototype.extractRight = function Future$extractRight(){ + return []; +}; + +Future.prototype._transform = function Future$transform(transformation){ + return new Transformer(transformation.context, this, cons(transformation, nil)); +}; + +Future.prototype.isTransformer = false; +Future.prototype.context = nil; +Future.prototype.arity = 0; +Future.prototype.name = 'future'; + +Future.prototype.toString = function Future$toString(){ + return this.name + getArgs(this).map(showArg$1).join(''); +}; + +Future.prototype.toJSON = function Future$toJSON(){ + return {$: $$type, kind: 'interpreter', type: this.name, args: getArgs(this)}; +}; + +function createInterpreter(arity, name, interpret){ + var Interpreter = function(context, $1, $2, $3){ + this.context = context; + this.$1 = $1; + this.$2 = $2; + this.$3 = $3; + }; + + Interpreter.prototype = Object.create(Future.prototype); + Interpreter.prototype.arity = arity; + Interpreter.prototype.name = name; + Interpreter.prototype._interpret = interpret; + + return Interpreter; +} + +var Computation = +createInterpreter(1, 'Future', function Computation$interpret(rec, rej, res){ + var computation = this.$1, open = false, cancel = noop, cont = function(){ open = true; }; + try{ + cancel = computation(function Computation$rej(x){ + cont = function Computation$rej$cont(){ + open = false; + rej(x); + }; + if(open){ + cont(); + } + }, function Computation$res(x){ + cont = function Computation$res$cont(){ + open = false; + res(x); + }; + if(open){ + cont(); + } + }); + }catch(e){ + rec(wrapException(e, this)); + return noop; + } + if(!(isFunction(cancel) && cancel.length === 0)){ + rec(wrapException(typeError( + 'The computation was expected to return a nullary cancellation function\n' + + ' Actual: ' + sanctuaryShow(cancel) + ), this)); + return noop; + } + cont(); + return function Computation$cancel(){ + if(open){ + open = false; + cancel && cancel(); + } + }; +}); + +var Never = createInterpreter(0, 'never', function Never$interpret(){ + return noop; +}); + +Never.prototype._isNever = true; + +var never = new Never(nil); + +function isNever(x){ + return isFuture(x) && x._isNever === true; +} + +var Crash = createInterpreter(1, 'crash', function Crash$interpret(rec){ + rec(this.$1); + return noop; +}); + +function crash(x){ + return new Crash(application1(crash, any, arguments), x); +} + +var Reject = createInterpreter(1, 'reject', function Reject$interpret(rec, rej){ + rej(this.$1); + return noop; +}); + +Reject.prototype.extractLeft = function Reject$extractLeft(){ + return [this.$1]; +}; + +function reject(x){ + return new Reject(application1(reject, any, arguments), x); +} + +var Resolve = createInterpreter(1, 'resolve', function Resolve$interpret(rec, rej, res){ + res(this.$1); + return noop; +}); + +Resolve.prototype.extractRight = function Resolve$extractRight(){ + return [this.$1]; +}; + +function resolve(x){ + return new Resolve(application1(resolve, any, arguments), x); +} + +//Note: This function is not curried because it's only used to satisfy the +// Fantasy Land ChainRec specification. +function chainRec(step, init){ + return resolve(Next(init))._transform(new ChainTransformation(nil, function chainRec$recur(o){ + return o.done ? + resolve(o.value) : + step(Next, Done, o.value)._transform(new ChainTransformation(nil, chainRec$recur)); + })); +} + +var Transformer = +createInterpreter(2, 'transform', function Transformer$interpret(rec, rej, res){ + + //These are the cold, and hot, transformation stacks. The cold actions are those that + //have yet to run parallel computations, and hot are those that have. + var cold = nil, hot = nil; + + //These combined variables define our current state. + // future = the future we are currently forking + // transformation = the transformation to be informed when the future settles + // cancel = the cancel function of the current future + // settled = a boolean indicating whether a new tick should start + // async = a boolean indicating whether we are awaiting a result asynchronously + var future, transformation, cancel = noop, settled, async = true, it; + + //Takes a transformation from the top of the hot stack and returns it. + function nextHot(){ + var x = hot.head; + hot = hot.tail; + return x; + } + + //Takes a transformation from the top of the cold stack and returns it. + function nextCold(){ + var x = cold.head; + cold = cold.tail; + return x; + } + + //This function is called with a future to use in the next tick. + //Here we "flatten" the actions of another Sequence into our own actions, + //this is the magic that allows for infinitely stack safe recursion because + //actions like ChainAction will return a new Sequence. + //If we settled asynchronously, we call drain() directly to run the next tick. + function settle(m){ + settled = true; + future = m; + if(future.isTransformer){ + var tail = future.$2; + while(!isNil(tail)){ + cold = cons(tail.head, cold); + tail = tail.tail; + } + future = future.$1; + } + if(async) drain(); + } + + //This function serves as a rejection handler for our current future. + //It will tell the current transformation that the future rejected, and it will + //settle the current tick with the transformation's answer to that. + function rejected(x){ + settle(transformation.rejected(x)); + } + + //This function serves as a resolution handler for our current future. + //It will tell the current transformation that the future resolved, and it will + //settle the current tick with the transformation's answer to that. + function resolved(x){ + settle(transformation.resolved(x)); + } + + //This function is passed into actions when they are "warmed up". + //If the transformation decides that it has its result, without the need to await + //anything else, then it can call this function to force "early termination". + //When early termination occurs, all actions which were stacked prior to the + //terminator will be skipped. If they were already hot, they will also be + //sent a cancel signal so they can cancel their own concurrent computations, + //as their results are no longer needed. + function early(m, terminator){ + cancel(); + cold = nil; + if(async && transformation !== terminator){ + transformation.cancel(); + while((it = nextHot()) && it !== terminator) it.cancel(); + } + settle(m); + } + + //This will cancel the current Future, the current transformation, and all stacked hot actions. + function Sequence$cancel(){ + cancel(); + transformation && transformation.cancel(); + while(it = nextHot()) it.cancel(); + } + + //This function is called when an exception is caught. + function exception(e){ + Sequence$cancel(); + settled = true; + cold = hot = nil; + var error = wrapException(e, future); + future = never; + rec(error); + } + + //This function serves to kickstart concurrent computations. + //Takes all actions from the cold stack in reverse order, and calls run() on + //each of them, passing them the "early" function. If any of them settles (by + //calling early()), we abort. After warming up all actions in the cold queue, + //we warm up the current transformation as well. + function warmupActions(){ + cold = reverse(cold); + while(cold !== nil){ + it = cold.head.run(early); + if(settled) return; + hot = cons(it, hot); + cold = cold.tail; + } + transformation = transformation.run(early); + } + + //This function represents our main execution loop. By "tick", we've been + //referring to the execution of one iteration in the while-loop below. + function drain(){ + async = false; + while(true){ + settled = false; + if(transformation = nextCold()){ + cancel = future._interpret(exception, rejected, resolved); + if(!settled) warmupActions(); + }else if(transformation = nextHot()){ + cancel = future._interpret(exception, rejected, resolved); + }else break; + if(settled) continue; + async = true; + return; + } + cancel = future._interpret(exception, rej, res); + } + + //Start the execution loop. + settle(this); + + //Return the cancellation function. + return Sequence$cancel; + +}); + +Transformer.prototype.isTransformer = true; + +Transformer.prototype._transform = function Transformer$_transform(transformation){ + return new Transformer(transformation.context, this.$1, cons(transformation, this.$2)); +}; + +Transformer.prototype.toString = function Transformer$toString(){ + return toArray(reverse(this.$2)).reduce(function(str, action){ + return action.name + getArgs(action).map(showArg$1).join('') + ' (' + str + ')'; + }, this.$1.toString()); +}; + +function BaseTransformation$rejected(x){ + this.cancel(); + return new Reject(this.context, x); +} + +function BaseTransformation$resolved(x){ + this.cancel(); + return new Resolve(this.context, x); +} + +function BaseTransformation$toJSON(){ + return {$: $$type, kind: 'transformation', type: this.name, args: getArgs(this)}; +} + +var BaseTransformation = { + rejected: BaseTransformation$rejected, + resolved: BaseTransformation$resolved, + run: moop, + cancel: noop, + context: nil, + arity: 0, + name: 'transform', + toJSON: BaseTransformation$toJSON +}; + +function wrapHandler(handler){ + return function transformationHandler(x){ + var m; + try{ + m = handler.call(this, x); + }catch(e){ + return new Crash(this.context, e); + } + if(isFuture(m)){ + return m; + } + return new Crash(this.context, invalidFuture( + this.name + ' expects the return value from the function it\'s given', m, + '\n When called with: ' + sanctuaryShow(x) + )); + }; +} + +function createTransformation(arity, name, prototype){ + var Transformation = function(context, $1, $2){ + this.context = context; + this.$1 = $1; + this.$2 = $2; + }; + + Transformation.prototype = Object.create(BaseTransformation); + Transformation.prototype.arity = arity; + Transformation.prototype.name = name; + + if(typeof prototype.rejected === 'function'){ + Transformation.prototype.rejected = wrapHandler(prototype.rejected); + } + + if(typeof prototype.resolved === 'function'){ + Transformation.prototype.resolved = wrapHandler(prototype.resolved); + } + + if(typeof prototype.run === 'function'){ + Transformation.prototype.run = prototype.run; + } + + return Transformation; +} + +var ApTransformation = createTransformation(1, 'ap', { + resolved: function ApTransformation$resolved(f){ + if(isFunction(f)) return this.$1._transform(new MapTransformation(this.context, f)); + throw typeError( + 'ap expects the second Future to resolve to a Function\n' + + ' Actual: ' + sanctuaryShow(f) + ); + } +}); + +var AltTransformation = createTransformation(1, 'alt', { + rejected: function AltTransformation$rejected(){ return this.$1 } +}); + +var MapTransformation = createTransformation(1, 'map', { + resolved: function MapTransformation$resolved(x){ + return new Resolve(this.context, call(this.$1, x)); + } +}); + +var BimapTransformation = createTransformation(2, 'bimap', { + rejected: function BimapTransformation$rejected(x){ + return new Reject(this.context, call(this.$1, x)); + }, + resolved: function BimapTransformation$resolved(x){ + return new Resolve(this.context, call(this.$2, x)); + } +}); + +var ChainTransformation = createTransformation(1, 'chain', { + resolved: function ChainTransformation$resolved(x){ return call(this.$1, x) } +}); + +var After = createInterpreter(2, 'after', function After$interpret(rec, rej, res){ + var id = setTimeout(res, this.$1, this.$2); + return function After$cancel(){ clearTimeout(id); }; +}); + +After.prototype.extractRight = function After$extractRight(){ + return [this.$2]; +}; + +function alwaysNever(_){ + return never; +} + +function after(time){ + var context1 = application1(after, positiveInteger, arguments); + return time === Infinity ? alwaysNever : (function after(value){ + var context2 = application(2, after, any, arguments, context1); + return new After(context2, time, value); + }); +} + +var alternative = {pred: isAlt, error: invalidArgumentOf('have Alt implemented')}; + +function alt(left){ + if(isFuture(left)){ + var context1 = application1(alt, future, arguments); + return function alt(right){ + var context2 = application(2, alt, future, arguments, context1); + return right._transform(new AltTransformation(context2, left)); + }; + } + + var context = application1(alt, alternative, arguments); + return function alt(right){ + application(2, alt, alternative, arguments, context); + return left[FL.alt](right); + }; +} + +var AndTransformation = createTransformation(1, 'and', { + resolved: function AndTransformation$resolved(){ return this.$1 } +}); + +function and(left){ + var context1 = application1(and, future, arguments); + return function and(right){ + var context2 = application(2, and, future, arguments, context1); + return right._transform(new AndTransformation(context2, left)); + }; +} + +var apply = {pred: isApply, error: invalidArgumentOf('have Apply implemented')}; + +function ap(mx){ + if(isFuture(mx)){ + var context1 = application1(ap, future, arguments); + return function ap(mf){ + var context2 = application(2, ap, future, arguments, context1); + return mf._transform(new ApTransformation(context2, mx)); + }; + } + + var context = application1(ap, apply, arguments); + return function ap(mf){ + application(2, ap, apply, arguments, context); + return mx[FL.ap](mf); + }; +} + +function invalidPromise(p, f, a){ + return typeError( + 'encaseP() expects the function it\'s given to return a Promise/Thenable' + + '\n Actual: ' + sanctuaryShow(p) + '\n From calling: ' + sanctuaryShow(f) + + '\n With: ' + sanctuaryShow(a) + ); +} + +var EncaseP = createInterpreter(2, 'encaseP', function EncaseP$interpret(rec, rej, res){ + var open = true, fn = this.$1, arg = this.$2, p; + try{ + p = fn(arg); + }catch(e){ + rec(wrapException(e, this)); + return noop; + } + if(!isThenable(p)){ + rec(wrapException(invalidPromise(p, fn, arg), this)); + return noop; + } + p.then(function EncaseP$res(x){ + if(open){ + open = false; + res(x); + } + }, function EncaseP$rej(x){ + if(open){ + open = false; + rej(x); + } + }); + return function EncaseP$cancel(){ open = false; }; +}); + +function encaseP(f){ + var context1 = application1(encaseP, func, arguments); + return function encaseP(x){ + var context2 = application(2, encaseP, any, arguments, context1); + return new EncaseP(context2, f, x); + }; +} + +function attemptP(_){ + return encaseP.apply(this, arguments)(undefined); +} + +var Encase = createInterpreter(2, 'encase', function Encase$interpret(rec, rej, res){ + var fn = this.$1, r; + try{ r = fn(this.$2); }catch(e){ rej(e); return noop } + res(r); + return noop; +}); + +function encase(f){ + var context1 = application1(encase, func, arguments); + return function encase(x){ + var context2 = application(2, encase, any, arguments, context1); + return new Encase(context2, f, x); + }; +} + +function attempt(_){ + return encase.apply(this, arguments)(undefined); +} + +var bifunctor = {pred: isBifunctor, error: invalidArgumentOf('have Bifunctor implemented')}; + +function bimap(f){ + var context1 = application1(bimap, func, arguments); + return function bimap(g){ + var context2 = application(2, bimap, func, arguments, context1); + return function bimap(m){ + var context3 = application(3, bimap, bifunctor, arguments, context2); + return isFuture(m) ? + m._transform(new BimapTransformation(context3, f, g)) : + m[FL.bimap](f, g); + }; + }; +} + +var BichainTransformation = createTransformation(2, 'bichain', { + rejected: function BichainTransformation$rejected(x){ return call(this.$1, x) }, + resolved: function BichainTransformation$resolved(x){ return call(this.$2, x) } +}); + +function bichain(f){ + var context1 = application1(bichain, func, arguments); + return function bichain(g){ + var context2 = application(2, bichain, func, arguments, context1); + return function bichain(m){ + var context3 = application(3, bichain, future, arguments, context2); + return m._transform(new BichainTransformation(context3, f, g)); + }; + }; +} + +function Eager(future){ + var _this = this; + _this.rec = noop; + _this.rej = noop; + _this.res = noop; + _this.crashed = false; + _this.rejected = false; + _this.resolved = false; + _this.value = null; + _this.cancel = future._interpret(function Eager$crash(x){ + _this.value = x; + _this.crashed = true; + _this.cancel = noop; + _this.rec(x); + }, function Eager$reject(x){ + _this.value = x; + _this.rejected = true; + _this.cancel = noop; + _this.rej(x); + }, function Eager$resolve(x){ + _this.value = x; + _this.resolved = true; + _this.cancel = noop; + _this.res(x); + }); +} + +Eager.prototype = Object.create(Future.prototype); + +Eager.prototype._interpret = function Eager$interpret(rec, rej, res){ + if(this.crashed) rec(this.value); + else if(this.rejected) rej(this.value); + else if(this.resolved) res(this.value); + else { + this.rec = rec; + this.rej = rej; + this.res = res; + } + return this.cancel; +}; + +function earlyCrash(early, x){ + early(crash(x)); +} + +function earlyReject(early, x){ + early(reject(x)); +} + +function earlyResolve(early, x){ + early(resolve(x)); +} + +function createParallelTransformation(name, rec, rej, res, prototype){ + var ParallelTransformation = createTransformation(1, name, Object.assign({ + run: function Parallel$run(early){ + var eager = new Eager(this.$1); + var transformation = new ParallelTransformation(this.context, eager); + function Parallel$early(m){ early(m, transformation); } + transformation.cancel = eager._interpret( + function Parallel$rec(x){ rec(Parallel$early, x); }, + function Parallel$rej(x){ rej(Parallel$early, x); }, + function Parallel$res(x){ res(Parallel$early, x); } + ); + return transformation; + } + }, prototype)); + return ParallelTransformation; +} + +var PairTransformation = createTransformation(1, 'pair', { + resolved: function PairTransformation$resolved(x){ + return new Resolve(this.context, [x, this.$1]); + } +}); + +var BothTransformation = +createParallelTransformation('both', earlyCrash, earlyReject, noop, { + resolved: function BothTransformation$resolved(x){ + return this.$1._transform(new PairTransformation(this.context, x)); + } +}); + +function both(left){ + var context1 = application1(both, future, arguments); + return function both(right){ + var context2 = application(2, both, future, arguments, context1); + return right._transform(new BothTransformation(context2, left)); + }; +} + +var Cold = 0; +var Pending = 1; +var Crashed = 2; +var Rejected = 3; +var Resolved = 4; + +function Queued(rec, rej, res){ + this[Crashed] = rec; + this[Rejected] = rej; + this[Resolved] = res; +} + +var Cache = createInterpreter(1, 'cache', function Cache$interpret(rec, rej, res){ + var cancel = noop; + + switch(this._state){ + /* c8 ignore next 4 */ + case Pending: cancel = this._addToQueue(rec, rej, res); break; + case Crashed: rec(this._value); break; + case Rejected: rej(this._value); break; + case Resolved: res(this._value); break; + default: + this._queue = []; + cancel = this._addToQueue(rec, rej, res); + this.run(); + } + + return cancel; +}); + +Cache.prototype._cancel = noop; +Cache.prototype._queue = null; +Cache.prototype._queued = 0; +Cache.prototype._value = undefined; +Cache.prototype._state = Cold; + +Cache.prototype.extractLeft = function Cache$extractLeft(){ + return this._state === Rejected ? [this._value] : []; +}; + +Cache.prototype.extractRight = function Cache$extractRight(){ + return this._state === Resolved ? [this._value] : []; +}; + +Cache.prototype._addToQueue = function Cache$addToQueue(rec, rej, res){ + var _this = this; + if(_this._state > Pending) return noop; + var i = _this._queue.push(new Queued(rec, rej, res)) - 1; + _this._queued = _this._queued + 1; + + return function Cache$removeFromQueue(){ + if(_this._state > Pending) return; + _this._queue[i] = undefined; + _this._queued = _this._queued - 1; + if(_this._queued === 0) _this.reset(); + }; +}; + +Cache.prototype._drainQueue = function Cache$drainQueue(){ + if(this._state <= Pending) return; + if(this._queued === 0) return; + var queue = this._queue; + var length = queue.length; + var state = this._state; + var value = this._value; + + for(var i = 0; i < length; i++){ + queue[i] && queue[i][state](value); + queue[i] = undefined; + } + + this._queue = undefined; + this._queued = 0; +}; + +Cache.prototype.crash = function Cache$crash(error){ + if(this._state > Pending) return; + this._value = error; + this._state = Crashed; + this._drainQueue(); +}; + +Cache.prototype.reject = function Cache$reject(reason){ + if(this._state > Pending) return; + this._value = reason; + this._state = Rejected; + this._drainQueue(); +}; + +Cache.prototype.resolve = function Cache$resolve(value){ + if(this._state > Pending) return; + this._value = value; + this._state = Resolved; + this._drainQueue(); +}; + +Cache.prototype.run = function Cache$run(){ + var _this = this; + if(_this._state > Cold) return; + _this._state = Pending; + _this._cancel = _this.$1._interpret( + function Cache$fork$rec(x){ _this.crash(x); }, + function Cache$fork$rej(x){ _this.reject(x); }, + function Cache$fork$res(x){ _this.resolve(x); } + ); +}; + +Cache.prototype.reset = function Cache$reset(){ + if(this._state === Cold) return; + if(this._state === Pending) this._cancel(); + this._cancel = noop; + this._queue = []; + this._queued = 0; + this._value = undefined; + this._state = Cold; +}; + +function cache(m){ + return new Cache(application1(cache, future, arguments), m); +} + +var ChainRejTransformation = createTransformation(1, 'chainRej', { + rejected: function ChainRejTransformation$rejected(x){ return call(this.$1, x) } +}); + +function chainRej(f){ + var context1 = application1(chainRej, func, arguments); + return function chainRej(m){ + var context2 = application(2, chainRej, future, arguments, context1); + return m._transform(new ChainRejTransformation(context2, f)); + }; +} + +var monad = {pred: isChain, error: invalidArgumentOf('have Chain implemented')}; + +function chain(f){ + var context1 = application1(chain, func, arguments); + return function chain(m){ + var context2 = application(2, chain, monad, arguments, context1); + return isFuture(m) ? + m._transform(new ChainTransformation(context2, f)) : + m[FL.chain](f); + }; +} + +function done(callback){ + var context1 = application1(done, func, arguments); + function done$res(x){ + callback(null, x); + } + return function done(m){ + application(2, done, future, arguments, context1); + return m._interpret(raise, callback, done$res); + }; +} + +function extractLeft(m){ + application1(extractLeft, future, arguments); + return m.extractLeft(); +} + +function extractRight(m){ + application1(extractRight, future, arguments); + return m.extractRight(); +} + +var CoalesceTransformation = createTransformation(2, 'coalesce', { + rejected: function CoalesceTransformation$rejected(x){ + return new Resolve(this.context, call(this.$1, x)); + }, + resolved: function CoalesceTransformation$resolved(x){ + return new Resolve(this.context, call(this.$2, x)); + } +}); + +function coalesce(f){ + var context1 = application1(coalesce, func, arguments); + return function coalesce(g){ + var context2 = application(2, coalesce, func, arguments, context1); + return function coalesce(m){ + var context3 = application(3, coalesce, future, arguments, context2); + return m._transform(new CoalesceTransformation(context3, f, g)); + }; + }; +} + +function forkCatch(f){ + var context1 = application1(forkCatch, func, arguments); + return function forkCatch(g){ + var context2 = application(2, forkCatch, func, arguments, context1); + return function forkCatch(h){ + var context3 = application(3, forkCatch, func, arguments, context2); + return function forkCatch(m){ + application(4, forkCatch, future, arguments, context3); + return m._interpret(f, g, h); + }; + }; + }; +} + +function fork(f){ + var context1 = application1(fork, func, arguments); + return function fork(g){ + var context2 = application(2, fork, func, arguments, context1); + return function fork(m){ + application(3, fork, future, arguments, context2); + return m._interpret(raise, f, g); + }; + }; +} + +var Undetermined = 0; +var Synchronous = 1; +var Asynchronous = 2; + +/*eslint consistent-return: 0 */ + +function invalidIteration(o){ + return typeError( + 'The iterator did not return a valid iteration from iterator.next()\n' + + ' Actual: ' + sanctuaryShow(o) + ); +} + +function invalidState(x){ + return invalidFuture( + 'go() expects the value produced by the iterator', x, + '\n Tip: If you\'re using a generator, make sure you always yield a Future' + ); +} + +var Go = createInterpreter(1, 'go', function Go$interpret(rec, rej, res){ + + var _this = this, timing = Undetermined, cancel = noop, state, value, iterator; + + function crash(e){ + rec(wrapException(e, _this)); + } + + try{ + iterator = _this.$1(); + }catch(e){ + crash(e); + return noop; + } + + if(!isIterator(iterator)){ + crash(invalidArgument('go', 0, 'return an iterator, maybe you forgot the "*"', iterator)); + return noop; + } + + function resolved(x){ + value = x; + if(timing === Asynchronous) return drain(); + timing = Synchronous; + } + + function drain(){ + //eslint-disable-next-line no-constant-condition + while(true){ + try{ + state = iterator.next(value); + }catch(e){ + return crash(e); + } + if(!isIteration(state)) return crash(invalidIteration(state)); + if(state.done) break; + if(!isFuture(state.value)){ + return crash(invalidState(state.value)); + } + timing = Undetermined; + cancel = state.value._interpret(crash, rej, resolved); + if(timing === Undetermined) return timing = Asynchronous; + } + res(state.value); + } + + drain(); + + return function Go$cancel(){ cancel(); }; + +}); + +function go(generator){ + return new Go(application1(go, func, arguments), generator); +} + +function invalidDisposal(m, f, x){ + return invalidFuture( + 'hook() expects the return value from the first function it\'s given', m, + '\n From calling: ' + sanctuaryShow(f) + '\n With: ' + sanctuaryShow(x) + ); +} + +function invalidConsumption(m, f, x){ + return invalidFuture( + 'hook() expects the return value from the second function it\'s given', m, + '\n From calling: ' + sanctuaryShow(f) + '\n With: ' + sanctuaryShow(x) + ); +} + +var Hook = createInterpreter(3, 'hook', function Hook$interpret(rec, rej, res){ + + var _this = this, _acquire = this.$1, _dispose = this.$2, _consume = this.$3; + var cancel, cancelConsume = noop, resource, value, cont = noop; + + function Hook$done(){ + cont(value); + } + + function Hook$rec(x){ + rec(wrapException(x, _this)); + } + + function Hook$dispose(){ + var disposal; + try{ + disposal = _dispose(resource); + }catch(e){ + return Hook$rec(e); + } + if(!isFuture(disposal)){ + return Hook$rec(invalidDisposal(disposal, _dispose, resource)); + } + cancel = Hook$cancelDisposal; + disposal._interpret(Hook$rec, Hook$disposalRejected, Hook$done); + } + + function Hook$cancelConsumption(){ + cancelConsume(); + Hook$dispose(); + Hook$cancelDisposal(); + } + + function Hook$cancelDisposal(){ + cont = noop; + } + + function Hook$disposalRejected(x){ + Hook$rec(new Error('The disposal Future rejected with ' + sanctuaryShow(x))); + } + + function Hook$consumptionException(x){ + cont = Hook$rec; + value = x; + Hook$dispose(); + } + + function Hook$consumptionRejected(x){ + cont = rej; + value = x; + Hook$dispose(); + } + + function Hook$consumptionResolved(x){ + cont = res; + value = x; + Hook$dispose(); + } + + function Hook$consume(x){ + resource = x; + var consumption; + try{ + consumption = _consume(resource); + }catch(e){ + return Hook$consumptionException(e); + } + if(!isFuture(consumption)){ + return Hook$consumptionException(invalidConsumption(consumption, _consume, resource)); + } + cancel = Hook$cancelConsumption; + cancelConsume = consumption._interpret( + Hook$consumptionException, + Hook$consumptionRejected, + Hook$consumptionResolved + ); + } + + var cancelAcquire = _acquire._interpret(Hook$rec, rej, Hook$consume); + cancel = cancel || cancelAcquire; + + return function Hook$fork$cancel(){ + rec = raise; + cancel(); + }; + +}); + +function hook(acquire){ + var context1 = application1(hook, future, arguments); + return function hook(dispose){ + var context2 = application(2, hook, func, arguments, context1); + return function hook(consume){ + var context3 = application(3, hook, func, arguments, context2); + return new Hook(context3, acquire, dispose, consume); + }; + }; +} + +var LastlyTransformation = createTransformation(1, 'lastly', { + rejected: function LastlyAction$rejected(x){ + return this.$1._transform(new AndTransformation(this.context, new Reject(this.context, x))); + }, + resolved: function LastlyAction$resolved(x){ + return this.$1._transform(new AndTransformation(this.context, new Resolve(this.context, x))); + } +}); + +function lastly(cleanup){ + var context1 = application1(lastly, future, arguments); + return function lastly(program){ + var context2 = application(2, lastly, future, arguments, context1); + return program._transform(new LastlyTransformation(context2, cleanup)); + }; +} + +var MapRejTransformation = createTransformation(1, 'mapRej', { + rejected: function MapRejTransformation$rejected(x){ + return new Reject(this.context, call(this.$1, x)); + } +}); + +function mapRej(f){ + var context1 = application1(mapRej, func, arguments); + return function mapRej(m){ + var context2 = application(2, mapRej, future, arguments, context1); + return m._transform(new MapRejTransformation(context2, f)); + }; +} + +var functor = {pred: isFunctor, error: invalidArgumentOf('have Functor implemented')}; + +function map(f){ + var context1 = application1(map, func, arguments); + return function map(m){ + var context2 = application(2, map, functor, arguments, context1); + return isFuture(m) ? + m._transform(new MapTransformation(context2, f)) : + m[FL.map](f); + }; +} + +var Node = createInterpreter(1, 'node', function Node$interpret(rec, rej, res){ + function Node$done(err, val){ + cont = err ? function EncaseN3$rej(){ + open = false; + rej(err); + } : function EncaseN3$res(){ + open = false; + res(val); + }; + if(open){ + cont(); + } + } + var open = false, cont = function(){ open = true; }; + try{ + call(this.$1, Node$done); + }catch(e){ + rec(wrapException(e, this)); + open = false; + return noop; + } + cont(); + return function Node$cancel(){ open = false; }; +}); + +function node(f){ + return new Node(application1(node, func, arguments), f); +} + +var ParallelApTransformation = +createParallelTransformation('pap', earlyCrash, earlyReject, noop, { + resolved: function ParallelApTransformation$resolved(f){ + if(isFunction(f)) return this.$1._transform(new MapTransformation(this.context, f)); + throw typeError( + 'pap expects the second Future to resolve to a Function\n' + + ' Actual: ' + sanctuaryShow(f) + ); + } +}); + +function pap(mx){ + var context1 = application1(pap, future, arguments); + return function pap(mf){ + var context2 = application(2, pap, future, arguments, context1); + return mf._transform(new ParallelApTransformation(context2, mx)); + }; +} + +function isFutureArray(xs){ + if(!isArray(xs)) return false; + for(var i = 0; i < xs.length; i++){ + if(!isFuture(xs[i])) return false; + } + return true; +} + +var futureArray = { + pred: isFutureArray, + error: invalidArgumentOf('be an Array of valid Futures') +}; + +var Parallel = createInterpreter(2, 'parallel', function Parallel$interpret(rec, rej, res){ + + var _this = this, futures = this.$2, length = futures.length; + var max = Math.min(this.$1, length), cancels = new Array(length), out = new Array(length); + var cursor = 0, running = 0, blocked = false, cont = noop; + + function Parallel$cancel(){ + rec = noop; + rej = noop; + res = noop; + cursor = length; + for(var n = 0; n < length; n++) cancels[n] && cancels[n](); + } + + function Parallel$run(idx){ + running++; + cancels[idx] = futures[idx]._interpret(function Parallel$rec(e){ + cont = rec; + cancels[idx] = noop; + Parallel$cancel(); + cont(wrapException(e, _this)); + }, function Parallel$rej(reason){ + cont = rej; + cancels[idx] = noop; + Parallel$cancel(); + cont(reason); + }, function Parallel$res(value){ + cancels[idx] = noop; + out[idx] = value; + running--; + if(cursor === length && running === 0) res(out); + else if(blocked) Parallel$drain(); + }); + } + + function Parallel$drain(){ + blocked = false; + while(cursor < length && running < max) Parallel$run(cursor++); + blocked = true; + } + + Parallel$drain(); + + return Parallel$cancel; + +}); + +var emptyArray = resolve([]); + +function parallel(max){ + var context1 = application1(parallel, positiveInteger, arguments); + return function parallel(ms){ + var context2 = application(2, parallel, futureArray, arguments, context1); + return ms.length === 0 ? emptyArray : new Parallel(context2, max, ms); + }; +} + +var RaceTransformation = +createParallelTransformation('race', earlyCrash, earlyReject, earlyResolve, {}); + +function race(left){ + var context1 = application1(race, future, arguments); + return function race(right){ + var context2 = application(2, race, future, arguments, context1); + return right._transform(new RaceTransformation(context2, left)); + }; +} + +function ConcurrentFuture (sequential){ + this.sequential = sequential; +} + +ConcurrentFuture.prototype = Object.create(Par.prototype); + +function Par (sequential){ + if(!isFuture(sequential)) throw invalidFutureArgument(Par.name, 0, sequential); + return new ConcurrentFuture(sequential); +} + +var $$type$1 = namespace + '/ConcurrentFuture@' + version; +var zeroInstance = new ConcurrentFuture(never); + +// Compliance with sanctuary-type-identifiers versions 1 and 2. +// To prevent sanctuary-type-identifiers version 3 from identifying +// 'Par' as being of the type denoted by $$type, we ensure that +// Par.constructor.prototype is equal to Par. +Par['@@type'] = $$type$1; +Par.constructor = {prototype: Par}; + +Par[FL.of] = function Par$of(x){ + return new ConcurrentFuture(resolve(x)); +}; + +Par[FL.zero] = function Par$zero(){ + return zeroInstance; +}; + +Par.prototype['@@type'] = $$type$1; + +Par.prototype['@@show'] = function Par$show(){ + return this.toString(); +}; + +Par.prototype.toString = function Par$toString(){ + return 'Par (' + this.sequential.toString() + ')'; +}; + +Par.prototype[FL.map] = function Par$FL$map(f){ + var context = captureContext( + nil, + 'a Fantasy Land dispatch to map via ConcurrentFuture', + Par$FL$map + ); + return new ConcurrentFuture(this.sequential._transform(new MapTransformation(context, f))); +}; + +Par.prototype[FL.ap] = function Par$FL$ap(other){ + var context = captureContext( + nil, + 'a Fantasy Land dispatch to ap via ConcurrentFuture', + Par$FL$ap + ); + return new ConcurrentFuture(other.sequential._transform( + new ParallelApTransformation(context, this.sequential) + )); +}; + +Par.prototype[FL.alt] = function Par$FL$alt(other){ + var context = captureContext( + nil, + 'a Fantasy Land dispatch to alt via ConcurrentFuture', + Par$FL$alt + ); + return new ConcurrentFuture(other.sequential._transform( + new RaceTransformation(context, this.sequential) + )); +}; + +function isParallel(x){ + return x instanceof ConcurrentFuture || sanctuaryTypeIdentifiers(x) === $$type$1; +} + +function promise(m){ + application1(promise, future, arguments); + return new Promise(function promise$computation(res, rej){ + m._interpret(rej, rej, res); + }); +} + +var RejectAfter = +createInterpreter(2, 'rejectAfter', function RejectAfter$interpret(rec, rej){ + var id = setTimeout(rej, this.$1, this.$2); + return function RejectAfter$cancel(){ clearTimeout(id); }; +}); + +RejectAfter.prototype.extractLeft = function RejectAfter$extractLeft(){ + return [this.$2]; +}; + +function alwaysNever$1(_){ + return never; +} + +function rejectAfter(time){ + var context1 = application1(rejectAfter, positiveInteger, arguments); + return time === Infinity ? alwaysNever$1 : (function rejectAfter(value){ + var context2 = application(2, rejectAfter, any, arguments, context1); + return new RejectAfter(context2, time, value); + }); +} + +var parallel$1 = {pred: isParallel, error: invalidArgumentOf('be a ConcurrentFuture')}; + +function seq(par){ + application1(seq, parallel$1, arguments); + return par.sequential; +} + +var SwapTransformation = createTransformation(0, 'swap', { + resolved: function SwapTransformation$resolved(x){ + return new Reject(this.context, x); + }, + rejected: function SwapTransformation$rejected(x){ + return new Resolve(this.context, x); + } +}); + +function swap(m){ + var context = application1(swap, future, arguments); + return m._transform(new SwapTransformation(context)); +} + +function value(res){ + var context1 = application1(value, func, arguments); + return function value(m){ + application(2, value, future, arguments, context1); + function value$rej(x){ + raise(error( + 'Future#value was called on a rejected Future\n' + + ' Rejection: ' + sanctuaryShow(x) + '\n' + + ' Future: ' + sanctuaryShow(m) + )); + } + return m._interpret(raise, value$rej, res); + }; +} + +export default Future; +export { Future, Par, after, alt, and, ap, attempt, attemptP, bichain, bimap, both, cache, chain, chainRej, coalesce, debugMode, done, encase, encaseP, extractLeft, extractRight, fork, forkCatch, go, hook, isFuture, isNever, lastly, map, mapRej, never, node, pap, parallel, promise, race, reject, rejectAfter, resolve, seq, swap, value }; diff --git a/package.json b/package.json index bd22457b..bec2f7d4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fluture", - "version": "12.2.1", + "version": "12.3.0", "description": "FantasyLand compliant (monadic) alternative to Promises", "main": "index.cjs", "type": "module",