-
Notifications
You must be signed in to change notification settings - Fork 8
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
Consider giving molds a :type-vector
property to support auto composability
#11
Comments
:type-vector
property to support auto composability:type-vector
property to support auto composability
Ah! Wonderful and useful ideas. I am rereading it, but just to say this is inspiring. |
I find this pretty interesting. The thing that I like is that even bare-metal as moldable-emacs is now, you can still discover paths one edge/mold at the time. Currently I list the available molds as a list of keys. I was thinking to move towards letting the user choose a mold by computing it and show the result, but maybe you got some good ideas in this regard? |
This seems a mold that needs to be written to me. You get a mold definition and it shows you its type information, and the molds you can compose. moldable-emacs should be able to compute this implicitly, but for debugging and thinking about things, it may be useful a nice visualization :) |
I think we could make use of a principle here: the user is always in the lead. The idea is that this is a tool to help you telling your story better. Calculating all combinations of molds could become expensive pretty quickly, so if we have such a principle we could make use of history and reduce the problem to precomputing only combinations of molds that are used often? |
This sounds another refactoring that I should do anyway! "to-org-table" is more pleasing than "ToOrgTable"? I am neutral since I just moved from Scala to Clojure XD |
Any suggestions about this is welcome! I tend to make private molds first and add to core.el and contrib.el only those that I feel are very reusable or exemplar. It would be useful to get examples of good small molds and of too big molds among those that exist from you. |
That sounds like a neat idea! But I wonder if you run into some kind of base-case recursive problem. I.e., how do you express what type-vector the example is? It might be powerful to abandon the type-vector idea in lieu of working in terms of the shape of the data, but I think that has limitations that type-vectors solve. E.g. you have an s-expression. There are heuristics you can apply, but not reliably, to determine: is this Common Lisp? Emacs Lisp? Scheme? Which Scheme? Just an alist? (Or even this aside, in English, in parenthesis)? Molds taking data may not care, which is why I suggested:
By specifying their most general acceptable type, they are more connected in the graph.
Just in markdown! Maybe I haven't been spoiled by anything easier, but it doesn't seem too onerous.
I realized that presenting the user with only the end-state of a mold is not sufficient because the traversal of the edges is significant (e.g. code -> AST -> cyclomatic-complexity/file -> csv is much different than code -> line-count/file -> csv). I think this prevents the use of spanning trees. I think we would have to do a DFS backtracking algorithm. So maybe the UX is:
Totally agreed, and I wish more software adhered to this and was truly a user agent. It's a big reason I use emacs.
That's certainly a great use. I suggest that it can also be a tool to allow user's to solve specific problems they might have by solving general problems in molds. E.g. your excellent blog post about moving private functions to the bottom. I hate having to solve the same problem over and over again in different contexts. I would much rather solve the general problem once, and then be able to use it in many contexts.
I think we can make some somewhat specific statements about how expensive this might be. Here's a slightly more detailed version of "Building the Graph":
So, roughly:
Next we'd need to do the DFS. I'll hand-wave over the implementation and see that Wikipedia says it'll take something like So, with this naive implementation, we can build the entire graph in something like And then disk is cheap, we have a homoiconic language handy, so store the paths on disk and regenerate when we add molds.
Indeed, lispy people favor kebab-case :) We could probably even drop the Really I should just code all this up instead of opining in a textbox with math. We'll see if I can find the time! |
Very cool you are hanging around, again pretty interesting ideas! I really like you can express in formulas the algorithm complexity, I just had a rough intuition it could pop :D
I am not sure about how I would deal with that with the "example"/data shape approach. I was thinking to make the information captured in the example more detailed, and intersect with the :given conditions.
Totally agreed. I also had an eureka moment: assuming we have something like that working efficiently enough and that we can plot the graph, we could present how introducing a new small mold could affect the graph!! And we could even make hypotheses: "user! If you develop this mold (e.g., with this input and this output), you could make the graph twice as big because you could link these two unlinked areas". That would be dreamy!
I learn a lot from your messages! I guess we need to exploit the type vector to avoid loops to keep things finite here.
Hey the ideas are amazing as well, and little by little I may get there. A rough&mini proof of concept would speed up things though: |
I am very unlikely to lose interest in this project as I think it has the possibility to lift more of my work out of the mud and help me achieve consistency with some things I'm bad at. I am very likely to not check in for long periods of time as demands on my time pull me in different directions. I think that is maybe a common understanding with open source software, but I wanted to let you know anyhow. I still plan on contributing the algorithm discussed above, but I have no idea when (or if someone will beat me to it). Thank you again for creating this project! |
Sorry, this got a little long. Writing this up helped me think through things.
TLDR: If we give mold definitions an ordered list of type information, in increasing specificity, and write a few functions, moldable-emacs can synthesize composable molds without having to write them.
From what I can tell, the "moldable" concept is about defining a graph:
list
->csv
->list
, or Sn -> Sm -> Sn.My impression is that the power of the moldable concept comes from the fact that if you can connect novel data in a buffer with a vertex in the graph with high valency (i.e. a high number of edges), you can now leverage the full body of molds to do interesting things. That is to say, if you can make the data in your buffer look like something the moldable graph knows a lot about, you can transform that buffer into interesting things.
Currently,
moldable-emacs
has the concept of "composable molds". This is a manual definition of a path through the graph. Molds already define their requisite starting state, Sn which includes assertions about runtime requirements as well as data type information. If they separated out the runtime-requirements from statements about the data's state, and then declared the state they will leave a buffer in, Sm, it should be possible to write an algorithm to automatically discover what "end states" are possible for the current buffer.This would reduce the maintenance burden of manually defining every path through the graph possible, and might surprise the user at what's possible with their current buffer.
Representing the vertices beginning state, Sn
I think there are a few pieces of information:
Representing the vertices end state, Sm
I think it should provide the type information of the data in increasing specificity (e.g. this is an
emacs-lisp
buffer, which means it's code, which means it's a tree, but it might be a tree with a pre-defined type, like an alist or plist, etc.). This is a vector of type-information, i.e. (using the previous example) <emacs-lisp, code, tree, plist>, or TV=<T0, T1, ..., Tn>. Note that the mold is in a unique position to have the highest resolution of what type-vector the data it produces has.Building the graph, G
When the hypothetical algorithm tries to build the graph, it would need to walk the list of known molds, V={M0, M1, ..., Mn}, and for each mold, Mi:
Using the graph, G
me-mold
, walk the graph to find the vertex whose type-vector fits the buffer/data in the most general way, i.e. f(buffer, G) = Mi where:The reason to use the mold with the most general matching type-vector as a starting point is so that we get the most paths through the graph as possible. Going back to our example, <emacs-lisp, code, tree, plist>, there might be some molds that can operate on plists, but not trees. If we pick the plist mold as a starting point, we are now disconnected from any other vertices that might know what to do with emacs-lisp, code, or trees.
The reason to use the mold with the lowest magnitude type-vector is because between two molds that have matched the buffer's type in equally general ways, the mold with the higher length type-vector is making the most specific claim about the data in the buffer, and we cannot be sure the assertion holds since a mold did not generate the data. E.g. a buffer is highly likely to be <emacs-lisp, code, tree>, but it is as of yet unknown whether it is <emacs-lisp, code, tree, plist>.
Implications
This approach changes molds a little. Instead of defining molds as BeginStateToEndState, e.g. "CSVToOrgTable", molds should only be named to refer to their end state, e.g. "ToOrgTable" (or I suggest, "to-org-table"). This is because that when the user is presented with options, the options will be terminal vertices, but the span between the user's buffer and the terminal vertex might be long. It would not make sense to see "CSVToOrgTable" if I'm looking at an emacs-lisp buffer. It would make sense (albeit maybe surprising!) to see "ToCSV".
Molds should become as small as possible to promote reuse.
Traversing the path through the graph may fail if one of the mold's prerequisites fails. For this reason, prerequisites should be used sparingly.
Composable molds go away, because moldable-emacs handles that messy bit for us :)
The text was updated successfully, but these errors were encountered: