Cognition: A new antisyntax language redefining metaprogramming
ret2pop.nullring.xyz
ret2pop.nullring.xyz
It is very neat to see this kind of syntax bootstrapping. I think there's some value (in a researchy-sense) to being able to do that. But I'm not sure if there's something fundamentally "better" about this approach over Racket's approach.
Postscript: Lisp (and Scheme and Racket) macros typically operate on AST (typically because Lisp has reader macros and Racket has a full-bodied reader extension) but Rhombus [3] operates on a "shrubbery", which is like an AST but it defers some parsing decisions until later. This gives macros a little flexibility in extending the syntax of the language. Another interesting point in the design space!
[1]: https://docs.racket-lang.org/guide/hash-reader.html
[2]: https://docs.racket-lang.org/datalog/datalog.html
[3]: Flatt, Allred & Angle et al. (2023-10-16) Rhombus: A New Spin on Macros without All the Parentheses, Proceedings of the ACM on Programming Languages. https://doi.org/10.1145/3580417
1: Which is powerful enough to implement a C compiler in: https://github.com/vsedach/Vacietis
In Lisp they don't. See Emacs Lisp, Common Lisp, ISLISP. A Lisp macro gets only passed some data and returns some data. There is nothing like an AST.
If we define a macro foo-macro and we call it:
(foo-macro ...)
then ... can be any data.Example:
(defmacro rev (&rest items)
(reverse items))
Above macro REV gets data passed and reverses it. The &rest list of ITEMS gets reversed. ITEMS is the list of source arguments in the macro call.We can then write:
(rev 1 2 3 4 +)
(rev (rev 10 n -) (+ a 20 b) (rev 30 a *) list)
Example: CL-USER 7 > (let ((n 4) (a 3) (b 2))
(rev (rev 10 n -)
(+ a 20 b)
(rev 30 a *)
list))
(90 25 -6)
There is no syntax tree. All the macro does, is to reverse the list of its source arguments.If I let the macro describe the thing it gets passed, then we get this:
CL-USER 8 > (defmacro rev (&rest items)
(DESCRIBE items)
(reverse items))
REV
CL-USER 9 > (rev 1 2 3 4 +)
(1 2 3 4 +) is a LIST
0 1
1 2
2 3
3 4
4 +
10
As a side effect, we can see that the macro gets a simple list passed. A list of numbers and a symbol ("symbol" is also a data type). Not text. Not an AST.Also data which is possibly not read, but computed by other code. We can compute the arguments of the macro REV and pass the thing to EVAL. Works the same as above.
CL-USER 10 > (eval (append '(rev) (loop for i from 1 to 4 collect i) '(+)))
(1 2 3 4 +) is a LIST
0 1
1 2
2 3
3 4
4 +
10
The macro only gets that data and can do anything with it. There is no idea of Abstract Syntax Tree: it does not need to be a tree, it does not need to be valid Lisp code and it carries no syntactical information. Generally, it also does not need to return valid Lisp code. To be computed all we need is that the evaluator eventually sees valid Lisp code, not the individual macro.In Lisp the "reader" by default only parses a data layer: symbolic expressions. EVAL, macros and other Lisp functionality gets mostly data passed. EVAL has to figure out, what (a b c) actually is as a program. It can traverse it in an interpreter or compile it. A compiler may internally create AST representations -> but that free to the implementation.
The Lisp language then typically is not defined over text syntax, but data syntax.
A Lisp interpreter processes during execution not text, but s-expressions. It's a "List Processor", not a Text Processor. Lisp not Texp. ;-) The function COMPILE gets an s-expression passed, not text.
Racket and Scheme have other macro systems.
For example I can make a circular list being a part of the source and the macro may process it.
Get the first two items from a list and add them:
CL-USER 21 > (defmacro add-2 (a)
(list '+ (first a) (second a)))
ADD-2Now we construct a circular list and use the macro:
CL-USER 22 > (add-2 #1=(1 2 3 . #1#))
3
The circular list is really a part of the source code: CL-USER 23 > '(add-2 #1=(1 2 3 . #1#))
(ADD-2 #1=(1 2 3 . #1#))
Another example: One could pass in a string and have the macro parse the string... (IF <text-expr> <then-expr> [<else-expr>])
But appearing in a macro expansion, it would just be a list where the first item was the symbol "IF" from the "COMMON-LISP" package. In addition, you could put e.g. (IF foo bar baz biff quux)
Inside the body of a macro you would get a list that does not match the syntax of the "if" special form, despite superficially looking like such a list. This doesn't match anything that one would call an "AST" in other languages, which would enforce syntactical correctness of special forms.Scheme did implement actual syntax objects and other lisps may have a concrete ast (pun slightly intended) layer but it's not required to enjoy the benefits of sexp as code and data.
my two cents
(let ((s (s s)))
(flet ((s (s) (declare (type s s)) s))
(tagbody (s) s (go s))))
The function READ has no idea what S is: variable, operator name, data symbol, type, go tag, function name, macro name, ...? For each above we don't know what s is. We would need to parse it according to some syntax (and possibly know the current state of the runtime.An AST would be the product of a parser and the parse would parse the code above according to some provided syntax. The AST then would encode a tree built from some syntax, where the nodes would be classified. In Lisp symbols and lists have multiple uses and the s-expression does not encode which uses it is: is it data, is it some kind of syntactical element. There is also no defined parser and no syntax it encodes on that level. READ is at best an s-expression reader, where it has zero knowledge what the lists and symbols supposed to mean in Lisp. For the reader (+ a b), (a + b), (a b +) are just s-expressions, not Lisp code.
Where there serious defects caused due to this dynamic nature (honest question) ? it seems to me that people adjusted to this without big troubles. Not that I'm against any improvement.
Nanopass shows an example of using "rewriting" while keeping to pretty much same structure for AST till you end up with native code.
The compiler will expand the macros at compile time and the generated source code then is checked.
One thing this macro system enables are macros which can implement relatively arbitrary syntactical extensions, not restricted by a particular syntax. That can be seen as useful&flexibility or as potential problem (-> needs knowledge and discipline while implementing macros, with the goal of ensuring the maintainability of the code).
In the lisp world, when data represents code, it's probably stored in a tree. Elsewhere, when data represents code, it's probably stored as an array of bytes. There code may not be recognised as being data at all.
It's the difference between eval taking a byte string and taking a parse tree. Rather literally.
This is only a convention. Lisp does it right, but as almost everything else thinks code is strings, confusion abounds.
The data AST is rich enough to for ergonomic, precise source-to-source manipulation. Even a pretty advanced Lisp compiler can be built which goes straight from the data AST to an intermediate representation, skipping the code AST stage.
"Data AST" means that when we have (+ 1 2), this doesn't say "I'm an arithmetic expression", but rather something weaker: "I'm a list of three elements: a symbol object, and two integer objects".
The list object is an abstract syntax tree for the printed list. It must be. It not a parse tree because a parse tree would preserve the representation of the parentheses: in a parse tree, every grammar symbol appears: the nodes of the tree are 1:1 to the grammar rules that they match. Since the parentheses, and whatnot, are gone, it must be abstract syntax.
Most of Lisp syntax is designed such that its syntactic units correspond to nodes of the data AST. That makes source-to-source transformations ergonomic, because the data AST data structure is easy to manipulate.
When I'm reading something informational (rather than recreational) I'm always asking myself "is this worth my time?" You should address this as soon as possible, by telling the reader what the document is about right at the start. "Cognition is a new language exploring user modifiable syntax" or something similar. I didn't get past the first four paragraphs because I couldn't determine it was worth continuing.
It doesn't. You will not be using this language. And even if you will, you'll get all the information from a documentation, not from this article. If your time is money you wasted your time reading the article.
Really why some people believe that all the content of Internet must be attuned to their personal quirks? Why they believe that it is better to change internet, than to adapt to what is already here? It is a text, not video or something sequential. You could scan it diagonally looking for something that is interesting for you. You could reject it if nothing was found. Or you could return to the beginning and read sequentially from there. And these features are available for a text structured in any way. I highly recommend to learn the technique, it could deal with whole books, by selecting useful pages to read and rejecting most of other pages, which tell you nothing new.
I'd argue that diverse article styles are much better, because they force you to consciously and actively sort through information you are consuming. You shouldn't do it passively, becouse your mind becomes lazy and stop thinking while consuming.
OTOH I would agree with you if it was not a text but a video. I hate videos because you need to decide upfront are you investing time into watching it or not. 2x speed and skips by 5-10 seconds helps somehow, but do not solve the problem.
Hard disagree, not always we read things which has a direct impact on what we do. Sometimes ideas in one area can spark solutions for other problems.
Imagine aerospace engineers never looking at birds, or military equipment not getting inspiration from chameleons.
Of course, but this effect is unpredictable. You could get an idea while reading some fiction, because the plot sparked some chain reaction of associations in your brain. But if it will happens or not is not predictable on basis of an abstract of an article. GP clearly talks about something else.
> military equipment not getting inspiration from chameleons.
A good example. If your goal is to fight the enemies it will be counterproductive to seeks for black swans by finding and studying new life forms. But you can still do it in a "fishing mode", just looking for something that seems interesting.
Science is living on a government support exactly because it is unpredictable. It can sometimes discover electricity, but most of the efforts of scientists gives little to no useful knowledge. One cannot know a priori if their research will have a big impact or not.
Sometimes it's inappropriate, and ultimately the author is the best judge of this.
If you view text composition as a UX problem, it will help you figure out when to use the tool and when not to.
Examples where it isn't used (clickbait headlines, recipe blogs with three pages of meandering before they get to the ingredients, SEO "optimised" youtube videos) are, IMO, examples of dark UX patterns more often than not. But your use-case may be valid.
(This comment written using an inverted pyramid structure).
I read the OP as constructive feedback not an attack. I also think that their advice is practically bog standard writing advice not a personality quirk.
I would also suggest that you might look in the mirror at your own comment when accusing someone of imposing their personality quirks on someone else.
Aside from the tone, the specific feedback was also a miss, imo. It was written from the standpoint of as if they were reading a marketing page, or a show hn post, which it is not. It is simply a blog post. An article. To me it provided a bunch of context and was kind of enjoyable.
When you have a marketing page or some kind of "check it out" post, there is a certain level of expectation that the reader can expect and it's even reasonable to complain when the given post does not get to the point. I agree with that.
This is not such a thing
By the way, what even defines "simply a blog post"? That's just a media format that doesn't say much about the content itself, does it? I do agree with the sentiment that it would have been good to know what the article is even going to be. Not even the paragraphs were very helpful in this regard. It does improve the reception of an article if it meets the intended audience.
In retrospect, this article is mostly about a basic compiler frontend language and how to bootstrap that into a fully-featured concatenative programming language. Which to me personally is a "hm, okay, interesting" kind of thing but I didn't read the article for this premise. I read it for the "new antisyntax language" and feel it was clickbaitish.
That, to me, is much more useful to gauge my interest than your proposed introduction.
It's clearly not the most important part of the project but it serves to illustrate the kind of problem that the project intends to solve. Without something like this section the following sections would be even more difficult to understand.
For instance:
> This makes the left and right parenthesis unchangable from within the language
The parenthesis character in Common Lisp can be redefined, even just temporarily, to anything you want.
This is a misunderstanding and shouldn't be in your opening play.
It sounds like the author thought of something they felt was neat, but felt they had to justify its existence first by a quick pot-shot at another similar thing. It would be more effective if either it were correct, or they just described their own creation from the get-go.
It was never meant to be a pot-shot, and I have nothing against lisp. I can tell why it reads that way, and we added that in because we wanted to illustrate why people should care.
As to your claim about us being wrong: I don't have an issue with being wrong, and maybe at the same time we are. At the same time, I think it is possible that there are misunderstandings that cause people to believe we aren't doing something new. Again, maybe we're not.
We're two 18 year olds, fresh out of high school. It's a research project, but we're not graduate students.
A lot of these comments are claiming it's not new because reader macros exist. From my understanding, our tokenization system is unique because it can all be done at runtime without backtracking or executing anything instantly, which is possible because cognition always makes use of the text read in, and never makes use of anything not yet read in, which means you don't have to backtrack. I mean, you could backtrack but it would be less elegant.
If I'm wrong about this then that's fine but then we still made something cool without even knowing it existed beforehand.
On the other hand, I'm adding it to my list of examples of "left handed scissors" languages, along with LISP and FORTH themselves. Languages which a few percent of people regard as more intuitive but most users do not and prefer ALGOL derivatives.
Like if you want to integrate JSON or XML into the language syntax you can.
Rather ironic to use it as an example of inflexible syntax.
Here's an example which adds completely integrated JSON support in under 100 lines of code, using only standard language APIs: https://gist.github.com/chaitanyagupta/9324402
If it was “look, shktshfdthjkl\n\nbhhj, so cool”, it would signal rocket rainbow unicorn and lose me at that. IMO we need more properly structured non-SV prose like this in tech, not less.
That said, personally I think that Forth is as philosophically pure as I'm willing to gaze up the ladder of programming purity. :P
https://aphyr.com/posts/353-rewriting-the-technical-intervie...
Then again I was once a pure math grad, so "beautiful, fascinating, albeit completely practically useless" is something I mean as a compliment.
I need to read up on Stem and then come back and read this post of yours again to better appreciate it, I suspect. But that sounds like fun.
not much is novel nowadays. great job!
Metaprogramming and programming are the same thing. It's just that no language, including all lisp, (but hilariously not m4) get quotation wrong. Lisp gets around this with macros which let you ignore quotation and deal with meta language statements expressed as object language statements when they clearly should not be.
This issue stems from the fact space in the object and meta language is treated as the termination of an atom without distinction between the two.
>Cognition is different in that it uses an antisyntax that is fully postfix. This has similarities with concatenative programming languages
Postfix languages are a dual of prefix languages and suffer from the same issue. You either need to define the arity of all symbols ahead of time and not use higher order functions or you need a pair of delimiters which can serialise a tree. Relying on an implicit zeroth order stack solved the problem in the same way a lobotomy solves depression.
I mean, fair and flowery, but an implicit stack has been a thing ever since proto computers/calculators. Just like a lobotomy reduces the availability of higher order processing, so too does going back to the utmost primitives in calculating a string of instructions
Reading the article was really enjoyable. As a reader, I could feel the authors' excitement and recognize the joy they've felt as they've climbed over hilltops only to realize a new range of possibilities.
If I understand it correctly, what's really being said here is that, with Cognition, you can build truly "thinking" machines.
Programs can write and execute their own novel subroutines, based on new input and without ever being halted and restarted with new instructions. And that means the program can learn and adapt by building new abstractions and possibly connect itself to new APIs.
To me, that's more exciting than a bigger neural network or a new training technique.
Common Lisp has reader macros. You can change the syntax to anything you like. There is even Fortran compiler written using reader macros to lead Fortran syntax.
Common lisp has
1. reader macros for read time,
2. macros
3. compiler macros for compile time
Macro language for all these is Common Lisp.
Metaprogramming has little to do with macros or syntax. Term refers to ability to manipulate semantics and meaning of of types, interfaces, classes, methods, etc. CLOS (Common Lisp Metaobject Protocol) for that if CL itself is not strong enough.
They are talking about CL reader macros here. You can use a different tokenizer in CL with reader macros, but you have to use an expression in the read table to say that you're switching tokenizers. It seems like in Cognition you can call a function and that will switch tokenizers in the callers context.
The first and only example I can think of is the halting problem. On a practical scale one might prove that the base language doesn’t have memory leaks, so neither can the derived language? What are the advantages of bootstrapping like this? If the answer is simply another form of “because it’s there” (Mallory, re climbing Everest) then I respect that!
thx but no thx
the previous line ends with three space characters to indicate sarcasm; interpret literally wherever trailing whitespace is not readily discernible
The part of the bootstrap you're referring to is, in fact, the part where they tell the reader to treat space and newline as delimiters, so it appears you're complaining about whitespace being significant in the part of the program where they declare it to be a delimiter.
Such is your right, of course, but it does lead one to wonder if you had some better idea for how to go about this.
I don't see how you could do that -without- a literal space being relevant in that way once.
Syntax provides structure. Or do you think sentence this without you syntax read can?
"Cognition is different in that it uses an antisyntax that is fully postfix"
Postfix is syntax. Just ask any German-speaking person about verbs on the ends of sentences. Read this, you can.
In the first example given, the ordering of the operands and operators is important. That is syntax.
This is someone trying to invent a stupidly compact language. Reminds me a lot of APL. Hints for the authors: (a) You haven't done away with syntax, you have just made it difficult for humans to read and understand, (b) readability and understandability are important factors in programming.
There's clearly something deep going on, but I will have to come back to this after an even deeper cup of coffee.
I suspect the reception of it being suspected to be a joke, is the mention of lisp and brainfuck priming them for a joke, combined with examples and concepts that seem to require a much stronger than normal technical background. So for the average Joe it ends up in the “turbo encabulator” zone where it’s not quite clear if what’s going on is real or in jest. The prerequisites for understanding just aren’t there.
I also suspect a non-zero percentage of the readers have involuntarily audio flashbacks of Soulja Boy when they see that many “cranks” on a page.
Quite the opposite, you'll find this is a strength of lisp code. That all its syntax is always represented as a tree makes it very easy to edit and manipulate in an editor which supports operations on that tree. What's more, you could add routines in your editor to display the code in any format you like and translate back to the lisp format when writing to the disk. This is much more difficult in most other programming languages.
Big words from a C project that has not a single warning option in its CFLAGS.
It's like packing things into a backpack and then only at the end learn that we are going to Alaska instead of Hawaii.
Silliness aside, I have the same problem and probably need to, yet again, beat my head against FORTH, preferably with an interpreter that somehow shows me the stack as it goes. Or maybe factor-lang instead on the grounds that it's higher level and also that I can escape to lexical variables when completely stuck.
It's inspired me to mess around in this area again, and I'll definitely have to re-read your blog post a few times.
In general, show more of what is possible in a more accessible way first, before presenting "line noise".
Overall that document would be helped by some editing to bring out more of what a reader who haven't spent months thinking about this will find interesting first.
It seems as though you've read the entire article and understood a decent portion of it. I'm impressed because I think I explained this suboptimally.
E.g. "here's a cool thing thing we can do <demonstrate the outcome of significantly changing a readable syntax>" to hook people, "here's how <show how you change syntax with higher level helpers>", "and if you really want to know how to bootstrap this from basics <here comes the linenoise>".
Maybe compare how e.g. Forth is often introduced, with how people describe bootstrapping of a simplistic Forth like Jonesforth or Sectorforth [2]. Showing people how they can define their own words and it fundamentally changes how they work with the language afterwards is cool to a lot of people who have no interest in details like how you an implement even numbers with a minimal set of primitives (e.g. Sectorforth relies on that - it doesn't have builtin numbers[3]).
Both are interesting to me, but I'm weird, and I think for most people it'd be easier to maintain their interest if those two aspects are either separate articles or at least if the bootstrapping is relegated to a standalone section they're clearly told they can skip.
[1] https://news.ycombinator.com/item?id=31368212
[2] https://github.com/cesarblum/sectorforth
[3] The Sectorforth Hello world defines every numeric constant it needs like this:
: -1 ( x -- x -1 ) dup dup nand dup dup nand and ;
: 0 -1 dup and ;
: 1 -1 dup + dup and ;
: 2 1 1 + ;
: 4 2 2 + ;
: 6 2 4 + ;
Which is fun if you're a language geek. Not so convincing if you want to know if Forth is fort you [EDIT: That mistake was wholly unintentional, but I'll leave it]. ldfgldftgldfdtgl
df
dfiff1 crank f ajksbdnfjasdnflaksdfbnfI think a lot of people on HN nowadays can only see the world through the lens of Javascript and as a result really can't appreciate what this is.
i think it'd also help a lot to have some gifs of the state machine operating on stuff
or maybe you could have something with "syntax" highlighting. a navigable timeline that changes the highlighting based on the current ignore lists and / or stack contents as you step through the code could be neat
It's a bit like being taught functional programming by starting with composing everything from combinators, including church numerals for numbers. Sure, knowing those bits is worthwhile theory, but not until you're convinced about the higher level utility.
In Italian "perculare" is a (slang) verb meaning "to make fun of someone, in a rude way".
I doubt this was intentional. If it is well, hats off to you
I'm having trouble working out how this differs from Factor, in which left bracket and quote are also not primitive.
How is this more general than a language like Binary Lambda Calculus, which can bootstrap into any other language, like Brainfuck in 112 bytes of bootstrap, or even into Cognition itself?
Doesn't that sound like TeX \catcode? In fact, I think you can bootstrap Cognition from TeX as well.
My understanding is that this is a Forth system, that tries to address a big problem with such systems, the messiness around "immediate" words, etc. It does this by using a global variable called crank.
Am I right?
Your post sounds like an interesting research project, but the examples given in the blog post seem somewhat discouraging to me. When I gaze at one of your examples, they seem obtuse and while I am sure I could understand the examples by not just skimming the article, this does tell me that the grammars you used are not very self-explanatory: Your syntax expresses meaning relative to the specific grammar as opposed to expressing meaning relative to the English language or pre-existing, well-established programming languages.
Is there some example of self-explanatory grammars and self-explanatory bootstrapping code in your language?
STOPPARSE
It would be defined as causing the normal parser to stop, and any text / bytes after that keyword is fed as input to the program.
__DATA__ sooort of counts and is probably the closest to pure STOPPARSE as GP is thinking of.
I also, once, wrote https://p3rl.org/Devel::Declare which basically grabbed the current read position and Did Things, including calling back into the existing perl parser to not have to re-implement everything - that was how perlers first got access to a mostly* working 'method' keyword.
(now there's a proper way of doing that in perl core, and Devel::Declare is (very happily to me) obsolete, but it was essential to prove the concept and the user interest to justify adding the actual feature to the core interpreter)
[*] the caveats are many and believe me I'm well aware the entire thing was a giant hack from the moment I first started writing it, but rather than trying to write them out I'll just say "however hacky you imagine this was, what I actually did is probably worse" and leave it there.
That just gives you arbitrary input. You can write your own interpreter for a language and do the input in that language, but that’s not “arbitrary metaprogramming” in the host language, at least as most people understand it. Or you can leverage whatever metaprogramming facilities are offered by the host via an external DSL you implement, which may be a more ergonomic way of metaprogramming the host language, but still is limited to the metaprogramming facilities exposed by the host language, so it’s only “arbitrary metaprogramming” to the extent that the host language already exposes arbitrary metaprogramming.
There's e.g. a giant pile of pure maths that demonstrates how to build up basic normal maths from a much tinier set of axioms and I find taking this in a similar spirit to make it make a lot more sense.
(helps I was a pure maths grad once, mind, my metaphor may be utterly useless to anybody who isn't)
Is the author claiming you cannot write a reader macro for postfix code? Am I understanding that correctly?
I don't personally understand how the authors readtable system is much different from Lisp (or even some Forth macro systems? Although I only touched the surface of those).
a a * b b * + sqrt
and in fact the process of entering a calculation can be informative, since you are thinking about the sequence of operations more. Writing infix requires either looking ahead to figure out when to add parentheses, or backing up and adding them after the fact. But I still have to simulate bits and pieces in my head when reading postfix.> Let's take a look at what the bootstrapping code for a very minimal syntax looks like: > > ldfgldftgldfdtgl > df > > dfiff1 crank f
However, the example in "3. Baremetal Cognition" is explained in an overly convoluted way, with many choices that IMO detracts from the point that (I think) you're trying to make. There's typos that makes it even harder to understand.
1. Use something like underscore instead of spaces and, maybe even another character like period instead of newline. You can explain after the section that you could have used space and newline instead of _ and .
2. Immediately after showing
ldfgldftgldfdtgl
df_
_
dfiff1_crank_f
you can parse it out for the reader, as something like "l" 'set-non-delim eval
"gl" 'set-non-delim eval
"tgl" 'set-non-delim eval
"dtgl"
"\n" 'set-non-delim eval
"_\n"
"_\n" 'set-non-delim eval
'set-ignore eval
eval
and so on. Or maybe even (set-non-delim "l")
(set-non-delim "gl")
(set-non-delim "tgl")
(set-non-delim "dtgl")
(set-non-delim "_\n")
(set-ignore "_\n")
(dtgl)
and only then you'd go through the source, character by character. Just because the source is hard to read by humans, doesn't mean we need to stick to it in an explanatory example.3. > Delimiters have an interesting rule, and that is that the delimiter character is excluded from the tokenized word unless we have not ignored a character in the tokenization loop, in which case we collect the character as a part of the current token and keep going.
There are four "negations" in this sentence: "excluded", "unless", "not", "ignored" and two turn to explain something ostensible simple: when to end tokens added to the stack (or container). This together with whitelist, blacklist, delim, singlet needs a much cleaner naming and description.
Also set non-delimiter is an extra negation.
4. There's an error right after "Now, for the rest of the code: ". The third line contains two spaces instead of a single one. (Using suggestion 1 would have also avoided this for yourself.)
# Comment about the actual content
5. I can kind of see the rationale for this (which is also explained in the beginning). However, I don't see exactly where we'd set clear boundaries since we can alwasy stuff semantics into the initial parser. For example, instead of have `f` bound to eval, we could have set `f` to execute the entire bootstrapping sequence and then rebind `f` to eval. So the entire example would be reduced to just `f`.
I guess we'd have to argue about the initial set of functions we are allowed to are somehow primitive enough. But even `d` (set-non-delim) while it only toggles some values in an array (or list) piggybacks on the parsers inherent ability to skip characters in its semantics and `i` (set-ignore) needs inversion implemented in the parser.
6. Here we assume that one byte per character is the default starting state of the world but unicode and other encodings don't have this so you'd need some parser to be get started anyways. And in that case, is an initial parser using space and end of line as separators really unusual?
7. I don't see why (not) reading ahead would such an important property for modifiable syntax. You just need to not really ahead too much, like the entire rest of the file or stream.
8. Regarless, I think this is worth exploring but also keep in mind some of these questions while doing that.
Lisp programmers claim that
You already know you're in for a fun ride lolCountry: United States State: Ohio City: Cincinnati Explanation: This photo was taken in the basement of the Cincinnati Museum Center at Union Terminal. The yellow wallpaper and carpeting are distinctive features of this space. Coordinates: 39.1031° N, 84.5120° W