Why is it that languages like this don't scale? It's not the first time I see a powerful language that got forgotten. Other examples include SmallTalk and Common Lisp (tiny community).
It is because some languages are "too powerful"? What does that say about our industry? That we're still not that advanced of a specie to be able to handle the full power of such languages?
I say that because it seems languages that are "dumbed down" seem to absolutely dominate our world (Python, Ruby, JS, etc.)
One thing I note is that all of the languages you name are very far from the machine. Also Forth is not close to the modern machine. Note that it only has two integer types and the larger one can be aligned either way you make sure it is not.
Forth was an excellent way to write a powerful and expressive programming language that could self-host with a bare minimum of assembly language "bare metal" programming.
The fridge-sized computer that Forth was originally developed on had double-digit kilobytes of memory (maybe 8192kwords, with 16-bit words) and clocked instructions through at a whopping 300kHz or so. The microcontroller that drives the Caps Lock LED on your keyboard is a hundred times faster with a hundred times the memory.
These days we do not need to squeeze editor, compiler, and target binary into such a tiny machine. If you're developing for a microcontroller you just use C on your "big" computer, which is unimaginably more powerful.
In the olden days of the 1990s I used a development system for embedded stuff that was written in and targetted Forth on a Z80 with a whopping 64kB of RAM and 5.25" floppies, but that was at least ten years old and five years out of date at the time.
You're probably reading my words on a slice of glass the size of half a sandwich that contains more computing power than existed in the whole world when Forth was first written.
It's a shame because writing something like Forth from the ground up (and I mean, assembly code to load the registers to start the ACIA to begin transmitting text to the terminal) perhaps in an emulated early 80s home computer is a great way to get a sense of what the chip behind it all is doing, and I feel that makes you a better programmer in "real" languages like Go or Python or C.
I think it's a simple abstraction situation and the move for programming environments that include everything.
Geordi Laforge doesn't code much on the Enterprise. He simply asks the computer to build him a model of the anomaly so he can test out ideas. In a way, modern languages like Python (even before LLMs) let you get a lot closer to that reality. Sure you had to know some language basics, but this was pretty minimal and you'd use those basic building blocks to glue together libraries to make an application. Python has a good library for practically anything I do and since this is standard, it's expected that a task doesn't take too long. I can't tell my boss I'll need 3 years to code my own solution that uses my own libraries for numpy and scipy. You're expected to glue libraries together. This is why MIT moved SICP from scheme to Python. It's a different world.
With Forth, every program is a work of art that encapsulates an entire solution to a problem from scratch. It's creator chuck moore takes this to such a level that he also fabs his own chips to work with his forth software optimally. These languages had libraries, but they weren't easy to share and didn't have any kind of repository before Perl's CPAN. Perl really took off for awhile, but Python won out by having a simpler language with builtin OO (Perl's approach was a really hacky builtin OO or you download a library...).
To be honest though, I spent a decade trying many languages (dozens including common lisp, Prolog, APL, C, Ada, Smalltalk, Perl, C#, C++, Tcl, Lua, Rust...etc) looking for the best and although I never became experts in those languages, I kept coming to the conclusion that for my particular set of needs, Python was the best I could find. I wasted a lot of time reading common lisp books and just found it much easier to get the same thing done in Python. Your mileage will vary if you're doing something like building a game engine. A lot of people are just doing process automation and stuff like that and languages like Python are just better than common lisp due to the environment and tooling benefits. Also, although Python isn't as conceptually beautiful as lisp, I found it much easier to learn. The syntax just really clicked for me and some people do prefer it.
I don't think there's a unifying reason why programming languages languish in obscurity; it's certainly not because they're "too powerful." What does "powerful" even mean? I used to care more about comparing programming languages, but I mostly don't these days. Actually used/useful languages mostly just got lucky: C was how you wrote code for Unix; Python was Perl but less funny-looking; Ruby was Rails; JavaScript is your only choice in a web browser; Lisp had its heyday in the age of symbolic AI.
Forth and (R4RS) Scheme are simple to implement, so they're fun toys. Some other languages like Haskell have interesting ideas but don't excel at solving any particular problems. Both toy and general-purpose programming languages are plentiful.
I've concluded that Forth isn't as powerful as Lisp because it can't do lists or heaps. STOIC addresses these and other limitations. Unfortunately it's got the least search friendly language name ever.
Many people glorify the simplicity of Lisp as an interpreter, but Forth is similar and underappreciated. Sadly, the only code I've written in Forth is... PostScript. Yeah, PostScript is a dialect of Forth. As a child, I really was amused by the demo of GraFORTH on Apple ][, which included 3D wireframe animations, which at the time were magical.
The difference between Forth and Lisp could not be more pronounced. Forth source code has entirely implicit structure, you can't even tell which function is called on which arguments. Lisp has entirely explicit structure which makes it much easier to read and edit. Lisp needs only a single primitive (lambda) to create the entire programming language, whereas Forth needs many primitives which break the core idea of the language in order to be usable. All of what is elegant about Lisp is ultimately lacking in Forth.
I had a copy of that as well - I forget whether it was a Christmas gift or if I bought it. The demos were neat, but I was lacking in ideas when I had time to play with it, and the Apple didn't go to college with me.
But if I were going to do some "from the ground up, using first principles, with nobody else's libraries" embedded work, Forth would certainly be something I'd consider.
If you like Forth, but find it challenging to build real stuff with, Factor (https://factorcode.org/) is most or all of the good stuff about Forth designed in a way that's much easier to do things with. It was designed by Slava Pestov (who I think had a big hand in Swift), and honestly it's a lot of fun to build webapps and other programs with, and much less brutal to read than Forth can be.
I have very fond memories of programming in PostScript within NeWS/HyperNeWS - it did quite a few things that I've never seen in any other environment.
Edit: To be fair relying on PostScript probably did limit the appeal, but I actually really liked it.
> The Factor UI is a GUI toolkit together with a set of developer tools, written entirely in Factor, implemented on top of a combination of OpenGL and native platform APIs: X11, Win32 and Cocoa.
> UI gadgets are rendered using the cross-platform OpenGL API, while native platform APIs are used to create windows and receive events. The platform bindings can be also used independently; X11 binding has also been used in a Factor window manager, Factory, which is no longer maintained. The Cocoa binding is used directly by the webkit-demo vocabulary in Factor.
Fascinating. Probably dead and no mention of Wayland, but fascinating.
Forth has been a peripheral fascination of mine for about a decade, just because it seems to do well at nearly every level of the software stack. Like a part of me wants to build a kernel with it, or make a web server, or anything in between.
I've never actually done any Forth, though, just because it's a bit arcane compared to the C-inspired stuff that took over.
I wish "Simple Made Easy," by Rich Hickey, could be applied here. Forth is simple but not easy. If there is something as simple as Forth but also accessible to mere mortals (aka easy) then I'd like to know what it is (I don't consider Clojure itself as a language to be simple in this sense).
Back in 2004 or so - ancient days now - I remember an elderly programmer on
#gobolinux (freenode IRC back in the days) who kept on praising Forth. I never
understood why, but he liked Forth a lot.
Now - that in itself doesn't mean a whole lot, as it is just anecdotal, but people
who are very passionate about programming languages are quite rare. I've not seen
something like that happen with any other language (excluding also another guy on
#gobolinux who liked Haskell). I did not see anyone praise, say, PHP, perl, JavaScript etc....
Some languages people don't like to talk about much. Forth though was different in
that regard. I never got into it; I feel it has outlived the modern era like many
other languages, but that guy who kept on talking about it I still remember. His
website also was built in Forth and it was oddly enough kind of an "interactive"
website (perhaps he also used JavaScript, I forgot, but I seem to remember he
said most or all of it was implemented in Forth - turtles all down the way).
I've had a soft spot for Forth and am toying with a silly Forth-like interpreter for web programming ... if not for actual use, at least for some fun time. One concept it adds is the notion of a "current selection" which can define the available vocabulary to use and is used to select and work with DOM elements. Just experimenting.
Edit: As a kid, I disliked BASIC as a language though it let me do fun stuff. So I made an interpreter in BASIC for a language I'd like and it turned out Forth-like (and I didn't know about Forth at that time). I guess I'm still that kid some 35 years later.
it mentions sometimes not naming things as great, but... what does naming intermediate values in forth look like? Is there even a naming scope that would allow for me to give values names in case I don't want to get entirely lost in the sauce?
I used to be a fan of these languages like Lisp and Forth and Joy (and Factor and Haskell), but then I found that what I a really long for is just (untyped) lambda calculus (as a universal language). (Combinatory logic is just a similar representation of lambda calculus, but the differences go away quickly once you start abstracting stuff.)
I think expressing semantics of all (common) programming languages in lambda calculus would give us a solid foundation for automated program translation. And we should aim for that, the babel tower of languages doesn't really help anyone.
The current issue I have is with type theory. So I am trying to embed notion of types directly into the lambda terms, so they would sort of "automatically typecheck" when composed. The crucial in this, in my opinion, are lambda terms that do not use lambda abstraction in their body, because you can think of these terms as a kind of mini-DSLs that have yet to be interpreted.
Anyway, once we can translate calculus of constructions (and other common formal logics) into untyped lambda calculus, it will also help us doing automated theorem proving. It must be theoretically possible, but to my knowledge nobody has really done this sort of hardcore formalization.
I implemented the Calculus of Constructions in untyped lambda calculus in order to shorten the 643 byte C program computing Loader's Number to 1850 bits (under 232 bytes) [1], as one of the milestones reached by my functional busy beaver function [2].
Grounding programming languages in mathematics like this is essentially the goal of Strachey and Scott's denotational semantics, which has been very influential in programming language theory:
It's a real cool idea to compile everything down to lambda calculus and then you solve all semantics issues. (If something fits) you can convert 1:1, use general libraries in one language in others without loss etc. Ah, what a beautiful world it could be!
FORTH has some elegance and it's so simple that it is tempting to implement it.
However, no language should permit defining the value of 4 by 12, as there is no situation in which this can bring more good than harm in the long term.
Another issue that affects FORTH but also Perl and other languages is that they deal with a lot of things implicitly (e.g. the stack, or arguments to functions). Most people agree that explicity is more easy to read than implicit.
RPN interpreters require very little core memory. So they were popular with computers where core memory was under ten kilobytes.
But its horrible for software engineering with multiple programmers and large codebases. Lacks structures, interfaces, modules, data abstraction that you expect in a modern language. We called it the "Chinese food" of coding- ten minutes later you had nomidea what you just coded.
"Working without names (also known as implicit or tacit or point-free programming) is sometimes a more natural and less irritating way to compute. Getting rid of names can also lead to much more concise code. And less code is good code."
Does Forth really reduce the burden of naming things? You don't name results but don't
you have to pay for it with the burden of naming words? (My impression is that there's more words in a Forth program than functions in an equivalent program in a language that has named variables).
In my first proper job as a software engineer I wrote a bunch of Forth for "fruit machines". I don't know what the US equivalent would be but they are low stakes gambling machines which are quite common in UK pubs. The core processor was a 6809 and Forth was chosen because the interpreter was super small and easy to implement. I really appreciated the quick interactive way you could update and tweak code as you tested it. I did get slightly weary of having to keep the state of the stack in your head as you DUP and SWAP stuff around but that was probably due to my inexperience and not decomposing things enough.
They continued to use Forth as the basis for their 68000 based video gaming machines although when it came to the hand classifier for video poker we ended up using C - mostly because we wanted to run a lot of simulations on one of these new fangled "Pentium" processors to make sure we got the prize distribution right to meet the target repayment rate of ~98%.
There's a certain mesmerizing effect that creeps in once you start digging into programming language fundamentals.
Any kind of notation, really, can do that to a person. It's kind of hypnotic.
I avoid it like the plague (getting too much into it). Not because I dislike it, but because I like it so much.
I believe the ideal programming language must be full of problems, and then obvious ways to get around those problems. It's better than a near-perfect language with one or two problems that are very hard to get around.
The "Stop Writing Dead Programs" video mentioned is quite nice. It's surprising how the web is a platform for many of the languages the presenter offer as inspiration.
I was captivated by the August 1980 issue of Byte magazine, which had a cover dedicated to Forth. It was supposed to be easy to implement, and I imagined I might do that with my new KIM-1 6502 board. Alas, the KIM-1 was lost when I went to college, and life forced me down different pathways for the next 45 years.
About a year ago I finally began to work on my dream of a Forth implementation by building a Forth-based flight management computer into a spaceflight simulation game that I am working on. Now, instead of writing mostly C# or GDscript code in Godot, I am trying to figure out ways to create a useful device using this awkwardly elegant language. I'm having fun with it.
One of the interesting bits is that I have been able to make the Forth code an entirely separate project on Github (https://github.com/Eccentric-Anomalies/Sky-Dart-FMS), with a permissive open-source license. If anyone actually built a real spacecraft like the one in my game, they could use the FMS code in a real computer to run it.
There is one part of the linked article that really speaks to me: "Implement a Forth to understand how it works" and "But be aware of what this will not teach you". Figuring out the implementation just from reading books was a fascinating puzzle. Once I got it running, I realized I had zero experience actually writing Forth code. I am enjoying it, but it is a lot like writing in some weird, abstract assembly language.
I spent a few months playing with forth after seeing a talk on it at Boston Code Camp. I struggled to find a practical application (I do web dev), but it had a lasting effect on my style of programming. Something about the way you factor a forth program changed me. Now I mainly do functional-flavored typescript, and while forth is NOT an FP language, there is a lot that carries over.
In Forth, the language rewards you for keeping your words focused and applying the single responsibility principal. It’s very easy to write a lot of small words that do one thing and then compose your program out of them. It’s painful to not do this.
There is no state outside the stack. If you call a word it pulls values off the stack and deposits values back on the stack. Having no other mechanism for transferring data requires you to basically create data pipelines that start to look like spoken language.
I first encountered Forth on a TI-99/4A, complete with that magnificent expansion box that looked like industrial HVAC equipment. Hearing me complain about TI Extended BASIC's glacial pace, my parents saw in one of my magazines that Forth was faster and bought it hoping I would find it helpful.
It was mind-bending but fascinating. I managed a few text adventures, some vaguely Pac-Man-esque clones, and a lingering sense that I was speaking a language from another dimension.
I've since forgiven my parents. Forth resurfaces now and then, usually when I reread Leo Brodie's thought-provoking Forth books, and I feel like I'm decoding the sacred texts of a minimalist cult. I came away thinking better, even if I've never completely caught up with the language.
The Forth super power is that you have full control over how a symbol is evaluated, both at compile and runtime. I don't know of anything else that offers that. Lisp doesn't.
That gives the developer pretty much free rein to do whatever they want, which can be both good and bad.
I've always loved the elegance of Frank Sergeant's 3 Instruction Forth paper [1], it's very cool once you wrap your head around it.
Also, studying the F83 Metacompiler is valuable as well. F83 is a very capable 8/16-bit Forth system.
I honestly marvel at how much work must have gone into F83, given the tools of the time. I wish I knew more about its development journey. How it got bootstrapped.
Stepping away from Forth in particular, one of the benefits of a stack-based / concatenative language is that it's easy to implement on constrained hardware. uxn [1] is a great example of that.
And shameless self-promotion, if you're interested in how these kinds of languages compare with more traditional named-based languages, with more theoretical constructs like the lambda calculus and combinatory logic, and with gadgets like a PyBadge — well you're in luck! I gave a talk about exactly that at the final Strange Loop [2].
52 comments
[ 3.7 ms ] story [ 74.9 ms ] threadIt is because some languages are "too powerful"? What does that say about our industry? That we're still not that advanced of a specie to be able to handle the full power of such languages?
I say that because it seems languages that are "dumbed down" seem to absolutely dominate our world (Python, Ruby, JS, etc.)
Forth was an excellent way to write a powerful and expressive programming language that could self-host with a bare minimum of assembly language "bare metal" programming.
The fridge-sized computer that Forth was originally developed on had double-digit kilobytes of memory (maybe 8192kwords, with 16-bit words) and clocked instructions through at a whopping 300kHz or so. The microcontroller that drives the Caps Lock LED on your keyboard is a hundred times faster with a hundred times the memory.
These days we do not need to squeeze editor, compiler, and target binary into such a tiny machine. If you're developing for a microcontroller you just use C on your "big" computer, which is unimaginably more powerful.
In the olden days of the 1990s I used a development system for embedded stuff that was written in and targetted Forth on a Z80 with a whopping 64kB of RAM and 5.25" floppies, but that was at least ten years old and five years out of date at the time.
You're probably reading my words on a slice of glass the size of half a sandwich that contains more computing power than existed in the whole world when Forth was first written.
It's a shame because writing something like Forth from the ground up (and I mean, assembly code to load the registers to start the ACIA to begin transmitting text to the terminal) perhaps in an emulated early 80s home computer is a great way to get a sense of what the chip behind it all is doing, and I feel that makes you a better programmer in "real" languages like Go or Python or C.
Stanislav Datskovskiy addressed this rather well:
https://www.loper-os.org/?p=69
Geordi Laforge doesn't code much on the Enterprise. He simply asks the computer to build him a model of the anomaly so he can test out ideas. In a way, modern languages like Python (even before LLMs) let you get a lot closer to that reality. Sure you had to know some language basics, but this was pretty minimal and you'd use those basic building blocks to glue together libraries to make an application. Python has a good library for practically anything I do and since this is standard, it's expected that a task doesn't take too long. I can't tell my boss I'll need 3 years to code my own solution that uses my own libraries for numpy and scipy. You're expected to glue libraries together. This is why MIT moved SICP from scheme to Python. It's a different world.
With Forth, every program is a work of art that encapsulates an entire solution to a problem from scratch. It's creator chuck moore takes this to such a level that he also fabs his own chips to work with his forth software optimally. These languages had libraries, but they weren't easy to share and didn't have any kind of repository before Perl's CPAN. Perl really took off for awhile, but Python won out by having a simpler language with builtin OO (Perl's approach was a really hacky builtin OO or you download a library...).
To be honest though, I spent a decade trying many languages (dozens including common lisp, Prolog, APL, C, Ada, Smalltalk, Perl, C#, C++, Tcl, Lua, Rust...etc) looking for the best and although I never became experts in those languages, I kept coming to the conclusion that for my particular set of needs, Python was the best I could find. I wasted a lot of time reading common lisp books and just found it much easier to get the same thing done in Python. Your mileage will vary if you're doing something like building a game engine. A lot of people are just doing process automation and stuff like that and languages like Python are just better than common lisp due to the environment and tooling benefits. Also, although Python isn't as conceptually beautiful as lisp, I found it much easier to learn. The syntax just really clicked for me and some people do prefer it.
Forth and (R4RS) Scheme are simple to implement, so they're fun toys. Some other languages like Haskell have interesting ideas but don't excel at solving any particular problems. Both toy and general-purpose programming languages are plentiful.
I've concluded that Forth isn't as powerful as Lisp because it can't do lists or heaps. STOIC addresses these and other limitations. Unfortunately it's got the least search friendly language name ever.
But if I were going to do some "from the ground up, using first principles, with nobody else's libraries" embedded work, Forth would certainly be something I'd consider.
My understanding is they were developed independently.
(I wish you would write again. I have immensely enjoyed the stuff on your website)
Edit: To be fair relying on PostScript probably did limit the appeal, but I actually really liked it.
https://concatenative.org/wiki/view/Factor/UI
> The Factor UI is a GUI toolkit together with a set of developer tools, written entirely in Factor, implemented on top of a combination of OpenGL and native platform APIs: X11, Win32 and Cocoa.
> UI gadgets are rendered using the cross-platform OpenGL API, while native platform APIs are used to create windows and receive events. The platform bindings can be also used independently; X11 binding has also been used in a Factor window manager, Factory, which is no longer maintained. The Cocoa binding is used directly by the webkit-demo vocabulary in Factor.
Fascinating. Probably dead and no mention of Wayland, but fascinating.
I've never actually done any Forth, though, just because it's a bit arcane compared to the C-inspired stuff that took over.
Now - that in itself doesn't mean a whole lot, as it is just anecdotal, but people who are very passionate about programming languages are quite rare. I've not seen something like that happen with any other language (excluding also another guy on #gobolinux who liked Haskell). I did not see anyone praise, say, PHP, perl, JavaScript etc....
Some languages people don't like to talk about much. Forth though was different in that regard. I never got into it; I feel it has outlived the modern era like many other languages, but that guy who kept on talking about it I still remember. His website also was built in Forth and it was oddly enough kind of an "interactive" website (perhaps he also used JavaScript, I forgot, but I seem to remember he said most or all of it was implemented in Forth - turtles all down the way).
https://github.com/srikumarks/pjs
Edit: As a kid, I disliked BASIC as a language though it let me do fun stuff. So I made an interpreter in BASIC for a language I'd like and it turned out Forth-like (and I didn't know about Forth at that time). I guess I'm still that kid some 35 years later.
I think expressing semantics of all (common) programming languages in lambda calculus would give us a solid foundation for automated program translation. And we should aim for that, the babel tower of languages doesn't really help anyone.
The current issue I have is with type theory. So I am trying to embed notion of types directly into the lambda terms, so they would sort of "automatically typecheck" when composed. The crucial in this, in my opinion, are lambda terms that do not use lambda abstraction in their body, because you can think of these terms as a kind of mini-DSLs that have yet to be interpreted.
Anyway, once we can translate calculus of constructions (and other common formal logics) into untyped lambda calculus, it will also help us doing automated theorem proving. It must be theoretically possible, but to my knowledge nobody has really done this sort of hardcore formalization.
[1] https://codegolf.stackexchange.com/questions/176966/golf-a-n...
[2] https://oeis.org/A333479
What exactly do you mean with this? That the amount of programming languages available isn't actually helpful, it's detrimental?
http://www.ultratechnology.com/antiansi.htm
https://en.wikipedia.org/wiki/Denotational_semantics
However, no language should permit defining the value of 4 by 12, as there is no situation in which this can bring more good than harm in the long term.
Another issue that affects FORTH but also Perl and other languages is that they deal with a lot of things implicitly (e.g. the stack, or arguments to functions). Most people agree that explicity is more easy to read than implicit.
But its horrible for software engineering with multiple programmers and large codebases. Lacks structures, interfaces, modules, data abstraction that you expect in a modern language. We called it the "Chinese food" of coding- ten minutes later you had nomidea what you just coded.
Does Forth really reduce the burden of naming things? You don't name results but don't you have to pay for it with the burden of naming words? (My impression is that there's more words in a Forth program than functions in an equivalent program in a language that has named variables).
They continued to use Forth as the basis for their 68000 based video gaming machines although when it came to the hand classifier for video poker we ended up using C - mostly because we wanted to run a lot of simulations on one of these new fangled "Pentium" processors to make sure we got the prize distribution right to meet the target repayment rate of ~98%.
Any kind of notation, really, can do that to a person. It's kind of hypnotic.
I avoid it like the plague (getting too much into it). Not because I dislike it, but because I like it so much.
I believe the ideal programming language must be full of problems, and then obvious ways to get around those problems. It's better than a near-perfect language with one or two problems that are very hard to get around.
The "Stop Writing Dead Programs" video mentioned is quite nice. It's surprising how the web is a platform for many of the languages the presenter offer as inspiration.
About a year ago I finally began to work on my dream of a Forth implementation by building a Forth-based flight management computer into a spaceflight simulation game that I am working on. Now, instead of writing mostly C# or GDscript code in Godot, I am trying to figure out ways to create a useful device using this awkwardly elegant language. I'm having fun with it.
One of the interesting bits is that I have been able to make the Forth code an entirely separate project on Github (https://github.com/Eccentric-Anomalies/Sky-Dart-FMS), with a permissive open-source license. If anyone actually built a real spacecraft like the one in my game, they could use the FMS code in a real computer to run it.
There is one part of the linked article that really speaks to me: "Implement a Forth to understand how it works" and "But be aware of what this will not teach you". Figuring out the implementation just from reading books was a fascinating puzzle. Once I got it running, I realized I had zero experience actually writing Forth code. I am enjoying it, but it is a lot like writing in some weird, abstract assembly language.
In Forth, the language rewards you for keeping your words focused and applying the single responsibility principal. It’s very easy to write a lot of small words that do one thing and then compose your program out of them. It’s painful to not do this.
There is no state outside the stack. If you call a word it pulls values off the stack and deposits values back on the stack. Having no other mechanism for transferring data requires you to basically create data pipelines that start to look like spoken language.
It was mind-bending but fascinating. I managed a few text adventures, some vaguely Pac-Man-esque clones, and a lingering sense that I was speaking a language from another dimension.
I've since forgiven my parents. Forth resurfaces now and then, usually when I reread Leo Brodie's thought-provoking Forth books, and I feel like I'm decoding the sacred texts of a minimalist cult. I came away thinking better, even if I've never completely caught up with the language.
That gives the developer pretty much free rein to do whatever they want, which can be both good and bad.
I've always loved the elegance of Frank Sergeant's 3 Instruction Forth paper [1], it's very cool once you wrap your head around it.
Also, studying the F83 Metacompiler is valuable as well. F83 is a very capable 8/16-bit Forth system.
I honestly marvel at how much work must have gone into F83, given the tools of the time. I wish I knew more about its development journey. How it got bootstrapped.
[1] https://pygmy.utoh.org/3ins4th.html
And shameless self-promotion, if you're interested in how these kinds of languages compare with more traditional named-based languages, with more theoretical constructs like the lambda calculus and combinatory logic, and with gadgets like a PyBadge — well you're in luck! I gave a talk about exactly that at the final Strange Loop [2].
[1] https://100r.co/site/uxn.html
[2] https://dcreager.net/talks/concatenative-languages/