<?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://datakinds.github.io//feed.xml" rel="self" type="application/atom+xml" /><link href="https://datakinds.github.io//" rel="alternate" type="text/html" /><updated>2026-08-11T02:47:27+00:00</updated><id>https://datakinds.github.io//feed.xml</id><title type="html">DK’S ABODE</title><subtitle>&quot;; DROP TABLE *;</subtitle><entry><title type="html">stacks, modules, oh my! a thinkbox (DRAFT!)</title><link href="https://datakinds.github.io//2026/08/07/stacks-modules-oh-my-a-thinkbox" rel="alternate" type="text/html" title="stacks, modules, oh my! a thinkbox (DRAFT!)" /><published>2026-08-07T23:10:00+00:00</published><updated>2026-08-07T23:10:00+00:00</updated><id>https://datakinds.github.io//2026/08/07/stacks-modules-oh-my-a-thinkbox</id><content type="html" xml:base="https://datakinds.github.io//2026/08/07/stacks-modules-oh-my-a-thinkbox"><![CDATA[<p>ohhh baby, <a href="https://datakinds.github.io/2019/06/30/jamq-thinkbox">i haven’t done a thinkbox in a long time</a>!</p>

<p>quick note: i’ll put a dagger symbol (†) next to any jargon i’ve made up, and i’ll leave it out if i’m pretty sure the jargon is real. im trying to do a little novel classification here, so.</p>

<p>let me tell you about</p>

<h1 id="modules">modules</h1>

<p>a module is a way to organize lots of behaviors under one scope. there are a few kinds of modules, and i want to suggest that these interpretations form a hierarchy. we’re going to start with the narrowest end of the hierarchy and work our way up. and it’ll be more relevant as we get to the ocaml section but we’re discussing modules strictly as they exist dynamically, at runtime. no types here, sorry!</p>

<h2 id="static-modules">static modules†</h2>

<p>this is like what Haskell calls a module, or what many languages (Python, Kotlin, etc) will call a <em>package</em>.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="nn">org.example</span>

<span class="k">fun</span> <span class="nf">printMessage</span><span class="p">()</span> <span class="p">{</span> <span class="cm">/*...*/</span> <span class="p">}</span>
<span class="kd">class</span> <span class="nc">Message</span><span class="p">(</span><span class="kd">val</span> <span class="py">text</span><span class="p">:</span> <span class="nc">String</span><span class="p">)</span> <span class="p">{</span> <span class="cm">/*...*/</span> <span class="p">}</span>
</code></pre></div></div>

