I keep bouncing off the Scheme language
100 points - last Friday at 8:32 AM
SourceComments
In much that same way that many people do the daily wordle or crossword, I do the daily leetcode.
I flip a coin and solve it first in either C++ or Python, then re-write my solution in the other one.
Usually it takes me around 20 minutes to solve it in either language, and 5 minutes to re-solve it in either language.
Recently I decided to start learning emacs lisp. This is an imperative lisp dialect that’s pretty different from scheme, but I think that the particular language doesn’t matter much for this process. I could a bit biased because I do have prior experience with SML and scheme.
I started re-solving the problems a third time in emacs lisp. And I’m still learning but I’ve felt my comfort with the language increase over time, and I expect that if I continue doing this then I will eventually reach parity with C++ and Python.
Currently it takes me about 20 minutes to re-solve a problem in emacs lisp, because I usually have to read documentation and/or look up something new.
Personally I find it easiest do design data flows: think about what we need in order to compute the result. The less I have to think about state the better. Functional patterns fall out and it feels simple and easy to me, so I do it. I'm way over the phase I thought that's somehow cooler than the OOP folks, however.
Best of all, is that the syntax grammar is so simple, that a simple CLAUDE.md + a few review agents lets me move super fast using AI. I spend most of my time anchoring on the design/plan and let AI write the implementation for most of the code.
I do wonder what a language with the same “taste” and minimalism as Scheme but embracing the actor model would look like. Erlang?
Even better if someone could figure out how to harmonize them in the same language: “There are exactly two ways to do it, and they’re interchangeable.”
Official docs: https://docs.racket-lang.org/rhombus/index.html
Collection of small examples: https://github.com/racket/rhombus/blob/master/demo.rhm
stack traces are esoteric and error messages entirely unhelpful,
documentation masquerades as deep but is indeed inconsistent and prosaic, mixing styles of reference, explanation, and how-to willy-nilly, (compare with Dybvig’s The Scheme Programming Language, which is focused and consistent, and it takes no time to get your answers; there’s just no method to guile and guix manuals), i hate it big time,
there’s big gaps in documentation (especially with Guix – there’s literally zero information about `define-record-type*` which is used everywhere in its codebase; admittedly, not scheme related, but still),
the cli requires too much memorization,
most modules are not named, but numbered, ie, instead of something like `(base list)`, you get `(srfi srfi-1)`, so you need to either memorize, or go through the info pages for each procedure you need to import, which means you also need to know the exact names for the procedures you need beforehand,
there’s like 4 ways to define a record, each with a different feature set and incompatibilities,
etc.
these are the reasons i find it hard to use.
to respond to the content of the article, the different neurotype idea is off, because scheme allows you very well to express sequences of operations; the ecosystem of APIs may not cater to this tho. although if it was rephrased into “scheme emphasizes symbolic manipulations, as opposed to operating a machine”, i would agree
There's your problem, right there. Vibe-coding is sabotaging learning before you even start.
You can learn some things by reading good code, but there's no substitute for the exercise of thinking through problems yourself. (Also, an LLM won't necessarily give you good code.)
First learn paint fence, Daniel-san. Not watch third-hand videos spliced together of other people painting the fence, and thinking you'll understand much of anything about it.
> I have the ALGOL neurotype.
Good news! Scheme started as a block-structured imperative "algorithmic" language in the spirit of ALGOL. Just with more parentheses.
Write as if in ALGOL, but using Scheme's comparable syntax and language features. And lots of parentheses.
Don't get confused by CS professors showing you pure-functional features, the metacircular evaluator, recursive programming, syntax extension and language-oriented programming, etc. You can come back to that.
Just start coding ALGOL-style in Scheme. You'll accomplish something in an hour.
Once you see it's easy, and are comfortable with that part, then the next thing you do, to get more idiomatic is one of the following, then do the other one:
* Try to get more functional, by eliminating some of the mutations of variables in your code. For example, if you're using `set!` a lot, can you eliminate them by, for example, making them arguments in a named-`let` recursion. (Or, instead of named-`let`, spell out the recursive functions, like some intro CS professors will want you to do, but that can obscure things that are obvious once you see the named-`let` lexical structure.)
* Try to get more language-oriented, by making a little domain-specific language, maybe with `syntax-rules`, `syntax-case`, or `syntax-parse`.
One more tip, for anyone coming from C, C++, Rust, etc., who may like trying to know the cost of everything: If you get hung up on high-level language features like GC, and not knowing which of a number of ways of doing something, is the right (performant) way, try not to. But if you want an intuition (that might be a lie), imagine that needless mutations or allocations may be more expensive than finding a different way to do it. And each FFI call has very expensive overhead. At one point that I had to make highly performant code, I made a little tool, to help confirm my intuitions: https://www.neilvandyke.org/racket/shootout/ There's also a statistical profiler in Racket now, and you can even (with work) rig it up in production systems, for measuring real-world workloads, which I used to guide optimizing performance of a large and complicated system.
You’re almost there. Just stop thinking about the sequence of instructions. Focus on the information half (the values) that you need to produce.