funcprolib
Version:
Functional Programming Library
189 lines (158 loc) • 6.1 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: main.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: main.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>import {
isError,
isFunction,
isNull,
isUndefined
} from "lodash/fp";
import eitherDefinition from "./either";
import maybeDefinition from "./maybe";
export function createMonad(monadDefinition) {
return function(input) {
// @note Handle different Monad types here ? E.g Either(Maybe())
if (input && input.isMonad) {
return input;
}
if (isFunction(input)) {
return (a) => createMonad(monadDefinition)(a).map(input);
}
const newMonad = (isError(input) || isNull(input) || Number.isNaN(input) || isUndefined(input)) ?
monadDefinition.createErroneousMonad(input) :
monadDefinition.createSuccessfulMonad(input);
newMonad.isMonad = true;
newMonad.toString = () => monadDefinition.toString(newMonad);
/**
* Apply a function on a monad value, but only if the monad is in an ok
* state
* @param {Function} fn - Function to apply
* @return {Object} If everything went right, a new monad with the
* result of calling given function with the monad value, or the same
* monad, untouched
**/
newMonad.map = function(fn) {
try {
if (monadDefinition.isInErrorState(newMonad)) {
return newMonad;
}
return createMonad(monadDefinition)(
fn(monadDefinition.getSuccessfulValue(newMonad))
);
} catch (err) {
return createMonad(monadDefinition)(err);
}
};
/**
* Apply a function on a monad erroneous value, or just return the
* monad right value
* @node Should be improved to apply given function on right value too
* @param {Function} fn - Function to apply
* @return {Object} If everything went right the monad value, or the
* result of calling the function with the monad's erroneous value
**/
newMonad.chain = function(input) {
if (monadDefinition.isInErrorState(newMonad)) {
if (isFunction(input)) {
return input(monadDefinition.getErroneousValue(newMonad));
}
return input;
}
// @note According to fantasyland specs, we should apply input on
// the monad value, even if it's not in an erroneous state
return monadDefinition.getSuccessfulValue(newMonad);
};
return newMonad;
};
}
/**
* Create a monad out of given input and map any number of functions
* on it
* @param {Object} monadDefinition - Monad definition
* @param {Array<Function>} fns - Functions to apply on the new monad
* @return {Object} A new Monad on which all given functions will
* have been called
**/
export function flow(monadDefinition) {
return function(...fns) {
const applier = (input) => fns.reduce(
(prev, curr) => prev.map(curr), createMonad(monadDefinition)(input)
);
applier.chain = (errorFn) => (input) => applier(input).chain(errorFn);
return applier;
};
}
/**
* Debug version of flow
* @node Merge with regular flow
* @param {Object} monadDefinition - Monad definition
* @param {Array<Function>} fns - Functions to apply on the new monad
* @return {Object} A new Monad on which all given functions will
* have been called
**/
flow.debug = function(monadDefinition) {
return function(...fns) {
let functionCall = 0;
const applier = (input) => fns.reduce(
function(prev, curr) {
const debug = "FuncProLib Debug - ";
const temp = prev.map(curr);
if (monadDefinition.isInErrorState(prev)) {
console.log(debug + "Monad is in an erroneous state. Bypassing ", curr.toString().split("\n")[0]);
} else {
functionCall = functionCall + 1;
console.log(`${debug}Call #${functionCall}`);
console.log(`${debug}Current value=${prev.toString()}`);
console.log(`${debug}Next function=${curr}`);
console.log(`${debug}New value=${temp.toString()}`);
}
return temp;
}, createMonad(monadDefinition)(input)
);
applier.chain = (errorFn) => (input) => applier(input).chain(errorFn);
return applier;
};
};
// @note Merge into one export const when JSLint accepts it (someday ?)
const createEither = createMonad(eitherDefinition);
const eitherFlow = flow(eitherDefinition);
eitherFlow.debug = flow.debug(eitherDefinition);
const createMaybe = createMonad(maybeDefinition);
const maybeFlow = flow(maybeDefinition);
maybeFlow.debug = flow.debug(maybeDefinition);
export {
createEither,
eitherFlow,
createMaybe,
maybeFlow
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#flow">flow</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.3</a> on Mon Dec 05 2016 08:25:35 GMT+0100 (CET)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>