On 11/02/2017 02:12 AM, Faré wrote:
I'm a bit confused. Is it a Lisp DSL, a graphical programming system, the two next to each other, or the two at the same time, etc.? When you program graphically, how do you specify the division in files and/or systems?
Seed is an interactive programming system that uses graphics more than mainstream programming tools. I wouldn't say it's purely a graphical system since you could use it with a text-based interface, but it's much more graphical than your standard IDE. Seed uses DSLs to define some parts of itself, and it makes a few key extensions to Lisp like the (meta) macro that are needed for it to work.
The translation of the graphical interface to files and systems is defined by the I/O spec language, one of Seed's main DSLs. Look at https://github.com/phantomics/seed/blob/master/demo-sheet/demo-sheet.seed and you'll see these forms:
1. (put-file (table-specs (get-file :-self)) :-self) 2. (put-file (sheet-content (get-file :main)) :main)
Form 1 is under the (main) branch and Form 2 is under the (cells) branch. If you watch the demo video, you'll see the "main" and "cells" branches in the visual display of the spreadsheet interface. The meaning of Form 1 is "take the input to the main branch, combine it with the content of the "main.lisp" file using the "table-specs" I/O medium, then save the resulting data to the "main.lisp" file.
Where does the "main.lisp" filename come from in Form 1? Notice that the second argument to put-file and the first argument to get-file is :-self. When the :-self argument is present, the name of the branch ("main" in this case) is string-downcased and has ".lisp" appended to it.
In Form 2, instead of using the name of the branch ("sheet") the keyword :main is used, which is converted to "main.lisp." If you look at https://github.com/phantomics/seed/blob/master/demo-sheet/main.lisp, you'll see that both the data for the spreadsheet cells and the cell-manipulating forms from the left column are represented there. In this branch, the "sheet-content" medium is used to convert between the format for stored spreadsheet data and the format used in the spreadsheet interface.
So Seed's interface can have any kind of file structure behind it. In this case, I use two different interface branches to interact with a single Lisp file. I could also have a dozen different files downstream from a single interface branch.
One of Seed's core ideas is that programming interface elements should be "self-actualized" and not tied to arbitrary structures like text buffers. The interface branches may have relationships with text files, remote APIs and other things but they are not defined by them. Seed makes it easy to create "views" of code; for instance, you could have a display mode where you are shown a function at the beginning of the code display followed by every other function in the software system that calls that first function, regardless of what file it's specified in. You could also create a view for a function and its unit tests.
Implementing things like this would be much harder in Emacs since Emacs is still tightly coupled to the concept of the text buffer as the main interactive element. The self-actualized nature of Seed's interface branches is the reason that they are amenable to graphical programming and other atypical modes of interaction.
Let me know if this makes sense. By the way, if you'd like to learn more I've been doing 1-on-1 workshops with developers to show them the basics of using and extending Seed, either in person or via screen share. The latter option would probably work best for you if you're interested.
The main thing to understand is that it's a dataflow language. Each successive form like (set-time) and (codec) is passed the input data, does something to it and passes it to the next form in the list. So the till macro transforms something like "(set-time) (do-something) (codec)" to "(codec (do-something (set-time original-data)))." With this language, I can implement things like clipboards and undo history in unique ways for different systems.
Reminds me of my uiop:nest macro. https://fare.livejournal.com/189741.html More seriously, congrats, it really looks neat at first glance.
That's cool. In my case I'm reversing the order of expansion as well as adding the implicit input, so (a) (b) (c) expands to (c (b (a input))). This makes it more intuitive to specify long series of media. Also, it's possible to assign two different possible expansions to an I/O medium depending on if it's taking input or output. So inside the (in) form, (a) will do something different than it does inside the (out) form since it's handling input rather than output.
Andrew