<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://gwaithimirdain.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://gwaithimirdain.github.io/" rel="alternate" type="text/html" /><updated>2026-06-02T18:40:18+00:00</updated><id>https://gwaithimirdain.github.io/feed.xml</id><title type="html">Gwaith-i-Mírdain</title><subtitle>The Jewel-smiths of Eregion.</subtitle><entry><title type="html">Modal datatypes and codatatypes</title><link href="https://gwaithimirdain.github.io/2026/06/02/modal-data-and-codata.html" rel="alternate" type="text/html" title="Modal datatypes and codatatypes" /><published>2026-06-02T00:00:00+00:00</published><updated>2026-06-02T00:00:00+00:00</updated><id>https://gwaithimirdain.github.io/2026/06/02/modal-data-and-codata</id><content type="html" xml:base="https://gwaithimirdain.github.io/2026/06/02/modal-data-and-codata.html"><![CDATA[<p>In multimodal Narya, the modal operators are not built in, but rather are defined by the user as special cases of modal datatypes and codata/record types (just as Σ-types, for instance, are user-defined as particular record types).  However, I’m running into some interesting questions of notation and typechecking when specifying these.</p>

<h2 id="modal-datatypes">Modal datatypes</h2>

<p>Like most type formers, modal operators can be classified as positive or negative.  The positive ones are simpler and were the only ones included in the original <a href="https://arxiv.org/abs/2011.15021">multimodal dependent type theory</a>.  If <code class="language-plaintext highlighter-rouge">□</code> is a positive modal operator, the idea is that a variable of type <code class="language-plaintext highlighter-rouge">□ A</code> can be “destructed” into an ordinary variable of type <code class="language-plaintext highlighter-rouge">A</code> that is annotated by the modality (corresponding to) <code class="language-plaintext highlighter-rouge">□</code>.  In premise-conclusion type theory syntax, this is written as follows (from the MTT paper):</p>

<p><img src="/images/positive-modal-simple-elim.png" alt="Image" /></p>

<p>The main thing to note is how we replace the element <code class="language-plaintext highlighter-rouge">M₀</code> of the modal type <code class="language-plaintext highlighter-rouge">⟨μ|A⟩</code> by a variable <code class="language-plaintext highlighter-rouge">y</code> that belongs to <code class="language-plaintext highlighter-rouge">A</code> but is annotated with the modality <code class="language-plaintext highlighter-rouge">μ</code>.</p>

<p>In multimodal Narya, positive modalities are not built-in, but can be defined by the user as a special case of a <em>datatype with modal constructor(s)</em>.  More generally, <em>any</em> of the arguments of a constructor can be annotated with a nontrivial modality, in which case when we match against that constructor, the pattern variable corresponding to that argument becomes similarly annotated.  For instance, here’s a definition of an ordinary positive modal operator:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def □ (A :□| Type) : Type ≔ data [
| box. (x :□| A) ]
</code></pre></div></div>

<p>There is some punning going on here: the <code class="language-plaintext highlighter-rouge">□</code> in the annotations <code class="language-plaintext highlighter-rouge">:□|</code> is the name of a modality (a morphism in the mode theory 2-category), which lives in a different namespace from user-defined constants, while the <code class="language-plaintext highlighter-rouge">□</code> being defined is a user-defined constant (a modal datatype).  I regard the possibility of such punning as a <em>good</em> argument for this notation for modal variable annotations, although of course it allows the user to shoot themselves in the foot by creating mismatches instead.</p>

<p>Given this definition, here is the proof that <code class="language-plaintext highlighter-rouge">□</code> is functorial:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def □map (A B :□| Type) (f :□| A → B) (u : □ A) : □ B ≔ match u [
| box. x ↦ box. (f x) ]
</code></pre></div></div>

<p>In the single branch of this match, the variable <code class="language-plaintext highlighter-rouge">x</code> is <code class="language-plaintext highlighter-rouge">□</code>-annotated.  Therefore, since <code class="language-plaintext highlighter-rouge">f</code> is also <code class="language-plaintext highlighter-rouge">□</code>-annotated, <code class="language-plaintext highlighter-rouge">f x</code> is also, and thus we can apply the constructor <code class="language-plaintext highlighter-rouge">box.</code> to it.  (More precisely, the argument of the constructor <code class="language-plaintext highlighter-rouge">box.</code> is checked in a <code class="language-plaintext highlighter-rouge">□</code>-locked context, and we can access <code class="language-plaintext highlighter-rouge">f</code> and <code class="language-plaintext highlighter-rouge">x</code> in that context because their annotation matches the lock.)</p>

<p>This is great, but to get all the desired behavior of modal operators in general we need a stronger version of their elimination rule:</p>

<p><img src="/images/positive-modal-elim.png" alt="Image" /></p>

<p>The difference here is that the term <code class="language-plaintext highlighter-rouge">M₀</code> in the modal type <code class="language-plaintext highlighter-rouge">⟨μ|A⟩</code> is in a context that’s locked by some other modality <code class="language-plaintext highlighter-rouge">ν</code>, and then the variable <code class="language-plaintext highlighter-rouge">x</code> that it’s destructed into is annotated by the composite modality <code class="language-plaintext highlighter-rouge">ν ∘ μ</code>.  This generality is necessary, for instance, when proving that modal types depend functorially on modes: if <code class="language-plaintext highlighter-rouge">μ</code> and <code class="language-plaintext highlighter-rouge">ν</code> are composable modalities, then to define a map from <code class="language-plaintext highlighter-rouge">⟨ ν | ⟨μ|A⟩ ⟩</code> to <code class="language-plaintext highlighter-rouge">⟨ ν ∘ μ | A ⟩</code> we first destruct on <code class="language-plaintext highlighter-rouge">ν</code>, and then we get an element of <code class="language-plaintext highlighter-rouge">⟨μ|A⟩</code> annotated by <code class="language-plaintext highlighter-rouge">ν</code> and we have to destruct that, requiring the above generalized elimination rule.  This extra modality <code class="language-plaintext highlighter-rouge">ν</code> is sometimes called a “window” modality because we “look through it” to find the modality <code class="language-plaintext highlighter-rouge">μ</code> to destruct.</p>

<p>The question is, (how) should the window modality should be notated in a Narya <code class="language-plaintext highlighter-rouge">match</code>?  If we are matching against a free variable, there is no need to notate it at all, since the context annotation on that variable must also be the window modality.  But Narya also allows matches on arbitrary terms, and in that case the term doesn’t determine the window modality; indeed, we can’t even <em>typecheck</em> the term until we <em>know</em> the window modality.</p>

<p>Here are some possibilities I can think of for notating a window modality <code class="language-plaintext highlighter-rouge">◇</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>match (M :◇| _) [ box. x ↦ ? ]
match M :◇| _ [ box. x ↦ ? ]
match M return (_ :◇| _) ↦ _ [ box. x ↦ ? ]
match M through ◇ [ box. x ↦ ? ]
match M under ◇ [ box. x ↦ ? ]
match M behind ◇ [ box. x ↦ ? ]
</code></pre></div></div>

<p>The first three don’t require any new keywords, only re-using the same variable annotation syntax.  (The <code class="language-plaintext highlighter-rouge">return</code> clause is necessary for a dependent match against a non-variable term anyway, and is allowed for non-dependent matches with a <code class="language-plaintext highlighter-rouge">_</code> as the output.)  These three syntaxes seem logical to me, but I think they’re also a bit ugly.  The discriminee of a match must synthesize a datatype, so under normal circumstances it would never need to be ascribed; so we can put a <code class="language-plaintext highlighter-rouge">_</code> there as the type, but that looks noisy.  We could allow putting the actual type there instead too, of course, but that would nearly always be redundant information.</p>

<p>The last three look less ugly to me, but they all involve introducing a new keyword such as <code class="language-plaintext highlighter-rouge">through</code>, <code class="language-plaintext highlighter-rouge">under</code>, or <code class="language-plaintext highlighter-rouge">behind</code>.</p>

<p>Anyone have any opinions?</p>

<h2 id="modal-codata-and-record-types">Modal codata and record types</h2>

<p>Negative modalities were introduced to an MTT-like theory in <a href="https://dl.acm.org/doi/10.1145/3514241">Modalities and Parametric Adjoints</a>, and appear to require more structure on the relevant modality.  The original paper used a parametric right adjoint, but using ordinary adjoints is simpler and covers the majority of examples, and that’s what I’m planning for multimodal Narya.  In this case, the rules as I wrote them in <a href="https://arxiv.org/abs/2303.02572">Semantics of multimodal adjoint type theory</a> are:</p>

<p><img src="/images/negative-modal-intro.png" alt="Image" /></p>

<p><img src="/images/negative-modal-elim.png" alt="Image" /></p>

<p>To be “sinister”, a modality <code class="language-plaintext highlighter-rouge">μ</code> must have a right adjoint <code class="language-plaintext highlighter-rouge">μ†</code>.  The first, introduction, rule, is then the same as that for the positive modality associated to <code class="language-plaintext highlighter-rouge">μ†</code>; but the elimination rule uses <code class="language-plaintext highlighter-rouge">μ</code> instead.</p>

<p>In multimodal Narya, negative modalities are also not built-in, but can be defined by the user as a special case of a <em>codata or record type with modal fields</em>.  And more generally, any of the fields of a codata or record type can be annotated by an adjunction of modalities.</p>

<p>But since there are two modalities in an adjunction, it’s already not entirely obvious how to notate the <em>definition</em> of such a codatatype.  If the adjunction is <code class="language-plaintext highlighter-rouge">♭ ⊣ ♯</code> as in spatial type theory, then we could annotate the “self variable” of the field by the left adjoint <code class="language-plaintext highlighter-rouge">♭</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def ♯ (A : Type) : Type ≔ codata [
| (x :♭| _) .unsharp : A ]
</code></pre></div></div>

<p>The annotation by <code class="language-plaintext highlighter-rouge">♭</code> makes sense because in the elimination rule, i.e. when projecting out the field of an element of <code class="language-plaintext highlighter-rouge">♯ A</code>, that element must be in a <code class="language-plaintext highlighter-rouge">♭</code>-locked context.  Annotating the self variable with its type is not currently allowed, but it would also be required if we wanted to implement “indexed codatatypes”.</p>

<p>However, we could instead try to annotate the <em>output</em> by the <em>right</em> adjoint:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def ♯ (A : Type) : Type ≔ codata [
| x .unsharp :♯| A ]
</code></pre></div></div>

<p>This annotation makes sense because in the <em>introduction</em> rule, i.e. when defining an element of <code class="language-plaintext highlighter-rouge">♯ A</code>, the value of <code class="language-plaintext highlighter-rouge">.usharp</code> must be defined in a <code class="language-plaintext highlighter-rouge">♯</code>-locked context, i.e. it “has type” <code class="language-plaintext highlighter-rouge">:♯| A</code>.</p>

<p>One problem with the second version is that the <code class="language-plaintext highlighter-rouge">:♯|</code> notation conflicts with the use of <code class="language-plaintext highlighter-rouge">|</code> to separate multiple fields of a codatatype, especially if the modality <code class="language-plaintext highlighter-rouge">♯</code> is replaced by a composite of named generating modalities, or has a longer name.  This seems like a poor reason to reject it in the abstract (since we could change that notation instead), but we need <em>some</em> reason to choose one or the other.</p>

<p>Anyway, there’s a more serious problem with modal codatatypes.  In Narya, field names are not scoped: when you write <code class="language-plaintext highlighter-rouge">x .fst</code>, Narya doesn’t know what codata or record type <code class="language-plaintext highlighter-rouge">fst</code> refers to until it synthesizes a type for <code class="language-plaintext highlighter-rouge">x</code> and inspects its definition.  This generally works perfectly with bidirectional type checking, and means you can freely use fields of the same name for different record types without any worry about whether they will conflict or which of them is “opened” at any time.  (Similarly, constructors don’t know what datatype they belong to, and hence must always be used in a checking context.)</p>

