Rendered at 11:44:17 GMT+0000 (Coordinated Universal Time) with Cloudflare Workers.
SA9G 13 hours ago [-]
My first language, 1980 in CMU, was Pascal... quickly followed by LISP in CS/AI courses and C for EE courses. I was a big fan of MacLisp at the time, the MIT version that GLS worked on (could see his comments all over the sources). Of course GLS moved on to Scheme and wrote a few definitive papers on closures. Yeah, that was before PC's everywhere... a loooong time ago. (C++ came years and years afterwards, not a fan. I would have stayed with hardware if the ++ version of C was forced on me all those years ago.)
GLS moved to CMU in the early 80's... I remember taking "Comparative Programming Languages" from him. Good teacher and impressive guy. In addition to the obvious, he also covered SNOBOL and APL in that course. Memories :-)
#i is the prefix for inexact
#e is the prefix for exact
So `#e0.1` is exact 0.1 which means it will be read as an exact fraction 1/10
and `#i0.1` will be read as a floating point number.
The `i` in `8i` is the imaginary unit.
The `1@1` is the polar notation for complex numbers.
The `10#` is a compatibility remain (the Scheme authors wanted a way to see how many signifant digits were known. In `10#` there 2. So `#` stands for "some digit". In most implementations this is read as 0. More details at [1]
An `#` followed by a list datum is read as a vector.
Thus `#()` is an empty vector and `()` is an empty list.
Complicated? Well, to support both inexact (floating point) and exact numbers (bignums and fractions) it makes sense to have `#i` and `#e` to explicitl choose.
The default is (more or less): numbers with . are inexact the others are exact.
Syntonicles 15 hours ago [-]
At first I was frustrated by this comment, having a fair amount of Lisp experience failing to grok the examples. In less than one minute I was able to locate, download and install the latest Racket and was in a REPL. There really are no excuses.
This was a wild ride. I'm torn on whether this feels like the Reader is bloated/polluted or whether this is the coolest numerical parser I've ever used. You can really do a lot to coerce the these numbers just by inserting an {o,s,e,i,b,#} into the number, with different semantics depending on the position of the character.
Somewhat overwhelming, I can only hope there's some elegance underlying it all...
nilslindemann 15 hours ago [-]
Curious, how would look that in Python?
zelphirkalt 3 hours ago [-]
Would need some imports:
import cmath
from fractions import Fraction
And then have to write numbers as strings to input them. From their examples:
Not really great, but workable. I don't like having to import things for basic math stuff like exact numbers, but having a lot of special syntax is maybe also not that great. I am guessing except for maybe macros, there is no other way, if one wants to take input (code) literally as exact numbers in all cases. If one were to just write down a number like `1.414213562373`, and expect it to be exactly represented in the program, then it cannot be read as a floating point number first and then converted into an exact number internally, because reading it as floating point number could already lose precision. So this kind of logic to interpret exact numbers would have to live somewhere before that. So it is in the reader. I am not sure how one could employ a macro instead, and then maybe access the digits of a written number, or whether that is possible. I think it should be possible. If it is, then of course things could be made into macros, after which one could use something like:
I think you clearly exposed one of the things that I couldn't never describe why I wasn't dragged into Racket/scheme. It's not only annoying is hard to remember all these differences.
Obviously the more you use the language these go away but still at least to me it doesn't seem to be a coherent syntax.
jqpabc123 16 hours ago [-]
It looks more like a "program" for an HP15c pocket scientific calculator.
Not necessarily a bad thing but also not exactly what I would call "expressive".
You may be able to build anything you want --- which may be efficient when communicating with the machine. But I wonder about now well this would communicate with other programmers.
Joel_Mckay 3 hours ago [-]
I actually wrote an audio sequencer in HP RPL as a kid.
It was far less complex to code, and human readable. Unicon was pretty cool also, but never became popular. Erlang/Elixir will probably become more relevant as people move into massively parallel constraint solvers.
The monolith centric languages are simply no longer appropriate for many classes of problems. =3
jibal 16 hours ago [-]
It's not a program, it is (obviously) a totally unrealistic hodgepodge expression for a list of constant values that simply demonstrates the literal syntax for a variety of types of values (real numbers, dotted pairs, rational numbers, complex numbers, polar coordinates, etc. -- Racket is unusually expressive in the types of literals). Your comment demonstrates something typical of HN, and it's not a good thing. It's as if in a discussion about C someone posted, without explanation, an entry from the Obfuscated C contest and then someone else, making zero effort to understand what was posted, said that it looked like line noise and questioned whether C is conducive to communication between programmers.
zelphirkalt 2 hours ago [-]
I think in this case it is probably justified, as the claim of "no special syntax" is unfortunately not true. To convey the amount of special syntax, it got crammed into one brief example snippet.
Still, far less than most other programming languages, virtue of having parentheses making things unambiguous. Outliers are Smalltalk and maybe (?) Forth.
euduhdhbene 3 hours ago [-]
First time dealing with developers I see. I’m sorry.
I think the problem is that `read` / `write` support shared data constructed using `shared`. But programs (read by `read-syntax` are not allow to have cycles.
shawn_w 11 hours ago [-]
Yeah, there's a toggle for it in read-syntax mode.
It might take a custom #lang. I'll play around with it when I have some free time...
That read-syntax doesn't just accept everything accepted by plain read is one of my biggest annoyances with Racket.
M0THXYZ 10 hours ago [-]
Hiii, I'm Geometridae (Astrid Motilla)! A friend from the Racket community mentioned that my article appeared here. Thank you for reading it, and I'll make sure to take all this feedback and these different perspectives into account for this and future articles! :)
I’d also encourage you to give it a try and have some fun with it! I’m using it for some of the 3D demos in my book. It’s definitely not a silver bullet, but I’ve found it can be pretty productive.
Personally, my favorite Lisps are Racket, Common Lisp, and Clojure, in that order. I’ve also been tempted to give Chicken Scheme a try! :)
iainctduncan 6 hours ago [-]
If you like those, a less well knowned Scheme you will likely really like is s7. :-)
perrygeo 21 hours ago [-]
> In The Amazing Digital Circus (episode 8, "hjsakldfhl"), when Kinger opens the terminal to try to reset Caine, you can see that Caine (a creative AI built in 1996) is programmed in Lisp. The file is literally named Caine-core.lisp.
Nice touch. Explains how Caine returns in episode 9: Lisp continuations allow for graceful error recovery.
valorzard 19 hours ago [-]
wasn't Caine written in common lisp? Pretty sure they show that the debugger they used in the command line was gdb (which ... is that even actually possible?)
perrygeo 18 hours ago [-]
Yep, `/usr/bin/gdb /usr/local/bin/clisp 1337` ... also in TADC lore, windows has forward slashes.
GregBuchholz 17 hours ago [-]
Windows has allowed forward slashes for directory separators for a long time. Seems like maybe it started with DOS 2.0.
On a more personal note, for some weird reason, Racket ended up being the language that got me one of my most important contracts. Through a whole series of butterfly-effect events, that eventually led me into CAD software development, which is where I discovered my love for metamaterials. It’s funny how these things happen!
slim 3 hours ago [-]
because autocad is scripted in lisp ?
fn-mote 19 hours ago [-]
Much as I am a fan of Racket, this is not a friendly intro. It is a speedrun.
When an introduction says “friendly”, I don’t expect it to assume that I know what lambda is.
When an introduction says “friendly”, I don’t expect syntax rules to appear in it. At all.
allthetime 17 hours ago [-]
It is rich with information, to the point, and presented in a way that a motivated and competent reader can immediately know something about and be useful with racket. That’s how it was for me anyways; someone who didn’t know anything about racket before reading through this.
Wtf kind of intro to a programming language doesn’t include syntax rules? We are all informed, experienced, technologically inclined people here. Not dumb children.
I’m struggling to see your comment as anything more than contrarian babble.
sudahtigabulan 17 hours ago [-]
> Wtf kind of intro to a programming language doesn’t include syntax rules?
PP could have been more clear and say syntax-rules (note the dash), which means macros. Macros are usually considered an advanced topic.
wormius 16 hours ago [-]
Thanks for the clarification! It makes much more sense seeing the term "macro".
dented42 17 hours ago [-]
> Wtf kind of intro to a programming language doesn’t include syntax rules?
Given that most languages don’t have syntax rules or anything like it, I’m gonna go out on a limb and say that most language introductions/overviews/tutorials don’t mention it.
AnimalMuppet 16 hours ago [-]
Most? I question that.
In fact, what languages can you say do not have syntax rules?
dented42 14 hours ago [-]
C, python, java, Fortran, ruby, Common Lisp, Haskell, go, zig (I think), forth, swift, cobol, pretty much any language that doesn’t directly descent from Scheme.
aobdev 15 hours ago [-]
Python and Java do not have any similar constructs
jibal 15 hours ago [-]
syntax-rules refers specifically to Racket macros.
Since macros are a very important part of Racket, complaining that a friendly introduction mentions them is [insert non-friendly characterization].
phlakaton 17 hours ago [-]
When I see "friendly introduction," I don't expect to see a deadhead sticker front and center. But I guess if you're an actual Deadhead it's not that startling. ;-)
wormius 16 hours ago [-]
TBF, deadheads are pretty friendly (just stay away from the Nitrous Mafia) LOL.
y1n0 16 hours ago [-]
not to mention a skull? is it a racket thing (or lisp in general thing) to spoof the grateful dead logo?
dented42 14 hours ago [-]
It used to be the official logo. The project was called PLT Scheme at the time.
> Emacs Lisp — millions of people run Lisp every day without knowing it, because their editor is a Lisp interpreter.
Are there seriously any emacs users who are completely unaware of elisp? Isn't elisp the entire point of picking emacs?
BeetleB 10 hours ago [-]
Most Emacs users I personally know simply treat it as an editor. They're not really aware how it works under the hood.
zelphirkalt 2 hours ago [-]
Still doubt, that they are unaware of Elisp. Bare bones vanilla Emacs is maybe a bit much to get used to these days, so anyone wanting to configure their Emacs will have opened their init.el or so file and will have put some Elisp snippets there.
soegaard 14 hours ago [-]
Btw - if people are interested in Racket related blogs / articles etc.
While the language is interesting, sadly, nobody is using it in the wild. Maybe due to cumbersome deployment options? The ability to produce native standalone executables would boost its usage I believe.
zelphirkalt 2 hours ago [-]
It is not due to deployment options. People put all sorts of stuff in docker containers every day. It is rather that few people make an effort to learn a lisp, and fewer still who choose to learn Racket. The few universities teaching good computer programming basics using Racket don't really make a dent. You simply don't have coworkers who know this stuff. Are you going to be the one person making a decision at the company, to use something no one but you knows? Not gonna happen.
I have not had a single coworker, who has even started to learn these things, even after I have presented a Scheme on a Friday afternoon, and showed off some cool threading/pipeline syntax-rules macro, and showed how this compared to Python, showing how it reduces boilerplate in a way impossible to do in Python.
Granted, this is in Germany, where CS education is not really all that great, and most universities teach boring Java or C++ or something.
At least we had a RacketCon in Berlin some time ago, and I was fortunate enough to have a prof at university, who at least introduced Dr.Scheme. His motto was: "I am not here to teach you C, Java, or Python. I am here to teach you computer programming." (translated) He went on to introduce languages of various paradigms, from Prolog, to Dr.Scheme (predecessor of Racket), to C, and Python. Thank you Prof. von Löwis.
velcrovan 8 hours ago [-]
Not only do I produce standalone executables in Racket, I cross-compile GUI apps written on MacOS to produce executables for Windows.
throwaway27448 17 hours ago [-]
Racket has been able to produce standalone executables for a while now.
gus_massa 17 hours ago [-]
I agree. In 2020 we had to manipulate some Moodle files. I wrote the code in Racket and I sent the ".exe" file to my coworkers, that never knew they were using Racket.
Vedor 17 hours ago [-]
For years, really.
hyperbolablabla 1 hours ago [-]
Naughty Dog uses Racket for all their scripting...
dented42 14 hours ago [-]
Given that a lot of people use it in the wild I’m not sure where you’re getting that from.
mark_l_watson 12 hours ago [-]
I wrote my own AI coding harness in Racket, it works fine, meets my own needs. I did earlier versions in Common Lisp and Python but the Racket version is the most full featured.
Interesting article overall, although some gotchas on the introduction.
Misses out on LispWorks and Allegro Common Lisp for the Common Lisp entry, which contrary to SBCL provide a similar graphics experience as the Lisp machines of yore, here missing out on TI and Xerox as well, Genera wasn't alone.
em-bee 21 hours ago [-]
any time the topic of racket comes up, i wonder if there are any interesting apps i could explore. but all i find is libraries and dev tools: https://awesome-racket.com/
The co-creator of Scheme is also co-author of Structure and Interpretation of Computer Programs[0]. Namely, Gerald Jay Sussman[1], the Panasonic Professor of Electrical Engineering at the Massachusetts Institute of Technology (MIT).
In teaching our material we use a dialect of the programming language Lisp. We never formally teach the language, because we don’t have to. We just use it, and students pick it up in a few days. This is one great advantage of Lisp-like languages: They have very few ways of forming compound expressions, and almost no syntactic structure. All of the formal properties can be covered in an hour, like the rules of chess. After a short time we forget about syntactic details of the language (because there are none) and get on with the real issues—figuring out what we want to compute, how we will decompose problems into manageable parts, and how we will work on the parts. Another advantage of Lisp is that it supports (but does not enforce) more of the large-scale strategies for modular decomposition of programs than any other language we know. We can make procedural and data abstractions, we can use higher-order functions to capture common patterns of usage, we can model local state using assignment and data mutation, we can link parts of a program with streams and delayed evaluation, and we can easily implement embedded languages. All of this is embedded in an interactive environment with excellent support for incremental program design, construction, testing, and debugging. We thank all the generations of Lisp wizards, starting with John McCarthy, who have fashioned a fine tool of unprecedented power and elegance.
We used it in the course I had that introduced functional programming. The only memorable thing I can remember writing in it for that class was a topological sort (I believe).
infinitebit 9 hours ago [-]
The second recursion example introduces 2 syntax features without explaining them (let, square brackets)
> For decades, Lisp was the language of artificial intelligence. [...] Then came the "AI winter," funding dried up, and Lisp went from star to cult language.
Lisp had fallen from relevance before then. Only the United States was still using it, and mostly out of technical debt and a stubborn refusal to move on. Prolog displaced it in the late 1970s, and even within the US, the Lisp part was an unfortunate implementation detail to get to a Prolog-shaped object. It's not surprising that the US fell way behind Japan in this area in the 1980s. Anybody who would imply they would take a Lisp machine over a PIM is either not interested in symbolic computation and just likes Lisp, or they're doing so out of total ignorance of how much more advanced the PIMs were for symbolic AI.
The cutting edge was with Prolog, and that's still the case today. Nobody's researching MIL in Lisp, even in America.
so-cal-schemer 11 hours ago [-]
I've read a large factor was minicomputers and microcomputers running Unix in C became much more affordable, and when the Berlin Wall fell in 1989 DoD funding for powerful and expensive Lisp workstations quickly dried up. And the nascent free software Lisp offerings left a lot to be desired (to be developed).
This visualization of relative programming language popularity shows Lisp was the 3rd most popular general purpose language in Q1 of 1984 behind Pascal (a learning language?) and C.
(Prolog shows at 12th, then drops off the chart)
Most Popular Programming Languages: Data from 1958 to 2025
That's why nobody uses Lisp machines today, but Lisp is somewhat orthogonal. It's true that the death of the Lisp machine economy hurt Lisp more than the end of the FGCS hurt Prolog. BUT this was happening long before the winter hit.
> This visualization of relative programming language popularity shows Lisp was the 3rd most popular general purpose language
Which is fine, and makes sense. But I'm addressing a claim about Lisp being "the Language" for the era of symbolic AI. Which is decidedly not high volume, nor is it general at all, it's really quite specific.
I'm correcting it, because I know Americans are heavily culturally silo'd on this, and symbolic AI is especially esoteric. Most people probably can't name a single commercial expert system off the top of their head, and that's not unreasonable. Our cultural view of symbolic AI is rife with American exceptionalism (I theorize partially because of government involvement) that just doesn't track with reality. Speaking as an American.
pasc1878 6 hours ago [-]
Pascal in 1984 was not just a teaching language.
The ranking then was due to Turbo Pascal which came out in November 1983. It was probaly the first IDE and compiler on PCs
BoingBoomTschak 13 hours ago [-]
And then mini/microKanren put Prolog in its rightful place: that of a useful DSL instead of a poor general purpose language.
ux266478 9 hours ago [-]
miniKanren is a replacement for a Prolog like a shitty tree-walking sexpr interpreter that doesn't even have modules is a replacement for Racket. I don't even know what to say to you for suggesting that, frankly.
Anyways the embedded inference engine as an idea failed a long time ago, Americans convinced themselves it was the way to do things and just refused to ever let it go. It's just extra baggage on the important bit, which is the symbolic computation. miniKanren has a niche more in line with a theorem solver.
Side note, does anybody know of some good Rhombus codebases I can read?
zelphirkalt 4 minutes ago [-]
Fairly new, I think there will not be much Rhombus around yet.
vatsachak 19 hours ago [-]
I've never seen the appeal in schemes other than hot reloadability...
so-cal-schemer 15 hours ago [-]
Lisp/Scheme/Racket is a very simple language that is also very fluid and malleable. You can express ideas and computations very precisely, concisely, and intuitively. There really aren't any barriers as they (Scheme/Racket at least) are rooted in the Lambda Calculus which is a theoretical model equivalent to the Turing Machine. Any language feature you'd like can be expressed: Want standard infix math expressions or a borrow-checker? That's a macro. Want lazy evaluation? That's a simple change in a meta-circular evaluator. Want a language that is the simplest and most direct mapping to your problem domain? A DSL.
The syntax lends itself to easy structural editing way before LSPs..
The other powers of Lisps (interactive development, hot reloadability, restarts on error, etc) are more tied to the sophistication of their implementations and runtime environments.
vatsachak 7 hours ago [-]
But I can use custom DSLs using macros in Rust or template Haskell. In Lean 4 you can even add grammar to the Lean parser.
I feel like the good parts of lisps have been adopted by typed languages...
so-cal-schemer 6 hours ago [-]
Absolutely. You can thank Lisp for paving the way. And in a way, those languages are part of the extended family.
16 hours ago [-]
WalterGR 19 hours ago [-]
Homoiconicity.
chowells 18 hours ago [-]
What makes this a desirable feature? From the perspective where local reasoning is the most desirable property a language can have, how does homoiconicity support that?
I honestly am curious. I've seen a few examples presented for it, but they always seem like bad software engineering to me. Where's an example that does something in a cleaner way than alternatives present in other languages while remaining compatible with local reasoning?
gus_massa 17 hours ago [-]
Homoiconicity makes writing macros easy.
If you don't like it, you can try https://rhombus-lang.org/ that is build on Racket and also has macros but uses a Python-like syntax.
Zambyte 14 hours ago [-]
Easy is an understatement. Macros and dynamic programming (often done using runtime reflection in other languages) are so trivially easy in Lisps that one can stumble into it without realizing they're even doing it. Anyone who has done these things in more "modern" languages knows these features are not something one can accidentally start doing. They take a lot of deliberate effort relative to standard, static programming.
soegaard 14 hours ago [-]
> Easy is an understatement. Macros and dynamic programming (often done using runtime reflection in other languages) are so trivially easy in Lisps that one can stumble into it without realizing they're even doing it.
Well, getting the interaction between modules and syntax transformations (macros) right is not an easy task.
Is Prolog bicameral? Because it has a `read` predicate? Is bicameral then just a matter of implementing a `read` function which returns a tree of tokens, which you could implement for C or Python? Which makes bicamerality a property of a library rather than a property of the language?
WalterGR 17 hours ago [-]
> From the perspective where local reasoning is the most desirable property a language can have
That's a perspective. If you're looking for a low-level language, then Scheme isn't it. (Forget iconicity - Scheme is garbage-collected. And supports continuations!)
If you don't program in machine code - which would maximize local reasoning - then you must know the language with the Correct balance of local reasoning and higher-level constructs. Knowing which language that is would add specificity to this discussion...
Pre-Scheme is a statically typed dialect of the Scheme programming language, combining the flexibility of Scheme with the efficiency and low-level machine access of C. The compiler uses type inference, partial evaluation, and other correctness-preserving transformations to compile a subset of Scheme into C with no additional runtime overhead. This makes Pre-Scheme a viable alternative to C for programming virtual machines, operating systems, and embedded systems where the runtime overhead of a complete Scheme implementation is not desirable.
Microscheme, or (ms) for short, is a functional programming language for the Arduino, and for Atmel 8-bit AVR microcontrollers in general. Microscheme is a subset of Scheme, in the sense that every valid (ms) program is also a valid Scheme program (with the exception of Arduino hardware-specific primitives). The (ms) compiler performs function inlining, and features an aggressive tree-shaker, eliminating unused top-level definitions. Microscheme has a robust FFI (Foreign Function Interface) meaning that C code may be invoked directly from (ms) programs. Therefore, the power of the existing wealth of Arduino libraries is available within Microscheme.
CRUNCH is an embedded compiler for a statically typed subset of R7RS Scheme, generating C code. The compiler uses type inference to decorate the code with type information without requiring declarations. CRUNCH can be used to translate embedded Scheme code sections, whole programs or multiple source modules into standalone executables or compiled code that can be invoked from Scheme.
The generated C code uses a small runtime-system contained completely in a single C header file. Reference counting is used for managing aggregate data like strings which removes the need for full tracing garbage collection or manual memory management while still having a relatively small overhead.
Since more or less a direct translation of Scheme to C is done, the generated code should run at roughly the same performance as C. No type-checking takes place as the types of all values have been inferred at compile time, and values are not tagged. With the exception of reference counted objects there is no additional runtime overhead and Scheme and C can directly interchange data. This makes CRUNCH very appropriate for writing programs that need a maximum of speed or that are target for constrained environments like deeply embedded systems. The code is portable to all systems that at least have a C compiler.
UNICODE strings are supported and can optionally be disabled for improving performance and reducing code size.
CRUNCH is heavily inspired by PreScheme, the low-level compiler that is originally part of the Scheme48 project. In fact, CRUNCH can be considered a modern reimplementation of PreScheme written in and for use with CHICKEN.
See also:
Crunch – a Scheme compiler with a minimal runtime (more-magic.net)
190 points by sjamaan on Dec 17, 2024 | hide | past | favorite | 72 comments
That's not at all what local reasoning means. Local reasoning is the property that a piece of code contains (when including the call graph) everything that can affect what it does. All mutation of a value is kept within some scope of ownership of that value. If you want to understand a piece of code, you can do it by understanding that piece of code, not the program as a whole.
Assembly makes non-local reasoning mandatory, as any code can update any location in memory without restriction. All memory accesses are global. References need not even be by name - they can be via computed addresses. There are no restrictions in place allowing the structure of the program to provide boundaries on what pieces of code may be understood as units.
so-cal-schemer 14 hours ago [-]
Homoiconicity is orthogonal to local reasoning. It just means the syntax is represented by the native data format, nested lists. This does make code generation very straightforward with list processing primitives.
Mutation in scheme is possible, via set!, and set-car! and set-cdr!, but it's not recommended. Functional program design side-steps the issue.
Yes, I know they're orthogonal. But every example of using macros I see in lisp is either some horrendous non-local logic, or something that can be done better using simpler tools. Where's the killer use case that clearly is good software engineering and not papering over the lack of another feature?
so-cal-schemer 11 hours ago [-]
I believe this was built with macros:
Coalton is an efficient, statically typed functional programming language that supercharges Common Lisp by taking great ideas from Haskell, Scheme, and OCaml.
(add to that something about great power - great responsibility and not holding it wrong)
bjoli 18 hours ago [-]
it allows you to create a language that compiles to your original language.
You can abstract everything away. Not like Haskell where laziness accounts for some and typeclasses for some (and often an exponential growth in compile times). No, it property let's you change the language.
This doesn't strike me as better than the alternatives. In Haskell, it's just a few different functions to handle the different use cases. That strikes me as far better than one "function" that magically does different things depending on how it's called. It is local, I'll give you that. But it still seems bad because you have overloaded the semantics along multiple axes simultaneously. I prefer building blocks with only a single set of semantics each. I believe it's better to write precise code than DWIM code.
bjoli 3 hours ago [-]
everybody agrees, which is why most sane people very rarely reach for macros. At the same time, it would be great if some of the libraries that rely on typeclass machinery for code generation could use lisp-like macros, because turning a 3 second recompile to a 35 second recompile (and I have experienced worse. Much worse.) is what kills exploratory programming. I heard optics mostly solves much of the problems of generic lens, but god forbid you use something like servant or polysemy.
Chez compiles a project of about 35000 lines (with heavy macro usage) in less than 0.5s on -O2.
eru 16 hours ago [-]
C has homoiconicity: you can represent C source code as C strings.
so-cal-schemer 13 hours ago [-]
You can show this is possible, but it is extremely onerous in comparison.
so-cal-schemer 4 hours ago [-]
Or not. Not even as a Turing Complete language.
Homoiconicity is a fundamental language property, not an algorithm nor an implementation issue. Lisp implemented in Pascal is still homoiconic. C is not homoiconic, whether the compiler is implemented in C or in Pascal, and C cannot be made homoiconic without adding fundamentally new and different constructs to the language definition.
You can't natively index into a string and get any C syntactic token out of it besides a char.
eru 10 hours ago [-]
You can write some library functions to get you more sophisticated indexing, if that's what you want.
Zambyte 6 hours ago [-]
The fact that you can write a C parser in C does not make C homoiconic. Not needing to have a user level parser is like, the whole thing that makes homoiconicity interesting.
jibal 15 hours ago [-]
You can't run that code within the language so no, obviously not. And even if you could, strings + eval alone is not homoiconicity--programs are not manipulated by the compiler as unstructured text strings.
eru 10 hours ago [-]
> You can't run that code within the language so no, obviously not.
Of course, you can. C is perfectly capable of writing C interpreters and compilers.
> And even if you could, strings + eval alone is not homoiconicity--programs are not manipulated by the compiler as unstructured text strings.
Lisps (typically) don't execute by walking over s-expressions, either. Lisp interpreters and compilers use more sophisticated representations.
jibal 9 hours ago [-]
I quite intentionally said "within the language" to preempt nonsense like "Of course, you can. C is perfectly capable of writing C interpreters and compilers."
eru 8 hours ago [-]
What does 'within the language' mean?
Is the standard library part of the language? Would a variant of C that came with an interpreter in the standard library (but no other changes) count as homoiconic?
Zambyte 5 hours ago [-]
[dead]
layer8 17 hours ago [-]
I don’t find it appealing when everything looks the same irrespective of purpose and context.
eru 16 hours ago [-]
Seems like a non-sequitur.
layer8 15 hours ago [-]
How so? Homoiconicity means that everything uses the same form of representation, and I’m familiar with how these things look in Lisp.
eru 11 hours ago [-]
Homoiconicity doesn't mean everything has to _look_ the same.
If the term has any meaning, it's about how program source code can be represented and manipulated easily by the user. (And I say 'can' deliberately, because even Lisps still allow you to treat source code as a big flat string, if you want to.)
I don't think homoiconicity is all that much of a useful concept. It's very hard to pin down. Eg C can represent its own source code, too, if a bit clunkily. And Lisps generally don't execute by walking over s-expressions: their internal representation of their own logic typically uses more sophisticated structures (and adding native code compilers to the mix complicates matters further).
BoingBoomTschak 13 hours ago [-]
You can read the words, you know? Together with proper indentation that almost makes it look like Python, there's no way you can get lost in Lisp.
jibal 15 hours ago [-]
Does i + 1 look the same as "i + 1"? The first is an expression, the second is a string. In LISP, it's similarly (+ i 1) vs '(+ i 1).
These sorts of shallow complaints can be made of any feature than one is not familiar with, hasn't used, and doesn't know or understand the benefits of. In any case, no one is forcing people to use this language or take advantage of this feature.
P.S. The "response" actually ignores all points made, attacks strawmen, moves the goalposts, and is intellectually dishonest (the original comment was clearly a complaint, and besides it wouldn't matter if some other word like "criticism" or "dissatisfaction" were substituted--my point remains). Again, no one is forcing anyone.
layer8 14 hours ago [-]
To answer your question, yes it does look pretty much the same in the Lisp version, less so in the string version. Also I didn’t complain; I expressed the opinion that I don’t agree that homoiconicity increases the appeal of a programming language, because the drawbacks outweigh the possible benefits for me. I spent some time programming in Lisp and am familiar with how homoiconicity works there.
The point is that these things are subjective, and there will never be a programming language that everyone likes the best.
As the article correctly mentions, Lisp as a concept is much older than any of the popular languages used these days; so are the attempts to get more people use it. Most of them are, unfortunately, unsuccessful, because it's probably impossible to understand Lisp after a quick and friendly introduction.
I first met Common Lisp during my college years in early 2000s: we had an enthusiast teacher who taught it for free, in his free time; it was interesting for me as a freshman to learn something new, but also I literally had no idea how to write Lisp code properly, without resorting to using `progn` here and there. For those not aware, `progn` is a form that allows you to write expressions in a sequential way, pretty much like you use the C compound statement, a `{ ... }` block. It works, and after some time you find that you're writing in some crappy imperative programming language with a lot of brackets but you don't learn much about the functional programming.
It took me more than a year, and definitely more than any short “friendly introduction”, to understand the functional approach.
Now, Racket. I first noticed it while doing my daily LeetCode; they added Racket as a supported language and you can go use it to solve a task. After not using Lisp for 20-something years, I appreciated the opportunity, but I found the type contract syntax infuriating. This is LeetCode #1, “Two sum”:
I don't know what you feel, but this makes me want to close this tab and never return. So if I find myself wanting to write some Lisp and there's a daily LeetCode task I want to solve, the first thing I do is I delete all this garbage and come back to the clean option:
(define (two-sum nums target) ...)
which, except for the minor syntax differences, brings me back to my college Lisp years and I can actually enjoy it.
tech_army 19 hours ago [-]
Will definitely try it.
SilentM68 14 hours ago [-]
Thanks for sharing. It's been bookmarked :)
.-.
/ λ \
'---'
19 hours ago [-]
usxr1515 17 hours ago [-]
I've been designing my own small language runtime in Rust (VM + JIT + AOT backends) mostly as a way to actually understand tradeoffs compiler authors make instead of just reading about them. Racket's approach to macros and language-oriented programming is one of the things I keep coming back to as a reference curious how much of that flexibility comes at a real runtime cost vs. being mostly a compile-time abstraction.
brabel 13 hours ago [-]
I can answer that for Common Lisp, specifically the SBCL implementation (there's several others). It compiles every function to native code (you can even inspect the assembly with `disassemble`). Macros are executed before code is compiled. Hence, once you've compiled a function, the macro disappears since its only role is to generate the expressions that are going to actually be compiled and then executed.
`unwind-protect` is like a `try/finally` in other languages, and I used that above to create something similar to `defer` in Go/Zig which is related to it, but with the operands inverted.
The ` symbol is a quasiquote. Unlike quote `'` it lets you unquote symbols inside with the , operator. That's why you'll always see a bunch of '`' and ',' in macros.
The @, thing is a "spread" (looks different in Racket from what I saw in the post, which used `...`). It just spreads whatever was on the list in the place you put that on, so if `action` is `(p 1) (p 2)`, then `(progn ,@action)` becomes `(progn (p 1) (p 2))`.
You can inspect what the actual code that will be compiled looks like with `macroexpand`:
I don't know Racket, but knowing it can compile to binary, I expect macros in Racket would work exactly the same.
gus_massa 10 hours ago [-]
Yes, Racket is quite similar, perhaps with more steps (but I guess you also simplified the steps in SBCL). It's something like 20 steps, but let's keep it short:
Racket ---expand the macros---> Simplified Racket "Kernel"
Simplified Racket "Kernel"---schemify---> Rumble (that is Chez Scheme + a few libraries and macros)
Rumble ---expand the macros---> Simplified Chez Scheme
Simplified Chez Scheme ---constants propagation/folding/other---> Simplified Chez Scheme
Simplified Chez Scheme ---compiler---> native code
GLS moved to CMU in the early 80's... I remember taking "Comparative Programming Languages" from him. Good teacher and impressive guy. In addition to the obvious, he also covered SNOBOL and APL in that course. Memories :-)
The `i` in `8i` is the imaginary unit. The `1@1` is the polar notation for complex numbers.
The `10#` is a compatibility remain (the Scheme authors wanted a way to see how many signifant digits were known. In `10#` there 2. So `#` stands for "some digit". In most implementations this is read as 0. More details at [1]
An `#` followed by a list datum is read as a vector. Thus `#()` is an empty vector and `()` is an empty list.
[1] https://stackoverflow.com/a/10936403/23567
Complicated? Well, to support both inexact (floating point) and exact numbers (bignums and fractions) it makes sense to have `#i` and `#e` to explicitl choose. The default is (more or less): numbers with . are inexact the others are exact.
This was a wild ride. I'm torn on whether this feels like the Reader is bloated/polluted or whether this is the coolest numerical parser I've ever used. You can really do a lot to coerce the these numbers just by inserting an {o,s,e,i,b,#} into the number, with different semantics depending on the position of the character.
Somewhat overwhelming, I can only hope there's some elegance underlying it all...
Obviously the more you use the language these go away but still at least to me it doesn't seem to be a coherent syntax.
Not necessarily a bad thing but also not exactly what I would call "expressive".
You may be able to build anything you want --- which may be efficient when communicating with the machine. But I wonder about now well this would communicate with other programmers.
It was far less complex to code, and human readable. Unicon was pretty cool also, but never became popular. Erlang/Elixir will probably become more relevant as people move into massively parallel constraint solvers.
The monolith centric languages are simply no longer appropriate for many classes of problems. =3
Still, far less than most other programming languages, virtue of having parentheses making things unambiguous. Outliers are Smalltalk and maybe (?) Forth.
https://onecompiler.com/racket
...and it didn't compile, complaining:
...maybe there is a switch needed to enable it?https://docs.racket-lang.org/reference/Reading.html#%28def._...
I couldn't figure it out with this either:
https://stackoverflow.com/questions/51942188/read-syntax-for...
...just to make sure I wasn't going crazy, this:
...does work as expected with this online scheme interpreter:https://www.jdoodle.com/execute-scheme-online
That read-syntax doesn't just accept everything accepted by plain read is one of my biggest annoyances with Racket.
I’d also encourage you to give it a try and have some fun with it! I’m using it for some of the 3D demos in my book. It’s definitely not a silver bullet, but I’ve found it can be pretty productive.
Personally, my favorite Lisps are Racket, Common Lisp, and Clojure, in that order. I’ve also been tempted to give Chicken Scheme a try! :)
Nice touch. Explains how Caine returns in episode 9: Lisp continuations allow for graceful error recovery.
https://en.wikipedia.org/wiki/Backslash#Filenames
When an introduction says “friendly”, I don’t expect it to assume that I know what lambda is.
When an introduction says “friendly”, I don’t expect syntax rules to appear in it. At all.
Wtf kind of intro to a programming language doesn’t include syntax rules? We are all informed, experienced, technologically inclined people here. Not dumb children.
I’m struggling to see your comment as anything more than contrarian babble.
PP could have been more clear and say syntax-rules (note the dash), which means macros. Macros are usually considered an advanced topic.
Given that most languages don’t have syntax rules or anything like it, I’m gonna go out on a limb and say that most language introductions/overviews/tutorials don’t mention it.
In fact, what languages can you say do not have syntax rules?
Since macros are a very important part of Racket, complaining that a friendly introduction mentions them is [insert non-friendly characterization].
https://users.cs.northwestern.edu/~robby/logos/
The skull didn't last long.
Are there seriously any emacs users who are completely unaware of elisp? Isn't elisp the entire point of picking emacs?
https://racket-stories.com/
I have not had a single coworker, who has even started to learn these things, even after I have presented a Scheme on a Friday afternoon, and showed off some cool threading/pipeline syntax-rules macro, and showed how this compared to Python, showing how it reduces boilerplate in a way impossible to do in Python.
Granted, this is in Germany, where CS education is not really all that great, and most universities teach boring Java or C++ or something.
At least we had a RacketCon in Berlin some time ago, and I was fortunate enough to have a prof at university, who at least introduced Dr.Scheme. His motto was: "I am not here to teach you C, Java, or Python. I am here to teach you computer programming." (translated) He went on to introduce languages of various paradigms, from Prolog, to Dr.Scheme (predecessor of Racket), to C, and Python. Thank you Prof. von Löwis.
Misses out on LispWorks and Allegro Common Lisp for the Common Lisp entry, which contrary to SBCL provide a similar graphics experience as the Lisp machines of yore, here missing out on TI and Xerox as well, Genera wasn't alone.
You can read the about it here: https://defn.io/2020/01/04/remember-internals/
See: https://en.wikipedia.org/wiki/Arc_(programming_language)#His...
In teaching our material we use a dialect of the programming language Lisp. We never formally teach the language, because we don’t have to. We just use it, and students pick it up in a few days. This is one great advantage of Lisp-like languages: They have very few ways of forming compound expressions, and almost no syntactic structure. All of the formal properties can be covered in an hour, like the rules of chess. After a short time we forget about syntactic details of the language (because there are none) and get on with the real issues—figuring out what we want to compute, how we will decompose problems into manageable parts, and how we will work on the parts. Another advantage of Lisp is that it supports (but does not enforce) more of the large-scale strategies for modular decomposition of programs than any other language we know. We can make procedural and data abstractions, we can use higher-order functions to capture common patterns of usage, we can model local state using assignment and data mutation, we can link parts of a program with streams and delayed evaluation, and we can easily implement embedded languages. All of this is embedded in an interactive environment with excellent support for incremental program design, construction, testing, and debugging. We thank all the generations of Lisp wizards, starting with John McCarthy, who have fashioned a fine tool of unprecedented power and elegance.
[0]: https://sarabander.github.io/sicp/
[1]: https://en.wikipedia.org/wiki/Gerald_Jay_Sussman
> For decades, Lisp was the language of artificial intelligence. [...] Then came the "AI winter," funding dried up, and Lisp went from star to cult language.
Lisp had fallen from relevance before then. Only the United States was still using it, and mostly out of technical debt and a stubborn refusal to move on. Prolog displaced it in the late 1970s, and even within the US, the Lisp part was an unfortunate implementation detail to get to a Prolog-shaped object. It's not surprising that the US fell way behind Japan in this area in the 1980s. Anybody who would imply they would take a Lisp machine over a PIM is either not interested in symbolic computation and just likes Lisp, or they're doing so out of total ignorance of how much more advanced the PIMs were for symbolic AI.
The cutting edge was with Prolog, and that's still the case today. Nobody's researching MIL in Lisp, even in America.
This visualization of relative programming language popularity shows Lisp was the 3rd most popular general purpose language in Q1 of 1984 behind Pascal (a learning language?) and C.
(Prolog shows at 12th, then drops off the chart)
Most Popular Programming Languages: Data from 1958 to 2025
https://youtu.be/ZTPrbAKmcdo?t=116
Gabriel's perspective from 1990:
Lisp: Good News, Bad News, How to Win Big - Richard P. Gabriel - Lucid, Inc
https://dreamsongs.com/WIB.html
> This visualization of relative programming language popularity shows Lisp was the 3rd most popular general purpose language
Which is fine, and makes sense. But I'm addressing a claim about Lisp being "the Language" for the era of symbolic AI. Which is decidedly not high volume, nor is it general at all, it's really quite specific.
I'm correcting it, because I know Americans are heavily culturally silo'd on this, and symbolic AI is especially esoteric. Most people probably can't name a single commercial expert system off the top of their head, and that's not unreasonable. Our cultural view of symbolic AI is rife with American exceptionalism (I theorize partially because of government involvement) that just doesn't track with reality. Speaking as an American.
The ranking then was due to Turbo Pascal which came out in November 1983. It was probaly the first IDE and compiler on PCs
Anyways the embedded inference engine as an idea failed a long time ago, Americans convinced themselves it was the way to do things and just refused to ever let it go. It's just extra baggage on the important bit, which is the symbolic computation. miniKanren has a niche more in line with a theorem solver.
The syntax lends itself to easy structural editing way before LSPs..
Why Racket? Why Lisp?
https://beautifulracket.com/appendix/why-racket-why-lisp.htm...
Why language-oriented programming? Why Racket?
https://beautifulracket.com/appendix/why-lop-why-racket.html
Creating Languages in Racket: Sometimes you just have to make a better mousetrap.
https://queue.acm.org/detail.cfm?id=2068896
Lisp is clay: the power of composable DSLs
https://fosdem.org/2026/schedule/event/HDE7JZ-lisp-is-clay/
The other powers of Lisps (interactive development, hot reloadability, restarts on error, etc) are more tied to the sophistication of their implementations and runtime environments.
I feel like the good parts of lisps have been adopted by typed languages...
I honestly am curious. I've seen a few examples presented for it, but they always seem like bad software engineering to me. Where's an example that does something in a cleaner way than alternatives present in other languages while remaining compatible with local reasoning?
If you don't like it, you can try https://rhombus-lang.org/ that is build on Racket and also has macros but uses a Python-like syntax.
Well, getting the interaction between modules and syntax transformations (macros) right is not an easy task.
"Composable and Compilable Macros: You Want it When?" Matthew Flatt http://dl.acm.org/authorize?24908
That's a perspective. If you're looking for a low-level language, then Scheme isn't it. (Forget iconicity - Scheme is garbage-collected. And supports continuations!)
If you don't program in machine code - which would maximize local reasoning - then you must know the language with the Correct balance of local reasoning and higher-level constructs. Knowing which language that is would add specificity to this discussion...
Pre-Scheme is a statically typed dialect of the Scheme programming language, combining the flexibility of Scheme with the efficiency and low-level machine access of C. The compiler uses type inference, partial evaluation, and other correctness-preserving transformations to compile a subset of Scheme into C with no additional runtime overhead. This makes Pre-Scheme a viable alternative to C for programming virtual machines, operating systems, and embedded systems where the runtime overhead of a complete Scheme implementation is not desirable.
https://ryansuchocki.github.io/microscheme/
Microscheme, or (ms) for short, is a functional programming language for the Arduino, and for Atmel 8-bit AVR microcontrollers in general. Microscheme is a subset of Scheme, in the sense that every valid (ms) program is also a valid Scheme program (with the exception of Arduino hardware-specific primitives). The (ms) compiler performs function inlining, and features an aggressive tree-shaker, eliminating unused top-level definitions. Microscheme has a robust FFI (Foreign Function Interface) meaning that C code may be invoked directly from (ms) programs. Therefore, the power of the existing wealth of Arduino libraries is available within Microscheme.
https://wiki.call-cc.org/eggref/6/crunch
CRUNCH is an embedded compiler for a statically typed subset of R7RS Scheme, generating C code. The compiler uses type inference to decorate the code with type information without requiring declarations. CRUNCH can be used to translate embedded Scheme code sections, whole programs or multiple source modules into standalone executables or compiled code that can be invoked from Scheme.
The generated C code uses a small runtime-system contained completely in a single C header file. Reference counting is used for managing aggregate data like strings which removes the need for full tracing garbage collection or manual memory management while still having a relatively small overhead.
Since more or less a direct translation of Scheme to C is done, the generated code should run at roughly the same performance as C. No type-checking takes place as the types of all values have been inferred at compile time, and values are not tagged. With the exception of reference counted objects there is no additional runtime overhead and Scheme and C can directly interchange data. This makes CRUNCH very appropriate for writing programs that need a maximum of speed or that are target for constrained environments like deeply embedded systems. The code is portable to all systems that at least have a C compiler.
UNICODE strings are supported and can optionally be disabled for improving performance and reducing code size.
CRUNCH is heavily inspired by PreScheme, the low-level compiler that is originally part of the Scheme48 project. In fact, CRUNCH can be considered a modern reimplementation of PreScheme written in and for use with CHICKEN.
See also:
https://news.ycombinator.com/item?id=42440767Assembly makes non-local reasoning mandatory, as any code can update any location in memory without restriction. All memory accesses are global. References need not even be by name - they can be via computed addresses. There are no restrictions in place allowing the structure of the program to provide boundaries on what pieces of code may be understood as units.
Mutation in scheme is possible, via set!, and set-car! and set-cdr!, but it's not recommended. Functional program design side-steps the issue.
see also:
SICP: 3.1.3 The Costs of Introducing Assignment
https://sarabander.github.io/sicp/html/3_002e1.xhtml#g_t3_00...
Coalton is an efficient, statically typed functional programming language that supercharges Common Lisp by taking great ideas from Haskell, Scheme, and OCaml.
https://coalton-lang.github.io/
Not well known, but surely good software engineering adding features. Lisp* is called the Programmable Programming Language for a reason.
pg wrote a treatise on Lisp macros (free download):
https://www.paulgraham.com/onlisp.html
(add to that something about great power - great responsibility and not holding it wrong)
You can abstract everything away. Not like Haskell where laziness accounts for some and typeclasses for some (and often an exponential growth in compile times). No, it property let's you change the language.
I got tired of loops sucking and made this, for example: https://rikspucko.koketteriet.se/bjoli/goof-loop
Chez compiles a project of about 35000 lines (with heavy macro usage) in less than 0.5s on -O2.
Homoiconicity is a fundamental language property, not an algorithm nor an implementation issue. Lisp implemented in Pascal is still homoiconic. C is not homoiconic, whether the compiler is implemented in C or in Pascal, and C cannot be made homoiconic without adding fundamentally new and different constructs to the language definition.
Further sources:
https://wiki.c2.com/?HomoiconicLanguages
https://wiki.c2.com/?HomoiconicExampleInManyProgrammingLangu...
https://wiki.c2.com/?GreenspunsTenthRuleOfProgramming
Of course, you can. C is perfectly capable of writing C interpreters and compilers.
> And even if you could, strings + eval alone is not homoiconicity--programs are not manipulated by the compiler as unstructured text strings.
Lisps (typically) don't execute by walking over s-expressions, either. Lisp interpreters and compilers use more sophisticated representations.
Is the standard library part of the language? Would a variant of C that came with an interpreter in the standard library (but no other changes) count as homoiconic?
If the term has any meaning, it's about how program source code can be represented and manipulated easily by the user. (And I say 'can' deliberately, because even Lisps still allow you to treat source code as a big flat string, if you want to.)
I don't think homoiconicity is all that much of a useful concept. It's very hard to pin down. Eg C can represent its own source code, too, if a bit clunkily. And Lisps generally don't execute by walking over s-expressions: their internal representation of their own logic typically uses more sophisticated structures (and adding native code compilers to the mix complicates matters further).
These sorts of shallow complaints can be made of any feature than one is not familiar with, hasn't used, and doesn't know or understand the benefits of. In any case, no one is forcing people to use this language or take advantage of this feature.
P.S. The "response" actually ignores all points made, attacks strawmen, moves the goalposts, and is intellectually dishonest (the original comment was clearly a complaint, and besides it wouldn't matter if some other word like "criticism" or "dissatisfaction" were substituted--my point remains). Again, no one is forcing anyone.
The point is that these things are subjective, and there will never be a programming language that everyone likes the best.
https://parentheticallyspeaking.org/articles/bicameral-not-h...
I first met Common Lisp during my college years in early 2000s: we had an enthusiast teacher who taught it for free, in his free time; it was interesting for me as a freshman to learn something new, but also I literally had no idea how to write Lisp code properly, without resorting to using `progn` here and there. For those not aware, `progn` is a form that allows you to write expressions in a sequential way, pretty much like you use the C compound statement, a `{ ... }` block. It works, and after some time you find that you're writing in some crappy imperative programming language with a lot of brackets but you don't learn much about the functional programming.
It took me more than a year, and definitely more than any short “friendly introduction”, to understand the functional approach.
Now, Racket. I first noticed it while doing my daily LeetCode; they added Racket as a supported language and you can go use it to solve a task. After not using Lisp for 20-something years, I appreciated the opportunity, but I found the type contract syntax infuriating. This is LeetCode #1, “Two sum”:
I don't know what you feel, but this makes me want to close this tab and never return. So if I find myself wanting to write some Lisp and there's a daily LeetCode task I want to solve, the first thing I do is I delete all this garbage and come back to the clean option: which, except for the minor syntax differences, brings me back to my college Lisp years and I can actually enjoy it.For example, here's a simple CL macro:
`unwind-protect` is like a `try/finally` in other languages, and I used that above to create something similar to `defer` in Go/Zig which is related to it, but with the operands inverted.The ` symbol is a quasiquote. Unlike quote `'` it lets you unquote symbols inside with the , operator. That's why you'll always see a bunch of '`' and ',' in macros.
The @, thing is a "spread" (looks different in Racket from what I saw in the post, which used `...`). It just spreads whatever was on the list in the place you put that on, so if `action` is `(p 1) (p 2)`, then `(progn ,@action)` becomes `(progn (p 1) (p 2))`.
You can inspect what the actual code that will be compiled looks like with `macroexpand`:
`progn` is a "special operator" that's needed when you want more than one expression to be evaluated in order.Example calling the macro:
As you can see, it executed the deferred expression last.We can prove that macros disappear after compile-time with an example:
You can see the Assembly is very simple for `(+ x x)` (the ADD instruction plus a bunch of stack/error maintenance).If we instead had a macro that did this:
And a function used that: Now, disassembling the function: Same thing exactly.I don't know Racket, but knowing it can compile to binary, I expect macros in Racket would work exactly the same.
Racket ---expand the macros---> Simplified Racket "Kernel"
Simplified Racket "Kernel"---schemify---> Rumble (that is Chez Scheme + a few libraries and macros)
Rumble ---expand the macros---> Simplified Chez Scheme
Simplified Chez Scheme ---constants propagation/folding/other---> Simplified Chez Scheme
Simplified Chez Scheme ---compiler---> native code
You can see the result with https://pkgs.racket-lang.org/package/disassemble