{"id":46,"date":"2026-04-15T00:50:58","date_gmt":"2026-04-15T00:50:58","guid":{"rendered":"https:\/\/llama.gs\/blog\/?p=46"},"modified":"2026-04-15T00:53:21","modified_gmt":"2026-04-15T00:53:21","slug":"teaching-a-language-to-think-in-hierarchies","status":"publish","type":"post","link":"https:\/\/llama.gs\/blog\/index.php\/2026\/04\/15\/teaching-a-language-to-think-in-hierarchies\/","title":{"rendered":"Teaching a Language to Think in Hierarchies"},"content":{"rendered":"<p>Bitcoin miners are <a href=\"https:\/\/www.cryptopolitan.com\/anthropic-broadcom-bitcoin-miners-ai-pivot\/\">liquidating their holdings to pivot into AI hosting<\/a>. The machines that wasted electricity producing imaginary money will now waste it producing imaginary intelligence. Anthropic has secured <a href=\"https:\/\/www.theregister.com\/2026\/04\/07\/broadcom_google_chip_deal_anthropic_customer\/\">3.5 gigawatts of compute<\/a> \u2014 the consumption of three and a half million households \u2014 to serve language models.<\/p>\n<p>GCC compiles the entire Linux kernel in fifteen minutes on a single machine drawing 200 watts. Fifty watt-hours. A light bulb left on for an afternoon. It manages this because it is not guessing. It has a grammar, a type system, and an optimisation pipeline where every transformation preserves semantics. There is no temperature parameter. There is no &#8220;try again and hope.&#8221;<\/p>\n<p>A compiler&#8217;s cost is \\(O(n \\log n)\\) in the size of the input. A language model&#8217;s cost is \\(O(n \\cdot d)\\) where \\(d\\) is the dimensionality of a model that cannot tell you whether the answer is correct. When the task has a formal specification, you do not need gigawatts. You need a parser.<\/p>\n<p>I have been writing parsers for twenty years. Today I started improving the one that matters most: the circuit description language at the heart of <a href=\"https:\/\/gitlab.llama.gs\/logic\/llogic\">llogic<\/a>, <a href=\"https:\/\/gitlab.llama.gs\/logic\/qbf-designer\">qbf-designer<\/a>, and the formal methods toolchain I am building at <a href=\"https:\/\/llama.gs\">Llama Logic<\/a>.<\/p>\n<p>My first encounter with a compiler was at <a href=\"https:\/\/en.wikipedia.org\/wiki\/Zend_Technologies\">Zend Technologies<\/a> in Ramat Gan in 2000. I was twenty-two, fresh off the plane from Bulgaria, and I did not know what a parser was. Zend built the PHP language engine. I watched a small team turn a grammar into a working language that ran half the web. I did not understand how.<\/p>\n<p>A few years later, at <a href=\"https:\/\/en.wikipedia.org\/wiki\/Delft_University_of_Technology\">Delft<\/a>, I read the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Compilers:_Principles,_Techniques,_and_Tools\">Dragon Book<\/a> and took the compiler construction course of Koen Langendoen. We became friends over my many years at the university. That course turned out to be one of the most useful things I have ever learned. It is the skill that lets me write software that works \u2014 not approximately, not statistically, not when the vibes are right, but deterministically, on all inputs, by construction.<\/p>\n<p>It is also how I got into diagnosis. At the end of my master&#8217;s I went to Koen and asked for a Ph.D. position in compiler construction. He told me &#8220;compilers are pass\u00e9&#8221; \u2014 but I could go work with Arjan J.C. van Gemund doing diagnostics. Arjan has since retired north to compose music, which is a better use of a fine mind than supervising Ph.D. students, though he was good at both. They needed a compiler for <a href=\"https:\/\/gitlab.llama.gs\/constraints\/lydia\">LyDiA<\/a>, the diagnostic modelling language. So I built one. Then I built many more. Every research system I have worked on since \u2014 LyDiA, the DXC framework at NASA Ames, the synthesis tools at PARC, and now llogic \u2014 has a parser at its core. The compiler is never the point. The compiler is always the point.<\/p>\n<p>A domain-specific language is a small language built for one job. SQL is a DSL for databases. Regular expressions are a DSL for pattern matching. Makefiles are a DSL for build dependencies. You do not write an operating system in SQL. You do not query a database with a Makefile. The language fits the problem, and because it fits, it can enforce constraints that a general-purpose language cannot.<\/p>\n<p>This is the point that the vibe-coding movement misses entirely. A grammar is not a convenience. It is a contract. When I write a parser for a circuit description language, the grammar specifies exactly what constitutes a valid circuit. If you misspell a gate type, the parser rejects your input. If you connect an output to a nonexistent signal, the parser tells you. If you instantiate a module that does not exist, you get an error message with a line number \u2014 not a plausible-looking circuit that silently computes the wrong function.<\/p>\n<p>This is what determinism means in practice. The parser either accepts or rejects. There is no 95% confidence. There is no temperature. The same input produces the same result every time, on every machine, for every user. A <a href=\"https:\/\/en.wikipedia.org\/wiki\/True_quantified_Boolean_formula\">QBF solver<\/a> receiving a malformed netlist will produce garbage. A diagnosis engine receiving an inconsistent model will compute meaningless results. The parser is the gate that keeps garbage out. It costs milliwatts. It works.<\/p>\n<p>There is a second reason, less often discussed. Humans need to read these things. An engineer debugging a faulty adder needs to look at the circuit description and understand it. A reviewer verifying a synthesis result needs to confirm that the specification matches the intent. This is not a machine-to-machine format. It is a language \u2014 with the same design obligations as any language: clarity, consistency, and the ability to say exactly what you mean and nothing else.<\/p>\n<p>The circuit DSL in llogic had outgrown its grammar. The new format adds modules, arrays, imports, and arbitrary nesting. A full adder, from primitives to a 4-bit module with array slicing:<\/p>\n<pre><code class=\"lang-llogic-circ\" data-line=\"\"># 4-bit ripple carry adder\n\nimport &quot;std_logic.circ&quot;\n\nmodule half_adder(input a, b; output s, c):\n    x: s = xor(a, b)\n    a: c = and(a, b)\nend\n\nmodule full_adder(input a, b, ci; output s, co):\n    wire f, p, q\n\n    inst half_adder ha1(a=a, b=b, s=f, c=p)\n    inst half_adder ha2(a=ci, b=f, s=s, c=q)\n    o: co = or(p, q)\nend\n\nmodule adder2(input a[2], b[2], ci; output s[2], co):\n    wire c0\n\n    inst full_adder bit0(a=a[0], b=b[0], ci=ci, s=s[0], co=c0)\n    inst full_adder bit1(a=a[1], b=b[1], ci=c0, s=s[1], co=co)\nend\n\nmodule adder4(input a[4], b[4], ci; output s[4], co):\n    wire cm\n\n    inst adder2 lo(a=a[0:1], b=b[0:1], ci=ci, s=s[0:1], co=cm)\n    inst adder2 hi(a=a[2:3], b=b[2:3], ci=cm, s=s[2:3], co=co)\nend<\/code><\/pre>\n<p>Four levels of nesting. Modules, arrays, slices, named connections. The flattener \u2014 a recursive tree walk, the same algorithm I used in LyDiA for system descriptions \u2014 traverses the instantiation tree and emits the flat netlist the solver has always consumed. The hierarchy is for the engineer. The solver does not know it exists.<\/p>\n<p>Sequential circuits work the same way. A 4-bit serial adder with synchronous reset:<\/p>\n<pre><code class=\"lang-llogic-circ\" data-line=\"\"># 4-bit serial adder with synchronous reset\n\nmodule shift4(input d, rst; output q):\n    wire d1, d2, d3\n\n    f1: d1 = dff(d, rst)\n    f2: d2 = dff(d1, rst)\n    f3: d3 = dff(d2, rst)\n    f4: q = dff(d3, rst)\nend\n\nmodule seq_adder4(input a, b, rst; output s, co):\n    wire i1, i2, ci\n\n    inst shift4 sa(d=a, rst=rst, q=i1)\n    inst shift4 sb(d=b, rst=rst, q=i2)\n    inst full_adder fa(a=i1, b=i2, ci=ci, s=s, co=co)\n    c: ci = dff(co, rst)\nend<\/code><\/pre>\n<p>A <code class=\"\" data-line=\"\">dff<\/code> with one argument is a plain register. Two arguments: synchronous reset. This maps directly to the standard Verilog template <code class=\"\" data-line=\"\">always @(posedge clk) if (rst) q &lt;= 0; else q &lt;= d;<\/code> \u2014 making translation between the two languages mechanical.<\/p>\n<p>So why not just use Verilog?<\/p>\n<p>Because Verilog is a simulation language that has been coerced into serving as a synthesis input. A synthesis tool reads an <code class=\"\" data-line=\"\">always<\/code> block, pattern-matches the sensitivity list, and <em>infers<\/em> what is a register and what is combinational logic. The engineer writes behaviour and hopes the tool&#8217;s heuristics match their intent. In llogic, a <code class=\"\" data-line=\"\">dff<\/code> is a <code class=\"\" data-line=\"\">dff<\/code>. An <code class=\"\" data-line=\"\">and<\/code> is an <code class=\"\" data-line=\"\">and<\/code>. There is no inference. The circuit says what it is.<\/p>\n<p>This matters for formal methods. Diagnosis requires knowing exactly what components exist. Synthesis requires a precise specification of the design space. Neither tolerates a language that hides structure behind inference rules. Verilog is the right language for RTL designers who want to describe behaviour and let tools figure out the structure. Llogic is the right language when the structure <em>is<\/em> the point.<\/p>\n<p>The parser, AST, and flattener should take a few days. When they are done I will update the <a href=\"https:\/\/gitlab.llama.gs\/logic\/llogic\">llogic repository<\/a> on the <code class=\"\" data-line=\"\">feature\/hierarchical-dsl<\/code> branch.<\/p>\n<p>Three and a half million households&#8217; worth of electricity to serve a model that <a href=\"https:\/\/www.theregister.com\/2026\/04\/13\/claude_outage_quality_complaints\/\">cannot tell whether it is thinking deeply or not<\/a>. Fifty watt-hours to compile a kernel. Considerably less to parse a circuit. The tools that work have always been quiet, small, and correct. The software will continue to not hallucinate.<\/p>\n<p><em>Ceterum censeo slopem esse delendam.<\/em><\/p>\n<p>(Cato the Elder ended every speech in the Roman Senate with &#8220;Carthage must be destroyed&#8221; \u2014 regardless of the topic. This is that, but for AI slop.)<\/p>\n<p><strong>Repository:<\/strong> <a href=\"https:\/\/gitlab.llama.gs\/logic\/llogic\">llogic<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Bitcoin miners are liquidating their holdings to pivot into AI hosting. The machines that wasted electricity producing imaginary money will now waste it producing imaginary intelligence. Anthropic has secured 3.5 gigawatts of compute \u2014 the consumption of three and a half million households \u2014 to serve language models. GCC compiles the entire Linux kernel in [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,17,18,1],"tags":[35,36,37,38],"class_list":["post-46","post","type-post","status-publish","format-standard","hentry","category-computer-science-and-philosophy","category-projects","category-research","category-uncategorized","tag-compilers","tag-dsl","tag-logic","tag-parsing"],"_links":{"self":[{"href":"https:\/\/llama.gs\/blog\/index.php\/wp-json\/wp\/v2\/posts\/46","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/llama.gs\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/llama.gs\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/llama.gs\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/llama.gs\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=46"}],"version-history":[{"count":9,"href":"https:\/\/llama.gs\/blog\/index.php\/wp-json\/wp\/v2\/posts\/46\/revisions"}],"predecessor-version":[{"id":55,"href":"https:\/\/llama.gs\/blog\/index.php\/wp-json\/wp\/v2\/posts\/46\/revisions\/55"}],"wp:attachment":[{"href":"https:\/\/llama.gs\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=46"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/llama.gs\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=46"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/llama.gs\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=46"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}