<p>However, in order to synthesize a type for <code class="language-plaintext highlighter-rouge">x</code>, Narya needs to know its <em>context</em>.  And in the case of a modal field, the element being projected out of is supposed to be typechecked/synthesized in a <em>locked</em> context.  So how should Narya figure out the modality to lock by?</p>

<p>One option would be to continue overloading modal ascription syntax:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(x :♭| _) .unsharp
</code></pre></div></div>

<p>This has the same pros and cons as the similar syntaxes for window modalities in <code class="language-plaintext highlighter-rouge">match</code>, above.</p>

<p>Another option would be to incorporate the modality in the name of the field:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x .♭.unsharp
</code></pre></div></div>

<p>Adding information to field names (which never contain internal periods themselves) has some precedent in the syntax for higher coinductive types (and although that syntax is arguably ugly itself, I haven’t thought of anything better).  And we could also use this in defining modal codatatypes:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def ♯ (A : Type) : Type ≔ codata [
| x .♭.unsharp : A ]
</code></pre></div></div>

<p>However, if we did this, there would be a potential conflict with higher coinduction: a field declaration like <code class="language-plaintext highlighter-rouge">.♭.ee</code> could mean either a <code class="language-plaintext highlighter-rouge">♭</code>-modal field named <code class="language-plaintext highlighter-rouge">ee</code> or an <code class="language-plaintext highlighter-rouge">ee</code>-dimensional higher field named <code class="language-plaintext highlighter-rouge">♭</code> (both dimension letters and modality names belong to different namespaces than field names).  The latter could be disambiguated by <code class="language-plaintext highlighter-rouge">.♭..e.e</code>, though, so we could default <code class="language-plaintext highlighter-rouge">.♭.ee</code> to mean the former (and I think actual ambiguity would be exceedingly unlikely to arise in practice).</p>

<p>Finally, another approach would be to try to synthesize “just enough” of <code class="language-plaintext highlighter-rouge">x</code> to find which codatatype it belongs to, and then inspect that to find the modality to lock its context to actually synthesize the whole thing.  However, in general “just enough” couldn’t be guaranteed to be any less work than synthesizing the whole thing, so it seems like this could add significant extra overhead to typechecking.</p>

<p>We could probably manage it so that if <code class="language-plaintext highlighter-rouge">x</code> synthesizes fully in an unlocked context (as for an ordinary non-modal field), it doesn’t need to be synthesized <em>twice</em>, so this wouldn’t impact performance of non-modal fields.  But if we did take this approach, it would probably be a good idea to also allow something like <code class="language-plaintext highlighter-rouge">(x :♭| _) .unsharp</code>, to allow the user to eliminate the double typechecking and improve performance with an explicit annotation.</p>

<p>Anyone have any thoughts?</p>]]></content><author><name></name></author><summary type="html"><![CDATA[In multimodal Narya, the modal operators are not built in, but rather are defined by the user as special cases of modal datatypes and codata/record types (just as Σ-types, for instance, are user-defined as particular record types). However, I’m running into some interesting questions of notation and typechecking when specifying these.]]></summary></entry><entry><title type="html">Well-scoped syntax and type-level categories</title><link href="https://gwaithimirdain.github.io/2026/05/30/well-scoped-syntax.html" rel="alternate" type="text/html" title="Well-scoped syntax and type-level categories" /><published>2026-05-30T00:00:00+00:00</published><updated>2026-05-30T00:00:00+00:00</updated><id>https://gwaithimirdain.github.io/2026/05/30/well-scoped-syntax</id><content type="html" xml:base="https://gwaithimirdain.github.io/2026/05/30/well-scoped-syntax.html"><![CDATA[<p>In coding Narya, one of my general principles is to use types as much as possible to eliminate the possibility of errors statically (that is, at compile time).  Which is, of course, what types are for, from a programming perspective.</p>

<p>In a fully dependently-typed language, it’s theoretically possible to eliminate <em>all</em> errors statically.  If you can write a sufficiently detailed type for a function that basically says “this function does exactly what it’s supposed to do”, then as soon as you define a function of that type that compiles successfully, you can be absolutely sure (at least insofar as you trust the compiler) that it will, in fact, do exactly what it’s supposed to do.  There are various problems with this theoretical dream, but I still find it useful as an ideal touchstone of typed programming.</p>

<p>One of the reasons we often can’t achieve that dream is that we may not be programming in a fully dependently typed language.  Whether it’s practical yet to write large-scale code in an actually dependently typed language is a discussion for another day; suffice it for now to say that at present I am not.  Narya is written in OCaml, a language which is in many ways a joy to program in, but it is not fully dependently typed: in general, types can’t depend on terms.  However, types can depend on <em>other types</em>, and the type system of OCaml is flexible enough that we can encode a whole separate layer of “type-level terms” for our types to depend on.</p>

<p>This is a well-known technique in OCaml (and other languages that support it, like Haskell).  I’m using it for lots of things in Narya, but one of the most important is <em>static scoping</em>.</p>

<h2 id="well-scoped-indices">Well-scoped indices</h2>

<p>Like many implementations of type theory, Narya represents variables (in typechecked terms) by <a href="https://en.wikipedia.org/wiki/De_Bruijn_index">De Bruijn indices</a>.  However, in Narya all De Bruijn indices are all <em>intrinsically well-scoped</em>.  That is, it’s impossible for the code to accidentally create a De Bruijn index that’s too large and points outside all the enclosing binders: the <em>OCaml</em> typechecker won’t allow it.</p>

<p>This is accomplished by indexing terms by a “phantom type” that records the length of their context, as a “type-level natural number”.  Here is how we encode the natural numbers as types:</p>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">zero</span> <span class="o">=</span> <span class="n">private</span> <span class="nc">Dummy_zero</span>
<span class="k">type</span> <span class="k">'</span><span class="n">a</span> <span class="n">suc</span> <span class="o">=</span> <span class="n">private</span> <span class="nc">Dummy_suc</span>
</code></pre></div></div>

