Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds lensIndex, lensProp, composeL & pipeL #971

Merged
merged 1 commit into from
Mar 25, 2015

Conversation

scott-christopher
Copy link
Member

This change introduces 2 new helpers for generating lenses,
lensIndex and lensProp, where lensIndex is used to
create a new lens with a focus on an array index, while
lensProp is used to create a new lens with a focus on an
object property.

var phraseLens = R.lensProp('phrase');
var obj1 = { phrase: 'Absolute filth . . . and I LOVED it!'};
phraseLens(obj1); // => 'Absolute filth . . . and I LOVED it!'
phraseLens.set('Ooh Betty', obj1); //=> { phrase: 'Ooh Betty'}

var headLens = R.lensIndex(0);
headLens([10, 20, 30, 40]); //=> 10
headLens.set('mu', [10, 20, 30, 40]); //=> ['mu', 20, 30, 40]

This change also introduces composeL and pipeL which
are used to compose lenses together, resulting in a new lens
which can be used to access and update nested properties
of a target object.

var headLens = R.lensIndex(0);
var secondLens = R.lensIndex(1);
var xLens = R.lensProp('x');
var secondOfXOfHeadLens = R.composeL(secondLens, xLens, headLens);

var source = [{x: [0, 1], y: [2, 3]}, {x: [4, 5], y: [6, 7]}];
secondOfXOfHeadLens(source); //=> 1
secondOfXOfHeadLens.set(123, source); //=> [{x: [0, 123], y: [2, 3]}, {x: [4, 5], y: [6, 7]}]

*/
module.exports = function lensIndex(n) {
return lens(nth(n), function(x, xs) {
return _concat(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably faster to do slice(xs, 0, n].concat([x], _slice(xs, n + 1))

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As suggested, I've updated this to use _slice(xs, 0, n).concat([x], _slice(xs, n + 1)) instead.

*/
module.exports = function(k) {
return lens(prop(k), assoc(k));
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no doubt, this is a super useful pattern

@CrossEye
Copy link
Member

🌿

Very nice stuff! I really like composeL/pipeL.

I wonder if we also want lensPath similar to lensProp using path and assocPath

*/
module.exports = function lensIndex(n) {
return lens(nth(n), function(x, xs) {
return _slice(xs, 0, n).concat([x], _slice(xs, n + 1));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth pulling this out to a separate function, equivalent to assoc for arrays?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

discussion about whether assoc should work on arrays as well: #773

This change introduces 2 new helpers for generating lenses,
`lensIndex` and `lensProp`, where `lensIndex` is used to
create a new lens with a focus on an array index, while
`lensProp` is used to create a new lens with a focus on an
object property.

```js
var phraseLens = R.lensProp('phrase');
var obj1 = { phrase: 'Absolute filth . . . and I LOVED it!'};
phraseLens(obj1); // => 'Absolute filth . . . and I LOVED it!'
phraseLens.set('Ooh Betty', obj1); //=> { phrase: 'Ooh Betty'}

var headLens = R.lensIndex(0);
headLens([10, 20, 30, 40]); //=> 10
headLens.set('mu', [10, 20, 30, 40]); //=> ['mu', 20, 30, 40]
```

This change also introduces `composeL` and `pipeL` which
are used to compose lenses together, resulting in a new lens
which can be used to access and update nested properties
of a target object.

```js
var headLens = R.lensIndex(0);
var secondLens = R.lensIndex(1);
var xLens = R.lensProp('x');
var secondOfXOfHeadLens = R.composeL(secondLens, xLens, headLens);

var source = [{x: [0, 1], y: [2, 3]}, {x: [4, 5], y: [6, 7]}];
secondOfXOfHeadLens(source); //=> 1
secondOfXOfHeadLens.set(123, source); //=> [{x: [0, 123], y: [2, 3]}, {x: [4, 5], y: [6, 7]}]
```
@buzzdecafe
Copy link
Member

🐄

this looks good. any input @davidchambers ?

module.exports = function(k) {
return lens(prop(k), assoc(k));
};

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👾

@davidchambers
Copy link
Member

I haven't yet used lenses, but these functions make sense to me.

buzzdecafe added a commit that referenced this pull request Mar 25, 2015
Adds lensIndex, lensProp, composeL & pipeL
@buzzdecafe buzzdecafe merged commit c326f88 into ramda:master Mar 25, 2015
@kevinbeaty
Copy link
Contributor

Love this. Was actually just looking for something like R.lensIndex and the other functions look just as useful. Thanks @scott-christopher !

@scott-christopher scott-christopher deleted the lens-compose branch March 25, 2015 02:17
@niant
Copy link
Contributor

niant commented May 5, 2015

Looking forward to this! Hopefully next release is soon 👍

@jethrolarson
Copy link
Contributor

Should lensIndex this use R.update for the setter?

Would this be too much dog food:
lensProp = converge(lens, prop, assoc);

@CrossEye
Copy link
Member

It would not necessarily be too much dogfood. But I would want to compare that to the existing implementation, especially as converge is one of our fill-in-the-gaps functions. (useWith is the other main one.) These help us do things that we would really like to be able just to do with compose but cannot for various reasons. So as useful as converge is, I would rather not promote it overmuch. And the other important point is that the current implementation is already very clean. Just making it points-free because we can doesn't add much.

@scott-christopher
Copy link
Member Author

The reason why update wasn't initially used to implement the setter in lensIndex was because update didn't exist at the time (well, for 4 days) :)

Using update would provide a nice symmetry with lensProp.

function lensProp(k) {
  return lens(prop(k), assoc(k));
}
function lensIndex(n) {
  return lens(nth(n), update(n));
}

@CrossEye
Copy link
Member

I would definitely be in favor of that change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants