:seven: :seven: :seven: on Nostr: so I found the hard parts of abstracting an expander to be extensible within the ...
so I found the hard parts of abstracting an expander to be extensible within the language.
let’s discuss macro/function application responsibility. In a Scheme you’re usually going to find an expander that has a few phases it goes through; it might do a lexical first pass before doing any expanding just to build a table of symbols, it might apply all phase-0 transformers across the entire file first before beginning phase-1+ recursive macro applications, and it can do this because the reader ensured everything was prepared for the expectations the expander has to meet for the runtime environment, and for most languages that set of runtime environment expectations are basically hard-coded by a spec. The EBNF grammar and syntax. Precedence. Things as simple as “how does function application work? how does looking up a member on a package work?” these are all set in stone and it makes implementing the language yourself remarkably straightforward after the spec-implementation has been finished. After all, that spec has been proven by other code.
But what if those were just the sane, minimal defaults? What if you needed access to these fundamentals? Well, as it turns out, there are entire research papers on these kinds of questions. There’s two big concepts: Resolution, and Claims. Everyone knows resolution; resolution is what happens when you use a variable name somewhere and the interpreter/compiler has to walk a tree of scopes to find where it’s owned and in what table the value is stored in. Claims, on the other hand, are kind of the opposite; you don’t have a lexical tree of things assigned, but you do have a list of patterns which can “claim” a syntax pattern: it’s only when no protocol claims that pattern that you actually reach an error or diagnostic. I think this is a really cool thing, especially when it can exist as part of a Resolution algorithm.
And what this gives me in return are the following interfaces for my protocols (rough, not finalized):
```
operator %:precedence 65 * x y -> mul x y
handler (_ module . fname) do
# if package contains fname, apply it
# otherwise, fall through to method-missing
end
inspector do
# not yet specced, but basically reflection on the protocol itself
end
```
Published at
2026-05-29 15:45:07 CESTEvent JSON
{
"id": "e7d4b181e497b27b83cfadfd90904f43b58aef8651360520decaa04157b14cdc",
"pubkey": "fb594e1a7dcf278c18c7d623c5a51ec41ab62ac5cea86554d70a9c691565161b",
"created_at": 1780062307,
"kind": 1,
"tags": [
[
"proxy",
"https://dsmc.space/objects/3e5b2650-cab0-4dc2-9410-a7d2ab3e02c7",
"activitypub"
],
[
"L",
"pink.momostr"
],
[
"l",
"pink.momostr.activitypub:https://dsmc.space/objects/3e5b2650-cab0-4dc2-9410-a7d2ab3e02c7",
"pink.momostr"
],
[
"-"
]
],
"content": "so I found the hard parts of abstracting an expander to be extensible within the language.\r\n\r\nlet’s discuss macro/function application responsibility. In a Scheme you’re usually going to find an expander that has a few phases it goes through; it might do a lexical first pass before doing any expanding just to build a table of symbols, it might apply all phase-0 transformers across the entire file first before beginning phase-1+ recursive macro applications, and it can do this because the reader ensured everything was prepared for the expectations the expander has to meet for the runtime environment, and for most languages that set of runtime environment expectations are basically hard-coded by a spec. The EBNF grammar and syntax. Precedence. Things as simple as “how does function application work? how does looking up a member on a package work?” these are all set in stone and it makes implementing the language yourself remarkably straightforward after the spec-implementation has been finished. After all, that spec has been proven by other code.\r\n\r\nBut what if those were just the sane, minimal defaults? What if you needed access to these fundamentals? Well, as it turns out, there are entire research papers on these kinds of questions. There’s two big concepts: Resolution, and Claims. Everyone knows resolution; resolution is what happens when you use a variable name somewhere and the interpreter/compiler has to walk a tree of scopes to find where it’s owned and in what table the value is stored in. Claims, on the other hand, are kind of the opposite; you don’t have a lexical tree of things assigned, but you do have a list of patterns which can “claim” a syntax pattern: it’s only when no protocol claims that pattern that you actually reach an error or diagnostic. I think this is a really cool thing, especially when it can exist as part of a Resolution algorithm.\r\n\r\nAnd what this gives me in return are the following interfaces for my protocols (rough, not finalized):\r\n\r\n```\r\noperator %:precedence 65 * x y -\u003e mul x y\r\nhandler (_ module . fname) do\r\n # if package contains fname, apply it\r\n # otherwise, fall through to method-missing\r\nend\r\ninspector do\r\n # not yet specced, but basically reflection on the protocol itself\r\nend\r\n```",
"sig": "441304fcf143bb8eeac407f963d1f94662a937b165a2268cc1f1fb077171227a02b076e7d47b09d9180607579e190c344a7f40b9b8c094e4d7eee63ad1e3ba70"
}