<p>(If you’re going to read this blog you should probably know at least basic <a href="https://ocaml.org/manual/5.4/index.html">OCaml syntax</a>.)  Thus, among the usual types <code class="language-plaintext highlighter-rouge">int</code>, <code class="language-plaintext highlighter-rouge">string</code> and so on, we now also have types <code class="language-plaintext highlighter-rouge">zero</code>, <code class="language-plaintext highlighter-rouge">zero suc</code>, <code class="language-plaintext highlighter-rouge">zero suc suc</code>, and so on, which we view as a copy of the natural numbers.  Now we can define the type of De Bruijn indices as a <a href="https://ocaml.org/manual/5.4/gadts-tutorial.html">GADT</a> depending on the length of their context:</p>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">_</span> <span class="n">index</span> <span class="o">=</span>
  <span class="o">|</span> <span class="nc">Top</span> <span class="o">:</span> <span class="k">'</span><span class="n">a</span> <span class="n">suc</span> <span class="n">index</span>
  <span class="o">|</span> <span class="nc">Pop</span> <span class="o">:</span> <span class="k">'</span><span class="n">a</span> <span class="n">index</span> <span class="o">-&gt;</span> <span class="k">'</span><span class="n">a</span> <span class="n">suc</span> <span class="n">index</span>
</code></pre></div></div>

<p>This is just the usual definition of the “finite types” in dependent type theory, but now with the indexing natural number being a <em>type</em> rather than an element of a type of natural numbers.  Thus we have the following indices:</p>

<ul>
  <li>there is nothing in <code class="language-plaintext highlighter-rouge">zero index</code></li>
  <li><code class="language-plaintext highlighter-rouge">Top : zero suc index</code></li>
  <li><code class="language-plaintext highlighter-rouge">Top : zero suc suc index</code> and <code class="language-plaintext highlighter-rouge">Pop Top : zero suc suc index</code></li>
  <li><code class="language-plaintext highlighter-rouge">Top : zero suc suc suc index</code> and <code class="language-plaintext highlighter-rouge">Pop Top : zero suc suc suc index</code> and <code class="language-plaintext highlighter-rouge">Pop (Pop Top) : zero suc suc suc index</code></li>
</ul>

<p>and so on.  Now when we define terms, we use these indices to denote variables:</p>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">_</span> <span class="n">term</span> <span class="o">=</span>
  <span class="o">|</span> <span class="nc">Var</span> <span class="o">:</span> <span class="k">'</span><span class="n">a</span> <span class="n">index</span> <span class="o">-&gt;</span> <span class="k">'</span><span class="n">a</span> <span class="n">term</span>
  <span class="o">...</span>
</code></pre></div></div>

<p>and <em>voila</em>: it’s impossible for De Bruijn indices to be out of scope.</p>

<h2 id="dimension-indexed-indices">Dimension-indexed indices</h2>

<p>In fact, what what Narya actually does is more complicated than this.  In observational higher type theories, at least the way Narya implements them, each “variable” in the context can actually be a collection of variables forming a cube of some dimension.  An ordinary single variable is a zero-dimensional cube.  A one-dimensional cube consists (in the arity-2 case) of three variables: two endpoints and a path.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(x₀ : A) (x₁ : A) (x₂ : Id A x₀ x₁)
</code></pre></div></div>

<p>For instance, these are what we add to the context when defining an equality of functions in <code class="language-plaintext highlighter-rouge">Id (A → B) f₀ f₁</code>, since that identity type is (isomorphic to)</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(x₀ : A) (x₁ : A) (x₂ : Id A x₀ x₁) → Id B (f₀ x₀) (f₁ x₁)
</code></pre></div></div>

<p>When we write this on a page, or even in proof assistant code, we write the variables <code class="language-plaintext highlighter-rouge">x₀</code>, <code class="language-plaintext highlighter-rouge">x₁</code>, <code class="language-plaintext highlighter-rouge">x₂</code> in linear order, and usually think of simply abstracting over three ordinary variables one at a time.  But one of the insights that makes Narya work is that internally, it’s better to treat these three variables together as a “bundle”, using a data structure that associates them directly to the faces of a cube (more on that in some other post, maybe), and <em>only</em> linearize them at the boundary of concrete syntax when interacting with the user.  This eliminates a whole class of potential bugs that could arise from inconsistent ways to order the faces of a cube, and makes the logic more intuitive and geometric: you are always just iterating over the faces of a cube, with no need to think about the order in which it happens.</p>

<p>Now, however, when we put a whole cube of variables into the context at once, we need more information to access a single variable: not just a De Bruijn index, which points to the whole <em>cube</em>, but a <em>face</em> of that cube.  This introduces a new source of potential “scoping” errors: what if the face has the wrong dimension to match the cube in the context?</p>

<p>Fortunately, we can also eliminate this possibility statically.  We represent <em>dimensions</em> as types: for now you can just think of them as another copy of the type-level natural numbers above.  Faces of a cube are then indexed by their domain and codomain, for instance an element of <code class="language-plaintext highlighter-rouge">(zero suc, zero suc suc) face</code> is a 1-dimensional face of a 2-dimensional cube (of which there are four).  And the parameter of a term, that above was just the <em>length</em> of a context, now becomes a <em>type-level list of dimensions</em> – in fact, a <a href="https://github.com/RedPRL/ocaml-bwd">backwards list</a>.  Here are the constructors of type-level backwards lists:</p>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">emp</span> <span class="o">=</span> <span class="n">private</span> <span class="nc">Dummy_emp</span>
<span class="k">type</span> <span class="p">(</span><span class="k">'</span><span class="n">xs</span><span class="o">,</span> <span class="k">'</span><span class="n">x</span><span class="p">)</span> <span class="n">snoc</span> <span class="o">=</span> <span class="n">private</span> <span class="nc">Dummy_snoc</span>
</code></pre></div></div>

