2 ms·
The reason you don't need to parse text is very much because of homoiconicity. Homoiconicity = same representation It means that the way you represent code in
by didibus 6y ago
The reason you don't need to parse text is very much because of homoiconicity.
Homoiconicity = same representation
It means that the way you represent code in a language is the same way you represent some data-structure in that language. This applies both syntactically and semantically.
(+ 1 2)
This is the Lisp syntax for a list of three elements. Parenthesis denote a list, and each word inside it denote an element of that list. The above list has elements +, 1 and 2.
So the above code is the syntax for a list, and when you deserialize this (read in Lisp parlens), you get a list of three elements. This is the semantic part. Now you have a List object of three elements. You can now loop over this list, access elements in it, change the order of the elements, you can append or prepend more elements to it, remove elements, and whatever else you can do with a list data-structure.
Finally, it happens that code is represented this way as well. So syntactically if you want to add 1 and 2 together, you'd also write:
(+ 1 2)
And semantically, the interpreter/compiler will not take text as input, it will take a list of three elements as input, because code is assumed to be modeled as a list of elements. Not using some special CompilerList, but using the standard list data-structure you use for any other list.
Which means to execute code, you take text which models code using the syntax used to represent lists, and you parse/deserialize it (read it) into a list data-structure, and then you feed this list to the evaluator which will execute it as code.
Thus the textual representation for code and for a list is the same, and the in-memory representation of code and of a list is the same, and finally this list can be executed as code or simply processed as a list. This is homoiconicity.
- cout 6y agoI would love to see a language with exactly what you described, but with dictionaries instead of lists as the fundamental data structure.
- didibus 6y agoYa that'd be interesting. How do you imagine the representation and evaluation semantics working? Something like: {call: function, arg1: value1, argN: valueN} Instead of (function value1 valueN) So maybe you'd have: { do1: { call: defn, name: hello, args: {first: String, last: String}, ret: IO, impl: { call: print, msg: { call: concat, strings: ["Hello ", first, " ", last] } } }, do2: { call: hello, first: "John", second: "Doe" } } Where the number after "do" is the order in which things should execute, or maybe we can simplify it by using insertion order preserving maps... Looking at it, if people thought nested parens made for an eyesore, I'm not sure this would be any better received haha.
- didibus 6y agoReplying to myself here, I'm curious to try it if we used order insertion preserving maps. What if then we had: {function: {arg1: value, argN: value}} So we'd get a hello world as such: {defn: { name: hello, args: {first: String, last: String}, ret: IO, impl: {print: { msg: {concat: { strings: ["Hello ", first, " ", last]}}}}}, hello: {first: "John", second: "Doe"} }