Comments (12)
Thanks for taking the time to put these together, they are really helping me learn.
I see what you are saying about not leveraging optics if just doing a transformation in one direction, which is the case here for sure. I do leverage optics for bidirectional things in several places in my application, but I think I then got used to using L
and started reaching for it in places where it wasn't necessary. Probably a good opportunity for me to clean up some code. Thanks again for the feedback
from partial.lenses.
Hi, on quick glance this seems like something that should be possible. I am busy today, but might have time to draft an example tomorrow. Is the goal just to transform (augment) the data structure (one way or two way) or to treat it as if it were augmented and then do something with the data structure (modify it or query something from it)?
from partial.lenses.
The goal is to transform it for reading by a charting library. I did get something working for this but had to essentially create 3 lenses, 1 for each scenario. Then I pick which one to use based on whether there are rows, columns, or both. I don't have that code with me but can post it here later today. Would love your feedback on it, thank you for looking at this!
from partial.lenses.
Here's what I have currently, where dataLens
is the final lens that will be used. Is there a better way to accomplish or approach this?
const recurseLens = L.lazy(rec =>
L.ifElse(
d => d instanceof Array,
L.collect([L.elems, rec]),
L.pick({
value: ["value", L.valueOr("")],
nodes: ["nodes", rec]
})
)
);
let dataLens = [];
if (hasRows === false && hasColumns === false) {
// insert row and column, then recurse
dataLens = [
L.collect(
L.pick({
value: ["value", L.define("DEFAULT_ROW")],
nodes: L.collect(
L.pick({
value: ["value", L.define("DEFAULT_COLUMN")],
nodes: recurseLens
})
)
})
)
];
} else if (hasRows === false) {
// insert row, then recurse
dataLens = [
L.collect(
L.pick({
value: ["value", L.define("DEFAULT_ROW")],
nodes: recurseLens
})
)
];
} else if (hasColumns === false) {
// Get the rows, then insert columns, then recurse
dataLens = [
L.collect([
L.elems,
L.pick({
value: ["value", L.valueOr("")],
nodes: L.collect(
L.pick({
value: ["value", L.define("DEFAULT_COLUMN")],
nodes: ["nodes", recurseLens]
})
)
})
])
];
}
else {
// If rows and columns exist, just recurse the whole structure
dataLens = recurseLens;
}
from partial.lenses.
Is there a way to tell whether two level deep structure has rows or columns based on just the structure itself (and not by using variables external to the data structure like in the example)?
from partial.lenses.
The recurseLens
const recurseLens = L.lazy(rec =>
L.ifElse(
d => d instanceof Array,
L.collect([L.elems, rec]),
L.pick({
value: ["value", L.valueOr("")],
nodes: ["nodes", rec]
})
)
)
filters a nested structure so that only value
and nodes
properties are left. Is that necessary? IOW, does the input data contain additional properties that need to be dropped, for example?
Also, the recurseLens
handles arbitrarily deep nesting. Is that also intentional or is the maximum depth always 3 (something like rows, columns, and data nodes)?
I assumed that neither of the above aspects is actually necessary. Here is a playground that does a kind of augmentation. If I understood the problem correctly, then the key is that when the input does not contain columns, then the default column needs to be inserted inside every row. The code in the playground achieves this using the insideLevelI
isomorphism constructor.
from partial.lenses.
The data structure itself does not tell me whether rows or columns are included.
It's not necessary to filter the additional properties off. I don't show it in the example code, but I actually rename the properties as well in my real implementation. The reason I do this is to try and keep the data provider somewhat agnostic from my charting library; otherwise if I switch to a different data provider, I will have to update my charting library to accept a new format. Does this step have negative performance implications?
The data can be arbitrarily nested after the rows and columns, so that was on purpose. Sorry, I should have mentioned that.
Thanks for coming up with an example solution, I'm working through it now. What is the global I
that you are using in I.seq()
for example?
from partial.lenses.
The I.seq
function comes from the Infestines library. It just pipes a given value through given unary functions. IOW, I.seq(x, f_1, ..., f_N)
is equivalent to f_N(...f_1(x)...)
.
from partial.lenses.
BTW, one thing that is important to understand about optics is that the API is different (press s
and go forward from that slide) compared to a traditional map/filter/reduce library. In particular, operations are separated from optics. An optic roughly specifies how the elements are selected from a data structure and the operation specifies what to do with those elements. So, when using the library, one first constructs an optic using primitive optics and optic combinators and then passes that optic and a data structure to an operation to get a result.
operation( optic , data ) ~> result
When you look at recurseLens
const recurseLens = L.lazy(rec =>
L.ifElse(
d => d instanceof Array,
L.collect([L.elems, rec]),
L.pick({
value: ["value", L.valueOr("")],
nodes: ["nodes", rec]
})
)
)
one thing that pops out is L.collect
, which is an operation rather than an optic combinator. When you apply an operation to an optic you get a function from data to a result rather than an optic. IOW, you get an ordinary unidirectional function. Of course, such ordinary functions are fine as read only optics, but usually one rather wants to create bidirectional optics. In this case, instead of using L.collect
one could use L.partsOf
to create a bidirectional lens like this.
from partial.lenses.
Thanks, this helps a lot. Especially thinking of an optic as a "selector" and separating it from the operations. There are probably a few places in my code where I'm using L.collect
in some weird/unnecessary ways, mainly to handle dealing with traversing arrays
from partial.lenses.
I'm struggling a bit with taking your original solution and modifying it. If I copy and paste as is, its great. But there are two modifications that I'm trying to make:
- incorporate L.pick or some other optic to tweak the data format like you showed in the second example
- incorporate recursion after the first 2 levels have been cleared
I'm pretty lost on where I would incorporate those changes
from partial.lenses.
Something like this.
Here is a similarly structured solution using only ordinary functions.
It sounds like in this case you need to perform a whole data structure transformation only in one direction. Without knowing more, I probably wouldn't recommend using optics in this particular case.
from partial.lenses.
Related Issues (20)
- Error with react native HOT 3
- Add Node compatible `L.querystring` isomorphism
- Optic doesn't support Symbol. HOT 8
- Consider adding more parsing + stringifying combinators or a separate library
- Consider adding support for Maps and Sets
- Consider adding support for splitting an object into disjoint subsets of keys HOT 1
- Change `L.removable` Take a Predicate? HOT 3
- Consider adding `disperse` operation and `partsOf` lens constructor
- Isomorphism in L.array called with undefined HOT 2
- Index isomorphism HOT 5
- Great Work 👍 Thank you (No issue) HOT 5
- Dealing with exceptions?
- I'd like to L.traverse an object HOT 4
- Usage with JSON Patching? HOT 3
- Add example exercise answers to wiki? HOT 4
- Nested matches for L.satisfying HOT 2
- Branches Does not preserve order HOT 2
- `L.get` has unexpected behavior HOT 2
- Does not works with Modules object
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from partial.lenses.