zlacker

[parent] [thread] 16 comments
1. simonw+(OP)[view] [source] 2026-01-19 23:51:38
I went looking for a single Markdown file I could dump into an LLM to "teach" it the language and found this one:

https://github.com/jordanhubbard/nanolang/blob/main/MEMORY.m...

Optimistically I dumped the whole thing into Claude Opus 4.5 as a system prompt to see if it could generate a one-shot program from it:

  llm -m claude-opus-4.5 \
    -s https://raw.githubusercontent.com/jordanhubbard/nanolang/refs/heads/main/MEMORY.md \
    'Build me a mandelbrot fractal CLI tool in this language' 
   > /tmp/fractal.nano
Here's the transcript for that. The code didn't work: https://gist.github.com/simonw/7847f022566d11629ec2139f1d109...

So I fired up Claude Code inside a checkout of the nanolang and told it how to run the compiler and let it fix the problems... which DID work. Here's that transcript:

https://gisthost.github.io/?9696da6882cb6596be6a9d5196e8a7a5...

And the finished code, with its output in a comment: https://gist.github.com/simonw/e7f3577adcfd392ab7fa23b1295d0...

So yeah, a good LLM can definitely figure out how to use this thing given access to the existing documentation and the ability to run that compiler.

replies(3): >>nodja+31 >>hahaha+y7 >>e12e+2f
2. nodja+31[view] [source] 2026-01-19 23:59:22
>>simonw+(OP)
I think you need to either feed it all of ./docs or give your agent access to those files so it can read them as reference. The MEMORY.md file you posted mentions ./docs/CANONICAL_STYLE.md and ./docs/LLM_CORE_SUBSET.md and they in turn mention indirectly other features and files inside the docs folder.
replies(1): >>simonw+x2
◧◩
3. simonw+x2[view] [source] [discussion] 2026-01-20 00:14:34
>>nodja+31
Yeah, I think you're right about that.

The thing that really unlocked it was Claude being able to run a file listing against nanolang/examples and then start picking through the examples that were most relevant to figuring out the syntax: https://gisthost.github.io/?9696da6882cb6596be6a9d5196e8a7a5...

4. hahaha+y7[view] [source] 2026-01-20 01:07:50
>>simonw+(OP)
But are you losing horsepower of the LLM available to problem solving on a given task by doing so?
replies(1): >>simonw+9g
5. e12e+2f[view] [source] 2026-01-20 02:22:21
>>simonw+(OP)
Oh, wow. I thought the control flow from the readme was a little annoying with the prefix -notation for bigger/smaller than;

    # Control flow
    if (> x 0) {
      (println "positive")
    } else {
      (println "negative or zero")
    }
But that's nothing compared to the scream for a case/switch-statement in the Mandelbrot example...

    # Gradient: " .:-=+*#%@"
        let gradient: string = " .:-=+*#%@"
        let gradient_len: int = 10
        let idx: int = (/ (* iter gradient_len) max_iter)
        if (>= idx gradient_len) {
            return "@"
        } else {
            if (== idx 0) {
                return " "
            } else {
                if (== idx 1) {
                    return "."
                } else {
                    if (== idx 2) {
                        return ":"
                    } else {
                        if (== idx 3) {
                            return "-"
                        } else {
                            if (== idx 4) {
                                return "="
                            } else {
                                if (== idx 5) {
                                    return "+"
                                } else {
                                    if (== idx 6) {
                                        return "*"
                                    } else {
                                        if (== idx 7) {
                                            return "#"
                                        } else {
                                            if (== idx 8) {
                                                return "%"
                                            } else {
                                                return "@"
                                            }
                                        }
replies(3): >>kamaal+Mf >>antonv+qA >>mortar+N01
◧◩
6. kamaal+Mf[view] [source] [discussion] 2026-01-20 02:29:02
>>e12e+2f
If you are planning to write so many if else statements. You might as well write Prolog.
◧◩
7. simonw+9g[view] [source] [discussion] 2026-01-20 02:32:29
>>hahaha+y7
Maybe a little, but Claude has 200,000 tokens these days and GPT-5.2 has 400,000 - there's a lot of space.
replies(1): >>hahaha+xe1
◧◩
8. antonv+qA[view] [source] [discussion] 2026-01-20 06:08:43
>>e12e+2f
> scream for a case/switch-statement

Maybe I’m missing some context, but all that actually should be needed in the top-level else block is ‘gradient[idx]’. Pretty much anything else is going to be longer, harder to read, and less efficient.

replies(1): >>e12e+1O
◧◩◪
9. e12e+1O[view] [source] [discussion] 2026-01-20 08:30:53
>>antonv+qA
True, with early return - there's no need to actually nest with else.

Logically this still would be a case/switch though...

replies(1): >>vidarh+VV
◧◩◪◨
10. vidarh+VV[view] [source] [discussion] 2026-01-20 09:30:01
>>e12e+1O
The point was that logically it would be an array lookup by index.

There's no need for any conditional construct here whatsoever.

You'll note it has already constructed a string in the right order to do that, but then copped out with the if-else.

replies(1): >>e12e+um1
◧◩
11. mortar+N01[view] [source] [discussion] 2026-01-20 10:02:41
>>e12e+2f
I mean for all intents and purposes this language is designed for use by LLM's, not humans, and the AI probably won't complain that a switch-case statement is missing. ;)
◧◩◪
12. hahaha+xe1[view] [source] [discussion] 2026-01-20 12:03:51
>>simonw+9g
True. You would know this better but are you also burning "attention" by giving it a new language? Rather than use its familiar Python pathways it needs to attend more to generate the unseen language. It needs to KV across from the language spec to the language to the goal. Rather than just speak the Python or JS it is uses to speaking.
◧◩◪◨⬒
13. e12e+um1[view] [source] [discussion] 2026-01-20 13:09:06
>>vidarh+VV
True enough. On that note, I had a look at the language reference - there's arrays - but also this:

    (char_at s index)        # Get ASCII value at index (0-based)
    (string_from_char code)  # Create string from ASCII value
So, you can pluck a character... From an UTF-8 string? What if the rendering used multibyte characters?
replies(1): >>vidarh+Ra2
◧◩◪◨⬒⬓
14. vidarh+Ra2[view] [source] [discussion] 2026-01-20 17:14:08
>>e12e+um1
Well, we can see the string, and we can see that is uses plain ASCII.
replies(1): >>e12e+ae2
◧◩◪◨⬒⬓⬔
15. e12e+ae2[view] [source] [discussion] 2026-01-20 17:24:42
>>vidarh+Ra2
In this case, sure. But what if we shifted to rendering with emojis or whatnot. What would the first ASCII character of the string be?
replies(1): >>vidarh+Ce5
◧◩◪◨⬒⬓⬔⧯
16. vidarh+Ce5[view] [source] [discussion] 2026-01-21 14:40:03
>>e12e+ae2
If you anticipate that need, you just store the gradient as an array of strings, and you still then only need a trivial lookup.
replies(1): >>e12e+ff7
◧◩◪◨⬒⬓⬔⧯▣
17. e12e+ff7[view] [source] [discussion] 2026-01-22 01:30:57
>>vidarh+Ce5
I was more commenting on the language design here; the idea of indexing into a UTF-8 string and returning an ASCII character. What does the index count? Bytes? There doesn't seem to be a way to get UTF-8 characters from strings?

Ed: There seems to be an UTF-8 library:

https://github.com/jordanhubbard/nanolang/tree/main/modules/...

[go to top]