Last active
June 20, 2022 20:04
-
-
Save steenhansen/f9a9e9eee2fd563e378d8ddfce98cf0a to your computer and use it in GitHub Desktop.
This file contains hidden or 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
/** | |
* 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