<p>Thus, for instance, here is a type-level backwards list of type-level natural numbers corresponding to <code class="language-plaintext highlighter-rouge">[1; 2; 0]</code>:</p>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(((</span><span class="n">emp</span><span class="o">,</span> <span class="n">zero</span> <span class="n">suc</span><span class="p">)</span> <span class="n">snoc</span><span class="o">,</span> <span class="n">zero</span> <span class="n">suc</span> <span class="n">suc</span><span class="p">)</span> <span class="n">snoc</span><span class="o">,</span> <span class="n">zero</span><span class="p">)</span> <span class="n">snoc</span>
</code></pre></div></div>

<p>One final change is to parametrize the type of indices by the dimension that some index points to in a type-level backwards list of dimensions:</p>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="p">(</span><span class="n">_</span><span class="o">,</span> <span class="n">_</span><span class="p">)</span> <span class="n">index</span> <span class="o">=</span>
  <span class="o">|</span> <span class="nc">Top</span> <span class="o">:</span> <span class="p">(</span><span class="k">'</span><span class="n">n</span><span class="o">,</span> <span class="p">(</span><span class="k">'</span><span class="n">a</span><span class="o">,</span> <span class="k">'</span><span class="n">n</span><span class="p">)</span> <span class="n">snoc</span><span class="p">)</span> <span class="n">index</span>
  <span class="o">|</span> <span class="nc">Pop</span> <span class="o">:</span> <span class="p">(</span><span class="k">'</span><span class="n">n</span><span class="o">,</span> <span class="k">'</span><span class="n">a</span><span class="p">)</span> <span class="n">index</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="k">'</span><span class="n">n</span><span class="o">,</span> <span class="p">(</span><span class="k">'</span><span class="n">a</span><span class="o">,</span> <span class="k">'</span><span class="n">k</span><span class="p">)</span> <span class="n">snoc</span><span class="p">)</span> <span class="n">index</span>
</code></pre></div></div>

<p>Now we can say the variables that appear in terms are determined by an index and a face <em>of the same dimension</em>:</p>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">_</span> <span class="n">term</span> <span class="o">=</span>
  <span class="o">|</span> <span class="nc">Var</span> <span class="o">:</span> <span class="p">(</span><span class="k">'</span><span class="n">n</span><span class="o">,</span> <span class="k">'</span><span class="n">a</span><span class="p">)</span> <span class="n">index</span> <span class="o">*</span> <span class="p">(</span><span class="k">'</span><span class="n">k</span><span class="o">,</span> <span class="k">'</span><span class="n">n</span><span class="p">)</span> <span class="n">face</span> <span class="o">-&gt;</span> <span class="k">'</span><span class="n">a</span> <span class="n">term</span>
  <span class="o">...</span>
</code></pre></div></div>

<p>and the OCaml typechecker will guarantee at compile-time that we never have a mismatch.  (This isn’t exactly what’s in the Narya code, but it’s the basic idea.)</p>

<h2 id="free-categories">Free categories</h2>

<p>My current project is to enhance Narya with <a href="https://arxiv.org/abs/2011.15021">Multimodal Type Theory</a>.  (I always intended to do that, but I’m doing it now because I have hopes that it will be useful in completing the implementation of HOTT; more on that later.)  In MTT, contexts aren’t built just out of typed variables, but also <em>locks</em> arising from modalities.  Specifically, each context has a <em>mode</em>, and if <code class="language-plaintext highlighter-rouge">μ : p → q</code> is a modality (mode morphism) then a <code class="language-plaintext highlighter-rouge">q</code>-context can be <code class="language-plaintext highlighter-rouge">μ</code>-locked to become a <code class="language-plaintext highlighter-rouge">p</code>-context.</p>

<p>Of course, this opens up yet another class of potential bugs: the source or target of a lock modality might not match up correctly.  And so, of course, I set out on a quest to eliminate such errors statically.</p>

<p>Actually – no, I didn’t, not to start with.  At first, I put in the locks without any static checking.  And I got things mostly working, but there were some weird bugs that I didn’t entirely understand, but which seemed like they had to do with putting the wrong modalities or modes in the wrong places.  So, instead of spending the time tracking down those specific bugs, I decided to rip everything apart and put in static modality-dependence in the context.  This had the result of not only squashing the bugs I can see now, but preventing any future such bugs from occurring.</p>

<p>This may seem like a strange way to code, but it’s worked for me numerous times.  In particular, when I do this, the bugs I started out looking at do, in fact, get fixed, even though it’s not always obvious to me exactly at what point I fixed them!  Sometimes I have a guess about more or less the point at which they got fixed, but other times I have no idea.  The latter is what happened with modal locks: to make the code compile under the new statically-typed locking regime, I had to rewrite enough of it more or less from scratch that I still have no idea where the bug was in the old version.  But it doesn’t matter, because the OCaml typechecker promises me that the new version is free of (those) bugs.</p>

<p>Personally, I find this kind of coding to be a joy.  Among other things, it means that I spend more of my time thinking about how things <em>should</em> work and doing them correctly, rather than trying to figure out why something <em>isn’t</em> working.  And it’s also very category-theoretic, which of course appeals to me as a category theorist.</p>

<p>Why is it category-theoretic?  I mean that partly in <a href="https://golem.ph.utexas.edu/category/2010/03/a_perspective_on_higher_catego.html">Tom Leinster’s sense</a> that doesn’t refer at all to categories: it solves problems in a conceptual way by moving to a higher level of generality.  But more concretely, this approach tends to incorporate more of the category-theoretic framework of mathematical descriptions of type theory into the implementation.</p>

<p>Static context locking is a case in point.  The parameter of a context should now a type-level backwards list that contains two kinds of elements: dimensions, representing variables, and modalities, representing locks.  (Each modality, like each dimension, is itself represented by a type; I’ll say more in some other post about how that works.)  In addition, each dimension is <em>also</em> paired with a modality, because variables in the context can be “modally annotated”.</p>

<p>However, not any old list of (modality, dimension) pairs and modalities is a valid “context length”, because the modes have to match up: if <code class="language-plaintext highlighter-rouge">μ : p → q</code> is a modality, then only a <code class="language-plaintext highlighter-rouge">q</code>-context can be <code class="language-plaintext highlighter-rouge">μ</code>-locked, and likewise only a variable in a <code class="language-plaintext highlighter-rouge">q</code>-context can be annotated by <code class="language-plaintext highlighter-rouge">μ</code>.  Mathematically, these context lengths, or “type-level contexts”, are the <em>free category</em> generated by a <a href="https://ncatlab.org/nlab/show/quiver">quiver</a> whose vertices are the modes, and with two kinds of edges: each modality <code class="language-plaintext highlighter-rouge">μ : p → q</code> yields a “lock” edge from <code class="language-plaintext highlighter-rouge">p</code> to <code class="language-plaintext highlighter-rouge">q</code>, while each pair <code class="language-plaintext highlighter-rouge">(μ , n)</code> of a modality <code class="language-plaintext highlighter-rouge">μ : p → q</code> with a dimension <code class="language-plaintext highlighter-rouge">n</code> yields a “variable” edge from <code class="language-plaintext highlighter-rouge">q</code> to <code class="language-plaintext highlighter-rouge">q</code> (adding a variable doesn’t change the <em>mode</em> of the context).</p>

<p>The foundation of static context locking is, therefore, a library for type-level free categories.  Doing this right required a fair amount of boilerplate, but fortunately these days AI makes it easy to generate boilerplate.  <a href="https://github.com/gwaithimirdain/narya/blob/2d95834d220cd47ff400bb7ee2d9b3a7a9fb3e69/lib/util/category.ml">Here</a> is the definition of type-level categories, and <a href="https://github.com/gwaithimirdain/narya/blob/2d95834d220cd47ff400bb7ee2d9b3a7a9fb3e69/lib/util/path.ml">here</a> is the free category on a quiver (whose morphisms are “paths” of edges in the quiver).</p>

<p>Finally, as usual, once we have a good abstraction, it turns out to be useful for lots of things.  For example:</p>

<ul>
  <li>
    <p>When extending a context by a telescope, we “compose morphisms” in this “context category”.</p>
  </li>
  <li>
    <p>There is a functor from the category of modes to this “context category” which makes every modality into a lock.  Locking a context is then just composition with the image of some modality under this functor.  (This is less trivial than it seems because for technical reasons, the basic “lock” constructor actually just locks by a <em>generating</em> modality.)</p>
  </li>
  <li>
    <p>There is also a functor in the other direction that discards all variables and composes up the locks in a context.  This is important when looking up a variable in a context: we need the composite of all the locks to its right to know what sort of “key” 2-cell is required to unlock it.</p>
  </li>
</ul>

<p>Multimodal Narya is not yet ready for release, but to whet your appetite here is some code that now compiles under the mode theory for an idempotent comonad <code class="language-plaintext highlighter-rouge">□</code>, exhibiting the functoriality and monad operations:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def □ (A :□| Type) : Type ≔ data [ box. (x :□| A) ]

def □map (A B :□| Type) (f :□| A → B) : □ A → □ B ≔ [ box. x ↦ box. (f x) ]

def ε (A :□| Type) (u :□ A) : A ≔ match u [ box. x ↦ x ]

def △ (A :□| Type) (u :□ A) : □ (□ A) ≔ match u [ box. x ↦ box. (box. x) ]

def □ε∘△ (A :□| Type) (u :□ A) : Id (□ A) (□map (□ A) A (ε A) (△ A u)) u
  ≔ match u [ box. x ↦ refl (box. x) ]

def ε□∘△ (A :□| Type) (u :□ A) : Id (□ A) (ε (□ A) (△ A u)) u ≔ match u [
| box. x ↦ refl (box. x)]
</code></pre></div></div>]]></content><author><name></name></author><summary type="html"><![CDATA[In coding Narya, one of my general principles is to use types as much as possible to eliminate the possibility of errors statically (that is, at compile time). Which is, of course, what types are for, from a programming perspective.]]></summary></entry><entry><title type="html">Syntax for modal type theory</title><link href="https://gwaithimirdain.github.io/2026/05/22/modal-syntax.html" rel="alternate" type="text/html" title="Syntax for modal type theory" /><published>2026-05-22T00:00:00+00:00</published><updated>2026-05-22T00:00:00+00:00</updated><id>https://gwaithimirdain.github.io/2026/05/22/modal-syntax</id><content type="html" xml:base="https://gwaithimirdain.github.io/2026/05/22/modal-syntax.html"><![CDATA[<p>Let’s start the blog off by tempting <a href="https://wiki.haskell.org/Wadler%27s_Law">Wadler’s Law</a>!  (Actually, Wadler’s Law does not align with my experience.  Perhaps due to the now-well-known nature of the Law itself and the perjorative view it implies of discussions of syntax, I’ve found that hardly anyone else ever wants to talk about syntax at all!  At least I’m <a href="https://www.youtube.com/watch?v=kQjrcSMYpaA">not the only one</a>.)</p>

<p>My current project is to enhance Narya with Multimodal Type Theory.  (I always intended to do that, but I’m doing it now because I hope that it will be useful in completing the implementation of HOTT; more on that later.)  I’ll have more to say about the implementation later, but right now I’m pondering some questions of concrete syntax.</p>

<h2 id="syntax-for-modes">Syntax for modes</h2>

<p>In modern modal type theories, the modal behavior is parametrized by a <em>mode theory</em>: a 2-category whose objects are called <em>modes</em> and whose morphisms are called <em>mode morphisms</em> or <em>modalities</em>.  There is a separate ordinary type theory at each mode, and the modalities induce modal operators mapping between them: a modality <code class="language-plaintext highlighter-rouge">μ : p → q</code> can induce a modal operator taking <code class="language-plaintext highlighter-rouge">p</code>-types to <code class="language-plaintext highlighter-rouge">q</code>-types.</p>

<p>In the literature on modal type theory, one tends to find judgments annotated by mode, such as <code class="language-plaintext highlighter-rouge">Γ ⊢ A typeₚ</code> or <code class="language-plaintext highlighter-rouge">Γ ⊢ A type @ p</code>.  In the concrete syntax of a proof assistant (at least, of Narya), the only judgment the user interacts with is a typing judgment.  But it would be quite annoying to have to constantly write <code class="language-plaintext highlighter-rouge">x :ₚ A</code> or <code class="language-plaintext highlighter-rouge">x : A @ p</code>.</p>

<p>I think a workable solution to this is to say that the names of modes are the same as the names of the corresponding universes of types at that mode.  Thus, if there is only one mode, that mode is called <code class="language-plaintext highlighter-rouge">Type</code>.  If there is another mode of “discrete types”, as in <a href="https://doi.org/10.1017/S096012952510025X">dTT</a>, we could call that mode <code class="language-plaintext highlighter-rouge">Disc</code>, and so on.  Then when we use one of these universe-names, it indicates directly which mode the corresponding type lives at, and the modes of essentially all other judgments should be inferrable.</p>

<h2 id="syntax-for-modal-variables">Syntax for modal variables</h2>

<p>The way modern modal type theories incorporate the modalities is that some variables are <em>annotated</em> by some modality.  In general, a variable in a context or judgment at mode <code class="language-plaintext highlighter-rouge">q</code> can be annotated by a modality <code class="language-plaintext highlighter-rouge">μ : p → q</code>, in which case the type of that variable must live at mode <code class="language-plaintext highlighter-rouge">p</code> (in a context which is “locked” by the modality <code class="language-plaintext highlighter-rouge">μ</code>, but that’s a story for another day).  Semantically, such a variable has the covariant modal operator associated to <code class="language-plaintext highlighter-rouge">μ</code> applied to its type, but syntactically it is a judgmental structure used to give rules for that modal operator as a type former.</p>

<p>There are two ways that these modal annotations are generally denoted syntactically in the literature.  One is to modify the typing colon.  For example, in crisp/spatial type theory the modal variables are denoted <code class="language-plaintext highlighter-rouge">x ∷ A</code>.  The corresponding modal operator, say <code class="language-plaintext highlighter-rouge">♭</code>, can then be defined as an inductive type generated by a constructor with a modal argument:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def ♭ (A ∷ Type) : Type ≔ data [
| flat. (x ∷ A) : ♭ A ]
</code></pre></div></div>

<p>If there are multiple modalities, this style requires additional “kinds of colons”.  There are a limited number of Unicode colon-like operators, but of course we can make more by combining characters:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(x :~ A) (y :: B) (z :# C) (w ∷♯ D)
</code></pre></div></div>

<p>and so on.</p>

<p>This approach has the advantage of conciseness.  However, it has several drawbacks:</p>

<ul>
  <li>
    <p>There are, to be sure, an unbounded number of colon-operators, but it seems a little awkward to have to keep thinking of a new one whenever we need a new modality, and we’ll quickly run out of the nicest-looking ones like <code class="language-plaintext highlighter-rouge">∷</code>.</p>
  </li>
  <li>
    <p>Are <code class="language-plaintext highlighter-rouge">::</code> and <code class="language-plaintext highlighter-rouge">∷</code> two different operators, or is the second a Unicode-variation of the first?  What characters are allowed in a colon-operator?  Narya’s existing lexer allows <code class="language-plaintext highlighter-rouge">x:A</code> to mean <code class="language-plaintext highlighter-rouge">x : A</code> because <code class="language-plaintext highlighter-rouge">:</code> is an ASCII symbol while <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">A</code> are identifiers.  I don’t want to give that up, but without modification the same wouldn’t be true of <code class="language-plaintext highlighter-rouge">x∷A</code>, which would be inconsistent and surprising.</p>
  </li>
  <li>
    <p>We need a “name” to refer to each modality, for instance in error messages like <code class="language-plaintext highlighter-rouge">♯-annotated variable is inaccessible behind ♭ lock</code>.  We could use the colon-operators as names, like <code class="language-plaintext highlighter-rouge">:#-annotated variable is inaccessible behind ∷ lock</code>, but that looks a little ugly and could be hard to understand.  And if modalities had names that were different from their colon-operators, the user would have to remember which names go with which colons.</p>
  </li>
  <li>
    <p>Some mode theories are finitely <em>generated</em> but not finite, and the user (or whoever specifies the mode theory) can only be expected to explicitly give names or colon-operators to the generators.  If the lock is a composite of generators, then we need to be able to say something like <code class="language-plaintext highlighter-rouge">♯-annotated variable is inaccessible behind ♭ ♭ ♭ lock</code>, which looks even uglier and more confusing as <code class="language-plaintext highlighter-rouge">:#-annotated variable is inaccessible behind ∷ ∷ ∷ lock</code>.</p>
  </li>
</ul>

<p>The other syntax for modal annotations in the literature is the one in the <a href="https://arxiv.org/abs/2011.15021">MTT paper</a>, where the type is annotated with the modality and a bar operator: <code class="language-plaintext highlighter-rouge">x : (♭ | A)</code>.  This solves all of these problems since we can use a more natural “name” for the modality such as <code class="language-plaintext highlighter-rouge">♭</code>, and a sequence of names to represent a composite of modalities as in <code class="language-plaintext highlighter-rouge">x : (♭ ♭ | A)</code>.  I’ve resisted using this syntax on paper because I think it’s fairly verbose, but something like it may be unavoidable in an implementation.</p>

<p>I am thinking of simplifying it a bit by removing the parentheses around <code class="language-plaintext highlighter-rouge">♭ | A</code>, since in practice an annotated variable is always inside outer parentheses anyway, as for instance in a modal function type <code class="language-plaintext highlighter-rouge">(x : ♭ | A) → B x</code>.  And as long as the modality names are valid identifiers (not ASCII symbols), the Narya lexer would allow us to write this as <code class="language-plaintext highlighter-rouge">(x :♭| A) → B x</code>, which is not that far from the modified-colon approach.  I’m curious if anyone else has thoughts.</p>

<p>One specific thing to note is that the names of modalities would (I think) be a separate category from other identifiers.  In particular, even if <code class="language-plaintext highlighter-rouge">♭</code> is a modality name, one could also <code class="language-plaintext highlighter-rouge">def ♭</code> to mean something inside the theory, without risk of parsing ambiguity since the <code class="language-plaintext highlighter-rouge">:</code> and <code class="language-plaintext highlighter-rouge">|</code> always bracket a modality name.  Of course, defining <code class="language-plaintext highlighter-rouge">♭</code> to mean something totally different would be confusing, but we might very well want to use it for the modal operator defined as above:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def ♭ (A :♭| Type) : Type ≔ data [
| flat. (x :♭| A) : ♭ A ]
</code></pre></div></div>

<h2 id="syntax-for-key-operators">Syntax for key operators</h2>

<p>To <em>use</em> a modally annotated variable, you have to “unlock” it with a “key” that is a 2-cell in the mode 2-category.  In the simplest case, if <code class="language-plaintext highlighter-rouge">μ : p → p</code> is an endo-modality, then to use a variable <code class="language-plaintext highlighter-rouge">x :μ| A</code> you need to unlock it with a 2-cell <code class="language-plaintext highlighter-rouge">α : μ ⇒ idₚ</code>.  More generally, if <code class="language-plaintext highlighter-rouge">μ : p → q</code> then <code class="language-plaintext highlighter-rouge">x :μ| A</code> can be unlocked with <code class="language-plaintext highlighter-rouge">α : μ ⇒ ν</code> if the context is “locked” by <code class="language-plaintext highlighter-rouge">ν</code> (I’m omitting what that means because I want to concentrate right now on syntax).</p>

<p>Many mode theories are locally posetal, so such 2-cells are unique when they exist.  In that case, there’s no need for a syntax for them as they can be inferred automatically.  But for a general mode theory, there might be multiple parallel 2-cells, so the user needs a way to specify which they want to use for unlocking.</p>

<p>Key operators have some formal similarities to higher-dimensional degeneracies, so I’ve been tempted to use a superscript syntax for them akin to Narya’s existing <code class="language-plaintext highlighter-rouge">x⁽ᵉᵉ⁾</code> for degeneracies.  However, on balance I think this would be too unwieldy: the superscripts would get too long to be easily readable.</p>

<p>One simple approach is a function-like prefix notation, so for instance <code class="language-plaintext highlighter-rouge">α x</code> would mean <code class="language-plaintext highlighter-rouge">x</code> unlocked with the key 2-cell <code class="language-plaintext highlighter-rouge">α</code>.  (This also has a precedent in degeneracies, where <code class="language-plaintext highlighter-rouge">refl x</code> means the same as <code class="language-plaintext highlighter-rouge">x⁽ᵉ⁾</code>.)</p>

<p>In the case of a mode theory that’s finitely generated but not finite, where only the generating 2-cells have names, we need to derive names for the non-generating ones.  I think we can get away without syntax for “vertical” composites of 2-cells (along 1-cells), because the key action of such a composite is just a composite of actions, so we can just write <code class="language-plaintext highlighter-rouge">β (α x)</code> instead of having a syntax for composing <code class="language-plaintext highlighter-rouge">α</code> and <code class="language-plaintext highlighter-rouge">β</code>.</p>

<p>Notating horizontal composition (along 0-cells) is more tricky.  The simplest option would be something like <code class="language-plaintext highlighter-rouge">α β x</code>.  As long as the names of 2-cells are not also available as identifiers, I think this would be technically unambiguous — but it could still be confusing, with <code class="language-plaintext highlighter-rouge">α β f x</code> meaning “act on the function-variable <code class="language-plaintext highlighter-rouge">f</code> with the horizontal composite of 2-cells <code class="language-plaintext highlighter-rouge">α β</code>, then apply the result to the argument <code class="language-plaintext highlighter-rouge">x</code>”.</p>

<p>A more verbose option would be for all key actions to be labeled by some keyword or symbol, such as <code class="language-plaintext highlighter-rouge">key α x</code> or <code class="language-plaintext highlighter-rouge">🗝️ α x</code>.  Then the first argument would always be a 2-cell, perhaps including a parenthesized (horizontal) composite of generating 2-cells: <code class="language-plaintext highlighter-rouge">🗝️ (α β) x</code>.</p>

<p>We could combine the two options by saying that if the 2-cell argument is just a single generator, the key can be omitted: <code class="language-plaintext highlighter-rouge">α x</code> means <code class="language-plaintext highlighter-rouge">🗝️ α x</code>, but <code class="language-plaintext highlighter-rouge">🗝️ (α β) x</code> has no analogous abbreviated form.  However, unlike the pure-key option, this would require that the names of 2-cells can’t be re-used for user definitions.</p>

<p>I’m especially curious if anyone else has thoughts about this.  Which versions look best to you?  If we need a “key” label, do you prefer the keyword <code class="language-plaintext highlighter-rouge">key</code>, the symbol <code class="language-plaintext highlighter-rouge">🗝️</code> (or <code class="language-plaintext highlighter-rouge">🔑</code>), or something else?</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Let’s start the blog off by tempting Wadler’s Law! (Actually, Wadler’s Law does not align with my experience. Perhaps due to the now-well-known nature of the Law itself and the perjorative view it implies of discussions of syntax, I’ve found that hardly anyone else ever wants to talk about syntax at all! At least I’m not the only one.)]]></summary></entry><entry><title type="html">Welcome</title><link href="https://gwaithimirdain.github.io/2026/05/21/welcome.html" rel="alternate" type="text/html" title="Welcome" /><published>2026-05-21T00:00:00+00:00</published><updated>2026-05-21T00:00:00+00:00</updated><id>https://gwaithimirdain.github.io/2026/05/21/welcome</id><content type="html" xml:base="https://gwaithimirdain.github.io/2026/05/21/welcome.html"><![CDATA[<p>This is the Gwaith-i-Mírdain development blog.  I’m planning to post thoughts and plans here semi-regularly as I work on coding Narya and speculate about what I might do in the future.  Please comment and share your thoughts!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[This is the Gwaith-i-Mírdain development blog. I’m planning to post thoughts and plans here semi-regularly as I work on coding Narya and speculate about what I might do in the future. Please comment and share your thoughts!]]></summary></entry></feed>