guitarvydas
12/06/2022, 9:30 PMIF
and IFX
were both parsed as the beginning of an IF
statement. Later, it was discovered that making spaces “special” would help in making parsers and would help in cleaning up silliness like IF
and IFX
. At the time, the character set consisted of ASCII (well, there was EBCDIC, championed by IBM, but, IBM was hated even more than Microsoft and Apple are hated today, so EBCDIC was mostly avoided by non-IBMers). The fact that ASCII only has 128 characters to choose from (some 32 “unprintables” must be subtracted from this count) made for silly decisions like denoting strings with the same beginning and ending quote (which makes parsing more difficult) and not-allowing spaces to be embedded in names. With Unicode, we have many more choices, but, we remain stuck with decisions made to appease 1950s hardware. Aside: in 2022, we have hardware that can handle vector graphics and overlapping graphical elements, e.g. windows and very-small windows (“buttons”, “widgets”), but, we are stuck with decisions made to appease 1950s hardware. I argue that we should be building languages based on vector graphics instead of non-overlapping characters. SVG is a simple example of something that might work on this front (rectangles, ellipses, lines, text, groups). Aside: “declaration before use” is a result of 1950s thinking (save CPU time by making compilers 1-pass), even though, in 2022, we could easily burn CPU cycles to figure out “declaration after use”. Aside: declaration-checking (before or after use) is only a helper for developers. The machine doesn’t care if you make a typo. “Declaration-checking” is an app to help developers stamp out simple errors (like typos). Demanding that programmers rearrange their code so that the declarations ALL come before the code is compiler-appeasement (based on 1950s hardware).
The best way to write a type checker is to use a Relational Language (like PROLOG, miniKanren, Datalog, etc., etc.). Relational languages are shining examples of languages that don’t appease compilers. In a relational language, you write relations (“truth”) and let the underlying system figure out how to implement the machinery for matching up the relations. Other technologies that bark up this same tree: declarative languages and ML. (Aside: oh my, HTML is a declarative language. But, HTML needs to lean on JavaScript to allow imperative break-outs).
There is no “ideal language”. The notation you use depends on the problem you are trying to solve. A simple example would be the idea of Spreadsheets vs. Lambda Calculus. Accountants and financial analysts like Spreadsheets. Programming rigor analysts like Lambda Calculus. Accountants would not want to use Lambda Calculus and rigor-ists would not want to use Spreadsheets. Another example, closer to my heart, is the difference between using Language Theory to generate parsers and using PEG to generate parsers. Language Theory-based parsers cannot do what PEG-based parsers can do (for example, parse balanced parentheses). Trying to force-fit language theory onto parsing has stagnated the field. Most languages look the same, with minor differences. (Aside: PEG is Parser Theory, not Language Theory, despite the superficial similarities in syntax). The fact that parsing is “difficult” has restricted programmers to using only a small number of programming languages, instead of using a zillion nano-languages and defining their own nano-languages (I call these SCNs (Solution Centric Notations)).
“Dynamic” languages are “good” for fast turnaround on ideas, but are “bad” for producing end-user apps which are cost-optimized. “Static languages” are “good” for Production Engineering apps, but, are “bad” for inventing new products. Trying to force-fit all use-cases into one language results in a watered-down notation which isn’t particularly good for either use-case. (Aside: at the moment, efforts to force-fit all use-cases into one language favour the Production Engineering side over the Design side of things, and, this is what I call “compiler appeasement”. When programmers have to stop and rearrange their inventions to help the compiler figure out how to optimize, they are appeasing the compiler). (Aside: if Physicists ALL engaged in worshipping functional notation, we wouldn’t have Feynman Diagrams, nor Polyani’s “Order Out of Chaos”, etc.).
Barnacles might be invented for helping developers, e.g. type checkers and linters. Twisting a language design to appease only pre-compilation is not OK in my book. At the moment, most of our programming languages are compiler-appeasement languages and insist that developers waste time (and imagination) on dealing with compiler-appeasement and pre-compilation issues, long before the program works.
Barnacle-like pre-compilation was researched in the mid-1900s with work like Fraser/Davidson peephole technologies. This was called RTL and formed the basis of gcc. Cordy’s Orthogonal Code Generator is a generalization of this technique replete with declarative syntax for portability choice-trees (MISTs) and Data Descriptors and Condition Descriptors that improve on the virtual registers used by RTL.
[This essay can be found in https://github.com/guitarvydas/py0d/issues/2]Konrad Hinsen
12/07/2022, 7:17 AMKartik Agaram
Nicholas Yang
12/09/2022, 2:34 AMguitarvydas
12/09/2022, 2:01 PMhttps://raw.githubusercontent.com/guitarvydas/drawware/dev/sourcecodehelloworld.png▾
<html>
<body>
<h1>My first SVG</h1>
<svg>
<g id='myfunc'>
<rect x="20" y="0" width="280" height="130" rx="19.5" ry="19.5" fill="none" stroke="black"/>
<text x="120" y="19">myfunc</text>
<g>
<rect x="60" y="40" width="200" height="60" fill="#f8cecc" stroke="#b85450"/>
<text x="70" y="64">print ('Hello ', end='')</text>
<text x="70" y="84">print ('World')</text>
</g>
</g>
</svg>
</body>
</html>
the Ohm-JS grammar that I used is:
CodeDrawing {
Main = "<html>" "<body>" H1 Drawing "</body>" "</html>"
H1 = "<h1>" stuff "</h1>"
Drawing = "<svg" stuff ">" CodeContainer "</svg>"
CodeContainer = "<g" FunctionName ">" Boundary Title CodeBlock "</g>"
Boundary = "<rect" stuff "/>"
Title = "<text" stuff ">" name "</text>"
CodeBlock = "<g>" RedRect Text+ "</g>"
RedRect = "<rect" (~AttrRed any)* AttrRed stuff "/>"
FunctionName = "id=" sq name sq
Text = "<text" stuff ">" stuff "</text>"
AttrRed = "fill=" dq "#f8cecc" dq
stuff = notElementChar+
notElementChar = ~"<" ~">" ~"/>" any
name = letter alnum*
sq = "'"
dq = "\""
}
And my personal notation (“Fab”) that completes the transpiler is:
CodeDrawing {
Main [khtml kbody H1 Drawing kbodyend khtmlend] = ‛«Drawing»'
H1 [kh1 stuff kh1end] = ‛«kh1»«stuff»«kh1end»'
Drawing [ksvg CodeContainer ksvgend] = ‛«CodeContainer»'
CodeContainer [kgroup FunctionName k Boundary Title CodeBlock kgroupend] = ‛def «FunctionName» ():«CodeBlock»
«FunctionName» ()'
Boundary [krect stuff kend] = ‛«krect»«stuff»«kend»'
Title [ktext stuff k name ktextend] = ‛«ktext»«stuff»«k»«name»«ktextend»'
CodeBlock [kgroup RedRect Texts+ kgroupend] = ‛\n(-«Texts»-)'
RedRect [krect cs* AttrRed stuff kend] = ‛«krect»«cs»«AttrRed»«stuff»«kend»'
FunctionName [kid sq1 name sq2] = ‛«name»'
Text [ktext stuff kend stuff2 ktextend] = ‛\n«stuff2»'
AttrRed [kfill dq kred dq2] = ‛«kfill»«dq»«kred»«dq2»'
stuff [cs+] = ‛«cs»'
notElementChar [c] = ‛«c»'
name [c1 cs*] = ‛«c1»«cs»'
sq [c] = ‛«c»'
dq [c] = ‛«c»'
}
The generated Python code (from the diagram) is:
def myfunc ():
print ('Hello ', end='')
print ('World')
myfunc ()
FYI - Fab transpiles to JavaScript code that can be used in conjunction with Ohm-JS. I got tired of writing JavaScript, so I built an SCN (nano-DSL) for myself.
I’ve chosen not to include the generated JavaScript code in this thread, but have pushed a working transpiler to the github listed above.
[pardon the cave-man HTML, but I don’t know enough about building web pages, and, clearly, need help]
31:50~ “In a ‘real’ Computer Science, the best languages of an era should serve as ’assembly code” for the next generation of expression.
Alan KayKonrad Hinsen
12/12/2022, 5:58 PM