Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ramda-fantasy

Package Overview
Dependencies
Maintainers
2
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ramda-fantasy - npm Package Compare versions

Comparing version 0.3.0 to 0.4.0

test/utils.js

4

package.json

@@ -16,3 +16,3 @@ {

"description": "Fantasy Land compatible types for easy integration with Ramda",
"version": "0.3.0",
"version": "0.4.0",
"homepage": "https://www.github.com/ramda/ramda-fantasy",

@@ -34,3 +34,3 @@ "license": "MIT",

"dependencies": {
"ramda": "^0.15.0"
"ramda": ">=0.15.0 <0.18.0"
},

@@ -37,0 +37,0 @@ "devDependencies": {

@@ -11,4 +11,4 @@ ramda-fantasy

## Project status
This project is in alpha status. The implementation of the Fantasy Land spec should be *mostly*
stable. Any methods outside of the Fantasy Land spec are subject to change. The types also have
This project is in alpha status. The implementation of the Fantasy Land spec should be *mostly*
stable. Any methods outside of the Fantasy Land spec are subject to change. The types also have
not undergone thorough testing/use yet.

@@ -18,11 +18,11 @@

Name | Setoid | Semigroup | Functor | Applicative | Monad | Comonad |
---------- | :-----: | :-------: | :-----: | :---------: | :---: | :------: |
Either | **✔︎** | | **✔︎** | **✔︎** | **✔︎** | |
Future | **✔︎** | | **✔︎** | **✔︎** | **✔︎** | |
Identity | **✔︎** | | **✔︎** | **✔︎** | **✔︎** | |
IO | **✔︎** | | **✔︎** | **✔︎** | **✔︎** | |
Maybe | **✔︎** | | **✔︎** | **✔︎** | **✔︎** | |
Reader | **✔︎** | | **✔︎** | **✔︎** | **✔︎** | |
Tuple | **✔︎** | **✔︎** | **✔︎** | **✔︎** | | |
Name | Setoid | Semigroup | Functor | Applicative | Monad | Comonad | Foldable |
---------- | :-----: | :-------: | :-----: | :---------: | :---: | :------: | :-------: |
Either | **✔︎** | | **✔︎** | **✔︎** | **✔︎** | | |
Future | **✔︎** | | **✔︎** | **✔︎** | **✔︎** | | |
Identity | **✔︎** | | **✔︎** | **✔︎** | **✔︎** | | |
IO | **✔︎** | | **✔︎** | **✔︎** | **✔︎** | | |
Maybe | **✔︎** | | **✔︎** | **✔︎** | **✔︎** | | **✔︎** |
Reader | **✔︎** | | **✔︎** | **✔︎** | **✔︎** | | |
Tuple | **✔︎** | **✔︎** | **✔︎** | | | | |

@@ -29,0 +29,0 @@

@@ -8,5 +8,13 @@ var R = require('ramda');

}
this.fork = f;
this._fork = f;
}
Future.prototype.fork = function(reject, resolve) {
try {
this._fork(reject, resolve);
} catch(e) {
reject(e);
}
};
// functor

@@ -57,2 +65,3 @@ Future.prototype.map = function(f) {

// chain must return a value of the same Chain
//:: Future a, b => (b -> Future c) -> Future c
Future.prototype.chain = function(f) { // Sorella's:

@@ -65,2 +74,13 @@ return new Future(function(reject, resolve) {

// chainReject
// Like chain but operates on the reject instead of the resolve case.
//:: Future a, b => (a -> Future c) -> Future c
Future.prototype.chainReject = function(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));
};
// monad

@@ -88,5 +108,43 @@ // A value that implements the Monad specification must also implement the Applicative and Chain specifications.

Future.prototype.toString = function() {
return 'Future(' + R.toString(this.fork) + ')';
return 'Future(' + R.toString(this._fork) + ')';
};
Future.memoize = function(f) {
var status = 'IDLE';
var listeners = [];
var cachedValue;
var handleCompletion = R.curry(function(newStatus, cb, val) {
status = newStatus;
cachedValue = val;
cb(val);
R.forEach(function(listener) {
listener[status](cachedValue);
}, listeners);
});
function addListeners(reject, resolve) {
listeners.push({ REJECTED: reject, RESOLVED: resolve } );
}
function doResolve(reject, resolve) {
status = 'PENDING';
return f.fork(
handleCompletion('REJECTED', reject),
handleCompletion('RESOLVED', resolve)
);
}
return new Future(function(reject, resolve) {
switch(status) {
case 'IDLE': doResolve(reject, resolve); break;
case 'PENDING': addListeners(reject, resolve); break;
case 'REJECTED': reject(cachedValue); break;
case 'RESOLVED': resolve(cachedValue); break;
}
});
};
module.exports = Future;

@@ -18,3 +18,4 @@ var R = require('ramda');

return new IO(function() {
return f(io.fn()).fn();
var next = f(io.fn.apply(io, arguments));
return next.fn.apply(next, arguments);
});

@@ -50,11 +51,4 @@ };

// this is really only to accommodate testing ....
IO.prototype.equals = function(that) {
return this === that ||
this.fn === that.fn ||
R.equals(IO.runIO(this), IO.runIO(that));
};
IO.prototype.toString = function() {
return 'IO(' + R.toString(this.fn) + ')';
};
var R = require('ramda');
module.exports = R.curryN(3, function liftA2(f, a1, a2) {
module.exports = R.curryN(3, function lift2(f, a1, a2) {
return a1.map(f).ap(a2);
});
var R = require('ramda');
module.exports = R.curryN(4, function liftA2(f, a1, a2, a3) {
module.exports = R.curryN(4, function lift3(f, a1, a2, a3) {
return a1.map(f).ap(a2).ap(a3);
});

@@ -39,2 +39,8 @@ var R = require('ramda');

Maybe.maybe = R.curry(function(nothingVal, justFn, m) {
return m.reduce(function(_, x) {
return justFn(x);
}, nothingVal);
});
// functor

@@ -101,2 +107,10 @@ _Just.prototype.map = function(f) {

_Just.prototype.reduce = function(f, x) {
return f(x, this.value);
};
_Nothing.prototype.reduce = function(f, x) {
return x;
};
_Just.prototype.toString = function() {

@@ -103,0 +117,0 @@ return 'Maybe.Just(' + R.toString(this.value) + ')';

@@ -41,12 +41,4 @@ var R = require('ramda');

Reader.ask = Reader(function(a) {
return a;
});
Reader.ask = Reader(R.always);
Reader.prototype.equals = function(that) {
return this === that ||
this.run === that.run ||
R.equals(Reader.run(this), Reader.run(that));
};
Reader.prototype.toString = function() {

@@ -56,2 +48,56 @@ return 'Reader(' + R.toString(this.run) + ')';

Reader.T = function(M) {
var ReaderT = function ReaderT(run) {
if (!(this instanceof ReaderT)) {
return new ReaderT(run);
}
this.run = run;
};
ReaderT.lift = R.compose(ReaderT, R.always);
ReaderT.ask = ReaderT(M.of);
ReaderT.prototype.of = ReaderT.of = function(a) {
return ReaderT(function() {
return M.of(a);
});
};
ReaderT.prototype.chain = function(f) {
var readerT = this;
return ReaderT(function(e) {
var m = readerT.run(e);
return m.chain(function(a) {
return f(a).run(e);
});
});
};
ReaderT.prototype.map = function(f) {
return this.chain(function(a) {
return ReaderT.of(f(a));
});
};
ReaderT.prototype.ap = function(a) {
var readerT = this;
return ReaderT(function(e) {
return readerT.run(e).ap(a.run(e));
});
};
ReaderT.prototype.equals = function(that) {
return this === that ||
this.run === that.run ||
R.equals(this.run().get(), that.run().get());
};
ReaderT.prototype.toString = function() {
return 'ReaderT[' + M.name + '](' + R.toString(this.run) + ')';
};
return ReaderT;
};
module.exports = Reader;

@@ -31,6 +31,2 @@ var R = require('ramda');

Tuple.of = function(x) {
return Tuple(x, x);
};
Tuple.fst = function(x) {

@@ -44,6 +40,2 @@ return x[0];

_Tuple.prototype.of = function(x) {
return Tuple(this[0], x);
};
// semigroup

@@ -50,0 +42,0 @@ _Tuple.prototype.concat = function(x) {

var assert = require('assert');
var types = require('./types');
var equalsInvoker = require('./utils').equalsInvoker;
var types = require('./types')(equalsInvoker);

@@ -4,0 +5,0 @@ var Either = require('..').Either;

var R = require('ramda');
var assert = require('assert');
var types = require('./types');
var equalsInvoker = require('./utils').equalsInvoker;
var types = require('./types')(equalsInvoker);
var Future = require('../src/Future');

@@ -89,2 +90,10 @@

describe('chainReject', function() {
it('.chainReject should work like chain but off reject case', function() {
var f1 = Future.reject(2);
var f2 = function(val){ return Future.of(val + 3);};
assert.equal(true, Future.of(5).equals(f1.chainReject(f2)));
});
});
describe('#ap', function() {

@@ -197,3 +206,165 @@ /*jshint browser:true */

describe('#fork', function() {
var result;
var futureOne = Future.of(1);
var throwError = function() {
throw new Error('Some error message');
};
var setErrorResult = function(e) {
result = e.message;
};
beforeEach(function() {
result = null;
});
it('creates a rejected future if the resolve function throws an error', function() {
futureOne.fork(setErrorResult, throwError);
assert.equal('Some error message', result);
});
it('rejects the future if an error is thrown in a map function', function() {
futureOne.map(throwError).fork(setErrorResult);
assert.equal('Some error message', result);
});
it('rejects the future if an error is thrown in a chain function', function() {
futureOne.chain(throwError).fork(setErrorResult);
assert.equal('Some error message', result);
});
it('rejects the future if an error is thrown in a ap function', function() {
Future.of(throwError).ap(futureOne).fork(setErrorResult);
assert.equal('Some error message', result);
});
});
describe('#memoize', function() {
var memoized;
var throwIfCalledTwice;
beforeEach(function() {
throwIfCalledTwice = (function() {
var count = 0;
return function(val) {
if (++count > 1) {
throw new Error('Was called twice');
}
return val;
};
}());
});
describe('resolve cases', function() {
beforeEach(function() {
memoized = Future.memoize(Future.of(1).map(throwIfCalledTwice));
});
it('can be forked with a resolved value', function(done) {
memoized.fork(done, function(v) {
assert.equal(1, v);
done();
});
});
it('passes on the same value to the memoized future', function(done) {
memoized.fork(done, function() {
memoized.fork(done, function(v) {
assert.equal(1, v);
done();
});
});
});
});
describe('reject cases', function() {
var throwError = function() {
throw new Error('SomeError');
};
beforeEach(function() {
memoized = Future.memoize(Future.of(1).map(throwIfCalledTwice).map(throwError));
});
it('can be forked with a rejected value', function() {
var result;
memoized.fork(function(err) {
result = err.message;
});
assert.equal('SomeError', result);
});
it('does not call the underlying fork twice', function() {
var result;
memoized.fork(function() {
memoized.fork(function(err) {
result = err.message;
});
});
assert.equal('SomeError', result);
});
});
describe('pending cases', function() {
it('calls all fork resolve functions when the memoized future is resolved', function(done) {
var delayed = new Future(function(reject, resolve) {
setTimeout(resolve, 5, 'resolvedValue');
});
var memoized = Future.memoize(delayed.map(throwIfCalledTwice));
var result1;
var result2;
function assertBoth() {
if (result1 !== undefined && result2 !== undefined) {
assert.equal('resolvedValue', result1);
assert.equal('resolvedValue', result2);
done();
}
}
memoized.fork(done, function(v) {
result1 = v;
assertBoth();
});
memoized.fork(done, function(v) {
result2 = v;
assertBoth();
});
});
it('calls all fork reject fnctions when the memoized future is rejected', function(done) {
var delayed = new Future(function(reject) {
setTimeout(reject, 5, 'rejectedValue');
});
var memoized = Future.memoize(delayed.bimap(throwIfCalledTwice, R.identity));
var result1;
var result2;
function assertBoth() {
if (result1 !== undefined && result2 !== undefined) {
assert.equal('rejectedValue', result1);
assert.equal('rejectedValue', result2);
done();
}
}
memoized.fork(function(e) {
result1 = e;
assertBoth();
});
memoized.fork(function(e) {
result2 = e;
assertBoth();
});
});
});
});
});
var assert = require('assert');
var types = require('./types');
var equalsInvoker = require('./utils').equalsInvoker;
var types = require('./types')(equalsInvoker);

@@ -4,0 +5,0 @@ var Identity = require('..').Identity;

var assert = require('assert');
var types = require('./types');
var types = require('./types')(function(io1, io2) {
return io1.runIO('x') === io2.runIO('x');
});

@@ -4,0 +6,0 @@ var IO = require('..').IO;

var R = require('ramda');
var assert = require('assert');
var types = require('./types');
var equalsInvoker = require('./utils').equalsInvoker;
var types = require('./types')(equalsInvoker);
var jsv = require('jsverify');

@@ -83,2 +84,13 @@

it('is Foldable', function() {
var fTest = types.foldable;
jsv.assert(jsv.forall(m, fTest.iface));
jsv.assert(jsv.forall('nat -> nat -> nat', 'nat', 'nat', function(f, n1, n2) {
return Maybe.Just(n1).reduce(R.uncurryN(2, f), n2) === f(n2)(n1);
}));
jsv.assert(jsv.forall('nat -> nat -> nat', 'nat', function(f, n) {
return Maybe.Nothing().reduce(R.uncurryN(2, f), n) === n;
}));
});
});

@@ -135,2 +147,16 @@

describe('#maybe', function() {
it('returns the result of applying the value of a Just to the second argument', function() {
jsv.assert(jsv.forall('nat -> nat', 'nat', 'nat', function(f, n1, n2) {
return R.equals(Maybe.maybe(n2, f, Maybe.Just(n1)), f(n1));
}));
});
it('returns the first argument for a Nothing', function() {
jsv.assert(jsv.forall('nat -> nat', 'nat', 'nat', function(f, n) {
return R.equals(Maybe.maybe(n, f, Maybe.Nothing()), n);
}));
});
});
});
var assert = require('assert');
var types = require('./types');
var Reader = require('..').Reader;
var readerTypes = types(function(r1, r2) {
return r1.run('x') === r2.run('x');
});
var transformerTypes = types(function(r1, r2) {
return r1.run('x').get() === r2.run('x').get();
});
var Identity = require('..').Identity;
var Reader = require('../src/Reader');
var ReaderTIdentity = Reader.T(Identity);
function add(a) {

@@ -29,3 +40,3 @@ return function(b) { return a + b; };

it('is a Functor', function() {
var fTest = types.functor;
var fTest = readerTypes.functor;
assert.ok(fTest.iface(r1));

@@ -37,3 +48,3 @@ assert.ok(fTest.id(r1));

it('is an Apply', function() {
var aTest = types.apply;
var aTest = readerTypes.apply;
var a = Reader(function() { return add(1); });

@@ -48,3 +59,3 @@ var b = Reader(function() { return always(2); });

it('is an Applicative', function() {
var aTest = types.applicative;
var aTest = readerTypes.applicative;

@@ -62,3 +73,3 @@ assert.equal(true, aTest.iface(r1));

it('is a Chain', function() {
var cTest = types.chain;
var cTest = readerTypes.chain;
var c = Reader(function() {

@@ -76,3 +87,3 @@ return Reader(function() {

it('is a Monad', function() {
var mTest = types.monad;
var mTest = readerTypes.monad;
assert.equal(true, mTest.iface(r1));

@@ -109,4 +120,80 @@ });

assert.equal(nameReader.run(Printer), '/** header */');
assert.equal(Reader.run(nameReader, Printer), '/** header */');
});
});
describe('Reader.T', function() {
var r1 = ReaderTIdentity(function(x) {
return Identity(x + '1 ');
});
var r2 = ReaderTIdentity(function(x) {
return Identity(x + '2 ');
});
it('is a Functor', function() {
var fTest = transformerTypes.functor;
assert(fTest.iface(r1));
assert(fTest.id(r1));
assert(fTest.compose(r1,
function(x) { return x + 'a'; },
function(x) { return x + 'b'; }
));
});
it('is an Apply', function() {
var aTest = transformerTypes.apply;
var a = ReaderTIdentity(function() { return Identity(add(1)); });
var b = ReaderTIdentity(function() { return Identity(always(2)); });
var c = ReaderTIdentity(always(Identity(4)));
assert(aTest.iface(r1));
assert(aTest.compose(a, b, c));
});
it('is an Applicative', function() {
var aTest = transformerTypes.applicative;
assert(aTest.iface(r1));
assert(aTest.id(ReaderTIdentity, r2));
assert(aTest.homomorphic(r1, add(3), 46));
assert(aTest.interchange(
ReaderTIdentity(function() { return Identity(mult(20)); }),
ReaderTIdentity(function() { return Identity(mult(0.5)); }),
73
));
});
it('is a Chain', function() {
var cTest = transformerTypes.chain;
var c = ReaderTIdentity(function() {
return Identity(ReaderTIdentity(function() {
return Identity(ReaderTIdentity(function() {
return Identity(3);
}));
}));
});
assert(cTest.iface(r1));
assert(cTest.associative(c, identity, identity));
});
it('is a Monad', function() {
var mTest = transformerTypes.monad;
assert(mTest.iface(r1));
});
it('is a Transformer', function() {
var mtTest = transformerTypes.transformer;
assert(mtTest.iface(Reader.T));
assert(mtTest.id(Reader.T));
assert(mtTest.associative(Reader.T));
});
});
describe('Reader.T examples', function() {
it('should provide its environment to a lifted monad', function() {
var readerTimes10 = ReaderTIdentity.ask.chain(function(env) {
return ReaderTIdentity.lift(Identity(env * 10));
});
assert.strictEqual(readerTimes10.run(3).get(), 30);
});
});
var R = require('ramda');
var assert = require('assert');
var types = require('./types');
var equalsInvoker = require('./utils').equalsInvoker;
var types = require('./types')(equalsInvoker);
var jsv = require('jsverify');

@@ -87,14 +88,2 @@

});
it('is an Applicative', function() {
var aTest = types.applicative;
var app1 = Tuple('', 101);
var app2 = Tuple('', -123);
var appF = Tuple('', mult(3));
assert.equal(true, aTest.iface(app1));
assert.equal(true, aTest.id(app1, app2));
assert.equal(true, aTest.homomorphic(app1, add(3), 46));
assert.equal(true, aTest.interchange(app2, appF, 17));
});
});

@@ -110,14 +99,2 @@

});
it('should lift the value into the tuple as both positions', function() {
var tpl = Tuple.of('pillow pets');
assert.equal('pillow pets', tpl[0]);
assert.equal('pillow pets', tpl[1]);
});
it('should maintain the current fst if it already has one', function() {
var tpl = Tuple.of(100).of('buckaroonies');
assert.equal(100, tpl[0]);
assert.equal('buckaroonies', tpl[1]);
});
});

@@ -124,0 +101,0 @@

@@ -9,5 +9,9 @@ var interfaces = {

monad: ['map', 'ap', 'chain', 'of'],
extend: ['extend']
extend: ['extend'],
foldable: ['reduce'],
transformer: ['lift']
};
var Identity = require('..').Identity;
function correctInterface(type) {

@@ -23,68 +27,108 @@ return function(obj) {

module.exports = {
semigroup: {
iface: correctInterface('semigroup'),
associative: function(a, b, c) {
return a.concat(b).concat(c).equals(a.concat(b.concat(c)));
}
},
module.exports = function(eq) {
return {
semigroup: {
iface: correctInterface('semigroup'),
associative: function (a, b, c) {
return eq(a.concat(b).concat(c), a.concat(b.concat(c)));
}
},
functor: {
iface: correctInterface('functor'),
id: function(obj) {
return obj.equals(obj.map(identity));
functor: {
iface: correctInterface('functor'),
id: function (obj) {
return eq(obj, obj.map(identity));
},
compose: function (obj, f, g) {
return eq(
obj.map(function (x) {
return f(g(x));
}),
obj.map(g).map(f)
);
}
},
compose: function(obj, f, g) {
return obj.map(function(x) { return f(g(x)); }).equals(
obj.map(g).map(f)
);
}
},
apply: {
iface: correctInterface('apply'),
compose: function(a, u, v) {
return a.ap(u.ap(v)).equals(
a.map(function(f) {
return function(g) {
return function(x) {
return f(g(x));
apply: {
iface: correctInterface('apply'),
compose: function (a, u, v) {
return eq(
a.ap(u.ap(v)),
a.map(function (f) {
return function (g) {
return function (x) {
return f(g(x));
};
};
};
}).ap(u).ap(v)
);
}
},
}).ap(u).ap(v)
);
}
},
applicative: {
iface: correctInterface('applicative'),
id: function(obj, obj2) {
return obj.of(identity).ap(obj2).equals(obj2);
applicative: {
iface: correctInterface('applicative'),
id: function (obj, obj2) {
return eq(obj.of(identity).ap(obj2), obj2);
},
homomorphic: function (obj, f, x) {
return eq(obj.of(f).ap(obj.of(x)), obj.of(f(x)));
},
interchange: function (obj1, obj2, x) {
return eq(
obj2.ap(obj1.of(x)),
obj1.of(function (f) {
return f(x);
}).ap(obj2)
);
}
},
homomorphic: function(obj, f, x) {
return obj.of(f).ap(obj.of(x)).equals(obj.of(f(x)));
chain: {
iface: correctInterface('chain'),
associative: function (obj, f, g) {
return eq(
obj.chain(f).chain(g),
obj.chain(function (x) {
return f(x).chain(g);
})
);
}
},
interchange: function(obj1, obj2, x) {
return obj2.ap(obj1.of(x)).equals(
obj1.of(function(f) { return f(x); }).ap(obj2)
);
}
},
chain: {
iface: correctInterface('chain'),
associative: function(obj, f, g) {
return obj.chain(f).chain(g).equals(
obj.chain(function(x) { return f(x).chain(g); })
);
}
},
monad: {
iface: correctInterface('monad')
},
monad: {
iface: correctInterface('monad')
},
extend: {
iface: correctInterface('extend')
},
extend: {
iface: correctInterface('extend')
}
foldable: {
iface: correctInterface('foldable')
},
transformer: {
iface: function (T) {
return correctInterface('transformer')(T(Identity)) &&
correctInterface('monad')(T(Identity)(identity));
},
id: function (transformer) {
var T = transformer(Identity);
return eq(T.lift(Identity.of(1)), T.of(1));
},
associative: function (transformer) {
var T = transformer(Identity);
var m = Identity(1);
var f = function (x) {
return Identity(x * x);
};
return eq(
T.lift(m.chain(f)),
T.lift(m).chain(function (x) {
return T.lift(f(x));
})
);
}
}
};
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc