- z3.sx: SX-to-SMT-LIB translator written in SX (359 lines), replaces Python translation logic - prove.sx: SMT-LIB satisfiability checker in SX — proves all 91 primitives sat by construction - Parser: support unicode characters (em-dash, accented letters) in symbols - Auto-resolve reader macros: #name finds name-translate in component env, no Python registration - Platform primitives: type-of, symbol-name, keyword-name, sx-parse registered in primitives.py - Cond heuristic: predicates ending in ? recognized as Clojure-style tests - Library loading: z3.sx loaded at startup with reload callbacks for hot-reload ordering - reader_z3.py: rewritten as thin shell delegating to z3.sx - Split monolithic .sx files: essays (22), plans (13), reactive-islands (6) into separate files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
113 lines
24 KiB
Plaintext
113 lines
24 KiB
Plaintext
(defcomp ~essay-sx-and-dennett ()
|
|
(~doc-page :title "SX and Dennett"
|
|
(p :class "text-stone-500 text-sm italic mb-8"
|
|
"Real patterns, multiple drafts, and the intentional stance — a philosopher of mind meets a language that thinks about itself.")
|
|
(~doc-section :title "I. The intentional stance" :id "intentional-stance"
|
|
(p :class "text-stone-600"
|
|
"Daniel " (a :href "https://en.wikipedia.org/wiki/Daniel_Dennett" :class "text-violet-600 hover:underline" "Dennett") " spent fifty years arguing that the mind is not what it seems. His central method is the " (a :href "https://en.wikipedia.org/wiki/Intentional_stance" :class "text-violet-600 hover:underline" "intentional stance") " — a strategy for predicting a system's behaviour by treating it " (em "as if") " it has beliefs, desires, and intentions, whether or not it \"really\" does.")
|
|
(p :class "text-stone-600"
|
|
"There are three stances. The " (em "physical stance") " predicts from physics — voltage levels, transistor states, bytes in memory. The " (em "design stance") " predicts from how the thing was built — a thermostat turns on the heating when the temperature drops below the set point, regardless of its internal wiring. The " (em "intentional stance") " predicts from ascribed beliefs and goals — the chess program \"wants\" to protect its king, \"believes\" the centre is important.")
|
|
(p :class "text-stone-600"
|
|
"Web frameworks enforce a single stance. React's mental model is the design stance: components are functions, props go in, JSX comes out. You reason about the system by reasoning about its design. If you need the physical stance (what is actually in the DOM right now?), you reach for " (code "useRef") ". If you need the intentional stance (what does this component " (em "mean") "?), you read the documentation. Each stance requires a different tool, a different context switch.")
|
|
(p :class "text-stone-600"
|
|
"SX lets you shift stances without shifting languages. The physical stance: " (code "(div :class \"card\" (h2 \"Title\"))") " — this is exactly the DOM structure that will be produced. One list, one element. The design stance: " (code "(defcomp ~card (&key title) (div title))") " — this is how the component is built, its contract. The intentional stance: " (code "(~card :title \"Hello\")") " — this " (em "means") " \"render a card with this title,\" and you can reason about it at that level without knowing the implementation.")
|
|
(~doc-code :lang "lisp" :code
|
|
";; Physical stance — the literal structure\n(div :class \"card\" (h2 \"Title\"))\n\n;; Design stance — how it's built\n(defcomp ~card (&key title) (div :class \"card\" (h2 title)))\n\n;; Intentional stance — what it means\n(~card :title \"Title\")\n\n;; All three are s-expressions.\n;; All three can be inspected, transformed, quoted.\n;; Shifting stance = changing which expression you look at.")
|
|
(p :class "text-stone-600"
|
|
"The key insight: all three stances are expressed in the same medium. You do not need a debugger for the physical stance, a type system for the design stance, and documentation for the intentional stance. You need lists. The stances are not different tools — they are different ways of reading the same data."))
|
|
(~doc-section :title "II. Real patterns" :id "real-patterns"
|
|
(p :class "text-stone-600"
|
|
"Dennett's 1991 paper \"" (a :href "https://en.wikipedia.org/wiki/Real_Patterns" :class "text-violet-600 hover:underline" "Real Patterns") "\" makes a deceptively simple argument: a pattern is real if it lets you compress data — if recognising the pattern gives you predictive leverage that you would not have otherwise. Patterns are not " (em "in the mind") " of the observer. They are not " (em "in the object") " independently of any observer. They are real features of the world that exist at a particular level of description.")
|
|
(p :class "text-stone-600"
|
|
"Consider a bitmap of noise. If you describe it pixel by pixel, the description is as long as the image. No compression. No pattern. Now consider a bitmap of a checkerboard. You can say \"alternating black and white squares, 8x8\" — vastly shorter than the pixel-by-pixel description. The checkerboard pattern is " (em "real") ". It exists in the data. Recognising it gives you compression.")
|
|
(p :class "text-stone-600"
|
|
"Components are real patterns. " (code "(~card :title \"Hello\")") " compresses " (code "(div :class \"card\" (h2 \"Hello\"))") " — and more importantly, it compresses every instance of card-like structure across the application into a single abstraction. The component is not a convenient fiction. It is a real pattern in the codebase: a regularity that gives you predictive power. When you see " (code "~card") ", you know the structure, the styling, the contract — without expanding the definition.")
|
|
(p :class "text-stone-600"
|
|
"Macros are real patterns at a higher level. A macro like " (code "defcomp") " captures the pattern of \"name, parameters, body\" that every component shares. It compresses the regularity of component definition itself. The macro is real in exactly Dennett's sense — it captures a genuine pattern, and that pattern gives you leverage.")
|
|
(p :class "text-stone-600"
|
|
"Now here is where SX makes Dennett's argument concrete. In most languages, the reality of patterns is debatable — are classes real? Are interfaces real? Are design patterns real? You can argue either way because the patterns exist at a different level from the code. In SX, patterns " (em "are") " code. A component is a list. A macro is a function over lists. The pattern and the data it describes are the same kind of thing — s-expressions. There is no level-of-description gap. The pattern is as real as the data it compresses, because they inhabit the same ontological plane.")
|
|
(~doc-code :lang "lisp" :code
|
|
";; The data (expanded)\n(div :class \"card\"\n (h2 \"Pattern\")\n (p \"A real one.\"))\n\n;; The pattern (compressed)\n(~card :title \"Pattern\" (p \"A real one.\"))\n\n;; The meta-pattern (the definition)\n(defcomp ~card (&key title &rest children)\n (div :class \"card\" (h2 title) children))\n\n;; All three levels: data, pattern, meta-pattern.\n;; All three are lists. All three are real."))
|
|
(~doc-section :title "III. Multiple Drafts" :id "multiple-drafts"
|
|
(p :class "text-stone-600"
|
|
"In " (a :href "https://en.wikipedia.org/wiki/Consciousness_Explained" :class "text-violet-600 hover:underline" "Consciousness Explained") " (1991), Dennett proposed the " (a :href "https://en.wikipedia.org/wiki/Multiple_drafts_model" :class "text-violet-600 hover:underline" "Multiple Drafts model") " of consciousness. There is no " (a :href "https://en.wikipedia.org/wiki/Cartesian_theater" :class "text-violet-600 hover:underline" "Cartesian theater") " — no single place in the brain where \"it all comes together\" for a central observer. Instead, multiple parallel processes generate content simultaneously. Various drafts of narrative are in process at any time, some getting revised, some abandoned, some incorporated into the ongoing story. There is no master draft. There is no final audience. There is just the process of revision itself.")
|
|
(p :class "text-stone-600"
|
|
"React is a Cartesian theater. The virtual DOM is the stage. Reconciliation is the moment where \"it all comes together\" — the single canonical comparison between what was and what should be. One tree diffs against another. One algorithm produces one patch. The entire UI passes through a single bottleneck. There is a master draft, and its name is " (code "ReactDOM.render") ".")
|
|
(p :class "text-stone-600"
|
|
"SX has no theater. There are multiple drafts, genuinely parallel, with no single canonical render:")
|
|
(ul :class "list-disc pl-6 space-y-1 text-stone-600"
|
|
(li (span :class "font-semibold" "Server draft") " — Python evaluates components into SX wire format. This is a draft: it contains component calls unexpanded, slots unfilled, decisions deferred.")
|
|
(li (span :class "font-semibold" "Wire draft") " — the SX source text transmitted over HTTP. It is a draft in transit — meaningful as text, interpretable by any reader, but not yet rendered.")
|
|
(li (span :class "font-semibold" "Client draft") " — JavaScript evaluates the wire format into DOM nodes. Another draft: the browser's layout engine will revise it further (CSS computation, reflow, paint).")
|
|
(li (span :class "font-semibold" "Interaction draft") " — the user clicks, the server produces new SX, the client patches the DOM. The revision process continues. No draft is final."))
|
|
(p :class "text-stone-600"
|
|
"Each draft is a complete s-expression. Each is meaningful on its own terms. No single process \"sees\" the whole page — the server doesn't see the DOM, the client doesn't see the Python context, the browser's layout engine doesn't see the s-expressions. The page emerges from the drafting process, not from a central reconciler.")
|
|
(p :class "text-stone-600"
|
|
"This is not a metaphor stretched over engineering. It is the actual architecture. There is no virtual DOM because there is no need for a Cartesian theater. The multiple drafts model works because each draft is in the same format — s-expressions — so revision is natural. A draft can be inspected, compared, serialised, sent somewhere else, and revised further. Dennett's insight was that consciousness works this way. SX's insight is that rendering can too."))
|
|
(~doc-section :title "IV. Heterophenomenology" :id "heterophenomenology"
|
|
(p :class "text-stone-600"
|
|
(a :href "https://en.wikipedia.org/wiki/Heterophenomenology" :class "text-violet-600 hover:underline" "Heterophenomenology") " is Dennett's method for studying consciousness. Instead of asking \"what is it like to be a bat?\" — a question we cannot answer — we ask the bat to tell us, and then we study " (em "the report") ". We take the subject's testimony seriously, catalogue it rigorously, but we do not take it as infallible. The report is data. We are scientists of the report.")
|
|
(p :class "text-stone-600"
|
|
"Most programming languages cannot report on themselves. JavaScript can " (code "toString()") " a function, but the result is a string — opaque, unparseable, implementation-dependent. Python can inspect a function's AST via " (code "ast.parse(inspect.getsource(f))") " — but the AST is a separate data structure, disconnected from the running code. The language's self-report is in a different format from the language itself. Studying it requires tools, transformations, bridges.")
|
|
(p :class "text-stone-600"
|
|
"SX is natively heterophenomenological. The language's self-report " (em "is") " the language. " (code "eval.sx") " is the evaluator reporting on how evaluation works — in the same s-expressions that it evaluates. " (code "parser.sx") " is the parser reporting on how parsing works — in the same syntax it parses. You study the report by reading it. You verify the report by running it. The report and the reality are the same object.")
|
|
(~doc-code :lang "lisp" :code
|
|
";; The evaluator's self-report (from eval.sx):\n(define eval-expr\n (fn (expr env)\n (cond\n (number? expr) expr\n (string? expr) expr\n (symbol? expr) (env-get env expr)\n (list? expr) (eval-list expr env)\n :else (error \"Unknown expression type\"))))\n\n;; This is simultaneously:\n;; 1. A specification (what eval-expr does)\n;; 2. A program (it runs)\n;; 3. A report (the evaluator describing itself)\n;; Heterophenomenology without the hetero.")
|
|
(p :class "text-stone-600"
|
|
"Dennett insisted that heterophenomenology is the only honest method. First-person reports are unreliable — introspection gets things wrong. Third-person observation misses the subject's perspective. The middle path is to take the report as data and study it rigorously. SX's self-hosting spec is this middle path enacted in code: neither a first-person account (\"trust me, this is how it works\") nor a third-person observation (English prose describing the implementation), but a structured report that can be verified, compiled, and run."))
|
|
(~doc-section :title "V. Where am I?" :id "where-am-i"
|
|
(p :class "text-stone-600"
|
|
"Dennett's thought experiment \"" (a :href "https://en.wikipedia.org/wiki/Where_Am_I%3F_(Dennett)" :class "text-violet-600 hover:underline" "Where Am I?") "\" imagines his brain removed from his body, connected by radio. His body walks around; his brain sits in a vat. Where is Dennett? Where the brain is? Where the body is? The question has no clean answer because identity is not located in a single place — it is distributed across the system.")
|
|
(p :class "text-stone-600"
|
|
"Where is an SX component? On the server, it is a Python object — a closure with a body and bound environment. On the wire, it is text: " (code "(~card :title \"Hello\")") ". In the browser, it is a JavaScript function registered in the component environment. In the DOM, it is a tree of elements. Which one is the \"real\" component? All of them. None of them. The component is not located in one runtime — it is the pattern that persists across all of them.")
|
|
(p :class "text-stone-600"
|
|
"This is Dennett's point about personal identity applied to software identity. The SX component " (code "~card") " is defined in a " (code ".sx") " file, compiled by the Python bootstrapper into the server evaluator, transmitted as SX wire format to the browser, compiled by the JavaScript bootstrapper into the client evaluator, and rendered into DOM. At every stage, it is " (code "~card") ". At no single stage is it " (em "the") " " (code "~card") ". The identity is the pattern, not the substrate.")
|
|
(p :class "text-stone-600"
|
|
"Most frameworks bind component identity to a substrate. A React component is a JavaScript function. Full stop. It cannot exist outside the JavaScript runtime. Its identity is its implementation. SX components have substrate independence — the same definition runs on any host that implements the SX platform interface. The component's identity is its specification, not its execution."))
|
|
(~doc-section :title "VI. Competence without comprehension" :id "competence"
|
|
(p :class "text-stone-600"
|
|
"Dennett argued in " (a :href "https://en.wikipedia.org/wiki/From_Bacteria_to_Bach_and_Back" :class "text-violet-600 hover:underline" "From Bacteria to Bach and Back") " (2017) that evolution produces " (em "competence without comprehension") ". Termites build elaborate mounds without understanding architecture. Neurons produce consciousness without understanding thought. The competence is real — the mound regulates temperature, the brain solves problems — but there is no comprehension anywhere in the system. No termite has a blueprint. No neuron knows it is thinking.")
|
|
(p :class "text-stone-600"
|
|
"A macro is competence without comprehension. " (code "defcomp") " expands into a component registration — it " (em "does") " the right thing — but it does not \"know\" what a component is. It is a pattern-matching function on lists that produces other lists. The expansion is mechanical, local, uncomprehending. Yet the result is a fully functional component that participates in the rendering pipeline, responds to props, composes with other components. Competence. No comprehension.")
|
|
(~doc-code :lang "lisp" :code
|
|
";; defcomp is a macro — mechanical list transformation\n(defmacro defcomp (name params &rest body)\n `(define ,name (make-component ,params ,@body)))\n\n;; It does not \"understand\" components.\n;; It rearranges symbols according to a rule.\n;; The resulting component works perfectly.\n;; Competence without comprehension.")
|
|
(p :class "text-stone-600"
|
|
"The bootstrap compiler is another level of the same phenomenon. " (code "bootstrap_js.py") " reads " (code "eval.sx") " and emits JavaScript. It does not understand SX semantics — it applies mechanical transformation rules to s-expression ASTs. Yet its output is a correct, complete SX evaluator. The compiler is competent (it produces working code) without being comprehending (it has no model of what SX expressions mean).")
|
|
(p :class "text-stone-600"
|
|
"Dennett used this insight to deflate the mystery of intelligence: you do not need a homunculus — a little man inside the machine who \"really\" understands — you just need enough competence at each level. SX embodies this architecturally. No part of the system comprehends the whole. The parser does not know about rendering. The evaluator does not know about HTTP. The bootstrap compiler does not know about the DOM. Each part is a competent specialist. The system works because the parts compose, not because any part understands the composition."))
|
|
(~doc-section :title "VII. Intuition pumps" :id "intuition-pumps"
|
|
(p :class "text-stone-600"
|
|
"Dennett called his thought experiments \"" (a :href "https://en.wikipedia.org/wiki/Intuition_pump" :class "text-violet-600 hover:underline" "intuition pumps") "\" — devices for moving your intuitions from one place to another, making the unfamiliar familiar by analogy. Not proofs. Not arguments. Machines for changing how you see.")
|
|
(p :class "text-stone-600"
|
|
"SX components are intuition pumps. A " (code "defcomp") " definition is not just executable code — it is a device for showing someone what a piece of UI " (em "is") ". Reading " (code "(defcomp ~card (&key title &rest children) (div :class \"card\" (h2 title) children))") " tells you the contract, the structure, and the output in a single expression. It pumps your intuition about what \"card\" means in this application.")
|
|
(p :class "text-stone-600"
|
|
"Compare this to a React component:")
|
|
(~doc-code :lang "lisp" :code
|
|
";; React: you must simulate the runtime in your head\nfunction Card({ title, children }) {\n return (\n <div className=\"card\">\n <h2>{title}</h2>\n {children}\n </div>\n );\n}\n\n;; SX: the definition IS the output\n(defcomp ~card (&key title &rest children)\n (div :class \"card\"\n (h2 title)\n children))")
|
|
(p :class "text-stone-600"
|
|
"The React version requires you to know that JSX compiles to createElement calls, that className maps to the class attribute, that curly braces switch to JavaScript expressions, and that the function return value becomes the rendered output. You must simulate a compiler in your head. The SX version requires you to know that lists are expressions and keywords are attributes. The gap between the definition and what it produces is smaller. The intuition pump is more efficient — fewer moving parts, less machinery between the reader and the meaning.")
|
|
(p :class "text-stone-600"
|
|
"Dennett valued intuition pumps because philosophy is full of false intuitions. The Cartesian theater feels right — of course there is a place where consciousness happens. But it is wrong. Intuition pumps help you " (em "see") " that it is wrong by giving you a better picture. SX is an intuition pump for web development: of course you need a build step, of course you need a virtual DOM, of course you need separate languages for structure and style and behaviour. But you don't. The s-expression is the better picture."))
|
|
(~doc-section :title "VIII. The Joycean machine" :id "joycean-machine"
|
|
(p :class "text-stone-600"
|
|
"In Consciousness Explained, Dennett describes the brain as a \"" (a :href "https://en.wikipedia.org/wiki/Consciousness_Explained" :class "text-violet-600 hover:underline" "Joycean machine") "\" — a virtual machine running on the parallel hardware of the brain, producing the serial narrative of conscious experience. Just as a word processor is a virtual machine running on silicon, consciousness is a virtual machine running on neurons. The virtual machine is real — it does real work, produces real effects — even though it is implemented in a substrate that knows nothing about it.")
|
|
(p :class "text-stone-600"
|
|
"SX is a Joycean machine running on the web. The web's substrate — TCP/IP, HTTP, the DOM, JavaScript engines — knows nothing about s-expressions, components, or evaluators. Yet the SX virtual machine runs on this substrate, producing real pages, real interactions, real applications. The substrate provides the physical-stance machinery. SX provides the intentional-stance narrative: this is a card, this is a page, this is a layout, this composes with that.")
|
|
(p :class "text-stone-600"
|
|
"The deeper parallel: Dennett argued that the Joycean machine is " (em "not an illusion") ". The serial narrative of consciousness is not fake — it is the real output of real processing, even though the underlying hardware is parallel and narrativeless. Similarly, SX's component model is not a convenient fiction layered over \"real\" HTML. It is the real structure of the application. The components are the thing. The HTML is the substrate, not the reality.")
|
|
(p :class "text-stone-600"
|
|
"And like Dennett's Joycean machine, SX's virtual machine can reflect on itself. It can inspect its own running code, define its own evaluator, test its own semantics. The virtual machine is aware of itself — not in the sense of consciousness, but in the functional sense of self-modelling. The spec models the evaluator. The evaluator runs the spec. The virtual machine contains a description of itself, and that description works."))
|
|
(~doc-section :title "IX. Quining" :id "quining"
|
|
(p :class "text-stone-600"
|
|
"Dennett borrowed the term \"" (a :href "https://en.wikipedia.org/wiki/Qualia#Dennett's_criticism" :class "text-violet-600 hover:underline" "quining") "\" from the logician " (a :href "https://en.wikipedia.org/wiki/Willard_Van_Orman_Quine" :class "text-violet-600 hover:underline" "W. V. O. Quine") " — a philosopher who argued that many seemingly deep concepts dissolve under scrutiny. Dennett \"quined\" qualia — the supposedly irreducible subjective qualities of experience — arguing that they are not what they seem, that the intuition of an inner experiential essence is a philosophical illusion.")
|
|
(p :class "text-stone-600"
|
|
"The concept of a \"" (a :href "https://en.wikipedia.org/wiki/Quine_(computing)" :class "text-violet-600 hover:underline" "quine") "\" in computing is related: a program that outputs its own source code. The word honours the same Quine, for the same reason — self-reference that collapses the distinction between describer and described.")
|
|
(p :class "text-stone-600"
|
|
"SX quines in both senses. In the computing sense: the self-hosting spec is a quine-like structure — " (code "eval.sx") " is an SX program that, when compiled and run, produces an evaluator capable of running " (code "eval.sx") ". It is not a literal quine (it doesn't output itself character-for-character), but it has the essential quine property: the output contains the input.")
|
|
(p :class "text-stone-600"
|
|
"In Dennett's philosophical sense: SX quines the web's qualia. The supposedly irreducible essences of web development — \"components,\" \"state,\" \"the DOM,\" \"the server-client boundary\" — dissolve under SX's scrutiny into what they always were: data structures. Lists of symbols. Expressions that evaluate to other expressions. The qualia of web development are not irreducible. They are patterns in s-expressions, and once you see that, you cannot unsee it.")
|
|
(p :class "text-stone-600"
|
|
"Dennett's lifelong project was to show that the mind is not what our intuitions say it is — that consciousness, free will, and the self are real phenomena that do not require the metaphysical foundations we instinctively assign them. They are " (a :href "https://en.wikipedia.org/wiki/Real_Patterns" :class "text-violet-600 hover:underline" "real patterns") " in physical processes, not ghostly essences hovering above matter.")
|
|
(p :class "text-stone-600"
|
|
"SX makes the same move for the web. Components are real patterns, not framework essences. The server-client boundary is a draft boundary, not an ontological divide. The build step is a habit, not a necessity. The virtual DOM is a Cartesian theater, not a requirement. Strip away the false intuitions, and what remains is what was always there: expressions, evaluation, and composition. All the way down."))))
|