How to do this in a functional way in JavaScript using Lodash? - javascript

I'm new to functional programming and I'm trying to refactor my code to have no side-effect.
let keywords = _.get(content, '[0].keywords', []);
keywords = keywords.slice(0, config.keywordLimit);
I'm using lodash. I believe you can just chain these two methods and be something like this.
const keywords = _.get(content, '[0].keywords', []).slice(0, config.keywordLimit);
But I'm just wondering if there's a more functional way of doing this in JavaScript?

Basically, functional style is all about composition. Here is a sample:
var get = _.curry(_.flip(_.get), 3);
var slice = _.curry(_.flip(_.slice), 3);
var comp = function(f, g) {
return function(x) {
return f(g(x));
}
};
var config = {
keywordLimit: 2
};
var program = comp(
slice(config.keywordLimit, 0),
get([], 'x')
)
var x = program({
x: ['abc', 'qwe', 'sdf']
});
console.log(x);
<script src="https://raw.githubusercontent.com/lodash/lodash/4.17.2/dist/lodash.min.js"></script>
In case, this fiddle doesn't work, here's jsbin: http://jsbin.com/gicocivife/edit?js,console
Pay attention to ugly curry(flip(get)) and curry(flip(slise)). The problem is that functions in lodash has such an order of arguments that prevents you from composition. Your function expects data to work with, right? Thus, the argument for this data must be the last one. Therefore, you can compose functions. I'd recommend to look at Ramda. Not only from my point of view this is a great library for FP. Here's the same example written with it.
var config = { keywordLimit: 2 };
var program = compose(
slice(0, config.keywordLimit),
view(lensProp('x'))
)
program({
x: ['abc', 'qwe', 'sdf']
});
The thing is, functions are curried by default. Thus, the partial application comes naturally. It also features Lenses, which is an awesome thing!

Related

Is there any reason to keep using var?

WHY NOT TO BAN 'VAR'?
My question is not about the difference between 'var' and 'let'. All such answers are advocating the advantages of using 'let'.
My question is: why not to tell frankly "do not use 'var' anymore"?
Is there a reason for not being so direct?
'var' is still in use on many serious tutorial sites: Mozilla MDN, w3schools ...
I am wondering if there is an hidden reason that I am missing.
There is one answer below: legacy (old browsers not supporting ES6)
Is that the only reason?
Any performance reason?
Or some fancy use of hoisting?
[ Here was the rest of my original post...
var arr = []; // -> const arr = [];
var obj = {}; // -> const obj = {};
var temp; // -> let temp;
var f = function(){}; // -> const f = function(){};
Doing so, I think that the only way a variable may behave like a var variable (hoisting etc.), is an -unfortunately- undeclared variable: x = sthg; in some function (becoming: var x = sthg; at global scope).
If I missed something, it would highly help me. ]
The only time I've even considered using var in the last year is to take advantage of it being hoisted outside of a code block, particularly with conditionals. Something like this contrived example:
const oneOrZero = shouldBeOne => {
if (shouldBeOne) {
var test = 1
} else {
var test = 0
}
return test
}
You can replace the var in this case with let, but that always struck me as kind of messy:
const oneOrZero = shouldBeOne => {
let test
if (shouldBeOne) {
test = 1
} else {
test = 0
}
return test
}
In the end, what I've done is take advantage of the ternary operator and const. This has the added advantage of not being reassignable after checking the initial conditional, which is typically my intent:
const oneOrZero = shouldBeOne => {
const test = shouldBeOne
? 1
: 0
return test
}
TL;DR: I haven't used var in over a year. const is much preferable, and typically forces me to write better code. let is occasionally useful.

Mapping using higher-order functions with ramda.js

