Point-free composition of lenses in Ramda.js - javascript

I am trying to compose functions that return lenses, to produce a new lens, and do it in a point-free style.
This is probably a more general question about function composition. Lenses are just a case-study. I am not interested in lenses specifically, but I want to know the general pattern for how to compose these functions in a point-free way.
const obj = {a: {x: 0}, b: {x: 42}};
// this won't work, but I want it to work
const pointFreeComposedLens = R.compose(R.lensProp, R.lensProp('x'));
R.view(pointFreeComposedLens('a'), obj); // returns 'undefined'
// this works
const pointyComposedLens = key => R.compose(R.lensProp(key), R.lensProp('x'));
R.view(pointyComposedLens('a'), obj); // returns '0'
What is the pattern for composing functions so that I don't need to keep re-writing the arguments for the first function in the composition pipeline?
For an egregious example:
const deepLens = (a, b, c) => R.lensPath([a, b, c]);
// This works, but is tedious & verbose
const extraDeep = (a, b, c, x) => R.compose(deepLens(a,b,c), R.lensProp(x));
const gammaDeep = (a, b, c, y) => R.compose(deepLens(a,b,c), R.lensProp(y));
// Doesn't work, but it would be nicer to write:
const extraDeep = x => R.compose(deepLens, R.lensProp(x));
// and call it like so:
R.view(extraDeep('a','b','c','x'), obj);

I know you're looking at lenses only as an example, but here is one way to get something like the behavior I think you want from them.
const {lensPath, compose, lens, view} = R
const deepLens = (a, b, c) => lensPath([a, b, c]);
const deeper = (lens, ...args) => compose(lens, lensPath(args))
const cLens = deepLens('a', 'b', 'c')
const obj = {a: {b: { c: {d: 1, e: 2, f: {g: 3, h: 4, i: {j: 5, k: 6}}}}}}
console.log(view(cLens, obj)) //=> {d: 1, e: 2, f: {g: 3, h: 4, i: {j: 5, k: 6}}}
console.log(view(deeper(cLens, 'f', 'g'), obj)) //=> 3
const fLens = deeper(cLens, 'f')
console.log(view (fLens, obj)) //=> {g: 3, h: 4, i: {j: 5, k: 6}}
const jLens = deeper(cLens, 'f', 'i', 'j')
// or jLens = deeper(fLens, 'i', 'j')
console.log(view(jLens, obj)) //=> 5
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
As to the broader composition question, lenses are generally a special case for a library like Ramda, as the composition is in the opposite order than usually expected. (The technical reasons are too much to go into here.)
But that's why this doesn't work:
const extraDeep = x => R.compose(deepLens, R.lensProp(x));
Ramda does allow the first function in a composition chain (rightmost in compose, leftmost in pipe to receive additional arguments. But when the composition order is reversed with lens composition, it doesn't do what you might like.
So if you are having similar issues with composition in another context, please open a separate question. I'd be curious to see what you're looking for.

Rest parameters will shorten the code to:
const extraDeep = (...rest) => last => R.compose(deepLens(...rest), R.lensProp(last))(rest.pop());
but I'm not sure if that is really elegant.

If your intention is to write a function that accepts a path and an object,
then path already exists:
R.path(['a', 'b'], {a: {b: 10}}); //=> 10
If you're interested in removing some parameters in some of your functions, deepLens could be rewritten as follow:
const deepLens = R.unapply(R.lensPath);
This point-free version has the added benefit that it is not limited to just three parameters. It will work with any number of parameters:
deepLens('a', 'b'); //=> R.lensPath(['a', 'b']);
deepLens('a', 'b', 'c'); //=> R.lensPath(['a', 'b', 'c']);
deepLens('a', 'b', 'c', 'd'); //=> R.lensPath(['a', 'b', 'c', 'd']);

Related

Using reduce without return keyword by looking for unique values in an array

I like to use Array.prototype.reduce() for several different scenarios in my code, it's pretty straightforward and handy.
Please observe in the 2 different solutions below the reduce() function takes 2 different initial values, in the first case is new Set() and the second is [].
In the below example the code uses reduce() without return keyword - Set one:
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => a.add(c), new Set());
console.log(Array.from(result));
The next example is using still reduce() but here with a return keyword - Array one:
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => {
a.find(e => e === c) ? null : a.push(c);
return a;
}, []);
console.log(result);
Question:
So the .add() function for Set returns the Set object itself. The .push() function for Array returns the length of the used Array.
The Set case helps me to shorten the code using .reduce() without return keyword because the above mentioned reason. In my second example I would like to use the solution without return keyword but still with Array somehow.
Is there any workaround solution to get the same result but without using return keyword in the second example? I would like to shorten the code further if possible.
Any help is appreciated.
You could take either the accumulator, if found or concat the element to the accumulator.
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => a.find(e => e === c) ? a : a.concat(c), []);
console.log(result);
Just to mention, Set takes a complete array with the constructor.
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = Array.from(new Set(data));
console.log(result);
Array#concat can add a new item to an array and returns a new array, so can works similar to Set#add. However, it still needs the conditional operator since you want to either add an element or nothing - for the latter case that's concatenating an array with an empty array:
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => a.concat(a.some(e => e === c) ? [] : c), []);
console.log(result);
Alternatively, you can use spread syntax to again combine two arrays:
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => [...a, ...(a.some(e => e === c) ? [] : c)], []);
console.log(result);
Neither of the two is perfect, to be honest. The existence of the conditional operator makes this harder to read when all one line but it's still an option.

Can you give me an example of how to use Ramda lift?

I am reading ramda documentation
const madd3 = R.lift((a, b, c) => a + b + c);
madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
It looks like a really useful function. I can't see what would be a use case for it.
Thanks
This function can only accept numbers:
const add3 = (a, b, c) => a + b + c;
add3(1, 2, 3); //=> 6
However what if these numbers were each contained in a functor? (i.e. a thing that contains a value; an array in the example below)
add3([1], [2], [3]); //=> "123"
That's obviously not what we want.
You can "lift" the function so that it can "extract" the value of each parameter/functor:
const add3Lifted = lift(add3);
add3Lifted([1], [2], [3]); //=> [6]
Arrays can obviously hold more than one value and combined with a lifted function that knows how to extract the values of each functor, you can now do this:
add3Lifted([1, 10], [2, 20], [3, 30]);
//=> [6, 33, 24, 51, 15, 42, 33, 60]
Which is basically what you'd have got if you had done this:
[
add3(1, 2, 3), // 6
add3(1, 2, 30), // 33
add3(1, 20, 3), // 24
add3(1, 20, 30), // 51
add3(10, 2, 3), // 15
add3(10, 2, 30), // 42
add3(10, 20, 3), // 33
add3(10, 20, 30) // 60
]
Note that each array doesn't have to be of the same length:
add3Lifted([1, 10], [2], [3]);
//=> [6, 15]
So to answer your question: if you intend to run a function with different sets of values, lifting that function may be a useful thing to consider:
const results = [add3(1, 2, 3), add3(10, 2, 3)];
is the same as:
const results = add3Lifted([1, 10], [2], [3]);
Functional programming is a long and mathematical topic, in particular the part dealing with monads and cathegory theory in general. But it is worth to take a look at it, here is a funny introduction with pictures.
In short, lift is a function that will take a n-arguments function and will produce a function that takes n wrapped-values and produces another resulting wrapped-value. A lift that take a one-argument function is defined by the following type signature
// name :: f is a wrp-value => function -> wrp-value -> wrp-value
liftA :: Applicative f => (a -> b) -> f a -> f b
Wait... Wrapped-value?
I will introduce briefly Haskell, only to explain this. In haskell, an easy example of wrapped-value is Maybe, Maybe can be a wrapped-value or nothing, that is also a wrapped-value. The following example applies a function to a Maybe containing a value, and a empty Maybe.
> liftA (+ 8) (Just 8)
Just 16
> liftA (+ 8) Nothing
Nothing
The list is also a wrapped-value, and we can apply functions to it. In the second case liftA2 applies two-argument functions to two lists.
> liftA (+ 8) [1,2,3]
[9,10,11]
> liftA2 (*) [1..3] [1..3]
[1,2,3,2,4,6,3,6,9]
This wrapped-value is an Applicative Functor, so from now I will call it Applicative.
Maybe Maybe you are starting to lose interest from this point...
But someone before us has got lost on this topic, finally he survived and published it as an answer to this question.
Lets look at what did he see...
...
He saw Fantasy Land
In fantasy-land, an object implements Apply spec when it has
an ap method defined (that object also has to implement
Functor spec by defining a map method).
Fantasy-land is a fancy name to a functional programming spec in
javascript. Ramda follows it.
Apply is our Applicative, a
Functor that implements also an ap method.
A Functor, is something that has the map method.
So, wait... the Array in javascript has a map...
[1,2,3].map((a)=>a+1) \\=> [ 2, 3, 4 ]
Then the Array is a Functor, and map applies a function to all values of it, returning another Functor with the same number of values.
But what does the ap do?
ap applies a list of functions to a list of values.
Dispatches to the ap method of the second argument, if present. Also
treats curried functions as applicatives.
Let's try to do something with it.
const res = R.ap(
[
(a)=>(-1*a),
(a)=>((a>1?'greater than 1':'a low value'))
],
[1,2,3]); //=> [ -1, -2, -3, "a low value", "greater than 1", "greater than 1" ]
console.log(res);
<script src="https://cdn.jsdelivr.net/npm/ramda#0.26.1/dist/ramda.min.js"></script>
The ap method takes an Array (or some other Applicative) of functions an applies it to a Applicative of values to produce another Applicative flattened.
The signature of the method explains this
[a → b] → [a] → [b]
Apply f => f (a → b) → f a → f b
Finally, what does lift do?
Lift takes a function with n arguments, and produces another function that takes n Aplicatives and produces a flattened Aplicative of the results.
In this case our Applicative is the Array.
const add2 = (a, b) => a + b;
const madd2 = R.lift(add2);
const res = madd2([1,2,3], [2,3,4]);
//=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
console.log(res);
// Equivalent to lift using ap
const result2 = R.ap(R.ap(
[R.curry(add2)], [1, 2, 3]),
[2, 3, 4]
);
//=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
console.log(result2);
<script src="https://cdn.jsdelivr.net/npm/ramda#0.26.1/dist/ramda.min.js"></script>
These wrappers (Applicatives, Functors, Monads) are interesting because they can be anything that implements these methods. In haskell, this is used to wrap unsafe operations, such as input/output. It can also be an error wrapper or a tree, even any data structure.
What hasn't been mentioned in the current answers is that functions like R.lift will not only work with arrays but any well behaved Apply1 data type.
For example, we can reuse the same function produced by R.lift:
const lifted = lift((a, b, c) => a + b - c)
With functions as the Apply type:
lifted(a => a * a,
b => b + 5,
c => c * 3)(4) //=> 13
Optional types (dispatching to .ap):
const Just = val => ({
map: f => Just(f(val)),
ap: other => other.map(otherVal => val(otherVal)),
getOr: _ => val
})
const Nothing = {
map: f => Nothing,
ap: other => Nothing,
getOr: x => x
}
lifted(Just(4), Just(6), Just(8)).getOr(NaN) //=> 2
lifted(Just(4), Nothing, Just(8)).getOr(NaN) //=> NaN
Asynchronous types (dispatching to .ap):
const Asynchronous = fn => ({
run: fn,
map: f => Asynchronous(g => fn(a => g(f(a)))),
ap: other => Asynchronous(fb => fn(f => other.run(a => fb(f(a)))))
})
const delay = (n, x) => Asynchronous(then => void(setTimeout(then, n, x)))
lifted(delay(2000, 4), delay(1000, 6), delay(500, 8)).run(console.log)
... and many more. The point here is that anything that can uphold the interface and laws expected of any Apply type can make use of generic functions such as R.lift.
1. The argument order of ap as listed in the fantasy-land spec is reversed from the order supported by name dispatching in Ramda, though is still supported when using the fantasy-land/ap namespaced method.
Basically it is taking a cartesian product and applies a function to each array.
const
cartesian = (a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []),
fn = ([a, b, c]) => a + b + c,
result = [[1, 2, 3], [1, 2, 3], [1]]
.reduce(cartesian)
.map(fn);
console.log(result); // [3, 4, 5, 4, 5, 6, 5, 6, 7]

Javascript copy array of properties to another object (one-liner) [duplicate]

This question already has answers here:
One-liner to take some properties from object in ES 6
(13 answers)
Closed 5 years ago.
This is obviously straight-forward using traditional loops, but I'm curious if anyone can think of a nice, compact way of doing it with destructuring and the spread operator.
For example, let's say I have
const foo = { a: 1, b: 2, c: 3, d: 4 };
const list = ['a', 'd'];
I'd like to create bar = { a: 1, d: 4 }.
You could do something like
const bar = {};
list.forEach((p) => { bar.p = list.p; });
But I'm wondering if anyone has a slick one-liner using ES2015+. For example, you can do const { b, c, ...bar } = foo, but that's if you have the inverse known prior to runtime.
While the solution ideally would support a dynamic list of properties in an array, one with a statically known list is better than nothing. (For example, const bar = ({{ a, d }} = foo)
The best I think you'll be able to do is with Array#reduce:
const foo = { a: 1, b: 2, c: 3, d: 4 };
const list = ['a', 'd'];
const bar = list.reduce((o, k) => (o[k] = foo[k], o), {})
console.log(bar)

Difference between Destructing and ...Spread in JavaScript

I am trying to understand the difference between destruct and ...Spread in the following scenario:
Example using ...Spread
function do2(a,b,c){
alert (a+b+c);
}
do2(...[5,3,5]);
Example using Destructing:
function do3({a , b , c}){
alert (a+b+c);
}
do3([5,3,5]);
When do I use each way? Can anyone tell the difference between both ways and which one to use in this scenario? I am still a beginner, so any help would be good.
Operator Spread
Spread example:
const add = (a, b) => a + b;
let args = [3, 5];
add(...args); // same as `add(args[0], args[1])`, or `add.apply(null, args)`
Functions aren't the only place in JavaScript that makes use of comma separated lists - arrays can now be concatenated with ease:
let cde = ['c', 'd', 'e'];
let scale = ['a', 'b', ...cde, 'f', 'g']; // ['a', 'b', 'c', 'd', 'e', 'f', 'g']
Destructuring
Destructuring is a way to quickly extract data out of an {} or [] without having to write much code.
let foo = ['one', 'two', 'three'];
let one = foo[0];
let two = foo[1];
let three = foo[2];
into
let foo = ['one', 'two', 'three'];
let [one, two, three] = foo;
console.log(one); // 'one'
ES6 also supports object destructuring, which might make uses more obvious:
let myModule = {
drawSquare: function drawSquare(length) { /* implementation */ },
drawCircle: function drawCircle(radius) { /* implementation */ },
drawText: function drawText(text) { /* implementation */ },
};
let {drawSquare, drawText} = myModule;
drawSquare(5);
drawText('hello');
The first example assigns a, b c to to elements of passed array at indexes 0, 1, 2, corresponding to the number of elements in the array
function do2(a, b, c){
alert (a + b + c);
}
do2(...[5, 3, 5]);
The second example expects an object as parameter to the function, {a , b , c} destructures the passed object assigning a, b, c as local variables within the function
function do3({a , b , c}){
alert (a + b + c);
}
do3({a:5, b:3, c:5});
See also What is SpreadElement in ECMAScript documentation? Is it the same as Spread operator at MDN?

function composition in ramda.js

Given the following:
var xs = [{a: 1}, {a: 2}, {a: 3}];
R.findIndex(R.propEq('a', 2))(xs); //=> 1
R.findIndex(R.propEq('a', 4))(xs); //=> -1
How do I create a new function that does not bind propEq immediately.
I thought curry might do it.
var myfn = R.findIndex(R.propEq);
myfn('a', '2')(xs); // => 1
I tried curry, but I don't have it quite correct.
var myfn = R.findIndex(R.curry(R.propEq)); // functional programming is rusty - this is not currect
Well, my first thought is that simply being explicit would be best here:
const findByProp = curry((key, val, xs) => findIndex(propEq(key, val), xs));
const xs = [{a: 1, b: 10}, {a: 2, b: 20}, {a: 3, b: 30}];
findByProp('a', 1, xs); //=> 0
findByProp('a', 2)(xs); //=> 1
findByProp('b')(30)(xs); //=> 2
There might be some way to make this points-free using useWith or converge or Sanctuary's S combinator, but they would probably in the end not be as readable as this.
You can see this in action on the Ramda REPL.

Categories