<p>(from <a href="https://kotlinlang.org/docs/packages.html">https://kotlinlang.org/docs/packages.html</a>. okay, kotlin does have things it calls modules but it’s the package that’s more relevant here. kotlin’s nominal modules are more strictly compilation units.)</p>

<p>these modules do nothing beside providing a scope and disambiguating names. so i can have a module which provides <code class="language-plaintext highlighter-rouge">org.example.PrintMessage</code> as above, but I can also have a secondary module which provides <code class="language-plaintext highlighter-rouge">org.example2.silly.PrintMessagee</code>. so let’s quantify what this kind of module does for us:</p>

<ul>
  <li>name disambiguation</li>
  <li>scoping and privitization
    <ul>
      <li>you can choose to not export a name from a module</li>
    </ul>
  </li>
  <li>dependency demand†
    <ul>
      <li>you can import a module from another module, bringing its names into scope</li>
      <li>notably you cannot do this arbitrarily, you MUST do this in an acyclic way in most languages, which will not do cycle analysis on this graph</li>
    </ul>
  </li>
  <li>compilation unit separation
    <ul>
      <li>if a module hasn’t changed, it doesn’t need to be recompiled. this comes for free because of the scope boundary</li>
    </ul>
  </li>
</ul>

<h2 id="closure-modules">closure modules†</h2>

<p>there is a middle-ground for how dynamic a module can be. instead of all data specified in a module being completely static, you can also have modules which close over some data explicitly and work with that data as state.</p>

<p>a particularly interesting example exists in Maude’s <a href="https://maude.lcc.uma.es/maude-manual/maude-manualch5.html#x40-640005">system modules</a>, in which entire rewriting theories can be scoped to a given module. a user may work with these modules as first class theory objects and may, for example, <a href="https://maude.lcc.uma.es/maude-manual/maude-manualch11.html#x81-17400011">do invariant checking directly on the module</a>.</p>

<p>modules as interpreted this way share a behavioral overlap with singleton classes. in a singleton class, we expect to only have one single instance (which may be statically identified by the class declaration), and this single instance can close over data and update itself. some singleton classes can even nest.</p>

<p>note that I’m NOT saying that these modules support implicit closure over some environment. we’ll touch on that in the next section.</p>

<p>let’s take a note of this capability:</p>

<ul>
  <li>explicit closure
    <ul>
      <li>you can choose to store data within the module, and you can choose to come back and mutate that data</li>
    </ul>
  </li>
</ul>

<h2 id="polymorphic-modules">polymorphic modules†</h2>

<p>we’ve made the singleton class comparison, so let’s extend that a little more. what if we could have N singleton classes, where each one was parameterized over a set of types and values?</p>

<p>i believe this to be equivalent in power (or actually just equivalent) to the sanitary macro. and as such let’s talk about the C++ STL. check out this example:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">T</span><span class="p">,</span> <span class="n">T</span> <span class="n">V</span><span class="p">&gt;</span>
<span class="k">class</span> <span class="nc">SingletonValue</span> <span class="p">{</span>
<span class="nl">public:</span>
    <span class="k">static</span> <span class="n">T</span> <span class="n">value</span><span class="p">()</span> <span class="k">noexcept</span> <span class="p">{</span> <span class="k">return</span> <span class="n">V</span><span class="p">;</span> <span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>
<p>invoked as</p>
<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">auto</span> <span class="n">x</span> <span class="o">=</span> <span class="n">SingletonValue</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="mi">42</span><span class="o">&gt;::</span><span class="n">value</span><span class="p">();</span>   <span class="c1">// gives x == 42</span>
<span class="k">auto</span> <span class="n">y</span> <span class="o">=</span> <span class="n">SingletonValue</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="mi">69</span><span class="o">&gt;::</span><span class="n">value</span><span class="p">();</span>   <span class="c1">// gives y == 69</span>
</code></pre></div></div>

<p>in the jargon of the hierarchy we’ve built, <code class="language-plaintext highlighter-rouge">SingletonValue</code> IS a polymorphic module. it is parameterized over a set of types and/or values (we could have used <code class="language-plaintext highlighter-rouge">auto</code> to drop the typevar fwiw). it does all of the behaviors we’ve scoped out above, with the added benefit of also now allowing us to instantiate multiple of these singleton modules. so what extra behaviors does this get us?</p>

<ul>
  <li>multiplicity
    <ul>
      <li>specifically, you may have 1 instance of a polymorphic module per unique parameter. so if you’ve got some sort of countable type, you’ve got infinite modules.</li>
    </ul>
  </li>
</ul>

<h2 id="functatorial-first-class-polymorphic-modules">functatorial (first-class) polymorphic modules</h2>

<p>let’s again expand the breadth of things a module can do—we now allow a closure module to take input. the only place i’ve ever seen this explicitly is in the SML family of languages. specifically, let’s look at ocaml’s <a href="https://ocaml.org/docs/functors">functors</a>:</p>

<blockquote>
  <p>As suggested by the name, a functor is almost like a function. However, while the inputs and outputs of functions are values, functors are between modules. A functor has a module as a parameter and returns a module as a result. A functor in OCaml is a parametrised module, not to be confused with a functor in mathematics.</p>
</blockquote>

<p>let me begin by saying that there is a rich mathematical backing to ocaml’s unified module system, which comes equipped with a formal calculus based off <a href="https://people.mpi-sws.org/~rossberg/1ml/1ml.pdf">Rossberg’s 1ML</a>. a little googling also <a href="https://hal.science/hal-05428136/document">brought me to this paper</a>, which speaks on a more recent ocaml feature (modular explicits) that allow higher-order functions to operate directly on modules and provides a calculus for unifying types quantified within modules with externally quantified types.</p>

<p>PLEASE take a look at the 1ML paper, and especially the Related Work section, for an academic and historical perspective on this hierarchy of module behaviors. additionally if you’re interested in the type-theoretic perspective and all the cool stuff ocaml can do with structs/model signatures, i’m not going to touch on that at all. I’m talking about modules from a purely dynamic perspective.</p>

<p>(now that i’ve said that, i can continue spewing colloquial bullshit)</p>

<p>the classic example of first-class functatorial modules in ocaml is a module that modifies another:</p>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="k">type</span> <span class="nc">X</span> <span class="o">=</span> <span class="k">sig</span>
  <span class="k">val</span> <span class="n">x</span> <span class="o">:</span> <span class="kt">int</span>
<span class="k">end</span>

<span class="k">module</span> <span class="nc">AddX</span> <span class="p">(</span><span class="nc">M</span> <span class="o">:</span> <span class="nc">X</span><span class="p">)</span> <span class="o">=</span> <span class="k">struct</span>
  <span class="k">let</span> <span class="n">add</span> <span class="n">y</span> <span class="o">=</span> <span class="nn">M</span><span class="p">.</span><span class="n">x</span> <span class="o">+</span> <span class="n">y</span>
<span class="k">end</span>
</code></pre></div></div>
<p>(from <a href="https://cs3110.github.io/textbook/chapters/modules/functors.html">https://cs3110.github.io/textbook/chapters/modules/functors.html</a>)</p>

<p>note that this immediately gives us a few new capabilities to think about:</p>

<ul>
  <li>nesting
    <ul>
      <li>modules can consume other modules as variables. passing in an anonymous module is identical to defining a module within another module in the effect it has on the environment</li>
    </ul>
  </li>
</ul>

<h1 id="whos-janna">who’s janna?</h1>

<p><a href="https://github.com/DataKinds/continuation-playground">janna (she/her) is a VM for working with modules</a>. <a href="https://github.com/DataKinds/tree-rewriter">in the tradition of naming my compilers after my OCs</a>, so too is she named. she supports a number of actions on modules, and i’d like to take the time to quantify this set of actions so we can get a full idea of how to interact with a module.</p>

<p>janna is a fully dynamic VM and does not have an initial pass for things like type/effect checking. janna is built in the forth tradition of parsing words, so janna’s not even statically decidable. this lets us do fun things with continuations without having to come up with a static managed runtime. if you want all these goodies with a type system on top of it, for Serious Work, go check out ocaml.</p>

<p>the intention is that janna will support first-class polymorphic modules. she will be able to create these modules on the fly and do all the composing you’d like. so let’s start walking up the hierarchy and look at the syntax and semantic of janna.</p>

<p>note that ALL the syntax and spellings here are subject to change, but it’s valid as of 8/10/2026.</p>

<h2 id="quick-sidenotes-before-we-begin">quick sidenotes before we begin</h2>

<h3 id="jannas-output">janna’s output</h3>

<p>i’ll use double boxes for code input vs code output</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>this is input
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>and this is output
</code></pre></div></div>

<p>note that janna has a little debug printer that does its best to dump the VM state. this is what it looks like in a fresh VM, you’ll see it again soon:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>?
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>janna v0 knows 4 modules: io, debug, main, core
open scopes (active scope first): main

within main, there are 0 definitions:

within main, the resolution chain is: debug, io, core

within main, open stacks (active first): hole

within main, there are 1 stacks:
hole[]
</code></pre></div></div>

<h3 id="jannas-datatypes">janna’s datatypes</h3>

<p>janna’s <a href="https://itch.io/jam/catjam-2026">for a gamejam</a> so she’s only getting features on an as-needed basis. janna currently only has two types—terms, which are bare words;</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>\ i'm-a-term .
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>i'm-a-term
</code></pre></div></div>

<p>and quotes, which are effectively sequences of words but stored internally as strings:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ Hark! O'er the five seas, land emerges! ] .s
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Hark! O'er the five seas, land emerges!
</code></pre></div></div>

<p>if i need something else i’ll add that something else. integers are a good candidate. but without loops or conditionals i haven’t seen the need yet!</p>

<h2 id="static-modules-1">static modules</h2>

<p><code class="language-plaintext highlighter-rouge">enter:</code> is a syntax word that consumes one name term and enters the scope of the module given by the name. if the module doesn’t exist, we create it. <code class="language-plaintext highlighter-rouge">leave</code> is its inverse, <code class="language-plaintext highlighter-rouge">:</code> is word definition. we call <code class="language-plaintext highlighter-rouge">?</code> twice so you, dear reader, can get Maximum Info, and see how janna is treating each scope here.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>enter: foo
: bar [ hello world ] . ;
?
leave
[ -------- ] .s
?
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>janna v0 knows 5 modules: debug, main, core, foo, io
open scopes (active scope first): foo, main

within foo, there are 1 definitions:
bar

within foo, the resolution chain is: 

within foo, open stacks (active first): hole

within foo, there are 1 stacks:
hole[]

--------

janna v0 knows 5 modules: debug, main, core, foo, io
open scopes (active scope first): main

within main, there are 0 definitions:

within main, the resolution chain is: debug, io, core

within main, open stacks (active first): hole

within main, there are 1 stacks:
hole[]
</code></pre></div></div>

<h3 id="scoping-privitization-disambiguation">scoping, privitization, disambiguation</h3>

<p>modules can hold named stacks and named definitions. this does a few things for us: firstly, disambiguation and scoping! watch us distinguish between two different definitions of <code class="language-plaintext highlighter-rouge">bar</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>enter: foo1
: bar [ hello world ] .s ;
leave
enter: foo2
: bar [ goodbye world ] .s ;
leave

enter: foo1 bar leave
enter: foo2 bar leave
bar
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hello world

goodbye world

Unknown word bar in modules ["main"]
</code></pre></div></div>

<h3 id="dependency-demand">dependency demand</h3>

<h3 id="compilation-unit-separation">compilation unit separation</h3>

<p>… is nonapplicable because we don’t statically compile.</p>

<h2 id="closure-modules-1">closure modules</h2>

<p>at initialization time, you’re free to pull data from other names</p>

<h2 id="polymorphic-modules-1">polymorphic modules</h2>

<p><code class="language-plaintext highlighter-rouge">enter</code> (not <code class="language-plaintext highlighter-rouge">enter:</code>) can take a quote as the name of the module. the first word from the quote is taken as the module name, all subsequent terms in the quote are taken as the parameter to the module.</p>

<p>TODO: maybe the subsequent words should be “the name of teh stack that we push the parameters to”…. much to think about?</p>

<p>TODO alternate: this parameter is automatically populated onto a named stack within the module, <code class="language-plaintext highlighter-rouge">M.T</code>.</p>

<h2 id="first-class-modules">first-class modules</h2>

<p>TODO: there should be an anonymous version of <code class="language-plaintext highlighter-rouge">enter</code>, and <code class="language-plaintext highlighter-rouge">leave</code> should push the name of the module to the stack.</p>

<h1 id="jannas-bag-of-tricks">janna’s bag of tricks</h1>

<p>special modules (like the parameterized module that holds continuations)</p>]]></content><author><name></name></author><category term="thinkbox" /><summary type="html"><![CDATA[ohhh baby, i haven’t done a thinkbox in a long time!]]></summary></entry><entry><title type="html">i dont care about your ai generated project</title><link href="https://datakinds.github.io//2026/08/07/i-dont-care-about-your-ai-generated-project" rel="alternate" type="text/html" title="i dont care about your ai generated project" /><published>2026-08-07T13:01:00+00:00</published><updated>2026-08-07T13:01:00+00:00</updated><id>https://datakinds.github.io//2026/08/07/i-dont-care-about-your-ai-generated-project</id><content type="html" xml:base="https://datakinds.github.io//2026/08/07/i-dont-care-about-your-ai-generated-project"><![CDATA[<p>i dont care about your ai generated project and i’m feeling particularly scornful about it after seeing two projects today that i really wanted to share before seeing that there was little to no human involvement in their development.</p>

<p>lots of people are posting lots of cool things that they have prompted a large language model to create. lots of my time gets wasted trying to figure out if there is a human with intention and skill behind a project; or if the thing is the product of channeling machine spirits via a <a href="https://www.youtube.com/watch?v=JnX-D4kkPOQ">federal-money-pit</a>-subsidized monthly credit.</p>

<p>set aside all your moral, <a href="https://techcrunch.com/2026/08/03/whos-legally-to-blame-for-anthropic-and-openais-autonomous-ai-hacks-its-complicated/">legal</a>, <a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ">intellectual-property</a>, <a href="https://www.youtube.com/watch?v=eZchOopvunQ">environmental</a>, <a href="https://www.youtube.com/watch?v=obmlZH3X9gs">risk-tolerance</a>, <a href="https://www.pcgamesn.com/wp-content/sites/pcgamesn/2025/12/december-2025-ram-price-rise.jpg">economic</a>, <a href="https://www.youtube.com/watch?v=qItugh-fFgg">geopolitical</a>, and <a href="https://www.youtube.com/watch?v=I-u8fo5esYI">long-term-tech-debt</a> related qualms with ai for a moment. lets say that ai Rules, actually, and nobody’s ever had their tap water collared by a surveillance datacenter that will never have the budget to upgrade to a closed-loop system. lets just say that for a moment and let’s fully accept that AI as it exists has no externalities to speak of.</p>

<p>there are two kinds of software projects i care about:</p>

<h3 id="you-made-a-tool">you made a tool.</h3>

<p>that’s awesome. maybe it saves you time, maybe it makes a difficult task easier. that’s a totally valid use-case for LLM generation—no need to waste more time on a means to an end than you’ve gotta!</p>

<p>but like—why do i care about your tool? what do i actually want to read about your tool?</p>

<p>if it’s directly relevant to me then maybe i’ll take an interest to the use-case and download it. but so many cool tools exist that i wouldn’t ever need to use, so it’s safe to assume this one’s not really gonna change my life either.</p>

<p>despite that i would love to hear about the challenges you faced while making the tool. your design considerations and your UX iteration. tell me how your tool scales or about wacky ways to use the thing. tell me about the rough edge your tool had that you smoothed over after some big breakthrough you synthesized while watching Breaking Bad. let me learn from not just your artifact but from your methodology.</p>

<p>except, you didn’t think about any of those things. you prompted a robot and gave it maybe an example invocation, a sketchy drawing, or described a few of its command line flags. but more likely you iterated with the robot to figure out how the tool would work at all.</p>

<p>i don’t want to read your chat logs. i can pay claude three dollhairs and recreate your logs and your whole tool in the time it takes me to get lunch. hearing this process teaches me nothing. seeing your &gt;1k LoC artifacts only tells me that you voluntarily opted to send money to a frontier inference provider. samuel alterman, dario amodei, along mask, and tongy stark need that cash. and you needed to purchase some thought.</p>

<p>i’ll be at the south indian lunch buffet while my rip of your tool is being created. an improvement in every promptable way—hashtag yolo mode bros! i’ll have a second agent iterating on the friction in common user stories, a third agent iterating on security vulnerabilities, and a fourth agent just refreshing your tool’s github to make sure i never lose feature parity. i won’t know how to use either of our tools until i read the readme or feed it back to a bot to summarize. i learned nothing. i filled a gas town ralph wiggum jira board with alphabet soup. my tool will beat your tool’s ass though, because i threw an extra few loops at it. $3? $300. but mine installs autonomously, just copy and paste this easy prompt directly into your agent. $3? no, $6, you had to rerun the install because it stochastically decided to purge your local npm packages instead.</p>

<h3 id="you-made-an-art">you made an art.</h3>

<blockquote>
  <p>that’s awesome. that’s really cool. i can’t believe you painted this. i’m in awe of your skill.</p>
</blockquote>

<p>[…]</p>

<blockquote>
  <p>no, you didn’t use paint for this? but you said you painted it right here—right in the attribution placard.</p>
</blockquote>

<p>[…]</p>

<blockquote>
  <p>i guess that’s understandable, i also don’t know how to paint well enough to put something like this together. and besides, painting something this huge would take sooo long. it could even take years!</p>
</blockquote>

<p>[…]</p>

<blockquote>
  <p>so this is just a photograph?</p>
</blockquote>

<p>[…]</p>

<blockquote>
  <p>well, i guess that’s fine. i’ll take you lying about the medium as part of the artistic experience. the thing still looks like you did a little digital brushwork though… tell me about your thoughts here!! what brushset did you choose? why’d you vary the energy like this?</p>
</blockquote>

<p>[…]</p>

<blockquote>
  <p>oh, you just had a tool lay out brushstrokes for you?</p>
</blockquote>

<p>[…]</p>

<blockquote>
  <p>i guess you did. now that you say it, i can even see the same bit of ugly aliasing on the edge of this brush stamp repeated in a bunch of spots around the canvas.</p>
</blockquote>

<p>[…]</p>

<blockquote>
  <p>really, i know how helpful the auto-brushstroking tool is. like, each of those strokes would have taken a solid five minutes. but you didn’t even try to fix up that aliasing.</p>
</blockquote>

<p>[…]</p>

<blockquote>
  <p>you didn’t notice the aliasing? did you look at this piece before you submitted it to the gallery?</p>
</blockquote>

<p>[…]</p>

<blockquote>
  <p>fine, whatever, you looked and you didn’t notice. can you at least tell me about what motivated you to paint this particular landscape?</p>
</blockquote>

<p>[…]</p>

<blockquote>
  <p>you didn’t take the original photograph?</p>
</blockquote>

<p>[…]</p>

<blockquote>
  <p>you just liked the vibes of some of the other photographs you’ve seen?</p>
</blockquote>

<p>[…]</p>

<blockquote>
  <p>so… what did you actually do here? it seems to me like all you’ve done is feed the machine a vague idea and then clicked on the prettiest pictures it spit out for a few hours.</p>
</blockquote>

<p>[…]</p>

<blockquote>
  <p>i don’t really think anything new is possible with a workflow like this. maybe you can do more of these canvases but was that really what you wanted to fill up your portfolio? they don’t really tell a story or say anything about you. this kind of just feels like you wasted both of our times.</p>
</blockquote>

<p>[…]</p>

<blockquote>
  <p>you know, you’re right! oh but it works! yeah it really does! it DOES do what it says it’ll do <del>in the readme</del> on the placard! and i can see it working right here! it might actually have a high chance of doing what you said you asked it to do! and it really does resemble human brushstroke! and that was worth all of this kerfuffle, i guess!</p>
</blockquote>

<hr />

<p>of course there’s other crap. i waved it all aside at the start. yeah of course every corporation is slinging ai slop at a far higher rate and a far lower quality bar than individuals. thats called “the commodification of labor” and you need to read a little Engels. yea of course there’s sketchy backroom deals and dark money funding triggering a massive credit bubble. thats called “politics, baby” and <a href="https://www.reddit.com/r/wallstreetbets/">you gotta ride the wave</a>. yea of course shmalterman horrifically assaulted his sister as an adolescent. that one’s a classic diagnosis—”narcissism”. and yea of course your grandma is looking at ai memes on fAIcebook. that one’s just called “your bloodline has been forever cursed”. sorry!</p>

<p>the only way to break the curse is to do crochet and play video games that have a no-AI disclaimer attached. or, like, seriously consider logging off.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[i dont care about your ai generated project and i’m feeling particularly scornful about it after seeing two projects today that i really wanted to share before seeing that there was little to no human involvement in their development.]]></summary></entry><entry><title type="html">Some Random Stuff: A 2025 In Review</title><link href="https://datakinds.github.io//2025/12/31/some-random-stuff-a-2025-in-review" rel="alternate" type="text/html" title="Some Random Stuff: A 2025 In Review" /><published>2025-12-31T21:12:00+00:00</published><updated>2025-12-31T21:12:00+00:00</updated><id>https://datakinds.github.io//2025/12/31/some-random-stuff-a-2025-in-review</id><content type="html" xml:base="https://datakinds.github.io//2025/12/31/some-random-stuff-a-2025-in-review"><![CDATA[<p>Hi gang. I haven’t been writing in a while. And that’s okay! I’ve been reading. And stepping away from the computer. Sometimes even crafting. Buying a house, and building stuff for the house.</p>

<p>This post is going to be the quickest whirlwind of everything that comes to mind that I’m excited about this year. It won’t be in chronological order, and it might not even all be 2025~ I’ve been spending a lot of</p>

<h2 id="new-jobs">New jobs!</h2>

<p>First half of the year, I was writing Golang for $BIG_FINANCIAL_COMPANY. Second half of the year, I’m writing Golang for $BIGGER_FINANCIAL_COMPANY. Have you <em>ever</em> seen me write Golang? No… sometimes you find the niche, sometimes the niche finds you.</p>

<h2 id="new-servers-new-hardware">New servers! New hardware!</h2>

<p>I’m building a data storage rack. I’ve currently got:</p>

<ul>
  <li>the rack itself</li>
  <li>a power strip</li>
  <li>two Pi 4’s</li>
  <li>a shoebox as their containment unit</li>
  <li>a fancy network switch</li>
  <li>and two DVD drives for, you know, ripping old shovelware that’s run out its copyright. And other activities of that nature.</li>
</ul>

<p>Please please please – if you know of a large 6-10 drive 12in depth 2-3u cost effective drive bay please let me know! It’s fine if I get ‘em used, I just hardly know where to even look to buy something like this. I used Synology at an old job, but the company’s went down the shitter and they lock their new systems down to only use their drives…</p>

<h2 id="new-languages">New languages!</h2>

<p>I’ve been working on a LOT of language projects this year. Esolanging has yet again captured my imagination, binding it with a knotty fervor unrivaled by the best sailors. My mind drips sweat. It pants and begs to be let—- wait, where was I? Esolanging, right. I got carried away.</p>

<p>Most of this is imported from Discord. It’s much easier for me to pop in there, wax poetic about some fake language for five minutes, and then disappear back into the ether. I’ve spent a lot of time in the <a href="https://discord.gg/9qdcu4X8Be">concatenative discord server</a> lately. Join there and join the server in my blog footer, then finish reading.</p>

<h3 id="rosin">Rosin</h3>

<p>Hey, this rings a bell! I started <a href="2024-12-02-2024-december-adventure-log.md">this during last year’s december adventure</a>. Which also happens to be my last blog post. Oh no, has this blog become a once-a-year venture? I hope not! Writing is invigorating. It just so happens to also be tiring.</p>

<p>Anyway, Rosin has come incredibly far. <a href="https://github.com/DataKinds/tree-rewriter/blob/main/EXECUTION_MODEL.md">There is a formal spec</a>, there’s a <a href="https://github.com/DataKinds/tree-rewriter/blob/main/test/Spec.hs">pretty large test suite</a>, eager variables are actually useful now in that they make the interpreter run until fixpoint on a particular tree. There’s a README that is like 6 months out of date (oops! hehe), I’ve covered most of the features I’m interested in covering.</p>

<p>The compiler’s gone through a bunch of iterative improvements that have drastically improved the codebase. Big ups to <code class="language-plaintext highlighter-rouge">@microchipsndip</code> on Discord and <a href="https://evincar.com/">evincar</a> for the suggestions. I would have never learned how I’m actually supposed to use <code class="language-plaintext highlighter-rouge">mtl</code> without these fellas.</p>

<p>A few functions I’m extra proud of:</p>

<ul>
  <li>The core pattern matching function: <a href="https://github.com/DataKinds/tree-rewriter/blob/main/src/Core.hs#L237-L276">https://github.com/DataKinds/tree-rewriter/blob/main/src/Core.hs#L237-L276</a>. I daresay this function almost reads like pseudocode.</li>
  <li>The runtime stepping function: <a href="https://github.com/DataKinds/tree-rewriter/blob/main/src/Runtime.hs#L243-L287">https://github.com/DataKinds/tree-rewriter/blob/main/src/Runtime.hs#L243-L287</a>. Finally reaping that sweet, sweet monadic DSL glory.</li>
</ul>

<p>Next is support for subinterpreters and parallelism (think <code class="language-plaintext highlighter-rouge">Ruby::Box</code>). Maybe also finally using my Trie implementation to match patterns.</p>

<p>Also, I named this language after an OC. She/they’re a demon-woman-changeling with black hair and gray skin that can take the form of a swarm of white-fur-red-eyed mice. Oy vey!</p>

<h3 id="objective-thue-thue-thue-plus-parallel-thue">Objective Thue (Thue++? Thue Plus? Parallel Thue?)</h3>

<p>Here’s another language idea I’ve been excited about: a version of Thue where you can pass messages back and forth between different rewriting engines that contain their own internal state. I’ve been playing around with the syntax and semantics, here’s some snippets ripped from discord messages:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">invoker</span> <span class="p">{</span>
    <span class="k">default</span> <span class="n">a</span>            <span class="c1">// If this scope is invoked without an input, what state do we default to?</span>
    <span class="n">strategy</span> <span class="n">pick</span><span class="o">-</span><span class="n">first</span>  <span class="c1">// Apply the very first matching rule as close to the start of the string as possible</span>
    <span class="n">b</span><span class="o">+</span> <span class="o">:~</span> <span class="err">$</span>              <span class="c1">// This rule (using :~) passes the RHS as a return value of the `invoker`, deleting (this is slow... what do?) the LHS from the internal state.</span>
    <span class="n">a</span> <span class="o">:=</span> <span class="n">ab</span>              <span class="c1">// This rule (using :=) matches the LHS and substitutes the RHS into the internal state of the `invoker`</span>
<span class="p">}</span>