I have a pattern in my code that keeps recurring and seems like it should be pretty common, but I can't for the life of me figure out what it's called or whether there are common ways of handling it: maping using a function that takes an argument that is itself the result of a function taking the maped element as an argument.
Here's the pattern itself. I've named the function I want mapply (map-apply), but that seems like the wrong name:
const mapply = (outer, inner) => el => outer(inner(el))(el)
What is this actually called? How can I achieve it in idiomatic Ramda? It just seems like it has to be a thing in the world with smart people telling me how to handle it.
My use case is doing some basic quasi-Newtonian physics work, applying forces to objects. To calculate some forces, you need some information about the object—location, mass, velocity, etc. A (very) simplified example:
const g = Vector.create(0, 1),
gravity = ({ mass }) => Vector.multiply(mass)(g),
applyForce = force => body => {
const { mass } = body,
acceleration = Vector.divide(mass)(force)
return R.merge(body, { acceleration })
}
//...
const gravitated = R.map(mapply(applyForce, gravity))(bodies)
Can somebody tell me: What is this? How would you Ramda-fy it? What pitfalls, edge cases, difficulties should I watch out for? What are the smart ways to handle it?
(I've searched and searched—SO, Ramda's GitHub repo, some other functional programming resources. But perhaps my Google-fu just isn't where it needs to be. Apologies if I have overlooked something obvious. Thanks!)
This is a composition. It is specifically compose (or pipe, if you're into being backwards).
In math (consider, say, single variable calculus), you would have some statement like fx or f(x) signifying that there is some function, f, which transforms x, and the transformation shall be described elsewhere...
Then you get into craziness, when you see (g º f)(x). "G of F" (or many other descriptions).
(g º f)(x) == g(f(x))
Look familiar?
const compose = (g, f) => x => g(f(x));
Of course, you can extend this paradigm by using composed functions as operations inside of composed functions.
const tripleAddOneAndHalve = compose(halve, compose(add1, triple));
tripleAddOneAndHalve(3); // 5
For a variadic version of this, you can do one of two things, depending on whether you'd like to get deeper into function composition, or straighten out just a little bit.
// easier for most people to follow
const compose = (...fs) => x =>
fs.reduceRight((x, f) => f(x), x);
// bakes many a noodle
const compose = (...fs) => x =>
fs.reduceRight((f, g) => x => g(f(x)));
But now, if you take something like a curried, or partial map, for instance:
const curry = (f, ...initialArgs) => (...additionalArgs) => {
const arity = f.length;
const args = [...initialArgs, ...additionalArgs];
return args.length >= arity ? f(...args) : curry(f, ...args);
};
const map = curry((transform, functor) =>
functor.map(transform));
const reduce = ((reducer, seed, reducible) =>
reducible.reduce(reducer, seed));
const concat = (a, b) => a.concat(b);
const flatMap = curry((transform, arr) =>
arr.map(transform).reduce(concat, []));
You can do some spiffy things:
const calculateCombinedAge = compose(
reduce((total, age) => total + age, 0),
map(employee => employee.age),
flatMap(team => team.members));
const totalAge = calculateCombinedAge([{
teamName: "A",
members: [{ name: "Bob", age: 32 }, { name: "Sally", age: 20 }],
}, {
teamName: "B",
members: [{ name: "Doug", age: 35 }, { name: "Hannah", age: 41 }],
}]); // 128
Pretty powerful stuff. Of course, all of this is available in Ramda, too.
const mapply0 = (outer, inner) => el => outer(inner(el))(el);
const mapply1 = (outer, inner) => R.converge(
R.uncurryN(2, outer),
[
inner,
R.identity,
],
);
const mapply2 = R.useWith(
R.converge,
[
R.uncurry(2),
R.prepend(R.__, [R.identity]),
],
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.24.1/ramda.min.js"></script>
I haven't tested this but it will probably work.
The first is your function.
The second uses converge to pass 'el' through the inner function and then the identity function and pass both into an uncurried version of outer.
R.uncurryN(2, outer) works like this outer(inner(el), el), this means that converge can supply the parameters.
the third might be too far but it's fun anyway, you are calling converge with the first parameter as an uncurried version of outer and the second as an array containing inner and the identity, useWith does this which completely removes function definitions from the solution.
I'm not sure if this is what you were looking for but these are the 3 ways of writing it I found.
Paraphrased from the comments on the question:
mapply is, actually, chain:
R.chain(f, g)(x); //=> f(g(x), x)
Well, mostly. In this case, note that x must be an array.
My solution to the problem, then, is:
const gravitated = R.map(
R.chain(applyForce, R.compose(R.of, gravity))
)(bodies)
The Ramda documentation for chain is not terribly helpful in this case: it reads simply, "chain maps a function over a list and concatenates the results." (ramdajs.com/docs/#chain)
The answer is lurking in the second example there, where two functions are passed to chain and partially applied. I could not see that until after reading these answers here.
(Thanks to ftor, bergi, and Scott Sauyet.)

Is it bad practice to use JavaScript Array.prototype.map with scoped variables

I know that map() is meant to iterate lists, run a function on each member and return (or not return) a value as a list item. But what if I use it the same way as I would use forEach()?
Example:
var stuff = [1, 2, 3];
var newStuff = {};
var moreStuff = [];
stuff.forEach(function(value, key){
newStuff[value] = {'value' : value};
moreStuff.push({'other_stuff': value});
});
$('body').append('<div>1. ' + JSON.stringify(newStuff) + '/' + JSON.stringify(moreStuff) + '</div>');
//vs.
newStuff = {};
moreStuff = [];
stuff.map(function(value, key){
newStuff[value] = {'value' : value};
moreStuff.push({'other_stuff': value});
});
$('body').append('<div>2. ' + JSON.stringify(newStuff) + '/' + JSON.stringify(moreStuff) + '</div>');
results...
1. {"1":{"value":1},"2":{"value":2},"3":{"value":3}}/[{"other_stuff":1},{"other_stuff":2},{"other_stuff":3}]
2. {"1":{"value":1},"2":{"value":2},"3":{"value":3}}/[{"other_stuff":1},{"other_stuff":2},{"other_stuff":3}]
https://jsfiddle.net/0n7ynvmo/
I'm pretty sure, async considerations are the same (and might botch this example), and results are the same, but for the sake of discussion of best practices, what are the drawbacks to one way vs. another? Is it an abuse of the map() method to change a previously scoped variable within the function and not actually return anything? Is the correct answer simply a matter of discretion?
It works. However, applying Principle of Least Astonishment here suggests that it's better to use the function whose known / primary use matches your intent rather than using a different one 'off-label'. There's no TECHNICAL reason to use .forEach() over .map() here that I know of, but because generating side-effects out of .map() is an uncommon pattern, it's going to make your code less legible than it would be if you used .forEach().
If you're working in a team environment where many hands will touch your code, then it's worth being conventional in order to maximize future understanding of intent.
It's really, really poor practice to pass a callback with side effects to map, filter, reduce, etc. Most folks reading your code would expect the callback to return the new array element and do nothing else.
Something like the following is more tightly tailored to your needs and more readable.
var moreStuff = stuff.map(function(value) {
return { otherStuff: value };
});
var newStuff = {};
stuff.forEach(function(value) {
newStuff[value] = { value: value };
});
Not really many drawbacks - except in forEach you're not returning a new list. But in your case, you want a new list, so use .map
var newStuff = {};
moreStuff = stuff.map(function(value, key){
newStuff[value] = {'value' : value};
return {'other_stuff': value};
});

Learning the expressive power of Javascript

I have lots of functions of the following template:
function (field, filter){
var q = {};
q[field] = doSomething(filter);
return q;
}
I am new to Javascript, but already got the idea that it is a very expressive language. So, my question is can the body of such a function be written more concisely?
(I cannot pass q as the parameter and eliminate var q = {}, since the output of these functions should not be merged into a single object hash).
I am perfectly aware that knowing the answer to this question is likely to make my code neither faster nor clearer. I just want to learn, that's all - so no flames, please.
No, you can't simplify it more.
You are trying to do something like this:
({})[field] = value;
but then you want to return the (now modified) {}. In order to do that you have to keep a reference to it. That's what your var q = {} does.
You can always avoid repetition in your code, using something like
function objectWith(field, value) {
var q = {}; q[field] = value; return q;
}
Which would make your original code into
function f(field, filter) {
return objectWith(field, doSomething(filter);
}
Or even better, avoid 'f' altogether and use
var o = objectWith(field, doSomething(filter);
whenever you would originally use it, assuming field is always a variable. Were it a literal, it would be even clearer to write
var o = { fieldLiteral: doSomething(filter) };
Just my devious tidbit, but what you are doing is the equivalent as the following piece of code :
function f(field, filter){
var q = {};
q.__defineGetter__(field, doSomething(filter));
return q;
}
There might be some way to shorten it in that form.

Using variables with nested Javascript object

Suppose I have this:
var a = { A : { AA : 1 }, B : 2 };
Is there a way for me to create a variable that could allow me to reference either AA or B? What would the syntax look like?
// I know I can do this:
a['B']; // 2
a['A']['AA']; // 1
// something like this?
var myRef = ???;
a[myRef]; 1 or 2 depending on myRef
If not, what's a better way to get what I'm going for here?
Not directly.
Solution 1 - use object flattening
Flatten object, to have new object var a = { 'A.AA' : 1; B : 2 };.
See compressing object hierarchies in JavaScript
or Flattening a complex json object for mvc binding to get the javascript function for it.
Soution 2 - write key-path accessor
I can see it was already addressed by Eugen.
Reposted code-reviewed version:
function Leaf(obj,path) {
path=path.split('.');
var res=obj;
for (var i=0;i<path.length;i++) res=res[path[i]];
return res;
}
Solution 3 - use eval
var x = eval("a." + myRef); // x will be 1 for myRef == "A.AA", 2 for "B"
Be careful with this solution as you may introduce some security issues. It is more of the curiosity.
Since i also encounter this problem, i wrote also a one line util for this (ES6):
const leaf = (obj, path) => (path.split('.').reduce((value,el) => value[el], obj))
Example:
const objSample = { owner: { name: 'Neo' } };
const pathSample = 'owner.name';
leaf(objSample, pathSample) //'Neo'
function Leaf(obj,path) {
path=path.split('.');
var res=obj;
for (var i=0;i<path.length;i++) obj=obj[path[i]];
return res;
}
Leaf(a,'B')=2
Leaf(a,'A.AA')=1
Decorate with error handling etc. according to your needs.
With lodash _.get function, you can access nested properties with dot syntax.
Node server-side example:
const _ = require('lodash');
let item = { a: {b:'AA'}};
_.get(item, 'a.b');
Actually no, because js object are seen as property bags and doing a[X] is for accessing first level properties only...
But you could wrap the logic a['A']['AA']; // 1 in a function that does the same, like this
//WARN... no undefined check here => todo !
function _(o, path) {
var tmp = o
for (var i=0 ; i < path.length ; i++) {
tmp = tmp[path[i]]
}
return tmp
}
var r = _(a, ['A', 'AA'])
This is pretty much the same as other answers, but the difference is when dummy boy create object property name containing dots... Like var a = {"a.a" : 3 } is valid.
Now, such problem would occurs maybe more often now with the help of IndexedDB to store anything locally...

Categories

Resources