> Obviously an LLM generated the code, but I felt comfortable following along and understood what it was doing, reading and Trusting the Tests. [...] My difficulty is with thinking the way that lets me write Scheme.
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.