<span class="n">counter</span> <span class="p">{</span>               <span class="c1">// Counts the number of a's it's been passed</span>
    <span class="n">strategy</span> <span class="n">pick</span><span class="o">-</span><span class="n">first</span>
    <span class="n">a</span> <span class="o">:=</span> <span class="n">I</span>
    <span class="p">.</span> <span class="o">:=</span>                <span class="c1">// VERY VERY VERY basic regex, anything I can easily compile to a fast FSM. </span>
                        <span class="c1">// In this case: match any character that's not `a` and delete it from the internal state.</span>
    <span class="n">I</span><span class="o">+</span> <span class="o">:::=</span> <span class="n">got</span> <span class="err">$</span> <span class="n">As</span>    <span class="c1">// LHS (I+) is another abuse of basic regex. :::= gives a rule that writes to stdout (similar to Thue proper). Deletes the LHS from the internal state.</span>
                        <span class="c1">// $ gives the entire match on the LHS. Think regex substitution syntax: $0, $1, $2, ...</span>
<span class="p">}</span>

<span class="n">invoker2</span> <span class="o">=</span> <span class="n">new</span> <span class="n">invoker</span> <span class="s">"aaa"</span> <span class="c1">// `new` is its own scoped object, just provided automatically by the compiler</span>
<span class="n">counter2</span> <span class="o">=</span> <span class="n">new</span> <span class="n">counter</span>
<span class="n">counter2</span> <span class="n">invoker2</span> 

<span class="c1">// Prints "got III As", "got IIII As", "got IIIII As", "got IIIIII As", ...d</span>
</code></pre></div></div>

<blockquote>
  <p>There are so few knobs to turn here that actually make sense:</p>
  <ul>
    <li>Where does the rewrite head start</li>
    <li>What does the state default to</li>
    <li>How does the rewrite head move when it fails a match</li>
    <li>How does the rewrite head move when it matches</li>
    <li>How does the rewriter decide which of many matching rules to select</li>
  </ul>
</blockquote>

<p>And a tiny Thue implementation in Raku:</p>

<pre><code class="language-raku">#!/usr/bin/env raku

grammar Thue {
    token TOP { 
        :my $*PAST-DIVIDER = False;
        \v* [&lt;line&gt; \v*]+ 
    }
    token line {
    || &lt;?{ $*PAST-DIVIDER }&gt; &lt;slurp&gt;
    || &lt;divider&gt;
    || &lt;rule&gt;
    }
    token slurp { (.+) $ }
    token divider { 
        ^^ '---' $$ 
        {$*PAST-DIVIDER = True}
    }
    regex rule { ^^ (.*?) (&lt;becomes&gt;) (\V*) $$ }
    proto token becomes {*}
          token becomes:sym&lt;regular&gt; { ':=' }
          token becomes:sym&lt;output&gt; { ':~' }
}

class RunThue {
    has %.rules;
    method slurp ($/) { 
        my @lhses = %!rules.keys.pick: *;
        my $did = False;
        my $state = $/;
        for @lhses -&gt; $lhs {
            $state.=subst($lhs, { $did = True; %!rules{$_} });
        }
        say $state;
        samewith(self, $state) if $did 
    }
    method rule ($/) { 
        say "got rule!! ", ($0 =&gt; $2);
        %!rules{$0} = $2; 
    }
}

Thue.parse: '
1_:=1++
0_:=1

01++:=10
11++:=1++0

_0:=_
_1++:=10

---

_1111111111_', actions =&gt; RunThue.new
</code></pre>

<h3 id="some-apl-with-lazy-function-application-adts-and-a-query-based-compiler">Some APL with lazy function application, ADTs, and a query-based compiler</h3>

<p>As always, my title does the language perfect justice &gt;:)</p>

<p>I’ve written way more about this in the readme for the language, you ought to just defer to that: <a href="https://github.com/DataKinds/apl">https://github.com/DataKinds/apl</a>.</p>

<h3 id="drill">DRILL</h3>

<p>It’s a subset of <a href="http://sam.cat-v.org/">Sam</a> that I wrote in 2 days for a silly Discord game. The code can be found <a href="https://github.com/DataKinds/drill">here</a>, and I often come back and stare at it because it’s the best C99 I wrote this year.</p>

<h3 id="a-forth-with-blackjack-hookers-and-row-types">A Forth, with blackjack, hookers, and row types</h3>

<p>You wanted me to write something here? I never promised that. Here’s a discord screenshot: <img src="/assets/imgs/2025-12-31-05-36-00.png" alt="Big ol discord screenshot that essentially amounts to me reinventing row types from first principals" /></p>

<p>I’m sorry to those who use screen readers, I am trading speed of writing this article for accessibility here. I gotta run to a NYE party after I post this, and I don’t even look cute yet. It’s kind of messed up if you really think about it.</p>

<p>Here are the two links from the screenshot. Good stuff!</p>

<ul>
  <li><a href="https://dl.acm.org/doi/pdf/10.1145/3290325">https://dl.acm.org/doi/pdf/10.1145/3290325</a></li>
  <li><a href="https://thunderseethe.dev/series/making-a-language/">https://thunderseethe.dev/series/making-a-language/</a></li>
</ul>

<h3 id="game-jams">Game Jams</h3>

<p>I signed up for 3, produced 0 games. I need to set my sights lower next time. Bummer!</p>

<h2 id="other-projects">Other projects!</h2>

<h3 id="lil-weirdo">Lil’ Weirdo</h3>

<p>Crap, everyone’s doing AI! <strong>Good thing I did it first.</strong> Predating character.AI, Sora, Meta’s fake girlfriends, or that one other discord bot that got banned for endagering kids, I present <a href="https://github.com/DataKinds/lilweirdo">Lil Weirdo</a>.</p>

<p>Lil Weirdo will keep a configurable message log in its special little brain, and it’ll use that message log in order to either insult or aggresively try to flirt with other users. Because it also remembers the messages that it previously sent, it usually ends up going all tsundere on you.</p>

<p>It can do a handful of other things too, like generate random video game achievements or random crafting recipies. I think I honed in the prompts pretty well, check them out here: <a href="https://github.com/DataKinds/lilweirdo/blob/main/src/templater.py#L81-L508">https://github.com/DataKinds/lilweirdo/blob/main/src/templater.py#L81-L508</a>.</p>

<p>It’s also set up to only use locally run LLMs through Ollama (which I think is adware now, so I gotta find something else).</p>

<h3 id="media-ive-consumed">Media I’ve consumed!</h3>

<p>Over the last few months I have felt my attention span return to me like a corpse-carrying eagle descending from the sky. It splays out its bounty – a ton of paperbacks.</p>

<p>I’ve been super into horror and sci-fi. Bird Box by Josh Malerman was great. Didn’t breathe the whole time. Three Body Problem by Cixin Liu was killer and I’m reading the second one now. I re-read There Is No Antimemetics Department by qntm.</p>

<p>I’m also gaming. Deadlock has been a godsend this year – finally, a good MOBA that isn’t League of Legends or DOTA 2! I love how they blended the chaos of hero shooters with the chess-ness of MOBAs. This year was another great one for roguelikes: Megabonk, Ball X Pit, and Risk of Rain 2 all had their moments.</p>

<h1 id="thank-you">Thank you!</h1>

<p>Thank you to all who read this site, thank you to the friends I’ve made on Discord, and thank the stars that we are afforded another beautiful year. Life would not be as rich without any of this fun stuff to talk about. See ya 2025, happy 2026!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Hi gang. I haven’t been writing in a while. And that’s okay! I’ve been reading. And stepping away from the computer. Sometimes even crafting. Buying a house, and building stuff for the house.]]></summary></entry><entry><title type="html">2024 December Adventure Log</title><link href="https://datakinds.github.io//2024/12/02/2024-december-adventure-log" rel="alternate" type="text/html" title="2024 December Adventure Log" /><published>2024-12-02T16:28:00+00:00</published><updated>2024-12-02T16:28:00+00:00</updated><id>https://datakinds.github.io//2024/12/02/2024-december-adventure-log</id><content type="html" xml:base="https://datakinds.github.io//2024/12/02/2024-december-adventure-log"><![CDATA[<p>Hello all! I will be participating in the 2024 <a href="https://eli.li/december-adventure">December Adventure</a>, and this is my captain’s log for the month. From Eli’s page:</p>

<blockquote>
  <p>The <a href="https://adventofcode.com/">Advent of Code</a> is cool, but a lot, and not everyone’s jam.
The December Adventure is low key. The goal is to write a little bit of code every day in December.</p>
  <h2 id="how">How?</h2>
  <p>Pick a project, or projects and work on them a little bit every day in December.</p>
</blockquote>

<h1 id="day-2-12224">Day 2 (12/2/24)</h1>

<p>Got this page set up and did a little brainstorming for what I want to work on this month. I know that there are two things off the top of my head I wanted to hammer out:</p>

<ul>
  <li>I wanted to get an 88x31 badge set up for my website, along with a little area to display others’ 88x31s. <a href="https://zptr.cc/">yui</a> asked me last month and I still have not bothered…</li>
  <li>I want to work more on <a href="https://github.com/DataKinds/tree-rewriter">Rosin</a> – specifically, fleshing out the pattern variables to allow any variable to specify its eagerness, and adding syntax for rewriting a global state on top of the s-expr rewrite pointer. Something like</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(; $comment) ~&gt; 

(; (This rewrite has no state attached))
hello ~&gt; world

(; (This rewrite only runs if there's a `ready` in the global bag))
hello |ready|~|done| world

(; (So we need new syntax for "lambda rules", rules which only run once. We use a backslash in place of the tilde.))
(; (Here's a "lambda rule" which adds a `ready` to the bag. The following rules are equivalent.))
\|ready|
||\|ready|
</code></pre></div></div>

<p>DAY 2 UPDATE 1: I ended up finishing a pretty good majority of the refactor that was required to flesh out pattern variables in Rosin! Check out the big ol’ git diff <a href="https://github.com/DataKinds/tree-rewriter/pull/1/files">here</a>.</p>

<h1 id="day-3-1232024">Day 3 (12/3/2024)</h1>

<p>I may or may not have stayed up past my bedtime working on Rosin… I’m passing all my regression tests on the new pattern variable branch!! Now we can swap eagerness on and off on all variables, even special accumulators. Tomorrow (today, after a sleep) I should write some more regression tests, for the pack/unpack accumulators and for the universal eagerness switch.</p>

<p>On the left, some of my regression tests. On the right, my passing test dashboard!</p>

<p><img src="/assets/imgs/december-adventure/2-regressionsuite.png" alt="A snippet of my regression suite" width="400" /> <img src="/assets/imgs/december-adventure/2-regressionpass.png" alt="My passing regression tests!" width="700" /></p>

<p>UPDATE 1: it’s 10:18pm, I just finished up a minor redesign of my site. Hopefully this color scheme is easier to read, and the header is no longer the size of the screen + it’s no longer begging for your attention. The mobile version of the site was also improved, so it should no longer be impossibly narrow on narrow screens. Let me know how it works!!</p>

<p>Update 2: Merged in my pattern variable refactor in Rosin and that simplified things nicely. I also <a href="https://github.com/DataKinds/tree-rewriter/tree/main/sample/regression">split apart the regression tests to make them stop sharing state</a> and updated the readme to reflect the new syntax.</p>

<h1 id="day-4">Day 4</h1>

<p>You know, I really don’t have to put the dates on the headings of each of these entries.</p>

<p>Today I worked a bit more on souping up the tests in Rosin. I made tests be <a href="https://github.com/DataKinds/tree-rewriter/commit/7a8da5a748d455e11f78e04ef16417323614cfdf#diff-0a88c502e6b2fded6c22871f555f64a0da4a9fc0213e4b7b067f15f51f2780be">printed to standard out</a> instead of requiring the compiler to output the final state. I also separated all the <a href="https://github.com/DataKinds/tree-rewriter/tree/main/sample/regression">test files into multiple different files</a> so they run in their own contexts.</p>

<p>All of this makes running tests quite nice. The Makefile lets me run specific sets of tests too.</p>

<p><img src="/assets/imgs/december-adventure/4-tests1.png" alt="Makefile running just one set of tests" />
<img src="/assets/imgs/december-adventure/4-tests2.png" alt="Makefile running all my tests" /></p>

<p>I also fixed some (but not all) bugs with the accumulators I uncovered while writing extra tests. For example, the Pack and Unpack accumulators don’t work quite how I want them to. They don’t quite walk the s-expression fully and it’s quite buggy.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>((pack ?@) ~&gt; ?@)
(pack (this (is a (strangely) nested) list)) 
 --- became --- 
(this is a) 
</code></pre></div></div>

<p>I’ll have to deal with that soon. For something I fixed… turns out if you matched multiple values against the negate accumulator, they’d all come back backwards.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>((negate ?- ?- ?-) ~&gt; ?-)
(negate 1 2 3) 
 --- became ---
(-3 -2 -1)
</code></pre></div></div>

<p>That’s fixed now. Progress!</p>

<h1 id="day-5">Day 5</h1>

<p>Didn’t do a lot of coding today. Between moving, work, and having a house guest over tonight I simply wasn’t sitting at the computer for very long.</p>

<p>I got about an hour to myself. I started thinking a bit about setting up a runtime state abstraction in Rosin. This will let me add a multiset bag, support one time lambda rules, and set up a better more explicit ordering for how rules are ingested and then applied.</p>

<p>My changes are still very preliminary, <a href="https://github.com/DataKinds/tree-rewriter/pull/2/files">I posted them up onto a separate branch</a>.</p>

<p>For background entertainment, I was watching this today:</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/GlPREQ55kzc?si=_2kTb6gSJyVrsogX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>

<h1 id="day-9">Day 9</h1>

<p>Whew. I am sorry for the lack of updates, but the last couple of days flew by. On the 6th and the 7th, my partner and I were going back and forth to the house we’re moving into. On the 7th and 8th our power was out. To be more specific: the power was out in exactly half of our unit – and my computer’s outlet was unfortunately affected. All the while I have work and other shenanigans that get in the way. Le sigh… we cringe on…</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/NmACjr4mAIY?si=DdYx7fkfBZh3H7mf" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>

<p>I worked on Rosin a little bit tonight. I fixed a bug in the new <a href="https://wiki.haskell.org/Zipper">tree zipper</a> datatype <a href="https://github.com/DataKinds/tree-rewriter/blob/main/src/Zipper.hs#L81-L90">where moving the zipper down to the first child</a> would <a href="https://github.com/DataKinds/tree-rewriter/commit/9aebbc03a45af3b47bc615feac96be6e9368a0ca#diff-37b5a1b9dce90ec661a8a9b74adc0b64c58e8c2c62b9717cbcacefff2b45074eL51">reverse the right hand side of the context</a>. I suppose it made sense at the time but hindsight is 50-50 and I cursed my past self. So the zipper works correctly now which is pretty cool. It worked well enough <a href="https://github.com/DataKinds/tree-rewriter/commit/5285ea99ed5b5acc8dbd584e12eef09563c3d0f0">so I merged the zipper into main :3</a></p>

<p>I have been listening to a lot of Remi Wolf.</p>

<iframe style="border-radius:12px" src="https://open.spotify.com/embed/track/1Wi1XpdZzGVIdRTzlTrIEF?utm_source=generator" width="100%" height="152" frameborder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe>

<h1 id="day-10">Day 10</h1>

<p>Rosin progresses little by little. You can now define single use rules with <code class="language-plaintext highlighter-rouge">~</code>, like so:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ rosin -p
(/evil/ ~ "$&lt;good$&gt;") "the evil wizard" "the evil tower"


+-----------------+
| Final transform |
+-----------------+
"the good wizard"
"the evil tower"
</code></pre></div></div>

<p>So that will definitely allow for some fun stuff.</p>

<p>I want to start writing more interesting programs in Rosin, but I keep going down development rabbitholes. The final rabbithole is nearing its conclusion: I have hashed out how I want multiset state rules to look. You will be able to interact with the multiset bag on the rewrite head with the <code class="language-plaintext highlighter-rouge">(:needs | :gives)</code> pattern. The same function that matched <code class="language-plaintext highlighter-rouge">~&gt;</code> rules WILL SOON know how to match all variations of these <code class="language-plaintext highlighter-rouge">|</code> rules… <a href="https://github.com/DataKinds/tree-rewriter/blob/main/src/Runtime.hs#L105">but it’s not quite there yet</a>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ rosin-can't-do-this-quite-yet -p

(|(apple pear orange peach)) puts an apple, pear, orange, and peach into the bag
(apple |) takes an apple out of the bag
(apple |) doesn't match a second time 

+-----------------+
| Final transform |
+-----------------+
puts an apple, pear, orange, and peach into the bag
takes an apple out of the bag
(apple |) doesn't match a second time
</code></pre></div></div>

<p>Both sides do not need to be specified. <code class="language-plaintext highlighter-rouge">|</code> indicates a multiset matching rule that will only run once, and <code class="language-plaintext highlighter-rouge">|&gt;</code> rules will run ad infinitum.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>( (pear apple grape peach) |&gt; ((fruit salad)) )
now the combination of pear, apple, grape, and peach will always become (fruit salad)
</code></pre></div></div>

<p>Wait, I heard you say: <code class="language-plaintext highlighter-rouge">(fruit salad)</code>? Like, you put an S-expression into the multiset? Heck yeah I did! <a href="https://github.com/DataKinds/tree-rewriter/blob/main/src/Runtime.hs#L45">The full range of Rosin values can go into the multiset</a> and this means we’ll be able to hijack the pattern variable machinery to do some very cute things:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>( (sword (stone :name)) | ((sword :name)) )

( | (stone "King's stone"))
( | sword)
will produce one thing in the bag: (sword "King's stone")
a sword's strength is derived from its legendary name
</code></pre></div></div>

<p>Last but not least – you’ll be able to devise a rule that only matches the S-expression tree when something is in the multiset bag. Or a tree rewrite rule that adds something into the bag. The <code class="language-plaintext highlighter-rouge">&amp;</code> symbol will be able to combine a multiset rewriting rule with a tree rewriting rule, such that the combined rule only matches when both conditions are satisfied. This has some crazy potential imo, and I just nailed down the syntax tonight:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(| n &amp; hello ~&gt; world) 
produces an n to the bag every time it matches `hello`

(n n | m &amp; (; :comment) ~&gt;) 
limits the amount of comments you can write to half the `hello`s you write... better be polite!
</code></pre></div></div>

<p>Some of this is implemented, some of it isn’t… but I feel good having this all theorycrafted and the way forward from here seems clear to me.</p>

<h1 id="day-11">Day 11</h1>

<p>Only posting a quick update today because I want to head to sleep early!!</p>

<p>A few new Rosin updates for ya….</p>

<p>I added a new regression test for the multiset state:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(Test a "Plain terms can be parsed and consumed"
    Given (
        ((pomme pomegranate) |&gt; weird-fruit-salad)
        (|pomme)
        (|pomegranate)
        (|(pomme pomegranate))
        (weird-fruit-salad|)
        (weird-fruit-salad |)
    )
    We expect ())
</code></pre></div></div>

<p>I finished setting up <a href="https://github.com/DataKinds/tree-rewriter/blob/main/src/Runtime.hs#L135">the consumption of rules with multiset action</a>, see <code class="language-plaintext highlighter-rouge">recognizeDef</code>. So Rosin will now really recognize and consume all these forms of rules:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(pattern ~&gt; template) a tree rewriting rule
(pattern ~ template) a one time tree rewriting rule
((things i want) |&gt; (things i will get)) a multiset rewriting rule
((things i want) | (things i will get)) a one time multiset rewriting rule
(want | get &amp; pattern ~ template) a one time combined tree+multiset rewriting rule
(want | get &amp; pattern ~&gt; template) a combined tree+multiset rewriting rule
</code></pre></div></div>

<p>Note that the shortened forms from the regression test (like <code class="language-plaintext highlighter-rouge">(weird-fruit-salad |)</code>) won’t currently work.</p>

<p>Very soon Rosin will be able to apply tree rewrite rules conditionally based on the state of the multiset, <a href="https://github.com/DataKinds/tree-rewriter/blob/main/src/Runtime.hs#L180">but for now I left a hole in the function</a> where it will be filled with dedicated <code class="language-plaintext highlighter-rouge">Multiset</code> methods. Soon. I’m so close to having this working.</p>

<div class="language-hs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- Filters a list of defs down to only those which are satisfied by the current state of the multiset</span>
<span class="n">filterByMultiset</span> <span class="o">::</span> <span class="kt">Monad</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="kt">EatenDef</span><span class="p">]</span> <span class="o">-&gt;</span> <span class="kt">RuntimeTV</span> <span class="n">m</span> <span class="p">[</span><span class="kt">EatenDef</span><span class="p">]</span>
<span class="n">filterByMultiset</span> <span class="n">defs</span> <span class="o">=</span> <span class="kr">do</span>
    <span class="n">pocket</span> <span class="o">&lt;-</span> <span class="n">gets</span> <span class="n">runtimeMultiset</span> 
    <span class="n">pure</span> <span class="o">$</span> <span class="n">filter</span> <span class="p">(</span><span class="n">ok</span> <span class="n">pocket</span><span class="p">)</span> <span class="n">defs</span>
    <span class="kr">where</span> <span class="n">ok</span> <span class="n">ms</span> <span class="o">=</span> <span class="n">undefined</span>
</code></pre></div></div>

<p>For anyone still reading, thanks for sticking with me on this journey. I have really been looking forward to writing these entries every night.</p>

<h1 id="day-15">Day 15</h1>

<p>I spent the day today on the phone with banks and electricians making preparations for the new house. A few days ago my partner and I hosted a packing party. All of our friends came over, ate pizza, and put our belongings into boxes. Progress on my blog or projects has taken a bit of a backseat to moving.</p>

<p>All that being said, I worked on Rosin a bit more tonight!</p>

<p>There is a full fledged <code class="language-plaintext highlighter-rouge">Multiset</code> type now. All I’ve got implemented is reading things out of the multiset but putting things in will come soon enough.</p>

<div class="language-hs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">module</span> <span class="nn">Multiset</span> <span class="kr">where</span>
<span class="kr">import</span> <span class="k">qualified</span> <span class="nn">Data.Map</span> <span class="k">as</span> <span class="n">M</span>
<span class="kr">import</span> <span class="nn">Control.Monad</span> <span class="p">(</span><span class="nf">foldM</span><span class="p">)</span>


<span class="kr">newtype</span> <span class="kt">Ord</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="kt">Multiset</span> <span class="n">a</span> <span class="o">=</span> <span class="kt">Multiset</span> <span class="p">{</span> <span class="n">unmultiset</span> <span class="o">::</span> <span class="kt">M</span><span class="o">.</span><span class="kt">Map</span> <span class="n">a</span> <span class="kt">Int</span> <span class="p">}</span> <span class="kr">deriving</span> <span class="p">(</span><span class="kt">Show</span><span class="p">)</span>

<span class="n">fromList</span> <span class="o">::</span> <span class="kt">Ord</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="p">[(</span><span class="n">a</span><span class="p">,</span> <span class="kt">Int</span><span class="p">)]</span> <span class="o">-&gt;</span> <span class="kt">Multiset</span> <span class="n">a</span>
<span class="n">fromList</span> <span class="o">=</span> <span class="kt">Multiset</span> <span class="o">.</span> <span class="kt">M</span><span class="o">.</span><span class="n">fromList</span>

<span class="n">toList</span> <span class="o">::</span> <span class="kt">Ord</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="kt">Multiset</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="p">[(</span><span class="n">a</span><span class="p">,</span> <span class="kt">Int</span><span class="p">)]</span> 
<span class="n">toList</span> <span class="o">=</span> <span class="kt">M</span><span class="o">.</span><span class="n">toList</span> <span class="o">.</span> <span class="n">unmultiset</span>

<span class="n">empty</span> <span class="o">::</span> <span class="kt">Ord</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="kt">Multiset</span> <span class="n">a</span>
<span class="n">empty</span> <span class="o">=</span> <span class="kt">Multiset</span> <span class="kt">M</span><span class="o">.</span><span class="n">empty</span>

<span class="n">null</span> <span class="o">::</span> <span class="kt">Ord</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="kt">Multiset</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Bool</span>
<span class="n">null</span> <span class="o">=</span> <span class="kt">M</span><span class="o">.</span><span class="n">null</span> <span class="o">.</span> <span class="n">unmultiset</span>

<span class="c1">-- Is this element inside the multiset in a sufficient quantity? </span>
<span class="n">inside</span> <span class="o">::</span> <span class="kt">Ord</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="kt">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Multiset</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Bool</span>
<span class="n">inside</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span> <span class="o">=</span> <span class="n">maybe</span> <span class="kt">False</span> <span class="p">(</span><span class="n">n</span> <span class="o">&lt;=</span><span class="p">)</span> <span class="o">.</span> <span class="kt">M</span><span class="o">.</span><span class="n">lookup</span> <span class="n">x</span> <span class="o">.</span> <span class="n">unmultiset</span> 

<span class="c1">-- Are these elements inside the multiset in a sufficient quantity? </span>
<span class="n">allInside</span> <span class="o">::</span> <span class="kt">Ord</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="kt">Multiset</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Multiset</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Bool</span>
<span class="n">allInside</span> <span class="n">xns</span> <span class="n">ms</span> <span class="o">=</span> <span class="n">all</span> <span class="p">(`</span><span class="n">inside</span><span class="p">`</span> <span class="n">ms</span><span class="p">)</span> <span class="p">(</span><span class="n">toList</span> <span class="n">xns</span><span class="p">)</span>

<span class="c1">-- Take out this many copies of this element from our multiset, if we can!</span>
<span class="n">grab</span> <span class="o">::</span> <span class="kt">Ord</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="kt">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Multiset</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="p">(</span><span class="kt">Multiset</span> <span class="n">a</span><span class="p">)</span>
<span class="n">grab</span> <span class="n">xn</span><span class="o">@</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">n</span><span class="p">)</span> <span class="n">ms</span> <span class="o">=</span> <span class="kr">if</span> <span class="n">inside</span> <span class="n">xn</span> <span class="n">ms</span> <span class="kr">then</span> <span class="kt">Just</span> <span class="o">.</span> <span class="kt">Multiset</span> <span class="o">.</span> <span class="kt">M</span><span class="o">.</span><span class="n">adjust</span> <span class="p">(</span><span class="n">subtract</span> <span class="n">n</span><span class="p">)</span> <span class="n">x</span> <span class="o">.</span> <span class="n">unmultiset</span> <span class="o">$</span> <span class="n">ms</span> <span class="kr">else</span> <span class="kt">Nothing</span>

<span class="c1">-- Take out this many copies of these elements from our multiset, if we can!</span>
<span class="n">grabMany</span> <span class="o">::</span> <span class="kt">Ord</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="kt">Multiset</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Multiset</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="p">(</span><span class="kt">Multiset</span> <span class="n">a</span><span class="p">)</span>
<span class="n">grabMany</span> <span class="n">xns</span> <span class="n">ms</span> <span class="o">=</span> <span class="kt">Multiset</span> <span class="o">&lt;$&gt;</span> <span class="n">foldM</span> <span class="p">(</span><span class="nf">\</span><span class="n">m</span> <span class="n">xn</span> <span class="o">-&gt;</span> <span class="n">unmultiset</span> <span class="o">&lt;$&gt;</span> <span class="n">grab</span> <span class="n">xn</span> <span class="p">(</span><span class="kt">Multiset</span> <span class="n">m</span><span class="p">))</span> <span class="n">ms'</span> <span class="n">xns'</span>
    <span class="kr">where</span> <span class="n">ms'</span> <span class="o">=</span> <span class="n">unmultiset</span> <span class="n">ms</span><span class="p">;</span> <span class="n">xns'</span> <span class="o">=</span> <span class="n">toList</span> <span class="n">xns</span>
</code></pre></div></div>

<p>The Rosin runtime now checks that the multiset is satisfactory for any given function before using it to rewrite. Check out that sick ass runtime:</p>

<div class="language-hs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- Filters a list of defs down to only those which are satisfied by the current state of the multiset</span>
<span class="n">filterByMultiset</span> <span class="o">::</span> <span class="kt">Monad</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="kt">EatenDef</span><span class="p">]</span> <span class="o">-&gt;</span> <span class="kt">RuntimeTV</span> <span class="n">m</span> <span class="p">[</span><span class="kt">EatenDef</span><span class="p">]</span>
<span class="n">filterByMultiset</span> <span class="n">defs</span> <span class="o">=</span> <span class="kr">do</span>
    <span class="n">pocket</span> <span class="o">&lt;-</span> <span class="n">gets</span> <span class="n">runtimeMultiset</span> 
    <span class="n">pure</span> <span class="o">$</span> <span class="n">filter</span> <span class="p">(</span><span class="n">ok</span> <span class="n">pocket</span><span class="p">)</span> <span class="n">defs</span>
    <span class="kr">where</span> 
        <span class="n">ok</span> <span class="o">::</span> <span class="kt">MS</span><span class="o">.</span><span class="kt">Multiset</span> <span class="p">(</span><span class="kt">Tree</span> <span class="kt">RValue</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">EatenDef</span> <span class="o">-&gt;</span> <span class="kt">Bool</span>
        <span class="n">ok</span> <span class="n">ms</span> <span class="n">def</span> <span class="o">=</span> <span class="kt">MS</span><span class="o">.</span><span class="n">allInside</span> <span class="p">(</span><span class="n">defWantsFromBag</span> <span class="n">def</span><span class="p">)</span> <span class="n">ms</span>

<span class="c1">-- Carry out one step of Rosin's execution. This essentially carries out the following:</span>
<span class="c1">--   1) We check for a definition at the current rewrite head and ingest it if there's one there</span>
<span class="c1">--   2) We try to apply our rewrite rules at the current rewrite head</span>
<span class="c1">--   3) We move onto the next element in the tree in DFS order. If we're at the end, we loop back to the start</span>
<span class="c1">-- Gives back (the amount of rules applied, whether we jumped back to the top of the tree). </span>
<span class="n">runStep</span> <span class="o">::</span> <span class="kt">RuntimeTV</span> <span class="kt">IO</span> <span class="p">(</span><span class="kt">Int</span><span class="p">,</span> <span class="kt">Bool</span><span class="p">)</span>
<span class="n">runStep</span> <span class="o">=</span> <span class="kr">do</span>
    <span class="n">verbose</span> <span class="o">&lt;-</span> <span class="n">gets</span> <span class="n">runtimeVerbose</span>
    <span class="c1">-- Begin 1</span>
    <span class="n">eatDef</span> 
    <span class="c1">-- Begin 2</span>
    <span class="c1">-- Apply single use tree rewriting rules</span>
    <span class="c1">-- !!! ===== We check the multiset here!!! Take a look....  ===== !!! --</span>
    <span class="n">defs</span> <span class="o">&lt;-</span> <span class="n">gets</span> <span class="n">runtimeSingleUseRules</span> <span class="o">&gt;&gt;=</span> <span class="n">filterByMultiset</span>
    <span class="n">maybeTreeRewrite</span> <span class="o">&lt;-</span> <span class="n">applyTreeDefs</span> <span class="n">defs</span>
    <span class="n">when</span> <span class="p">(</span><span class="n">isJust</span> <span class="n">maybeTreeRewrite</span><span class="p">)</span> <span class="o">$</span> <span class="kr">do</span> <span class="c1">-- A single use rule matched once, we gotta delete it!</span>
        <span class="kr">let</span> <span class="p">(</span><span class="kt">Rewrite</span> <span class="n">patternToDelete</span> <span class="kr">_</span><span class="p">)</span> <span class="o">=</span> <span class="n">fromJust</span> <span class="n">maybeTreeRewrite</span>
        <span class="n">modifyRuntimeSingleUseRules</span> <span class="p">(</span><span class="n">filter</span> <span class="p">(</span><span class="n">patternDefEq</span> <span class="n">patternToDelete</span><span class="p">))</span>
    <span class="c1">-- Apply multi use tree rewriting rules</span>
    <span class="c1">-- !!! ===== We check the multiset here again!!! Wow!!!!!  ===== !!! --</span>
    <span class="n">defs'</span> <span class="o">&lt;-</span> <span class="n">gets</span> <span class="n">runtimeRules</span> <span class="o">&gt;&gt;=</span> <span class="n">filterByMultiset</span>
    <span class="n">maybeTreeRewrite'</span> <span class="o">&lt;-</span> <span class="n">applyTreeDefs</span> <span class="n">defs'</span>
    <span class="c1">-- Begin 3 (I Love Laziness)</span>
    <span class="n">newZipper</span> <span class="o">&lt;-</span> <span class="n">gets</span> <span class="p">(</span><span class="kt">Z</span><span class="o">.</span><span class="n">nextDfs</span> <span class="o">.</span> <span class="n">runtimeZipper</span><span class="p">)</span>
    <span class="n">modifyRuntimeZipper</span> <span class="p">(</span><span class="n">const</span> <span class="n">newZipper</span><span class="p">)</span>
    <span class="n">when</span> <span class="n">verbose</span> <span class="p">(</span><span class="n">lift</span> <span class="o">$</span> <span class="n">print</span> <span class="n">newZipper</span><span class="p">)</span>
    <span class="c1">-- Give back the value we use to assess termination</span>
    <span class="n">atTop</span> <span class="o">&lt;-</span> <span class="n">gets</span> <span class="p">((</span><span class="o">==</span> <span class="kt">[]</span><span class="p">)</span> <span class="o">.</span> <span class="kt">Z</span><span class="o">.</span><span class="n">_Ups</span> <span class="o">.</span> <span class="n">runtimeZipper</span><span class="p">)</span>
    <span class="n">pure</span> <span class="p">(</span><span class="n">sum</span> <span class="o">$</span> <span class="n">maybe</span> <span class="mi">0</span> <span class="p">(</span><span class="n">const</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&lt;$&gt;</span> <span class="p">[</span><span class="n">maybeTreeRewrite</span><span class="p">,</span> <span class="n">maybeTreeRewrite'</span><span class="p">],</span> <span class="n">atTop</span><span class="p">)</span>
        <span class="kr">where</span>
            <span class="c1">-- True if the EatenDef has the same pattern as the tree</span>
            <span class="n">patternDefEq</span> <span class="o">::</span> <span class="kt">Tree</span> <span class="kt">RValue</span> <span class="o">-&gt;</span> <span class="kt">EatenDef</span> <span class="o">-&gt;</span> <span class="kt">Bool</span>
            <span class="n">patternDefEq</span> <span class="n">pat1</span> <span class="n">def</span> <span class="o">=</span> <span class="kr">case</span> <span class="n">defToRewrite</span> <span class="n">def</span> <span class="kr">of</span>
                <span class="kt">Nothing</span> <span class="o">-&gt;</span> <span class="kt">True</span>
                <span class="kt">Just</span> <span class="p">(</span><span class="kt">Rewrite</span> <span class="n">pat2</span> <span class="kr">_</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">pat1</span> <span class="o">/=</span> <span class="n">pat2</span> 
</code></pre></div></div>

<p>Sorry. Maybe it’s rude to throw a huge block of code at you at once. I ought to be more polite.</p>

<p>Anyways, Rosin will now refuse to match a rule if the multiset state is insufficient. Look!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cat sample/small.tree; rosin -p sample/small.tree 
(fruit-salad | () &amp; hello ~&gt; world)
(1 2 3 hello 4 5 6)

+-----------------+
| Final transform |
+-----------------+
(defined "Multiset {unmultiset = fromList [(fruit-salad,1)]}| &amp; hello ~&gt; world")
(1 2 3 hello 4 5 6)
</code></pre></div></div>

<p>So that’s that. Hope you enjoyed! Next time maybe we’ll go less heavy on the Haskell and heavier on the Rosin. Talk to you soon!</p>

<h1 id="day-16">Day 16</h1>

<p>Tonight cost me a lot of my sanity and I will inevitably be gluing back together the pieces of my sleep-deprived codebase later.</p>

<p>That being said… <a href="https://github.com/DataKinds/tree-rewriter/commit/3a3e4fca7edae9fb754a0c312aeff2f4744cd50f">Rosin now has full support for rules which interact with multiset state</a>. It’s done oh my god it’s done. Done enough to start writing tests for and to start making more informed decisions on structuring the codebase. They don’t do anything fancy like match against regex but that can all happen soon. We have a foundation in place to build off of!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cat sample/poc.rosin; rosin -p sample/poc.rosin 
(| pear)
(| pear)
(| pear)
(| orange)

(@ bag)

((pear pear) | pear-salad)

(@ bag)

+-----------------+
| Final transform |
+-----------------+
((orange 1) (pear 3))
((orange 1) (pear 1) (pear-salad 1))
</code></pre></div></div>

<p>What’s <code class="language-plaintext highlighter-rouge">(@ bag)</code>, you may ask? That’s a builtin! This particular builtin writes out the current state of the multiset bag.</p>

<p>There are a couple of builtins hanging around now. Most notably <code class="language-plaintext highlighter-rouge">(@ parse :str)</code> which parses a string into a Rosin tree, and <code class="language-plaintext highlighter-rouge">(@ cat :path)</code> which loads another file as a string. These together make my test files prettier.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>((p ?&gt;) ~&gt; ?&gt;)
((t :desc :!got :wanted) ~&gt; (p (❌ :desc got :got wanted :wanted)))
((t :desc :!val :val) ~&gt; (p (✅ :desc :val)))
((Test a :desc Given :test We expect :val) ~&gt; (t :desc :test :val))

(Test a "Lambda rule"
    Given (((fruit basket) ~ apples oranges pears dragonfruit) 
           (fruit basket) 
           (fruit basket)) 
    We expect (apples oranges pears dragonfruit
               (fruit basket)))

(Test a "Confusing named rule"
       Given ((once ~ once once) once) We expect (once once))
</code></pre></div></div>

<p>now becomes</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(@ parse (@ cat "t.rosin"))

(Test a "Lambda rule"
    Given (((fruit basket) ~ apples oranges pears dragonfruit) 
           (fruit basket) 
           (fruit basket)) 
    We expect (apples oranges pears dragonfruit
               (fruit basket)))

(Test a "Confusing named rule"
       Given ((once ~ once once) once) We expect (once once))
</code></pre></div></div>

<p>which is way cuter if I do say so myself.</p>

<p>More to come soon!</p>

<h1 id="day-17">Day 17</h1>

<p>Nothing today. I played through a cute little game called <a href="https://store.steampowered.com/app/3361470/Digseum/">Digseum</a> after work tonight.</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/E19QiXv27I8?si=WuYzU35pfNAjIFGN" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>

<p>It was absolutely adorable. Worth the $2 and quite satisfying to boot.</p>]]></content><author><name></name></author><category term="software" /><category term="december-adventure" /><summary type="html"><![CDATA[Hello all! I will be participating in the 2024 December Adventure, and this is my captain’s log for the month. From Eli’s page:]]></summary></entry><entry><title type="html">Stop Asking What, Start Asking Why</title><link href="https://datakinds.github.io//2024/11/13/stop-asking-what-start-asking-why" rel="alternate" type="text/html" title="Stop Asking What, Start Asking Why" /><published>2024-11-13T22:03:00+00:00</published><updated>2024-11-13T22:03:00+00:00</updated><id>https://datakinds.github.io//2024/11/13/stop-asking-what-start-asking-why</id><content type="html" xml:base="https://datakinds.github.io//2024/11/13/stop-asking-what-start-asking-why"><![CDATA[<p>It tends to be the case that doing something professionally can kill one’s drive to do so recreationally. Despite this, I still enjoy hobby programming and participating in online programming communities in my off-time. In these communities I have found a wealth and breadth of knowledge I would not have encountered otherwise. However, that comes with a risk: it is very easy to waste your time online. Even worse, the variance in how much you will get out of any given conversation is massive.</p>

<p>There is a lot of precedent for how to maximize the value of your time when you <em>ask questions</em> online. “<a href="https://solhsa.com/dontask.html">Don’t ask to ask</a>” and (perhaps more humorously) <a href="https://en.wikipedia.org/wiki/Ward_Cunningham#Law">Cunningham’s Law</a> are what immediately comes to my mind in this context. There is much less precedent for how to answer questions – or even why we choose to spend our time answering questions online.</p>

<p>Eric S. Raymond <a href="http://catb.org/~esr/faqs/smart-questions.html">has written at length about asking good questions</a><sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> and yet left the “<em>How To Answer Questions in a Helpful Way</em>” section stunted at 9 suggestions. Stack Overflow is the same: the page <a href="https://stackoverflow.com/help/how-to-ask">describing how to ask questions</a> is rich with direct suggestions on how to make the best use of your time asking questions. Most of the given advice is generally applicable to any development forum with tags and post titles. The <a href="https://stackoverflow.com/help/how-to-answer">page describing how to answer them</a> is about half the length and full of softer advice dedicated to SO’s specific position as a community question-archival site: writing with good grammar, providing context to avoid link bitrot, using the bounty system to ask someone to continue your partial answer.</p>

<p>There is an asymmetry here. Advice given to question-askers involves getting the most value out of the time you and the community spend on said question. This <em>is</em> ultimately the goal of the asker: to learn, to gain value from the question at hand. Contrast this with advice given to question-answerers, which is more scatter-shot and generally revolves around <em>producing a satisfactory answer</em>. This is unmotivating as <em>this is ultimately not the goal of the answerer!</em> I claim, supported by the text above, that there are really two reasons someone would want to answer questions:</p>

<ol>
  <li>
    <p><strong>To learn.</strong></p>

    <p>Common knowledge dictates that one does not understand something if they cannot explain it. Explaining things online is a fantastic way to find one’s own knowledge blind spots; collaborative problem-solving gives a very low-risk opportunity to dive deeper into topics just outside of one’s reach.</p>

    <p>Learning also happens at a community level. Raymond notes that a helpful answer will “<em>[h]elp your community learn from the question.</em> When you field a good question, ask yourself ‘How would the relevant documentation or FAQ have to change so that nobody has to answer this again?’ Then send a patch to the document maintainer.”.</p>
  </li>
  <li>
    <p><strong>To grow their community.</strong></p>

    <p>Raymond notes that “[Hackers] like answering questions for people who have demonstrated they can learn from the answers”. A person who grew after interacting with a community is going to come back for more. This is a positive feedback loop, and it’s multiplied by the near-realtime responses and casual atmosphere given by platforms such as Discord or IRC. Strong learners with interesting, insightful, novel questions make for great community members!</p>
  </li>
</ol>

<p>I am excluding any communities that set up gamified or otherwise perverse objectives to encourage participation (upvote this post if you agree!)</p>

<p>This brings me to my ultimate point: <strong>how do we maximize these incentives as question-answerers</strong>? What can we do to go above and beyond producing helpful answers, making the time we spend answering more valuable to us? Here are a couple of things that I have personally found to make my time participating online more valuable:</p>

<h2 id="the-great-nonexhaustive-framework-for-online-participation">The great, nonexhaustive framework for online participation</h2>

<ul>
  <li>Use realtime platforms to your advantage
    <ul>
      <li>As mentioned above, instant messaging platforms allow for instant feedback between question-askers and question-answerers. Many of the concerns about asking good questions come from a time of email lists and traditional forums, where a lack of information in the original post could take days to be rectified. Over Discord, getting clarifications from askers is often a matter of minutes. This drastically limits the frustration and wasted time associated with badly-framed questions.</li>
      <li>The conversational nature of chat platforms allows troubleshooting and stating a problem space to naturally become brainstorming. This is not the case on Q&amp;A platforms, for example, as there is a strict distinction between “question” and “answer”. Intermediate brainstorming and conversation is relegated to a comments section or a secondary chat room. On an IM platform this distinction does not exist – to maximize learning, one must take advantage of this.</li>
    </ul>
  </li>
  <li>Assume good faith
    <ul>
      <li>This is the titular “stop asking what, start asking why”.
        <ul>
          <li>Bad actors or low-effort posters in online communities are inevitable. That being said,</li>
          <li>I have seen enough instances in programming communities where someone will come in with a conversational style or set of ideas that resemble bad-faith posting. They’ll use ALL CAPS or a twyping qwirk or send / messages / with / one / word. They might be stubborn or rash or stuck on their own ideas.</li>
          <li>These posters often present some of the most unique ideas available, and I have found that engaging can often maximize learning (sometimes at the cost of frustration). As a question-answerer, maximizing learning mandates that one must assume good-faith in these situations and dig into the “why”s of their choices rather than being stuck on the “what”s of their possibly absurd current situation. This <em>does</em> often require skill in analyzing XY problems.</li>
        </ul>
      </li>
      <li>Assuming a given person is a bad actor is a losing-sum game. Consider the cases:
        <ul>
          <li>A good-faith question is met with an assumption of good-faith ➡️ everyone is happy, the question may get answered</li>
          <li>A bad-faith question is met with an assumption of good-faith ➡️ either the asker improves their question, gets bored and leaves, or they escalate, at which point you can disengage</li>
        </ul>
      </li>
      <li>Or, on the contrary:
        <ul>
          <li>A good-faith question is met with an assumption of bad-faith ➡️ a potential community member is turned away</li>
          <li>A bad-faith question is met with an assumption of bad-faith ➡️ time is saved as you may disengage immediately</li>
        </ul>
      </li>
      <li>To maximize community growth, we must therefore assume good-faith to avoid turning away potential community members.</li>
      <li>To maximize learning as a result of these interactions, we must consider that nothing is learned upon turning away community members or immediately disengaging with bad-faith questions. <em>Something</em> may be learned if the is answered or if the badly-posed question is improved. Attempting to assist with the low-effort poster’s issue may give the answerer an opportunity to gain a deeper knowledge of the system being badly asked about.</li>
      <li>Efficient moderation allows active community participants to more effectively gauge when to disengage with an actual bad actor, minimizing the time wasted.</li>
    </ul>
  </li>
  <li>Address XY problems through risk analysis
    <ul>
      <li>To address an XY problem, one must first learn to identify an XY problem.
        <ul>
          <li>Look for questions where the asker wants to know how to carry out a task using tooling that isn’t made for that task</li>
          <li>Look for questions where the asker insists there is only one way forward</li>
          <li>Look for questions where the asker thinks a process is <em>supposed</em> to work.</li>
        </ul>
      </li>
      <li>Address the problem fully if you choose to address it. Ask the asker what they’re trying to accomplish instead of entertaining their solution. Note that they only see trees where you may see the forest. Learn from the aspects of the situation that they’ve missed, and consider if there are any similar workflows that you have that are suffering from the same blind spots.</li>
      <li>Raymond states the fundamental point well: “<em>If you’re going to answer the question at all, give good value.</em> Don’t suggest kludgy workarounds when somebody is using the wrong tool or approach. Suggest good tools. Reframe the question.”</li>
    </ul>
  </li>
  <li>Askers must answer. Answerers must ask.
    <ul>
      <li>To maximize learning, you must be willing to have a conversation!</li>
      <li>Make use of the resource that other question-answerers provide.</li>
      <li>There must be no hierarchical distinction between those who ask and those who answer in a community. Maximization of learning requires that everyone is comfortable to both seek knowledge and to share their subset of knowledge.
        <ul>
          <li>The effect where longer standing members of a community are afforded more technical weight than newer members needs to be explicitly considered when the goal is the breakdown of hierarchy.</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<p>I hope that you’re able to get something out of the suggestions I’ve made above. If not, hopefully the reframing of online discussion as something potentially valuable encourages you to go out and participate :)</p>

<hr />

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Shout out to the footnote at <a href="https://dontasktoask.com/">https://dontasktoask.com/</a> for linking Raymond’s essay, I hadn’t seen it before and it’s a complete treasure trove of info. Without that this whole blog post was just going to be the <code class="language-plaintext highlighter-rouge">Assume good faith</code> bullet point. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name></name></author><category term="software" /><summary type="html"><![CDATA[It tends to be the case that doing something professionally can kill one’s drive to do so recreationally. Despite this, I still enjoy hobby programming and participating in online programming communities in my off-time. In these communities I have found a wealth and breadth of knowledge I would not have encountered otherwise. However, that comes with a risk: it is very easy to waste your time online. Even worse, the variance in how much you will get out of any given conversation is massive.]]></summary></entry><entry><title type="html">[old draft] Ride along wrapper-free game development in Haskell</title><link href="https://datakinds.github.io//2024/09/27/ride-along-game-development-in-haskell" rel="alternate" type="text/html" title="[old draft] Ride along wrapper-free game development in Haskell" /><published>2024-09-27T22:00:00+00:00</published><updated>2024-09-27T22:00:00+00:00</updated><id>https://datakinds.github.io//2024/09/27/ride-along-game-development-in-haskell</id><content type="html" xml:base="https://datakinds.github.io//2024/09/27/ride-along-game-development-in-haskell"><![CDATA[<p>Hey all! I was going through my blog post backlog and found this draft from <code class="language-plaintext highlighter-rouge">2019-06-05</code>. Thought I’d just throw it up on the blog: there’s some useful stuff about Haskell’s FFI here, and I also wax poetic about software development a little bit. This was written before the whole <a href="https://datakinds.github.io/2022/06/17/100-blog-posts">100 blog posts</a> thing so it doesn’t count.</p>

<p>The original title of this was to be “From Context to Cptr: Bare Bones Game Development in Haskell”. I will let 2019 me take it from here.</p>

<hr />

<p>I got into programming when I was 8 because I wanted to make games. I guess, deep down, I was never truly able to satiate that desire. I’ve never released a game, I’ve never completed a game, and hell – I’ve never gotten far enough to even draw up assets for a game.</p>

<p>But I ran into a library yesterday called Raylib that kind of rekindled the playful fire that lived deep down under my pragmaticism. Raylib lives at <a href="https://www.raylib.com/">https://www.raylib.com/</a>. I immediately fired up VS Code and hammered out some C for the first time in two or three years. Suffice to say, I had <em>fun</em>. Not fun like “wow, this code is elegant,” or fun like “wow I’m making a lot of money doing this,” but fun like “I’m giggling at the screen because I made a circle bounce back and forth.”</p>

<p>And that was an incredible feeling.</p>

<p>So, in the spirit of all things good: if it’s worth doing, it’s worth overdoing. That’s why I’m writing this blog post.</p>

<p>This won’t be like any other blog post that I’ve written. I am writing this post live as I’m experimenting with building a game from the bottom up in Haskell. You’ll see every single decision I make, and everything I find exciting enough to share, even if I go back on it five minutes later. No game frameworks, no library bindings – just me, Stack, a fresh install of <a href="https://www.glfw.org/">GLFW</a>, and a readiness to get hacking.</p>

<p>In one window, I have my blog post. In the other window, my code. Without further ado…</p>

<h2 id="923-pm-day-1">9:23 PM, day 1</h2>

<p>I came up with the idea and started writing this blog post.</p>

<h2 id="1119-pm">11:19 PM</h2>

<p>Finally got around to initializing the stack project!</p>

<p><img src="/assets/imgs/ride-along-game-dev/1119.png" alt="Stack project screenshot" /></p>

<h2 id="1257-am">12:57 AM</h2>

<p>Here’s my first attempt at defining enough of a wrapper around GL and GLFW in order to <a href="https://www.glfw.org/documentation.html">run the example code on the GLFW documentation page</a>. This is before I’ve even tried compiling it, so this is pre-iteration-1:</p>

<p><code class="language-plaintext highlighter-rouge">GLFW.hs</code>:</p>

<div class="language-hs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{-# LANGUAGE ForeignFunctionInterface #-}</span>

<span class="kr">module</span> <span class="nn">GLFW</span> <span class="kr">where</span>

<span class="kr">import</span> <span class="nn">Control.Monad</span>

<span class="cd">-- | Init functions</span>
<span class="n">foreign</span> <span class="kr">import</span> <span class="nn">ccall</span> <span class="s">"glfwInit"</span> <span class="n">init</span> <span class="o">::</span> <span class="kt">IO</span> <span class="kt">Int</span>
<span class="n">foreign</span> <span class="kr">import</span> <span class="nn">ccall</span> <span class="s">"glfwTerminate"</span> <span class="n">terminate</span> <span class="o">::</span> <span class="kt">IO</span> <span class="nb">()</span>

<span class="cd">-- | Window functions</span>
<span class="kr">data</span> <span class="kt">Window</span> <span class="o">=</span> <span class="kt">InternalWindow</span> <span class="kr">deriving</span> <span class="p">(</span><span class="kt">Storable</span><span class="p">)</span>
<span class="n">foreign</span> <span class="kr">import</span> <span class="nn">ccall</span> <span class="s">"glfwCreateWindow"</span> <span class="n">createWindow</span> <span class="o">::</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">CString</span> <span class="o">-&gt;</span> <span class="kt">IO</span> <span class="p">(</span><span class="kt">Ptr</span> <span class="kt">Window</span><span class="p">)</span>
<span class="n">foreign</span> <span class="kr">import</span> <span class="nn">ccall</span> <span class="s">"glfwWindowShouldClose"</span> <span class="n">_windowShouldClose</span> <span class="o">::</span> <span class="kt">Ptr</span> <span class="kt">Window</span> <span class="o">-&gt;</span> <span class="kt">IO</span> <span class="kt">Int</span>
<span class="n">windowShouldClose</span> <span class="o">::</span> <span class="kt">Ptr</span> <span class="kt">Window</span> <span class="o">-&gt;</span> <span class="kt">IO</span> <span class="kt">Bool</span>
<span class="n">windowShouldClose</span> <span class="o">=</span> <span class="n">fmap</span> <span class="p">(</span><span class="mi">0</span> <span class="o">/=</span><span class="p">)</span> <span class="o">.</span> <span class="n">_windowShouldClose</span>
<span class="n">foreign</span> <span class="kr">import</span> <span class="nn">ccall</span> <span class="s">"glfwSwapBuffers"</span> <span class="n">swapBuffers</span> <span class="o">::</span> <span class="kt">Ptr</span> <span class="kt">Window</span> <span class="o">-&gt;</span> <span class="kt">IO</span> <span class="nb">()</span>
<span class="n">foreign</span> <span class="kr">import</span> <span class="nn">ccall</span> <span class="s">"glfwPollEvents"</span> <span class="n">pollEvents</span> <span class="o">::</span> <span class="kt">IO</span> <span class="nb">()</span>

<span class="cd">-- | Context functions</span>
<span class="n">foreign</span> <span class="kr">import</span> <span class="nn">ccall</span> <span class="s">"glfwMakeContextCurrent"</span> <span class="n">makeContextCurrent</span> <span class="o">::</span> <span class="kt">Ptr</span> <span class="kt">Window</span> <span class="o">-&gt;</span> <span class="kt">IO</span> <span class="nb">()</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">GL.hs</code>:</p>

<div class="language-hs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{-# LANGUAGE CPP, ForeignFunctionInterface #-}</span>

<span class="kr">module</span> <span class="nn">GL</span> <span class="kr">where</span>

<span class="o">#</span><span class="n">include</span> <span class="o">&lt;</span><span class="kt">GL</span><span class="o">/</span><span class="n">gl</span><span class="o">.</span><span class="n">h</span><span class="o">&gt;</span>

<span class="kr">data</span> <span class="kt">ClearMask</span> <span class="o">=</span> <span class="kt">COLOR_BUFFER_BIT</span> <span class="o">|</span> <span class="kt">DEPTH_BUFFER_BIT</span> <span class="o">|</span> <span class="kt">STENCIL_BUFFER_BIT</span>
<span class="n">foreign</span> <span class="kr">import</span> <span class="nn">ccall</span> <span class="s">"glClear"</span> <span class="n">_clear</span> <span class="o">::</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">IO</span> <span class="nb">()</span>
<span class="n">clear</span> <span class="o">::</span> <span class="kt">ClearMask</span> <span class="o">-&gt;</span> <span class="kt">IO</span> <span class="nb">()</span>
<span class="n">clear</span> <span class="kt">COLOR_BUFFER_BIT</span> <span class="o">=</span> <span class="n">_clear</span> <span class="kt">GL_COLOR_BUFFER_BIT</span>
<span class="n">clear</span> <span class="kt">DEPTH_BUFFER_BIT</span> <span class="o">=</span> <span class="n">_clear</span> <span class="kt">GL_DEPTH_BUFFER_BIT</span>
<span class="n">clear</span> <span class="kt">STENCIL_BUFFER_BIT</span> <span class="o">=</span> <span class="n">_clear</span> <span class="kt">GL_STENCIL_BUFFER_BIT</span>
</code></pre></div></div>

<h2 id="108-am">1:08 AM</h2>

<p>Turns out including header files in Haskell isn’t as easy as using <code class="language-plaintext highlighter-rouge">#include &lt;GL/gl.h&gt;</code>.</p>

<p><img src="/assets/imgs/ride-along-game-dev/108.png" alt="C preprocessor error" /></p>

<h2 id="638-pm-day-3">6:38 PM, day 3</h2>

<p>After a day long break where I was busy with some freelance work, I came back to this project and finally made some progress! After fixing some linker errors a couple Haskell bugs…</p>

<p>We have a window!</p>

<p><img src="/assets/imgs/ride-along-game-dev/638.png" alt="Hello, window!" /></p>

<h3 id="interlude-why-haskell">Interlude: Why Haskell?</h3>

<blockquote>
  <p>I believe that the monadic approach to programming, in which actions are first class values, is itself interesting, beautiful, and modular. In short, Haskell is the world’s finest imperative programming language.</p>
</blockquote>

<p><a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/mark.pdf">from https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/mark.pdf</a>.</p>

<p>I didn’t want to do this in C because C is the language that can directly interface with GLFW and OpenGL. I didn’t want to be able to do this because I wanted a reason to sit and ponder each function before I use it. Having to write sensible bindings for every single graphics function that I use encouraged me to take this time.</p>

<p>So the question remained of what langauge I should decide to use. I could have went with a run-of-the-mill scripting language, but something about the elegant abstractions of Haskell drew me toward using it for this project.</p>

<p>For one, Haskell is my favorite language, so it’s naturally one of my top choices for anything that I do. But further than that, the biggest roadblock that I hit trying to learn OpenGL the first time a while back was the difficulty of composing abstractions on top of the admittedly obtuse graphics pipeline. Haskell is notorious for being able to abstract. So abstract I shall.</p>

<h2 id="1153-pm-day-3">11:53 PM, day 3</h2>

<p>Started reading through <a href="https://learnopengl.com/Getting-started/Hello-Triangle">https://learnopengl.com/Getting-started/Hello-Triangle</a>. Buffers make a lot more sense than I remember them making.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Hey all! I was going through my blog post backlog and found this draft from 2019-06-05. Thought I’d just throw it up on the blog: there’s some useful stuff about Haskell’s FFI here, and I also wax poetic about software development a little bit. This was written before the whole 100 blog posts thing so it doesn’t count.]]></summary></entry><entry><title type="html">launching blog v2</title><link href="https://datakinds.github.io//2024/07/27/launching-blog-v2" rel="alternate" type="text/html" title="launching blog v2" /><published>2024-07-27T05:37:00+00:00</published><updated>2024-07-27T05:37:00+00:00</updated><id>https://datakinds.github.io//2024/07/27/launching-blog-v2</id><content type="html" xml:base="https://datakinds.github.io//2024/07/27/launching-blog-v2"><![CDATA[<p>Hello all</p>

<p>as you can see, the blog looks different!</p>

<p>it used to look like this</p>

<p><img src="/assets/imgs/v2/image.png" alt="the old blog, stardrew valley themed" /></p>

<p>it was themed after stardew valley. it was cute and i liked it a lot. The reasons I decided to give it a visual overhaul are as follows:</p>
<ul>
  <li>I didn’t know where to put other pages without it looking bizarre,</li>
  <li>I’d like to write more long form content <em>about</em> video games and I felt like having my page themed after a single game is a lil biased, and</li>
  <li>I didn’t feel like touching up the background lol</li>
</ul>

<p>I had a few goals with this redesign</p>
<ul>
  <li>Keep it quirky</li>
  <li>Keep it readable for old posts (including adding some extra goodies like syntax highlighting)</li>
  <li>Giving myself space to add more pages and do further experimentation</li>
</ul>

<p>I suppose this also counts as part of my <a href="/2022/06/17/100-blog-posts">100 blog posts challenge</a>, but I’m no longer numbering the titles because that was annoying lol</p>

<p>so, with this redesign I’ve given myself a good foundation to keep hacking away on. hope you like it! new long form posts and possibly other goodies soon…</p>]]></content><author><name></name></author><category term="100-blog-posts" /><category term="v2-site" /><summary type="html"><![CDATA[Hello all]]></summary></entry><entry><title type="html">nasin nanpa sin tan nasin nanpa Loman</title><link href="https://datakinds.github.io//2022/11/08/nasin-nanpa-sin-tan-nasin-nanpa-loman" rel="alternate" type="text/html" title="nasin nanpa sin tan nasin nanpa Loman" /><published>2022-11-08T02:14:00+00:00</published><updated>2022-11-08T02:14:00+00:00</updated><id>https://datakinds.github.io//2022/11/08/nasin-nanpa-sin-tan-nasin-nanpa-loman</id><content type="html" xml:base="https://datakinds.github.io//2022/11/08/nasin-nanpa-sin-tan-nasin-nanpa-loman"><![CDATA[<p>toki! mi wile e nasin pona pi toki nanpa lon toki pona. mi kepeken nimi pu taso. ni la mi ken ala toki e nimi san (3), e nimi likujo (7), e ante. mi pilin pona tawa nanpa ni taso:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>* wan = 1
* tu = 2
* luka = 5
* mute = 20
* ale = 100
</code></pre></div></div>

<p>jan li toki e nimi “tu tu” la mi kute li sona e nanpa 4. jan li toki e nimi “tu wan” la mi sona e nanpa 3. jan pi mute suli a li sona sama. mi toki lon ilo Siko kepeken nasin ni la jan li sona e nanpa mi.</p>

<p>nasin ni li pona lukin. taso, o lukin tu. mi wile toki e nanpa 99. nasin ni la nanpa 99 li sama nimi “mute mute mute mute luka luka luka tu tu”. ni li suli ike a! mi wile ala toki e ni. mi toki e ni la jan li ken ala sona e nanpa 99. jan li kute e “… mute, mute, mute, …”. ni li pakala e lawa.</p>

<p>mi toki e nimi “luka wan” la jan li sona e nanpa 6. sama la jan Loman li sitelen e nimi “VI” la jan Loman ante li lukin li sona e nanpa 6. jan Loman li ken sitelen kin e nimi “IV”. jan ante li lukin e nimi “IV” la ona li sona e nanpa 4. taso… mi ken ala toki e nimi “wan luka”. mi tawa e nimi “luka” lon monsi pi nimi “wan” la jan li ken ala sona e nanpa 4. jan li sona e nanpa 6, anu, jan li sona e ijo “wan” pi mute 5. mi wile pana e sona pi nasin nanpa Loman ni la mi wile kepeken nasin ni a.</p>

<p>nasin nanpa Loman li wawa. mi wile toki e nanpa 99 la mi ken toki lili kepeken nasin ni. o lukin! nanpa 99 li sama nimi “wan ale” kepeken nasin ni. nimi “wan ale” li pakala ala li suli pona. kin la nanpa 4 li sama nimi “wan luka”.</p>

<p>lawa pi nasin nanpa Loman li pona (sama toki pona, tawa mi). ni la toki pona li wile e nasin nanpa la toki pona o kama jo e nasin ni. lawa pi nasin nanpa Loman li ni:</p>

<ol>
  <li>nanpa lili li lon monsi pi nanpa suli la o wan e ona. o lukin: nimi “luka (suli) wan (lili)” li sama nanpa 5 + 1 = 6.</li>
  <li>nanpa li lon monsi pi nanpa sama la o wan e ona. o lukin: nimi “luka luka (sama)” li sama nanpa 5 + 5 = 10.</li>
  <li>nanpa suli li lon monsi pi nanpa lili la o pakala e nanpa suli kepeken nanpa lili. o lukin: nimi “luka (lili) mute (suli)” li sama nanpa 20 - 5 = 15.</li>
</ol>

<p>lawa ni li lawa ale! mi toki e ni: nasin nanpa Loman li pona li wile lili e wawa sina. nasin ni li pona e nanpa. mi pilin e ni: nasin nanpa Loman li kute e nasin pi toki pona.</p>

<p>o tawa! o musi! o toki!</p>]]></content><author><name></name></author><category term="toki-pona" /><category term="100-blog-posts" /><summary type="html"><![CDATA[toki! mi wile e nasin pona pi toki nanpa lon toki pona. mi kepeken nimi pu taso. ni la mi ken ala toki e nimi san (3), e nimi likujo (7), e ante. mi pilin pona tawa nanpa ni taso:]]></summary></entry><entry><title type="html">[5/100] jan li pali e toki pona tan ni: toki pona li musi.</title><link href="https://datakinds.github.io//2022/08/31/jan-li-pali-e-toki-pona-tan-ni-toki-pona-li-musi" rel="alternate" type="text/html" title="[5/100] jan li pali e toki pona tan ni: toki pona li musi." /><published>2022-08-31T06:30:00+00:00</published><updated>2022-08-31T06:30:00+00:00</updated><id>https://datakinds.github.io//2022/08/31/jan-li-pali-e-toki-pona-tan-ni-toki-pona-li-musi</id><content type="html" xml:base="https://datakinds.github.io//2022/08/31/jan-li-pali-e-toki-pona-tan-ni-toki-pona-li-musi"><![CDATA[<h2 id="open-musi">open musi</h2>

<p>jan pi wile sona li toki tawa mi e ni: “sina toki kepeken toki pona tan seme? jan seme li toki sama?”.</p>

<p>mi toki e ni: “mi toki kepeken toki pona tan ni: ona li musi. kama pi sona toki li pona tawa mi.”</p>

<p>taso, jan pi wile sona li toki e ni: “sona pi toki pona li sona pi toki ala. sina o kama sona e toki <em>lon</em>.”</p>

<p>mi toki e ni: “toki pona li toki lon ala lon?”</p>

<p>jan pi wile sona li toki e ni: “toki pona li lon ala. sina o kama sona e toki Tosi e toki Sonko e toki Epanja. sina ken ala esun kepeken toki pona. “</p>

<p>mi toki e ni: “mi wile ala esun. ante la toki pona li <a href="https://www.semanticscholar.org/paper/How-learning-Toki-Pona-may-help-improving-in-a-or-Coluzzi/cdcd2e3c691092d9075a1e93122158cab22cfdea">ken pana e sona pi toki ante tawa sina</a>. taso, ni li pana e sona ala la ni li awen pona.”</p>

<hr />

<h2 id="ijo-suli">ijo suli</h2>

<p>ijo suli li ni: toki pona li musi. jan mute li toki e ni: “mi o kama sona e toki pona tan seme?” taso, toki pona li musi ala tawa sina la sina o kama ala sona e toki pona. tan ante li lon ala. musi li ale.</p>

<p>“musi li ale” li nasin wawa. jan mute li toki lawa e ni: “toki pona o wan e jan ale. toki pona o toki International Auxillary Language!” taso, ni li pakala e nasin wawa. toki IAL li musi ala! nasin pi wan e jan ale li musi ala! mi toki tu: toki pona li musi ala tawa jan la jan o kama ala sona e toki pona. taso, toki IAL li pona la toki IAL li wile e ni: jan ale li ken toki lon ona. ona li pona (jan ale li toki e ona) la jan mute li wile ala toki lon ona li musi ala toki. ni li ike suli. mi ale o kute e nasin wawa.</p>

<p>ante la kulupu pi toki pona li pana e pona mute tawa jan ale. jan suli li toki wawa e ni: “kulupu suli li ken ike”. ni li lon lili, taso, nasin wawa li ken awen e pona pi kulupu ni. kulupu li suli la toki pona li musi tawa jan ale kulupu la kulupu li awen pona. mi toki tu: musi li ale.</p>

<hr />

<h2 id="pini-musi">pini musi</h2>

<p>jan pi wile sona li toki e ni: “sina ken ala toki tawa jan lon linluwi ala.”</p>

<p>mi toki e ni: “sina ken ala toki tawa mama sina lon linluwi ala. mi en mama sina li toki lon tenpo pimeja ale.”</p>]]></content><author><name></name></author><category term="100-blog-posts" /><category term="toki-pona" /><summary type="html"><![CDATA[open musi]]></summary></entry><entry><title type="html">[4/100] nimi “pi” li sama ala nimi “of” tan seme? kin la toki sona ante.</title><link href="https://datakinds.github.io//2022/08/13/nimi-pi-li-sama-ala-pi-nimi-of-tan-seme" rel="alternate" type="text/html" title="[4/100] nimi “pi” li sama ala nimi “of” tan seme? kin la toki sona ante." /><published>2022-08-13T01:50:00+00:00</published><updated>2022-08-13T01:50:00+00:00</updated><id>https://datakinds.github.io//2022/08/13/nimi-pi-li-sama-ala-pi-nimi-of-tan-seme</id><content type="html" xml:base="https://datakinds.github.io//2022/08/13/nimi-pi-li-sama-ala-pi-nimi-of-tan-seme"><![CDATA[<p>toki. sina lukin e pakala toki mi la sina o toki tawa mi. mi o pona e lipu ni.</p>

<hr />

<p>jan sin li toki sona e ni: “nimi ‘pi’ li sama ala sama nimi ‘of’ lon toki Inli?”. jan sona li toki e ni: “ala”.</p>

<p>kin la jan sin li toki sona e ni: “mi ken ala ken ante pi toki Inli e nimi ‘toki’ tawa nimi ‘talk’ [anu nimi ante…]”. jan sona li toki e ni: “ala”.</p>

<p>ni li nasin pona. taso… ona li sama ala tan seme? sina ken ala ante tan seme? mi pana e sona ni lon lipu ni.</p>

<p>ijo wan li ken weka e len sona la ijo wan li ni:</p>

<p><strong>nimi ale li jo e poki kon.</strong></p>

<p>poki kon li seme? o lukin:</p>

<p>mi sitelen e nimi “tomo” lon poki kon ona:</p>

<p><img src="/assets/imgs/2022-08-12-19-31-20.png" alt="" /></p>

<p>lon la poki kon ona li jo e ijo mute. mi ken sitelen e ijo:</p>

<p><img src="/assets/imgs/2022-08-12-19-44-50.png" alt="" /></p>

<p>mi ken sitelen e nimi ante e poki kon ante:</p>

<p><img src="/assets/imgs/2022-08-12-20-01-38.png" alt="" /></p>

<p>o lukin! nimi “tomo” en nimi “building” li jo e sitelen sama. mi ken wan e ni tu:</p>

<p><img src="/assets/imgs/2022-08-12-20-24-43.png" alt="" /></p>

<p>taso, mi ken ala wan e sitelen ale pi nimi “tomo” e sitelen ale pi nimi “building”. nimi “building” taso li jo e sitelen pi jan pali. kin la nimi “tomo” taso li jo e sitelen pi tomo telo e sitelen pi tomo lape.</p>

<p>nimi “tomo” li sama ala nimi “building” tan sitelen ni. poki kon ni tu li jo e sitelen ante.</p>

<p>mi ken sitelen e poki kon mute ante. taso, poki kon ante li ken ala sama poki kon pi nimi “tomo”.</p>

<p><img src="/assets/imgs/2022-08-12-20-59-15.png" alt="" /></p>

<p>nimi “bedroom” li lon insa poki kon pi nimi “tomo”. ni li wawa tan ni: bedroom ale li tomo. (taso, tomo ale ala li bedroom).</p>

<p>ijo ale li toki e ni: nimi “tomo” li ken sama pi nimi mute. nimi mute ni li lon poka poki kon pi nimi “tomo”.</p>

<p>sina sitelen e poki kon ale la sina pali e jaki. nanpa sitelen li suli ike. nanpa pi poki kon li suli ike. nimi li wawa!</p>

<hr />

<p>mi wile e ni: sina pilin pona li pilin lawa wawa.</p>

<h1 id="o-pona-tawa">o pona tawa:</h1>

<ul>
  <li>sitelen tan linluwi <a href="https://www.flickr.com/photos/brent_nashville/4645745968">https://www.flickr.com/photos/brent_nashville/4645745968</a> CC BY-NC 2.0</li>
  <li>sitelen tan linluwi <a href="https://commons.wikimedia.org/wiki/File:Bed_Room.jpg">https://commons.wikimedia.org/wiki/File:Bed_Room.jpg</a> CC BY-SA 4.0</li>
  <li>sitelen tan linluwi <a href="https://commons.wikimedia.org/wiki/File:Construction_workers.JPG">https://commons.wikimedia.org/wiki/File:Construction_workers.JPG</a> CC BY-SA 3.0</li>
  <li>jan Ki lon ma pi kama sona. ona li pona e toki ni.</li>
</ul>]]></content><author><name></name></author><category term="toki-pona" /><category term="100-blog-posts" /><summary type="html"><![CDATA[toki. sina lukin e pakala toki mi la sina o toki tawa mi. mi o pona e lipu ni.]]></summary></entry></feed>