calmm-js / partial.lenses

Partial lenses is a comprehensive, high-performance optics library for JavaScript
MIT License
915 stars 36 forks source link

Nested matches for L.satisfying #214

Closed abraham-chan closed 5 years ago

abraham-chan commented 5 years ago

https://calmm-js.github.io/partial.lenses/playground.html#MYewdgzgLgBAJgQygmBeGBtAUAbxggLhigCcBXAUwBoZgALASwBs4SKwiMcG4iBGGoWLkKAXwC6MUVVz4iAMwRMI1WoxZsOmbrxgAmQUVKUJUmeKxYAMgDpQTJhWBQAFLYhIGEeQE8GYAHMXACUbAAcSEDCXACIEGIBKBJpEZASAbiA

const data = [
  { a: true, children: [{id: 1, a: true}] },
  { a: false, children: [{id: 2, a: true}] },
]

L.collect(L.satisfying(R.prop("a")), data);

Results in:

Array [
  Object {
    "a": true,
    "children": Array [
      Object {
        "a": true,
        "id": 1,
      },
    ],
  },
  Object {
    "a": true,
    "id": 2,
  },
]

I was also expecting to see

  Object {
    "a": true,
    "id": 1,
  }

Is this the intended behaviour?

polytypic commented 5 years ago

Yes, that behaviour is intended. One reason is that a fundamental property of applicative traversals is that traversals operate over non-overlapping focuses. Also, it is possible to use e.g. L.lazy to create an optic with some recursive behaviour from an optic without such recursive behaviour, but it is not possible to take out recursive behaviour from an optic (so non-recursive building blocks are more versatile).

One way to use traversals for something like this is to make the focuses non-overlapping by dividing objects with children into two disjoint subsets: one with only the children and another with everything except the children. Here is an example. By dividing the objects like that into disjoint subsets it is still possible to update the objects in a single pass.

It is also possible to use the monadic L.seq combinator to operate on a single focus multiple times and collect the results with a suitable monad, but then you lose the nice properties of applicative traversals. Such a monadic collect is not provided out of the box, but there is test code that does it and here is an example.

abraham-chan commented 5 years ago

Thanks for the constructive response! Really appreciate the effort you put into this project :+1: