Skip to content

Instantly share code, notes, and snippets.

@steenhansen
Last active June 20, 2022 20:04
Show Gist options
  • Save steenhansen/f9a9e9eee2fd563e378d8ddfce98cf0a to your computer and use it in GitHub Desktop.
Save steenhansen/f9a9e9eee2fd563e378d8ddfce98cf0a to your computer and use it in GitHub Desktop.
/**
* ES6 versions of Either monad used in FP in JS
* Author: Luis Atencio
* https://github.com/luijar/functional-programming-js/blob/master/src/model/monad/Either.js
*/
// Run the below examples in the console
class Base_Either {
constructor(value) { this._value = value; }
get value() { return this._value; }
static left(a) { return new Left(a); }
static right(a) { return new Right(a); }
static fromNullable(val) { return val !== null && val !== undefined ? Base_Either.right(val) : Base_Either.left(val); }
static of(a){ return Base_Either.right(a); } };
class Either extends Base_Either { answer() {return this._value; } };
class Left extends Either {
map(_) { return this; } // noop
get value() { throw new TypeError("Can't extract the value of a Left(a)."); }
getOrElse(other) { return other; }
orElse(f) { return f(this._value); }
chain(f) { return this; }
getOrElseThrow(a) { throw new Error(a); }
filter(f) { return this; }
get isRight() { return false; }
get isLeft() { return true; }
toString() { return `Either.Left(${this._value})`; } };
class Right extends Either {
map(f) { return Either.of(f(this._value)); }
getOrElse(other) { return this._value; }
orElse() { return this; }
chain(f) { return f(this._value); }
getOrElseThrow(_) { return this._value; }
filter(f) { return Either.fromNullable(f(this._value) ? this._value : null); }
get isRight() { return true; }
get isLeft() { return false; }
toString() { return `Either.Right(${this._value})`; } };
function decodeJson(some_json){
try {
const json_obj = JSON.parse(some_json);
return Either.of(json_obj);
} catch (json_error){
return Either.left(json_error); } }
const getProp = key_name => an_object => {
if (an_object == null) {
return Either.left(Error (`Null object`));
}
const contained_obj = an_object[key_name];
if (contained_obj === undefined) {
return Either.left(Error (`Missing key of '${key_name}'`));
}
return Either.of(contained_obj); }
const isMoniker = a_name => {
const name_type = typeof a_name;
if (name_type !== 'string') {
return Either.left(Error (`Name is not a string but a '${name_type}'`));
}
if (a_name.length ===0) {
return Either.left(Error ('Name cannot be empty'));
}
return Either.of(a_name); }
const eitherMiddleName = person_json => {
const middle_name = decodeJson(person_json)
.chain(getProp('person'))
.chain(getProp('address'))
.chain(getProp('name'))
.chain(getProp('middle'))
.chain(isMoniker)
.answer();
return middle_name; }
const showMiddleName = a_person => {
const middle_name = eitherMiddleName(a_person);
if (middle_name instanceof Error) {
if (typeof a_person === 'string') {
const key_quotes = (a_person.toString()).replace(/"(\w+)"( )*:/g, "$1 :");
const str_quotes = key_quotes.replace(/"/g, "'");
return `Error - ${middle_name.message} - ${str_quotes}`;
}
return `Error - Null`;
}
return `Middle - ${middle_name}`; }
var no_middle = '{"person" : { "address": { "name": {"first": "Abraham", "last":"Lincoln"}}}}';
var number_middle = '{"person" : { "address": { "name": {"first": "Abraham", "middle": 12, "last":"Lincoln"}}}}';
var empty_middle = '{"person" : { "address": { "name": {"first": "Abraham", "middle": "", "last":"Lincoln"}}}}';
var bad_json = ",{17";
var no_name = '{"person" : { "address": { "moniker": {"first": "Abraham", "last":"Lincoln"}}}}';
var no_address = '{"person" : { "info": { "name": {"first": "Abraham", "last":"Lincoln"}}}}';
var no_person = '{"human" : { "address": { "name": {"first": "Abraham", "last":"Lincoln"}}}}';
var empty_object = '{}';
var no_object = '[]';
var null_val = null;
var has_middle = '{"person" : { "address": { "name": {"first": "Abraham", "middle":"The Best", "last":"Lincoln"}}}}';
var the_people = [no_middle, number_middle, empty_middle, bad_json, no_name, no_address,
no_person, empty_object, no_object, null_val, has_middle];
the_middles = the_people.map(a_person=> showMiddleName(a_person));
console.dir(the_middles);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment