I'm starting or trying to learn functional programming monads.
So the first is Maybe. I'm trying to convert the code with maybe monad.
function(fieldName, vals, fields) {
var newValue = vals[fieldName];
if (typeof(newValue) == 'undefined') {
var elemFrom = fields[fieldName];
if (elemFrom) {
newValue = fields[fieldName]
}
}
if (typeof (newValue) != 'undefined') {
return newValue
}
}
Here I have a bunch of checks for undefined which i think is good use of monay.
My problem is that I read that you pass value to the maybe monad and map function.
However in my case I replace the value inside the monad.
If I pass null the map method will do nothig since the value is undefined.
I'm not using a framework, i want simple implementation so I can understand it.
Should I add "else" method in the maybe monad class (function).
I have the opposite case "Do something if the value is undefined"
Can you suggest how to solve the issue
Thank you
So the function you posted could be rewritten as
const f = (a, b, c) => b[a] === undefined ? c[a] : b[a];
It isn't clear to me that this needs to be a function at all rather than being inlined wherever you want to use the relevant object properties, but maybe you're partially applying it or something, I'm not judging.
As for Maybe, a (very simple) implementation might look something like this:
class Maybe {
static of (value) {
return new Maybe(value);
}
// Proper solution here should be recursive to handle
// nesting properly, but I'm lazy
static equals (a, b) {
return a.chain(x => x) === b.chain(x => x);
}
constructor(value) {
this._value = value;
}
map (f) {
// Does not distinguish null from undefined, but YMMV. Note
// that if the Maybe value is null or undefined we never touch
// f, that's the null propagation thing.
return this._value == null ? this : new Maybe(f(this._value));
}
chain (f) {
const result = this._value == null ? this : f(this._value);
console.assert(result instanceof Maybe);
return result;
}
}
Now we can test that it obeys the Monad laws:
const a = 3;
const f = x => Maybe.of(x * x);
Maybe.of(a).chain(f) === f(a) // left identity
Maybe.equals(Maybe.of(5).chain(Maybe.of), Maybe.of(5)); // right identity
And that it's a valid Functor
Maybe.equals(Maybe.of(3).map(x => x), Maybe.of(3)); // identity
Maybe.equals( // composition
Maybe.of(3).map(x => x + 2).map(x => x * 3),
Maybe.of(3).map(compose(x => x * 3, x => x + 2))
);
Sweet.
So now, to your function. It would be rewritten as
const f = (a, b, c) => {
return b[a] === undefined ? Maybe.of(c[a]) : Maybe.of(b[a]);
}
Perhaps you see now the reason for my confusion, Maybe isn't really saving you much here. But if I were using Maybe I'd rewrite the whole thing like this:
const or = (a, b) => {
return Maybe.of(a == null ? b : a);
}
And then I would just pass in the property accesses:
const obj1 = { a: 2, c: 3 };
const obj2 = { b: 4 };
const prop = "a"
const result = or(obj1["prop"], obj2["prop"]); // Maybe(2)
Update
Credit to #Bergi in the comments reminding me about Alternative. You could add a method to the Maybe class above like so:
alt (x) {
if (!(x instanceof Maybe)) {
throw new TypeError("Expected a Maybe");
}
return this.chain(x => x) == null ? x : this;
}
// semantics
Maybe.of(null).alt(Maybe.of(3)); // Maybe(3)
Maybe.of(2).alt(Maybe.of(4)); // Maybe(2)
// usage
Maybe.of(obj1[prop]).alt(Maybe.of(obj2[prop]));
Note that this doesn't totally satisfy as an implementation of Alternative (you'd also need a zero/empty method) but you can read here and here for more details. This is probably the best replacement for the function you posted.
Related
I think there is something that i'm missing about method chaining. To me it feels incomplete.
Method chaining works by having each method return this so that another method on that object can be called. However, the fact that the return value is this and not the result of the function seems inconvenient to me.
Here is a simple example.
const Obj = {
result: 0,
addNumber: function (a, b) {
this.result = a + b;
return this;
},
multiplyNumber: function (a) {
this.result = this.result * a;
return this;
},
}
const operation = Obj.addNumber(10, 20).multiplyNumber(10).result
console.log(operation)
key points:
Every method in the chain Obj.addNumber(10, 20).multiplyNumber(10) returns this.
The last part of the chain .result is the one that returns a value other than this.
The problem with this approach is that it require you to tack on a property / method to get a value at the end other thanthis.
Compare this with built-in functions in JavaScript.
const str = " SomE RandoM StRIng "
console.log(str.toUpperCase()) // " SOME RANDOM STRING "
console.log(str.toUpperCase().trim()) // "SOME RANDOM STRING"
console.log(str.toUpperCase().trim().length) // 18
key points:
Each function in the chain returns the result of the function not this (maybe this is done under the hood)
No property / method is required at the end of the chain just to get the result.
Can we implement method chaining to behave the way built-in functions in Javascript behave?
First of all, each of your console.log doesn't return properly:
console.log(str.toUpperCase.trim) //undefined
It returns undefined because str.toUpperCase returns the function object and does not execute the function itself so it won't work
The only correct usage is
console.log(str.toUpperCase().trim()
Now about your question, it is pretty easy to do it without a result and it is much more efficient.
Everything in javascript has a method called valueOf(), here is my example of calling everything like that for numbers, though I prefer just making functions instead of Objects.
const Obj = {
addNumber: function (a = 0) {
return a + this.valueOf();
},
multiplyNumber: function (a = 1) {
return a*this.valueOf();
},
}
const nr = 2;
Object.keys(Obj).forEach(method => {
Number.prototype[method] = Obj[method];
})
console.log(Number.prototype); // will print out addNumber and multiplyNumber
// Now You can call it like this
console.log(nr.addNumber().multiplyNumber()); // Prints out 2 because it becomes (nr+0)*1
console.log(nr.addNumber(3).multiplyNumber(2)) // Prints out 10;
I think you are misunderstanding what method chaining actually is. It is simply a shorthand for invoking multiple methods without storing each intermediate result in a variable. In other words, it is a way of expressing this:
const uppercase = " bob ".toUpperCase()
const trimmed = uppercase.trim()
as this
const result = " bob ".toUpperCase().trim()
Nothing special is happening. The trim method is simply being called on the result of " bob ".toUpperCase(). Fundamentally, this boils down to operator precedence and the order of operations. The . operator is an accessor, and is evaluated from left to right. This makes the above expression equivalent to this (parens used to show order of evaluation):
const result = (" bob ".toUpperCase()).trim()
This happens regardless of what is returned by each individual method. For instance, I could do something like this:
const result = " bob ".trim().split().map((v,i) => i)
Which is equivalent to
const trimmed = " bob ".trim()
const array = trimmed.split() //Note that we now have an array
const indexes = array.map((v,i) => i) //and can call array methods
So, back to your example. You have an object. That object has encapsulated a value internally, and adds methods to the object for manipulating the results. In order for those methods to be useful, you need to keep returning an object that has those methods available. The simplest mechanism is to return this. It also may be the most appropriate way to do this, if you actually are trying to make the object mutable. However, if immutability is an option, you can instead instantiate new objects to return, each of which have the methods you want in the prototype. An example would be:
function MyType(n) {
this.number = n
}
MyType.prototype.valueOf = function() {
return this.number
}
MyType.prototype.add = function(a = 0) {
return new MyType(a + this)
}
MyType.prototype.multiply = function(a = 1) {
return new MyType(a * this)
}
const x = new MyType(1)
console.log(x.add(1)) // { number: 2 }
console.log(x.multiply(2)) // { number: 2 }
console.log(x.add(1).multiply(2)) // { number: 4 }
console.log(x.add(1).multiply(2) + 3) // 7
The key thing to note about this is that you are still using your object, but the valueOf on the prototype is what allows you to directly utilize the number as the value of the object, while still making the methods available. This is shown in the last example, where we directly add 3 to it (without accessing number). It is leveraged throughout the implementation by adding this directly to the numeric argument of the method.
Method chaining is the mechanism of calling a method on another method of the same object in order to get a cleaner and readable code.
In JavaScript method chaining most use the this keyword in the object's class in order to access its method (because the this keyword refers to the current object in which it is called)
When a certain method returns this, it simply returns an instance of the object in which it is returned, so in another words, to chain methods together, we must make sure that each method we define has a return value so that we can call another method on it.
In your code above, the function addNumber returns the current executing context back from the function call. The next function then executes on this context (referring to the same object), and invokes the other functions associated with the object. it's is a must for this chaining to work. each of the functions in the function chaining returns the current Execution Context. the functions can be chained together because the previous execution returns results that can be processed further on.
This is part of the magic and uniqueness of JavaScript, if you're coming from another language like Java or C# it may look weird for you, but the this keyword in JavaScript behaves differently.
You can avoid the necessity of this and be able to return a value implicitly, using a Proxy object with a get-trap.
Here you find a more generic factory for it.
const log = Logger();
log(`<code>myNum(42)
.add(3)
.multiply(5)
.divide(3)
.roundUp()
.multiply(7)
.divide(12)
.add(-1.75)</code> => ${
myNum(42)
.add(3)
.multiply(5)
.divide(3)
.roundUp()
.multiply(7)
.divide(12)
.add(-1.75)}`,
);
log(`\n<code>myString(\`hello world\`)
.upper()
.trim()
.insertAt(6, \`cruel coding \`)
.upper()</code> => ${
myString(`hello world`)
.upper()
.trim()
.insertAt(6, `cruel coding `)
.upper()
}`);
log(`<br><code>myString(\`border-top-left-radius\`).toUndashed()</code> => ${
myString(`border-top-left-radius`).toUndashed()}`);
// the proxy handling
function proxyHandlerFactory() {
return {
get: (target, prop) => {
if (prop && target[prop]) {
return target[prop];
}
return target.valueOf;
}
};
}
// a wrapped string with chainable methods
function myString(str = ``) {
const proxyHandler = proxyHandlerFactory();
const obj2Proxy = {
trim: () => nwProxy(str.trim()),
upper: () => nwProxy(str.toUpperCase()),
lower: () => nwProxy(str.toLowerCase()),
insertAt: (at, insertStr) =>
nwProxy(str.slice(0, at) + insertStr + str.slice(at)),
toDashed: () =>
nwProxy(str.replace(/[A-Z]/g, a => `-${a.toLowerCase()}`.toLowerCase())),
toUndashed: () => nwProxy([...str.toLowerCase()]
.reduce((acc, v) => {
const isDash = v === `-`;
acc = { ...acc,
s: acc.s.concat(isDash ? `` : acc.nextUpcase ? v.toUpperCase() : v)
};
acc.nextUpcase = isDash;
return acc;
}, {
s: '',
nextUpcase: false
}).s),
valueOf: () => str,
};
function nwProxy(nwStr) {
str = nwStr || str;
return new Proxy(obj2Proxy, proxyHandler);
}
return nwProxy();
}
// a wrapped number with chainable methods
function myNum(n = 1) {
const proxyHandler = proxyHandlerFactory();
const obj2Proxy = {
add: x => nwProxy(n + x),
divide: x => nwProxy(n / x),
multiply: x => nwProxy(n * x),
roundDown: () => nwProxy(Math.floor(n)),
roundUp: () => nwProxy(Math.ceil(n)),
valueOf: () => n,
};
function nwProxy(nwN) {
n = nwN || n;
return new Proxy(obj2Proxy, proxyHandler);
}
return nwProxy();
}
// ---- for demo ---- //
function Logger() {
const report =
document.querySelector("#report") ||
document.body.insertAdjacentElement(
"beforeend",
Object.assign(document.createElement("pre"), {
id: "report"
})
);
return (...args) => {
if (!args.length) {
return report.textContent = ``;
}
args.forEach(arg =>
report.insertAdjacentHTML(`beforeEnd`,
`<div>${arg.replace(/\n/g, `<br>`)}</div>`)
);
};
}
body {
font: 12px/15px verdana, arial;
margin: 0.6rem;
}
code {
color: green;
}
In JavaScript, comparisons that involve undefined properties are evaluated as false, rather than throwing an error, even in "strict" mode.
This has created more than one hard-to-resolve bug in my code.
Is there any way to a) detect these mistakes, or b) mitigate against them?
> let x = {foo: 1}
> x.foo == 2 // Sensible behaviour
false
> x.floo // Where floo is a typo.
ReferenceError: floo is not defined
> x.floo == 2 // Nonsensical behaviour
false
Although #jonrsharpe is absolutely right that you should use Typescript if you need that level of control, just for fun, here's a pure javascript implementation. Wrap your object in strict(...) and you will get reference errors on undefined props:
const SPECIAL_PROPS = [
// well-known symbols
...Object.getOwnPropertyNames(Symbol).map(p => Symbol[p]),
// used by JSON.strinfigy
'toJSON',
// something else?
];
let strict = obj => new Proxy(obj, {
get(t, p) {
if (p in t)
return t[p];
if (!SPECIAL_PROPS.includes(p))
throw new ReferenceError(`property ${String(p)} is not defined`);
}
});
let x = strict({foo: 1})
x.foo == 2 // Sensible behaviour
x.floo == 2 // Reference error
Needless to say, this is a purely runtime check, which kinda defeats the whole purpose.
You can try using a Proxy
let x = {foo: 1}
let handler = {
get: function(target,prop,reciver){
if(!target.hasOwnProperty(prop)){
throw new Error('Sorry property do not exist')
} else{
return target[prop]
}
}
}
let proxy = new Proxy(x,handler)
console.log(proxy.foo)
console.log(proxy.floo)
You can check item === undefined.
Or define additional property .isNull() in Object prototype that covers this case:
Object.defineProperty(Object.prototype, 'isNull', {
value: function (obj) {
return (obj === null || obj === undefined);
}
});
Usage:
if(Object.isNull(x)) {
....
}
Is there a way to shorten this fragment of code?
const result = getResult();
if (!result) {
return;
}
// Work with result
I keep having lots of these in my code and would love to do something like:
const result = getResult() || return;
// Work with result
EDIT:
I only want convertable inputs to be persisted.
const parseInput = (input: string): void => {
const convertedInput = convert(input);
if (!convertedInput) {
return;
}
persist(convertedInput);
}
I know I could call the converter twice. But I want to avoid that:
const parseInput = (input: string): void => {
if (!convert(input)) {
return;
}
persist(convert(input));
}
Your code is as good as it gets, however, if you want to experiment a bit with the functional style, you can wrap the value into a "monad", which would invoke attached functions only if the value is non-zero. Here's a toy implementation:
function maybe(x) {
return {
value: x,
apply(fn) {
if (this.value)
this.value = fn(this.value)
return this;
}
}
}
With this maybe, your example would look like:
const parseInput = input => maybe(convert(input)).apply(persist)
See the Oliver's answer for a more serious approach.
You can do this
const result = "default value" || getResult();
If getResult is null or not defined then you'll get result as "default value". If that's what you want
function getResult() {
return null;
}
const result = "okay" || getResult();
console.log(result)
And when getResult is not defined you get
const result = "okay" || getResult();
console.log(result)
Basically, the syntax is
null || undefined || null || 0 || "okay" || "defined" // "okay"
It goes from left to right and picks the most relevant value
I don't really know if this answer will give you something that you'll be happy with, but it seems to me to present a potential solution to the problem of handling unknown results.
Maybes are structures which have this kind of checking built-in. the .map() below will not be called if there is no value in the Maybe, so the code which consumes it does not need to check whether a value is present.
This does mean that you have to change the way in which you handle these values however, and, unless you want to write your own, it means using a library. As such this is hardly an ideal solution, but I hope it gives an option at least.
const { None, Some } = Monet;
const getResult = () => Math.random() > 0.5
? None()
: Some(1);
const test = getResult()
.map(x => x + 2);
console.dir(test.val);
<script src="https://cdn.jsdelivr.net/npm/monet#0.9.0/dist/monet.min.js"></script>
I've been using Folktale's Validation on a new project and I've found it really useful, but I have hit a wall with the need for sequential validations. I have a config object and I need to perform the following validations:
is is an Object?
are the object's keys valid (do they appear on a whitelist)?
are the values of the keys valid?
Each validation depends on the previous validation - if the item isn't an object, validating its keys is pointless (and will error), if the object has no keys, validating their values are pointless. Effectively I want to short-circuit validation if the validation fails.
My initial thought was to use Result instead of Validatio, but mixing the two types feels confusing, and I already havevalidateIsObject` defined and used elsewhere.
My current (working but ugly) solution is here:
import { validation } from 'folktale';
import { validateIsObject } from 'folktale-validations';
import validateConfigKeys from './validateConfigKeys';
import validateConfigValues from './validateConfigValues';
const { Success, Failure } = validation;
export default config => {
const wasObject = validateIsObject(config);
let errorMessages;
if (Success.hasInstance(wasObject)) {
const hadValidKeys = validateConfigKeys(config);
if (Success.hasInstance(hadValidKeys)) {
const hasValidValues = validateConfigValues(config);
if (Success.hasInstance(hasValidValues)) {
return Success(config);
}
errorMessages = hasValidValues.value;
} else {
errorMessages = hadValidKeys.value;
}
} else {
errorMessages = wasObject.value;
}
return Failure(errorMessages);
};
I initially took the approach of using nested matchWiths, but this was even harder to read.
How can I improve on this solution?
You can write a helper that applies validation rules until a Failure is returned. A quick example:
const validateUntilFailure = (rules) => (x) => rules.reduce(
(result, rule) => Success.hasInstance(result)
? result.concat(rule(x))
: result,
Success()
);
We use concat to combine two results. We use Success.hasInstance to check whether we need to apply the next rule. Your module will now be one line long:
export default config => validateUntilFailure([
validateIsObject, validateConfigKeys, validateConfigValues
]);
Note that this implementation doesn't return early once it sees a Failure. A recursive implementation might be the more functional approach, but won't appeal to everyone:
const validateUntilFailure = ([rule, ...rules], x, result = Success()) =>
Failure.hasInstance(result) || !rule
? result
: validateUntilFailure(rules, x, result.concat(rule(x)))
Check out the example below for running code. There's a section commented out that shows how to run all rules, even if there are Failures.
const { Success, Failure } = folktale.validation;
const validateIsObject = (x) =>
x !== null && x.constructor === Object
? Success(x)
: Failure(['Input is not an object']);
const validateHasRightKeys = (x) =>
["a", "b"].every(k => k in x)
? Success(x)
: Failure(['Item does not have a & b.']);
const validateHasRightValues = (x) =>
x.a < x.b
? Success(x)
: Failure(['b is larger or equal to a']);
// This doesn't work because it calls all validations on
// every item
/*
const validateItem = (x) =>
Success().concat(validateIsObject(x))
.concat(validateHasRightKeys(x))
.concat(validateHasRightValues(x))
.map(_ => x);
*/
// General validate until failure function:
const validateUntilFailure = (rules) => (x) => rules.reduce(
(result, rule) => Success.hasInstance(result)
? result.concat(rule(x))
: result,
Success()
);
// Let's try it out!
const testCases = [
null,
{ a: 1 },
{ b: 2 },
{ a: 1, b: 2 },
{ a: 2, b: 1 }
];
const fullValidation = validateUntilFailure([
validateIsObject,
validateHasRightKeys,
validateHasRightValues
]);
console.log(
testCases
.map(x => [x, fullValidation(x)])
.map(stringifyResult)
.join("\n")
);
function stringifyResult([input, output]) {
return `input: ${JSON.stringify(input)}, ${Success.hasInstance(output) ? "success:" : "error:"} ${JSON.stringify(output.value)}`;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/folktale/2.0.1/folktale.min.js"></script>
I need to replace imagesrc with the value stored in this object. However when I run:
if(data['results'][res]['entities']['media']["0"]["media_url"]) {
imagesrc = data['results'][res]['entities']['media']["0"]["media_url"];
}
I get the error:
Cannot read property '0' of undefined
How can I run my condition so that I don't get errors if something is undefined?
if (data['results'][res]['entities']['media']["0"] == undefined
|| data['results'][res]['entities']['media']["0"] == null) {
...
}
you can place your code inside a try catch block and examin error message.
You could write a function that walks the object tree and returns undefined as soon as it hits an undefined property:
function safeGetData(obj, names)
{
for (var i = 0; i < names.length; ++i) {
if (typeof obj === "undefined") {
return undefined;
}
obj = obj[names[i]];
}
return obj;
}
You can use it like this:
var imagesrc = safeGetData(data,
["results", res, "entities", "media", "0", "media_url"]);
I’m a fan of using short circuit evaluation for these kinds of situations:
items && items[val] && doSomething(items[val])
Some people might be repulsed by this, but I think it’s a nice and readable way to express something that should only be evaluated if certain conditions are met.
In this case, we’re actually chaining two short circuit evaluations. First, we determine whether items has a defined value. If it undefined, then the rest of the expression is moot, so we won’t even bother to evaluate it. AND if it is defined, then let’s check for the existence of some property that we’re interested in. If it’s undefined, then bail out. AND if it’s true, we can go ahead and evaluate the rest of the expression.
I think it’s a lot easier to reason through at a glance than:
if (items) {
if (items[val]) {
doSomething(items[val])
}
}
Ternary operators work similarly:
items
? items[val]
? doSomething(items[val])
: alert(‘The property “‘ + val + ‘“ has not yet been defined.’)
: alert(‘You have not yet defined any items!’)
It's an old topic, I know. It's just to add my 2 cents.
I'm definitely not a javascript "guru", but here's one of my old attempts. It relies upon a couple of new ecmascript 6 features and it's going to approach the problem in a more "functional" way:
const prop = (...arr) => obj => arr.reduce((acc, v) => acc && acc.hasOwnProperty(v) ? acc[v] : undefined, obj)
And some tests in order to show how it should work:
describe('unit - prop', () => {
const event = {
record: {
sns: {
subject: 'Hello',
message: '<div>Welcome!</div>'
}
}
}
it('property exists', done => {
const value = prop('record', 'sns', 'subject')(event)
expect(value)
.to
.be
.equal('Hello')
done()
})
it('property does not exist', done => {
const value = prop('record', 'bad', 'subject')(event)
expect(value)
.to
.be
.undefined
done()
})
})
Does it make sense?