{"action":"created","issue":{"url":"https://api.github.com/repos/ramda/ramda/issues/1205","labels_url":"https://api.github.com/repos/ramda/ramda/issues/1205/labels{/name}","comments_url":"https://api.github.com/repos/ramda/ramda/issues/1205/comments","events_url":"https://api.github.com/repos/ramda/ramda/issues/1205/events","html_url":"https://github.com/ramda/ramda/pull/1205","id":89736482,"number":1205,"title":"composable lenses","user":{"login":"davidchambers","id":210406,"avatar_url":"https://avatars.githubusercontent.com/u/210406?v=3","gravatar_id":"","url":"https://api.github.com/users/davidchambers","html_url":"https://github.com/davidchambers","followers_url":"https://api.github.com/users/davidchambers/followers","following_url":"https://api.github.com/users/davidchambers/following{/other_user}","gists_url":"https://api.github.com/users/davidchambers/gists{/gist_id}","starred_url":"https://api.github.com/users/davidchambers/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/davidchambers/subscriptions","organizations_url":"https://api.github.com/users/davidchambers/orgs","repos_url":"https://api.github.com/users/davidchambers/repos","events_url":"https://api.github.com/users/davidchambers/events{/privacy}","received_events_url":"https://api.github.com/users/davidchambers/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":19,"created_at":"2015-06-20T08:08:22Z","updated_at":"2015-06-21T17:12:24Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/ramda/ramda/pulls/1205","html_url":"https://github.com/ramda/ramda/pull/1205","diff_url":"https://github.com/ramda/ramda/pull/1205.diff","patch_url":"https://github.com/ramda/ramda/pull/1205.patch"},"body":"#### API changes\r\n\r\n```\r\nBefore:                                     After:\r\n\r\n- lens                                      - lens\r\n- lensProp                                  - lensProp\r\n- lensIndex                                 - lensIndex\r\n- lensOn                                    - view\r\n- composeL                                  - set\r\n- pipeL                                     - over\r\n```\r\n\r\n#### Creating lenses\r\n\r\n```javascript\r\nvar nameLens =                              var nameLens =\r\nR.lens(R.prop('name'), R.assoc('name'));    R.lens(R.prop('name'), R.assoc('name'));\r\n```\r\n\r\n`R.lens` takes the same arguments as before, but returns a different value. In the new API one never interacts directly with the return value, one simply provides it as an argument to `R.view`, `R.set`, or `R.over`.\r\n\r\nThe helper functions `R.lensProp` and `R.lensIndex` remain unchanged:\r\n\r\n```javascript\r\nvar addressLens = R.lensProp('address');    var addressLens = R.lensProp('address');\r\nvar headLens = R.lensIndex(0);              var headLens = R.lensIndex(0);\r\n```\r\n\r\nLenses are now just functions, so `R.composeL` and `R.pipeL` are no longer necessary:\r\n\r\n```javascript\r\nvar streetLens =                            var streetLens =\r\nR.composeL(headLens, addressLens);          R.compose(addressLens, headLens);\r\n```\r\n\r\nNote that `R.compose` reads left-to-right here. It's way too late for me to reason about this. :)\r\n\r\nThe following examples will use this data structure:\r\n\r\n```javascript\r\nvar alice = {\r\n  name: 'Alice Jones',\r\n  address: ['22 Walnut St', 'San Francisco', 'CA']\r\n};\r\n```\r\n\r\n#### `view`\r\n\r\n```javascript\r\nnameLens(alice);                            R.view(nameLens, alice);\r\n// => 'Alice Jones'                         // => 'Alice Jones'\r\n\r\nstreetLens(alice);                          R.view(streetLens, alice);\r\n// => '22 Walnut St'                        // => '22 Walnut St'\r\n```\r\n\r\n#### `set`\r\n\r\n```javascript\r\nnameLens.set('Alice Smith', alice);         R.set(nameLens, 'Alice Smith', alice);\r\n// => { name: 'Alice Smith'                 // => { name: 'Alice Smith'\r\n//    , address: [ '22 Walnut St'           //    , address: [ '22 Walnut St'\r\n//               , 'San Francisco'          //               , 'San Francisco'\r\n//               , 'CA' ] }                 //               , 'CA' ] }\r\n```\r\n\r\n#### `over`\r\n\r\n```javascript\r\nstreetLens.map(R.toUpper, alice);           R.over(streetLens, R.toUpper, alice);\r\n// => { name: 'Alice Jones'                 // => { name: 'Alice Jones'\r\n//    , address: [ '22 WALNUT ST'           //    , address: [ '22 WALNUT ST'\r\n//               , 'San Francisco'          //               , 'San Francisco'\r\n//               , 'CA' ] }                 //               , 'CA' ] }\r\n```\r\n\r\nThis API feels more in keeping with the rest of the library (returning a function with two functions attached is rather odd). Also, removing the need for special composition functions is very nice indeed.\r\n\r\nI'm opening this pull request for discussion. If we decide we like this change I'll spend some time writing documentation and figuring out the type signatures!\r\n\r\nMany thanks to @tel for walking me through the various approaches to creating lenses. The existence of this pull request suggests I absorbed at least some of the information. ;)\r\n\r\n/cc @joneshf, Master of Lenses\r\n"},"comment":{"url":"https://api.github.com/repos/ramda/ramda/issues/comments/113932286","html_url":"https://github.com/ramda/ramda/pull/1205#issuecomment-113932286","issue_url":"https://api.github.com/repos/ramda/ramda/issues/1205","id":113932286,"user":{"login":"tel","id":1141,"avatar_url":"https://avatars.githubusercontent.com/u/1141?v=3","gravatar_id":"","url":"https://api.github.com/users/tel","html_url":"https://github.com/tel","followers_url":"https://api.github.com/users/tel/followers","following_url":"https://api.github.com/users/tel/following{/other_user}","gists_url":"https://api.github.com/users/tel/gists{/gist_id}","starred_url":"https://api.github.com/users/tel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tel/subscriptions","organizations_url":"https://api.github.com/users/tel/orgs","repos_url":"https://api.github.com/users/tel/repos","events_url":"https://api.github.com/users/tel/events{/privacy}","received_events_url":"https://api.github.com/users/tel/received_events","type":"User","site_admin":false},"created_at":"2015-06-21T17:12:23Z","updated_at":"2015-06-21T17:12:23Z","body":"So as an example, we might have a prism, an interesting one, `odds :: Prism Int Int` which \"pulls out\" the option integers have to being either odd or even. Then `over odds (+1)` is a function which only \"fires\" when its target is odd. And, interestingly, turns all numbers even.\r\n\r\n"}}