Skip to content

Instantly share code, notes, and snippets.

@bas080
Last active March 20, 2016 15:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bas080/169c2fe7ad2d1b69a1ac to your computer and use it in GitHub Desktop.
Save bas080/169c2fe7ad2d1b69a1ac to your computer and use it in GitHub Desktop.
var _ = require('ramda');
_.exists = exists;
_.args = args;
_.ap = ap;
_.Either = Either;
_.Either.either = _.curry(either);
_.Identity = Identity;
_.Left = Left;
_.Maybe = Maybe;
_.Maybe.maybe = _.curry(maybe);
_.Right = Right;
_.Task = Task;
////////////////
// Playground //
////////////////
// application :: Number -> Either(String, Number)
function application(id){
return _.Either(function(Left, Right){
if (_.exists(id))
return Right(id);
return Left('request failed');
});
}
// user :: Number -> Task Number Error
function user(index){
return _.Task(function(rej, res){
setTimeout(function(){
index ?
res(index) : rej(Error('notValidUser'));
}, Math.random() * 2000);
});
}
// simulates the behaviour of a standard Promise
function APromise(value){
return {
then: then,
};
function then(fun) {
fun(value);
return APromise(value);
}
}
var promise = Promise(APromise(222));
_.ap(_.compose(
console.log,
_.add(20)
), [promise]);
// afschrijven :: {k: v} -> Number b -> {k: v}
function afschrijven(user, amount){
user.balans = user.balans - amount;
return user;
}
// safePath :: [k] -> {k: v} -> Maybe v | Undefined
var safeProp = _.curryN(2, _.compose(_.Maybe, _.path));
_.map(console.log, safeProp([0,0], [['there'],2])); //console.log is not called
_.map(console.log, safeProp([0,0,'not_there'], [[1],2])); //console.log is not called
// safeGet :: Object a -> Maybe b
var safeName = safeProp(['name']);
var person = {
name: 'James'
};
var greet = _.concat('Hello ');
_.ap(_.compose(
console.log,
greet
), [user('Bas')]);
console.log(
_.Either.either(_.identity, _.add(20), application(234))
);
_.ap(log(_.multiply), [user(20), _.Maybe(20)]);
_.ap(log(
_.compose(
_.join(' '),
_.args
)
), [Identity('Hello'), user('world')])
/////////////////
// Applicative //
/////////////////
/**
* An ap (applicative) function that also manages function currying. This allows
* functions to be called using functors
*
* @param {Function} fun called when all functors have "resolved"
* @param {Array} functors the functors to be called
* @returns {*} the value
*
* FIXME: what to return?
*/
function ap(func, functors) {
// used to check if all arguments are passed to the curried function
var returns = [];
var resolved = 0; // used to check if all functors have resolved/called
var expected = functors.length;
functors.forEach(call);
function call(functor, index){
_.map(curried, functor);
function curried(val){
resolved += 1;
returns[index] = val;
if (resolved === expected)
func.apply(null, returns);
};
}
}
//////////
// Task //
//////////
function Task(resolver){
return {
constructor: Task,
map: function map(fn){
return Task(resolver(_.identity, fn));
},
};
}
Task.of = function of(value){
return Task(function(rej, res){
res(value);
});
};
//////////////
// Identity //
//////////////
function Identity(value){
return {
constructor: Identity,
value: _.always(value),
map: function map(fn){
return Identity(fn(value));
}
};
};
Identity.of = function(value){
return Identity(value);
};
///////////
// Maybe //
///////////
function Maybe(value){
var self = {
constructor: Maybe,
value: _.always(value),
};
self.map = function map(fn){
return Maybe(Maybe.maybe(fn, self));
};
return self;
}
function maybe(fn, maybe){
var value = maybe.value();
return _.exists(value) ?
fn(value) : value;
};
Maybe.of = function of(value){
return Maybe(value);
}
/////////////
// Promise //
/////////////
_.Promise = Promise;
function Promise(promise){
return {
constructor: Promise,
map: function map(fn){
promise.then(fn);
return Promise(promise);
},
};
}
Promise.of = function(value){
return promise.then = _.always(value);
};
////////////
// Either //
////////////
function Either(either){
return either(Left, Right);
}
function either(l, r, e){
switch (e.constructor) {
case Left:
return l(e.value());
case Right:
return r(e.value());
}
}
//////////
// Left //
//////////
function Left(value){
return {
constructor: Left,
map: function(){
return Left(value);
},
value: _.always(value),
};
}
Left.of = Left;
///////////
// Right //
///////////
function Right(value){
return {
constructor: Right,
map: function(fn){
return Right(fn(value));
},
value: _.always(value),
};
}
Right.of = Right;
///////////////
// Functions //
///////////////
// log :: (a -> b) -> (* -> (a -> b)) -> b
function log(f){
return function(v){
var result = f.apply(null, arguments);
console.log(result);
return result;
}
}
// exists :: a -> Boolean
function exists(value){
return (value != null);
}
// args :: *... -> [*]
function args(){
return _.values(arguments);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment