Last active
March 20, 2016 15:09
-
-
Save bas080/169c2fe7ad2d1b69a1ac to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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