Three Dollar Quillhttps://mwchase.neocities.org/2024-03-19T04:00:00-04:00Weekly Roundup 2024-03-192024-03-19T04:00:00-04:002024-03-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-19:/weekly-roundup-2024-03-19<p class="first last">I mean, it's fine, I guess...</p>
<ul class="simple">
<li>Wednesday: I thought some about conlangs that have failed in their goals, or at least not succeeded persuasively.
I had some ideas about what "went wrong", but I'm not sure if those ideas are more "insight" or "assuming my experiences are universal".</li>
<li>Thursday: I thought my plan for Tsetatsatal would "get less away from me" than my previous attempts.
Ahahahahaha.</li>
<li>Friday: I made some progress on Tsetatsatal, and then fled the screens.</li>
<li>Saturday: I don't remember what I did.</li>
<li>Sunday: More progress on Tsetatsatal.</li>
<li>Monday: I tried to get some idea of what would work for IPA characters, and mostly got ideas of what wouldn't work.</li>
</ul>
<p>Next week, I'm going to try to put together basic stuff for the IPA, then helpers for phonetic charts, then get back to Tsetatsatal.</p>
Diary 2024-03-182024-03-18T04:00:00-04:002024-03-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-18:/diary-2024-03-18<p class="first last">A lot of research, no action yet.</p>
<p>Starting this post early because I had stuff that can go in it on my mind...</p>
<p>I had a look at just a few phonology sections on Wikipedia to refresh my memory, and from looking at them it looks clear to me that "just subset the IPA charts" is not going to work well.
My inclination is to say "people can come up with whatever rows and columns they like, although I'd like to provide some sensible defaults".
And "it should be possible to nest heading cells in verious ways, and I'm not confident right now that I can figure out the proper manifestation of the nesting automatically".
What goes in cells should be relatively freeform, but I'd like the ability to choose between "centered, left-justified, right-justified, some text left- and some text right- justified" on a per-cell basis.
As far as IPA symbols, that should be entirely freeform, but it would be good to have some helpers for stuff like aspiration and devoicing.</p>
<p>And those helpers look to be a minor nightmare to put together, because the IPA symbols have a lot of <em>stuff</em> going on, in terms of unicode representation.
And Wikipedia isn't helping, with the frankly bizarre styling it inflicted on the table I'd like to use, which seems to make it entirely unsuitable for printing.
(Also, there's <em>something</em> going on with the click consonants that doesn't look right.
I don't have plans for click consonants in Tsetatsatal, but it would offend my sensibilities if I ignored them or got them wrong.
That said, it looks like so much of the details of click phonemes is represented through diacritics, that it looks to me like the sensible course of action initially would be to have a separate helper just for getting the IPA character for the place of articulation, and punt on filling in the rest of the details for now.)</p>
<p>Those digressions aside, I think I have to acknowledge that, while it would be <em>cool</em> to build up some of the IPA consonant representations in a sort of refinement process, it makes much more sense to create a hardcoded lookup table.
Sadly, even this isn't totally straightforward, because there's a lot of <em>stuff</em> going on in the various IPA tables I'm looking at, and they also don't agree with each other in some significant ways.
Stuff like "do we call out dental plosives as distinct from alveolar plosives?" or "so what should the deal with sibilants be?" and especially "so what does it mean in these charts when the line between cells ends halfway between?"
At this stage, it seems like it would make more sense to simply embed the IPA chart in the supporting cells and be all "copy out the symbols that you want".</p>
<p>Plausible other things to work with would be stuff like "combining mark/spacer applier" or "superscript converter".</p>
<p>Looking at what I can find easily, there are a few issues, which I'll need to take some time to remedy.
I'll get to it in a few days, hopefully.
For now, I want to get off my computer.</p>
<p>Good night.</p>
Diary 2024-03-172024-03-17T04:00:00-04:002024-03-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-17:/diary-2024-03-17<p class="first last">More incremental progress.</p>
<p>Ugh, I was trying to fix some stuff I messed up on my Deck, and it turns out I was working with outdated directions, so that wasted a bunch of time.
I'll come back to it later, because I don't want to keep thinking about it right now.</p>
<p>I made some progress on the conlang stuff, but mostly on the code side.
I think I need to add a bunch of placeholder entries so I have some idea of the scope of what needs to get filled in.
I'll try that now.</p>
<p>...</p>
<p>Mm, that's a bunch of work to do later...</p>
<p>Thinking over how to move forward, I think I should be focusing on phoneme charts.
That'll help with the possibility of missing phonemes in words.</p>
<p>Anyway, I'll think about that (it's probably going to end up with functions to generate the HTML explicitly), but right now, I'm going to switch gears for a bit.
What I've got in mind is not too interesting to talk about; it's just something simple that I want done.</p>
<p>Good night.</p>
Diary 2024-03-162024-03-16T04:00:00-04:002024-03-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-16:/diary-2024-03-16<p class="first last">Okay to skip.</p>
<p>Okay, I didn't get much done today, so I don't really have anything to talk about.
I'll just try to get something interesting to talk about tomorrow.</p>
<p>Good night.</p>
Coding 2024-03-152024-03-15T04:00:00-04:002024-03-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-15:/coding-2024-03-15<p class="first last">It's called Tsetatsatal currently, and unfortunately that spelling is slightly non-indicative.</p>
<p>So, the good news is that I have put together some prototype code for dealing with conlang stuff in marimo (the stuff I'm doing works as a more general feature request, which I've filed and I intend to write up a recipe for replicating what I'm doing), and I've started adding lexicon entries.
It feels decent enough working with all of this, so that's all good.</p>
<p>The bad news is that my head has hurt all day, and I should get away from screens again.</p>
<p>Good night.</p>
Diary 2024-03-142024-03-14T04:00:00-04:002024-03-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-14:/diary-2024-03-14<p class="first last">The category is vibes, again.</p>
<p>Well, I didn't think any more about the stuff I was thinking about yesterday.
Instead, I decided to start writing stuff down about the language I currently have in mind.</p>
<p>The basic thing I'm trying to work out for myself is how far I can push the concept of stative verbs, in the direction I'm interested in.</p>
<p>I'm also looking into writing up a conlang grammar in marimo, on the supposition that maybe that will get less away from me than trying to write a grammar in Sphinx.
It might have gotten away from me <em>a little</em>, because I'm trying to work out how to handle stuff like phonetics charts and the lexicon.
Probably, I should just bite the bullet and do stuff by hand at first, then convert it all into stuff upstream.
But not right now, because I was messing around with other stuff earlier.
For now, I need to try again to rest.</p>
<p>Good night.</p>
Diary 2024-03-132024-03-13T04:00:00-04:002024-03-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-13:/diary-2024-03-13<p class="first last">Trying not to ruffle feathers, because I'm not sure which feathers to ruffle right now.</p>
<p>I'm feeling really tired right now, going to have to deal with that somehow.</p>
<p>I was thinking some today about the history of conlangs, and the way that the craft of conlanging has been entangled to varying degrees with utopian thinking.
I personally haven't had to deal with this any (except for from myself once like twenty years ago, when I was <em>sure</em> I'd cracked the code to representing and manipulating concepts in a consistent framework with a simple phonetic representation...), so I'm thinking about this in terms of its historical legacy.</p>
<p>I don't know if my thoughts are well-developed enough for me to go into much more detail without accidentally offending someone (I'd like it to be on purpose), but that is what I've been thinking about a lot.
And questions like...</p>
<ul class="simple">
<li>Wait, how are we defining success?</li>
<li>Will a new language meaningfully advance that goal?</li>
<li>How have we determined what is wrong?</li>
<li>How reliable are those methods of determination?</li>
</ul>
<p>Sadly, it turns out that linguistics ability is not a substitute for project management.
Lots of things aren't, like programming ability.</p>
<p>Ugh, I'd like to end this post on a more definite note, but I'm feeling incredibly tired.
Like, all I can say for how I feel right now is that it <em>is</em> possible to feel even more tired than this, which is not an impressive bar to clear.</p>
<p>Good night.</p>
Weekly Roundup 2024-03-122024-03-12T04:00:00-04:002024-03-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-12:/weekly-roundup-2024-03-12<p class="first last"><em>Definitely</em> not doing this again.</p>
<ul class="simple">
<li>Wednesday: I finished work on the conversion script, and rattled off a list of bugs I had to fix that probably made the script sound <em>extremely</em> fake.
Like, I had problems with a custom parser, xpath handling, <em>and</em> unpickling?
Ridiculous.</li>
<li>Thursday: I had a rough day.</li>
<li>Friday: I had another rough day.</li>
<li>Saturday: I had a less rough day.</li>
<li>Sunday: I tried to get back into writing, and didn't get too far.</li>
<li>Monday: I was very sore, and not sure what I felt like doing.</li>
</ul>
<p>Next week, maybe I'll get back to writing, maybe I'll mess around with other stuff.
We'll see.</p>
Diary 2024-03-112024-03-11T04:00:00-04:002024-03-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-11:/diary-2024-03-11<p class="first last">My poor muscles... I didn't even <em>do anything</em> that would make this somehow "worth it".</p>
<p>Uugh.
I have been sore all day.</p>
<p>As a result, I didn't really focus on much.
While I've been trying to get back to the writing I was doing before, I feel like I'm kind of at the mercy of my whims, and my whims are inclined towards conlang stuff right now.
I've got some ideas I'm messing with, but nailing stuff down there is, um, more writing, so I figured the sensible thing to look into would be reading about other conlangs that strike my interest.</p>
<p>Rather than drag out this entry any longer, I'm going to get off the laptop and try getting back to that.</p>
<p>Good night.</p>
Diary 2024-03-102024-03-10T05:00:00-04:002024-03-10T05:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-10:/diary-2024-03-10<p class="first last">Don't go too quickly...</p>
<p>Oh hey, it's the yearly "when is the right day to adjust the timestamps" moment.
I <em>think</em> I switch them tomorrow.</p>
<p>Anyway, I'm trying to ramp things up at a reasonable pace for now.
For writing, I've got "update the build pipeline" and "copy everything into the outline" as blocking things.
I tried to get stuff into the outline, and I had trouble with how un-fleshed-out the beginning is; I'll take another stab at it later, but for now I'm working on transferring setting notes.</p>
<p>Right now, I want to get to sleep and deal with the time change.</p>
<p>Good night.</p>
Diary 2024-03-092024-03-09T05:00:00-05:002024-03-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-09:/diary-2024-03-09<p class="first last">Not sure when I'll be "done" with this, but I'm going to work not to repeat the experience.</p>
<p>Wow, I feel not-great at the moment.
At least I don't have a headache.</p>
<p>My current hope is that this clears up by morning, and I can focus on destressing.</p>
<p>But right now, bed sounds good.</p>
<p>Good night.</p>
Diary 2024-03-082024-03-08T05:00:00-05:002024-03-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-08:/diary-2024-03-08<p class="first last">Let's see how things go tomorrow. Nothing here today, though.</p>
<p>I'm currently hoping that tomorrow, I'll be able to take care of the stuff I've been over-focusing on this last week.
Then coast through the weekend.</p>
<p>I don't have anything else I want to talk about right now.</p>
<p>Good night.</p>
Diary 2024-03-072024-03-07T05:00:00-05:002024-03-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-07:/diary-2024-03-07<p class="first last">Uuugh... boring...</p>
<p>Well.
I currently lack the focus to do much, so I'm just going to publish this and get off my laptop to try and let my eyes recover.</p>
<p>Got to stop staring at this like I might think of something else to add.</p>
<p>Good night.</p>
Coding 2024-03-062024-03-06T05:00:00-05:002024-03-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-06:/coding-2024-03-06<p class="first last">Reaping, sowing, etc. Point is, my eyes hurt, and everyone could have anticipated this except for me, a week ago.</p>
<p>To all indications, the conversion script works now.
Tally of bugs:</p>
<ul class="simple">
<li>I needed to rework the code to extract node metadata, because the rinky-dink parser was failing to empty the stack, which prevented some metadata from being recorded.
(There may be Bonus Bugs hiding in here, because the parser is meant to handle input that I have no intention to produce, because I failed to rein in scope creep.)</li>
<li>I copied code from another project to find elements using xpaths.
That code turned out to have never run, and it was slightly broken.</li>
<li>I failed to anticipate the sheer number of ways that Python will pickle "a set full of strings", and had to allow-list a bunch more opcodes.</li>
<li>I realized that I'd allow-listed so many opcodes that I should also look into writing a custom unpickler that only loads trusted globals.
The first time, I forgot which global I actually needed to trust.</li>
</ul>
<p>All of this was ultimately not too bad.</p>
<p>With all of that taken care of, I'm all set to start migrating text into the outline...
Except that my eyes hurt and I just really want to lie down and doodle.
So I'm going to go do that.</p>
<p>Good night.</p>
Weekly Roundup 2024-03-052024-03-05T05:00:00-05:002024-03-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-05:/weekly-roundup-2024-03-05<p class="first last">Good progress for how I was doing, but I should probably, like, sleep.</p>
<ul class="simple">
<li>Wednesday: I pushed the conversion script in a somewhat more quick-and-dirty direction.</li>
<li>Thursday: I got some stuff done to avoid worrying about recomputations in the conversion script, which is helpful for consolidating logic into one place.</li>
<li>Friday: I made some more progress on the script, and started pondering some of the weird behaviors I've set myself up to think about.</li>
<li>Saturday: I realized that I was approaching said weird behaviors in the wrong way, and found the right way (according to me).</li>
<li>Sunday: I had still more weird design issues to work through, so I did.</li>
<li>Monday: I got <em>probably</em> the last of the big issues with the script, leaving just the little ones.</li>
</ul>
<p>Next week, I'm going to try and get the script and build process to the point where I'm comfortable migrating content from the flat file into the outline.</p>
Coding 2024-03-042024-03-04T05:00:00-05:002024-03-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-04:/coding-2024-03-04<p class="first last">Bad habits for writing. I need to change them somehow.</p>
<p>Okay.
I was doing other stuff all day, and then in the last hour or so I rushed through implementing most of the stuff I think I need for the conversion script.
At this point, I just need to slap a click wrapper on top of all of this, and make sure I wire everything together properly inside.</p>
<p>That shouldn't be too hard, but I want to get some sleep before trying.</p>
<p>Also, this file is a complete mess by now.
If I don't give it some editing passes, it'll bother me how messed up it is.</p>
<p>Anyway, I'm going to try and relax and sleep now.</p>
<p>Good night.</p>
Coding 2024-03-032024-03-03T05:00:00-05:002024-03-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-03:/coding-2024-03-03<p class="first last">Thinking things through "out loud" to make progress.</p>
<p>Hm.
I mostly messed around today, but I did get some more work done on the conversion script just now.
I've got <em>hopefully</em> the right behavior for the title marker at each level of the tree.
I've got a bit of work to do in terms of figuring out the runtime checks that I want to try to ensure stylistic consistency.
But the big thing I need to work through is how to assemble the text of the different nodes together.
Things I think I need:</p>
<ul class="simple">
<li>Some kind of matching argument at the top level</li>
<li>A header helper that does things like temporarily increase the header level</li>
<li>Probably this should all be generators or something?</li>
<li>Chapters and books need to know their own number</li>
<li>I need to figure out where I want end-of-node line breaks to be in all of this. Inserted programmatically, already in the outline, something else?</li>
</ul>
<p>Thinking about the line breaks...
There should be 2+ breaks between everything I think, because I'm not going to want to have multiple scenes in a paragraph, probably.
So, I can either emit those as I go, or say "okay, join on double newlines".
Stuff to consider for later.</p>
<p>Well, I can figure the rest out later, it's nothing I haven't done before.
For now, sleep.</p>
<p>Good night.</p>
Coding 2024-03-022024-03-02T05:00:00-05:002024-03-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-02:/coding-2024-03-02<p class="first last">Sometimes, I'm not sure how to do something, and the correct answer turns out to be "don't".</p>
<p>Okay, let's see where I am now.</p>
<p>At the level I'm currently considering, the most complicated logic is "there's an optional <tt class="docutils literal">subtitle</tt> node, and I want to properly handle all of the nodes that <em>are not</em> <tt class="docutils literal">subtitle</tt>."
I've got the vague sense that I'm doing something wrong with my design, which is pretty much just in my head right now.
Like, I'm currently leaning towards, there's some kind of dependence between the <tt class="docutils literal">subtitle</tt> property and the other attribute.
It feels to me like the current draft is wrong, because it's a relatively monolithic setup, and adapting it to the more complicated requirements means I need to duplicate and rework a lot of it.</p>
<p>Let's see if I can divide this up a little...</p>
<p>Hm.
I can certainly pull apart different ideas and make the individual units of code smaller, but it's not yet clear if I have the pieces I need to build back up what I want.
Thinking about it, the problem I was having before was kind of that I had <em>two</em> monoliths...</p>
<p>Okay, I consolidated a bunch of logic into a compound cached property, and then wrote additional properties to pull out distinct parts of it.
This seems like a useful thing to do in this code, for whatever reason; I have some of this in the general <tt class="docutils literal">Node</tt> code as well.</p>
<p>Anyway, with that, plus just knocking out all of the simpler child relationships quickly, I have the tree structure just about handled.
Next, I need to get the rest of the data for each node, and then I can work on presentation logic.
At that point, it should be ready to move into proper testing.</p>
<p>But for now, I need to sleep.</p>
<p>Good night.</p>
Coding 2024-03-012024-03-01T05:00:00-05:002024-03-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-03-01:/coding-2024-03-01<p class="first last">Just changing things until this all seems to make sense. Not there yet.</p>
<p>Okay, I'm in a little better shape compared to yesterday, but I do need to hurry here.</p>
<p>I've improved the basic wrapper class, and I think it's about ready.
I've written a mixin class for wrappers around that, which layer semantics around the the helper methods from the basic wrapper.
None of those semantics are written yet.
I'm aware that some of them are going to need some further tweaks; I haven't really thought about headings yet.
Most things are ready to be filled in, but there is one wrinkle I'm trying to figure out how I want to handle:</p>
<p>Chapters can have several different types of children; their first child could be a subtitle, and their children (including the first) can be scenes or summaries.
I have an attempt at a helper for handling these constraints, but I don't know that I've hit the right design yet.
I'll think about that more later, because right now it's late.</p>
<p>One last thing; here is what I think I need to get done:</p>
<ul class="simple">
<li>Figure out how to handle headings</li>
<li>Figure out the right way to handle children of chapters</li>
<li>Actually write the code to process this stuff out</li>
<li>Migrate draft from the text file to the outline</li>
<li>Update build process</li>
</ul>
<p>That'll all take some time, and the right thing for me to do right now is sleep.</p>
<p>Good night.</p>
Coding 2024-02-292024-02-29T05:00:00-05:002024-02-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-29:/coding-2024-02-29<p class="first last">Progress, and no time to explain it.</p>
<p>I was kind of out of it today, but I did make some quick improvements to the conversion script, just about getting <tt class="docutils literal">cached_property</tt> stuff set up so I can feel better about calling some of this code.</p>
<p>Anyway, it's too late and I need to wrap up several minutes ago.</p>
<p>Good night.</p>
Coding 2024-02-282024-02-28T05:00:00-05:002024-02-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-28:/coding-2024-02-28<p class="first last">Getting closer to having the script be usable.</p>
<p>All right.
I wasn't focused much on coding today, but I did put together a few things for the conversion script.
Basically, I realized, hey, this conversion script is super bespoke and not meant to be reused, so I don't need to take my usual stances against inheritance, so I made a base class for all of my node wrapper stuff, and once I've got that class in a nice place, I can subclass it into all of the wrappers and then focus on pulling out the relevant information.</p>
<p>For now, though, I want to get to bed.</p>
<p>Good night.</p>
Weekly Roundup 2024-02-272024-02-27T05:00:00-05:002024-02-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-27:/weekly-roundup-2024-02-27<p class="first last">Just did what I felt like, vibed.</p>
<ul class="simple">
<li>Wednesday: I threw together some pretty rough validation code to stop the conversion script from getting pwned by malicious input that there is no obvious way for it to end up on my computer, then started thinking about the actual business logic.</li>
<li>Thursday: I was so gobsmacked by what looks like the way I'm "supposed to" handle one of the requirements I set myself, that I put together a quick hack to see how I get struck down for my hubris.</li>
<li>Friday: I did a little more work with that, and then got distracted by something else I could code up.</li>
<li>Saturday: I prototyped something roughly analagous to μKanren, for... some reason.</li>
<li>Sunday: Traveled out.</li>
<li>Monday: Traveled back.</li>
</ul>
<p>Next week, I don't know yet what I'll feel like working on; I'll just try to take things as I go.</p>
Diary 2024-02-262024-02-26T05:00:00-05:002024-02-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-26:/diary-2024-02-26<p class="first last">Extremely safe to skip.</p>
<p>Travel back.</p>
<p>Video games.</p>
<p>Nothing to write about.</p>
<p>Oh well.</p>
<p>Good night.</p>
Diary 2024-02-252024-02-25T05:00:00-05:002024-02-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-25:/diary-2024-02-25<p class="first last">Maybe this counts as recharging?</p>
<p>Traveled today, and then got way into video games.
I did do some shell programming this morning, but it's not worth talking about.</p>
<p>It's late and I need to lie down now.</p>
<p>Good night.</p>
Coding 2024-02-242024-02-24T05:00:00-05:002024-02-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-24:/coding-2024-02-24<p class="first last">Awkward position where it's <em>based</em> on Micro, but the code size is probably closer to Mini. Something something, stuff getting longer when you translate it.</p>
<p>Well, I didn't get anything done on the stuff I was working on just two days ago, so here's what happened instead:</p>
<p>Every once in a while, I read about a programming concept, and just go through implementing it without any clear idea of what I'm going to do with it.
This time, it was getting reminded of the existence of <a class="reference external" href="https://github.com/VPetukhov/miniKanren/blob/master/HemannMuKanren2013.pdf">μKanren</a>, and trying to put together some Python implementations.</p>
<p>The one that <em>probably</em> works, (though I haven't actually tested all of the primitives, so there could be some really nasty surprises in there) is based around using <a class="reference external" href="https://pyrsistent.readthedocs.io/en/latest/api.html">pyrsistent</a> maps for states, an <a class="reference external" href="https://www.attrs.org/en/stable/">attrs</a> class that compares by identity for variables, and using iterators for streams.
That description basically locks down most of the implementation; I'll also note that I favored callable classes over closures.
What remains is the definition of unification, which, well...</p>
<blockquote>
The definition of <tt class="docutils literal">unify</tt> and the terms of the language are orthogonal to the presentation of μKanren: both could be changed with limited consequence for the rest of the system.</blockquote>
<p>So, naturally, I figured out how to make that all <em>extremely configurable</em>.
Basically, there are some new operators, which register new implementations of unification for the purposes of the goal that they wrap.</p>
<p>I am still not sure what to do with this, if anything, so I'm going to try to switch gears soon.
Anyway, I'm starting to feel a little stiff, so I'm going to wrap up now.</p>
<p>Good night.</p>
Coding 2024-02-232024-02-23T05:00:00-05:002024-02-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-23:/coding-2024-02-23<p class="first last">Got a bunch of work still ahead of me, so naturally I started another project.</p>
<p>Okay, well.
I got distracted by something else that I don't feel like discussing right now, but I did make a little progress on the outline-to-draft converter.
Specifically:</p>
<ul class="simple">
<li>"Hm, chapter subtitles should probably be a distinct node at the beginning."</li>
<li>And I tested out my weird janky parser. I am aware that it has shortcomings, but I have chosen to only care about them in the event that they become relevant.</li>
</ul>
<p>Maybe later, I can describe what got me all distracted.
But right now, I'm having a bit more trouble than usual typing, so it's time to get to bed.</p>
<p>Good night.</p>
Coding 2024-02-222024-02-22T05:00:00-05:002024-02-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-22:/coding-2024-02-22<p class="first last">Disbelief-driven programming</p>
<p>After yesterday's entry, I remembered that I want to handle Leo directives (by ignoring them) and reStructuredText bibliographic fields (which I'm not <em>overly</em> concerned about getting right, by my standards, but I still need to do <em>stuff</em>).
I'm right now trying to figure out the right way to handle bibliographic fields.
I could try to hack together a small portion of a reStructuredText parser to winnow them out, or I could attempt to use docutils to just get it parsed out for free.
I'm currently not sure which option would be more of a pain, and whether there's some better way.</p>
<p>Let's take a look at the latter option, since it's easier to tell what that entails.</p>
<ul class="simple">
<li><tt class="docutils literal">parser = docutils.parsers.rst.Parser()</tt></li>
<li>Store the input in a variable.</li>
<li><tt class="docutils literal">document = <span class="pre">docutils.utils.new_document("programmatic")</span></tt> (not exactly right, but let's see how this trips me up first)</li>
<li><tt class="docutils literal">parser.parse(input, document)</tt></li>
</ul>
<p>Where the input looks something like</p>
<div class="highlight"><pre><span></span><span class="nc">:key:</span> value
Hold on, does something <span class="ge">*weird*</span> happen if I have an indented field list inside a code block?
</pre></div>
<p>And my hope is that I can extract a mapping of bibliographic fields, and get back the literal text of the rest of it.
I do not know if that's a supported usage, so this might be a non-starter.
(If it's not, do I have to roundtrip it through <tt class="docutils literal">xml2rst</tt> or something?)</p>
<p>...</p>
<p><tt class="docutils literal">AttributeError: 'Values' object has no attribute 'pep_references'</tt></p>
<p>Clearly, I was a fool to trust the builtin documentation.</p>
<p>Okay, maybe the mistake was specifically trusting the default behavior of the <tt class="docutils literal">settings</tt> argument.
Okay, that was it, had to get the proper default parser from the <tt class="docutils literal">frontend</tt> module.
Now, I have more information than I know what to do with.</p>
<p>After playing around a bit, I see that there are <tt class="docutils literal">field_list</tt> objects, which contain the desired mapping information, several nodes deep.
It is <em>possible</em>, then, to pull out those nodes and get the mapping, and <em>somehow</em> convert what remains back to reStructuredText, but...</p>
<p>It's truly impressive to me how this part of the Python ecosystem has managed to convince me that slopping together a rinky-dink little parser would be less trouble than wiring together existing libraries.</p>
<p>...</p>
<p>It is now rather later than I would like, but I have tossed something together that looks plausible.
I'll have to try it out later, but it should be at least close.
And now, I rest.</p>
<p>Good night.</p>
Coding 2024-02-212024-02-21T05:00:00-05:002024-02-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-21:/coding-2024-02-21<p class="first last">Decisive action, deferred.</p>
<p>Okay, here we are, still dealing with whatever is going on in my head, sinuses, and wherever else.
I just threw together some validation code that should prevent my generator script from doing something weird in the face of a malicious pickle.
This is, I think, somewhere between hard and impossible to handle in the general case, but in this case, I'm specifically looking for a set of strings, so, like, I think there's less than a dozen opcodes that are valid for that purpose.</p>
<p>The next thing I want to consider is how to handle all of the wrapper-type classes I wrote.
Currently, they have attributes that refer to the "child" classes, and keeping that would mean that the nodes would have to be converted eagerly.
This seems a little unreasonable when it comes to the case of "convert just part of the tree for spellcheck purposes".
In that context, it's sort of justifiable to make the top level lazy, but I don't know which rationale wins at the lower levels:</p>
<ul class="simple">
<li>All use cases will require the whole thing eventually</li>
<li>Doing it all lazily is more consistent</li>
<li>Something about performance characteristics from allocating a bunch of memory up front versus interleaving more kinds of operations later</li>
</ul>
<p>I'm going to figure "calculating things on the fly means I can add new attributes as properties, instead of as more code in a constructor function".
So, on the one hand, I know which way I want to go forward.
On the other hand, I've been thinking about this long enough that now it's late and I <em>really</em> want to get to bed.</p>
<p>Good night.</p>
Weekly Roundup 2024-02-202024-02-20T05:00:00-05:002024-02-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-20:/weekly-roundup-2024-02-20<p class="first last">I sort of forgot how long this was lasting...</p>
<ul class="simple">
<li>Wednesday: I worked out why and how to generate ninja files. And got a headache.</li>
<li>Thursday: I wrote some helper code for generating ninja files, which is unlikely to help anyone but me. And had a headache.</li>
<li>Friday: I took that helper code and turned used it to write a Python script that generates the currently-used ninja file for my writing project. While I had a headache.</li>
<li>Saturday: I switched gears to remembering how to traverse Leo files. And still had a headache.</li>
<li>Sunday: I figured out how to extract relevant information from the elements in a Leo file. While having a headache.</li>
<li>Monday: I wrote a Node class capable of traversing down, but not up, a Leo file, which <em>should</em> be all I need. Still had the headache.</li>
</ul>
<p>Next week, I'm going to look into building instances of the higher-level helper classes I wrote before, and into fleshing out their behavior so I can actually be useful.
And dabble with a few other projects.
And take some NSAIDs, sheesh.</p>
Coding 2024-02-192024-02-19T05:00:00-05:002024-02-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-19:/coding-2024-02-19<p class="first last">Figuring out the way I want to handle XML in generating the outlines.</p>
<p>All right.
I think I've covered the adaptation layer over lxml and Leo, so now what's left is taking my draft of the higher-level concepts, and fix them up so they work with the wrapper code I wrote.</p>
<p>I figure I'll describe what I wrote today in a bit more detail:</p>
<ul class="simple">
<li>The <tt class="docutils literal">Node</tt> class now just has an attribute I called <tt class="docutils literal">t_ref</tt>, which corresponds to the <tt class="docutils literal">t</tt> and <tt class="docutils literal">tx</tt> attributes.</li>
<li>Now there are a bunch of properties, which do things like:</li>
<li>Get the xml element of type <tt class="docutils literal">v</tt> or <tt class="docutils literal">t</tt>, depending on what's needed;</li>
<li>Get the title</li>
<li>Get the text</li>
<li>Get the tags</li>
<li>Get the children</li>
</ul>
<p>I've got nothing else I want to think about on this right now, so I'm going to wrap up this and work on other things for a bit.</p>
<p>Good night.</p>
Coding 2024-02-182024-02-18T05:00:00-05:002024-02-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-18:/coding-2024-02-18<p class="first last">Doing what I can while I deal with this headache or whatever.</p>
<p>Okay, I got inspired to look more into generating stuff from Leo files.
I think I mentioned I wanted to key some behavior off of tags, so here's what I found looking at the file.</p>
<p>Node tags are stored in <tt class="docutils literal">t</tt> elements, in an attribute called <tt class="docutils literal">__node_tags</tt>.
This attribute contains a hex-encoded string; when decoded to bytes and unpickled, the result is a set containing the tags as strings.</p>
<p>So, assuming I remember the relationship between <tt class="docutils literal">v</tt> and <tt class="docutils literal">t</tt> elements correctly, <tt class="docutils literal">v</tt> tags lay out the tree structure, and point to <tt class="docutils literal">t</tt> elements, which contain the node text and other metadata.
Of the <tt class="docutils literal">v</tt> tags that point to a given <tt class="docutils literal">t</tt> element, just one contains the <tt class="docutils literal">vh</tt> element that gives the node title.
I could be wrong about this in hopefully subtle ways.</p>
<p>However, for the purposes of this script, I'm going to generally <em>ignore</em> the node titles, except to find the root of the outline.
So, I want to say "for each <tt class="docutils literal">v</tt> that is a <em>direct</em> child of <tt class="docutils literal">vnodes</tt>, find all <tt class="docutils literal">v</tt> that are <em>descendants</em> of <tt class="docutils literal">vnodes</tt>, such that their <tt class="docutils literal">t</tt> attributes match, and they contain a <tt class="docutils literal">vh</tt> element that contains the string <tt class="docutils literal">"Draft"</tt>".
Looks like the child information follows the <tt class="docutils literal">vh</tt> element, so I <em>will</em> need to perform that search in all cases, in case of something non-standard going on with the tree/graph layout.</p>
<p>In terms of actually printing this stuff out, I should avoid loops, which my whole "tag what kind of node it is" idea should get me for free.</p>
<p>Anyway, I've just about run out of juice for today, so I'm going to wrap up.</p>
<p>Good night.</p>
Coding 2024-02-172024-02-17T05:00:00-05:002024-02-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-17:/coding-2024-02-17<p class="first last">Quick refresher...</p>
<p>Still dealing with stuff today.
I'd like to work on the conversion code, and one part of that is reminding myself how I wrote some similar code.
Let's see what we've got here...</p>
<ul class="simple">
<li>Parse the file</li>
<li>Find "vnodes" and "tnodes"</li>
<li>For all "v" in "vnodes", I may need to use a helper function to get "the" copy of a "v", the one with the "vh"</li>
<li>The structure I'm going with wants the top-level "v" with "vh.text" of "Draft".</li>
</ul>
<p>To get much further than this, I'm going to need to put together pseudocode for how this should all fit together, fill in the outline enough to be able to execute it, and work through it all manually-ish.</p>
<p>I'll try to get on that tomorrow; I'm once again really sleepy.
I'm not totally sure I <em>stopped</em> being sleepy today.
Therefore...</p>
<p>Good night.</p>
Coding 2024-02-162024-02-16T05:00:00-05:002024-02-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-16:/coding-2024-02-16<p class="first last">Hooray, I can now apply The Wonders Of Metaprogramming to my build process if I feel like it.</p>
<p>Hooray, I took the weird code I wrote yesterday, and created a version that will regenerate itself if I edit the Python script I wrote.</p>
<p>At this point, there are a few directions I can take this.
If I can make a better "python" rule, then I can split up the script into smaller files and have them all properly tracked.
That seems pretty straightforward to specify and put together.
(Although if I push it too far, then it kind of makes a case to try switching to tup...)</p>
<p>The bigger thing to look into is figuring out how I want the generation scripts for the actual artifacts to work.
I don't have the focus to think about that right now, so I should get ready for bed instead.</p>
<p>Good night.</p>
Coding 2024-02-152024-02-15T05:00:00-05:002024-02-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-15:/coding-2024-02-15<p class="first last">Was there really a point to this? No. Is it likely to make sense to anyone else? Also no. But I did it, and I feel like that counts for something.</p>
<p>Okay, I can't <em>really</em> do too much today, but let's see what I can work out for later.</p>
<p>I want to write a Python script to generate my <tt class="docutils literal">build.ninja</tt> file.
In service of this, I have installed the "ninja_syntax" package.
The key thing for me to use from that package is the <tt class="docutils literal">Writer</tt> class, which requires an object with a <tt class="docutils literal">write(str)</tt> method, and a <tt class="docutils literal">close()</tt> method.
A text file, basically.
I have a set of rules and build statements to generate.
My initial thought is that I should have some kind of helper method for the build statements, so I can just call <tt class="docutils literal"><span class="pre">some_object.pandoc("story.rst",</span> <span class="pre">output="build/story.html")</span></tt>.</p>
<p>The idea of wrapping these disparate objects around each other like a matryoshka doll is making my teeth itch a little.
Kind of makes me want to replicate the <tt class="docutils literal">Compendium</tt> creation code from MOTR, but that's probably extreme overkill, and yet...</p>
<p>...
I have just discovered that the interface to ninja_syntax has changed somewhat over the versions, and I assume I should probably just vendor a version that matches my installed version of Ninja.</p>
<p>...</p>
<p>Okay, after vendoring the file and doing the thing, I should be all set to start writing code to generate a <tt class="docutils literal">build.ninja</tt> file.
Sadly, it is late and I am feeling bad <em>in addition to</em> feeling tired, so I'm going to go lie down.</p>
<p>Good night.</p>
Coding 2024-02-142024-02-14T05:00:00-05:002024-02-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-14:/coding-2024-02-14<p class="first last">The screens have much information about how to build software artifacts, but also, they have the terrible terrible light.</p>
<p>Me several months ago: "Why does the Ninja documentation warn you against hand-writing the files? This is really easy and pleasant."</p>
<p>Me now: "The prospect of writing rules for anything remotely tricky makes my skin crawl. ... <em>Oooh...</em>"</p>
<p>So, yeah, I'm at a bit of a juncture here.
Either I can write code to generate some gnarly nonsense for Ninja to work with, or I can try out something else, like, see if <a class="reference external" href="https://gittup.org/tup/index.html">tup</a> acts any nicer when I have ideas like "well, I might want to change the code to translate the draft between different formats, and that should force the build to redo, so I guess I've got to write files like—"</p>
<div class="highlight"><pre><span></span>rule python
command = python $args > $out
build build/preface.rst: python build.py draft.leo
args = build.py --section preface draft.leo
</pre></div>
<p>Or however Ninja works, I didn't actually try that out, in part because <tt class="docutils literal">build.py</tt> isn't fleshed out enough to do that yet.</p>
<p>In any case, I think I basically understand how to try and put stuff together for generating Ninja code, which makes it somewhat unfortunate that I feel kind of bad right now actually, and just want to go lie down.</p>
<p>Good night.</p>
Weekly Roundup 2024-02-132024-02-13T05:00:00-05:002024-02-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-13:/weekly-roundup-2024-02-13<p class="first last">Train of thought jumped the tracks and landed on another set of tracks.</p>
<ul class="simple">
<li>Wednesday: I tried to get the logic right for handling "absolute convergence requires that only countably many values are non-zero".</li>
<li>Thursday: I wrote really weird code.</li>
<li>Friday: I explained why I wrote the really weird code, and what I think makes it weird.</li>
<li>Saturday: I got sidetracked away from Dafny to work on build pipelines for a novel draft.</li>
<li>Sunday: I tried to figure out the minimum I need from these pipelines, so I can get back to writing.</li>
<li>Monday: I went over what I'm trying to do there again, and put together the beginnings of a basic idea of how this all should work.</li>
</ul>
<p>Next week, I'll keep working on <em>something</em>, that's for sure.</p>
Coding 2024-02-122024-02-12T05:00:00-05:002024-02-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-12:/coding-2024-02-12<p class="first last">Closing in on a design with a speed normally reserved for something that could get spooked.</p>
<p>First pass at how to represent all of this:</p>
<ul class="simple">
<li>There is a <strong>draft</strong>, made up of multiple <strong>documents</strong>.</li>
<li>The document type can be a union if need be, but I'd like to try to come up with a protocol.</li>
<li>Specific types are... let's say <tt class="docutils literal">FictionOutline</tt> and <tt class="docutils literal">ReferenceWork</tt>.
(The latter is needed for a factual description of the neopronoun usage. That... shouldn't have character arcs.)</li>
<li>For now, I want to structure the <tt class="docutils literal">ReferenceWork</tt> pretty loosely; the current draft just has thirty-something lines of text that should appear in the preface, so I'd like to be able to just slap those into a node and call it done.
Hm.
Not sure how I want to set up the titles...
This all seemed obvious in my head, but somehow I ended up tying my mental model into knots.</li>
</ul>
<p>Like, if I say "the pre-processing should strip out Leo's <tt class="docutils literal">@</tt> directives", then I can include metadata at the topmost level and title it like that.</p>
<p>All right, thinking about this more...
It might make sense to just work with undifferentiated node types to start with, and then work on narrowing things down as I find unique behavior/validation logic.
Although I can kind of anticipate some things.
Like "I want to define a bunch of metadata for each chapter, such that there is a set of key names for which any given key is either given a value by every chapter or none of them".</p>
<p>So, I can try working with:</p>
<ul class="simple">
<li><tt class="docutils literal">Draft</tt></li>
<li><tt class="docutils literal">ReferenceWork</tt></li>
<li><tt class="docutils literal">FictionOutline</tt></li>
<li><tt class="docutils literal">FictionBook</tt></li>
<li><tt class="docutils literal">FictionChapter</tt></li>
<li><tt class="docutils literal">Scene</tt></li>
<li><tt class="docutils literal">Summary</tt></li>
</ul>
<p>The next thing to figure out is where I put all of this stuff.
On reflection, it probably shouldn't be in the tasks file, since I'm going to want to call it from the ninja build, so I guess I need to set up a virtual environment and requirements file for this stuff.
I'll get on most of that later.
Right now, I once again need to get to bed.</p>
<p>Good night.</p>
Coding 2024-02-112024-02-11T05:00:00-05:002024-02-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-11:/coding-2024-02-11<p class="first last">Gathering requirements</p>
<p>Okay, writing this early in case my laptop has another little <em>accident</em> like it did about half an hour ago.
I've currently shifted gears to considering how I might convert my disorganized draft file into a more comprehensible outline file.</p>
<p>Here is the hierarchy as I see it at a glance:</p>
<ul class="simple">
<li>Top-level: title</li>
<li>Second-level: preface;
the preface contains explanatory notes about the word choices in the book(s);
it therefore is needed to understand/contextualize the story proper, but it does not fit into the structure of the rest of the outline;
spell-checking it will require a different dictionary from the rest of the book;
there are some parts of the "preface" that are more properly "notes", and should be transcribed into a separate branch of the .leo file's tree structure.</li>
<li>Second-level: main story;
the actual contents here are a muddle of notes-to-self, outline fragments, actual text meant to show up in the draft, and who knows what else;
of interest from the notes is that I call out how a specific event should be followed by a chapter break.</li>
<li>Lower-level: chapters;
not currently planned out except in the broadest contours;
I'm aware that whether to have chapters is a choice, but the choice of chapter break I have in there is <em>really amusing</em> to me, so it's a choice I'm making in the affirmative;
I'll reconsider if I end up with "Chapter 2: Everything Else";
the other thing I need to ponder some is the question of chapter titles, subtitles, quotations, etc.</li>
<li>Lower-level: "scenes" and "summary";
Rather than my draft, this is based on the writing advice I've been reading;
The idea here is that I would like to reason about smaller parts of the narrative than a single chapter, so I should call them out here.</li>
<li>Other levels: I am aware that I <em>could</em> come up with groupings of chapters (I probably will end up needing "book" to be honest, because the draft ends on a sequel hook), but I don't want to get ahead of myself;
similarly, maybe there are divisions that I'd like between chapter and scene, or within scene, but my gut feeling is that I should try working with book-chapter-scene, and see what that gets me;
(the obvious things that occur to me are "paragraph" and "sentence", which I hope illustrate why I think it may be best to hold off on dividing things up that finely).</li>
</ul>
<p>If we assume that I'm going with book-chapter-scene, then I've got some ideas for what I need to get things right.</p>
<ul class="simple">
<li>Books must have a title, and this title must end up in the generated documents.</li>
<li>Chapters may have a title etc, which should end up in the generated documents.</li>
<li>I would like chapters to be consistent about what such information they have associated with them.</li>
<li>Chapters are also numbered.</li>
<li>It is likely but not certain that I would like to associate different kinds of metadata with scenes, such as which arcs they relate to.</li>
<li>Some of this metadata is best expressed through references to scenes in other parts of the tree.</li>
</ul>
<p>Summing things up:</p>
<ul class="simple">
<li>Every division between book and chapter, inclusive, represents a visible distinction in the final output, including, for example, specific formatting to call out the boundary.</li>
<li>These nodes are to be named with a word or abbreviation indicating their role (for verification purposes), and a short summary of their contents, for aid in navigating the tree.</li>
<li>The contents of these nodes are to consist of some lines of metadata, followed by a more detailed summary of the child nodes.</li>
<li>The contents of a node should be fully accounted for by its direct children.</li>
<li>For evaluating the outline, I would like the ability to mark specific nodes as "included literally" or something; such nodes should not be allowed to have child nodes.</li>
</ul>
<p>I wish to process all of this into a few different forms:</p>
<ul class="simple">
<li>preface only</li>
<li>story without preface</li>
<li>story with preface (which is then processed into other forms)</li>
<li>absolutely everything (not sure the exact way this should present everything, so I'd like to hold off for now)</li>
</ul>
<p>To accomplish this, I'm pretty sure I need:</p>
<ul class="simple">
<li>Use of <strong>node tags</strong> for repeated scalar or mostly-scalar metadata.</li>
<li>Use of <strong>inline metadata</strong> for key-value metadata, unless there is some alternative.</li>
</ul>
<p>I think this is all solid as an idea, but I need to take some time to sketch it out on paper for a bit before I can implement it.
And none of that is happening now, because it's late again.</p>
<p>Good night.</p>
Coding 2024-02-102024-02-10T05:00:00-05:002024-02-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-10:/coding-2024-02-10<p class="first last">The category and tags are all wonky now, but I feel committed, so oh well.</p>
<p>Okay, this is interesting.
I don't have the proper context for putting things together in terms of absolute convergence, but when I tried drafting the required predicates, a few things jumped out at me:</p>
<ul class="simple">
<li>The use of "counting" values makes the structure of the predicates simpler.</li>
<li>This simplification means that I need different predicates supporting it.</li>
</ul>
<p>I'll need some time to collect my thoughts on this.
So, for at least a little bit, I'm going to put this project down and focus on some other things.</p>
<p>In particular, I've got a novel I've been writing, and the current draft document is unwieldy to navigate.
I've been reading about writing advice, and trying to figure out how to change my process to address the issues I'm having.</p>
<p>Currently, I have a reStructuredText file that contains a combination of "actual draft text", [text in brackets] that indicates summarized ideas of what could go in, and reStructuredText comments that indicate structure that doesn't have either of the former two backing it up.
I have a tasks.py file that defines tasks to check the spelling of the file; this is necessary because I need to allow some words, and forbid others.
(Weirdly enough, when I was trying to forbid particular words, hunspell wouldn't acknowledge those words, so I needed an extra step to find them with a regular expression.)
And another to convert the file to html and docx, as handled by <a class="reference external" href="https://ninja-build.org/">ninja</a>, via a hand-written file.</p>
<p>What I'm considering trying to do is to convert the draft to an outline in <a class="reference external" href="https://leoeditor.com/">Leo</a>, and write code to process the .leo file into an rst file that can then feed through the other steps.
What I need to figure out before embarking on trying to do all that is, what structure do I want to put the outline in?
What would be helpful for me?</p>
<p>Here are my quick thoughts, untested ideas:</p>
<ul class="simple">
<li>Have the outline correspond to the hierarchical organization of the draft.</li>
<li>Figure out how I might attempt to add in some helpful metadata, but don't worry too much if I can't figure out how to make that practical.</li>
</ul>
<p>So, going forward, not now, but soon, my plan would be to transcribe the draft and some scraps of exposition into a .leo file, with one section for the outline, and another for notes.
Sort of like a very un-flashy Scrivener file, since I don't feel like resuscitating an old laptop and trying to get Scrivener working again.
There are still some questions to answer here about the details of the structure, and I'll try to figure them out later.
For now, I've pushed things way too late.</p>
<p>Good night.</p>
Coding 2024-02-092024-02-09T05:00:00-05:002024-02-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-09:/coding-2024-02-09<p class="first last">It's a little weird that this works, except that there's no reason it <em>shouldn't</em>.</p>
<p>Here we go, I've verified that my weird Dafny code appears to work, so I'm ready to talk about it.</p>
<p>The goal:
Functions that return other functions which meaningfully depend on their outputs.</p>
<p>The problem:
Dafny <em>appears</em> not to support creating closures.
I tried the workaround of "make an object", and that ran into "can't allocate in functions" (which, from my basic experience with Rust, I guess makes sense (please note that Rust functions and Dafny functions are pretty different things)), but also "I tried returning a bound function from an instance, and that didn't seem to work, oh well".</p>
<p>The messed-up workaround:
While Dafny, if I'm reading the grammar documentation correctly, doesn't have a way to declare a function inside a function, it does have the ability to use <tt class="docutils literal">ensures</tt> clauses to describe <em>what properties a function capable of doing such a thing would have</em>, and then just, don't write a body for the function, and it will successfully reason about whatever currying-based nonsense you ask it to.</p>
<p>I suppose another possible approach would be to write a predicate describing the desired relationships, then using the predicate with an assignment statement to create a fake closure through Prolog Nonsense.
I think that approach would be more flexible in some key ways, but I don't think I need them, so I'll keep on with what I'm doing now.
And if I do end up needing the flexibility, I can write the predicate, replace the <tt class="docutils literal">ensures</tt> clause with it, and move on.</p>
<p>...</p>
<p>All right, I've put together a few more of these helper functions.
At this point, I'm just about ready to redo the absolute convergence predicates, knowing what I now know about how I want to set things up.
I could try getting on with that now, or...</p>
<p>Or I could say "You know what, that's enough for now, I want a break from screens and to get ready for bed."
Probably the smart play.</p>
<p>Good night.</p>
Coding 2024-02-082024-02-08T05:00:00-05:002024-02-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-08:/coding-2024-02-08<p class="first last">A potential victory in the fight against Dafny's syntax(!)</p>
<p>Okay, so.</p>
<p>It turns out one of the things I wanted to do last time isn't straightforward to accomplish in Dafny, but I may have found a way to do it.
An extremely cursed, messed-up-seeming way.</p>
<p>I don't feel like describing what I was trying to do, or verifying that my attempt at a fix actually works.
I'll do that later.</p>
<p>For now, I'm going to read and wind down.</p>
<p>Good night.</p>
Coding 2024-02-072024-02-07T05:00:00-05:002024-02-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-07:/coding-2024-02-07<p class="first last">Pardon my extremely unmotivated notational choices.</p>
<p>So, last time, I—</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Ahem</p>
</div>
<p>mentioned that working with absolute convergence requires coming up with a means of counting the non-zero elements of an infinite set.</p>
<p>So, to try to formalize this before I trip all over myself in the code...</p>
<p>Given a set <tt class="docutils literal">S</tt> and a partial function <tt class="docutils literal">σ</tt> from <tt class="docutils literal">S</tt> to ℝ.
We want a pair of functions between <tt class="docutils literal">S</tt> and ℕ, such that:</p>
<ul class="simple">
<li>For a given <tt class="docutils literal">s</tt> in <tt class="docutils literal">S</tt>, if <tt class="docutils literal">σ(s)</tt> is non-zero, <tt class="docutils literal">s</tt> is mapped to an integer <tt class="docutils literal">n</tt>, and <tt class="docutils literal">n</tt> is mapped back to <tt class="docutils literal">s</tt>.</li>
<li><tt class="docutils literal">σ(s)</tt> is defined for all <tt class="docutils literal">s</tt> in <tt class="docutils literal">S</tt>; extend <tt class="docutils literal">σ</tt> by giving it a zero value for all input values not in <tt class="docutils literal">S</tt>, thereby producing a total function.</li>
<li>For a given <tt class="docutils literal">n</tt> in ℕ, if <tt class="docutils literal">n</tt> is mapped to an <tt class="docutils literal">s</tt> in <tt class="docutils literal">S</tt> such that <tt class="docutils literal">σ(s)</tt> is non-zero, then <tt class="docutils literal">s</tt> is mapped back to <tt class="docutils literal">n</tt>.</li>
</ul>
<p>The computational artifact of interest is the mapping from ℕ to <tt class="docutils literal">S</tt>.
Let us assume it can be a partial function.
We can combine such a mapping with <tt class="docutils literal">σ</tt> to obtain a <em>total</em> function from ℕ to ℝ, which, if the sum is absolutely convergent, it is identical to summing over <tt class="docutils literal">S</tt>.</p>
<p>We can avoid having to define an explicit inverse function, by using existential quantifiers, I think.</p>
<p><tt class="docutils literal">σ(s)</tt> is non-zero implies that there exists an <tt class="docutils literal">n</tt>, and this <tt class="docutils literal">n</tt> must be unique, which is equivalent to "for all <tt class="docutils literal">n'</tt> that correspond to <tt class="docutils literal">s</tt>, <tt class="docutils literal">n == n'</tt>".</p>
<p>I'm going to need to think carefully about whether the first and third bullet points are equivalent, because I tried to relax the requirements from "inverse functions", and it's muddling my thinking.
Right now I'm leaning towards "the previous paragraph is all I need", but, we'll see after I've had some rest.</p>
<p>(Since I've thought about this hard enough that now I just really really want to switch gears and let it all percolate for a bit.)</p>
<p>Good night.</p>
Weekly Roundup 2024-02-062024-02-06T05:00:00-05:002024-02-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-06:/weekly-roundup-2024-02-06<p class="first last">I accomplished a quantity of things that I find somewhat surprising.</p>
<ul class="simple">
<li>Wednesday: I wrote up a list of properties a binary relation can have, that seemed either useful or easy to describe.</li>
<li>Thursday: I learned the basics of Dafny project files, which seem really useful for anything involving more than one file, <em>and</em> anything involving particular tweaks to the verification process.</li>
<li>Friday: I tried to prove some bedrock theorems in Dafny, and had a bad time with that, but I did learn a little about the module system.</li>
<li>Saturday: My day was too busy to do much that interested me.</li>
<li>Sunday: I pulled Demiurgent Business out of mothballs to publish the jam and jam-adjacent versions, which aren't really fleshed-out, or tested, but they are <em>short</em>, at least.</li>
<li>Monday: I figured out how to prove that bedrock stuff from earlier.</li>
</ul>
<p>Next week, maybe I'll keep on with this, maybe I'll wind up glomming onto one of the other half-dozen-plus projects I have lying around.</p>
Coding 2024-02-052024-02-05T05:00:00-05:002024-02-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-05:/coding-2024-02-05<p class="first last">The whole setup still looks a little strange.</p>
<p>All right.
I don't have time to explain it, but, by following some suggestions online, I managed to prove that summing from a series with indices drawn from a set, the order that the indices are chosen doesn't matter.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Only abstractly, and not with IEEE floats as the output, of course.</p>
</div>
<p>Anyway, with that, and a few other things I wrote, I'm most of the way towards being ready to work on the absolute convergence stuff again.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Doesn't the focus on countable sets in the context of absolute convergence require some form of bijective mapping to the naturals, thereby rendering the whole detour to avoid imposing an ordering on the sets of indices pointless?</p>
</div>
<p>At least I got some experience wrangling Dafny.</p>
<p>Anyway, it's late and I'm tired.</p>
<p>Good night.</p>
Demiurgent Business 2024-02-042024-02-04T05:00:00-05:002024-02-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-04:/demiurgent-business-2024-02-04<p class="first last">Life hack: write the bulk of the post like three months ago, and then, this is the important part, <em>actually publish it</em>.</p>
<p>This weekend is probably going to be a bit of a wash, so I decided to put out some stuff I put on my tumblr a few months ago.
See, during my NaNo (which failed for various reasons that I want to think about at some point...), there was a 200-word RPG jam, and I ended up taking some time to strip Demiurgent Business to the barest essentials.
I ended up with two versions:</p>
<div class="section" id="jam-version-1">
<h2>Jam-version-1</h2>
<div class="section" id="demiurgent-business">
<h3>Demiurgent Business</h3>
<p>For 3+ players</p>
<p>Each player picks 1 [Supernatural] trait and 1 [Character] trait, then names and describes the resulting character.</p>
<p>Example [Supernatural] traits:</p>
<ul class="simple">
<li>Time-traveling</li>
<li>Android</li>
<li>Psychic</li>
<li>Alien</li>
</ul>
<p>Example [Character] traits:</p>
<ul class="simple">
<li>Honor student</li>
<li>Athlete</li>
<li>Slacker</li>
<li>Tech whiz</li>
</ul>
<p>The group designs the Demiurge: agree on two [Character] traits, then name and describe the resulting character.</p>
<p>One player starts as the Demiurge; pass the role clockwise when a new scene begins.</p>
<p>When a scene begins, set Gnosis to 0.
The Demiurge describes the scene's goal.
The other players help the Demiurge fulfill that goal.</p>
<p>The Demiurge describes obstacles that arise.
The other players describe how their characters resolve the obstacle.
For every [Character] trait involved in the resolution, decrement Gnosis to a minimum of 0.
Then, for every [Supernatural] trait involved, increment Gnosis.
Whenever Gnosis increases to 3, the Demiurge may make 1 mundane change to the setting.
Whenever Gnosis increases to 6, the Demiurge may make 1 mundane or miraculous change to the setting.
When Gnosis increases to 9, the Demiurge achieves Apotheosis; the Demiurge's current player wins.
Otherwise, the scene ends when the other players determine that the goal is completed, or impossible.</p>
</div>
</div>
<div class="section" id="too-long-to-be-jam-version-2">
<h2>Too-long-to-be-jam-version-2</h2>
<div class="section" id="demiurgent-business-1">
<h3>Demiurgent Business</h3>
<p>For 3+ players</p>
<p>Each player picks 1 [Supernatural] trait and 1 [Character] trait, then names and describes the resulting character.</p>
<p>Example [Supernatural] traits:</p>
<ul class="simple">
<li>Time-traveling</li>
<li>Android</li>
<li>Psychic</li>
<li>Alien</li>
</ul>
<p>Example [Character] traits:</p>
<ul class="simple">
<li>Honor student</li>
<li>Athlete</li>
<li>Slacker</li>
<li>Tech whiz</li>
</ul>
<p>The group designs the Demiurge: agree on two [Character] traits, then name and describe the resulting character.</p>
<p>One player starts as the Demiurge; when a new scene begins, the player who relied most on their [Supernatural] trait in the previous scene becomes the Demiurge.</p>
<p>When a scene begins, set Gnosis to 0.
The Demiurge describes the scene's goal.
The other players help the Demiurge fulfill that goal.</p>
<p>The Demiurge describes obstacles that arise.
The other players describe how their characters resolve the obstacle.
For every [Character] trait involved in the resolution, decrement Gnosis to a minimum of 0.
Then, for every [Supernatural] trait involved, increment Gnosis.
Whenever Gnosis increases to 3, the Demiurge may make 1 mundane change to the setting.
Whenever Gnosis increases to 6, the Demiurge may make 1 mundane or miraculous change to the setting.
When Gnosis increases to 9, the Demiurge achieves Apotheosis; the Demiurge's current player wins.
Otherwise, the scene ends when the other players determine that the goal is completed, or impossible.</p>
</div>
</div>
<div class="section" id="commentary">
<h2>Commentary</h2>
<p>First off, I haven't tested either version of this, so it probably has <em>issues</em>.
In particular, there's the issues around the differences between the two versions.
I made the changes because I wanted to try to make play more fast-paced and competitive, but I'm worried it could lead to a kingmaker dynamic.</p>
<p>Going forward, I want to try to come up with tables to roll on for [Supernatural] and [Character] traits, as well as the ability to mad-libs together a scene's goal, so that sometimes the players have to figure out what sub-goals and obstacles there may be to accomplish "Film a Website".</p>
<p>And once that's done, there's the possibility of putting together alternative tables for [Character] traits and goals, allowing for supplements that are somewhat analogous to Fiasco playbooks, thus allowing for scenarios like "The Demiurge is Beret Guy from xkcd, and the player characters are employees at his strange start-up."</p>
<p>Anyway, I'll keep that all in mind.
For now, I'm actually writing this early and basically banking it against tonight.
Maybe I'll add something after we travel, maybe not.
We'll see.</p>
<p>Nah, I'm good.</p>
<p>Good night.</p>
</div>
Diary 2024-02-032024-02-03T05:00:00-05:002024-02-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-03:/diary-2024-02-03<p class="first last">Oh well, maybe tomorrow, but leaning towards not.</p>
<p>I had a whole bunch of stuff that I had or wanted to take care of today, and that ultimately translated into "No time to consider stuff for Dafny."</p>
<p>I'm traveling tomorrow and the day after, and my plan with that is to either get <em>something</em> done with Dafny (either proving some basic facts, or fixing up the files I wrote before I understood what project files were capable of), or to write up some stuff from a few months ago that I may as well at some point, hopefully soon.</p>
<p>Right now, though, I want to close stuff down and get to bed.</p>
<p>Good night.</p>
Coding 2024-02-022024-02-02T05:00:00-05:002024-02-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-02:/coding-2024-02-02<p class="first last">Question: is Dafny "of the belief" that the ghost version takes on a single value? Because, if so, why isn't the lemma "obvious", and if not, what the heck does any of this <em>mean</em>?</p>
<p>Instead of rewriting my following-along code, I wrote an <tt class="docutils literal">IsTotalOrder</tt> predicate in terms of named properties, and now I'm thinking about the finite sum stuff.
What I'd like to figure out is if there's some way to establish the equivalence between the explicitly ordered non-ghost version, and the unordered ghost version.</p>
<p>Going to speculate on ways to do that.</p>
<p>Suppose I do induction that "builds up" stuff.
Given a set <tt class="docutils literal">s</tt> and an order <tt class="docutils literal">r</tt>, I want to build things up something like:</p>
<ul class="simple">
<li>If <tt class="docutils literal">s == {}</tt>, then both versions sum to <tt class="docutils literal">0.0</tt>.</li>
<li>Suppose both versions have the same sum for some <tt class="docutils literal">s</tt>.
Now, given an element <tt class="docutils literal">k</tt> (not in <tt class="docutils literal">s</tt>?), I want to try establishing that <tt class="docutils literal">s + {k}</tt> increases both results by <tt class="docutils literal">summand(k)</tt>.</li>
</ul>
<p>Hm, I've got some time to try this out.
I also need to get a handle on the import system in Dafny, but I want to work that out at some point anyway...</p>
<p>"By default (in the absence of any export set declarations) all the names declared in a module are available outside the module using the <tt class="docutils literal">import</tt> mechanism."</p>
<p>Neat, thank you for that.</p>
<p>"<tt class="docutils literal">Error: module Relation does not exist</tt>"</p>
<p>No thank you for <em>that</em>.
What am I doing wrong here...
Tinker, fiddle...</p>
<p>"<tt class="docutils literal">Error: Import declaration uses same name as a module in the same scope: Relation</tt>"</p>
<p>Huh.
That implies that it doesn't really work the way that I think it does...
Let's try what it looks like that should allow.</p>
<p>Huh, yeah, module names are just globally available, and import does rebinding?
That... freaks me out a little bit.</p>
<p>Anyway, I got the code reuse wrangled, copied over the code, and now I'm working on constructing a lemma to prove that addition of a finite collection of numbers works the way everyone knows it does.
Dafny does not yet know it, at least not in a way germane to the way I phrased the lemma.</p>
<p>Unfortunately, it's now late, and I'll have to wait until sometime tomorrow to get this worked out, if not later.</p>
<p>Bed.</p>
<p>Good night.</p>
Coding 2024-02-012024-02-01T05:00:00-05:002024-02-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-02-01:/coding-2024-02-01<p class="first last">Extremely excited to rewrite my <tt class="docutils literal">tasks.py</tt> file to run <tt class="docutils literal">dafny verify path/to/dfyconfig.toml</tt> as much as possible.</p>
<p>I was kind of out of it today, but I managed to get all of the baseline definitions I was thinking about in.
At this point, I just need to define the total order stuff, and move along.</p>
<p>The more important thing is, I now get the (very very very) basics of Dafny projects.
At this point, it makes sense to try to rewrite my existing "following-along" code to be consistent with the style guide, and to try to handle verifying it with as few project files as possible.</p>
<p>Well, I'll get to that later, and get to bed now.</p>
<p>Good night.</p>
Coding 2024-01-312024-01-31T05:00:00-05:002024-01-31T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-31:/coding-2024-01-31<p class="first last">Hoarding property definitions like a <em>really weird</em> dragon.</p>
<p>I've got other stuff I want to put up entries about this week, but today was a lot, so instead I'm going to do some planning for the module separation I want to do.</p>
<p>I'm right now focusing on the total ordering relation, and for the fun(?) of it, I'd like to define that predicate in the context of other predicates applying to binary relations.
Let's see which properties may be of interest:</p>
<ul class="simple">
<li>Reflexive and irreflexive</li>
<li>Antisymmetric, asymmetric, symmetric</li>
<li>Connected and strongly connected</li>
<li>Dense</li>
<li>Transitive and antitransitive</li>
<li>Quasitransitive? Like, I can define it, but I'm not sure offhand what I'd do with it.</li>
<li>Serial? Like, sure.</li>
<li>Euclidean?</li>
</ul>
<p>These properties should be a good baseline for putting things together, and then building more elaborate properties on top of them.</p>
<p>I'll try to get on that in the next few days.
For now...</p>
<p>Good night.</p>
Weekly Roundup 2024-01-302024-01-30T05:00:00-05:002024-01-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-30:/weekly-roundup-2024-01-30<p class="first last">Actually trying to work with some of this rigorously is still a real shock to the system.</p>
<ul class="simple">
<li>Wednesday: I had some troubles with Dafny, so I set my sights a little lower.</li>
<li>Thursday: Screen headache.</li>
<li>Friday: I started trying to take rigorous definitions of limits, and convert them to Dafny code.</li>
<li>Saturday: I came up with a game plan for (part of) the infinite limit representation.</li>
<li>Sunday: I ran into bizarre issues with Dafny that sound like bugs, or at least missing features, but I lack the context to understand the stuff about how it's "supposed to work", so eh.</li>
<li>Monday: I got past the issues, made everything verify, then looked at the file and thought "that's too big; I should learn how Dafny projects work so I can break this into at least four files".</li>
</ul>
<p>Next week, I'll probably do that; I also have a few other things that I've started messing with recently, and a few things that I've been messing with on and off.</p>
Coding 2024-01-292024-01-29T05:00:00-05:002024-01-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-29:/coding-2024-01-29<p class="first last">I'm not retyping those names.</p>
<p>I did a bunch of admin work stuff today, and then played video games, so I haven't done a ton of work with the Dafny code.
Instead of trying to rush into anything, I'm going to plan a little for later:</p>
<ul class="simple">
<li><tt class="docutils literal">IsTotalOrder</tt> seems like a generally useful predicate.</li>
<li><tt class="docutils literal">ThereIsAMinimum</tt> seems like a special-purpose lemma, which should get bundled up as a private member of the module that provides...</li>
<li><tt class="docutils literal">SumOver</tt>, which I would like to figure out some way to provide an equivalent <tt class="docutils literal">ghost</tt> version of that doesn't need an ordering.
(The trick is <em>proving</em> that the two versions are equivalent.)</li>
<li><tt class="docutils literal">LessEqual</tt> is a basic helper predicate that bundles with some of the predicates below, but I wouldn't mind getting rid of it if I work out the proof I mention above.</li>
<li>I've got a bunch of helper things that I don't know how generally useful they are: <tt class="docutils literal">HasMinimum</tt>, and <tt class="docutils literal">Minumum</tt> are needed for how I'm trying to define absolute convergence, but I don't know if anything else has reason to refer to them.</li>
<li><tt class="docutils literal">IRHelper</tt> is only needed because <tt class="docutils literal">InclusiveRange</tt> was having troubles; wait, can I define nested functions in Dafny, because that would be handy here.
Either way, these together represent a single coherent concept that seems generally useful.
(Part of that usefulness is that I couldn't be bothered to figure out the right number theory proof for "there are a finite number of integers between any two integers, and if your response to that is "that sounds like something that the set comprehension heuristics should give you for free", the answer to that is "somehow, not the way I was using them".)</li>
<li><tt class="docutils literal">SetUntil</tt> is a helper for absolute convergence stuff, but it's probably needed as part of proving absolute convergence in any specific case.</li>
<li><tt class="docutils literal">NonNegativeAtValues</tt> is a predicate needed for absolute convergence stuff; I'm not sure offhand that there's any use exposing it.</li>
<li>Then, I've finally got three predicates with really unwieldy names; these build up to the idea of absolute convergence, and until I try actually establishing absolute convergence of basic series, I won't know how generally useful they are to refer to.</li>
</ul>
<p>So, that works out to four-ish modules I want to break this stuff into:</p>
<ul class="simple">
<li>total order and anything related to that somehow</li>
<li>finite sums</li>
<li>inclusive ranges</li>
<li>limits of absolutely convergent sums</li>
</ul>
<p>And, with that, I'm going to call things done for now, and get ready for bed.</p>
<p>Good night.</p>
Coding 2024-01-282024-01-28T05:00:00-05:002024-01-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-28:/coding-2024-01-28<p class="first last">Cutting edge technology, in that there are many edges to cut oneself on.</p>
<p>Okay, after a lot of struggle (something seems to be <em>wrong</em> with the whole "heuristics" thing that set comprehensions have, and some of my efforts to fix it landed me on StackOverflow reading about "triggers", and completely confused because this was happening in set comprehensions rather than a <tt class="docutils literal">forall</tt>, so I couldn't figure out how to translate the stuff about triggers into this context), I've got the functions from last night implemented and the code somewhat cleaned up.</p>
<p>Now, for the rest of the cleanup, I need to figure out how to set up modules and imports so I can slim down these files and come up with better names.</p>
<p>For the moment, I need to wind down, now that I've accomplished a bunch of stuff, at great psychic cost.</p>
<p>Good night.</p>
Coding 2024-01-272024-01-27T05:00:00-05:002024-01-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-27:/coding-2024-01-27<p class="first last">I don't intend to inflict these names on anyone else more than this post already does so.</p>
<p>Well, shortly after last entry, I remembered that <tt class="docutils literal">forall</tt> exists, which will probably be helpful to writing this stuff up in Dafny.</p>
<p>The challenge I have now is that I'm not sure what to call some of the predicates I'll be writing.</p>
<p>The major thing I want to work towards is a predicate for "this value is the limit of this increasing series as the index increases to infinity".</p>
<p>This is equivalent to "for every positive real number, there is a finite number of terms that add up to between that number and the limit, but no finite number of terms that adds up to strictly more than the limit".</p>
<p>So, we want to say that, given a positive real number and everything else, we can find a minimum value above which the series is bounded between the limit and the limit minus the epsilon.</p>
<p>And finally, we want to say whether, given a <em>specific</em> minimum and everything else, that set of values describes a valid example of the definition of a limit.</p>
<p>From this, we can then build out predicates for more interesting sets and summands.</p>
<p>I'm not going to try and implement this right now, but I'd at least like to try to come up with some names.</p>
<ul class="simple">
<li><tt class="docutils literal">InfiniteLimitOfIncreasingSeries</tt></li>
<li><tt class="docutils literal">IndexBeyondWhichIncreasingSeriesIsBounded</tt></li>
<li><tt class="docutils literal">BoundsOfIncreasingSeriesBeyondIndex</tt></li>
</ul>
<p>Or something like that.</p>
<p>I've got nothing more in me tonight, so I'm going to try to wrap up soon.</p>
<p>Good night.</p>
Coding 2024-01-262024-01-26T05:00:00-05:002024-01-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-26:/coding-2024-01-26<p class="first last">No idea if this will work. Slightly worried it'll drain my battery. Oh well.</p>
<p>Well, I feel awful, but I also feel <em>stubborn</em>.
Let's see what I can make of infinite sums that converge absolutely.</p>
<p>First off, this is all ghost functions unless I get <em>seriously inspired</em>.</p>
<p>Next off, a lot of the math for this (somewhat reasonably) involves infinite limits.
But those only make sense when the set being summed over is a subset of the integers.
The dream is that there is a general notion of convergence, and a lemma or something that shows that constructs involving limits satisfy it.</p>
<p>Before anything else, let's consider what's needed to express one of these limits, because that's probably going to be tricky.</p>
<p>For these infinite limits, let's start by only caring about positive infinity.
And assume that the inputs to the primitive version we start with are non-negative.
These assumptions will probably have to be unbundled later, but I need to prototype <em>something</em>.</p>
<p>With all of this, if we say that some infinite sum over a subset of the integers with a minimum value (another assumption), then the limit of that sum as more integers are included is...</p>
<p>Ugh...</p>
<p>Given an epsilon, we can determine an N, such that the sum of the subset up to any number <em>above</em> N will always be within epsilon of the limit.</p>
<p>This sounds like a negative statement, and I'm not sure where establishing a negative in Dafny stands in terms of pain level, ranging from "trivial" through "confusing" to "impossible".
Perhaps some form of inductive proof...
Like, if I can establish that, for a given function, having the inequality hold for some number M means I can establish that it also holds for M+1...</p>
<p>So, that provides a way forward to answering the question; now I just need to figure out how to <em>ask</em> it.</p>
<ul class="simple">
<li>So, we need a subset of the integers.</li>
<li>We need a function from the integers to the reals.</li>
<li>We need the values of the function to be non-negative for every integer in the set.</li>
</ul>
<p>Now, function plus infinite set <em>does not</em> have a general algorithm.
So, I <em>think</em> this needs to be some form of lemma or predicate or something.</p>
<p>Like, a predicate that requires some inductive stuff.</p>
<p><tt class="docutils literal">ghost predicate Lim(nums: iset<int>, summand: (int) <span class="pre">-></span> real, limit: real, epsilon: real, N: int)</tt></p>
<p>Or something.
The idea is that it would require the <tt class="docutils literal">nums</tt> set to have a lowest element, that every element <tt class="docutils literal">k</tt> in <tt class="docutils literal">nums</tt> has a non-negative value for <tt class="docutils literal">summand(k)</tt>, and that if we take the finite subset of <tt class="docutils literal">nums</tt> less than <tt class="docutils literal">N</tt>, then the <em>finite sum</em> of <tt class="docutils literal">summand</tt> applied to the elements of that subset must be less than <tt class="docutils literal">limit</tt>, and that sum plus <tt class="docutils literal">epsilon</tt> must be <em>greater than</em> <tt class="docutils literal">limit</tt>, and the same predicate must hold except with <tt class="docutils literal">N+1</tt> instead of <tt class="docutils literal">N</tt>.</p>
<p>I'm not sure if I'm able, at my current level of abilities or in general, to express that idea and make use of it, but it seems like a promising avenue.</p>
<p>And, I am wiped out for tonight and ready to take a break.</p>
<p>Good night.</p>
Diary 2024-01-252024-01-25T05:00:00-05:002024-01-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-25:/diary-2024-01-25<p class="first last">Uuuuuugh again</p>
<p>I messed myself up today staring at screens, so now I need to <em>stop looking at my laptop</em>, and I'm not currently doing a great job of that.</p>
<p>It would be nice if I thought of something else for this entry, but nope.</p>
<p>I need to go grab a book or something.</p>
<p>Good night.</p>
Coding 2024-01-242024-01-24T05:00:00-05:002024-01-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-24:/coding-2024-01-24<p class="first last">I really hope "if you're missing certain asserts, it just spins its wheels forever" is something that's going to go away.</p>
<p>Guys, it is <em>really hard</em> to write this stuff incrementally when I assume that "not filling in the branches of an if statement" will result in some kind of verification error, and instead it just makes my laptop fans try to launch it through the ceiling.</p>
<p>I've changed things up a bit:</p>
<ul class="simple">
<li>a ghost function to specify behavior; I think it assumes that Dafny's <tt class="docutils literal">real</tt> type is associative and commutative under addition</li>
<li>a ghost predicate for stating that a dyadic function acts as a total ordering</li>
<li>a lemma stating that any finite set has a minimum according to a given total ordering</li>
<li>a summation method that requires a total ordering to fix the order of execution</li>
</ul>
<p>I am doing <em>something</em> wrong with the last bit, but I can't tell what.</p>
<p>...</p>
<p>A-ha!
I neglected to invoke the lemma in the method, which caused Dafny to go into an infinite loop because I don't know!</p>
<p>A few more tweaks later, and now I just need to determine why Dafny appears to think that <tt class="docutils literal">0.0</tt> might not be equal to <tt class="docutils literal">0.0</tt>.</p>
<p>...</p>
<p>I think I understand the gap between what I'm trying to get Dafny to accept and what it has available to work with, but I don't want to deal with it...</p>
<p>So I didn't.
I stripped out the ghost function and made the "regular" function be the entire implementation.
I'll try not to care about that too much.</p>
<p>Once I got the code all verifying, I figured out which asserts I could get rid of, which turns out to be risky because the ones I couldn't get rid of put it into an infinite loop again.</p>
<p>So, the code is, if not clean, at least sort of short.
Maybe I'll clean it up later.
Maybe I'll move on to other bits of code.
Maybe I'll decide to do something else entirely.</p>
<p>I'll work that all out later, and for now get to bed, because sleepy.</p>
<p>Good night.</p>
Weekly Roundup 2024-01-232024-01-23T05:00:00-05:002024-01-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-23:/weekly-roundup-2024-01-23<p class="first last">It's not a great feeling to run into these sharp edges, but whatever.</p>
<ul class="simple">
<li>Wednesday: I started looking into summation, and thinking about how to handle it in Dafny.</li>
<li>Thursday: I narrowed in on the thing that I absolutely need to figure out how to do in Dafny, in order to use it for verifying this math.</li>
<li>Friday: I took another look at the chapter in the textbook, and things ended up going a little out of control.</li>
<li>Saturday: I discovered that interacting with sets in Dafny is... strange.</li>
<li>Sunday: I found a few things that I had been doing wrong with Dafny, and then ended up doing a few other things wrong.</li>
<li>Monday: Got sick.</li>
</ul>
<p>Next week, I'm not sure what I feel like doing.
I did discover that whatever I'm doing wrong with Dafny is orphaning z3 processes that are squatting on one core each-ish, so that's... not ideal.
As far as Dafny goes, I want to try and figure out at which point the hang is coming into play.
As far as other things go...
I'm not sure, we'll see.</p>
Diary 2024-01-222024-01-22T05:00:00-05:002024-01-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-22:/diary-2024-01-22<p class="first last">Uuuuuugh</p>
<p>Well, I'd been thinking of trying to work on Concrete Mathematics and Dafny today, but I relaxed most of the day, and tonight, my body came up with other, much less pleasant plans.</p>
<p>Now it's much later than I meant to be up, and there's no way I can get anything else done.
I'm going to hope that things work out a little better tomorrow, but let's not force anything.</p>
<p>Good night.</p>
Coding 2024-01-212024-01-21T05:00:00-05:002024-01-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-21:/coding-2024-01-21<p class="first last">I should not be trusted to know what is not possible with Dafny.</p>
<p>Okay, still getting to grips with Dafny.
It's not a fast process when I'm just doing a little a day, I guess.
In any case, I now understand something that had me a little confused.
The meaning of the keywords kind of changed around between Dafny 3 and 4, and a lot of the stuff I'm reading happens to be for 3, but I'm using 4 because I wanted to make some use of the standard library.</p>
<p>In particular, what 3 expresses via <tt class="docutils literal">function method</tt> is just <tt class="docutils literal">function</tt> in 4, while what 3 calls <tt class="docutils literal">function</tt> is <tt class="docutils literal">ghost function</tt> in 4.</p>
<p>In light of this, I've slightly updated my existing files to make sure that they're actually expressing what they're supposed to; basically just making sure that the recurrent forms are <em>ghost</em> functions.</p>
<p>I also ran across some documentation about telling Dafny to generate counterexamples; I'll have to try that out later.</p>
<p>Aside from that, I tried to put together some flexibly generic code for summing over sets, using a short guide I found about <a class="reference external" href="https://leino.science/papers/krml275.html">iterating over a collection</a>, and I'm not sure what I'm doing wrong, but my attempts to follow the directions seem to be putting Dafny in another infinite loop, so that'll be some kind of pain to troubleshoot.</p>
<p>(At least the infinite version should be "easier", since I think that <em>has</em> to be ghost.)</p>
<p>Also, thinking about this, I'm going to have to remember how to rigorously prove convergence, and that could be... a thing.</p>
<p>I may end up needing to take a break from this and focus on somewhat less intimidating pursuits.
For the moment, I should get ready for bed.</p>
<p>Good night.</p>
Coding 2024-01-202024-01-20T05:00:00-05:002024-01-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-20:/coding-2024-01-20<p class="first last">I can't tell if it needs to be like that.</p>
<p>"Hey, what if I handle finite sums as a simple function, since those don't need to worry about convergence tests?"</p>
<p>"Hey, why don't I make the baseline implementation use finite sets, for flexibility?"</p>
<p>"... I don't understand how to iterate over a set in Dafny, possibly because I'm now too tired to read the documentation properly."</p>
<p>"After writing that last line, I figured out where to look in the documentation, and now I kind of wish I hadn't?"</p>
<p>Okay, so, if I want to do all of this in a function, I need to extract an element via a bizarre sequence of glyphs, then set difference it out and recurse?
At least I don't need to worry myself about tail recursion, since I'm not planning to execute this.
I might do it anyway, just because it's not like I can make this <em>any harder</em> to grasp.</p>
<p>Anyway, I'm going to consider it a win that I worked out that much, and try to get ready for bed.</p>
<p>Good night.</p>
Coding 2024-01-192024-01-19T05:00:00-05:002024-01-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-19:/coding-2024-01-19<p class="first last">Regrettably, I'm just getting started. This notation and its uses are... flexible.</p>
<p>Okay, let's see.</p>
<p>Delimited summation notation has a lower and upper bound on an integer, and a function from an integer to a real.</p>
<p>Generalized summation notation has an <tt class="docutils literal">iset</tt> (should there be something separate for specifically a <tt class="docutils literal">set</tt>?) of some type <tt class="docutils literal">T</tt>, and a function from <tt class="docutils literal">T</tt> to <tt class="docutils literal">real</tt>.</p>
<p>It may be pleasant to include a form that combines bounds with predicates, but I'm not sure how many "nice-to-haves" there are to lay out.
Like, a single integer index, with lower and upper bounds, <em>plus</em> a predicate, seems sensible.</p>
<p>Then I read a little further, and remember some things that make it not clear to me how things should proceed.
Like, working in Python-style pseudocode because I don't want to look stuff up, suppose we have <tt class="docutils literal">Sigma(a, p)</tt>, and I want to change it to <tt class="docutils literal">Sigma(lambda k: a(k + 1), lambda k: p(k + 1))</tt>...
That looks vaguely reasonable, although for the actual code I'll probably want something like a shift operator for this specific case?</p>
<p>The sense I'm getting is that this should be a "sandwich" type of thing, where the "boundaries" prefer simple delimited summation to delimited summation with a predicate, to summation with a predicate or iset or something.</p>
<p>Now, the chapter is discussing Iverson brackets, which I want to represent as a function from <tt class="docutils literal">bool</tt> to a function from <tt class="docutils literal">real</tt> to <tt class="docutils literal">real</tt>.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">A tape player?</p>
</div>
<p>Moving right along, I suppose the second function there would ideally have a default value of <tt class="docutils literal">1.0</tt>.</p>
<p>Although, maybe it's not a function, because we see also the possibility of "summation with no explicit predicates, but a bunch of Iverson brackets in the summand".
How all of <em>that</em> gets represented depends on how much Dafny can "look inside" functions to pull stuff out.
I'll have to experiment with that later.
For now, let's assume it can, and try to contrive a situation where it's obvious if that's wrong.</p>
<p>Anyway, I got distracted and it's late.
Better get to bed.</p>
<p>Good night.</p>
Coding 2024-01-182024-01-18T05:00:00-05:002024-01-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-18:/coding-2024-01-18<p class="first last">If I can't figure out how to do this one thing in Dafny, I'll have to switch to some other system where I can.</p>
<p>All right.
Skimmed to the end of the Sums chapter, and now it's time to look at it again, more carefully.</p>
<p>I'm currently sort of vacillating between "in Dafny, just go all in on doing arithmetic with <tt class="docutils literal">real</tt> values" (and hope there aren't precision issues when it comes to doing purely verification), and "okay, but the chapter mentioned complex numbers, so I should really try to define traits to support algebras" (I have no experience writing traits in Dafny).</p>
<p>The reasonable course of action is to see how far I can get with "a data type that includes integral bounds, optional predicates, and a function from integers to reals".
It's been really easy for me to get caught up in thinking about stuff like "Oh, this operator is basically a predicate followed by <tt class="docutils literal">and</tt> in Python", and lose sight of the fact that it's just as important, if not moreso, to have tools for <em>manipulating</em> these forms, and not just <em>evaluating</em> them.</p>
<p>It's way too late to mess around with code right now, but here's the main question I think I'd like to address:</p>
<p>Given some format for expressing an infinite sum, is it possible to express the predicate "this sum converges absolutely"?
Furthermore, can I properly express the <em>implications</em> of that for reasoning?
If I can't figure out how to do that, then it's probably not worth trying to manipulate the sums programmatically.</p>
<p>We'll see where I get with that in a few days, hopefully.
For now, it's later than I meant to be writing this.</p>
<p>Good night.</p>
Coding 2024-01-172024-01-17T05:00:00-05:002024-01-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-17:/coding-2024-01-17<p class="first last">I don't remember reading this chapter before, which is kind of weird.</p>
<p>I'm reading up on sums right now, and putting together plans for stuff to represent them in Python and Dafny.
It's pretty straightforward to write Python code to evaluate concrete examples, but there are some wrinkles when it comes to writing stuff up in Dafny.</p>
<p>Stuff like:</p>
<ul class="simple">
<li>I don't know whether Dafny has a rational datatype</li>
<li>A very very very quick skim of the Dafny documentation didn't reveal a way to define new semantics for existing operators... (And a slightly less quick skim indicates that this is explicitly not a thing you can do in Dafny.)</li>
<li>So an equivalent of sigma notation that may involve rational functions of the index values would seem to require some kind of usage of "traits".</li>
<li>Maybe it would make sense to write something that works in the integer domain to start with, and get some idea of the kinds of operations that I end up using?</li>
</ul>
<p>Anyway, I'll hopefully finish skimming this chapter soon, and then go back to the beginning and read it more carefully.
It's sort of interesting how trying to take an "implementation" perspective causes me to notice things that the text doesn't focus on.
Like, if you're working with numbers mentally, going from the integers to the rationals is often not that big a deal (unless you're doing something with raising things to the powers of natural numbers, and that's the bit that gets changed).
In software, that can be scary.</p>
<p>Anyway, I don't want to stay up any longer, so I'm going to wrap things up abruptly.</p>
<p>Good night.</p>
Weekly Roundup 2024-01-162024-01-16T05:00:00-05:002024-01-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-16:/weekly-roundup-2024-01-16<p class="first last">Good job with Dafny, bad luck with time management.</p>
<ul class="simple">
<li>Wednesday: I didn't have a good time going back into work.</li>
<li>Thursday: I tried using marimo and Dafny to verify stuff related to <em>Concrete Mathematics</em>. It didn't go great to start with.</li>
<li>Friday: I got Dafny working much better.</li>
<li>Saturday: Too much work. (Remember that I date these the day after I write them...)</li>
<li>Sunday: I ran into some issues with Dafny; I basically had to declare a helper function "closed form" by fiat, even though it's not, I don't think.</li>
<li>Monday: I took a look at the harder problems from <em>Concrete Mathematics</em>, and decided, you know what, I don't <em>need</em> to do those right now.</li>
</ul>
<p>Next week, I'm going to keep up with that, try to work on lore for my wife's writing, maybe get back to my own writing, and maybe get a better handle on audio editing because I have some weird ideas to get out.</p>
Coding 2024-01-152024-01-15T05:00:00-05:002024-01-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-15:/coding-2024-01-15<p class="first last">No actual coding today, but I didn't want to put this entry out of context.</p>
<p>Hm.
I'm about to the first set of exam questions in <em>Concrete Mathematics</em>, and, hm.
Wow.
I'm going to have the smiley do a dramatic reenactment of what probably <em>would have</em> happened if I'd ever gotten questions like these on an exam.</p>
<div class="admonition smiley smiley-glitchier">
<p class="first admonition-title">:) (glitchier)</p>
<p>What?</p>
<p>What‽</p>
<p>Breathing too quickly...</p>
<p class="last">World... going faint.</p>
</div>
<p>I hadn't realized how poorly that would translate from my thoughts to text, but oh well.</p>
<p>Looking over the other problems, these are all pretty intimidating.
Maybe I should move along for now...</p>
<p>In any case, it's late and I should get to bed.</p>
<p>Good night.</p>
Coding 2024-01-142024-01-14T05:00:00-05:002024-01-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-14:/coding-2024-01-14<p class="first last">It's going to be really jarring when I'm not just checking the book's work for going from recurrence relations to closed forms.</p>
<p>Hm.
I'm a little further along representing the Josephus problem in marimo and Dafny, but I'm not sure that what I have really constitutes a closed form.</p>
<p>I didn't figure out a way to use the standard library for this, so instead I ended up writing a helper that zeroes out the lower digits.
If I can figure out a faster version of that, then I'll be happy, but I think for now I'll move on.</p>
<p>Also, I continue to thank Dafny for just how much math it seems to be able to do.</p>
<p>In any case, I think I managed to read the text closely enough to move onto generalizing it some.
Let's see how that goes.</p>
<p>...</p>
<p>Hm.</p>
<p>I'm at the end of the section, and I haven't got code for this last example.
Actually representing it looks like a bit much.
I need to have <tt class="docutils literal">d</tt> values of beta and <tt class="docutils literal">d - 1</tt> values of alpha, along with a value for <tt class="docutils literal">c</tt>.</p>
<p>Whatever, I'll figure that part out later.
For the moment, I can take a look at the exercises, and go "oh, past me did most of these, so there's really not much to be done here".</p>
<p>But <em>really</em> for the moment, I should get to bed.</p>
<p>Good night.</p>
Diary 2024-01-132024-01-13T05:00:00-05:002024-01-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-13:/diary-2024-01-13<p class="first last">Don't want to go through that again.</p>
<p>Good news: new toy arrived in the mail today.</p>
<p>Bad news: epically long day at work today, so I ended up too exhausted to set it up.
I'll have to do it in the morning.</p>
<p>Nothing else worth talking about; work was <em>massive</em>.</p>
<p>Good night.</p>
Coding 2024-01-122024-01-12T05:00:00-05:002024-01-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-12:/coding-2024-01-12<p class="first last">Let's see how well the Mystery Code I installed to get this post to render works.</p>
<p>Things are going... very well with Dafny.
I've got a general form that I'm doing, and I don't know whether it's idiomatic, but it seems to work for my purposes.</p>
<p>Basically, I define the recurrence relation I'm trying to solve stuff for as a function, define another function for the closed form if applicable, define a lemma that just handles the recursive case because the base case has been trivial every time so far, and write a method that is required to satisfy the recurrence relation, but is implemented by invoking the closed form, and passing the result to the lemma.</p>
<p>That was all pretty abstract.
Let's try to make things a bit more concrete.</p>
<p>..smiley:</p>
<pre class="literal-block">
Heyo!
</pre>
<p>... Suppose we want to verify a closed form equation for the number of regions we can divide the plane into, given <tt class="docutils literal">n</tt> straight lines.
To start with, we need the recurrence relation, and the method that implements equivalent semantics:</p>
<div class="highlight"><pre><span></span><span class="kd">function</span> <span class="nf">regions_from_lines</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="kt">int</span><span class="p">):</span> <span class="kt">int</span>
<span class="k">requires</span> <span class="mi">0</span> <span class="o"><=</span> <span class="n">n</span>
<span class="p">{</span>
<span class="k">if</span> <span class="n">n</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">then</span> <span class="mi">1</span>
<span class="k">else</span> <span class="n">regions_from_lines</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">n</span>
<span class="p">}</span>
<span class="kd">method</span> <span class="nf">RegionsFromLines</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="kt">int</span><span class="p">)</span> <span class="k">returns</span> <span class="p">(</span><span class="n">regions</span><span class="p">:</span> <span class="kt">int</span><span class="p">)</span>
<span class="k">requires</span> <span class="mi">0</span> <span class="o"><=</span> <span class="n">n</span>
<span class="k">ensures</span> <span class="n">regions</span> <span class="o">==</span> <span class="n">regions_from_lines</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">}</span>
</pre></div>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Should you be using <tt class="docutils literal">nat</tt>?</p>
</div>
<p>I don't know, maybe?
Probably?</p>
<p>Anyway, I'm conceptualizing this as the general template that I'm going to try to fit stuff into.
Obviously, it doesn't currently verify, because I didn't write the code.
Let's go through all of the steps, including the intermediate bits.</p>
<div class="highlight"><pre><span></span><span class="kd">function</span> <span class="nf">regions_from_lines</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="kt">nat</span><span class="p">):</span> <span class="kt">nat</span>
<span class="p">{</span>
<span class="k">if</span> <span class="n">n</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">then</span> <span class="mi">1</span>
<span class="k">else</span> <span class="n">regions_from_lines</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">n</span>
<span class="p">}</span>
<span class="kd">method</span> <span class="nf">RegionsFromLines</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="kt">nat</span><span class="p">)</span> <span class="k">returns</span> <span class="p">(</span><span class="n">regions</span><span class="p">:</span> <span class="kt">nat</span><span class="p">)</span>
<span class="k">ensures</span> <span class="n">regions</span> <span class="o">==</span> <span class="n">regions_from_lines</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">regions</span> <span class="o">:=</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">n</span> <span class="o">*</span> <span class="p">(</span><span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<p>Technically, I could do a return statement here, but I'm going to stick the lemma afterwards, so this is easier to write later.
Now, this, of course, does not verify, because Dafny isn't going to proactively try to validate the Mystery Formulas I give it.
The next step, then, is to create an inductive lemma that validates the relationship between the recurrence relation and the Mystery Formula.
Because this lemma will involve the Mystery Formula in its <tt class="docutils literal">requires</tt> line, I'll define it as a function so I don't have to get it exactly in sync with itself:</p>
<div class="highlight"><pre><span></span><span class="kd">function</span> <span class="nf">regions_from_lines</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="kt">nat</span><span class="p">):</span> <span class="kt">nat</span>
<span class="p">{</span>
<span class="k">if</span> <span class="n">n</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">then</span> <span class="mi">1</span>
<span class="k">else</span> <span class="n">regions_from_lines</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">n</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nf">closed_form</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="kt">int</span><span class="p">):</span> <span class="kt">int</span>
<span class="p">{</span>
<span class="mi">1</span> <span class="o">+</span> <span class="n">n</span> <span class="o">*</span> <span class="p">(</span><span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span>
<span class="p">}</span>
<span class="kd">lemma</span> <span class="nf">RegionInduction</span><span class="p">(</span><span class="n">lines</span><span class="p">:</span> <span class="kt">nat</span><span class="p">,</span> <span class="n">regions</span><span class="p">:</span> <span class="kt">int</span><span class="p">)</span>
<span class="k">requires</span> <span class="n">regions</span> <span class="o">==</span> <span class="n">closed_form</span><span class="p">(</span><span class="n">lines</span><span class="p">)</span>
<span class="k">ensures</span> <span class="n">regions</span> <span class="o">==</span> <span class="n">regions_from_lines</span><span class="p">(</span><span class="n">lines</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">}</span>
<span class="kd">method</span> <span class="nf">RegionsFromLines</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="kt">nat</span><span class="p">)</span> <span class="k">returns</span> <span class="p">(</span><span class="n">regions</span><span class="p">:</span> <span class="kt">nat</span><span class="p">)</span>
<span class="k">ensures</span> <span class="n">regions</span> <span class="o">==</span> <span class="n">regions_from_lines</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">regions</span> <span class="o">:=</span> <span class="n">closed_form</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
<span class="n">RegionInduction</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">regions</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
<p>This moves the verification failures from the method into the lemma.
At this point, I should probably emphasize that I haven't gotten any help or guidance from another person on this currently, so I could be putting together something that is excessively verbose, or inefficient, or just somehow hard to read.
Regardless, the next step is to fill in the lemma with enough information for Dafny to carry out an inductive argument.</p>
<div class="highlight"><pre><span></span><span class="kd">function</span> <span class="nf">regions_from_lines</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="kt">nat</span><span class="p">):</span> <span class="kt">nat</span>
<span class="p">{</span>
<span class="k">if</span> <span class="n">n</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">then</span> <span class="mi">1</span>
<span class="k">else</span> <span class="n">regions_from_lines</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">n</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nf">closed_form</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="kt">int</span><span class="p">):</span> <span class="kt">int</span>
<span class="p">{</span>
<span class="mi">1</span> <span class="o">+</span> <span class="n">n</span> <span class="o">*</span> <span class="p">(</span><span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span>
<span class="p">}</span>
<span class="kd">lemma</span> <span class="nf">RegionInduction</span><span class="p">(</span><span class="n">lines</span><span class="p">:</span> <span class="kt">nat</span><span class="p">,</span> <span class="n">regions</span><span class="p">:</span> <span class="kt">int</span><span class="p">)</span>
<span class="k">requires</span> <span class="n">regions</span> <span class="o">==</span> <span class="n">closed_form</span><span class="p">(</span><span class="n">lines</span><span class="p">)</span>
<span class="k">ensures</span> <span class="n">regions</span> <span class="o">==</span> <span class="n">regions_from_lines</span><span class="p">(</span><span class="n">lines</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="mi">1</span> <span class="o"><=</span> <span class="n">lines</span> <span class="p">{</span>
<span class="n">RegionInduction</span><span class="p">(</span><span class="n">lines</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">regions</span> <span class="o">-</span> <span class="n">lines</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">method</span> <span class="nf">RegionsFromLines</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="kt">nat</span><span class="p">)</span> <span class="k">returns</span> <span class="p">(</span><span class="n">regions</span><span class="p">:</span> <span class="kt">nat</span><span class="p">)</span>
<span class="k">ensures</span> <span class="n">regions</span> <span class="o">==</span> <span class="n">regions_from_lines</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">regions</span> <span class="o">:=</span> <span class="n">closed_form</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
<span class="n">RegionInduction</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">regions</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
<p>And, assuming I copied everything over correctly, we're done.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">This seems like cheating somehow.
You just ignored the base case, and the inductive step is just running the recurrence relation backwards?</p>
</div>
<p>It turns out that, once you've figured out which water to lead Dafny to, it <em>will</em> drink.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p>Even so, I feel like being skeptical.
All you've shown us is that some layouts of file verify, while others do not.
This could all be some kind of souped-up regular expression.</p>
<p class="last">"Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?"</p>
</div>
<p>Okay, let's see what happens if I sabotage the closed form.
Comment out the denominator, and...
Hm.
I'll have to see later if there's some way to make Dafny go into more detail, but it does catch the issue.</p>
<p>Anyway, with all that said and done, I've got some cleanup to do to the code(?) I've written, and then it's time to tackle the next section of the textbook.
Very carefully and deliberately.</p>
<p>For now, better wind down and rest.</p>
<p>Good night.</p>
Coding 2024-01-112024-01-11T05:00:00-05:002024-01-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-11:/coding-2024-01-11<p class="first last">Still a little rough around the edges...</p>
<p>I had this whole neat idea about doing exploratory coding in marimo, and then verifying ideas using Dafny, but my initial attempts in this area have so far gone... not great.</p>
<p>Marimo is fine so far, but when I gave Dafny a recurrence relation and closed form for the optimal number of moves for a tower of Hanoi puzzle, I expected it to either get something à la "Even a computer could discover this", or to quickly bail out because I gave it almost nothing to work with.
Instead it just... sat there, with no indication of what it was doing, or how long it would take.</p>
<p>Just checked, and it's at least possible for Dafny to successfully verify a file, so it's not <em>obviously</em> an issue that occurs every time.</p>
<p>After a little more poking, this does have something to do with the method specifically, but I'm, like, not sure what to do with that yet.
I'll have to think about it, I guess.</p>
<p>...</p>
<p>Hold up, I searched the issues for some key words, found stuff that eventually led me to the experimental <tt class="docutils literal"><span class="pre">--disable-nonlinear-arithmetic</span></tt> flag.
I pass it in, and...</p>
<p>Yay!
It fails!</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Yay?</p>
</div>
<p>I needed it to commit to a course of action.</p>
<p>So, given that verification is failing, I think I need to write a lemma, and have it work via induction?
I'll try to figure this out later.
For now, I want to sleep.</p>
<p>Good night.</p>
Diary 2024-01-102024-01-10T05:00:00-05:002024-01-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-10:/diary-2024-01-10<p class="first last">Maybe if I turn up the lights when I get home...</p>
<p>First day back in the office.
Uuuuuuuuuugh.</p>
<p>I've got a few things I want to try to look into, but it's pretty hard to work up the energy for that when the sun's down by the time I get home.
The main thing is trying to find a good mind-mapping tool, because I tried to map stuff out about my writing in a notebook, and the result was totally unreadable.
Another is getting back into Concrete Mathematics, and trying to work on the exercises in marimo.
Hopefully, I'll be able to transfer stuff there to calendars for worldbuilding, and balancing incremental games.</p>
<p>Anyway, I need to get ready for bed.</p>
<p>Good night.</p>
Weekly Roundup 2024-01-092024-01-09T05:00:00-05:002024-01-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-09:/weekly-roundup-2024-01-09<p class="first last">I am preparing to slack off <em>so much</em>, you guys.</p>
<ul class="simple">
<li>Wednesday: We got home, and I got a few small things done and started.</li>
<li>Thursday: I talked some about a project I've been working on in various forms for a while now.</li>
<li>Friday: I continued to work on that project.</li>
<li>Saturday: Nothing much happened, and this frustrated me.</li>
<li>Sunday: I got a few things done, and called that a win.</li>
<li>Monday: I got a bit more done, and then took it easy.</li>
</ul>
<p>Next week, I'm going to probably be messing around with writing projects, but we'll see.</p>
Diary 2024-01-082024-01-08T05:00:00-05:002024-01-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-08:/diary-2024-01-08<p class="first last">A good day, but nothing to write about.</p>
<p>I finished up with the list I put together for yesterday, and then took things easy.
I guess we'll have to see what starting work back up tomorrow feels like; probably really disorienting.</p>
<p>For the moment, I'm tired and having trouble writing, so oh well, cutting this short so I'm not obsessing over it all night.</p>
<p>Good night.</p>
Diary 2024-01-072024-01-07T05:00:00-05:002024-01-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-07:/diary-2024-01-07<p class="first last">Slightly more done than I committed to, hooray.</p>
<p>Well, that was an interesting mixed bag.
After the last entry, I put together a list of things I want to accomplish soon.
I got the stuff that I considered highest priority done, so I guess today was successful.
The rest of the list should be workable to take care of tomorrow morning, so I'll get that done when the time comes.</p>
<p>One of those things was finally reading the stuff I wrote to my wife.
Got some positive feedback there.
I'd like to write some more, but my current feeling is that I should try to take all of the names and people I made up, and figure out how they fit together.
Stuff in the text and explicit speculation only; not going to write lore.</p>
<p>Anyway, I let things get late, which is part of the reason I didn't do the lower-priority stuff while I was putting this entry together.
It'll all be fine.</p>
<p>Good night.</p>
Diary 2024-01-062024-01-06T05:00:00-05:002024-01-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-06:/diary-2024-01-06<p class="first last">This is frustrating. Don't look.</p>
<p>Every day since we got back, I've thought "Well, I'll get a bunch done today." and it hasn't happened yet.</p>
<p>So, fine, I'm going to lower my expectations and/or perform reverse psychology, and declare that I'm going to take things <em>super easy</em> tomorrow, and see how that works out!</p>
<p>Good night.</p>
Diary 2024-01-052024-01-05T05:00:00-05:002024-01-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-05:/diary-2024-01-05<p class="first last">It'd be really weird if this turned out to represent a consistent shift in pronunciation.</p>
<p>I didn't really have "momentum" today, but I did manage to do a trial read of the writing using YSK.
It's mostly fine, but one thing I wasn't expecting is that using these words that aren't part of standard English caused my pronunciation of the letter R to shift?
Like "These words aren't English, so I'd better pronounce things like some other language?" I guess...</p>
<p>I don't have anything else in mind to talk about, so I'm just going to post and wrap up.</p>
<p>Good night.</p>
Diary 2024-01-042024-01-04T05:00:00-05:002024-01-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-04:/diary-2024-01-04<p class="first last">In addition to the words I made up, I also had fun with "gravely misunderstood" and "rectify".</p>
<p>Seems like I'm not ramping back up in any impressive way.
I've got some writing that I'm revising.
That's not ready until I've read it out loud to check for issues with how it flows.
At least it's not metrical poetry, so I'm not going to be sounding it out and going "Well, formally, this fits the meter, but I can't actually pronounce it with that emphasis."</p>
<p>I might as well talk a little bit more about this project.
From an inspiration perspective, I've got some inspirations, and things that I think I should read for inspiration, that I think sound pretty impressive, and I suspect that the result will be... not.
I think it could speak to some people, but this kind of feels different from other projects, where a lot of the time I could imagine it getting a lot of traction and influence—</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">If it came out decades ago into a world where its own inspirations somehow didn't exist.</p>
</div>
<p>Yes, yes, that.</p>
<p>But the point is, this project, which I haven't properly named yet, feels like it has a much smaller ambition.
I don't want to talk too much about the content; I'd rather let it speak for itself when I'm comfortable releasing it.
However, I can talk about one of the reasons I'm putting effort into something that's intentionally "smaller".</p>
<p>This writing, and some other writing I've done in the previous year (some of it more on the ambitious side of the scale), is meant as a vehicle for... I guess I'll call it an experimental variant of English?
Swap out three or four basic word roots for, let's say three new roots, doing the work of six.</p>
<p>The point of all of this, the entire reason, the thing that, if you don't understand it, will render <em>everything I am doing here incomprehensible</em></p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Pay attention, this bit is important.</p>
</div>
<p>is that one of the major obstacles I've encountered in writing over the past few years is feeling slowed down by the fact that I have to commit to a character's gender identity if I want to use pronouns for them, <em>and be able to use multiple pronouns to be able to differentiate between them</em>.
I know this problem probably won't resonate with a lot of people, and I don't always have it, but I have it enough that I just wanted a break.</p>
<p>So, I devised what I'm calling the "YSK paradigm", named after the first letter of each of the roots for the new pronouns.
I don't feel like going into detail about spelling/pronunciation right now (there's a non-zero chance I'll end up revising the current version), but I'll lay out the basic idea:</p>
<ul class="simple">
<li>The "Y" pronouns indicate "this person or people"</li>
<li>The "S" pronouns indicate "that person or people"</li>
<li>The "K" pronouns indicate "that person or people over there"</li>
<li>There are singular and plural versions.</li>
</ul>
<p>Now, I've failed to explain this before, and in an attempt to anticipate that failure mode, I'd like to say, if one of the thoughts you have after reading the last few paragraphs is "If you're using these, it would help to have a table beforehand explaining which characters get which pronouns", then you have gravely misunderstood me, and if you wish to rectify that, you should reread from after the smiley box.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">"smiley box"?</p>
</div>
<p>Well, what's anyone <em>supposed</em> to call that thing ↑?</p>
<p>Anyway, maybe I'll have stuff using these put out publicly soon, maybe not.
We'll see.</p>
<p>For now, I once again need to get to bed.</p>
<p>Good night.</p>
Diary 2024-01-032024-01-03T05:00:00-05:002024-01-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-03:/diary-2024-01-03<p class="first last">About two weeks of not being in our usual bed. Eesh.</p>
<p>All right, we're back.
Time to relax a bit.</p>
<p>I found the color stuff I was looking for; it was <a class="reference external" href="https://reasonable.work/colors/">Reasonable Colors</a>.</p>
<p>Aside from working that stuff out, I didn't get too much done today.
I discussed some lore for a project my wife is working on.
We made some important progress there, but nothing that would look big if we pointed at it, if that makes sense.</p>
<p>And now it's late, and I'd like to get things wrapped up in the next few minutes.</p>
<p>Good night.</p>
Weekly Roundup 2024-01-022024-01-02T05:00:00-05:002024-01-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-02:/weekly-roundup-2024-01-02<p class="first last">Post-holiday rundown</p>
<ul class="simple">
<li>Wednesday: I made some progress with MOTR, at least in terms of planning changes.</li>
<li>Thursday: I executed the plans, and ran into issues, which I eventually fixed.</li>
<li>Friday: I got to a point with MOTR where I need a break; I <em>may</em> have some plans to look into later.</li>
<li>Saturday: I took things easy.</li>
<li>Sunday: I complained about Vue.js. Oh well.</li>
<li>Monday: I explained what I was looking into Vue.js for, and how I'm looking into restricted color palettes.</li>
</ul>
<p>Next week, we're heading back home, then I'll work more on writing or something.</p>
Diary 2024-01-012024-01-01T05:00:00-05:002024-01-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2024-01-01:/diary-2024-01-01<p class="first last">I have googled so many things with no luck...</p>
<p>Okay, let's see.
It's kind of late now, but we'll probably be up for a while longer.
Thinking about the stuff I was talking around yesterday.</p>
<p>I've got a few ideas for incremental games that I want to mess with, and I think that <a class="reference external" href="https://github.com/Acamaeda/The-Modding-Tree">The Modding Tree</a> would be a good fit for them in terms of functionality, but.
The visuals make my head hurt.
Too much contrast, too small text.
Sometimes far too little contrast.
From a layout perspective, things <em>can</em> get really janky.</p>
<p>So, I want to try to rethink a lot of the visual language, and part of that is restricting the color scheme so that there's more "accent colors" and less "the color of this layer is an animated gif".
I'm thinking of doing this based on <a class="reference external" href="https://github.com/jan-warchol/selenized">Selenized</a>, but I was also thinking about trying to use a color palette that I'm having trouble finding, and it's bothering me...</p>
<p>We'll see if I ever remember, but for now, I want to shut things down now.</p>
<p>Good night.</p>
Diary 2023-12-312023-12-31T05:00:00-05:002023-12-31T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-31:/diary-2023-12-31<p class="first last">I feel like it shouldn't be allowed for "When does this variable end up pointing to an object that has these fields?" to be so hard for me to answer.</p>
<p>I could have made this into a coding entry, but I didn't.
The main thing worth talking about that I did today was to take a VueJS 2 project that I'm passingly familiar with, and try to create a fork using VueJS 3.
I very, very quickly ended up out of my depth, and decided, you know what, I'm going to focus on the other things I want out of this project.</p>
<p>(The problem I ran into was how to convert <tt class="docutils literal">set</tt> and <tt class="docutils literal">delete</tt> calls into uses of proxy objects, when I was having trouble tracking down which code actually populates the values that need to be replaced with proxies.
If someone can point me (on Mastodon or Cohost or whatever) to a resource that explains how to deal with this in an unfamiliar codebase, I think that's all I'd actually need to attempt the update again.
No advanced libraries or anything complicating the migration.)</p>
<p>Anyway, the more significant thing I wanted to work on with this was a comprehensive overhaul of the visual language, because it's kind of a bad sign, I think, when I have to squint at small numbers on weird contrast backgrounds that give me crazy afterimages.</p>
<p>I'll try and explain what I'm on about later; I want to wrap things up right now.</p>
<p>Good night.</p>
Diary 2023-12-302023-12-30T05:00:00-05:002023-12-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-30:/diary-2023-12-30<p class="first last">Just kind of did whatever.</p>
<p>Hm.
Not too organized today.
The most significant thing I did was some research for a project I may write up here, we'll see.</p>
<p>Aside from that, I'm futzing around with games to maybe play.
Maybe later, I'll play them, and maybe I'll write something about them.
We'll see.
Maybe that'll wait until I have access to a controller again.</p>
<p>I think I must be just recovering from some of the issues I ran into trying to update MOTR.
We'll see what I'm up for doing in the next few days.</p>
<p>For now, I really should get to bed.</p>
<p>Good night.</p>
Coding 2023-12-292023-12-29T05:00:00-05:002023-12-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-29:/coding-2023-12-29<p class="first last">"Ooh, nameless things, how spooky..." They're really confusing and frustrating, is what they are.</p>
<p>Okay.
Okay.
Okay.</p>
<p>I've finished up the current round of code reorganization, and this has successfully excised that one branch I didn't want to write tests for.
Good.</p>
<p>Unfortunately, this has left the code in a state of... chaos would be a strong word.
Basically, I've been isolating the code into logical units based on how different pieces of data relate to each other, and I've basically ended up with more of these logical units than I have concepts.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Believe it.
One of the new classes is literally just named <tt class="docutils literal">Foo</tt>.</p>
</div>
<p>So, obviously, I would like to address that.
But I've got plenty of experience from while I was doing the recent rewrites, of <em>trying to do just that</em>, and bouncing off.
Now, <em>hopefully</em> this will be easier following the rewrites, but I think for sure I need to take a break and look at this with fresh eyes.</p>
<p>I've also got some out-there ideas that might not work, which could simplify things a little, potentially.
(Initial simplified tests indicate that it could help.
The idea is to try to cut down on the absurd proliferation of type variables, by, um, creating more type variables.)
Here's the playground code I wrote so I hopefully remember what I was thinking of doing:</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Generic</span><span class="p">,</span> <span class="n">TypeVar</span>
<span class="n">L</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"L"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">list</span><span class="p">[</span><span class="n">Any</span><span class="p">])</span>
<span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T"</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Hello</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">L</span><span class="p">]):</span>
<span class="k">def</span> <span class="nf">fst</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">Hello</span><span class="p">[</span><span class="nb">list</span><span class="p">[</span><span class="n">T</span><span class="p">]])</span> <span class="o">-></span> <span class="n">T</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
</pre></div>
<p>Anyway.
I can try to get into other coding projects, or I can get back to some writing that I kind of left myself hanging on.
We'll see.</p>
<p>For now, though, it's not worth trying to do any more tonight.</p>
<p>Good night.</p>
Coding 2023-12-282023-12-28T05:00:00-05:002023-12-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-28:/coding-2023-12-28<p class="first last">Trust nobody, not even yourself.</p>
<p>Oh boy.
I've gotten so close to getting this stuff working, I just need to figure out what I did to make Mypy unhappy with the code related to —
Aw man, I figured it out, that was awful.</p>
<p>See, I've got <tt class="docutils literal">GenericRunner</tt>, which has specializations to <tt class="docutils literal">Runner</tt> and <tt class="docutils literal">ModuleRunner</tt>, and doing that was perhaps not the best idea, because of stuff like "accidentally passing an unbound method reference scoped to <tt class="docutils literal">Runner</tt> instead of <tt class="docutils literal">GenericRunner</tt>".
Ugh, oh well.</p>
<p>With that bit of insight obtained, I've gotten Mypy to accept the required upstream changes, and gotten the tests to pass.
Once I have the many flake8 issues that I have doubtless introduced addressed, I can finally make the changes I intended to make in the <tt class="docutils literal">GenericRunner</tt> class itself, and see how that shakes out.
Once those are in, it's one more round of renames, and then I can merge this to the coverage topic, then have a completely awful merge up to the future topic.</p>
<p>Wish me luck...</p>
<p>Anyway, that's all happening later.
Right now I'm going to get to bed so I'm not up super-late again.</p>
<p>Good night.</p>
Coding 2023-12-272023-12-27T05:00:00-05:002023-12-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-27:/coding-2023-12-27<p class="first last">I confused myself several times working this out.</p>
<p>Hoo boy...
I just roughed out the Protocol for handling the different behavior needed for <tt class="docutils literal">ParametricCommand</tt> stuff, and keeping straight what it does is going to be a nightmare.
I'll try to run through it quick before I get ready for bed.
Basically, there's one method that takes a <tt class="docutils literal">Matrix</tt>, and <em>may</em> modify it.</p>
<ul class="simple">
<li>If the method is called on the newtype-style wrapper, it must pass back its argument, unchanged.</li>
<li>If the method is called, specifically on a <tt class="docutils literal">ParametricCommand[Module, _program.T, _installer.T, _runner.T]</tt>, it must accept a <tt class="docutils literal">Matrix[ModuleRunner[_entry.T, Any, _installer.T]</tt>, and return a <tt class="docutils literal">Matrix[GenericRunner[_entry.T, _program.T, _installer.T, _runner.T]]</tt>.</li>
</ul>
<p>Strictly speaking, it probably doesn't have to be quite so detailed with the types, but every <tt class="docutils literal">Any</tt> makes it harder to think about.
Either way, I'll see if I'm up for implementing all this tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2023-12-262023-12-26T05:00:00-05:002023-12-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-26:/weekly-roundup-2023-12-26<p class="first last">A hectic week.</p>
<ul class="simple">
<li>Wednesday: Bad time management.</li>
<li>Thursday: I messed around with a few things, but nothing in enough detail to write about.</li>
<li>Friday: I started tinkering with MOTR again.</li>
<li>Saturday: Bad time management.</li>
<li>Sunday: Decent time management, but due to factors, I still didn't have anything to write about.</li>
<li>Monday: I got some insight into changes I'm going to want to make to MOTR.</li>
</ul>
<p>Next week, I'm going to try to get stuff done, now that we're not rushing around.</p>
Coding 2023-12-252023-12-25T05:00:00-05:002023-12-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-25:/coding-2023-12-25<p class="first last">Ah, back to <em>extremely</em> inside baseball.</p>
<p>Okay.
So.
I'm in the middle of some kind of big weird rewrite regarding what used to be <tt class="docutils literal">CommandBuilder</tt> and is currently <tt class="docutils literal">Runner</tt>, because that name's not <em>great</em>, but it's <em>better</em>.</p>
<p>The actually important change is that I added a parameter to <tt class="docutils literal">Runner</tt> to replace one of its <tt class="docutils literal">Optional</tt> fields.
The upshot of doing that <em>locally</em> is that I get to delete a conditional branch that was <em>really bothering me</em>.
However, actually going through with this change incurs a lot of costs, and I figured I'd try to pay those costs before getting too attached to the benefits.
Currently, I'm squirreled up in the <tt class="docutils literal">parametric_command</tt> code.</p>
<p>Let's quick lay out what's going on there, because if I just try to touch the code without planning, I'll probably mess it up.
So, there are two axes of variation I care about.
They're on the <tt class="docutils literal">ParametricCommand</tt> class, which has two fields: a <tt class="docutils literal"><span class="pre">ParametricCommandMeta[...]</span></tt>, and a <tt class="docutils literal"><span class="pre">ParametricCommand[...]</span> | <span class="pre">SelectionDirectory[...]</span></tt>.</p>
<p>Now that the <tt class="docutils literal">ParametricCommandMeta</tt> class has a <tt class="docutils literal">_runner.T</tt> parameter, it's necessary to look at how the actions there interact with the union members.
The answer is, that if <tt class="docutils literal">_runner.T</tt> is <tt class="docutils literal">None</tt>, then the union can't be a <tt class="docutils literal"><span class="pre">ParametricCommand[...]</span></tt>, because that branch of the union represents something being run as a module.</p>
<p>Now, the interesting question is whether the opposite case should also be disallowed.
I'm going to go with a firm maybe: I should go with whatever makes the implementation easier.</p>
<p>And speaking of the implementation, if I'm going to change this union into something that keys off of the <tt class="docutils literal">_runner.T</tt>, I'm going to need to write a parametric protocol to handle that, and to make that work, I'm going to need to write a wrapper class for the <tt class="docutils literal">SelectionDirectory</tt>.
Then, if I've got a protocol <em>anyway</em>, I might as well leverage it by rewriting all of the <tt class="docutils literal">ParametricCommand</tt> methods that currently dispatch on the union branch into protocol methods.</p>
<p>Key note for my future self: because the wrapper class is going to basically be the newtype pattern, I don't need to explicitly expose the class to the rest of the code; I can just apply it in the <tt class="docutils literal">with_directory()</tt> function, keeping the calling interface the same.</p>
<p>I think that covers everything I was thinking about.
I'd try to do it now, but, as usual when I'm writing these, it's late.</p>
<p>Good night.</p>
Diary 2023-12-242023-12-24T05:00:00-05:002023-12-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-24:/diary-2023-12-24<p class="first last">Sort of meant to be back somewhat sooner, but oh well.</p>
<p>As anticipated, there was a bunch of travel today that kind of got in the way of having much to write about.
I have made some minor progress on a few things, but nothing yet worth discussing.</p>
<p>The travel led to a good time, but being on the road for so long, it's hard to deal with it.</p>
<p>I'm not thinking too clearly, so I'm going to try to get ready for bed soon.</p>
<p>Good night.</p>
Diary 2023-12-232023-12-23T05:00:00-05:002023-12-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-23:/diary-2023-12-23<p class="first last">Maybe I need to stop playing The Modding Tree games...</p>
<p>I ended up not having much today to write about.
I'm going to be on the road a bunch tomorrow, so I'm not going to have much tomorrow, either.
These next few days are going to have a lot going on, so now I'm thinking about, once I'm through all of that, I'm going to need to figure out how to actually get stuff done.</p>
<p>I'm done for now.</p>
<p>Good night.</p>
Coding 2023-12-222023-12-22T05:00:00-05:002023-12-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-22:/coding-2023-12-22<p class="first last">I remember seeing someone advocate for every product type having just two members. Kind of moving in that direction...</p>
<p>I did a few things today, but one of them was picking MOTR back up from where I left off.
This basically boiled down to fixing all of the Mypy and other errors caused by removing a single default value.</p>
<p>If I remember what I was thinking when I took a break, the next step is to consolidate the field that I changed with the one after it, into yet another new data class.
Then I can add a new type parameter to the class that <em>still</em> needs to be renamed, and then I get to fix a new set of Mypy errors.
I remain hopeful that this will all resolve into an improved layout and data flow, but it is hard to deny that the process of getting to wherever the endpoint is, kind of looks like someone deconstructed all of a multi-course meal...</p>
<p>Anyway, I need to wrap things up and get to bed.</p>
<p>Good night.</p>
Diary 2023-12-212023-12-21T05:00:00-05:002023-12-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-21:/diary-2023-12-21<p class="first last">Yay, incremental progress.</p>
<p>So, I've got more time tonight, and I have <em>something</em> to write about this time.</p>
<p>I've been messing around with writing really short-form stuff in a vague ambiguously-fantasy setting.
I'm trying to draw from the early works of Lord Dunsany, from Invisible Cities, and from Tlön, Uqbar, Orbis Tertius.</p>
<p>I feel like this is kind of hemming in some of my worldbuilding-related excesses, because the "point" of the setting is to raise questions, more or less, so it doesn't <em>help</em> me any to try to "stockpile" answers.</p>
<p>There's another point to all of this writing, but I don't feel like I can explain it coherently right now.
I've tried to explain it to a few people in the past, and got frustrated when stuff that I thought was completely clear just got, like, glossed over.</p>
<p>But I shouln't focus on that right now, because the main thing I'm feeling right now is tired.</p>
<p>Good night.</p>
Diary 2023-12-202023-12-20T05:00:00-05:002023-12-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-20:/diary-2023-12-20<p class="first last">Oops.</p>
<p>It's late.</p>
<p>I did unimportant stuff for most of the day.</p>
<p>I have less than no time to write this, so I'm not going to.</p>
<p>Good night.</p>
Weekly Roundup 2023-12-192023-12-19T05:00:00-05:002023-12-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-19:/weekly-roundup-2023-12-19<p class="first last">A few time many "Whoops it's 11 PM"s this week...</p>
<ul class="simple">
<li>Wednesday: I didn't have much to say because I was distracted. Miscellaneous bits of work.</li>
<li>Thursday: I rewrote some code for representing playing cards. It had issues.</li>
<li>Friday: I found some things that marimo never claimed to be suited for, and definitely isn't.</li>
<li>Saturday: More progress on the card code, and then I decided to step away from it until I figure out what it's <em>for</em>.</li>
<li>Sunday: I made some minor progress writing.</li>
<li>Monday: Terrible time management.</li>
</ul>
<p>Next week, I'm going to hopefully get more on top of all of these projects.
We'll see.</p>
Diary 2023-12-182023-12-18T05:00:00-05:002023-12-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-18:/diary-2023-12-18<p class="first last">Time management my insufficiently beloved...</p>
<p>"Haha, why don't I play some silly browser games and oh no it is 11 PM."</p>
<p>Anyway, I also found some good inspiration stuff for my writing; I'll talk about that later.
For now, I need to salvage things by getting into bed as soon as I can.</p>
<p>Good night.</p>
Diary 2023-12-172023-12-17T05:00:00-05:002023-12-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-17:/diary-2023-12-17<p class="first last">I really should try to explain what I'm trying to do with this writing sometime...</p>
<p>I did some short-form writing that I think it helping me with the stuff I intend it to help with.
This stuff is all so short that I should probably try to figure out some way to turn it into poems, or better-structured "flash fiction".</p>
<p>I let things get late, and I don't have anything else to say on the matter, really.
Good night.</p>
<p>Good night.</p>
Coding 2023-12-162023-12-16T05:00:00-05:002023-12-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-16:/coding-2023-12-16<p class="first last">Trying to figure out what I actually want to do with this code...</p>
<p>The card code is shaping up a bit.
I <em>thought</em> I was going to change the "design" somewhat, but I ended up just improving the implementation of the existing interface.
I added some helpers and a new type, and then created a bunch more decks.</p>
<p>I think I should try to change gears from this for a while, but when I come back to it, I should <em>probably</em> try to figure out how to write pretty-printers for decks.</p>
<p>Anyway, I'm going to stop thinking about that, and try to focus on writing instead.
I've got some stuff I need to focus on, but some of the details there are flexible.
Anyway, I've been spacing out listening to utterly cursed song remixes for too long, so I'm just going to cut this off abruptly.</p>
<p>Good night.</p>
Coding 2023-12-152023-12-15T05:00:00-05:002023-12-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-15:/coding-2023-12-15<p class="first last">I'll have to look for other ways to do code sketching.</p>
<p>Okay, let's see...</p>
<p>I was looking into doing Tkinter prototyping in marimo.
I think I would not recommend this; I anticipated the obvious caveats, but there were some non-obvious issues, that I'm not sure what to think of.
(Basically, I wanted to put the <tt class="docutils literal">mainloop()</tt> calls in a UI callback so there's like, a "setup" phase, and then I can trigger the actual window stuff with a button.
This doesn't work, but I don't know why it doesn't and if it "should".)</p>
<p>Anyway, I messed around with the card code as well, and I'm stuck against, like, I need to take this rough prototype and then properly think through how it should all relate.
Even with some of my attempts to clean stuff up, it's still a bit of a mess.
I'm tired now, so I'm going to wrap up and try to figure out the design I should be aiming for.</p>
<p>Good night.</p>
Coding 2023-12-142023-12-14T05:00:00-05:002023-12-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-14:/coding-2023-12-14<p class="first last">Not sure what I want to <em>do</em> with this, but I <em>want</em> it. At least it didn't cost me much to write.</p>
<p>Oof, partied too hard today, in a way that was imperceptible at the time.
Let's see how much I'm up for.</p>
<p>I dusted off some of my old hobby code today, copying it from a Jupyter notebook into marimo.
Along the way, I made some changes.
See, the original version had a bunch of type-level <em>stuff</em> going on, and I ended up replacing what I was trying to do there with runtime validation.
This was <em>mostly</em> fine in my opinion, but I think I swung the pendulum <em>slightly</em> too far, and I need to find some way to recover the marker-y nonsense I had going on, to a limited extent.</p>
<p>Anyway, the code itself.
I can't explain <em>why</em>, but I wanted to have a minimal toolkit for expressing arbitrary decks of cards.
Currently, I've got code that can generate a normal 52-card deck plus any number of jokers, and both Japanese and Korean hanafuda/hwatu decks.
My <em>assumption</em> is that that's enough flexibility to handle most traditional decks; I'm not intending to handle anything that has a regular release schedule, for example.</p>
<p>So, what's left to do before I ponder trying to library-ize this code?</p>
<ul class="simple">
<li>Get some type-marker-y stuff in, and tighten up some annotations.</li>
<li>Figure out how to pretty-print card names, and generally how to write multimethods against them.
Right now, I'm using the default <tt class="docutils literal">attrs</tt> methods for printing, which are way too verbose for most purposes, but any replacement is going to need some form of contextual information that I'm not sure how to provide.</li>
</ul>
<p>Anyway, I'll think about that, and other things, and try to make it to the weekend.</p>
<p>Good night.</p>
Diary 2023-12-132023-12-13T05:00:00-05:002023-12-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-13:/diary-2023-12-13<p class="first last">Got distracted. I guess I'm unwinding or whatever.</p>
<p>I wasn't really organized enough to have a single post to write today.
I've been reading a bunch, and I should be done with that book soon.
In any case, I messed around with a few other things.</p>
<p>I made some further attempts at musical arrangement, and the result is... it sounds okay so far in aggregate, but it becomes much weaker when broken down to its basic components, which bothers me somewhat.</p>
<p>I also did some worldbuilding stuff, and I'm making some progress there.
The specific stuff I'm working on, I'm probably not going to pick back up, so I'll try to switch focus there to some projects that are more relevant to me.</p>
<p>For now, though, I really need to be getting to bed.</p>
<p>Good night.</p>
Weekly Roundup 2023-12-122023-12-12T05:00:00-05:002023-12-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-12:/weekly-roundup-2023-12-12<p class="first last">I'm not sure, but I think my efforts to get more dang sleep are paying off.</p>
<ul class="simple">
<li>Wednesday: I investigated the basic sounds of some common chord loops.</li>
<li>Thursday: I made a little more progress with that, but not much more.</li>
<li>Friday: I fiddled around with marimo, and had some weird ideas about stuff I could try to do with it.</li>
<li>Saturday: I wrote some very normal Python code. There is no need to look at the post to confirm this.</li>
<li>Sunday: Traveled out, didn't have much to say.</li>
<li>Monday: Traveled back, had slightly more to say, which still wasn't much.</li>
</ul>
<p>Next week, I've got a few things lined up.
I'm attempting to arrange some simple music for, um, nine parts...
And I've got some stuff ready to mess around with for some worldbuilding from months ago...
And I've got some other worldbuilding I'm trying to put together for some stuff my wife is working on.</p>
Diary 2023-12-112023-12-11T05:00:00-05:002023-12-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-11:/diary-2023-12-11<p class="first last">Oh also my laptop freaked out again this morning. Not happy about that...</p>
<p>Travel back.</p>
<p>I did research on a few things I was interested in, and I think I'm getting a better handle on them, but I don't feel like I have anything interesting to say about them yet.</p>
<p>One thing: as far as music goes, I'm going to try arranging existing pieces for combinations of instruments I'm interested in, and see if I learn anything from that.
As far as that goes, I feel like I just need to do some minor research and thinking to handle <em>most</em> of the instruments, but I don't know anything about arranging for percussion, so that's going to be a thing.</p>
<p>I do have some work I want to do on other things, but I don't know if I have the energy to talk about it now, so I'm not sure about doing it.
But, I'm spacing out right now, so I'd better wrap up.</p>
<p>Good night.</p>
Diary 2023-12-102023-12-10T05:00:00-05:002023-12-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-10:/diary-2023-12-10<p class="first last">Nothing interesting in this one.</p>
<p>More travel today.</p>
<p>I'm still pondering ways to push my usage of marimo, but I don't have anything to <em>show</em> for that yet.
Hopefully I'll have something there in a few days.</p>
<p>Aside from that, tonight was a lot, and I'll just hurt myself if I push really hard.
It's time to chill out.</p>
<p>Good night.</p>
Coding 2023-12-092023-12-09T05:00:00-05:002023-12-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-09:/coding-2023-12-09<p class="first last">Granted, the error was "Stop that, you can't do that"; I simply chose to ignore it.</p>
<p>Still doing stuff in marimo.
The bug I reported got fixed, which I'm glad about.
It <em>sounded</em> like it wouldn't be too hard to address, <em>given familiarity with the code</em>, and I think that's how it ended up.</p>
<p>...</p>
<p>Hm, yeah, looks very much like a "small change, but you have to know <em>which</em> small change".</p>
<p>Aside from that bug, I wrote some extremely normal code.</p>
<div class="admonition smiley smiley-glitchy">
<p class="first admonition-title">:) (glitchy)</p>
<p class="last">You have to show them. It's <em>hilarious</em>.</p>
</div>
<p>You know, there are languages where this functionality would be completely unremarkable.</p>
<div class="admonition smiley smiley-glitchy">
<p class="first admonition-title">:) (glitchy)</p>
<p class="last">I want you to make them imagine the calibre of Mypy plugin that would be required to make this even vaguely okay.</p>
</div>
<p>It only raised one error in the playground!</p>
<p>...</p>
<p>Fine.</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">GenericEnumType</span><span class="p">(</span><span class="n">enum</span><span class="o">.</span><span class="n">EnumType</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__getitem__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__getitem__</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">__class_getitem__</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
</pre></div>
<div class="admonition smiley smiley-glitchier">
<p class="first admonition-title">:) (glitchier)</p>
<p class="last">yes... ha ha ha... YES</p>
</div>
<p>I will say that I really do appreciate how marimo made it easier to prototype these Metaprogramming Crimes.
Just regenerating everything downstream when I want to quick try out another approach.
That would be a nightmare in a REPL or (to a somewhat lesser extent) in Jupyter.</p>
<p>Although, on that note, I'd kind of like to apologize to the marimo team for taking the capabilities they gave me, gave everyone, and doing... that.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Yeah, how do you sleep at night?</p>
</div>
<p><em>Soon</em>.</p>
<p>Good night.</p>
Coding 2023-12-082023-12-08T05:00:00-05:002023-12-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-08:/coding-2023-12-08<p class="first last">Not really sure where any of this will, or can, go, but whatever.</p>
<p>The inscrutable exhortations of my soul told me to transcribe mathematical functions from a book into a marimo notebook, so I guess that's what I did today.
I'm right now at a point where I need to decide how I want to represent some numbers; this is likely to result in a significant amount of thought for very little change in the behavior of the code, and I'm at peace with that.</p>
<p>I am, for reasons, not going to go into much more detail about this code, so let's see if anything else occurs to me...</p>
<p>Here's an idea that might be questionable: with the right design, an interactive fiction library compatible with Python could use marimo to do output validation similar to the "<a class="reference external" href="https://ganelson.github.io/inform-website/book/WI_1_7.html">Skein</a>" concept from Inform.</p>
<p>...</p>
<p>So, I just looked into interactive fiction in Python, and nothing leapt out at me as "this is well-suited for what I was thinking of".
I'll just let this idea stew for a bit, and focus on other things for the time being.</p>
<p>For the immediate future, though, oof, sleep.</p>
<p>Good night.</p>
Music Theory 2023-12-072023-12-07T05:00:00-05:002023-12-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-07:/music-theory-2023-12-07<p class="first last">If anyone wants to recommend me tutorials via Mastodon or whatever, that'd be cool.</p>
<p>Still messing around with basic stuff.
I think I need to get a little bolder with my melodies, since the stuff I had before was pretty much all stepwise motion.</p>
<p>There is a major obstacle to self-directed stuff here, and that is that my ability to judge how well something works seems to be hampered by a deep sense of satisfaction as a result of "hear one thing three times, then something else, then repeat from the beginning".
Maybe I can build that up somehow?</p>
<p>I'll have to think about it later, because it's once again really late and I'm tired.</p>
<p>Good night.</p>
Music Theory 2023-12-062023-12-06T05:00:00-05:002023-12-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-06:/music-theory-2023-12-06<p class="first last">This feels like it should be harder, so I'm pretty sure I'm missing something.</p>
<p>Wow, the last post in this category was a while ago.
Anyway, I started small with this whole "music" thing.
I came up with some rhythmic ideas I thought were interesting, put them over basic chord loops, found stable-enough scale degrees to put in the melody, and ended up with minimal cores of what could potentially become a song.
The thing I need to deal with is just how much heavy lifting the choice of chord loop seems to do:</p>
<ul class="simple">
<li><a class="reference external" href="https://en.wikipedia.org/wiki/Royal_road_progression">Royal Road progression</a> → sounds like it could be from some random OVA I saw ten years ago and forgot about.</li>
<li><a class="reference external" href="https://en.wikipedia.org/wiki/I%E2%80%93V%E2%80%93vi%E2%80%93IV_progression">The progression that's been common in pop music</a> → a pop song.</li>
<li>The same progression, but in minor key → a pop song, but it's sad now.</li>
</ul>
<p>It's kind of weird to think about how much saying "these chords in this order" seems to constrain what the song sounds like.
Like, does it end up with "choose the chords to set the tone, put the desired melody on top, and then just puzzle-game the voicing into place"?
Is that how this works?
I <em>must</em> be erasing some vital nuance here.</p>
<p>Anyway, I'll leave that to tomorrow, because it's late and I meant to already be in bed.</p>
<p>Good night.</p>
Weekly Roundup 2023-12-052023-12-05T05:00:00-05:002023-12-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-05:/weekly-roundup-2023-12-05<p class="first last">Mostly I just realized just how tired I've consistently been lately, and how I should do something about that.</p>
<ul class="simple">
<li>Wednesday: I came to a decision in MOTR that I didn't want to rush, so I'm going to be focusing on other things for the duration of this roundup. I thought about looking into some programming languages besides Python. (And then <em>mostly</em> didn't.)</li>
<li>Thursday: I dusted off one of my old projects, and immediately got confused by the Python standard library.</li>
<li>Friday: I figured out what was going on with the stuff I was confused by, but I was really tired, so, not much happened.</li>
<li>Saturday: Even more tired.</li>
<li>Sunday: I switched "projects to try working on in marimo" again.</li>
<li>Monday: A bit more marimo, including a very specific bug report. I resolved to back-burner the "algorithmic music" stuff I was aiming towards, in favor of getting more non-algorithmic experience.</li>
</ul>
<p>Next week, we'll see what I can manage there.</p>
Coding 2023-12-042023-12-04T05:00:00-05:002023-12-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-04:/coding-2023-12-04<p class="first last">The tags are... not really accurate, but whatever.</p>
<p>Okay, I've been poking at a few marimo notebooks today, (and filed another bug; don't worry about it), but I've ended up in a frame of mind again where I want to totally overdo the architecture of music-related stuff.
Maybe if I describe what I'm thinking about there, it'll alleviate the urges somewhat.</p>
<p>So, background.
Historically, the intervals between different notes were rational numbers with small-enough numerators and denominators; this <em>basically</em> equates to "sounding consonant".
Using rational numbers for this purpose has some good qualities, and some qualities that made it hard to compose certain kinds of music.
In the western musical tradition, this system was overtaken by one based on the twelfth root of two.
This greatly simplified composition and tuning, though it did result in some intervals sounding off.
However, they're <em>consistently</em> off, so that's good enough, especially now that people are used to them.</p>
<p>Now, that's all well and good if you're not a <em>huge nerd</em>, but I'm over here wondering about stuff like "But what would it sound like to use one of the old systems?"
(Yes, systems, plural.
There were varying ideas about "the right way" to choose rational intervals.)
"In the context of roots, what if we use a different root than twelfth, or a different base than two?"</p>
<p>There has already been a lot of investigation into this, and a bunch of existing software.
From a modeling perspective, it would be "nice" to be able to track intervals in terms of fractional powers of primes, but actually doing all of this is a bunch of effort that other people have figured out the right way to go to.</p>
<p>While I was writing that paragraph, I had a look at the <a class="reference external" href="https://en.xen.wiki/w/List_of_music_software">tools page on the Xenharmonic wiki</a>, and tried some of them out.
With what I've found in the course of a few minutes, here is what I've decided is the sensible thing to do:</p>
<ul class="simple">
<li>Focus on "traditional" (twelve equal divisions of the octave) stuff at first, in whatever tools feel good.</li>
<li>Figure out what it takes to replicate the basics of such compositions in a tool that supports xenharmonics.</li>
<li>Start tweaking things to make use of less traditional tunings.</li>
</ul>
<p>That's, like, effort and stuff, compared to trying to come up with weird algebraic representations that only need to work in theory, but it really would be better to focus on practical matters.</p>
<p>Later, because it's late now and I'm tired.</p>
<p>Good night.</p>
Coding 2023-12-032023-12-03T05:00:00-05:002023-12-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-03:/coding-2023-12-03<p class="first last">Trying to give myself enough rest that my expectations for myself become reasonable again.</p>
<p>I'm still messing with marimo for, I'm going to call it "sketching" with Python.
It's working out well for that.
I decided to change focus from [NOT VERY EXCITING SECRET] to <a class="reference external" href="https://pedrokroger.net/mfgan">Music for Geeks and Nerds</a>.
I'd previously messed with it, or possibly tried to reinvent things from first principles, but those efforts were plagued by overthinking.
I'm going to see what I can accomplish by just following along with the book, and "sketching" code rather than putting together elaborate scaffolding.</p>
<p>Anyway, if I'm honest with myself, I'm actually pretty tired, even if it's "early" by my usual standards, so I'm going to wrap things up and try to get a reasonable amount of rest.</p>
<p>Good night.</p>
Diary 2023-12-022023-12-02T05:00:00-05:002023-12-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-02:/diary-2023-12-02<p class="first last">I should stop <em>thinking</em> about napping, and nap...</p>
<p>I was pretty out of it today, so I'm not going to push myself.
This is in part (or maybe a lot) because (I'm pretty sure) I haven't been getting enough sleep lately, so, like, I should get to work on that.</p>
<p>First step on that: start moving towards bed earlier.
I'm already super tired, so, like, if I keep up, I'll be <em>really</em> unhappy.
Okay, that's enough justifying my decisions.</p>
<p>Good night.</p>
Coding 2023-12-012023-12-01T05:00:00-05:002023-12-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-12-01:/coding-2023-12-01<p class="first last">I should have figured out a way to cram in a nap.</p>
<p>I think I have a better understanding of the enum stuff from yesterday, and I can put things together more nicely, later.</p>
<p>All told though, my verdict on today is that I was pretty tired, and I managed to get some stuff planned out in spite of that.
I can potentially get some stuff done before tomorrow, but I'm not going to force myself.
I'll just see what I can manage while this entry publishes.</p>
<p>Good night.</p>
Coding 2023-11-302023-11-30T05:00:00-05:002023-11-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-30:/coding-2023-11-30<p class="first last">The question I had the smiley ask is actually not quite fair, but in my defense, this code is a maze.</p>
<p>I haven't really touched the languages I was talking about last time, but I have thought of something to attempt with them that should be more interesting than running through a couple of basic introductory exercises.
I have a book, which documents some code, which I wish to adapt for purposes outside of its original design.
I could try to work with the code in its original language, but I... don't want to.
So, let's try working with it in those languages.</p>
<p>My plan is to try to express things in a marimo notebook for prototyping, and then try to transplant that design to the other languages.
We'll see how that goes; when I was thinking about this earlier, I remembered running into Weird Problems because I was trying to customize Python's <tt class="docutils literal">enum</tt> support in a very specific way that must not have been expected.</p>
<p>...</p>
<p>I tracked down the problem I ran into, and now this is just going to bother me.
Basically, I was trying to make an <tt class="docutils literal">Enum</tt> where the <tt class="docutils literal">auto</tt> values start at 0 instead of 1, and the code has both:</p>
<ul class="simple">
<li>The way to do this that seemed elegant and obvious to me</li>
<li>and the viscerally disgusting hack that I used when the elegant and obvious option had no clear effect.
(Also included is light diagnostic code confirming the necessity of the hack.)</li>
</ul>
<p>...</p>
<p>Found it.</p>
<div class="highlight"><pre><span></span><span class="n">v</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_generate_next_value</span><span class="p">(</span>
<span class="n">key</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_member_names</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">_last_values</span><span class="p">[:],</span>
<span class="p">)</span>
</pre></div>
<div class="admonition smiley smiley-glitchy">
<p class="first admonition-title">:) (glitchy)</p>
<p class="last">Why does the staticmethod take an argument if it's always going to be a constant?</p>
</div>
<p>I'm not sure why the interface is like that, but now I hypothesize that the "hack" is almost the right version, and I should <em>remove</em> the "elegant fix", because it's subtly breaking one of the interfaces.
I'll see what I think tomorrow.</p>
<p>Good night.</p>
Coding 2023-11-292023-11-29T05:00:00-05:002023-11-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-29:/coding-2023-11-29<p class="first last">If there isn't a plan to change typing support for attrs the way I want, I'm not sure where the discussion should start.</p>
<p>My laptop hasn't done anything too objectionable since last time.</p>
<p><em>So far</em>.</p>
<p>Anyway, I poked a bit more at MOTR, and it's going well, but I need to make a decision.
There is an attribute that is currently optional, and I want to change the type from a union to a bound typevar.
This is incompatible (<a class="reference external" href="https://peps.python.org/pep-0696/">currently</a>? I'm not sure if this PEP would change that) with supplying a default value to attrs, so I need to make it a required argument, but it kind of sucks to make downstream stuff explicitly pass <tt class="docutils literal">None</tt>, so I'd like to have some alternative constructors, and then I need to work out what those should look like.
I'm somewhat leaning towards a minimal default constructor, and then "fluent" modification methods to open the type space back up, but this feels like something I need to think about, at least subconsciously.</p>
<p>So, I'm going to let that sit for a bit, and also ponder the other languages I'm considering looking at.
The initial field was pretty weird and uneven, but right now it's narrowed down to Rust, TypeScript via Deno, and Kotlin.
I'm not sure if the criteria I used were applied consistently or really make any sense, so please don't consider any of the choices I made or didn't make to be significant.</p>
<p>I'll have to look into doing something with them later.
For now, I'm going to wind down.</p>
<p>Good night.</p>
Weekly Roundup 2023-11-282023-11-28T05:00:00-05:002023-11-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-28:/weekly-roundup-2023-11-28<p class="first last">Surprising amount of work on MOTR for not intending to focus on it.</p>
<ul class="simple">
<li>Wednesday: I messed around a little with marimo, a Python project that wants to compete with Jupyter. I didn't do anything that really evaluated how well it competes, but I did find some minor rough edges, which eventually translated into a documentation update.</li>
<li>Thursday: I followed up on marimo, and then I got some messed-up behavior out of Mypy.</li>
<li>Friday: I fixed some Mypy issues by ignoring them. (And putting a bug URL in a comment.)</li>
<li>Saturday: More progress on MOTR.</li>
<li>Sunday: I kept on splitting up stuff in MOTR.</li>
<li>Monday: I continued on that, and things worked out well.</li>
</ul>
<p>Next week, I'm going to see how much further I can take that.
However, I finally put together some obvious conclusions about how to put together a tech stack for hobby stuff, so I've got research to do.</p>
Coding 2023-11-272023-11-27T05:00:00-05:002023-11-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-27:/coding-2023-11-27<p class="first last">Lightly poked the codebase, and it responded well.</p>
<p>We had more travel today, and some technical issues with the laptop.
However, I had time to start tweaking the class structure in MOTR, and it improved some code that I hadn't been thinking about, so that's a good sign.
I'll see how far I can chase this, and then <em>finally</em> look for something else to focus on.</p>
<p>I just now got ready for some of the changes that will end up potentially being much more complicated, but they promise to eliminate two lines of missed coverage, so I'm going to consider them worth it, because I really don't want to cover those lines.</p>
<p>Anyway, I need to wind down, and recover from stuff like the technical issues.</p>
<p>Good night.</p>
Coding 2023-11-262023-11-26T05:00:00-05:002023-11-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-26:/coding-2023-11-26<p class="first last">Three new okay names, but still haven't replaced the bad one...</p>
<p>All right, after messing with other stuff all day, I am taking a closer look at the increasingly-ineptly-named <tt class="docutils literal">CommandBuilder</tt> class, and I think I'm getting some ideas for how to go forward.
(No, for whatever reason, I am not tired of this.)</p>
<p>The <tt class="docutils literal">CommandBuilder</tt> has five fields, but the address a number of interlocking roles.
First up, there's <tt class="docutils literal">executable</tt> and <tt class="docutils literal">partial_invocation</tt>, which are processed together to produce an <tt class="docutils literal">InvocationEnvironment</tt>.
Then, <tt class="docutils literal">allowed_codes</tt> (which I recall is renamed in the future topic, but eh), <tt class="docutils literal">pass_module_codes</tt>, and <tt class="docutils literal">module_args</tt>.</p>
<p>There are a few things going on with those.
One is that <tt class="docutils literal">module_args</tt> is a <tt class="docutils literal">Union</tt>, but I want to turn it into a constrained type variable.
This would have some downstream effects that I haven't thought all the way through, but if I <em>can</em> put the distinction between "has module args" and "doesn't" into the type system, I want to.
However, looking at these fields with fresh eyes, I see that <tt class="docutils literal">pass_module_codes</tt> doesn't mean anything when <tt class="docutils literal">module_args</tt> is <tt class="docutils literal">None</tt>, so those fields should really be a single field that can contain a product type.
Furthermore, the purpose of <tt class="docutils literal">pass_module_codes</tt> is just to control the evolution of the <tt class="docutils literal">allowed_codes</tt> variable, so it should be bundled together as well.</p>
<p>This works out to: <tt class="docutils literal">ModuleInfo</tt>, <tt class="docutils literal">CodeInfo</tt>, <tt class="docutils literal">ExecutableAndInvocation</tt>, and...</p>
<p>And...</p>
<p>And...</p>
<div class="admonition smiley smiley-glitchier">
<p class="first admonition-title">:) (glitchier)</p>
<p class="last">Out with it.</p>
</div>
<p>I don't know!
Somehow, using "command" in some capacity still seems to make sense, because this is the first level where it's looping back around to the scope of information in the task class, which is called <tt class="docutils literal">Cmd</tt>.
But keeping it feels like a copout.
It's kind of like, these new names aren't great, they're fine, but not great, and bringing them together like this pushes them to the breaking point.</p>
<p>Well, I've thought about this for a long time now, and no luck.
Maybe I need to just actually try it, either tomorrow or in a few days.
For now, rest.</p>
<p>Good night.</p>
Coding 2023-11-252023-11-25T05:00:00-05:002023-11-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-25:/coding-2023-11-25<p class="first last">I didn't have time to properly describe anything I did.</p>
<p>Still tweaking MOTR and managing my time poorly.
With a little more messing around, I should have the renames propagated all the way up the layers, and get back to imlementing wrappers.
Sadly, even though I am making progress, it's slow going, and it looks likely I'll need a few more passes once I've got the module structure sorted out.</p>
<p>Regardless, it is way too late and I should get to bed.</p>
<p>Good night.</p>
Coding 2023-11-242023-11-24T05:00:00-05:002023-11-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-24:/coding-2023-11-24<p class="first last">Yet more incremental progress, some of it via just slapping a <tt class="docutils literal">type: ignore</tt> on.</p>
<p>Well, as far as marimo goes, we agreed on a documentation change rather than a code change; it's not onerous to get the right behavior once you understand what can make the behavior wrong, but the factors that can make the behavior wrong are subtle.
So, documentation.</p>
<p>Besides that, I cleared up some issues with MOTR.
At this point, I either get back to working on the names, or I find some other project to make progress on.</p>
<p>I would have liked to get more done today, but Thanksgiving is always pretty disruptive.</p>
<p>I'm (still? I forget) trying to figure out if there's some better way to accomplish what I want from MOTR.
The painful truth, though, is that I can't see how any of the alternatives could compete with the hacked-together motrfile that MOTR itself currently uses.
So, it's like, it's the best at delivering what I want, but still not good enough.</p>
<p>I've reviewed the state of the code, and the obvious place to work on is where I've been focusing already, so, eh...
I think I need to find something else to work on as a distraction, but we'll see how things go.
Later.
For now, I get to bed.</p>
<p>Good night.</p>
Coding 2023-11-232023-11-23T05:00:00-05:002023-11-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-23:/coding-2023-11-23<p class="first last">Mypy is punishing me for my hubris, for some reason.</p>
<p>Update on marimo: one of my concerns about it was unfounded, and another is intended to be worked on.
Here's the quick summary: <em>do not</em> use <tt class="docutils literal">from __future__ import annotations</tt>, because marimo code implicitly has it.
There are a few rough edges around this, but they're working on it.
I haven't tried using anything like Pydantic in this environment, and I'm not sure what would happen, so that's the main concern I'd have about usability.</p>
<p>I took another look at MOTR, and found some more issues I need to fix in the plugin, but then I ended up with some issues that confuse me, and I think I did something wrong outside of the plugin.
It's hard to describe what's really going on, besides "It's pretty weird", so I'm going to have to sleep on it.</p>
<p>I'm going to do some writing while this publishes.</p>
<p>Good night.</p>
Coding 2023-11-222023-11-22T05:00:00-05:002023-11-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-22:/coding-2023-11-22<p class="first last">This is not a great job of evaluating marimo, but I didn't hate it even though I was arguably kind of misusing it, so that's cool.</p>
<p>I ended up not focusing on much today.
Mainly, I messed around with some of the tech I was interested in messing with.
Specifically, <a class="reference external" href="https://marimo.io/">marimo</a>.</p>
<p>As I understand it, marimo is trying to be a replacement for Jupyter in terms of exploratory data processing and visualization.
That... was not what I used it for, so the overall experience was mostly illuminating in terms of "Boy, Python sure can be used in a lot of ways, and the resulting code can look very different."</p>
<p>To get a feel for marimo, I looked over some code I'd written as a Jupyter notebook that, to be clear, never needed to be a Jupyter notebook, so getting it into marimo was mostly not interesting, except for all of the typos that I found because the code was never actually run.</p>
<p>From the perspective of my own code, my main takeaways were that working with annotations felt not-great, and I'd have to look over the code to understand how some of this all works.
Like, looking at the generated Python file, I'm not sure how the code representing the cells gets dealt with as something to <em>actually run</em>.</p>
<p>Mostly, I've come away with a greater sense of how much the purpose or tooling can change the look of the code.
Like, I'd never write something that looks like a marimo notebook "by accident", and there are at least aspects of the Python that Dafny generates that <em>I</em> wouldn't think to write like.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">If you haven't taken a look at the Python code that Dafny generates, please understand that that was a self-directed burn that does not intend to disrespect the Dafny project.</p>
</div>
<p>Overall, I'm very interested in the "automatic literate programming" aspect of marimo, but I'm seeing some teething problems for <em>specific styles of code</em>.
If you're not using annotations, I doubt you'll hit any of the issues I did.
(Although it occurs to me now that I think some Python code may be outright syntactically invalid to put in a marimo notebook, like star imports.)</p>
<p>Sadly, I don't have anything to say about the <tt class="docutils literal">marimo</tt> module, because I... didn't try to use it.
This code was really not meant for notebooks, but having it in a weird interface helps to dull the itching sensation I get when Python code is neither a fully standalone script, nor a version control repository with a full test harness set up.</p>
<p>Potentially, there's some better tool out there for that specific use case.
"Make it easier to set up a repository with test harnesses" isn't it for me, because I am several years worth of rabbit hole into writing a task runner that accords with my sensibilities, and I haven't run across anything that obsoletes my work on MOTR.
So, my best hope is probably <em>something</em> in the notebook space, but I'm not sure what.
Maybe I just need to think more about what I'm trying to accomplish here...</p>
<p>Anyway, the one thing I'd really like to change so far about marimo is the tab completion bindings, but maybe that's just a matter of "it's not working how Kakoune works".
Aside from that, I'm interested in trying to use it the next time I need to do actual notebook stuff.</p>
<p>For now, I'm going to wind down.</p>
<p>Good night.</p>
Weekly Roundup 2023-11-212023-11-21T05:00:00-05:002023-11-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-21:/weekly-roundup-2023-11-21<p class="first last">Suddenly, I made progress.</p>
<ul class="simple">
<li>Wednesday: I filed a Mypy bug, in case the behavior in question is actually considered a bug; and tried to work around it in the meantime.</li>
<li>Thursday: I explained what the code involved is doing, why that requires a plugin, how the plugin is currently breaking, and how I'm trying to get insight into all of this.</li>
<li>Friday: I got a little distracted with some runtime and plugin improvements that are out of scope.</li>
<li>Saturday: I zoned out all day.</li>
<li>Sunday: I kept on considering stuff for the plugin that makes sense from the perspective of "generally usable library", but is out-of-scope for "I didn't want to keep on writing virtually the same wrapper code".</li>
<li>Monday: We traveled, and I didn't get much done.</li>
</ul>
<p>Next week, I'll figure out what I want to work on next, since I managed to update the plugin after the last entry, but that just exposed a non-plugin-related bug.
I'm thinking either back to music, some strange fanfiction I thought of, or trying to do planning work for some of the project ideas I have kicking around.</p>
Diary 2023-11-202023-11-20T05:00:00-05:002023-11-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-20:/diary-2023-11-20<p class="first last">On the road again...</p>
<p>We had travel today, but I did get to think some about the plugin for MOTR.</p>
<p>I just threw together a few more typing tests, and honestly they just raised more questions, like, was all of this code necessary in the first place?</p>
<p>Hopefully, I'll have answers in a few days.
For now, I should wrap up.</p>
<p>Good night.</p>
Coding 2023-11-192023-11-19T05:00:00-05:002023-11-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-19:/coding-2023-11-19<p class="first last">I'm not sure how many distinct configurations this adds up to...</p>
<p>Okay, so.
I ended up taking things easy today, but I did put together a list of things to investigate for the dependent mapping plugin in MOTR.
Basically, I need to consider:</p>
<ul class="simple">
<li>Which methods the plugin works with, and the types of their arguments</li>
<li>How the methods are to be invoked</li>
<li>Whether a given type is to be a single concrete type, or something more complex.</li>
</ul>
<p>There is a lot of <em>stuff</em> to be written to get all of this testable.
Some weird combinatorial explosion, considering that I'm working with parametric types that I then want to see working sensibly in unions and the like.</p>
<p>Anyway, it's late and I need to sleep a lot.</p>
<p>Good night.</p>
Diary 2023-11-182023-11-18T05:00:00-05:002023-11-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-18:/diary-2023-11-18<p class="first last">Time management fell off a cliff. Okay to skip this one.</p>
<p>I had no focus today, so there's nothing to write about, and I want to finish this up quickly.
I'll see what I manage to do tomorrow, but absolutely nothing else is getting done right now.</p>
<p>Good night.</p>
Coding 2023-11-172023-11-17T05:00:00-05:002023-11-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-17:/coding-2023-11-17<p class="first last">Figuring out a good developer experience for myself.</p>
<p>Well, I got distracted, but I do have a few notes.</p>
<ul class="simple">
<li>Currently, calling a method from the <tt class="docutils literal">DependentMapping</tt> protocol does not (I assume) work at run time.</li>
<li>But I can make it work.</li>
<li>So it's mainly a question of what it would take to make it work in the plugin.</li>
</ul>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">What exactly does "making it work" entail?</p>
</div>
<p>Um...</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="fm">__add__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span> <span class="o">+</span> <span class="n">other</span>
</pre></div>
<div class="admonition smiley smiley-glitchy">
<p class="first admonition-title">:) (glitchy)</p>
<p class="last">MmmMMmmmm, that's the <em>good stuff</em>.</p>
</div>
<p>Getting that in would require some minor investment in terms of testing because suddenly the method bodies would need to be executed.</p>
<p>Anyway, I need to get back into the guts of this code to figure out how to change it properly.
Something that just occurred to me is that I can define a "notes" variable inside my debug hook, breakpoint after it, and then I'll be able to get to the breakpoint by running Mypy, at which point I can remind myself what I was just doing by printing the notes variable, so it's all right there in front of me.</p>
<p>Anyway, I let it get late, so I'll just wrap up for now and see what I can do with this in the coming days.</p>
<p>Good night.</p>
Coding 2023-11-162023-11-16T05:00:00-05:002023-11-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-16:/coding-2023-11-16<p class="first last">Maybe this will be helpful to someone else who wants to write plugins for supporting utterly wretched code.</p>
<p>So, like I said, I filed the bug report, and then realized "Wait, I bet I can handle this."
So here's the general idea:
I've written a plugin for handling the concept of a dependent mapping, a mapping where the type of a value depends on the type of the corresponding key.
I'm allowing for arbitrary relationships, which <em>should</em> require a concept along the lines of higher-kinded types, which Python's typing ecosystem mostly does not have.
Now, a higher-kinded type is basically like, you have a type-level function between types, and you can write type-level functions that operate on type-level functions instead of plain types.
So, you could have <tt class="docutils literal">list[T]</tt> or <tt class="docutils literal">T | None</tt>, and you'd like to be able to pass them around.
This turns out to not really work; you can't pass around "a generic type with a hole in it".</p>
<p><em>However</em>, we can instead take a type-level function, and turn it into the type of a function that transforms types the way we'd like it to.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">What?</p>
</div>
<p>Let's turn those examples above into what I'm talking about.</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ListOf</span><span class="p">(</span><span class="n">Protocol</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">__k</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span>
<span class="o">...</span>
<span class="k">class</span> <span class="nc">Maybe</span><span class="p">(</span><span class="n">Protocol</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">__k</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="o">-></span> <span class="n">T</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="o">...</span>
</pre></div>
<p>Now, these callable protocols are entirely concrete, of course; just look at the <tt class="docutils literal">class</tt> lines.</p>
<p>Now, these callable protocols are entirely generic, of course; just look at the <tt class="docutils literal">def</tt> lines.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">There's no way Mypy is cool with this.</p>
</div>
<p>Absolutely not; why do you think we're in this mess?</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">We?</p>
</div>
<p>Anyway, I could imagine various uses for this idiom; actually implementing these protocols could be useful for some kind of data processing pipeline, potentially.
But I've instead been using them as the type arguments of a generic protocol, which is like <tt class="docutils literal">Mapping</tt>, but is not <tt class="docutils literal">Mapping</tt>.
Most of the methods on the protocol actually typecheck perfectly fine, and to bridge the gap, I had to write a plugin that transforms a select few signature and method accesses, pulling up variables hidden inside the protocols.</p>
<p>This worked perfectly fine for a few versions, but with Mypy 1.7.0, some new type inference code became the default, and it gives those methods much less helpful default signatures.
At first I thought "Well, I need the signatures to go back the way they were", but then I realized that most of the information is still intact, just not where I want it to be, and there is a finite set of methods to update, so I can hardcode rather a lot if I need to.</p>
<p>Let's have a look at what I've put together so far.
Now, none of this is functional code changes; it doesn't really work to rush into writing a Mypy plugin; getting small details wrong can crash it outright.
So, I'm currently focused on diagnostics.
Print-based diagnostics.
Just stick a print statement in the plugin code, and it shows up in the command-line output.
EZ.</p>
<p>Here's what I've got currently:</p>
<div class="highlight"><pre><span></span><span class="n">CALLABLE_SLOTS</span> <span class="o">=</span> <span class="p">(</span>
<span class="s2">"arg_types"</span><span class="p">,</span>
<span class="s2">"arg_kinds"</span><span class="p">,</span>
<span class="s2">"arg_names"</span><span class="p">,</span>
<span class="s2">"min_args"</span><span class="p">,</span>
<span class="s2">"ret_type"</span><span class="p">,</span>
<span class="s2">"name"</span><span class="p">,</span>
<span class="s2">"definition"</span><span class="p">,</span>
<span class="s2">"variables"</span><span class="p">,</span>
<span class="s2">"is_ellipsis_args"</span><span class="p">,</span>
<span class="s2">"implicit"</span><span class="p">,</span>
<span class="s2">"special_sig"</span><span class="p">,</span>
<span class="s2">"from_type_type"</span><span class="p">,</span>
<span class="s2">"bound_args"</span><span class="p">,</span>
<span class="s2">"def_extras"</span><span class="p">,</span>
<span class="s2">"type_guard"</span><span class="p">,</span>
<span class="s2">"from_concatenate"</span><span class="p">,</span>
<span class="s2">"imprecise_arg_kinds"</span><span class="p">,</span>
<span class="s2">"unpack_kwargs"</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">pprint_callable_type</span><span class="p">(</span><span class="n">callable_type</span><span class="p">,</span> <span class="n">when</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="n">when</span><span class="p">,</span> <span class="s2">"("</span><span class="p">)</span>
<span class="k">for</span> <span class="n">slot</span> <span class="ow">in</span> <span class="n">CALLABLE_SLOTS</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="n">slot</span><span class="p">,</span> <span class="s2">"="</span><span class="p">,</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">callable_type</span><span class="p">,</span> <span class="n">slot</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">")"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">debug_hook</span><span class="p">(</span><span class="n">hook</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">new_hook</span><span class="p">(</span><span class="n">ctx</span><span class="p">):</span>
<span class="n">self_arg</span> <span class="o">=</span> <span class="n">ctx</span><span class="o">.</span><span class="n">type</span><span class="o">.</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="nb">print</span><span class="p">(</span><span class="n">self_arg</span><span class="o">.</span><span class="n">type</span><span class="p">[</span><span class="s2">"__call__"</span><span class="p">]</span><span class="o">.</span><span class="n">type</span><span class="p">)</span>
<span class="n">before</span> <span class="o">=</span> <span class="n">ctx</span><span class="o">.</span><span class="n">default_signature</span>
<span class="n">pprint_callable_type</span><span class="p">(</span><span class="n">before</span><span class="p">,</span> <span class="s2">"before"</span><span class="p">)</span>
<span class="n">after</span> <span class="o">=</span> <span class="n">hook</span><span class="p">(</span><span class="n">ctx</span><span class="p">)</span>
<span class="n">pprint_callable_type</span><span class="p">(</span><span class="n">after</span><span class="p">,</span> <span class="s2">"after"</span><span class="p">)</span>
<span class="k">return</span> <span class="n">after</span>
<span class="k">return</span> <span class="n">new_hook</span>
</pre></div>
<p>Most of the hooks in the plugin focus on rewriting the method signature, so I've written a diagnostic decorator that details the information relevant to the plugin's functionality, and how the hook transforms the information that it's supposed to transform.
Because it's a decorator, I can put it on a hook, and take it off, without worrying about messing up the hook's body.</p>
<p>I've put together a small synthetic test file, and am comparing the debug output with and without the new type inference.
So far, I'm seeing that the output is <em>mostly</em> the same; it's just that <tt class="docutils literal">arg_types</tt> and <tt class="docutils literal">ret_type</tt> have <tt class="docutils literal">Never</tt> instead of anything useful.</p>
<p>And... I just discovered a crash that was latent in the plugin code all along.
I'm going to have to figure out how to convert that into a proper call, or at least a reasonable error telling people "Hey, you can't use the plugin like that. Stop it."</p>
<p>Anyway, it's going to take some more work and a bunch of notes to put together a plan for how to handle this stuff.
I'd better put this entry down and see what I'm up for the rest of the night.</p>
<p>Good night.</p>
Diary 2023-11-152023-11-15T05:00:00-05:002023-11-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-15:/diary-2023-11-15<p class="first last">Maybe there are other ways to turn the code eldritch.</p>
<p>I just filed a bug that I'm not confident will get fixed—</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">"fixed"</p>
</div>
<p>But I figured I'd at least ask.</p>
<p>That said, now that I've thought about it some more, there may be an alternative on my end to changing the behavior.
If I can reach inside...</p>
<p>Hm...</p>
<p>Yes, it does appear that nearly all of the information I need is still available, and I "just" need to hardcode the remainder.
I think this will end up being "switch to the old type inference, get information about what the signature 'should' look like, and add that information in".</p>
<p>We'll see what that ends up being like later.
For now, I need to get to bed.</p>
<p>Good night.</p>
Weekly Roundup 2023-11-142023-11-14T05:00:00-05:002023-11-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-14:/weekly-roundup-2023-11-14<p class="first last">I got more done on MOTR than expected, but now I'm taking a break really for real.</p>
<ul class="simple">
<li>Wednesday: I made and planned some improvements to MOTR.</li>
<li>Thursday: I ran into some complications, and tried to work out the best way to deal with them.</li>
<li>Friday: I didn't really make concrete progress, but I did keep thinking.</li>
<li>Saturday: Eh, rough day apparently.</li>
<li>Sunday: I discovered bugs in Mypy, both comprehensible and incomprehensible.</li>
<li>Monday: I finished updating MOTR, ignoring the Mypy issues for now. It was a very easy update once the code was in place.</li>
</ul>
<p>Next week, I'm going to try to psych myself up to file one of those Mypy bugs.
And probably other things, I don't know.</p>
Coding 2023-11-132023-11-13T05:00:00-05:002023-11-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-13:/coding-2023-11-13<p class="first last">I had to update one line of test code, and then the tests passed. Spooky.</p>
<p>I've got MOTR's code cleaned up in the rewrite branch.
Now, I <em>could</em> get back in there trying to continue the updates or tweak the names I came up with.
(Those names are overall better than what came before, but not great.)
But I think I'd like to step back and find other stuff to focus on, at least until we get a new Mypy release or two.</p>
<p>It's probably best for me to work on getting thoughts written down for music, but I felt like trying to learn a bit about Dafny today, so I did.
There are two categories of thing I'm interested in with Dafny: what kind of code does it make sense to write in Dafny, and what does it take to integrate that code with other code bases?
Looking at the output from the Python builder, I'm fairly certain this code won't cleanly slot into my usual Python workflows, though there are a few niche applications where there <em>could</em> be potential.
But in general, it seems like it'd make more sense to have Dafny target faster code and then FFI into it.
I don't know how hard that actually is, though.</p>
<p>As far as what to write, I think I need to learn more than the basics of the data model.</p>
<p>Anyway, I took too long with this post, so I'm going to cut it off abruptly.</p>
<p>Good night.</p>
Coding 2023-11-122023-11-12T05:00:00-05:002023-11-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-12:/coding-2023-11-12<p class="first last">Mypy somehow managed to infer types that shouldn't even exist...</p>
<p>Things that have happened with MOTR:</p>
<ul class="simple">
<li>The Mypy 1.7 update broke things; fortunately somebody else already filed a bug.</li>
<li>I'm deep into the rewrite; it'll be interesting to see how badly the tests go, once the code looks reasonable.</li>
<li>I ran into an absolutely inexplicable Mypy bug that I'll try to get a reproducer for once everything else is cleaned up.</li>
</ul>
<p>Fortunately, I'm doing most of this on a branch.
I had a sense that the update could be hairy, and it has been so, so much worse than I was anticipating.</p>
<p>Anyway, it's late and I'm tired.
We'll see how this ends up tomorrow.</p>
<p>Good night.</p>
Diary 2023-11-112023-11-11T05:00:00-05:002023-11-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-11:/diary-2023-11-11<p class="first last">Meh, whatever.</p>
<p>I poked a little at MOTR, but not enough to write about.
I think I'm going to need to put it down in favor of something else for a while.</p>
<p>I've got some things I can mess with, but I think I mostly need to find some way to unwind.
We'll see how that goes.
I'm going to start by not trying very hard with this post.</p>
<p>Good night.</p>
Coding 2023-11-102023-11-10T05:00:00-05:002023-11-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-10:/coding-2023-11-10<p class="first last">No significant progress.</p>
<p>Still thinking.
Need to tease out the concepts.
Invocation to represent launching a command; add implicit artifacts to represent dependencies; add installers to convert executables to dependencies...</p>
<p>I still need to think about it, yeah.</p>
<p>Good night.</p>
Coding 2023-11-092023-11-09T05:00:00-05:002023-11-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-09:/coding-2023-11-09<p class="first last">Looks like the old layout was <em>almost</em> right, which is a shame, because I still have no idea what to call these things...</p>
<p>Hm.
It turns out that things aren't <em>quite</em> as easy as switching to <tt class="docutils literal">Invocation</tt>, because there are various pieces of data that have to get passed around and worked with.
Like, however you create a <tt class="docutils literal">Cmd</tt> task, doing so requires four pieces of information:</p>
<ul class="simple">
<li>the arguments</li>
<li>the environment</li>
<li>the implicit artifacts</li>
<li>the failure codes that shouldn't abort</li>
</ul>
<p>I've got a <em>sense</em> for how this should all fit together with some of the high-level stuff, but I'm not confident in my gut feelings here.
Those gut feelings are:</p>
<ul class="simple">
<li>arguments + environment -> invocation; this is known</li>
<li>invocation + implicit -> ???; this type would convert failure codes to facts</li>
<li>??? + installer mapping -> ????; this type would downconvert to a ??? suitable for the above; this type (modulo layout) is currently called <tt class="docutils literal">Metadata</tt>, but, no.</li>
</ul>
<p>I think I need to let this percolate for a bit, and I do have some other things to focus on in the meantime, so let's do that...</p>
<p>Good night.</p>
Coding 2023-11-082023-11-08T05:00:00-05:002023-11-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-08:/coding-2023-11-08<p class="first last">I think this made coverage go up, as well?</p>
<p>I guess my plans ended up being for just a week in the future.
My plan now is to create an <tt class="docutils literal">Invocation</tt> or <tt class="docutils literal">InvocationParameters</tt> or something like that, a container describing the information required to dispatch a command.
Next, rewrite the upper layers in terms of that, and see what falls out.</p>
<p>I'd hoped to get more done tonight, but I at least got the environment variable representation fully cut over, so that's nice.</p>
<p>For now, I'm going to chill out and read stuff.</p>
<p>Good night.</p>
Weekly Roundup 2023-11-072023-11-07T05:00:00-05:002023-11-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-07:/weekly-roundup-2023-11-07<p class="first last">New plan for writing: no more than one week of drafting at a time.</p>
<ul class="simple">
<li>Wednesday: I made some plans for how to reorganize parts of MOTR.</li>
<li>Thursday: I made a promising start on the NaNo.</li>
<li>Friday: I was tired.</li>
<li>Saturday: I caught back up, but still tired.</li>
<li>Sunday: Tired.</li>
<li>Monday: I ran out of runway on the NaNo, and realized there were serious issues, and, like, if I don't have a plan to address the issues, how can I charge ahead writing?</li>
</ul>
<p>Next week, I'm going to switch to some smaller projects (MOTR is made up of many small projects, okay?).
For one, I want to try to put some of those changes to MOTR into practice; I think I can do something a little cleaner than what I had in mind at first.
For another, I'm looking into messing around with music composition again.</p>
Diary 2023-11-062023-11-06T05:00:00-05:002023-11-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-06:/diary-2023-11-06<p class="first last">Really not sure where to take this...</p>
<p>Okay, so, NaNo.
I'm not <em>definitely</em> giving up on it, but I'm not going to finish it the way I'm going currently.
There are a few problems here:</p>
<ul class="simple">
<li>I have painfully low energy and just want to lie down forever.</li>
<li>I've more-or-less exhausted the stuff I pre-planned.</li>
<li>I'm not sure if the stuff I want to write about merits something novella-length on its own.</li>
<li>I'm trying to show off some fancy worldbuilding I came up with, but every character currently alive is looking at it and going "So, it's a <em>bad idea</em> to engage with that".
At the same time, if a character <em>did</em> do the irresponsible thing, it would probably render the narrative too confusing.</li>
</ul>
<p>Ultimately, what I really wanted to get out of this was a test of some insultingly simple command-line tools I put together for writing, and the ultimate verdict on those so far is a resounding "maybe".
Like, for sure, they don't get in the way in the way that any minimally functional editor does, but I guess I can't really evaluate how well they worked without trying to put the output through a bunch of editing passes.</p>
<p>Basically, if I can address all of the points above in the next few days, I'll get back into it, and otherwise I'll let it be.
(Not like I wasn't already sneaking in work on other things anyway.
Maybe this whole "work on just one thing for a month" thing isn't for me any more...)</p>
<p>Anyway, for now, I'm going to print some stuff out so I can get off my laptop and try to take things easy.</p>
<p>Good night.</p>
Diary 2023-11-052023-11-05T04:00:00-05:002023-11-05T04:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-05:/diary-2023-11-05<p class="first last">It's hard to come up with stuff to say beyond "still on par, wish I could get a buffer, but I'm not going to beat myself up over it".</p>
<p>I hit par today, and after that, I'm trying to take things easy, because I'm dealing with a lot of stress.</p>
<p>At least I'm relaxing.</p>
<p>Good night.</p>
Diary 2023-11-042023-11-04T04:00:00-04:002023-11-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-04:/diary-2023-11-04<p class="first last">A mathematically average day of writing, for what it's worth.</p>
<p>I'm doing a little better now, I guess.
As far as writing, I'm staying on par.
I wanted to try to get ahead, but it's late enough that I'm not going to try to force it.
I'm a little worried I've written myself into a corner, so I'm going to hope that sleeping gives me some inspiration.</p>
<p>As for the rest of tonight...
There is nothing else.</p>
<p>Good night.</p>
Diary 2023-11-032023-11-03T04:00:00-04:002023-11-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-03:/diary-2023-11-03<p class="first last">Had a bad day, just hoping for some good days to balance it out.</p>
<p>So.
I was really tired today, and I didn't keep pace, but at least I'm over par.
I should have a few days to properly divide between rest and writing, and we'll see where that leaves me.</p>
<p>Right now, though, I'm just going to read.</p>
<p>Good night.</p>
Diary 2023-11-022023-11-02T04:00:00-04:002023-11-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-02:/diary-2023-11-02<p class="first last">I put most of my words today into a text file called "draft", so there aren't many in this post.</p>
<p>Good start out the gate with NaNoWriMo today.
Nothing too flashy, just a solid batch of words over the course of a few hours.
I'm... not totally certain what I'm going to fill the overall wordcount with, but I'm going to try not to worry about that.</p>
<p>I'm really tired, but that's just my system being all out of sorts from whatever messed-up stomach bug I picked up somewhere.
All the same, I want to get off my laptop for now.</p>
<p>Good night.</p>
Coding 2023-11-012023-11-01T04:00:00-04:002023-11-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-11-01:/coding-2023-11-01<p class="first last">Making plans for a few weeks from now, hopefully.</p>
<p>I'm going to switch gears tomorrow, but until then, I've been having a look at the parts of MOTR that I want to update, and one thing that I have to deal with is that I'm not sure what my endgame was seven or eight months ago.
My goal <em>currently</em> is to put together a tower of types, based on constructing types like <tt class="docutils literal">GeneralizedType = SpecializedType[SomeType | T]</tt>.
It looks like my thought process at the time was "So, I want to devise a more specialized type for environment variables, because the higher layers in the stack need that, and it [apparently] makes sense to plumb that back down to the lowest layer where it's relevant; oh, but I should make sure to avoid breaking backwards compatibility".
Frankly, it looks like I was wrong about that last bit, because my current motrfile doesn't seem to set any environment variables.
That means I should be able to mess with it however I want.</p>
<p>And what I'm currently thinking is:</p>
<ul class="simple">
<li>Ditch the <tt class="docutils literal">LegacyEnvVar</tt> concept, and get everything working with <tt class="docutils literal">EnvVar</tt>.</li>
<li>Create a compound type that works with arguments and environment variables via a single type variable.</li>
<li>Create another compound type that bundles that type with the implicit io, using a separate type variable. (Might not go with this, not sure.)</li>
<li>Make a new helper function to take these new types.</li>
<li>Propagate these types up the layers of abstraction.</li>
<li>(NOTE: I cannot change the <tt class="docutils literal">Cmd</tt> type currently, because it's being used directly by the Motrfile.)</li>
<li>This should get rid of a <tt class="docutils literal">Metadata</tt> type, at the cost of potentially adding more fields to another class that needs a redesign anyway.</li>
</ul>
<p>I won't try to work on this tonight; at some point I'll be back on this.
For now, I should wrap up, and figure out how sick I am or am not...</p>
<p>Good night.</p>
Weekly Roundup 2023-10-312023-10-31T04:00:00-04:002023-10-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-31:/weekly-roundup-2023-10-31<p class="first last">If I need to do renames to be motivated to get the coverage up, I'll have to do renames.</p>
<ul class="simple">
<li>Wednesday: I was sick a week ago. Guess what's happening now!</li>
<li>Thursday: I pondered some more renames for MOTR.</li>
<li>Friday: I made some progress on planning for MOTR, but didn't implement the plans just yet.</li>
<li>Saturday: There was enough of a plan, so I put it into effect, then made some other improvements.</li>
<li>Sunday: I realized that some of the code in MOTR is probably needlessly strict, so I need to look into what contracts actually need to be upheld.</li>
<li>Monday: I finally remembered what <tt class="docutils literal">command.Metadata</tt> is meant to accomplish. Such is the obfuscatory power of a really, really bad name.</li>
</ul>
<p>Next week, I'm going to try to spend a little time planning out the changes needed to remove <tt class="docutils literal">command.Metadata</tt>.
However, after tomorrow (keeping in mind the weird dating system for these blog posts), I'm going to have another place I'm going to be trying to put my focus...</p>
Coding 2023-10-302023-10-30T04:00:00-04:002023-10-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-30:/coding-2023-10-30<p class="first last">Still gradually coming up with plans to improve the structure of the code...</p>
<p>Okay.
I've got some more insight on one of the <tt class="docutils literal">Metadata</tt> classes, but it hasn't translated into a new name yet.</p>
<p>Here's the deal:</p>
<p>A command, like you'd dispatch on the shell, has some arguments, and environment variables associated with the execution.
It also may rely on or cause side effects that are not specifically mentioned in the arguments or environment variables.
This is expressed within the low-level interfaces exposed in current releases of MOTR.</p>
<p>A concept at a higher level is an <tt class="docutils literal">Executable</tt>, which is approximately "anything that requires some kind of installation process that MOTR is to handle, and is capable of processing arguments, environment variables, etc"
This could be either a shell script, or the slightly less obvious "argument to <tt class="docutils literal">python <span class="pre">-m</span></tt>"</p>
<p>The <tt class="docutils literal">Metadata</tt> class sort of combines these, by having containers corresponding to the lower-level ideas, but allowing <tt class="docutils literal">Executable</tt>s in addition to the normal data types.
It then provides facilities to convert these <tt class="docutils literal">Executable</tt>s down to the normal data types.</p>
<p>So, the problem is, <em>obviously</em> <tt class="docutils literal">Metadata</tt> is a bad name for this, and I should come up with something better.
But I'm not sure what yet.
One possibility is to push some of the concepts to the lower level, which would effectively remove the class, via converting its functionality into a single function.
Ultimately this wouldn't get rid of the problem of naming a class, but it would <em>simplify</em> it, by making the class to be named smaller and more focused.</p>
<p>I think that'll get things in a good position, though it'll be a rough merge up to the future topic.
For now, I'll be glad I've come up with a plan.</p>
<p>Good night.</p>
Coding 2023-10-292023-10-29T04:00:00-04:002023-10-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-29:/coding-2023-10-29<p class="first last">Soon I should get some more improved names out of this...</p>
<p>All right, let's see.
More coverage for MOTR, and now I'm staring at some of the remaining lines, and thinking "Hm, it seems like some of this validation is too strict."
That's going to take some careful thought to be sure of one way or the other.</p>
<p>Like, the <tt class="docutils literal">matrix.directory</tt> decorator combines together some amount of <tt class="docutils literal">SelectionDirectory</tt> and <tt class="docutils literal">Matrix</tt> objects, along with a function to map the values all together.
The question I need to consider is, what can go wrong when it's guaranteed or possible that the matrix will allow iteration over labels outside of the directories?
To address that, I'm going to need to once again trace out the code that can potentially be hit by the highest levels of abstraction in this system.
For now, I'm not up for doing that work; maybe tomorrow.</p>
<p>Good night.</p>
Coding 2023-10-282023-10-28T04:00:00-04:002023-10-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-28:/coding-2023-10-28<p class="first last">The increased coverage is improving the code, by the way. When I hit these error cases in tests, I have to actually write messages for them.</p>
<p>Did the simplest possible layout that I'm comfortable with; the result is a little iffy currently, and I might rework it slightly later, but it's fine for now.</p>
<p>All of that cleanup got me comfortable writing more tests for the <tt class="docutils literal">matrix</tt> module.
Just a few more tests, and it should be covered, and I can start working on other modules.</p>
<p>For now, though, I'm just going to take things easy.</p>
<p>Good night.</p>
Coding 2023-10-272023-10-27T04:00:00-04:002023-10-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-27:/coding-2023-10-27<p class="first last">Grudges so petty, even I can't believe I'm still holding them.</p>
<p>I did a little research, and I've decided to go with <tt class="docutils literal">DependentMapping</tt>.
I'm still trying to figure out how to organize things.
Because, I want to bring in sample magmas that other code can drop into <tt class="docutils literal">update_with()</tt> calls.</p>
<p>I think I want this to look something like</p>
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">dependent_mapping.magmas</span>
<span class="o">...</span>
<span class="n">CustomMapping</span> <span class="o">=</span> <span class="n">dependent_mapping</span><span class="o">.</span><span class="n">DependentMapping</span><span class="p">[</span><span class="n">_CustomCallableProtocol</span><span class="p">]</span>
</pre></div>
<p>That's straightforward enough to describe, but I've lost track of the guidance on what's acceptable to put in <tt class="docutils literal">__init__.py</tt> files, and the <tt class="docutils literal">DependentMapping</tt> protocol is... beefy.
(That said, some of the opinions I remember seeing about <tt class="docutils literal">__init__.py</tt> came from people who also said that slash args were useless, which is a <em>fascinating</em> position to take with respect to a project I was working on at the time, which contained some functions that needed to take a limited number of positional arguments, and totally arbitrary keyword arguments.)</p>
<p>So, I'm going to publish this entry, and start reading up on what is and isn't acceptable in <tt class="docutils literal">__init__.py</tt> files.
And get to bed at a somewhat reasonable time.</p>
<p>Good night.</p>
Coding 2023-10-262023-10-26T04:00:00-04:002023-10-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-26:/coding-2023-10-26<p class="first last">I swear all this polish is going to pay off in like a few months.</p>
<p>I'm feeling better now.
More focused.
Let's not squander it.</p>
<p>I tried out those renames I was thinking of for MOTR, and I think that they did improve things.
To be sure, I'm going to need to step away from the code for a bit, then read over the modules I changed to see if they're any clearer.</p>
<p>After getting those changes in, I find myself focusing on a helper function that I wrote into <tt class="docutils literal">Axes.combine</tt>.
That function clearly needs to go together with the whole... "functions only defined on finite sets" concept that ties a lot of the new layers of MOTR together.
To me, that means that the relevant module needs to be moved higher in the tree, next to the <tt class="docutils literal">saltate</tt> module.
And that suggests that I should try to come up with a non-awkward name for it.</p>
<p><tt class="docutils literal">per_item_parametric_mapping</tt> to...
Hm.
Basically, the idea is that this type represents the same concept as a parametrically typed function, but it's only defined for values that are specifically set.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p>...
What's this paper?</p>
<p>...
All right.</p>
<p class="last">"But, Max.
Mypy doesn't let you define a type that acts like that."</p>
</div>
<p>Not without <em>convincing</em> it doesn't.</p>
<p>Anyway, what to call this...
After the renames I've done, shortening it to <tt class="docutils literal">ParametricMapping</tt> doesn't sound <em>unreasonable</em> to me.
Need to figure out the right naming conventions around the magmas, though.
The annoying thing about <tt class="docutils literal">ParamatricMapping</tt>, when I think about it, is that you need to look at it and think "Well, <tt class="docutils literal">Mapping</tt> is already parametric, so how is this different?"</p>
<p>Well, I'll take some time to think about this, and see what I feel like doing.</p>
<p>Good night.</p>
Diary 2023-10-252023-10-25T04:00:00-04:002023-10-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-25:/diary-2023-10-25<p class="first last">Being sick is weird.</p>
<p>I was too tired to focus today, and there's no way I can improve the situation by trying to force something now.
For what it's worth, I did pile in a few more project ideas, so things promise to get <em>interesting</em> in a few months.</p>
<p>Hopefully I'll have more energy tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2023-10-242023-10-24T04:00:00-04:002023-10-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-24:/weekly-roundup-2023-10-24<p class="first last">Time is a flat circle.</p>
<ul class="simple">
<li>Wednesday: I thought about names in MOTR, and wasn't sure if I wanted to go the finally-obvious route.</li>
<li>Thursday: I still wasn't sure about the names, but I was able to write some code that will eventually be useful, I think.</li>
<li>Friday: I came up with absurdly many projects to work on... at some point.</li>
<li>Saturday: "Well, let's get back into MOTR for now... but also attempt NaNoWriMo."</li>
<li>Sunday: Settling on the obvious name gave me the motivation I needed to write tests again.</li>
<li>Monday: I got more test coverage... but ran back into having problems with the names.</li>
</ul>
<p>Next week, I'm going to keep on pondering the name ideas, and see how I feel.</p>
Coding 2023-10-232023-10-23T04:00:00-04:002023-10-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-23:/coding-2023-10-23<p class="first last">Still trying to come up with evocative names.</p>
<p>Hmmph.
I'm pushing up the coverage on the <tt class="docutils literal">matrix</tt> module, but it's getting to the point where I have to consider the names of things before I feel comfortable writing more tests.</p>
<p>See, there are a few supplemental classes in that module that I'm not feeling totally on-board with the current names of: <tt class="docutils literal">AdaptiveMatrix</tt> and <tt class="docutils literal">MappedSelection</tt>.</p>
<p>Let's consider <tt class="docutils literal">MappedSelection</tt> first.
Basically, it's a single selection label, plus a function to map from the type of the selection label to something that can be slotted into a <tt class="docutils literal">Path</tt>.
Put together, it allows for the creation of two matrices which can be freely combined because they have the same axis structure.
The label itself and the matrices are relevant in different parts of the code.</p>
<p>One of those parts of the code is the <tt class="docutils literal">AdaptiveMatrix</tt>, which combines a variable-length tuple of <tt class="docutils literal">MappedSelection</tt>s with a <tt class="docutils literal">Matrix[T]</tt>, which is constrained to iterate over exactly the same labels as are present in the tuple of <tt class="docutils literal">MappedSelection</tt>s.
The <tt class="docutils literal">AdaptiveMatrix</tt> is one of three possible things that can end up in a sequence of command-line arguments(ish):</p>
<ul class="simple">
<li>static text</li>
<li>the paths of artifacts passed between commands</li>
<li>auxiliary data required by specific matrix values (<tt class="docutils literal">AdaptiveMatrix</tt>)</li>
</ul>
<p>This sounds niche, but everything breaks if I don't have it, so.</p>
<p>When I look at the code, I think this could potentially get a bunch more complicated, but maybe not...</p>
<p>Anyway.</p>
<p>The key perspectives of the <tt class="docutils literal">MappedSelection</tt>:</p>
<ul class="simple">
<li>It can provide a <tt class="docutils literal">Matrix</tt> that exposes a value of an arbitrary type.</li>
<li>It can provide a <tt class="docutils literal">Matrix</tt> that exposes a value suitable to use as a directory name, and these matrices are perfectly correlated.</li>
<li>It can provide a <tt class="docutils literal">selection.Label</tt> that is used to constrain and determine the structure of other matrices.</li>
</ul>
<p>I'm not going to put in the effort tonight, but now I wonder if something like <tt class="docutils literal">SelectedDirectory</tt> and <tt class="docutils literal">MatrixDirectory</tt> would strike me better.
I'll sleep on it.
For now, I've got other stuff I'll focus on for a bit to clear my head.</p>
<p>Good night.</p>
Coding 2023-10-222023-10-22T04:00:00-04:002023-10-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-22:/coding-2023-10-22<p class="first last">Well, somehow I ended up making progress.</p>
<p>Okay, so I gave myself sort of a break today, focusing on improving various bits of MOTR.
I finally settled on calling it a <tt class="docutils literal">Matrix</tt>, and this cascaded into a bunch of renames that made things clearer.
And made a few other changes.</p>
<p>That added up to enough clarity and motivation that I finally added a line of test coverage.
Now, I'm not sure how best to handle the remaining lines in the <tt class="docutils literal">matrix</tt> module, because the vast majority of those lines are validation failures or similar.
I guess there's nothing for it but to carefully construct a bunch of axes "wrong" to make sure they hit the validation errors...</p>
<p>To get that done, I guess I just need to be in the right frame of mind to power through the monotony.
Anyway, it's past time I meant to post this; I need to get to bed now.</p>
<p>Good night.</p>
Coding 2023-10-212023-10-21T04:00:00-04:002023-10-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-21:/coding-2023-10-21<p class="first last">Possibly too many plans.</p>
<p>The document of ideas is even longer now, so that's... a thing.
I've come up with some ideas to integrate some Python libraries with the way that I, and, near as I can tell, nobody else, write tests, so that'll be really interesting.
Unfortunately, I still don't have the discipline to Just Use tox, Nox, or Hatch's matrices.</p>
<p>With that in mind, I'm going to try to put some renames into practice in MOTR, now that I know what one of the <tt class="docutils literal">Metadata</tt> classes should be called instead.
(I just checked, and there are apparently just two?
I must be using them <em>a lot</em>, because it feels like they're everywhere.)</p>
<p>With that said, however...
Due to a confluence of factors, I'm interested in giving NaNoWriMo another try this year.
(The factors in question are, I have finally "properly" developed an idea that I have been utterly failing to explain to people for like a decade, and I just threw together some tools for drafting that I want to see in serious action.)</p>
<p>So, the <em>plan</em> is to kind of disappear for a month.
That is things working as intended.</p>
<p>We'll see how things actually go when the time comes.
For now, sleep.</p>
<p>Good night.</p>
Coding 2023-10-202023-10-20T04:00:00-04:002023-10-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-20:/coding-2023-10-20<p class="first last">The document I produced working on this has some turbo-cursed questions in it.</p>
<p>I messed with last night's "greenfield development" a little; it should be about ready to by put into use, assuming Mypy doesn't have any weird objections to it.</p>
<p>For now, though, I suddenly had <em>a bunch</em> of ideas for stuff to work on besides MOTR, so I'm going to focus on categorizing and prioritizing <em>dozens</em> of things I <em>could</em> be looking into.</p>
<p>...</p>
<p>I managed to roughly bin everything.
I haven't prioritized them yet.
In terms of concrete goals, there are three-ish things I can look into:</p>
<ul class="simple">
<li>Music theory and synthesis stuff, with an eye towards stuff besides 12EDO</li>
<li>Prototyping interpreters for Impliciula</li>
<li>Going back to my dice rollers project</li>
</ul>
<p>We'll see if I manage to settle on one.
One serious obstacle I have is that, unless someone just <em>gives me</em> a toxfile or a noxfile, I'll probably end up longing for MOTR, so the best bet may actually be looking into the options that specifically don't involve Python...</p>
<p>Anyway, I don't want to stick around too much longer right now.</p>
<p>Good night.</p>
Coding 2023-10-192023-10-19T04:00:00-04:002023-10-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-19:/coding-2023-10-19<p class="first last">A little greenfield development, as a treat.</p>
<p>Quick name thought: some CI products call it a "matrix", but...
On the one hand, I want to say "tensor" because more dimensions, but apparently a tensor is more identified with a generalization of a linear transformation, and linear transformations can be represented by matrices, but the grids the CI products generate don't have anything to do with linear transformations.</p>
<p>What we have is some kind of generalized Cartesian product and the ability to map over the result.
I mean, except that the Cartesian-product-like-thing is idempotent, and commutative, and associative.
So, like, at that point, what is it?
(I guess if an ordering is defined over the labels, then we can fold the Cartesian product over an ordered set of labels mapped to typed sets?)</p>
<p>Anyway, I want to change gears, so I'm going to prototype some code that I won't be able to use for a while.</p>
<p>...</p>
<p>Okay, done for now, got a few things to think about while I wait to be able to use this.
Basically, I wanted a wrapper around <tt class="docutils literal">contextvars</tt>, using <tt class="docutils literal">contextlib</tt>, so I can have context managers controlling the values of <tt class="docutils literal">box</tt> and <tt class="docutils literal">selection</tt> instead of passing them through every function, mostly unchanged.
This is pretty easy to throw together, but I did add just enough functionality to raise questions.
Like, the basic functionality is to have a <tt class="docutils literal">get()</tt> helper method, and a <tt class="docutils literal">set()</tt> method that returns a context manager.
But I anticipate that I'll want to express the logic a lot of the time as "update whatever value there is, with this function" rather than "temporarily replace the current value with one that happens to be related to it".
So I wrote an <tt class="docutils literal">update()</tt> context manager, and it's like, if there isn't a value in the variable currently, do I want that to fail outright, for the caller to specify a default value to <tt class="docutils literal">get()</tt>, or for the caller to provide a default value that <em>replaces</em> the act of calling the function passed in?</p>
<p>I guess I'll need to figure out what I want to happen in my actual use cases for this stuff.
I think I'd want the <tt class="docutils literal">get()</tt> to fail, and a helper function in the stack to catch the <tt class="docutils literal">LookupError</tt> and convert it to something MOTR-specific?
Which is certainly easy to implement from the standpoint of the code I'm looking at now...</p>
<p>Anyway, I'm tired and foggy.
Time to wind down.</p>
<p>Good night.</p>
Coding 2023-10-182023-10-18T04:00:00-04:002023-10-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-18:/coding-2023-10-18<p class="first last">I <em>really</em> care about names, okay?</p>
<p>I discussed naming concepts in MOTR with my wife, and I came up with A Breakthrough.
Just need a couple more...</p>
<p>In short (because I want to rest my eyes), one of the key concepts in (the high level code in) MOTR is currently called <tt class="docutils literal">Parametric</tt>, and has an attribute just called <tt class="docutils literal">metadata</tt>, which is... a <tt class="docutils literal">Metadata</tt>.
After a bunch of discussion, I realized that the <tt class="docutils literal">Metadata</tt> is roughly analagous to the concept of "shape" or "axes" of a multi-dimensional array.
Which, you'd think would settle "what to rename <tt class="docutils literal">Parametric</tt>", but...</p>
<p>Okay, so, <tt class="docutils literal">Parametric</tt> corresponds to what some continuous integration systems call a "matrix", but when I searched on the web, it seemed like this usage is, in some sense, common but not standard, if that makes any sense?
I was looking because I'm used to thinking of "a matrix with an arbitrary number of axes" as "a tensor" (though I admittedly don't use tensors much), but I thought to myself "If I call it a 'tensor', I bet people will ask why I didn't call it a 'matrix'".</p>
<p>Anyway, even if I'm not sure what I want to call it, that line of thinking did get me thinking about some potential features I could add.
Basically, it wouldn't be <em>too</em> hard to support excluding particular combinations of axis values, though it would be easier after a planned refactor that I don't want to do while I've got the kind of coverage gaps I've had for months.</p>
<p>Final thought: staring at the code relevant to that feature idea is forcing me to re-ponder the tension between "Wanting the Mypy coverage report to look good" and "Heehee <tt class="docutils literal"><span class="pre">itertools.product(*(itertools.zip_longest(...)</span> for x in y))</tt> go brrrrrrrr".
Like, really, that "line" of code needs an essay explaining what's going on...</p>
<p>Anyway, I have nothing more to say, and no coherent exit strategy, so,</p>
<p>Good night.</p>
Weekly Roundup 2023-10-172023-10-17T04:00:00-04:002023-10-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-17:/weekly-roundup-2023-10-17<p class="first last">Maybe if I give this stuff better names, more of it will fit in my head.</p>
<ul class="simple">
<li>Wednesday: I ran into Problems with MOTR, which were, on balance, mostly self-inflicted.</li>
<li>Thursday: I did some unpleasant work on MOTR, and did some easier stuff to take the edge off.</li>
<li>Friday: I finished up with the easy stuff, and then I was tired...</li>
<li>Saturday: "You know what would be fun? Cataloguing every global name, attribute, and function name in the code base."</li>
<li>Sunday: I went several layers deep trying to figure out which names need to be changed first.</li>
<li>Monday: I circled back around to names that have given me trouble before.</li>
</ul>
<p>Next week, maybe I'll keep on messing with the names, or maybe I'll come up with something else to do.</p>
Coding 2023-10-162023-10-16T04:00:00-04:002023-10-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-16:/coding-2023-10-16<p class="first last">I'm not sure where I'm going with this.</p>
<p>Traveled back, and had time to consider the names in MOTR.
I've ended up having to reconsider something that was bothering me last time:
I've managed to build part of the system thoroughly and pervasively around a concept that I can't figure out a good name for.
It's as if I'm a carpenter who is perfectly skilled on a technical level, but I don't know the word for "join", so I have no idea how to explain what I'm doing.</p>
<p>Basically, suppose you have a data type called a <tt class="docutils literal">Label</tt>, which has a type parameter with no run-time effect, and it compares by identity instead of by structure.
This means you can (provided the proper plugin code exists) construct containers that map a <tt class="docutils literal">Label[M[T]]</tt> to a <tt class="docutils literal">N[T]</tt>, for some <tt class="docutils literal">M</tt> and <tt class="docutils literal">N</tt>.
I call the type mapping <tt class="docutils literal">Label[T]</tt> to <tt class="docutils literal">T</tt>, <tt class="docutils literal">Box</tt>.
The metaphor here is that the box has a label on it, and the label indicates what's in there.
Now, suppose <tt class="docutils literal">M[T]</tt> is <tt class="docutils literal">tuple[T, <span class="pre">...]</span></tt>.
If you apply the corresponding label to a <tt class="docutils literal">Box</tt>, then the value is a collection of <tt class="docutils literal">T</tt>.
But if you have a container with the given <tt class="docutils literal">M</tt>, but <tt class="docutils literal">N[T]</tt> is just <tt class="docutils literal">T</tt>, then that same label maps to a single <tt class="docutils literal">T</tt>.
This could be a choice of <tt class="docutils literal">T</tt> from the collection in the <tt class="docutils literal">Box</tt>, and because it's a choice, I call it a <tt class="docutils literal">Selection</tt>.</p>
<p>I went a little crazy with custom container types once I got the plugin working, but those two types end up enabling a lot.
Clearly, once you have these types, and the right labels, you can convert a function that takes values of types into a function that takes a <tt class="docutils literal">Box</tt>.
And if some of the labels are to collections where you just need one value, you can get that value out of a <tt class="docutils literal">Selection</tt>.
In the context where I'm using these functions, it makes sense to want them to, instead of returning a value directly, actually return a generator that yields something called <tt class="docutils literal">Fact</tt>s, and then terminates with the value.
There are some obvious questions here about whether these values can actually be expected to be in the relevant containers, and pinning down the answers to those questions is where a lot of the code at this level of abstraction comes from.
But the first question I think I need to answer here is, given a function that takes a box and a selection, and yields facts before stopping with a value, what do we call that?</p>
<p>(There are some changes I want to make to the code later that will somewhat obscure this relationship at a syntactic level, but I'd rather ignore that caveat.)</p>
<p>The idea of all of this is that the top-level invocation will yield the facts associated with every possible selection that can be made from the box.
(Where the definition of "every possible selection" is actually very subtle and fiddly.)</p>
<p>I wonder if one of those parenthesized statements could help.
Like, if the underlying function is just a nullary function that returns a generator.
(Or possibly just an arbitrarily resumable generator...)
That object is now wholly defined by its output behavior, which is to calculate a value and yield facts as a side effect.</p>
<p>This feels like there's something to figure out from this perspective, but it's like I'm missing a piece...</p>
<p>I'll just have to think about it later, because it's getting late and I feel my mind fogging up.</p>
<p>Good night.</p>
Coding 2023-10-152023-10-15T04:00:00-04:002023-10-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-15:/coding-2023-10-15<p class="first last">Not too convenient to only be remembering scattered pieces of how this is supposed to work. I suppose I could review my old blog posts...</p>
<p>Okay, I got distracted today, and there was travel, so this is going to be a quick entry.
I worked through the names in MOTR a little more, and I'm right now in the area of the <tt class="docutils literal">Artifact</tt> protocol, along with some of the helper classes it relies on.
The <tt class="docutils literal">Artifact</tt> protocol is suffering from a lack of evocativeness, with method names like <tt class="docutils literal">convert</tt>, <tt class="docutils literal">forbid_narrowing</tt>, and <tt class="docutils literal">exposed_selections</tt>.</p>
<ul class="simple">
<li><tt class="docutils literal">convert</tt> just needs a more evocative name</li>
<li><tt class="docutils literal">forbid_narrowing</tt> should be better aligned with what the implementations ultimately do, which is focused around the "exclusive fields" of a <tt class="docutils literal">Parametric</tt>.</li>
<li><tt class="docutils literal">exposed_selections</tt> points towards the <tt class="docutils literal">parametric.MappedSelection</tt> helper class, which stands out to me as the biggest problem here.</li>
</ul>
<p>The point of <tt class="docutils literal">MappedSelection</tt> is that it extracts a value from a <tt class="docutils literal">Selection</tt> container, but it also offers a way to convert that value to a segment of a string-based path.
It is made via the <tt class="docutils literal">parametric.map_over</tt> decorator and the <tt class="docutils literal">installer.adaptor</tt> helper, which is a name that extra needs to be updated, because it hasn't gotten to the current round of naming yet...</p>
<p>Anyway, I think that class isn't being used to its full potential yet, which complicates things, but it is being used.
It's too late right now for me to determine more.
I'll try to understand this code better in the morning.</p>
<p>Good night.</p>
Coding 2023-10-142023-10-14T04:00:00-04:002023-10-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-14:/coding-2023-10-14<p class="first last">Just needed a new perspective on some of this stuff.</p>
<p>Well.
I ended up looking over some of the tests representing what a typical motrfile would look like, and I concluded that it wasn't great.
I took some notes on reducing clutter and making it easier to get the code right, but what I ended up deciding the code needs, is a holistic look at all of the names, and how they fit together, or sometimes, really don't.
So, I've started to catalogue every global variable, class, field, function, and parameter name in the project by module, and to include any notes I come up with on what to do with the names.</p>
<p>I've already come up with a few ideas for improvements, so let's see about getting those in before I write up too much more of this stuff.</p>
<p>For now, though, sleep.</p>
<p>Good night.</p>
Coding 2023-10-132023-10-13T04:00:00-04:002023-10-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-13:/coding-2023-10-13<p class="first last">Let's see if I can remember which names are supposed to be "the good ones"...</p>
<p>All right, I've made all of the obvious typing-related changes to MOTR's code.
If I'm not going to write tests for plugin-related cases I can't figure out how to hit, I guess I need to go between improving test coverage and improving names.</p>
<p>...</p>
<p>I suppose one other thing I can do is work on documenting the <tt class="docutils literal">saltate</tt> plugin thoroughly enough that I feel confident using it, and then getting test coverage up that way...</p>
<p>Anyway, I'll see what I'm up for later, because I'm really tired now.</p>
<p>Good night.</p>
Coding 2023-10-122023-10-12T04:00:00-04:002023-10-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-12:/coding-2023-10-12<p class="first last">Unanticipated benefit of rebuilding my environment: I get to up the version of requirements, and play with new toys.</p>
<p>Okay.
I managed to find an acceptable workaround for the Mypy 1.6 stuff, though I remain somewhat salty.
I did a merge up to future just to hopefully make subsequent merges a little less bad, and now I'm staring at the missing coverage in the plugins, thinking "Do I actually care? Is this a condition that can actually be hit?"</p>
<p>Probably the sensible thing to do for now is to focus on documentation and deriving test cases.
Then, later, I can reconsider these uncovered lines, and either figure out tests for them, or ask for help with those parts of the plugins.</p>
<p>...</p>
<p>Wait a sec.
I bumped the Python version in the dev environment.
That means I'm good to update more of the typing syntax.
Necessary, no, but nice-to-have, yes.</p>
<p>I'll get on that tomorrow, because right now I need to get to bed.</p>
<p>Good night.</p>
Coding 2023-10-112023-10-11T04:00:00-04:002023-10-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-11:/coding-2023-10-11<p class="first last">I have tried all of the workarounds that have been obvious to me so far.</p>
<p>I regret to inform that getting back into MOTR is super-cursed.
Things I ran into:</p>
<ul class="simple">
<li>It only works on Python 3.11 because of reasons.</li>
<li>I somehow managed to write the motrfile against a version that I never published, so I had to monkeypatch the internals at the beginning of the motrfile.</li>
<li>Mypy 1.6 has a behavior change that I want to call a regression.
Basically, it breaks using <tt class="docutils literal">overload</tt> and <tt class="docutils literal">singledispatchmethod</tt> together, under <em>some circumstances</em>.</li>
<li>The <tt class="docutils literal">saltate</tt> plugin had a bug, and I never noticed until I happened to throw together a test case that demonstrated it.
Unpleasantly, the bug was in one of the cases that aren't even a little hexed on a conceptual level, so I don't even have the excuse that the relevant behaviors are confusing; the code was just wrong, and it may still be wrong...</li>
</ul>
<p>I need to wrap up, because I'm having a bad time right now, and if I stay up any longer, I'll just make it worse.</p>
<p>Good night.</p>
Weekly Roundup 2023-10-102023-10-10T04:00:00-04:002023-10-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-10:/weekly-roundup-2023-10-10<p class="first last">Those were good ideas, maybe this is a bad idea...</p>
<ul class="simple">
<li>Wednesday: I got enough help to be comfortable switching to Kakoune.</li>
<li>Thursday: That said, there is still something wrong with my custom rc file. However, I decided to think about other things.</li>
<li>Friday: I pondered some more how to streamline my Python setup.</li>
<li>Saturday: I got enough pondered to be ready for the switchover, more or less.</li>
<li>Sunday: The switchover went off without a hitch. Neat.</li>
<li>Monday: Now that my Python setup isn't, like, kind of unreasonable, I considered trying to get back into Python development, which got me considering the elephant in the room...</li>
</ul>
<p>Next week, I'm going to be reviewing the code for MOTR again.
According to my memories, if I can get the <tt class="docutils literal">saltate</tt> plugin to be reasonable, then I shouldn't have any major trouble understanding and testing the rest of the new code.
So, it goes:</p>
<ul class="simple">
<li>Review the generic attrs code in Mypy, and check for any changes since I last touched the <tt class="docutils literal">saltate</tt> plugin.</li>
<li>Update the <tt class="docutils literal">saltate</tt> plugin and associated tests.</li>
<li>Once I have that working and covered, merge up to the documentation branch, study the diffs, and document anything that is confusing to me.</li>
<li>Use that knowledge to plan new tests.</li>
<li>Try to get to a point where I can finally cut new releases again.</li>
</ul>
Coding 2023-10-092023-10-09T04:00:00-04:002023-10-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-09:/coding-2023-10-09<p class="first last">Still working on tool setup, not much interesting to say.</p>
<p>I futzed around with tooling a bunch today.
I think I need to get back to writing in order to try this software out.</p>
<p>One thing I'm going to need to consider, as I look over this and think about doing Python development again, is whether I'm going to be comfortable with an existing task runner, or if I'm going to end up trying to revive MOTR, which may need some help to get running with the new stack.</p>
<p>Oh well, I tried to come up with much more to say, and I didn't.
We'll see how I feel about all of this later.</p>
<p>Good night.</p>
Coding 2023-10-082023-10-08T04:00:00-04:002023-10-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-08:/coding-2023-10-08<p class="first last">Nice to see prep work paying off.</p>
<p>Okay, if you're reading this, that means that switching my Python stack worked.
I believe I verified this earlier today, but one more test can't hurt.
I'm excited to see how my new systems work out, because I don't yet have much hands-on experience with them.
I'd like to say more about this, but it's late, and I don't know what else I'd say right now.</p>
<p>Let's see what I think of tomorrow.</p>
<p>Good night.</p>
Coding 2023-10-072023-10-07T04:00:00-04:002023-10-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-07:/coding-2023-10-07<p class="first last">When I get this all put together, it'll be interesting to see what kinds of things no longer happen and oblige me to go "This actually makes sense and is good, because of the reasons why."</p>
<p>I've put together all of the pseudocode I think I'll need to close the gaps in functionality I'll feel from switching off of pyenv.
I've looked up most of the information I'll need to translate that pseudocode into fish shell functions.</p>
<p>I should be good to carry out the switchover tomorrow, but I'd better do it early, because the code supporting this blog is easily the most convoluted environment I'm going to want to have up and running.</p>
<p>I'm trying to think of whether there's anything else from today that I'd lke to talk about now, and nothing comes to mind.
I'm going to go read.</p>
<p>Good night.</p>
Coding 2023-10-062023-10-06T04:00:00-04:002023-10-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-06:/coding-2023-10-06<p class="first last">Working more on tooling...</p>
<p>Okay, I kind of gave myself a rough time today, so I'm going to try to go a little easier on myself right now.</p>
<p>I mentioned yesterday wanting to rework my Python setup.
My goal is to put together a better experience than I have currently.
Right now, my Python installs are provided by pyenv, and, through a mix of existing and hand-rolled plugins, I manually-ish set up virtual environments for running scripts and having the requirements for projects.</p>
<p>Problems with this include: too many Pythons, and, relatedly-ish, something is always outdated.</p>
<p>One aspect that I don't have a plan for yet is that I can set a virtual environment per directory.
(I do have an idea, which is "copy the stuff I'm doing with <tt class="docutils literal">opam</tt>" ("and also try not to think too hard about how my OCaml tooling is set up in NeoVim but not Kakoune"))</p>
<p>Aside from that, though, here's the idea:</p>
<ul class="simple">
<li>Stop activating pyenv in my <tt class="docutils literal">config.fish</tt> file, but leave the entire directory tree in place</li>
<li>Get Python from deadsnakes PPA</li>
<li>Punt on installing PyPy because I don't use it for much</li>
<li>Configure pip to require an activated virtualenv</li>
<li>Create virtualenv for pipx and install it, set up shell integration</li>
<li>Install a bunch of binaries</li>
<li>Figure out the logic for directory-based virtualenvs, and do it</li>
</ul>
<p>All of that kind of has to be in one day so I can actually publish my post when I'm done, so I'm going to try to do that last step tomorrow, then pull the trigger on all of this over the weekend.
For now, I'm going to wind down.</p>
<p>Good night.</p>
Coding 2023-10-052023-10-05T04:00:00-04:002023-10-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-05:/coding-2023-10-05<p class="first last">Working on tooling...</p>
<p>I now understand Kakoune a little better, but I'm still doing something wrong, but, like, just exactly wrong enough that it seems to work perfectly when I paste the commands in, but fail when I run the command that eventually invokes them.
I haven't made sense of that yet; I'll formulate a question for IRC eventually.</p>
<p>Aside from that, I'm pondering reworking my Python setup; I have some ideas, but I need to do more research and go over exactly what my requirements are.
Regardless, I don't have it in me to write anything else now.</p>
<p>Good night.</p>
Coding 2023-10-042023-10-04T04:00:00-04:002023-10-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-04:/coding-2023-10-04<p class="first last">A lot of the functionality is questionable, but it's good enough to get on with.</p>
<p>Got some help from IRC, and now I'm blogging in Kakoune.
There are a few things I have yet to work out:</p>
<ul class="simple">
<li>What is the workflow for using <tt class="docutils literal"><span class="pre">next-hunk</span></tt> and <tt class="docutils literal"><span class="pre">prev-hunk</span></tt>?
I don't have any evidence that my code isn't translated properly, but the first issue to address is that I still don't know how to use the Git version.</li>
<li>I broke <tt class="docutils literal">annotate</tt> (<tt class="docutils literal">blame</tt>).
I'm not sure how, but I did.
For extra infuriation points, this is code that I specifically tested manually because it looked so gnarly, and it worked fine then!</li>
<li>There's probably other messed-up stuff in there that I don't know about.</li>
</ul>
<p>That said, it makes more sense to me to focus on getting more experience with Kakoune, and I can come back and try to fix the rc file later.</p>
<p>Aside from that, I'm going to try to wind down a little early tonight, because of scheduling nonsense.</p>
<p>Good night.</p>
Weekly Roundup 2023-10-032023-10-03T04:00:00-04:002023-10-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-03:/weekly-roundup-2023-10-03<p class="first last">Weird litte grab-bag there...</p>
<ul class="simple">
<li>Wednesday: I tried to sketch out Impliciula's AST based on vibes, and learned that sketching out an AST based on vibes is probably a bad idea.</li>
<li>Thursday: I discovered an OCaml feature that I hadn't suspected the existence of (in part because I'm not reading the documentation in any kind of order), and had to go lie down.</li>
<li>Friday: I figured out some of the things to be done with that feature, meaning that the presentational barriers to implementing it are probably down, so I just need to deal with the technical aspects...</li>
<li>Saturday: I started looking into what it would take to make pre-commit work with Mercurial along with Git. I would take <em>a lot</em>.</li>
<li>Sunday: I redid my towncrier fork for the heck of it.</li>
<li>Monday: A little more prep work for pre-commit, that has me thinking now that whatever cursed shims are required should probably exist in their own package, to avoid saddling the project with tech debt.</li>
</ul>
<p>Next week, I've got some ideas for what to work on, but I'm not totally sure yet.</p>
Coding 2023-10-022023-10-02T04:00:00-04:002023-10-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-02:/coding-2023-10-02<p class="first last">Getting through all of the basically easy stuff...</p>
<p>I would like my laptop to stop crapping out.
Not in the sense that it no longer turns on at all, mind you...</p>
<p>Anyway.</p>
<p>I finished the towncrier changes, but they're not tested, so what happens on usage is a surprise.
I've got it handy to mess with later, but I didn't actually have anything I want to use it with currently.</p>
<p>I went over the different hook types used by the pre-commit tool, and tried to match them up with the hooks provided by Mercurial.
The ways to do so are not always obvious...</p>
<p>Anyway, unless I find some guidance on Kakoune, I'm going to have to find something else to do next week.
I'll think about that some after I post this.
Nothing more to talk about tonight, though.</p>
<p>Good night.</p>
Coding 2023-10-012023-10-01T04:00:00-04:002023-10-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-10-01:/coding-2023-10-01<p class="first last">The several hundred commits from upstream are less of a problem, and more of an opportunity. Still a little bit of a problem, though.</p>
<p>All right.
Quick post because I got distracted.</p>
<p>I went through the syntax highlight in my <tt class="docutils literal">hg.kak</tt> file, and hopefully got it all properly updated.
Now all that remains to clear up is <em>when I can expect to usefully use</em> <tt class="docutils literal"><span class="pre">next-hunk</span></tt> and <tt class="docutils literal"><span class="pre">prev-hunk</span></tt>.</p>
<p>Failing that, since my account is in limbo, I took a look at towncrier.</p>
<p>It turns out my branch is so hopelessly out-of-date that it made more sense to make my modifications completely from scratch.
I've just gotten started with that, but I believe what I end up with is going to make more sense than my original modifications.
In part because I looked up a few more of Mercurial's help files, and in part because some code changes mean that my changes slot in a little more nicely, at least for now.</p>
<p>I'll try and get it all put together tomorrow, because it should hopefully be pretty quick, now that I understand the basics of what's changed.</p>
<p>Anyway, it's late and I should get to bed.</p>
<p>Good night.</p>
Coding 2023-09-302023-09-30T04:00:00-04:002023-09-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-30:/coding-2023-09-30<p class="first last">This kind of shouldn't be so hard, but oh well.</p>
<p>Sometimes I have simple desires with complicated realizations.
Like, what does it take for me to be able to get away with using Mercurial as a GitHub client?
One thing I want is Mercurial support in towncrier, which I have in a fork that is probably woefully out-of-date.</p>
<p>Somewhat more generally used, however, is pre-commit.
If I could install the pre-commit hooks in a clone made with hg-git, that'd be the dream.
Looking at the way the internal git module is used within the pre-commit repository...</p>
<ul class="simple">
<li>main.py: <tt class="docutils literal">git.get_root</tt>, <tt class="docutils literal">git.check_for_cygwin_mismatch</tt></li>
<li>story.py: <tt class="docutils literal">git.init_repo</tt>, <tt class="docutils literal">no_git_env</tt></li>
<li>staged_files_only.py: <tt class="docutils literal">get.intent_to_add_files</tt></li>
<li>commands/run.py: <tt class="docutils literal">git.get_changed_files</tt>, <tt class="docutils literal">git.get_all_files</tt>, <tt class="docutils literal">git.is_in_merge_conflict</tt>, <tt class="docutils literal">git.get_conflicted_files</tt>, <tt class="docutils literal">git.get_staged_files</tt></li>
<li>commands/autoupdate.py: <tt class="docutils literal">git.init_repo</tt>, <tt class="docutils literal">git.get_best_candidate_tag</tt></li>
<li>commands/try_repo.py: <tt class="docutils literal">git.head_rev</tt>, <tt class="docutils literal">git.git_path</tt>, <tt class="docutils literal">git.get_staged_files</tt>, <tt class="docutils literal">git.commit</tt></li>
<li>meta_hooks/check_hooks_apply.py: <tt class="docutils literal">git.get_all_files</tt></li>
<li>meta_hooks/check_useless_excludes.py: <tt class="docutils literal">git.get_all_files</tt></li>
<li>commands/install_uninstall.py: <tt class="docutils literal">git.get_git_common_dir</tt>, <tt class="docutils literal">git.has_core_hookpaths_set</tt></li>
</ul>
<p>But also a bunch of places that use git inline...</p>
<p>In addition, there are the questions of how to translate between "hooks are script files" and "hooks are configuration entries", and between different hook names.</p>
<p>Unfortunately, it's late now.
I'll see what I can get planned to do tomorrow.</p>
<p>Good night.</p>
Coding 2023-09-292023-09-29T04:00:00-04:002023-09-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-29:/coding-2023-09-29<p class="first last">Getting real tired of being jiggled around a bunch six times a week.</p>
<p>Okay.
Polymorphic variants.
I've come up with an expression syntax that I think is acceptable, and that I don't have anything else I'd want to use it for, so that's part of that language feature worked out: if I want it, it's possible to write the expressions concisely.</p>
<p>Now let's look at the types.
My whole "symbol to English translation" schtick means that <tt class="docutils literal">|</tt> becomes <tt class="docutils literal">or</tt> as usual; furthermore, <tt class="docutils literal">&</tt> seems like it should become <tt class="docutils literal">and</tt>, and <tt class="docutils literal">></tt> becomes <tt class="docutils literal">open</tt> and <tt class="docutils literal"><</tt> becomes <tt class="docutils literal">closed</tt>, maybe.
At least as a first draft.</p>
<p>I would like to get some hands-on experience with these ideas, but that's going to have to wait, because my energy levels just crashed.</p>
<p>Good night.</p>
Coding 2023-09-282023-09-28T04:00:00-04:002023-09-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-28:/coding-2023-09-28<p class="first last">Is this worth the trouble it would take to implement it, and to <em>have implemented it</em>?</p>
<p>My phone and my NAS conspired to delete a file I was working on, and the latest backup was missing stuff from yesterday, so I had to rewrite that section.
A little annoying, but whatever.</p>
<p>Anyway, let's take a look at how to put together a syntax...
Transcribing stuff from the OCaml reference, and...
Hold up...
What's a "polymorphic variant" <em>for</em>?</p>
<p>...</p>
<p>OCaml has type unions.</p>
<p>...</p>
<p>Why am I surprised?</p>
<p>Okay, before I do anything else here, I need to work out what I think this would look like in Impliciula.</p>
<p>...</p>
<p>It seems to me like I can either keep the lack of explicit declarations, but require a new sigil (and I'm now thinking about whether it's possible to avoid the sigil that I'm already using), or avoid a new sigil, but need some kind of special type declaration form.</p>
<p>I'm going to need to think about this more, to see if I want to do anything besides "not implement this".
But for now, I'm tired.</p>
<p>Good night.</p>
Coding 2023-09-272023-09-27T04:00:00-04:002023-09-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-27:/coding-2023-09-27<p class="first last">"Don't worry about it, I built it based on vibes." It collapses.</p>
<p>So, getting answers about Kakoune is <em>presumably</em> going to happen at some point.
I could try to work out the syntax highlighting, but I ended up thinking about Impliciula.</p>
<p>What I think makes sense for Impliciula is to translate my various ideas so far into a specification of the abstract syntax tree.
This has the advantage of being <em>mostly</em> isolated from the gambles I'm taking with the surface syntax.
This should end up being a relatively streamlined expression syntax, with some somewhat baroque statement syntax.</p>
<p>...</p>
<p>I was trying to kind of wing it and put together something equivalent to (a subset of) what OCaml can express from memory and vibes, and having tried that, I would recommend... not doing that.
When I have the energy and focus handy, I need to basically try to straight translate bits of the syntax specifications for OCaml and Koka.</p>
<p>Once I have the abstract syntax types, then I can experiment with developing a basic interpreter, to answer questions such as "can I actually give Impliciula a well-defined semantics?"
For now, though, I need to rest my eyes and get to bed.</p>
<p>Good night.</p>
Weekly Roundup 2023-09-262023-09-26T04:00:00-04:002023-09-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-26:/weekly-roundup-2023-09-26<p class="first last">I hope I never have to use some of the things I have learned for any other purpose than this.</p>
<ul class="simple">
<li>Wednesday: I wrote some standard library code in Impliciula, and considered how it was coming out.</li>
<li>Thursday: I got deep into a rabbit hole around naming and implementing "<tt class="docutils literal">fold</tt>" operations.</li>
<li>Friday: I developed more questions about how to do things in Impliciula, and started looking into other text editors, because at this point, I only use Neovim to write this blog.</li>
<li>Saturday: I finally realized that multimethods and gradual typing are a tricky combination. I also looked into Kakoune a bit.</li>
<li>Sunday: I thought more about Impliciula and Kakoune.</li>
<li>Monday: I replaced an AWK script in Kakoune with a shell invocation of Mercurial which constructs a Kakoune scripting command using a template. It was hard to face the world after that.</li>
</ul>
<p>Next week, I'm going to try to wrap up the Mercurial helper for Kakoune, and switch to using Kakoune for blogging, and try to switch back to it for things that I ended up using Kate for somehow.</p>
Coding 2023-09-252023-09-25T04:00:00-04:002023-09-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-25:/coding-2023-09-25<p class="first last">Don't try to think about how many levels of nesting that line has.</p>
<p>What remains to be done for the Mercurial helper for Kakoune:</p>
<ul class="simple">
<li>Figure out the differences between Git and Mercurial relevant to the syntax highlighting definitions.</li>
<li>Figure out how <tt class="docutils literal">jump_hunk()</tt> is supposed to, like, <em>do</em> anything.
Like, when do I want to be using the sub-commands that invoke this function?</li>
</ul>
<p>Other than that, it's overall been a pretty straightforward update with nothing too crazy.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last"><em>A-hem</em></p>
</div>
<p>Come on, they don't need to see—</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Paste the line, Max.</p>
</div>
<p>... <tt class="docutils literal"><span class="pre">evaluate-commands</span> %sh{ hg annotate <span class="pre">"$@"</span> <span class="pre">-T</span> <span class="pre">"set-option</span> global hg_annotate_flags <span class="pre">%val\{timestamp}{lines</span> % ' <span class="pre">\'{lineno}|{node|short}</span> {date|isodatesec} <span class="pre">{user|person}\''}"}</span></tt></p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Yay!</p>
</div>
<p>The eagle-eyed among you will notice that this should be slower than the code it's replacing, since I couldn't find an equivalent to the <tt class="docutils literal"><span class="pre">--incremental</span></tt> flag.
Eh, at least the code is shorter.</p>
<p>Anyway, quick Impliciula thought: I'm doubting that I can make "gradual typing in the sense of a particular shape of the type system" work, but maybe I can do "gradual typing in the sense of carrying out local type inference".
This is a compromise in terms of library design, but it should still allow tossing off short scripts without thinking too hard.</p>
<p>Anyway, I'm tired, and I'd like a good night's sleep without the vaccine side effects, so let's wrap this up...</p>
<p>Good night.</p>
Coding 2023-09-242023-09-24T04:00:00-04:002023-09-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-24:/coding-2023-09-24<p class="first last">I'm going to be really peeved if there was documentation on this code somewhere, and I just didn't know about it.</p>
<p>Quick thought on the problems I was pondering about Impliciula: possibly, values could be tagged with a type that includes all of the relevant information.
It's not obvious to me how this would get filled in under some circumstances, though.
I'm going to need to find papers on this kind of thing...</p>
<p>Anyway, I spent more effort today on my attempt to convert Kakoune's Git helper to Mercurial.
Currently, I'm trying to figure out what the AWK function in the blame handler does, and to what extent I can just, like, ignore it.
Like, it kind of looks like I should be able to construct the <tt class="docutils literal"><span class="pre">line-specs</span></tt> data directly using a properly laid-out template?
Hopefully I get that figured out in the next few days.
For the moment, I have to once again try to sleep off the vaccine side effects.</p>
<p>Good night.</p>
Coding 2023-09-232023-09-23T04:00:00-04:002023-09-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-23:/coding-2023-09-23<p class="first last">Right now, I've got hard problems, and annoying problems...</p>
<p>As I was thinking about other aspects of Impliciula, I realized that I've been glossing over an issue that has foundational implications: various features that I want depend on the exact type of expressions, which means that the resolution associated with those features has to happen before any type erasure.
I'm not sure what options I have for satisfying that kind of design constraint in a dynamic context.</p>
<p>My basic suspicion is that I outright cannot support dynamic multimethod resolution without something <em>really clever</em> to keep the type names under control.</p>
<p>Anyway, I'll keep thinking about whether there's some way around that, but aside from that, I've been looking at Kakoune's built-in Git scripting, and trying to convert it to Mercurial scripting.
Frustratingly, this involves getting a better understanding of Git, just so I know what some of the commands even are.</p>
<p>Frankly, with the vaccine side effects doing their thing, I'm a little amazed that I got as far as I did, and I'm going to wind down for now.</p>
<p>Good night.</p>
Coding 2023-09-222023-09-22T04:00:00-04:002023-09-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-22:/coding-2023-09-22<p class="first last">I will not be taking questions on how one "accidentally" does that.</p>
<p>Minor meta note: I somehow accidentally stopped using <a class="reference external" href="https://neovim.io/">Neovim</a> for most purposes.
<em>So</em>, while I'm in that situation, I figured I might as well look into alternatives.
I've been hearing stuff about <a class="reference external" href="http://kakoune.org/">Kakoune</a> and <a class="reference external" href="https://helix-editor.com/">Helix</a>, and because I literally only use Git in depth when I'm being paid for it, I decided to look into Kakoune since it should in theory be more amenable to getting it working with Mercurial and maybe Pijul.
But doing that means I <em>immediately</em> need to understand how to write a <tt class="docutils literal">.kak</tt> file, so that's... a thing.</p>
<p><em>Anyway</em>, I was thinking some more about the whole catamorphism rabbit hole I went down yesterday, and I realized something that I need to deal with...
Impliciula currently inherits Koka's usage of curly braces for blocks/anonymous functions, so it's not obvious to me how to make OCaml-style records work, but the <em>interesting</em> syntax I'm trying to make work means that I can't have Koka-style structs.
I have an inkling of an idea for how to make this work nicely, but it needs some time to stew.
I'll at least try to explain it for now...</p>
<p>I'm right now working under the assumption that blocks can have different internal semantics, and even syntax, in different contexts, where context is indicated by a prefix.
So, for example, a <tt class="docutils literal">signature</tt> block can contain a bare <tt class="docutils literal">type</tt> declaration, while a <tt class="docutils literal">structure</tt> block has to assign a type expression.
As such, the easy solution is to come up with "record" and "record type" blocks, and see if I can come up with better names.</p>
<p>I don't have anything else in me for tonight, so let's leave it there and hope I'm vaguely rested tomorrow.</p>
<p>Good night.</p>
Coding 2023-09-212023-09-21T04:00:00-04:002023-09-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-21:/coding-2023-09-21<p class="first last">This is <em>really confusing</em>, okay?</p>
<p>I tried to come up with a nice way to deal with some of the OCaml standard library code that I was having trouble translating to Impliciula, and I think I just made more problems for myself.</p>
<p>Here's the deal: various standard library types have a <tt class="docutils literal">fold</tt> function defined which, in the cases I've looked at, takes named arguments that are named after the different constructors for the type, and those arguments are functions that convert the relevant variants to a return value.
I was looking at this like "I do not want to figure out what kind of noun phrase would accommodate those parameters".
"... But what if, all of those named arguments were packed into a record type?"
At that point, the record type is *checks the giant pile of open web browser tabs* ... isomorphic to the evaluation function in an F-algebra?
I think?</p>
<p>Now, the normal way to define an F-algebra is to put together an endofunctor that, I think, represents the partially applied computation.
The equivalent with a record type for the evaluation function is to represent the partial evaluations as parameters of each function in the record.
So each function in the record would be receiving a destructured variant and the intermediate calculation, and those can be cut down based on the variant...</p>
<p>I'm going to need to try sketching implementations both ways, because I can't figure out whether I prefer to be closer to how the OCaml functions sort of look, or to the theoretical description.
Like, is it better for all implementors to put together a <tt class="docutils literal"><span class="pre">when-is-be</span></tt> block, or to construct it in one place per type using raw materials from everywhere?
The former is more flexible, but the latter was clearly (at least to me) good enough for OCaml.</p>
<p>Yeah, this is definitely something that I need to take a good, clear look at, which is not happening right now.
I should go to bed as soon as I can.</p>
<p>Good night.</p>
Coding 2023-09-202023-09-20T04:00:00-04:002023-09-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-20:/coding-2023-09-20<p class="first last">Punctuating run-on sentences with linebreaks. Sure.</p>
<p>I've written a bunch of Impliciula code.
It's not ready to show off yet, but it is making me question whether the whole "make code more like sentences than mathematical notation" concept is actually feasible.
Some of these lines are over 100 characters, so one thing I need to salvage this is some idea of where line breaks are workable from a parsing perspective, and helpful from a punctuation perspective.
I just tried something that looks helpful, but it's still all a little breathless.</p>
<p>Syntax aside, something occurred to me about semantics:</p>
<p>If I keep up the whole gradual typing idea, then code that isn't being accelerated should need to specify the resume behavior of effects at definition time.
I think.
Like, yes, when the code is being accelerated, it's helpful to guarantee that the fastest/smallest paths allowable get baked in, but in the dynamic regime, the handlers need to be tracked dynamically, so...</p>
<p>Maybe the way to do this is to just allow using <tt class="docutils literal">_</tt> when specifying what kind of resume behavior an effect has...</p>
<p>In any case, I guess I should focus on the effect syntax, because once I have a version of that that I'm comfortable with, I can put out some more concrete stuff here and elsewhere.</p>
<p>Anyway, I should stop looking at my screen.</p>
<p>Good night.</p>
Weekly Roundup 2023-09-192023-09-19T04:00:00-04:002023-09-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-19:/weekly-roundup-2023-09-19<p class="first last">Just got to keep going...</p>
<ul class="simple">
<li>Wednesday: I asked for some help with Impliciula. As of now, there have been... no takers.</li>
<li>Thursday: I thought about a new project that I could start.</li>
<li>Friday: I was tired.</li>
<li>Saturday: I had brain fog.</li>
<li>Sunday: One of my ideas for dealing with the brain fog didn't work out, so we kind of tweaked it, and we'll see at some point.</li>
<li>Monday: I don't want to go into details, but it sucked, and continues to suck.</li>
</ul>
<p>Next week, I might have it in me to sketch out standard library modules for Impliciula.
It'd be nice if someone expressed interest, but maybe I can just inflict them on a Discord server or some part of the fediverse.</p>
Diary 2023-09-182023-09-18T04:00:00-04:002023-09-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-18:/diary-2023-09-18<p class="first last">At some point, life will run out of curveballs...</p>
<p>Well, I got some bad news today.
Something that I thought was bad, was actually worse.
Oh well.
Nothing to be done for now, so far as I know.</p>
<p>Aside from that, I'm trying to balance "needing to take things easy" with "wanting to get work done on <em>something</em>".
I think I did all right today, but I'll do better if I just cut things short now.</p>
<p>Good night.</p>
Diary 2023-09-172023-09-17T04:00:00-04:002023-09-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-17:/diary-2023-09-17<p class="first last">Some really frustrating days for me.</p>
<p>Well, the ways I tried to improve things today didn't really work out, but we've got something slightly different that we're going to try later.
Just need to take things a day at a time and not try to rush to the end, I guess.</p>
<p>Relatedly, I did get some other stuff done today, although I would have liked to have done more.
Oh well.</p>
<p>I should stop writing and try to wind down.</p>
<p>Good night.</p>
Diary 2023-09-162023-09-16T04:00:00-04:002023-09-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-16:/diary-2023-09-16<p class="first last">I'm going through stuff, I guess.</p>
<p>Ugh...</p>
<p>I really want to work on stuff, but my mind feels... tangled.
Like a tightly wound spring that's rusted together.</p>
<p>I'm trying to think of ways to get out of this state, and there are some things I can try, but the only sensible course of action to begin with is to cut this entry off here and get some sleep.</p>
<p>Good night.</p>
Diary 2023-09-152023-09-15T04:00:00-04:002023-09-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-15:/diary-2023-09-15<p class="first last">i cri evry tiem</p>
<p>Tired...</p>
<p>Just wanna sleep forever...</p>
<p>Not gonna get to...</p>
<p>Good night.</p>
Diary 2023-09-142023-09-14T04:00:00-04:002023-09-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-14:/diary-2023-09-14<p class="first last">Secrets...</p>
<p>Hm.
This is awkward.
I was coming up with stuff to work on later, but I don't really have much to talk about from that yet...</p>
<p>I mean I guess I can drop a few things in here...
I want to retool Missable Mysteries, in part because I'm no longer vibing with the name.
Ideally, I want something that is a little more up-front about its currently hidden agenda, which is to armchair-diagnose a celebrity with dyscalculia.</p>
<p>But I had some thoughts about math stuff I could talk about without having a weird hidden agenda, and I'm currently trying to put together an outline for "alternative representations of numbers, especially ones that easily express things that we don't normally think of as numbers".
Like "a notation that treats numbers as a special case of matrices" or "this is an extension to (a subset of) the rationals, which breaks ordering, but <em>not</em> the way that complex numbers do".
One thing I need to work out with this idea is how much theory to frontload...</p>
<p>Anyway, I've got nothing else in me for today, so it's time to wrap up.</p>
<p>Good night.</p>
Coding 2023-09-132023-09-13T04:00:00-04:002023-09-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-13:/coding-2023-09-13<p class="first last">Please take a look; I don't think I can do this alone.</p>
<p>I've decided that I don't see a way forward for Impliciula without someone to discuss it with, so I put out posts on <a class="reference external" href="https://cohost.org/mwchase/post/2825088-request-for-someone">Cohost</a> and <a class="reference external" href="https://im-in.space/@mwchase/111055743741723732">Mastodon</a> asking for anyone who's interested in discussing a weird programming language idea.
If that describes you, please take a look.</p>
<p>Anyway, I spaced out until it was way late, so I'm not going to post anything else.</p>
<p>Good night.</p>
Weekly Roundup 2023-09-122023-09-12T04:00:00-04:002023-09-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-12:/weekly-roundup-2023-09-12<p class="first last">Maybe I should have done less, I don't know...</p>
<ul class="simple">
<li>Wednesday: I looked over some of the fiddly corners of OCaml's syntax.</li>
<li>Thursday: I looked at Koka, specifically the syntax for defining effects. I don't know what most of it does.</li>
<li>Friday: I thought a little about how to handle effects.</li>
<li>Saturday: I chilled out because I was feeling terrible.</li>
<li>Sunday: I had some ideas about how to divide up the kinds of effects.</li>
<li>Monday: I had some thoughts about what effect syntax would be compatible with how I'm planning to make the syntax of Impliciula.</li>
</ul>
<p>Next week, I'm not sure what I'll be focusing on.</p>
Coding 2023-09-112023-09-11T04:00:00-04:002023-09-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-11:/coding-2023-09-11<p class="first last">It's good enough, I think.</p>
<p>Quick thoughts about how to do effects in Impliciula:</p>
<ul class="simple">
<li>The form of the effects has to be visible at the handler definition somehow.</li>
<li>I think this "should" be done with something akin to a match construction.</li>
<li>And a perform builtin to dispatch the effect.</li>
<li>This does prevent the development of the <tt class="docutils literal">val</tt> sugar.</li>
<li>It would be nice to be able to construct handlers as values.</li>
<li>However this works, it goes in a block construct...</li>
</ul>
<p>These handler ideas sound about right, and I suppose the perform idea is about right...</p>
<p>Potentially effect interleaving could be handled by some form of newtype wrapper?
That's probably not scalable, but I'm not sure.
I don't fully understand the approach that the paper I was reading was taking, so I don't think I can come up with something comparable yet.
I'll have to keep on reading that paper, I guess.</p>
<p>Anyway, it is very late now.</p>
<p>Good night.</p>
Coding 2023-09-102023-09-10T04:00:00-04:002023-09-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-10:/coding-2023-09-10<p class="first last">The pitch for this stuff works really easy on me, but actually designing it? Hard.</p>
<p>It's late, but I want to see what I can do quickly to lay the groundwork for working on the effect system later.</p>
<p>The minimal effect system in terms of syntax is to simply have one way to define operations.</p>
<p>This is problematic for two related reasons, both deriving from the fact that I want expressive power on the level of Koka for this:
Effects that strong use a continuation that can be called arbitrarily many times, which means that the straightforward implementation would have to basically use "heap frames" instead of stack frames, which would both make performance pretty bad in general, and complicate reasoning about behavior.</p>
<p>(Another issue with having such "simple" syntax is that it doesn't allow for specifying that a particular operation should be handled by a handler other than the nearest one.)</p>
<p>One possible course of action that occurs to me is to try to express this stuff in terms of modular implicits somehow.
I'm not totally sure if that makes sense, but let's see...</p>
<p>Doing stuff with "normal" modular implicits means that you're relying on matching up an implicitly available module to the input types, and <em>potentially</em> that module could define functions with effects.
One question I need to consider is whether it works to vary the effects in different versions of the module...
I <em>think</em> that kind of thing at least needs to be considered with modules in general, so, just as a module can define a type, a module can also define an effect.</p>
<p>Okay, trying to get past that diversion, what matters is that <strong>a function that has an effect, is relying on its caller to provide a handler; that handler can be given various abilities to resume the computation</strong>.
My quick read on what are possible amounts of resumption to allow is that the cases that are meaningfully distinct are "never, once, more than once".
These can come together as:</p>
<ul class="simple">
<li>Resumption is never allowed.</li>
<li>Resumption is allowed up to once.</li>
<li>Resumption is allowed an arbitrary number of times.</li>
<li>Resumption is allowed exactly once.</li>
<li>Resumption is allowed once or more.</li>
</ul>
<p>"It must be resumed more than once" doesn't sound sensible, so I'm going to put it aside for now.</p>
<p>One of the things I need to understand here is, what assumptions I need to relax when considering multiple resumption...</p>
<p>And I think I need to read over the Koka documentation again to understand what questions I should even be asking...</p>
<p>Anyway, that's all I have time for right now.</p>
<p>Good night.</p>
Diary 2023-09-092023-09-09T04:00:00-04:002023-09-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-09:/diary-2023-09-09<p class="first last">This was not a day for doing things.</p>
<p>So, I had (or have) a migraine, and I took measures to deal with it.
They seem to have worked, but they do mean that I lack the focus to write in any detail.
We'll see what I'm capable of tomorrow, but I can tell that "trying harder" isn't going to do anything in the next hour, so, like, don't push myself.</p>
<p>Good night.</p>
Coding 2023-09-082023-09-08T04:00:00-04:002023-09-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-08:/coding-2023-09-08<p class="first last">Small insight, but skippable.</p>
<p>I had a bit more of a look at the paper I mentioned last entry, and I've come to the conclusion that I'm probably not going to get anywhere unless I start putting together strawman syntax and semantics examples.</p>
<p>Anyway, I am sick or something so I'm going to go lie down byyyyyyye.</p>
<p>Good night.</p>
Coding 2023-09-072023-09-07T04:00:00-04:002023-09-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-07:/coding-2023-09-07<p class="first last">I'm not even sure I'm reading the right paper.</p>
<p>I'm looking at the Koka documentation on effects, and here are the way things look offhand:</p>
<ul class="simple">
<li>An effect can be <tt class="docutils literal">named</tt>.</li>
<li>An effect can be <tt class="docutils literal">linear</tt>.</li>
<li>An effect can be <tt class="docutils literal">rec</tt>ursive.</li>
<li>An effect can have a "kind".</li>
<li>An effect can be "in" a type.</li>
<li>An effect can define any number of operations, including zero.</li>
<li>An operation can be <tt class="docutils literal">pub</tt>.</li>
<li>An operation can be <tt class="docutils literal">val</tt>, <tt class="docutils literal">fun</tt>, or <tt class="docutils literal">ctl</tt></li>
</ul>
<p>...</p>
<p>A handler can define a <tt class="docutils literal">finally</tt> clause, even though <tt class="docutils literal">finally</tt> is also a function???
Like, Impliciula would be able to get away with this, because one would be spelled <tt class="docutils literal">finally</tt> and one would be spelled <tt class="docutils literal">finally::</tt>, but Koka has more conventional syntax, so I'm confused.</p>
<p>Anyway, I'm trying to read about the implications of all of this, but it's late and I'm tired.</p>
<p>Good night.</p>
Coding 2023-09-062023-09-06T04:00:00-04:002023-09-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-06:/coding-2023-09-06<p class="first last">Going to have to keep in mind that "wanting the documentation to make intuitive sense" won't be enough to make it so.</p>
<p>I decided to switch back to Impliciula, and there's a <em>chance</em> that I'll switch back again soon because... one sec.</p>
<p>So, because I've got rough equivalents for a lot of OCaml syntax together, I went through the language extensions to see what I need to figure out how to include.
There are a few definite yeses, a few things that sound important, and a few things that sound mainly like the horrifying stuff that people figured out how to do with the <tt class="docutils literal">coding:</tt> directive in Python.</p>
<p>I don't understand all of the extensions, in part due to the intensely abbreviated presentation in that part of the manual, but I've got initial notes on all of the extensions, even if one extension just got notes of "Yo what the fuck".</p>
<p>Now, I need to put some time into reviewing Koka's syntax and shoring up my understanding.</p>
<p>Note to self, document an "explicit subset" of Impliciula's syntax when the time comes, and then gradually explain how to abbreviate that.
That seems like it would <em>hopefully</em> be less mysterious than the presentation of the Koka book.
Although, maybe the Koka book just feels like that to me when I'm trying to use it as "the wrong kind of documentation"?
I'll think about all of that later, starting with "how should defining and handling effects look?"
(One thing I'd like to keep in mind is whether it's possible to somehow describe "effects that only propagate outwards", if that makes any sense.
Like, if I want to use a comparison function that logs to somewhere.)</p>
<p>Anyway, I'm not getting anything else done right now.</p>
<p>Good night.</p>
Weekly Roundup 2023-09-052023-09-05T04:00:00-04:002023-09-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-05:/weekly-roundup-2023-09-05<p class="first last">That was a good gear-switch.</p>
<ul class="simple">
<li>Wednesday: I switched gears to writing, and described some of the stuff I'm working through with Sundered Empire.</li>
<li>Thursday: I continued on with that.</li>
<li>Friday: I did a bit more writing, and pondered whether I'm going to end up cutting a bunch of the stuff that I was working on.</li>
<li>Saturday: I mentioned some of the character traits I hope to avoid, and pondered what's necessary to avoid overcorrection.</li>
<li>Sunday: Travel, but I published the chosts.</li>
<li>Monday: Tired.</li>
</ul>
<p>Next week, I don't yet know what I'll feel like working on.
We'll see.</p>
Diary 2023-09-042023-09-04T04:00:00-04:002023-09-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-04:/diary-2023-09-04<p class="first last">Feel free to skip.</p>
<p>I didn't end up doing anything worth writing about today, so I'm just going to have another short nothing entry.</p>
<p>Good night.</p>
Diary 2023-09-032023-09-03T04:00:00-04:002023-09-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-03:/diary-2023-09-03<p class="first last">There's not much... here.</p>
<p>We traveled today, and I don't feel great.
But I decided to shove all my Cohost drafts out the door, so here's <a class="reference external" href="https://cohost.org/mwchase">my Cohost</a>.
Have a look, see what you think, comment on it if you have an account.</p>
<p>I don't think I have anything else to say.</p>
<p>Good night.</p>
Diary 2023-09-022023-09-02T04:00:00-04:002023-09-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-02:/diary-2023-09-02<p class="first last">One time the original She-Ra cartoon managed to do a White Savior episode with only pale-skinned characters. I think about that sometimes.</p>
<p>Getting to some good stuff in writing, but I need to think some about where to take it next.
I've got some travel and stuff coming up in the next few days, so maybe I'll end up switching gears for a bit again soon.</p>
<p>One thing I'll need to ponder is a way to give the original main character a chance to shine again.
The (not-quite-drafted) introductory sequence has them doing cool stuff, and then being brought low.
I'm going to need to figure out how to showcase their skills, because they're mostly way outside of a context where their skills would reasonably apply.</p>
<p>Like, this is pulp-inspired, and I'm trying to avoid the "hypercompetent outsider" concept, but they should be good for something besides moral support.
I'll have to think about this.</p>
<p>Good night.</p>
Diary 2023-09-012023-09-01T04:00:00-04:002023-09-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-09-01:/diary-2023-09-01<p class="first last">Asymptotically approaching the "explaining nuclear physics in caveman speak" bit.</p>
<p>I got a bit more writing done.
Once I get the lines I want written, maybe I should skip ahead a bit, because it feels a little like I'm spinning my wheels here.</p>
<p>Like, I'm concerned with whether the new stuff I'm writing is fulfilling to read, whether it's adding anything beyond a recap of what the reader recently read.
I may be accidentally recreating the conventions related to the serialized nature of the kind of science fiction I'm trying to emulate.
And, if so, is that a problem?
Maybe I should try to figure out a way to release this stuff serially?
I dunno.</p>
<p>Anyway, I am tired and I don't want to prolong this post.</p>
<p>Good night.</p>
Diary 2023-08-312023-08-31T04:00:00-04:002023-08-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-31:/diary-2023-08-31<p class="first last">"Being-in-space deficiency" is admittedly a weird way to express the concept of "muscular and skeletal atrophy", but I stand by it.</p>
<p>I haven't heard anything about <em>not making us go into the office for, frankly, no good reason</em>, even as the trend lines bend back upwards.
This sucks.</p>
<p>I tried to distract myself from that by doing some writing.
I've gone a but further forward in the Sundered Empire stuff, at least chronologically, but I keep on setting the characters challenges and puzzles that then I have to figure out how they'd tackle them.</p>
<p>Like, okay, someone shows up from space, and, through heroic efforts at communication, conveys to you that they were sent to do something, and whether they succeed or fail, both outcomes are bad.
What do you do with that information?
How do you determine whether they're running some kind of con?
Suppose it seems reasonable that the outcomes would be, in fact, bad, but it's not clear whether those outcomes will actually come about.</p>
<p>I suppose also I'm worried that all of this caution might read as strange to some of the audience, but I think it makes sense, and I don't want things to go super-easy for the main characters.
I'm definitely not going to take it as far as "and now they have a knock-down brawl", not least because the one from space needs physical therapy to deal with being-in-space deficiency.</p>
<p>I guess I'll just have to sleep on it.</p>
<p>Good night.</p>
Diary 2023-08-302023-08-30T04:00:00-04:002023-08-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-30:/diary-2023-08-30<p class="first last">"Isotopes on planet, like fingerprint in chemicals."</p>
<p>Well, I'm still <em>thinking</em> about Impliciula, but I don't think I'm up for the amount of documentation I'd need to read to figure out what capabilities it needs to have, and how they should be expressed.</p>
<p>So, writing.
I have no idea how well I did on the scene I'm drafting currently, but it's not something I have much experience with, so that's interesting to me.
Two characters are trying to communicate, but they have one language in common, which neither of them are entirely fluent in.
One has a broad vocabulary but mostly uses the language informally, resulting in "uneducated-sounding" grammar.
The other can remember what words mean after hearing them used, but as far as speaking, can only remember entire sentences meant to be used as cocktail-party witticisms.</p>
<p>I'm trying to go for a contrast between an expert in various matters who ends up talking "like a caveman", and someone who can sound "high-bred" but has minimal relevant knowledge.
I don't know how well I pulled it off, but whatever.
The one thing I still want to do in this area is to have a technobabble lecture in caveman-speak.</p>
<p>But for now, I need to get to bed.</p>
<p>Good night.</p>
Weekly Roundup 2023-08-292023-08-29T04:00:00-04:002023-08-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-29:/weekly-roundup-2023-08-29<p class="first last">I worked on this stuff just enough to feel like I don't want to for a while.</p>
<ul class="simple">
<li>Wednesday: I did some work considering how to get syntax highlighting for Impliciula in Cohost.</li>
<li>Thursday: I did some work specifically on the lexer needed for syntax highlighting.</li>
<li>Friday: I improved the lexer.</li>
<li>Saturday: I filled in some more gaps in the lexer.</li>
<li>Sunday: I figured out the answer to a bunch of technical issues with Cohost.</li>
<li>Monday: I decided to take a break from this, and work on something else.</li>
</ul>
<p>Next week, I'm going to somehow blog about the stuff I'm writing.</p>
Diary 2023-08-282023-08-28T04:00:00-04:002023-08-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-28:/diary-2023-08-28<p class="first last">Just trying to be in tune with my intuitions about when to drop something for like a week or two.</p>
<p>After all of the Cohost stuff I worked out, I still need to give those drafts some editing passes, but I don't wanna...
So, for this next week, I'm going to try to focus on writing, to take my focus off the Cohost drafts.</p>
<p>I'm going to need to work on having stuff to say about this writing, or the next week's worth of entries are going to be <em>really boring</em>.
Oh well.</p>
<p>I'll see what I can do right now, then get this published.</p>
<p>The setting for the story I'm working on is called the Sundered Empire.
Centuries before the story starts, the lines of communication and commerce in an interstellar empire were severed by a series of rebellions, dividing the empire into many smaller states.
In the years since, the different states developed their own identities; when the connections began to be re-established, the different states refused to re-integrate.
At the time the story starts, fully reunifying the empire is a pipe dream, a topic of idle conversation among the upper class.
However, one ambitious noble comes across hints of lost technology that could obliterate the borders between the states, and enlists the services of a legendary thief to recover it.
The trail leads to a planet that has been left alone since the time of the Sundering, where the thief meets and eventually befriends an accomplished polymath who leads a small tribe living in the jungle.
<em>Stuff happens</em>, and then they discover the lost technology and turning it on makes everything more complicated and precarious.</p>
<p>So, um, that's the first book, and, spoilers, maybe, I dunno.
My hope is that I can get the readers through the whole "legendary thief on a strange planet" plot without ever <em>overwhelming</em> them with the "former empire" backstory.</p>
<p>We'll see how I do with expanding on that summary in a few days.</p>
<p>Good night.</p>
Diary 2023-08-272023-08-27T04:00:00-04:002023-08-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-27:/diary-2023-08-27<p class="first last">Closing in on publishing these posts...</p>
<p>I've gotten the prototype highlighter working well enough, for now, so I decided to try to get its output usable with Cohost.
After smacking my head against it a bunch, I found the things that need to be done to use Pygments with Cohost:</p>
<ul class="simple">
<li>Use the "Lightbulb" theme, or a similar dark theme.</li>
<li>However, replace the line number colors with whatever is the "default" color according to the scheme.</li>
<li>Replace all linebreaks in the HTML output with <tt class="docutils literal"><br></tt> tags.</li>
</ul>
<p>The result looks a little weird to me, but it should serve.</p>
<p>Anyway, I got distracted and it's late, going to bed now byyyyyye</p>
<p>Good night.</p>
Coding 2023-08-262023-08-26T04:00:00-04:002023-08-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-26:/coding-2023-08-26<p class="first last">Computers... :(</p>
<p>Okay, I'm not in the mood to make all of the decisions that need to be made, but I started messing with the lexer prototype, and let's see what's missing:</p>
<ul class="simple">
<li>Strings</li>
<li>Numbers</li>
<li>Arithmetic operations</li>
<li>semicolons</li>
<li>arrow</li>
<li>something about lists?</li>
</ul>
<p>I got drafts for most of that, except for lists.
Also I should have comments, which is going to end up being a whole other thing...</p>
<p>Nevertheless, I think I'm at the point where I can put together short snippets and have some highlighting.
And, trying it out with my color scheme and...
Wow.
That's terrible.
Like I should maybe re-evaluate the color scheme I'm using for this blog, because "half the keywords, and the function invocations and variable names all get <em>identical</em> highlighting" is a ridiculous scenario to end up in.</p>
<p>I'll try to get something that makes sense tomorrow...</p>
<p>...</p>
<p>I got sidetracked, and tried to make the theme from scratch, and I ended up with something nearly as bad as my custom theme, from modifying one of the bundled ones.</p>
<p>I'm going to try to ask for help.
We'll see how that goes, but also I need to get ready for bed.</p>
<p>Good night.</p>
Coding 2023-08-252023-08-25T04:00:00-04:002023-08-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-25:/coding-2023-08-25<p class="first last">Not much actual content, but whatever.</p>
<p>Okay, I put together the chart, and iterated on it a bunch to write the necessary regexes for the prototype lexer.
It's missing <em>a lot</em> of stuff I'm going to want down the line, but I'm trying to pick my battles.
And the regexes are totally normal, nothing strange here.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">You wrote a biblically accurate emoticon.</p>
</div>
<p>Come on, <tt class="docutils literal"><span class="pre">(?::(:{SEGMENT}:)*:?)</span></tt> isn't <em>that</em> bad...</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">That is 100% an angel named, like, Ixushavel, with the caveat that nobody who actually knows Hebrew was consulted on this point.
And attempting to copy the "derivation" that "justifies" that name indicated that Hebrew almost certainly doesn't work like that.
Or possibly that easily-available machine translation is being pushed past its limits.</p>
</div>
<p>Anyway, I should be good to test whether this actually works now.
And once I've confirmed the basic cases, I can shore up some of the details I haven't covered yet, and then get back to the CSS Weeds.</p>
<p>For now, I need to get to bed.</p>
<p>Good night.</p>
Coding 2023-08-242023-08-24T04:00:00-04:002023-08-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-24:/coding-2023-08-24<p class="first last">Something something, it's (not) about sending a message.</p>
<p>Okay.
I want to write a lexer for Impliciula.
For that, I need test cases.
Let's start listing things.
In each case, assume the whitespace is needed but I don't really care how it lexes.</p>
<ul class="simple">
<li><tt class="docutils literal"><span class="pre">list-of:</span> 'a</tt>: function-inline-right, type-variable</li>
<li><tt class="docutils literal"><span class="pre">list-of:</span> int</tt>: function-inline-right, name</li>
<li><tt class="docutils literal">nil</tt>: name</li>
<li><tt class="docutils literal">head: head <span class="pre">and-tail:</span> tail</tt>: function-inline-right, name, function-inline-right, name</li>
<li><tt class="docutils literal"><span class="pre">for-all-e-in:</span> list e: <span class="pre">::is-even</span></tt>: function-inline-right, name, function-inline-right, function-prefix-left</li>
<li><tt class="docutils literal"><span class="pre">there-exists-an-e-in:</span> list <span class="pre">such-that-e:</span> <span class="pre">::is-even</span></tt>: function-inline-right, name, function-inline-right, function-prefix-left</li>
</ul>
<p>Pause here to note that I will consider goofy unicode abbreviations for those, so they're more like <tt class="docutils literal"><span class="pre">∀-e-in::e::</span></tt> and <tt class="docutils literal"><span class="pre">∃-e-in::st-e::</span></tt> (which have to be function-prefix-left, function-prefix-left unless I want to devise Cursed Tokens <em>or</em> if I don't indicate the side on the prefix form, and let it contain multiple parts, in which case it's function-prefix, and that above is function-prefix-left instead of function-prefix)</p>
<p>The problematic cases come in with partial evaluation.
Like, if I want to apply <tt class="docutils literal"><span class="pre">for-all-e-in::e::</span></tt> to the predicate, can that be <tt class="docutils literal"><span class="pre">for-all-e-in::</span> e: <span class="pre">::is-even</span></tt>, or does it have to be <tt class="docutils literal"><span class="pre">for-all-e-in:</span> : e: <span class="pre">::is-even</span></tt>?
I really want to make the former work, but that would seem to mean that function-prefix-right, function-inline-right, function-prefix-left is a valid call.
I can't "simply" lex the freestanding colons separately because otherwise I think the inline-right, prefix-left sequence is instead something really messed up.
I think I'd like to allow the prefix version to contain double colons, because the alternative is to just split it into a bunch of prefix-rights.
Prefix-left can only be a single segment, and prefix-right and prefix-right-left end in double colon and can maybe contain multiple segments.</p>
<p>I'm going to need to make some kind of Punnett square for the token types I'm trying to come up with here.
Not a Punnett square.
Um...
I dunno.</p>
<p>I'm going to wrap up, and doodle that chart while this publishes.</p>
<p>Good night.</p>
Diary 2023-08-232023-08-23T04:00:00-04:002023-08-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-23:/diary-2023-08-23<p class="first last">This may be too clever, at least for me.</p>
<p>The Cohost writing is almost done.
It just wants some syntax examples.
Which means I need to write the lexer.
Which means I need to figure out if my current ideas actually lex.</p>
<p>The issue I need to work out focuses on two special values I need to handle.
The simple part is that I want <tt class="docutils literal">_</tt> to be handled specially, but the special handling doesn't need to be in the lexer, so whatever.
The complicated part is...</p>
<p>So, I'm trying to base the function syntax off of Smalltalk, sort of.
And one of the "great" ideas I came up with was to use <tt class="docutils literal">:</tt> not just as a terminator (and sometimes starting character) for parts of a function name, but to represent an unevaluated function using <tt class="docutils literal">::</tt> instead, so <tt class="docutils literal">:</tt> is used to indicate partial evaluation.
(The starting character version is because I decided that I wanted to allow having an argument before the function name.
Smalltalk doesn't have to specially represent this because—OH MY GOSH, LOOK OVER THERE)</p>
<p>So, the idea is that there will be functions like <tt class="docutils literal"><span class="pre">:is-even</span></tt> which can be delayed by writing as <tt class="docutils literal"><span class="pre">::is-even</span></tt>, and <em>part</em> of my uncertainty about all of this is how to put everything into a nice canonical form.</p>
<p>Anyway, it's too late for me to think about all of this, so I'm going to wrap up.</p>
<p>Good night.</p>
Weekly Roundup 2023-08-222023-08-22T04:00:00-04:002023-08-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-22:/weekly-roundup-2023-08-22<p class="first last">That travel really disturbed things, but it was worth it.</p>
<ul class="simple">
<li>Wednesday: I complained about my laptop being messed up for over an hour, then made plans for how to get feedback on NABTO, now called Impliciula.</li>
<li>Thursday: I started drafting entries elsewhere.</li>
<li>Friday: We traveled.</li>
<li>Saturday: I did the stuff that we traveled for.</li>
<li>Sunday: I did some work on the drafts, but started encountering issues that I don't fully understand yet.</li>
<li>Monday: More drafting, and we traveled back.</li>
</ul>
<p>Next week, I'm going to try to finish up the drafts.</p>
Diary 2023-08-212023-08-21T04:00:00-04:002023-08-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-21:/diary-2023-08-21<p class="first last">Note to self: do not read computer science papers at 11:50 PM.</p>
<p>All right, I did some more Cohost writing, and we traveled back.</p>
<p>The Cohost writing feels weird.
It's been so long since I properly drafted a blog post ahead of time.</p>
<p>I'm going to need to find editors for this to force me to confront issues like "I'm not actually explaining anything".
Maybe I can just let the initial versions be kind of bad, and revise them after publishing if anyone pays attention?</p>
<p>Either way, for now I need to get to bed.</p>
<p>Good night.</p>
Diary 2023-08-202023-08-20T04:00:00-04:002023-08-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-20:/diary-2023-08-20<p class="first last">The CSS Weeds are no fun...</p>
<p>I slept way in today.
I was able to make some progress on the chost drafts.
I think with a few more days worth of work, I'll be ready to post them.
Although, maybe I'll want to have syntax examples, so that's going to push the estimates out a bit.</p>
<p>Mentioning that sent me out into the CSS Weeds.
The short of it is, I'm not sure how to make Pygments play nice with Cohost's CSS restrictions.</p>
<p>I got as far as "remove usage of CSS variables", but at this point the style still has all kinds of Problems.
Like, something somewhere in the box model for what I'm trying to do is Too Chunky, but I haven't had the wherewithal to methodically track down what's going on there.</p>
<p>I'll try to work out what's going on there later, but for now I should get to bed.</p>
<p>Good night.</p>
Diary 2023-08-192023-08-19T04:00:00-04:002023-08-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-19:/diary-2023-08-19<p class="first last">Let's see how much relaxation I can get in this weekend.</p>
<p>The day has been accomplished.
In the end, I wasn't up for doing my own thing much, but whatever.
I wrote a few more stubs for Cohost; at this point, I'm going to try to get all of the stubs filled in over the next week or so.</p>
<p>I don't have it in me to do anything else today, though.</p>
<p>Good night.</p>
Diary 2023-08-182023-08-18T04:00:00-04:002023-08-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-18:/diary-2023-08-18<p class="first last">All wound up and nothing to write.</p>
<p>Traveled, not up for much.
I kind of anticipated this, so I'm just going to chill.
We'll see how tomorrow works out for me, but I'm not really sure what to expect.
I assume we should have the end of the day pretty free, but maybe that's totally wrongheaded.</p>
<p>I really really need to just listen to some music or something, so I'm going to wrap this up now.</p>
<p>Good night.</p>
Diary 2023-08-172023-08-17T04:00:00-04:002023-08-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-17:/diary-2023-08-17<p class="first last">Banking up writing for elsewhere...</p>
<p>I futzed around some with post drafts on Cohost.
I don't have anything to put up there yet, but with a few more days of tweaking (not necessarily <em>these</em> next few days), I should be at a point where I'm comfortable publishing all of my posts and angling for feedback.</p>
<p>I still need to decide what to do with the various bits of software that I'm going to want in order to support early discussion...</p>
<p>Good night.</p>
Coding 2023-08-162023-08-16T04:00:00-04:002023-08-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-16:/coding-2023-08-16<p class="first last">It turns out I can't just will a fully-architected software project into existence, and I have to work out Processes or something.</p>
<p>Hhhhhhgghblhhhhhhhhhhhhh.</p>
<p>The laptop overheated or something earlier.
Did Not Like That.</p>
<p>Anyway, I'm thinking about ramping up on Cohost with NABTO (which I'm <em>probably</em> going to end up calling "Impliciula"), and there are a few steps I feel like I need to take:</p>
<ul class="simple">
<li>Extract the code highlighting stuff from the blog stylesheet</li>
<li>Put together a prototype Pygments lexer for what I have currently of NABTO/Impliciula's syntax.</li>
<li>Get this hosted somewhere.
This isn't <em>totally</em> straightforward because I don't want to use Git, so I'm <em>personally</em> thinking either a Mercurial forge or the Pijul nest.</li>
</ul>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Flashbacks to the time you listed every SCM you could think of <em>except</em> Git.</p>
</div>
<p>Let's be fair, I also didn't list BitKeeper.</p>
<p>Anyway, I'm a little out of it, possibly because <em>resurrecting my laptop</em> is kind of stressful.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Isn't your working theory that you just need to wait for it to cool off, which admittedly seems to take <em>a really long time</em>?</p>
</div>
<p>Stop being right; it doesn't help.</p>
<p>Anyway, the idea is that I'd figure out how to incorporate that stuff into the workflow of something like prechoster, so I can drop code blocks into my chosts.
Hypothetically, I could also drop the raw HTML into the ReST here, but, ehhh.</p>
<p>I lack the focus to get on this right now, but I guess I need a venv with Pygments installed, and then I can create a custom lexer, and I can invoke that... somehow.
Looks like I want to base it off of <tt class="docutils literal">python <span class="pre">-m</span> pygments <span class="pre">-x</span> <span class="pre">-l</span> your_lexer.py:SomeLexer <inputfile></tt>.
I bet I could write a script to handle all the dispatch stuff...
Anyway, time to wind down.</p>
<p>Good night.</p>
Weekly Roundup 2023-08-152023-08-15T04:00:00-04:002023-08-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-15:/weekly-roundup-2023-08-15<p class="first last">It's kind of a pain to work on this without any feedback, but I don't know the best place to look for feedback.</p>
<ul class="simple">
<li>Wednesday: I tried to figure out how I want the effect system in NABTO to work. I don't think I came to a solid conclusion.</li>
<li>Thursday: I fiddled some more with the syntax I want for NABTO.</li>
<li>Friday: I went into some proper detail about the weird syntax experiments I want to try out.</li>
<li>Saturday: I didn't have anything to post about.</li>
<li>Sunday: I went into more detail on the syntax ideas, and pushed them further into the language.</li>
<li>Monday: I figured out another puzzle I was having with the syntax.</li>
</ul>
<p>Next week, I guess I'll keep on with this.
I'm considering moving my posting habits around a bit to make it easier to get feedback on some things; I'll update the footer if I decide to go through with that.</p>
Coding 2023-08-142023-08-14T04:00:00-04:002023-08-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-14:/coding-2023-08-14<p class="first last">Recognizing when I couldn't figure something out because I was trying to solve the wrong problem.</p>
<p>I've punted on whether to have <tt class="docutils literal">rec</tt> (or "<tt class="docutils literal">recursive</tt>"), because I wanted to focus on how to keyword modules and modules types.
I need some kind of keyword for various things to have them inline.
That also includes functions, so maybe I can come up with some insight there?</p>
<p>Well, I got an idea for inline functions, but I don't feel any closer to having a handle on "<tt class="docutils literal">struct</tt>" or "<tt class="docutils literal">sig</tt>".
It's like... these don't correspond to a basic grammatical form, more like a poetic or rhetorical structure?</p>
<p>Maybe the right way to look at them is as some kind of block structure, in which case the inline form would just be <tt class="docutils literal">structure <span class="pre">{...}</span></tt> or <tt class="docutils literal">signature <span class="pre">{...}</span></tt>.
Which, given what I've gone through thinking about this, seems reasonable.</p>
<p>Well, time to get to bed, and maybe think about <tt class="docutils literal">rec</tt>, I dunno.</p>
<p>Good night.</p>
Coding 2023-08-132023-08-13T04:00:00-04:002023-08-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-13:/coding-2023-08-13<p class="first last">Something something, keywords are like violence.</p>
<p>I'm messing a bit more with the Smalltalk-inspired stuff, and I don't think it's going to deliver on its goals of readability, unless I can come up with a better type definition syntax than <tt class="docutils literal">let type <span class="pre">list-of:</span> 'a be nil or cons: 'a onto: <span class="pre">list-of:</span> 'a</tt>.
Either I need to figure out a reasonable way to make that read more like prose, or I need to come up with a more modest goal.
Or just scrap the whole thing.</p>
<p>To be honest, I do like the aspect of putting in the parameter's purpose next to its usage.
So, maybe I want to focus my efforts on make the usage conform to some standard, and don't worry so much about the definition...</p>
<p>Oh man, I just tried annotating types on a function definition, and I think I actually really like what I came up with.</p>
<p>In that case, now I want to focus on match/switch/case statements.
Right now, it's generically ML-ish, which doesn't <em>particularly</em> mesh with the pseudo-English going on around it.
Let's look at the parts involved:</p>
<ul class="simple">
<li>A value, which should be named like a noun.</li>
<li>A list of pairs.</li>
<li>The first part of each pair is a destructuring operation, which should be a type constructor, and I've just realized that <tt class="docutils literal">cons: _ onto: _</tt> doesn't look like a noun phrase.
Heck.</li>
<li>Anyway, the second part can look like any part of speech I come up with, as long as it's consistent for a given statement.</li>
</ul>
<p>Thinking about it that way implies that, instead of <tt class="docutils literal"><span class="pre">-></span></tt>, I should be using the second keywords from the various forms of definition.
That's no use without something for the beginning to coordinate with it, though.</p>
<p>Hm.
If you squint at it hard enough, like maybe really <em>really</em> hard, a match construct kind of looks like an anonymous function that gets pipelined into.</p>
<p>...</p>
<p>Okay, I've got an idea.
It's weird, but at this point, it's commit, or be committed.
The new syntax I'm trying out is <tt class="docutils literal">when _ is _ (be|do|then) _</tt>, and...</p>
<p>I like it.</p>
<p>I am going to have <em>so</em> much trouble convincing people this isn't an esolang.</p>
<p>Anyway, I'm going to wrap up for tonight, and ponder something else for a bit: should I have an equivalent to <tt class="docutils literal">rec</tt> from OCaml, or just not, like in Koka?</p>
<p>Good night.</p>
Diary 2023-08-122023-08-12T04:00:00-04:002023-08-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-12:/diary-2023-08-12<p class="first last">I was just so done with stuff today, so, eh.</p>
<p>I seem to have been out of it all day, so I guess I don't have anything to write about.
I've got some stuff set aside to look at later.
But for now, I should properly wind down.</p>
<p>Good night.</p>
Coding 2023-08-112023-08-11T04:00:00-04:002023-08-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-11:/coding-2023-08-11<p class="first last">I may have lost it, or maybe every language is going to look like this in 20 years, or maybe some secret third thing.</p>
<p>Yesterday I mentioned having some weird ideas to try out for NABTO's syntax.
I've been thinking about them some more, and I figured I could try describing them.</p>
<p>Here's the basic idea: the same underlying semantics can be represented with different syntaxes.
See, for example, <a class="reference external" href="https://hylang.org/">Hy</a>, which allows writing Lisp code that ultimately runs on the Python VM.
So, I can experiment with how different surface syntaxes work to express the concepts in NABTO without worrying that it will compromise the underlying semantics in some way.
The basic rule I think I need to follow is that a language concept has to either map to an idea that I want to take from another language, or it needs to be possible to implement it as a <em>local</em> syntax transformation.</p>
<p>With all that said, researching for NABTO has exposed me to a bunch of different ways to express concepts, and, like, they're fine, but...
So, what set this off is how unfamiliar the type construction syntax in OCaml is, but then I found myself considering the corresponding syntax in other languages, and the way that many widely-used languages represent function application...
Maybe it's just because some of my coworkers don't seem to have a problem writing horrifyingly long parameter lists, but I think the usefulness of making <em>functions in programming</em> visually resemble <em>functions in mathematics</em> breaks down when simply <em>enumerating the parameters</em> (not even explaining what they're for) looks like it would take a full paragraph of prose.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">It sounds like you're advocating for making certain types of code harder to write because of a personal preference.
You're going to ruffle some feathers with that stance.</p>
</div>
<p>Well, I don't know how effectively I'm "advocating" for anything, but I'm not saying nobody should ever write a fifteen-parameter function.
I just think that they should work to justify the contribution of each parameter to the cohesive concept that the function represents.
<tt class="docutils literal">f(x, y, z)</tt> is good enough as it goes, but I've found myself longing for something a little more verbose.
More talk.
Perhaps a... small bit more talk?</p>
<p>I don't see many people using Smalltalk, and I'm not sure if Objective-C got traction for any reason besides "On Mac, you kind of had to use it", so the idea I'm dancing around, of expressing a function as a phrase, with the parameters slotted into predetermined gaps in the function's name, may alienate some people.
To them, I say, "Don't worry! NABTO isn't object-oriented in the Smalltalk sense, so this is probably going to also alienate the people who were nodding along before."</p>
<p>Let's get some examples.
Suppose you have a list called <tt class="docutils literal">lst</tt>.
In Python, you'd get the length of it by calling <tt class="docutils literal">len(lst)</tt>, or maybe <tt class="docutils literal">lst.__len__()</tt> for... some reason.
In OCaml, <tt class="docutils literal">length lst</tt> or <tt class="docutils literal">lst |> length</tt>.
In Koka, <tt class="docutils literal">length(lst)</tt> or <tt class="docutils literal">lst.length</tt>.</p>
<p>I am pondering something like <tt class="docutils literal"><span class="pre">length-of:</span> lst</tt>.
In this, a typical function would be named as a noun phrase with one or more gaps within it.
I'm currently leaning towards omitting articles for the sake of brevity.
If I put them in, they'd end up functioning as a means of distinguishing values (have articles) from types (don't have articles).
But for the moment I'd rather see how well things go with a mild headlinese influence.
("For moment, rather see how things go with mild headlinese influence"?)
Once I have the mental image of code mimicking prose more closely, I imagine stuff like replacing the <tt class="docutils literal">=</tt> in <tt class="docutils literal">let ... =</tt> with <tt class="docutils literal">be</tt>, and changing out Koka's <tt class="docutils literal">:=</tt> operator for <tt class="docutils literal">set ... to</tt>.</p>
<p>Not all functions "return nouns", though.
A function returning <tt class="docutils literal">()</tt> must be some kind of verb, and a predicate is very much like an adjective.
Therefore, suppose that we allow <tt class="docutils literal">to ... do</tt> as an alternative to <tt class="docutils literal">let ... be</tt>, and allow a sort of "one-argument pipelining" with an <tt class="docutils literal">is</tt> operator.
So, like <tt class="docutils literal">if 4 is even:: then ...</tt>, and <tt class="docutils literal">even::</tt> could be defined like <tt class="docutils literal">when n is even:: then ...</tt>.
Or <tt class="docutils literal">iff n is even:: then ...</tt>.
I'm not seeing good sugar for something like <tt class="docutils literal">element: e <span class="pre">is-in:</span> l</tt>, so maybe that needs to settle for <tt class="docutils literal">let element: e <span class="pre">is-in:</span> l be ...</tt>, unless it's permissible to use the non-is syntax in <tt class="docutils literal">iff ... then</tt> as well.</p>
<p>One obstacle to this idea is that I'm not always sure what noun to use for various higher-order function concepts.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Also, how do you intend to handle pipelining in general, if your syntax is so inflexible?
Or default arguments, for that matter?</p>
</div>
<p>For pipelining, I have an idea that amuses me: <tt class="docutils literal">let <span class="pre">somewhat-large</span> be <span class="pre">fibonacci-number:</span> 1700; <span class="pre">factorial-of:</span> that</tt>.
That is, using <tt class="docutils literal">that</tt> in all code like <tt class="docutils literal">_</tt> in the Python REPL.
And speaking of <tt class="docutils literal">_</tt>, <tt class="docutils literal">increment: number by: _</tt>, literally letting the function definition fill in the blank.</p>
<p>There is <em>a lot</em> of syntax to try and fit into this paradigm, but I want to see how far I can push this.</p>
<p>For now, I'm going to wind down.</p>
<p>Good night.</p>
Coding 2023-08-102023-08-10T04:00:00-04:002023-08-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-10:/coding-2023-08-10<p class="first last">Negaverse Raku is my favorite anime character.</p>
<p>I'm still tweaking the code samples and pondering how I want effect handling to work.
I ended up with this weird imbalance where most of the code looks like OCaml, but the effect handling looks <em>kind of</em> like Koka, and my initial goals for the language and my thoughts on the effect handling would be better served by having it the other way around.</p>
<p>Part of the problem is that I was basing things off of the Koka code samples, which have <em>heavy</em> doses of syntactic sugar.
My intuition is that I'll make something much more coherent if I focus on the subset of Koka that does stuff like use brackets instead of indentation.</p>
<p>There's also the somewhat "fun" aspect that I'm trying out syntax that neither language uses, which ends up necessitating entirely new forms of syntactic sugar to handle capabilities from the source languages that don't translate cleanly.</p>
<p>(With the ideas I'm trying to pull in, I kind of imagine NABTO coming together into some kind of negaverse Raku.)</p>
<p>I'm not going to do any more tonight, but I think the right way forward is to chart out the relationships between the different syntactic elements of the languages, and figure out what purposes they're serving.</p>
<p>Good night.</p>
Coding 2023-08-092023-08-09T04:00:00-04:002023-08-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-09:/coding-2023-08-09<p class="first last">I'm not sure if there's a good way to get syntax highlighting for a language that doesn't even have a lexer, so I'm not going to show off code samples yet.</p>
<p>I wrote some sample programs in a possible syntax for NABTO.
There are various things that are likely to need to change:</p>
<ul class="simple">
<li>I haven't considered how to integrate types into the syntax.</li>
<li>The effect handling syntax is <em>mostly</em> taken from Koka, and it's not gelling well with the OCaml influences.</li>
</ul>
<p>I think what I need is something like...
There are a bunch of type constructors that package record/variant/whatever types together with information related to resumption, and defining an effect consists of <em>somehow</em> associating a record type and a constructor together, and handling an effect consists of having a modified match statement that unpacks the resumption information.
(Maybe there's some kind of automatic casting between different effect constructors?)
Anyway, to perform an effect, the code needs to construct the data type associated with the effect, and then the runtime somehow determines which kind of effect wrapper to use...
Although, that information would be ambiently available at runtime...
Doing that would foreclose a number of desirable optimizations...</p>
<p>If I want to get the optimizations, then I need to be able to make a statement something like "from a type level, this type is guaranteed not to capture beyond this level of detail".</p>
<p>Wait...
Maybe there could be an overloaded function, and then defining an effect can be done by setting up a modular implicit that associates the data type to the specific effect construction machinery.
I'm not sure what the right way to approach this from an ergonomic perspective would be, but I think this can work.
It conceals some weird footguns, but I think people would need to <em>try</em> to find them, so it's probably fine.</p>
<p>This has been a productive night, and I should wrap up.</p>
<p>Good night.</p>
Weekly Roundup 2023-08-082023-08-08T04:00:00-04:002023-08-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-08:/weekly-roundup-2023-08-08<p class="first last">Still holding out for an exemption...</p>
<ul class="simple">
<li>Wednesday: Scheduling...</li>
<li>Thursday: I made some breakthroughs with NABTO.</li>
<li>Friday: I assume there was nothing in here because of the Scheduling again.</li>
<li>Saturday: The problem here wasn't the Scheduling, but just that I didn't manage my own time well.</li>
<li>Sunday: I got a bit more fleshed out about NABTO.</li>
<li>Monday: I went into more detail on NABTO, but didn't commit to much.</li>
</ul>
<p>Next week, I'm going to try to get more interesting stuff done with drafting NABTO.</p>
Coding 2023-08-072023-08-07T04:00:00-04:002023-08-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-07:/coding-2023-08-07<p class="first last">Some people are going to be confused by the detail I'm going into, and some people are going to be Very Unhappy because I made the Wrong Decisions.</p>
<p>One thing that I'm not sure about when it comes to a standard library for NABTO is, what kinds of data types are useful to have?
My intention is that NABTO should be usable for writing scripts to execute from the shell, simple low-traffic internet-connected operations like a small IRC bot, stuff like that.
And I'd <em>like</em> it to scale up to bigger stuff, but I think it makes sense to nail down the behavior, and then investigate what it takes to scale it.</p>
<p>Anyway, there's algebraic stuff I definitely want, like booleans, optionals, lists, results, eithers (OCaml draws a distinction), maps, sets, arrays, tuples.
And there definitely need to be facilities for manipulating bytes, and some kind of good interface to files full of bytes.</p>
<p>But I also want to have the ability to deal with text and numbers, and these abilities raise a number of questions that people feel very strongly about:</p>
<ul class="simple">
<li>Should there be multiple numerical types, or just one?
(When there's just one, it seems to me like it's usually a 64-bit floating point type.)</li>
<li>If there are distinct types for whole numbers and floats, should the whole numbers have a specified size, or be unbounded?</li>
<li>If there's a bounded type for whole numbers, should there be multiple sizes?
Should there be signed and unsigned variants?</li>
<li>If there are different floating and whole number types, what should be required to convert between them?
What about converting between different flavors within those categories?</li>
<li>I probably want to represent rational numbers somehow.
What representation should I use, and should it be in the core library or not?</li>
<li>Assume for the moment that text is represented as utf-8 by default.
(There are some libraries that I should look into, that I think would translate interestingly into a module system.)
Should strings be indexed to retrieve bytes, code points, graphemes, or should they simply not be indexed at all?
Keep in mind that none of these categories will <em>always</em> correspond to "the width of a grapheme in a fixed-width font" in a nice way.</li>
</ul>
<p>My thoughts on this so far:</p>
<ul class="simple">
<li>It would be good to have facilities for using NABTO as a calculator (floating point or rational (and algebraic, if I can understand the work that's been done on algebraic representations)), and for reasoning about discrete chunks of memory and data (integers, <em>possibly</em> both signed and unsigned)</li>
<li>I actually do have some opinions about integer operations: I think I like how Python handles integer division; that is, always rounding down, sign of non-zero remainder matches the sign of the divisor.
That is, the semantics.
I'm not overly attached to the <tt class="docutils literal">//</tt> syntax.</li>
<li>It would be good to have some way to get text into or out of a file, but that's not <em>always</em> what's going to be happening, and different types will probably be involved.</li>
<li>Maybe I want to try to replicate Python 3's thing where instead of comparing some instances directly, it takes a "key" function to convert to a type that is simpler to compare.
(At least sometimes. Can't do that all the time without ending up in an infinite regress.)</li>
<li>Oh geez I forgot that the behavior of changing the case of text is locale-sensitive.</li>
<li>I don't know if it would help with that, but I guess I should look into how Swift does things.</li>
</ul>
<p>Anyway, it's late and I want to wrap up.</p>
<p>Good night.</p>
Coding 2023-08-062023-08-06T04:00:00-04:002023-08-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-06:/coding-2023-08-06<p class="first last">I've been focused on other stuff, I guess.</p>
<p>Here's what I've decided makes sense as a way to develop NABTO:</p>
<ul class="simple">
<li>Figure out what the standard library functions should look like.
I'm currently thinking somewhere between OCaml and Koka, but focusing on OCaml, making functions uncurried and row-polymorphic in effects, and furthermore using multimethods where sensible.</li>
<li>Figure out what I want to do for stuff like arithmetic and format strings.</li>
</ul>
<p>That's all I've got for now.
It's best if I get to bed now.</p>
<p>Good night.</p>
Coding 2023-08-052023-08-05T04:00:00-04:002023-08-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-05:/coding-2023-08-05<p class="first last">Good to skip this one.</p>
<p>Well, I'm still not in great shape to write anything, but I really want to figure out how to pitch the concepts behind NABTO.</p>
<p>Unfortunately, I got distracted doing research, and maybe the answer is "I need to do a bunch more research before I can talk about this stuff persuasively."</p>
<p>Anyway, it's late and I'm tired.</p>
<p>Good night.</p>
Coding 2023-08-042023-08-04T04:00:00-04:002023-08-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-04:/coding-2023-08-04<p class="first last">Please feel free to skip</p>
<p>Tired and distracted.
My plan is to finish this post quickly, and take down physical notes on NABTO.
But mainly, I need to get some rest.</p>
<p>Good night.</p>
Coding 2023-08-032023-08-03T04:00:00-04:002023-08-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-03:/coding-2023-08-03<p class="first last">With this, the real hard work can begin... Once I feel like it.</p>
<p>Another rough day, but I stumbled across what was a missing piece of the puzzle in NABTO's "design".
Here are the three things I want to try to build it up around:</p>
<ul class="simple">
<li>An effect system that works with the type system (like in <a class="reference external" href="https://koka-lang.github.io/koka/doc/index.html">Koka</a>)</li>
<li>Modular implicits (like in <a class="reference external" href="https://arxiv.org/abs/1512.01895">this paper</a>)</li>
<li>Gradual typing with some kind of sensible runtime semantics for the <tt class="docutils literal">dynamic</tt> type</li>
</ul>
<p>That last goal very obviously complicates the design and implementation of the other two.
My feeling on this is that a language with explicit effects and modular implicits in an ML-style module and type system would be extremely interesting, but I <em>want</em> to see if it's possible to have gradual typing too.</p>
<p>(One other thing I've been rolling around in my head is the concept of marking an effect as "must be performed".)</p>
<p>There are... a lot of things that would need to be investigated and reconciled to see if all of this even makes sense, but now I feel like I have a specific goal to work towards.
Stuff of note:</p>
<ul class="simple">
<li>Koka <tt class="docutils literal">var</tt>s, unlike OCaml <tt class="docutils literal">ref</tt>s, interact with the effect system.</li>
<li>I want effects, though not necessarily all effects, to be arbitrarily resumable, which means that the runtime needs to be written really carefully, especially in conjunction with gradual typing.</li>
<li>Modular implicits offer an alternative way to lay out some fundamental standard library modules, so that needs to be looked into.</li>
<li>OCaml also has a bunch of language extensions that seem useful for NABTO, but I don't fully grasp the tradeoffs and limitations involved.</li>
<li>I don't know what I want function calls to look like.</li>
<li>I want to see how stuff like Trio's design would work with Koka-style effects.</li>
<li>And generally the kinds of utility libraries that languages have.</li>
<li>Also I need to know more about Perceus.</li>
</ul>
<p>Thinking about all of this, it kind of seems like my best bet for actually accomplishing anything here is to figure out how to articulate the vision I'm going for in a way that would convince people who, um, actually understand this stuff to put work in.</p>
<p>I'm going to get ready for bed now.
Until I get some inspiration for how to write about this stuff persuasively, I can mess with parsing, or maybe some cursed Lua I put together recently.</p>
<p>Good night.</p>
Diary 2023-08-022023-08-02T04:00:00-04:002023-08-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-02:/diary-2023-08-02<p class="first last">Not happy with The Situation.</p>
<p>I am too tired and out-of-it to have anything to write for today.
I'm sort of thinking of taking a break from the OCaml stuff, because there is, in fact, more schedule fuckery.</p>
<p>I'm messing around with other things right now, and there's nothing to write about those currently, so I'm cutting this off here.</p>
<p>Good night.</p>
Weekly Roundup 2023-08-012023-08-01T04:00:00-04:002023-08-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-08-01:/weekly-roundup-2023-08-01<p class="first last">I <em>think</em> this is coming back from a diversion, and not diverting so hard that it wraps around, but who's to say?</p>
<ul class="simple">
<li>Wednesday: I put together some ideas for internal data structures for an Earley parser.</li>
<li>Thursday: I decided to take a break from Earley parsers to mess around with Math Stuff that seems like it "should" work better in OCaml than in Haskell or Rust.</li>
<li>Friday: I redid the Math Stuff a little, and confirmed a few of OCaml's capabilities.</li>
<li>Saturday: I set out a bunch of work for myself on the Math Stuff.</li>
<li>Sunday: I decided to take a break from the Math Stuff to mess around with the Earley parser code.</li>
<li>Monday: I tried to refresh my memory about which types need to exist for the Earley parser internals.</li>
</ul>
<p>Next week, I'm going to either power through these weird internals, or get distracted with something else.</p>
Coding 2023-07-312023-07-31T04:00:00-04:002023-07-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-31:/coding-2023-07-31<p class="first last">Getting enough work done.</p>
<p>I did other stuff today, but I did just now jump back into the Crafting Interpreters stuff.
I'd mentioned that I wanted to implement the "dot" from Earley parsers as a zipper list.
(Regular reminder that I'm messing with Earley parsers because I'm specifically avoiding what Crafting Interpreters actually says to do.)</p>
<p>Remembering what comes next:</p>
<ul class="simple">
<li>I need to put together the composite type for representing an item using this stuff, including writing a comparison function.</li>
<li>I need to put together the composite types for representing the work queue items, and write comparison functions for them.</li>
<li>I need to sketch out what translations of previous iterations of the scan/parse/complete code will look like.</li>
</ul>
<p>For now, I need to wind down and get to bed.</p>
<p>Good night.</p>
Coding 2023-07-302023-07-30T04:00:00-04:002023-07-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-30:/coding-2023-07-30<p class="first last">Finally hitting my limit with this side project.</p>
<p>Okay, I'm at the point where I need to take a break from this whole weird side project, and also to read some actual literature on constructivism.
For now, the stuff I'm trying to put together is sprawling into something that doesn't make sense.
Maybe by reading up on this stuff, I can come up with some helpful primitives.</p>
<p>This post, surprisingly, already took too long to write, so I'm going to just call it.</p>
<p>Good night.</p>
Coding 2023-07-292023-07-29T04:00:00-04:002023-07-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-29:/coding-2023-07-29<p class="first last">It's so bloated...</p>
<p>I'm tired, but here's what I've worked out from reading Wikipedia and messing around:</p>
<ul class="simple">
<li>There are five-ish basic structures I want to mess with to start with.</li>
<li>Each of these structures needs a few of its own versions of things:<ul>
<li>A "witness" module type that constructs a contradiction-checking function from components of the structure.</li>
<li>A "witness of" functor that combines an instance of the structure type and the witness type.</li>
<li>Functors that construct structure instances out of other structure instances; these functors should themselves provide functors that map from attestations of the components to new attestations for the composite.</li>
</ul>
</li>
</ul>
<p>The attestation concept has a lot going on, and I'm trying to figure out whether it needs specialized components as well, or if it can be general like some of the support code.
An attestation, in my informal thoughts on this, has:</p>
<ul class="simple">
<li>A structure (module, necessary for typing)</li>
<li>A property (module, necessary for typing)</li>
<li>A witness function (probably in a module; derived from structure and property, but I think not in a generalizable fashion)</li>
<li>The witness module provides an unreduced specimen type; there must also be a partially reduced specimen type</li>
<li>Fully reduced specimen type</li>
<li>Mapping from unreduced specimen type to list of partially reduced specimen type</li>
<li>Function to test reduced specimen types for a contradiction</li>
<li>Mapping from partially reduced specimen type to fully reduced specimen types</li>
</ul>
<p>Probably more, there's so much in there...
And some stuff that maybe can be moved out of the module interface.
I think a bunch of this needs to be structure-specific, so I'll have to figure out how much of it can be factored out.</p>
<p>Okay, that's... a lot.
I'm going to wind down and try to take it easy for a while.</p>
<p>Good night.</p>
Coding 2023-07-282023-07-28T04:00:00-04:002023-07-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-28:/coding-2023-07-28<p class="first last">I'll be shocked if this project results in something with even "okay" ergonomics.</p>
<p>Okay, I let things go late tonight, so I'm going to try to just jot down some thoughts.</p>
<p>After the entry last night, I redid things a bit.
Now, there's a single module per property (ish), and a given property and (currently) magma can be combined in a functor to produce a module that determines whether a collection of values in the magma represent a contradiction of the property.
There are at least two directions that I need (want?) to take this.</p>
<ul class="simple">
<li>What does it look like when I make the structure more complicated?
The obvious place to start here is to single out a value of the magma's type, and to devise a property check that the designated value is an identity element.</li>
<li>Constructing these predicates is not the end goal.
My gut tells me I want the ability to take the attestations for the property of some modules, combine those modules into a compound module, and also combine those attestations into a compound attestation.</li>
</ul>
<p>I've been trying to mentally line up the different parts that could be involved there.
Here's one idea that just popped into my head, and I'll lay it out, pop into the playground, and say whether it seems reasonable:</p>
<ul class="simple">
<li>Assume that, when there's a compound or derived property at play, the user knows about it, so it's fine to do some one-off stuff.</li>
<li>A compound module functor knows how the component modules get put together, so it also knows how to put together corresponding attestations.
(It also has the knowledge to do more elaborate stuff, like combining structures that carry out different operations on the same underlying set.)</li>
<li>So, if I'm using modules to represent both algebraic structures and assertions about them, does that mean that my "combine structures" functor can define a "combine assertions" functor?</li>
</ul>
<p>...</p>
<p>Oh, yes.</p>
<div class="admonition smiley smiley-glitchy">
<p class="first admonition-title">:) (glitchy)</p>
<p class="last">Ha ha ha... <em>Yes</em></p>
</div>
<p>*Ahem*</p>
<p>I'm still getting a handle on what OCaml will and won't let me do.
When I was first messing around with this space, I was trying to accomplish things in a way that very much did not fit with what OCaml lets you do, and it kind of seems like there isn't a way to make it do that, because the syntax that expressed my ideas already meant something different.
So it's really gratifying to see a way forward to accomplishing this stuff.</p>
<p>I can try to do this stuff over the next few days, and see what falls out.
For now, I'm going to wrap up.</p>
<p>Good night.</p>
Coding 2023-07-272023-07-27T04:00:00-04:002023-07-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-27:/coding-2023-07-27<p class="first last">Today's large upload brought to you by a protest.</p>
<p>Okay.
So.
I <em>could</em> keep on with the Crafting Interpreters stuff I was sketching out yesterday.
I <em>could</em> do a lot of things.
Like take another tack for encoding Math Stuff.</p>
<p>So I was reading an article on constructive mathematics, and one point it made was that the kinds of limitations that constructivists place on mathematical reasoning can be related to the kinds of limitations that software has to be written under in order to... do anything.
One example I'll develop is, it's not obvious to me how you'd establish that a particular property holds for every member of a set.
So let's flip it around.
Let's reason about what we can do with a contradiction of a property.</p>
<p>Well, if the set is, handwavily speaking, "simple", then, not too much, really.
But if the set is built up from smaller sets in some manner, then it should be possible to <em>reduce</em> the contradiction into one that applies to the smaller set.
If not, then there's something wrong with the reduction or the composition, and we can report that still.</p>
<p>Let's see if I can put this together in a way that makes sense to anyone, and hopefully to me.
Let's have an informal class of types called <strong>elements</strong>.
These elements are used to <strong>witness</strong> contradictions to a property.
Something like:</p>
<div class="highlight"><pre><span></span><span class="k">type</span> <span class="k">'</span><span class="n">a</span> <span class="n">total</span> <span class="o">=</span> <span class="nc">Total</span> <span class="k">of</span> <span class="k">'</span><span class="n">a</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span>
<span class="k">type</span> <span class="k">'</span><span class="n">a</span> <span class="n">commutative</span> <span class="o">=</span> <span class="nc">Commutative</span> <span class="k">of</span> <span class="k">'</span><span class="n">a</span> <span class="o">*</span> <span class="k">'</span><span class="n">a</span>
<span class="c">(* I tried defining a "binary operation" sig, but I just confused myself. *)</span>
<span class="k">module</span> <span class="k">type</span> <span class="nc">Magma</span> <span class="o">=</span> <span class="k">sig</span>
<span class="k">type</span> <span class="n">t</span>
<span class="k">val</span> <span class="n">op</span><span class="o">:</span> <span class="n">t</span> <span class="o">-></span> <span class="n">t</span> <span class="o">-></span> <span class="n">t</span>
<span class="k">end</span>
<span class="k">module</span> <span class="k">type</span> <span class="nc">Witness</span> <span class="o">=</span> <span class="k">sig</span>
<span class="k">type</span> <span class="n">t</span>
<span class="k">val</span> <span class="n">is_contradiction</span><span class="o">:</span> <span class="n">t</span> <span class="o">-></span> <span class="kt">bool</span>
<span class="k">end</span>
<span class="k">module</span> <span class="nc">TotalWitness</span><span class="o">(</span><span class="nc">M</span> <span class="o">:</span> <span class="nc">Magma</span><span class="o">)</span> <span class="o">=</span> <span class="k">struct</span>
<span class="k">type</span> <span class="n">t</span> <span class="o">=</span> <span class="nn">M</span><span class="p">.</span><span class="n">t</span> <span class="n">total</span>
<span class="k">let</span> <span class="n">is_contradiction</span> <span class="o">(</span><span class="nc">Total</span> <span class="o">(</span><span class="n">a</span><span class="o">,</span> <span class="n">b</span><span class="o">))</span> <span class="o">=</span>
<span class="k">try</span>
<span class="nn">M</span><span class="p">.</span><span class="n">op</span> <span class="n">a</span> <span class="n">b</span> <span class="o">|></span> <span class="n">ignore</span><span class="o">;</span>
<span class="bp">false</span>
<span class="k">with</span> <span class="o">_</span> <span class="o">-></span> <span class="bp">true</span>
<span class="k">end</span>
<span class="k">module</span> <span class="nc">CommutativeWitness</span><span class="o">(</span><span class="nc">M</span> <span class="o">:</span> <span class="nc">Magma</span><span class="o">)</span> <span class="o">=</span> <span class="k">struct</span>
<span class="k">type</span> <span class="n">t</span> <span class="o">=</span> <span class="nn">M</span><span class="p">.</span><span class="n">t</span> <span class="n">commutative</span>
<span class="k">let</span> <span class="n">is_contradiction</span> <span class="o">(</span><span class="nc">Commutative</span> <span class="o">(</span><span class="n">a</span><span class="o">,</span> <span class="n">b</span><span class="o">))</span> <span class="o">=</span> <span class="nn">M</span><span class="p">.</span><span class="n">op</span> <span class="n">a</span> <span class="n">b</span> <span class="o"><></span> <span class="nn">M</span><span class="p">.</span><span class="n">op</span> <span class="n">b</span> <span class="n">a</span>
<span class="k">end</span>
</pre></div>
<p>I doubt that I got all of this exactly right.
Like, the specific operation should probably be encoded in the witness type or module...
Let's see if defining composition enlightens things any.</p>
<div class="highlight"><pre><span></span><span class="k">module</span> <span class="nc">MagmaProduct</span><span class="o">(</span><span class="nc">M1</span> <span class="o">:</span> <span class="nc">Magma</span><span class="o">)</span> <span class="o">(</span><span class="nc">M2</span> <span class="o">:</span> <span class="nc">Magma</span><span class="o">)</span> <span class="o">:</span> <span class="nc">Magma</span> <span class="o">=</span> <span class="k">struct</span>
<span class="k">type</span> <span class="n">t</span> <span class="o">=</span> <span class="nn">M1</span><span class="p">.</span><span class="n">t</span> <span class="o">*</span> <span class="nn">M2</span><span class="p">.</span><span class="n">t</span>
<span class="k">let</span> <span class="n">op</span> <span class="o">(</span><span class="n">a1</span><span class="o">,</span> <span class="n">a2</span><span class="o">)</span> <span class="o">(</span><span class="n">b1</span><span class="o">,</span> <span class="n">b2</span><span class="o">)</span> <span class="o">=</span> <span class="o">(</span><span class="nn">M1</span><span class="p">.</span><span class="n">op</span> <span class="n">a1</span> <span class="n">b1</span><span class="o">,</span> <span class="nn">M2</span><span class="p">.</span><span class="n">op</span> <span class="n">a2</span> <span class="n">b2</span><span class="o">)</span>
<span class="k">end</span>
</pre></div>
<p>All right.
There's a slight problem there with the module type specification turning <tt class="docutils literal">t</tt> abstract, but, eh.
I'm getting tired, but I'm going to try to articulate the bigger problems here.
The key thing missing is the code to isolate and express the errors.
That needs to build on the code above, or something like it.</p>
<p>At this point, I have some ideas for totally reworking this, but it's too late right now for it to be a good idea to try to write them up.</p>
<p>...</p>
<p>I tried working on it outside of this entry, and just confused myself.
Time to get ready for bed.</p>
<p>Good night.</p>
Coding 2023-07-262023-07-26T04:00:00-04:002023-07-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-26:/coding-2023-07-26<p class="first last">Finding a data layout that fits nicely in my head.</p>
<p>I do have some other ideas that I'm turning over in my head to see how I could express them in OCaml, but the current result there is "seemingly pretty poorly".
Like a bunch of really messed-up functors...</p>
<p>So, let's get back to Lox.
By which I mean, the stuff that Crafting Interpreters specifically recommends against doing, in the effort to implement Lox.</p>
<p>I'm trying to figure out the right structure for the state sets and the "work queue".
Because I want to augment the state sets with additional information, let's temporarily call them something else, like "cells".
When we're working with cell #n, then we need access to possibly every cell from 0 to n inclusive, as well as "the current work queue" and "the next work queue".</p>
<p>There are several operations that call each other recursively.</p>
<ul class="simple">
<li>Adding an item to a work queue consumes the old version of the queue, and returns a new one. Additionally, it updates the cell corresponding to the work queue...</li>
<li>Predicting an item consumes from a work queue (consumes and returns a new version), and updates the corresponding cell</li>
<li>Scanning an item consumes from a work queue and the current token and updates the corresponding cell</li>
<li>Completing consumes from a work queue and potentially any cell, and updates the corresponding cell.</li>
</ul>
<p>Here's what my gut says to do to implement all of this:</p>
<ul class="simple">
<li>Have a pair of cell and work queue.</li>
<li>Have a pair of <em>those</em>.</li>
<li>Do not add the "current" cell to the array until it is done being processed; special-case getting it in the completion code.</li>
<li>Have each function operate on the pair of data structures, taking it in and returning it.</li>
<li>Maybe define some kind of fixpoint helper to replace all of the loops.</li>
</ul>
<p>All of this gives me a reasonable target to shoot for later, so I'm feeling good about it now.
I'm going to wrap up for now and mess with the other ideas on paper.</p>
<p>Good night.</p>
Weekly Roundup 2023-07-252023-07-25T04:00:00-04:002023-07-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-25:/weekly-roundup-2023-07-25<p class="first last">I mean, I still don't know if it works, but it should work <em>better</em>.</p>
<ul class="simple">
<li>Wednesday: I got some code written for nullability detection in the parser.</li>
<li>Thursday: My laptop wouldn't turn on for like half an hour, and has since refused to elaborate. I did not like this.</li>
<li>Friday: I got some more code for the nullability checks written. It didn't look great.</li>
<li>Saturday: I tracked down some bugs in the nullability checks, through code inspection.</li>
<li>Sunday: I tried to clean up the code. I do not know if I succeeded.</li>
<li>Monday: I started planning out a format for storing information about the parsing process.</li>
</ul>
<p>Next week, I'm going to try to flesh out and implement those plans, and maybe find something else to mess around with in OCaml.</p>
Coding 2023-07-242023-07-24T04:00:00-04:002023-07-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-24:/coding-2023-07-24<p class="first last">I'm not really focusing on algorithmic properties, just, like, what offends my sensibilities as a Zachtronics enjoyer?</p>
<p>I was doing stuff besides working on coding today, so I'm going to just drop a few notes on implementation stuff:</p>
<ul class="simple">
<li>The logic for constructing a parse forest requires the index of the start.</li>
<li>The straightforward way to handle this is with an <tt class="docutils literal">array</tt>, but I'm skeptical of the performance characteristics.</li>
<li>So I'm still messing around with whether it's possible to implement something decent using <tt class="docutils literal">list</tt>.
Like some kind of system of adding up indices so it's actually pointing <em>back</em> instead of counting from the beginning.
There are two immediately obvious drawbacks to this approach: it sounds tricky, which isn't great when I'm trying to figure out the actual main implementation at the same time; and I don't actually know if any of it would help.</li>
<li>For parse forest construction, the useful indices would be the left-hand-side and the start index.</li>
<li>For actually constructing stuff, I think the relevant thing is completion, because the work structure can have any required format.
To carry out completion, we need to look for a non-terminal after the dot, which is a completely different arrangement of data.</li>
<li>Maybe instead of "just" a mapping from left-hand-side to start index to sets of zippered right-hand-sides, I should have "that, plus a map from non-terminal-after-dot to 'whatever the format is for inserting into the work queue'"</li>
</ul>
<p>I think that's enough to work with later.
For now, I'm going to properly wrap up.</p>
<p>Good night.</p>
Coding 2023-07-232023-07-23T04:00:00-04:002023-07-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-23:/coding-2023-07-23<p class="first last">I think I changed a few lines back and forth several times.</p>
<p>Hm.
I spent a few hours moving code around trying to make things "more readable", and I think I made some improvements to start with, but now it's just kind of, like, sloshing around?</p>
<p>Earlier I was looking for some kind of set of guidelines for when to use stuff like <tt class="docutils literal">|></tt> and <tt class="docutils literal">@@</tt>, and I didn't have any luck, but now I feel like I <em>really</em> need some guidelines like that, because it's all just getting kind of weird now.</p>
<p>Anyway, it's way late, so I'm getting to bed finally.</p>
<p>Good night.</p>
Coding 2023-07-222023-07-22T04:00:00-04:002023-07-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-22:/coding-2023-07-22<p class="first last">I shouldn't be trying to read the code this late, but props to OCaml for being so readable once I get a basic handle on the syntax.</p>
<p>All right, it's late because I watched a movie that was strange, but probably should have been stranger somehow?</p>
<p>Anyway, let's take a look at the nullability code.
Here is the premise: some nonterminal symbols are known to be nullable, and the rest are not known to be nullable.
I have a set representing the symbols known to be nullable, and for the symbols not known to be nullable: a map of maps of sets of sets.
It maps from a symbol that is on the right-hand-side of rules, to the symbol that is on the left-hand-side of such rules, and the set that it maps to is of sets of right-hand-side symbols not known to be nullable.</p>
<p>Working from the outside of the <tt class="docutils literal">update_nullable</tt> code path...</p>
<p>It starts by converting the list of the right-hand-side to a <tt class="docutils literal">NSet.t option</tt> containing all of the nonterminal symbols if there were no terminal symbols.
If this is <tt class="docutils literal">None</tt>, then there's no work to do and it passes back the set and map unchanged.
Otherwise, it takes the set and passes it to the next function in.
I think I just noticed a bug.
I'm taking a set difference in the wrong place.
Just move it sooner, and...
Okay, that should work.</p>
<p>Okay, so it filters out all elements of the right-hand-side set that are already known to be nullable.
If there's still <em>something</em> in the set, then that needs to be added to the map:
Every element in the set needs to be added or updated in the map, by adding or updating the left-hand-side key, to make sure that it points to a set containing the new set.
And if there's nothing in the right-hand-side set, then the course of action is to mark the left-hand-side as nullable.</p>
<p>Marking a symbol is nullable is accomplished with a recursive function that pulls and accumulates work from and into a set.
If the set is empty, it has no more work to do and passes back the other argument unchanged.
Otherwise, it pulls one element from the set, and, hm.
It's getting late and I need to be better rested to grasp this code.
I <em>think</em> I'm missing a call to <tt class="docutils literal">NMap.remove</tt>, and I <em>think</em> I just put it in the right place.
But the quick and basic idea is to remove the newly nullable symbol from the sets in the sets in the maps in the map, as well as from the maps in the map.
At that point, if any sets of sets contain the empty set, then the corresponding left-hand-side needs to be added to the work set.</p>
<p>I mean, this all <em>seems</em> to make sense, but I'm really tired, so I don't know that I'm trustworthy about this.
I should get to bed.</p>
<p>Good night.</p>
Coding 2023-07-212023-07-21T04:00:00-04:002023-07-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-21:/coding-2023-07-21<p class="first last">Not sure I'm supposed to have four close parens in a row.</p>
<p>Okay, I've <em>potentially</em> got the nullability detection code working properly.
There are <em>a lot</em> of moving parts, and I suspect a lot of the code I threw together isn't idiomatic.
Like, I managed to get one statement indented nearly halfway across the line.
And some function applications that I think are in "the wrong order" from an allocation perspective.
All sorts of code that can be cleaned up, <strong>if</strong> it's doing the right thing in the first place.</p>
<p>So, I can forge ahead with trying to handle parsing now that I at least have the <em>representation</em> of nullability in a usable state, but also I want to try to validate that my various ideas for this code are correct, and that the code as written implements them, and then look into simplifying things.</p>
<p>At the moment, I'll do neither, because I need to get to bed.</p>
<p>Good night.</p>
Diary 2023-07-202023-07-20T04:00:00-04:002023-07-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-20:/diary-2023-07-20<p class="first last">My laptop turned on <em>immediately</em> after I edited a message onto the front page saying that it wouldn't. Thanks for the tech support.</p>
<p>The whole schedule change thing continues to be pointless.
I think I might have some ammunition to get out of it, but we'll see.</p>
<p>Right now, though, I'm a little rattled because my laptop randomly shut down earlier today, and I'm just like "not again".</p>
<p>I've got some ideas for stuff to do trying to work on code written in OCaml, but like I said, rattled.</p>
<p>Hopefully my laptop is better behaved tomorrow.
I did try to reduce some of the load on it.</p>
<p>Anyway, I don't have the focus to stay up any longer.</p>
<p>Good night.</p>
Coding 2023-07-192023-07-19T04:00:00-04:002023-07-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-19:/coding-2023-07-19<p class="first last">"This looks complicated. *does it*" is always a classic.</p>
<p>I started specifying and implementing what's required to incrementally detect nullable rules.
One hurdle is that I'm informally writing this out in a mostly imperative style, but I'm implementing it all functionally, and sometimes the gaps between the two approaches get... wide.</p>
<p>Complaining about this was enough of an impetus to try and get the implementation right before I could manage to explain what the issues were, so this is probably close to done, but there are still various bits of bookkeeping to handle.</p>
<p>I can't handle them right now, because it's late.
Let's see what I'm up for tomorrow...</p>
<p>Good night.</p>
Weekly Roundup 2023-07-182023-07-18T04:00:00-04:002023-07-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-18:/weekly-roundup-2023-07-18<p class="first last">Gradually getting a better handle on both OCaml and Earley parsers.</p>
<ul class="simple">
<li>Wednesday: Not a great day.</li>
<li>Thursday: I tried to figure out one of my previous attempts to implement Earley parsing.</li>
<li>Friday: I looked at the module types I'd written, and tried to figure out how to improve them from a usability standpoint.</li>
<li>Saturday: I made some progress on simplifying the grammar modules.</li>
<li>Sunday: I moved on to considering the internal types relevant to the parsing operation.</li>
<li>Monday: I realized that I need to handle nullable symbols, and investigated a possible way to incrementally detect nullable symbols.</li>
</ul>
<p>Next week, I'm going to keep on with that schedule stuff that's messed me up, and hopefully argue against it.
Aside from that, I'm going to try to get the nullability stuff in a sensible state.</p>
Coding 2023-07-172023-07-17T04:00:00-04:002023-07-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-17:/coding-2023-07-17<p class="first last">This is going to be weird and sprawling, but let's see how it goes.</p>
<p>Now that I have some ideas for the types involved in the actual parsing part of the Earley parser, I've got a better handle on visualizing its operation, and I've concluded that I do, in fact, need nullability checking.
Which is a shame.
Loup Vaillant has <a class="reference external" href="https://loup-vaillant.fr/tutorials/earley-parsing/empty-rules">an explanation</a> of what that's supposed to solve, but I'm going to try phrasing it in terms of my "trying to teach this stuff to myself" code structure.</p>
<p>Basically...
Start with the three operations: scanning, prediction, and completion.
Now, ignore scanning, because it inherently operates on two distinct state sets, so it's unproblematic in this context.
Going over prediction, it does operate on just one state set, but once a prediction has been done, there is guaranteed to be no more work.
Now, completion is a little more subtle, because it's unproblematic <em>if</em> the item being completed was started in an earlier state set, which is guaranteed to be the case... unless the symbol is nullable.</p>
<p>There are a few ways to deal with this:</p>
<ul class="simple">
<li>Retry completions until nothing changes, making sure to bring in predictions as those are added.</li>
<li>Determine the set of nullable symbols immediately before parsing.</li>
<li>Determine the set of nullable symbols incrementally, as rules are added.</li>
</ul>
<p>I kind of don't want to do things the first way, because I suspect that that would end in some weird redundant loops.</p>
<p>So, I need to either have nullability calculations right before parsing, or incrementally.
I <em>want</em> doing it incrementally to be a slam dunk, but I suspect that it's not.
Basically, if you add a single rule, the <em>immediate</em> question is whether it renders the left-hand-side symbol nullable, but <em>if it does</em>, then every non-nullable symbol has to be checked for whether making that first symbol nullable makes that other symbol nullable.
Jeffrey Kegler's <a class="reference external" href="https://github.com/jeffreykegler/old_kollos/blob/master/notes/misc/loup2.md">note</a> on the nullable stuff presents a linear-time algorithm for detecting nullables.
I'm going to try to walk through what doing it incrementally would look like.</p>
<p>So, there are going to be several auxiliary maps.
These maps only need to concern themselves with rules that have no terminal symbols.
One map from LHS to rules.
One map from RHS symbols to sets of rules (including LHS I think).
A set of nonterminals with empty rules.
A mapping from every non-terminal in the LHSs to whether that is a nullable symbol, false by default.</p>
<p>At this point, things diverge sharply and I kind of have to wing it.
I believe I'll have to re-derive the time bounds of what I'm about to propose, if I want to know what they are.</p>
<p>When adding a rule:</p>
<ul class="simple">
<li>If there are terminal symbols, ignore it.</li>
<li>If the rule is empty, add it to the set of empty rules.
Actually, this step and data might not be needed.</li>
<li>If the LHS is already marked nullable, ignore it.</li>
<li>If the RHS is made up only of nullable symbols, mark the LHS as nullable, and then, iterate over every rule with the LHS in the RHS, to see whether any of those rules now have only nullable symbols in the RHS.
If so, mark the associated LHS as nullable and recurse.</li>
</ul>
<p>I'm honestly missing what anything besides the RHS map and the nullability map is accomplishing in this, so I'm going to see how far I can get with just those.</p>
<p>One thing I note is that, once a symbol has been marked nullable, there's no reason to check any rules with that LHS, so it could be efficient to remove such rules from the RHS sets.
Potentially there could be a different way to store the RHS data other than literally, like as sets of symbols not known to be nullable.
Then, when a set gets to zero, mark the LHS as nullable and cut down on stuff.
You know, stuff.</p>
<p>I think this is enough to get started with tweaking the representation.
Looking over it, I'm highly skeptical that what I have in mind is worst-case linear, but it shouldn't lead to any huge degradations in grammars that don't "need" this stuff.</p>
<p>One more pass at trying to make sense of this:</p>
<p>To mark a rule nullable, check the RHS table.
It should be safe for the RHS table to contain tables from the LHS to the sets of symbols not known to be nullable.
When a symbol is marked nullable, then that means that it needs to be removed from every other entry.
For <em>each other</em> RHS symbol, put together a set of LHS symbols to check.
If any LHS symbol is associated with the set of just the nullable symbol, then that symbol has to be marked nullable on the next pass.
For LHS symbols with other sets, those sets represent RHS symbols that need to be updated; doing so is guaranteed not to produce more nullable symbols.</p>
<p>I'm still not sure about the time bounds, but I think I can get this to make sense, so I'm going to take down some notes on how I need to change up stuff, and then get to bed.</p>
<p>Good night.</p>
Coding 2023-07-162023-07-16T04:00:00-04:002023-07-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-16:/coding-2023-07-16<p class="first last">This code is going to be so elegant, it'll have its pinky out for literally all beverages.</p>
<p>I went over the parser code for Lox a bunch, and I <em>think</em> the interfaces make sense now.
At this point, the functor requires two simple modules, instead of three with a complicated relationship between them, so at minimum, the code is simpler now just because I'm not trying to use features that I think I have some serious gaps in my understanding of.</p>
<p>At this point, the only code missing for the basic parser case is... the code that actually handles parsing.
The hurdle to clear there is that I need to figure out the types required to handle the "items".
It's like I need to consider every phase of the parsing process simultaneously to figure out what data is actually needed.
But, like, there must be some way to break this down...</p>
<p>The state sets are stored in an array.
The sets themselves should be <tt class="docutils literal">NMap</tt>s containing sets of partially completed rules, and start indices.
I'm not sure whether some of these will need to carry information about semantic actions, or if I can safely just leverage the grammar to retrieve them.
Let's assume the latter.</p>
<p>It <em>may</em> be the case that I want items derived from a successful scan to carry the matching terminal symbol.
That could also be in a tuple with the map, or simply not stored within the array.
Because of those latter two options, let's assume that it's not stored inside the items.
My idea for the structure of the items is to have <em>two</em> lists of symbols like a zipper list, and for the queued form, to take the Cartesian product with the relevant symbol type.
This means that each queue has a different type, which will match up with the action associated with that queue.</p>
<p>Now that I understand the queue types, I should hopefully be able to write them out properly and get the flow between them correct.
Unfortunately, to actually implement this, I'm going to need to either get really clever with pure functions, or bite the bullet and write a bunch of imperative stuff.</p>
<p>I'll think about that over the next few days or whatever.</p>
<p>Good night.</p>
Coding 2023-07-152023-07-15T04:00:00-04:002023-07-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-15:/coding-2023-07-15<p class="first last">Relearning the healing power of deleting code.</p>
<p>All right, I've given things some thought, and here is what I've concluded:
If you're making modules and types for grammars the way I intend to (which is clearly not the only way), then it's going to need a bunch of gnarly compound types, but crucially, they're entirely built up from just two basic types that the user has to pass in.
So, if we give <em>those</em> types as arguments in <tt class="docutils literal">OrderedType</tt> modules, then that relieves the user of constructing a bunch of modules to pass in.</p>
<p>The next thing I need to think about is how to handle the whole error-wrapping idea.
Is it reasonable to say "If you want an error-correcting grammar, then use the special error-correcting grammar constructor, which will give you back a module for a non-error-correcting grammar, and then you can pass that into a function on the higher-level module"?</p>
<p>Maybe... maybe the error-correcting version should have a different relationship between its input types and the compound types in the grammar, compared to the basic version.</p>
<p>Like, what's the right choice between:</p>
<ul class="simple">
<li>A module that requires another similar module</li>
<li>A module that provides another similar module</li>
<li>A module that secretly uses a similar module in its implementation?</li>
</ul>
<p>And now I'm realizing that a lot of these types should be abstract, which will hopefully make the code shorter overall.
Like, the compound types that the code needs to know about:</p>
<ul class="simple">
<li>The grammar itself.
This should be a map from non-terminals <em>from an implementation perspective</em>, but all the consumer needs is an empty grammar function, and a function to add rules.</li>
<li>Rules within the grammar.
The user needs a way to construct these, which requires the ability to create instances of the non-terminal and the matcher types.</li>
<li>Semantic actions.
The user needs a way to construct these, which requires the ability to <em>destructure</em> the token type.</li>
</ul>
<p>So, ultimately, this requires three public types, and one abstract type.
Two of the public types need a comparison function to implement the various compound types.</p>
<p>I think this is enough to fix up the interfaces around the grammar, but right now I need to get to bed.</p>
<p>Good night.</p>
Coding 2023-07-142023-07-14T04:00:00-04:002023-07-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-14:/coding-2023-07-14<p class="first last">I think if I get this wrong, the result is basically unusable, but I'm not sure what getting it right looks like.</p>
<p>I stared at my old code some more, and I'm starting to get a handle on what exactly I was doing.
It looks like the difference between using a <tt class="docutils literal">set</tt> and a <tt class="docutils literal">dict</tt> was just a matter of some cases "wanting" to cache the result of a computation.</p>
<p>I'm thinking about how best to handle the idea of yet another type to put into a <tt class="docutils literal">Set</tt> or a <tt class="docutils literal">Map</tt>.
I <em>must</em> be doing something wrong, because all of this boilerplate is really unpleasant.</p>
<p>I wonder if I can get away with turning all of this "map" stuff into functions from keys to values, because that would cut out a lot of this nonsense.
Or maybe I should be trying to define just a few <tt class="docutils literal">Map</tt>s in the interface, and constructing the implementation out of <tt class="docutils literal">OrderedType</tt>s?</p>
<p>Today was another exhausting day, so I'm going to wrap up for now, and try to figure out what's a sensible way to do this stuff tomorrow or over the weekend.</p>
<p>Good night.</p>
Coding 2023-07-132023-07-13T04:00:00-04:002023-07-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-13:/coding-2023-07-13<p class="first last">Past me really should have explained all of this clever stuff...</p>
<p>I still haven't got a handle on the new schedule stuff (honestly, I'd like to figure out some way to just be exempted from it, because I don't see what the point is).
Anyway, I'm going to try to take some quick notes on Earley parser stuff and have that be my post.</p>
<p>So.
My attempt at a Python implementation has a few moving parts.
One of these is called <tt class="docutils literal">add_item</tt>.
It supposes that if an item is already in an Earley set, then the next action for it must be queued up, and it accomplishes this by first checking, then queueing, then adding.
The queues are represented by a <tt class="docutils literal">set[Item]</tt> (for completion) and two <tt class="docutils literal">dict[Item, Symbol]</tt>.
An <tt class="docutils literal">Item</tt> is a combination of a <tt class="docutils literal">Rule</tt> and an integer index, which could be obnoxious if I translate it directly, because I think that means a bunch more modules.
The different queues are pulled from using different functions that don't return a value, they just mutate the queues.
Now, a close port of the Python logic would actually not be The Worst, because the queues don't leak anywhere, but I would like to see if it's possible to avoid using mutation.</p>
<p>I think the missing piece in understanding how to update this is just to take some notes, because reading the ipynb file in vim is... probably not the best way to get a handle on this.
Anyway, I will regret it so much if I don't get ready for tomorrow, so I've got to be done now.</p>
<p>Good night.</p>
Diary 2023-07-122023-07-12T04:00:00-04:002023-07-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-12:/diary-2023-07-12<p class="first last">Light on details, heavy on headaches.</p>
<p>Schedule change results so far: terrible; awful.
Tomorrow, I'm going to try changing the schedule in a different way, which should hopefully leaving feeling a little less bad.</p>
<p>To try to offset the bad vibes I was dealing with, I picked back up some writing I'd been meaning to get back to.
It's pretty good stuff, and so far it's still doing what it's supposed to, so I think that helped a little.</p>
<p>Anyway, part of that schedule change is going to involve getting up earlier, so I should go.</p>
<p>Good night.</p>
Weekly Roundup 2023-07-112023-07-11T04:00:00-04:002023-07-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-11:/weekly-roundup-2023-07-11<p class="first last">This is going a bit slow, but I guess I'll keep challenging myself.</p>
<ul class="simple">
<li>Wednesday: I got scanning for Lox working in OCaml.</li>
<li>Thursday: I tried to figure out what I'd want for implementing parsing for Lox.</li>
<li>Friday: I speculated a bit about what types might make sense for parsing. (Some of the types, did not, in fact, make sense.)</li>
<li>Saturday: Trying to actually use those types didn't work out or at least was difficult, but I forget the details.</li>
<li>Sunday: I tried to work through how to write the relevant type signatures.</li>
<li>Monday: I didn't go through the details, but I did a bunch of cleanup work that obsoleted the speculation I did the day before.</li>
</ul>
<p>Next week, I've got some schedule changes to deal with, so I'm not totally sure what I'll be up for.</p>
Coding 2023-07-102023-07-10T04:00:00-04:002023-07-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-10:/coding-2023-07-10<p class="first last">Things are about to keep on getting confusing.</p>
<p>All right.
At this point, the types are... less wrong.
I'm highly skeptical that I've gotten this stuff to a completely idiomatic state.
I'm now getting back up to speed on the right way to <em>actually carry out the parsing</em>.</p>
<p>Looking over my previous disorganized notes, I <em>think</em> my plan is to try to do things kind of naively, which means putting together the equivalent of a do-whole loop, but also needing to figure out how to translate the non-local references in the Python version...</p>
<p>Although, if I end up feeling up to writing Python for hobby stuff again, the insights I had around representing this stuff in OCaml could be helpful as far as writing type annotations that make sense.</p>
<p>Anyway, it's late and I'm tired, so I'm cutting this off now.</p>
<p>Good night.</p>
Coding 2023-07-092023-07-09T04:00:00-04:002023-07-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-09:/coding-2023-07-09<p class="first last">Does this suck because I'm inexperienced, or is there some actual avenue of improvement? Since I can't come up with a better suggestion, I'm going to assume it's the former.</p>
<p>All right, let's see if I can put something together quickly.</p>
<p>...</p>
<p>And I tried actually using the stuff I wrote before, and I've concluded two main things.</p>
<p>One is that I'm pushing past my comfort zone a bit in terms of the OCaml features that I'm trying to use.
More importantly, the code as I've written it is just kind of a confusing mess.</p>
<p>I just now tried to tidy it up a little, and... doubt.
I'm going to try to push forward and see if there's any kind of, like, obstruction.</p>
<p>So, the current thing I'm trying to put together is a <tt class="docutils literal">parse</tt> function.
It starts with a grammar and (currently) a sequence of nonterminals.
The first thing it needs to do is create a <tt class="docutils literal">('t, 'o) item NMap.t array</tt>.
That array should start off containing an empty map.
It's only empty because I'm <em>trying</em> to break this up into steps.</p>
<p>Aw crud.
I got a few steps in before realizing that one of the types is wrong.
I need a container to go in the middle of one of these horrifying types, and the code is still so bad that I think doing this technically qualifies as an improvement.
So, here's the puzzle...
I need to take the terminal matchers and make them suitable to use as (part of) keys to a <tt class="docutils literal">Map</tt>.
To make that work, the functional values have to be removed.
I think this can be accomplished by creating a module to hold the function definitions, and make the actual matchers into normal variant types.</p>
<p>...</p>
<p>Okay, I've started doing that, and now part of the code is a lot cleaner, but I'm pretty sure the rest of the file is just covered in red lines because I only <em>started</em> this.
I'm going to leave it there for tonight.</p>
<p>Good night.</p>
Coding 2023-07-082023-07-08T04:00:00-04:002023-07-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-08:/coding-2023-07-08<p class="first last">I have no idea whether the type signatures I'm writing are remotely reasonable.</p>
<p>I tried to put together a signature for the grammar stuff for Earley parsing.
I've tweaked it a few times, and I'm almost certainly going to tweak and change it a lot more as I figure out what's actually reasonable and what's needed to actually handle the task of parsing.</p>
<p>I think I have what I need to test it out by actually trying to write the functions, but I'm not up for that right now.
We'll see about tomorrow.</p>
<p>Good night.</p>
Coding 2023-07-072023-07-07T04:00:00-04:002023-07-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-07:/coding-2023-07-07<p class="first last">I used a lot of words trying to explain this, but I'm not sure whether I explained anything.</p>
<p>All right, let's see what it takes to handle Earley parsing, in terms of types.</p>
<p><tt class="docutils literal">type 't terminal_matcher = { match_ : 't <span class="pre">-></span> bool ; produce : () <span class="pre">-></span> 't }</tt></p>
<p>Might change the input to that second function.
And I think it should <em>not</em> be required that the <tt class="docutils literal">produce</tt> function only produces values that satisfy the predicate.</p>
<p>Anyway.</p>
<p><tt class="docutils literal">type n; module NMap = Map.Make(struct type t = n; let compare = compare end); type ('t, 'o) grammar = n * <span class="pre">(((n,</span> 't terminal_matcher) Either.t list * <span class="pre">(('o,</span> 't) Either.t list <span class="pre">-></span> 'o)) NMap.t)</tt></p>
<p>Without the language tools, I don't know which parentheses are needed, or even if I got that all right.
So, let's see if I can explain all of that.</p>
<p>With the <tt class="docutils literal">terminal_matcher</tt>, I'm maybe kind of bending the rules for "what is a grammar", because the usual description is in terms of terminal symbols, which are more-or-less associated with a particular <em>field</em> on the <tt class="docutils literal">token</tt> type in this context.
So, the "sensible" thing in my mind is to have a type that relates to the <tt class="docutils literal">token</tt> type, and write helpers that express "match this terminal symbol" in terms of what structure the <tt class="docutils literal">token</tt> has.</p>
<p>Now, to handle the structure of the grammar, I need to have the nonterminal symbol type as a module-level type instead of a variable, so I can use it to instantiate a <tt class="docutils literal">Map</tt>.
This map is used to hold the majority of the information in the grammar, with the remainder being the initial symbol next to it.
Within the grammar, each value is a pair of a list of nonterminals and terminal matchers, along with the semantic actions, which are functions that combine lists of their output type and terminal symbols.</p>
<p>The expected definition of the action functions is a little dynamic, because I couldn't see a way to encode all of the type information in an existential type so that it doesn't interfere with the ability to put all of these different signatures into one type of slot.</p>
<p>Oh yeah, I defined a record type to hold two functions for the matcher, instead of just aliasing to one of the types, because I'm trying to plan ahead to having a functor that replaces <tt class="docutils literal">n</tt> with <tt class="docutils literal">n option</tt> and provides the ability to convert from the wrapped module type to the wrapped type for this module, but with extra output stuff.</p>
<p>A missing piece of the puzzle is that the grammar modules need to define a <tt class="docutils literal">parse</tt> function that takes a grammar and a list (or something) of tokens, and the error-correcting version almost certainly needs a custom parse function to try to avoid all of the pathological parse behavior that I'm pretty sure adding the error correcting would introduce, at least the way <em>I'm</em> thinking of doing it.
(Other people may be built different.)</p>
<p>I think I should be done for now, and think about this more over the weekend.</p>
<p>Good night.</p>
Coding 2023-07-062023-07-06T04:00:00-04:002023-07-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-06:/coding-2023-07-06<p class="first last">Figuring out what I'm supposed to do when other stuff doesn't do what it's supposed to do.</p>
<p>Okay, I'm trying to move on to parsing now, and I need some time to figure out the right way to handle it.</p>
<p>I'm still on the idea I had previously of "let's learn something besides recursive descent", <em>in part</em> because I think trying that in OCaml would lead to an utterly monstrous <tt class="docutils literal">let rec</tt> that would only get bigger as I go.</p>
<p>So, I'm back looking at Earley parsers, and I think I've got an idea of how to put the types together.
However, I want to consider error correction possibilities.
From doing some research, I think I want to do something like this:</p>
<p>First, have a grammar definition, including semantic actions.</p>
<p>Then, the following:</p>
<ul class="simple">
<li>A transformation of the semantic actions to a form that includes an error score.</li>
<li>New rules for matching "junk" where each token matched increases the error score.</li>
<li>Terminal matchers need the ability to create "synthetic" tokens in the absence of proper input, which signal somehow that they're not present in the source.</li>
<li>Create rules in which the terminal matchers are replaced with matching zero or more junk, and their argument to the semantic action creates the synthetic token.</li>
<li>The junk rules need to create something that the modified matches know to discard.</li>
<li>Some combinations of this stuff.</li>
<li>Probably the additional data should include error details so those can get reported.</li>
<li>Bias advancing in the parse without errors (maybe using effects to create continuations or something?) so that working code doesn't end up generating a massive error forest just in case.</li>
</ul>
<p>Like prioritize by number of errors, and then by index.</p>
<p>Okay, this sounds workable, but I'm not sure.
I'm going to have to sleep on it.</p>
<p>Good night.</p>
Coding 2023-07-052023-07-05T04:00:00-04:002023-07-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-05:/coding-2023-07-05<p class="first last">Well, it's not obviously broken at this point. Kind of worried about the non-obvious breakage, then...</p>
<p>Traveled back, and messed around with algebra stuff in OCaml.
But let's ignore that for now, and see about getting scanning written for Lox.
What do I have so far...</p>
<p>I have a function that attempts to produce a token given some source string and a <tt class="docutils literal">control</tt> data structure.
It returns an updated <tt class="docutils literal">control</tt> value, and a <tt class="docutils literal">token option</tt>.
The equivalent code in Lua relied on a helper function that acts similarly to <tt class="docutils literal">filter_map id</tt>, so, um, let's assume I'm using that, and I need to define a function that produces a <tt class="docutils literal">token option Seq.t</tt> or something.</p>
<p>Given all of that writeup, I've managed to write the desired iterator, wire it in, handle the effects, and...</p>
<p>Something, somewhere in it is broken.
The problem currently seems localized to the <tt class="docutils literal">number</tt> function.
I'll see if I can fix that up quickly.</p>
<p>...</p>
<p>Got it.
I forgot to copy over <em>everything</em>, and I ended up with an off-by-one error.
Now it all seems to work perfectly.</p>
<p>I'm going to wrap things up for tonight, but now feels like a good time to sum up how I feel about OCaml so far:</p>
<p>The normal programming with looking at types and matching everything up is great, basic meta-programming with the module system is fine, trying to push the limits of "obvious" when it comes to meta-programming just ends in confusion so far.</p>
<p>I'd like to figure out if there's some way to avoid that confusion, but I'm going to keep assuming for now that it's a result of a deficit in my understanding.
Anyway, it's late now.</p>
<p>Good night.</p>
Weekly Roundup 2023-07-042023-07-04T04:00:00-04:002023-07-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-04:/weekly-roundup-2023-07-04<p class="first last">Huh, working on a specific project seems to be easier. Who would have thought.</p>
<ul class="simple">
<li>Wednesday: I kept on struggling with algebraic structure stuff.</li>
<li>Thursday: Ditto.</li>
<li>Friday: I decided to step away from that whole thing, and revisit Crafting Interpreters.</li>
<li>Saturday: I decided to use a new, shiny feature for Crafting Interpreters.</li>
<li>Sunday: I decided to directly adapt some of my old Lua code into OCaml, and felt like it ended up weirdly similar.</li>
<li>Monday: I had good luck continuing on with that stuff.</li>
</ul>
<p>Next week, I'm going to see how much further I can go.
I made more progress today that I haven't written up, so I anticipate I'll get a clean build soon; maybe then I'll discover some weird bugs as a result of the conversion.</p>
Coding 2023-07-032023-07-03T04:00:00-04:002023-07-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-03:/coding-2023-07-03<p class="first last">"Oh, hey, because I defined a function instead of a loop, I can just... call the function again. Cool."</p>
<p>Travel.</p>
<p>But also, a bunch more work with OCaml.
I'm writing helper functions and finding places that can probably be cleaned up later in the code that I'm writing.
The code feels pretty good to write.
We'll see later how it feels to read.</p>
<p>I put writing this entry off way too long, and I'm not going to draw it out.</p>
<p>Good night.</p>
Coding 2023-07-022023-07-02T04:00:00-04:002023-07-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-02:/coding-2023-07-02<p class="first last">Apparently I can write... whatever the hell this is... in any language.</p>
<p>I ended up deciding to try to patch together the scanning code from one of my Lua versions.
While I can express a bunch of the basic primitives fine, as I get to somewhat higher level stuff, I'm hitting imperative constructs, and, like, while I <em>can</em> use those in OCaml, I want to try to avoid them.</p>
<p>Like, let's see.
I've defined a function called <tt class="docutils literal">str</tt>.
Its OCaml version will take a source string and a <tt class="docutils literal">control</tt> record.
The first major thing it does is enter a while loop that advances the state of the <tt class="docutils literal">control</tt> record in various fashions.</p>
<p>By laying that out, I <em>seem</em> to have gotten a little further in implementing this stuff, and fixed a few issues along the way.
I hadn't quite grasped that OCaml's effect system allows you to pass effects around, and invoke them separately from constructing them.
This makes sense in retrospect, but it's not something I <em>currently</em> need, so I had to change some code.</p>
<p>Anyway, big thanks to ocamlformat for taking my stream-of-consciousness one-line monstrosities and making it so that at least I can read them.</p>
<p>Finally, I should be about done for tonight.
I've got a rough template for how to port the rest of the code, and then I can try to give it a nice interface.</p>
<p>Good night.</p>
Coding 2023-07-012023-07-01T04:00:00-04:002023-07-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-07-01:/coding-2023-07-01<p class="first last">Let's see what strange ways this decision comes around to bite me.</p>
<p>The more I thought about how I wanted to handle errors from inside the Lox interpreter, the more I was inclined to try using the experimental effect system in OCaml.
It's like, yes, I'm pretty sure OCaml absolutely <em>would</em> allow me to make a module level ref and twiddle it back and forth, but I'd rather scope the ref to the <tt class="docutils literal">run</tt> function and make the caller handle the output.
So, I've written the helper functions that <em>produce</em> the effects, but I need to do a bit more work to be able to get the effect handler into the <tt class="docutils literal">run</tt> function.</p>
<p>Hopefully, if I skip ahead and around a bit, I can put together the proper code soon.
Ideally, without going to the next chapter before I get all of this handled.</p>
<p>I can work on that later.
For now (or, half an hour ago...) I should get ready for bed.</p>
<p>Good night.</p>
Coding 2023-06-302023-06-30T04:00:00-04:002023-06-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-30:/coding-2023-06-30<p class="first last">Expect a future entry to be much more frustrated.</p>
<p>I took another look at the code that I was planning to... "take inspiration from", and either one specific part of it is subtly non-idiomatic, or I don't understand idiomatic OCaml.
I'm going to assume the latter.
In any case, I'm now looking for some other place to start messing around in.</p>
<p>After I pondered it a little, something occurred to me that made a lot of sense: Lox from Crafting Interpreters.
I've gotten relatively far with it before, mainly hindered by the fact that I wanted language features that are in OCaml, but not so much in Lua.
So, if I'm focusing on the early parts of Crafting Interpreters, I can focus the effort of learning on "Okay, I know how to do this thing in a bunch of languages. What's the OCaml version?"</p>
<p>...</p>
<p>All right, I've gotten a few things done, but it's about to get weird.
I'm going to need to get error handling right, and that sounds like a thing to work on later.</p>
<p>Good night.</p>
Coding 2023-06-292023-06-29T04:00:00-04:002023-06-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-29:/coding-2023-06-29<p class="first last">Having a staring contest with OCaml, and blinking.</p>
<p>Okay.
I had a look at how the different structures with some group properties relate, and I don't think I can "just ignore" stuff like associativity, because of how it seems to interact with divisibility.</p>
<p>Trying to state what I actually want to accomplish here:</p>
<p>Any given structure should be able to specify "laws" that its operations satisfy, both as a run-time specification of a test, and as a compile-time specification of "capabilities that the module provides".
Because this doesn't necessarily relate to a single function or value, I want to somehow tag this information to the module itself.
Which means having something else in the struct to hold that static and run-time information.
I can't see any way through this that doesn't involve somehow constructing an intersection of types, be they module types, object types, or something else.</p>
<p>One thing that might help constrain what I'm looking for is to consider what the tests look like.
If I'm requiring that every property can be "pulled off" of the module where it definitely applies, then it needs to carry a reference to that module.
For now, let's assume that I <em>probably</em> shouldn't do that.</p>
<p>I'm going to try to revisit one of my original ideas...
Hm.
Wouldn't work, but now I'm curious about module constraints and extensions...</p>
<p>Ugh.
Nothing is coming together with this, so I'm looking at how other people have done stuff in this area.
I think I want to just swipe how other people have done this, and try to extend that with tests of the laws.</p>
<p>Maybe I can try that out later.
For now, I need to wind down.</p>
<p>Good night.</p>
Coding 2023-06-282023-06-28T04:00:00-04:002023-06-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-28:/coding-2023-06-28<p class="first last">All right, let's see what's the proper way to do this. (I do not see what the proper way to do this is.)</p>
<p>Well, I messed around in Peglin, but I'd rather work with OCaml stuff for this post.
Let's see about some of the stuff I was thinking about last time.</p>
<p>I decided to start off by trying to make some of the currently not-too-important code I wrote "actually work", and I ran into trouble.
Here's the deal.
Any algebraic structure that includes a magma can potentially have that magma be commutative.
This isn't too important to the main... does anyone call it the Group Theory Cube, or something like that?
But it's definitely something that comes up.
For example, the trivial group and the cyclic groups are commutative.
So, if I'm all like, "I want to mark the loops coming out of this functor as commutative", or whatever, then I need to be able to construct a signature for "a loop, but commutative".</p>
<p>I'm not sure if the way I'm currently trying to express this even makes sense in OCaml.
Like, the stuff I'm reading kind of makes it look like "stick stuff onto a random signature" isn't an intended thing, in part because the syntax I'm trying to use is very similar to the syntax for a completely different concept.
So, maybe I need some other way to mark "properties that only become apparent by calling the magma operation multiple times".
The first thing that I thought of is "something with phantom types", but that doesn't seem to have solved what I think is the actual hard part, of "some magmas can be associative, some can be associative, some can be both, some can be neither".
And worse, "what if somebody else thinks of a property to check?"</p>
<p>Maybe if I can figure out how to express "this set contains such and such member" as a type-level assertion, I can turn this idea into "there's a set of properties".</p>
<p>... Or maybe I can swing something with object types.
Like, structural typing gets me "I can sort of have type lattice stuff", but I think it's going to discard that information pretty aggressively.
I guess the big thing I need to think about is "how do I think this information is even going to get consumed?"
Like, I can figure out how to write tests for these properties, but I'm not sure how to express "these properties are needed for this context".</p>
<p>I'll have to think about it, and then commit to something for now.</p>
<p>Good night.</p>
Weekly Roundup 2023-06-272023-06-27T04:00:00-04:002023-06-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-27:/weekly-roundup-2023-06-27<p class="first last">Just trying to get to grip with the idiomatic way to do things in OCaml.</p>
<ul class="simple">
<li>Wednesday: I laid out some ideas for stuff to do in OCaml.</li>
<li>Thursday: I tried to explain what I'm trying to accomplish in OCaml.</li>
<li>Friday: I thought some about how to write the tests for the OCaml stuff.</li>
<li>Saturday: Peglin...</li>
<li>Sunday: I had even more thoughts about how to write the property-based tests in OCaml.</li>
<li>Monday: Didn't do much I guess.</li>
</ul>
<p>Next week, I'm hopefully going to get more done with OCaml or writing or something.</p>
Diary 2023-06-262023-06-26T04:00:00-04:002023-06-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-26:/diary-2023-06-26<p class="first last">I think I need to figure out how to take a break or something. Don't bother reading this post.</p>
<p>I was kind of out of it today, and we were doing stuff that I don't have anything to write about, so, eh.</p>
<p>It sucks that I don't have more to write for now, but I don't.</p>
<p>Good night.</p>
Coding 2023-06-252023-06-25T04:00:00-04:002023-06-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-25:/coding-2023-06-25<p class="first last">No idea what standards to apply.</p>
<p>I mostly took things easy today.
I did just now mess around with writing OCaml modules representing some simple groups.
From doing this, I concluded that I need to tweak things some more.</p>
<p>Here's the deal.
I wrote a functor that creates a cyclic group given a module containing an int.
However.
If I want to generate tests for such a module, I need to let the functor that generates the tests know what the order of the group is.</p>
<p>I <em>think</em> there are two ways to accomplish this:</p>
<ul class="simple">
<li>Create a new signature specifically for cyclic groups that exposes the order.</li>
<li>Create a functor that generates the relevant cyclic group, next to the module containing the tests.</li>
</ul>
<p>I think I'm going to need to reach out to someone who knows what they're doing, but my gut reaction is that it's probably more helpful in general to expose the order as part of the interface of the module.
My reasoning here is, suppose we have hypothetical other metaprogramming based around these kinds of functors.
I think it's a similar amount of effort to implement either option, but it <em>seems</em> more helpful for multiple forms of metaprogramming to all act on the same module, rather than generating their own copies.
(My recollection is that each invocation of a functor is a distinct module, even if the input modules are identical.)
And this would theoretically allow people to supply their own implementations of, for example, cyclic groups.
Not <em>obviously</em> helpful, but I don't see what preventing it would accomplish.</p>
<p>Anyway, it's late, and I should wrap things up.</p>
<p>Good night.</p>
Diary 2023-06-242023-06-24T04:00:00-04:002023-06-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-24:/diary-2023-06-24<p class="first last">Had some misplays, but still pulled it off clean.</p>
<p>Okay.
I poked a bit at the OCaml stuff, but didn't get too much done.
Some writing.
Some Peglin.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">*ahem*</p>
</div>
<p>Kind of a lot of Peglin.
If I get a few more good runs, I should get another orb unlocked.
It's not a <em>good</em> orb, but it's another orb.</p>
<p>I'm not thinking of anything else to write, so, oh well, calling it here.</p>
<p>Good night.</p>
Coding 2023-06-232023-06-23T04:00:00-04:002023-06-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-23:/coding-2023-06-23<p class="first last">I'm still not totally sure I've got the right overall organization here.</p>
<p>I just sketched out the eight basic signatures relevant to group theory.
The next thing to look into is the twelve functors that are apparently necessary to represent "forgetting parts of the structure".
Most of these should be really easy.
(I guess there can be a few more, but, eh.)</p>
<p>After all of that, I can start thinking about functors along the lines of "here is a generator function associated with this structure" and "here are the tests for checking specific properties", and then "here are the tests for checking combinations of properties".</p>
<p>Once I prove that stuff out with simple things like permutation groups, symmetry groups, and modular arithmetic, I can try to build out more elaborate structures, at which point I should have everything I need to work on stuff like geometric algebra.</p>
<p>Just pondering this a little, but I guess the test functors would need something like another set of signatures that just refer to the particular functions in use, and they can use that to be like "whatever module you pass in needs to express these capabilities".</p>
<p>I'm not sure, though.
Maybe it's sufficient to say "we compare the behavior to this simpler structure that does test for the property".
But where does that leave stuff like commutativity?</p>
<p>I'm going to see if these questions are any less vexing tomorrow.</p>
<p>Good night.</p>
Coding 2023-06-222023-06-22T04:00:00-04:002023-06-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-22:/coding-2023-06-22<p class="first last">Really not trying to throw shade with any of these comments.</p>
<p>Okay, yesterday in the summary, I promised to motivate my efforts to represent algebraic structures in OCaml.
The motivation is a little abstract, but I'm going to try anyway.</p>
<p>One common aspect of mathematics is to build complex concepts on top of simpler ones.
In some cases, it's essentially possible to swap out the specific "simpler concept" for a different one with similar properties.
To get even more hand-wavy, there is a type of algebraic structure called a "field", which is basically "something that you can do high-school algebra to", and "being able to do high-school algebra to something" is a prerequisite for being able to do <em>college-level</em> algebra to it.</p>
<p>In other words, if you have a bunch of fields, and a bunch of things that <em>do something</em> to fields, you can snap them together arbitrarily like legos with no physical form.
Basically, I want to really grasp stuff like geometric algebra, and, um, things that Norman Wildberger thinks would be easier to teach than current curricula, and also have the tools to pose questions like "what's the weirdest thing I can come up with that's still technically a 'triangle'?"</p>
<p>I'll see when I'm up for actually working on this; I was kind of tired and out of it today, so maybe tomorrow, maybe later.
For now...</p>
<p>Good night.</p>
Coding 2023-06-212023-06-21T04:00:00-04:002023-06-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-21:/coding-2023-06-21<p class="first last">I got so bogged down in the mid-level details here that I forgot to motivate this stuff any more concretely. Um, I have my reasons, trust me.</p>
<p>Okay, I'm kind of out of it right now, but I'd like to work through my ideas for other stuff to try with OCaml.
One concept that ML-style modules seem well-suited to representing is that of an <a class="reference external" href="https://en.wikipedia.org/wiki/Algebraic_structure">algebraic structure</a>, which is something that Missable Mysteries would have/will end up covering.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Kind of want to change the name...</p>
</div>
<p>I've tied myself in knots trying to fit an algebraic structure (admittedly a somewhat complicated one) into typed Python.
I think doing it in Rust would require a bunch of newtypes in the general case, because Rust traits are all about "the implementation" of a concept, and some of the really interesting stuff happens when you're explicitly manipulating multiple groups derived from the same set.</p>
<p>Whereas in OCaml, a specific algebraic structure would be a module, a kind of algebraic structure would be a module signature, and a mapping between algebraic structures, such as "forgetting" parts of a structure, would be a functor.</p>
<p>This is <em>slightly</em> short of what I want, because I'm not sure if there's a good statically-analyzable way to handle the <em>axioms</em> of an algebraic structure.
So, what I want to see if I can do is to express axioms in a form that a property-based testing library can handle.
I searched around a bit, and found <a class="reference external" href="https://github.com/c-cube/qcheck">qcheck</a>.</p>
<p>I think there are two basic concepts that need to be defined together to write the kind of tests I have in mind:</p>
<ul class="simple">
<li>An axiom corresponds to a test function.</li>
<li>An algebraic structure will have some associated types, which need to have some kind of generator to produce values.</li>
</ul>
<p>I guess all of this is going to take a bunch more modules and functors.
Like, given an algebraic structure with some signature, that needs to combine with a generator, which... stuff happens, and eventually a module pops out with a list of tests.</p>
<p>Properties to test include:</p>
<ul class="simple">
<li>totality</li>
<li>commutativity</li>
<li>associativity</li>
<li>divisibility</li>
<li>invertibility</li>
<li>identity</li>
<li>distributivity</li>
<li>forgetting properties in different orders results in structures with the same behavior</li>
</ul>
<p>I'm pretty tired, so I'm going to wrap this up now, and then sketch out exactly how I think this stuff should fit together.</p>
<p>Good night.</p>
Weekly Roundup 2023-06-202023-06-20T04:00:00-04:002023-06-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-20:/weekly-roundup-2023-06-20<p class="first last">The fact that I don't usually say to much about the day of these entries really cut down on the drama this week.</p>
<ul class="simple">
<li>Wednesday: Peglin and OCaml.</li>
<li>Thursday: Peglin and OCaml.</li>
<li>Friday: I worked a little on OCaml stuff, and included a digression that inspired me to somewhat improve keyboard-related stuff. That's not quite all the way done, but whatever.</li>
<li>Saturday: Some more progress with OCaml.</li>
<li>Sunday: Travel and Peglin.</li>
<li>Monday: Travel and sort of OCaml.</li>
</ul>
<p>Next week, I'm going to try and make more progress with OCaml, and maybe branch out into some stuff that I can talk about without worrying about "spoilers".</p>
Diary 2023-06-192023-06-19T04:00:00-04:002023-06-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-19:/diary-2023-06-19<p class="first last">*shrug*</p>
<p>And, we traveled back, and I'm still a little out of it.</p>
<p>I've been messing with some ideas for the OCaml stuff, and I'll try to execute on them later, but right now it's late and I need to get to bed.</p>
<p>Good night.</p>
Diary 2023-06-182023-06-18T04:00:00-04:002023-06-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-18:/diary-2023-06-18<p class="first last">The Peglin Wikia seems to have gotten painfully out-of-date.</p>
<p>We traveled today, so I'm kind of out of it.</p>
<p>Nevertheless, I now have almost all of the unlocks in Peglin that seem... reasonable?
I'm missing a seemingly very rare event combination, several Cruciball levels, and a relic that can only be unlocked in custom games.</p>
<p>The sensible thing to do is to try for the rare events while pushing Cruciball levels, since the custom unlock conditions look... silly.
Like, that there is a meme run.</p>
<p>Or maybe I'll step away from all that for now, and do, like, an All Skull Orbs custom run or something.</p>
<p>Anyway, it's late and I can't think of anything else to say.</p>
<p>Good night.</p>
Coding 2023-06-172023-06-17T04:00:00-04:002023-06-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-17:/coding-2023-06-17<p class="first last">It still doesn't actually compile. Oh well.</p>
<p>Okay, I'm still not feeling great, so I'm going to make this quick.</p>
<p>I poked at my OCaml Cryptopals code today, and I'm getting it into a position that I think makes more sense, but it's going to be even better once I put together some functors.
This is perhaps "ludicrous overkill", but I really really don't want to write two copies of this helper code.</p>
<p>(By the way I played a little Peglin and I can't tell if it was trying to unlock orbs or playing on the highest unlocked Cruciball, but Cruciball 7 is a <em>pain</em>.)</p>
<p>Anyway, I've got some more helper code to write.
It's really pleasant putting some of this stuff together.</p>
<p>For now, I really need to get to bed, though.</p>
<p>Good night.</p>
Coding 2023-06-162023-06-16T04:00:00-04:002023-06-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-16:/coding-2023-06-16<p class="first last">Not sure what messed me up so badly today, but at least I did something.</p>
<p>I wasn't up for much today, because I had a terrible headache for a lot of it.</p>
<p>I was able to start on <em>some</em> coding stuff though.
I've made several attempts over the years to do <a class="reference external" href="https://cryptopals.com/">Cryptopals</a> stuff in Python, and I've solved the early sets in, as I recall, a few different ways.
(I... don't want to actually look at the old code, because some of it is so cursed that I can't currently type like that, though that's admittedly more to do with not bothering to set up the proper keyboard-related software.)</p>
<p>I'm messing around with the code for the very first challenge.
Basically, putting a lot of effort into being a very specific kind of lazy.
Specifically, I'm not checking whether there are already libraries for what the challenge is about.
And I'm trying to avoid boilerplate.
This is going to make a bunch of the code really "clever", but that's kind of the point, so.</p>
<p>In any case, I still haven't had the time and focus to get this to a point where it all even compiles, so, you know, slow going with a new language.
I'll just have to keep at it.</p>
<p>Good night.</p>
Diary 2023-06-152023-06-15T04:00:00-04:002023-06-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-15:/diary-2023-06-15<p class="first last">Died to the final boss due to having no healing whatsoever. So sad.</p>
<p>Hoo boy, finally got the Balladin.
Now I just need to figure out what random stuff I still need to unlock.
I think there are a few things that I assume I must have taken that I actually haven't.
The other side of it, of course, is events in the Castle that just.
don't.
spawn.</p>
<p>Anyway, I'm done with that for tonight.
After I post this, I'm going to mess around with OCaml stuff...</p>
<p>Good night.</p>
Diary 2023-06-142023-06-14T04:00:00-04:002023-06-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-14:/diary-2023-06-14<p class="first last">I guess I'm taking things easy?</p>
<p>Still trying to get that really nice Ballwark build in Peglin, but at least I've grabbed a few new orbs.</p>
<p>Aside from that, I'm still trying to learn OCaml, and trying to work on Fair Fights.
I made a separate blog for Fair Fights stuff, and I'll link it once there's anything there.</p>
<p>As far as OCaml goes, I'm most interested to learn the equivalent, where applicable, of common Python idioms, because if I try to just translate stuff over in a literal way, that... is unlikely to work.</p>
<p>Anyway, it's late and I should get to bed.</p>
<p>Good night.</p>
Weekly Roundup 2023-06-132023-06-13T04:00:00-04:002023-06-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-13:/weekly-roundup-2023-06-13<p class="first last">Peglin.</p>
<ul class="simple">
<li>Wednesday: I played Peglin and did <em>a little</em> conlanging.</li>
<li>Thursday: Just all Peglin.</li>
<li>Friday: More Peglin, and messing with learning programming languages.</li>
<li>Saturday: More Peglin, and I wondered whether there's an "intended" time to get into custom starts.</li>
<li>Sunday: We went out and did a bunch of stuff, and I somehow had the energy for Peglin afterwards.</li>
<li>Monday: Yet more Peglin.</li>
</ul>
<p>Next week, I'm not going to lie, there's probably going to be more Peglin.
I've got a few other things I might have <em>something</em> to say about, but we'll see.</p>
Diary 2023-06-122023-06-12T04:00:00-04:002023-06-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-12:/diary-2023-06-12<p class="first last">Getting up early so I can get plenty of rest, or something.</p>
<p>I was pretty out of it today.
I unlocked <em>stuff</em> in Peglin, but I forget exactly what.
A few relics that I was like "Now I can feel okay about never taking this again", and some like "Oh, I probably had a build in the past that would have benefited from this, but I forgot about the relevant stuff for the synergies."</p>
<p>Aside from that, I just mostly took things easy.</p>
<p>Messed around with my appearance a little.
It's a work in progress, and I don't want to go into any more detail right now.</p>
<p>I don't remember if there was anything else worth talking about, so I'm just going to cut this now.</p>
<p>Good night.</p>
Diary 2023-06-112023-06-11T04:00:00-04:002023-06-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-11:/diary-2023-06-11<p class="first last">Crowds...</p>
<p>Ooouuuugh...</p>
<p>I feel like a ping-pong ball that was in a dryer.
That didn't stop me from unlocking a Cruciball level, but I don't really feel like doing anything else now.</p>
<p>Okay, time to try to relax.</p>
<p>Good night.</p>
Diary 2023-06-102023-06-10T04:00:00-04:002023-06-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-10:/diary-2023-06-10<p class="first last">Seems like games are what I'm up for currently.</p>
<p>Whew, making more progress in Peglin.
I ended up with a bunch of conflicting synergies, that basically compensated for the fact that they worked against each other by just always swinging high.
Just like, "this is a Muscircle build!" *crits constantly*</p>
<p>One thing I find myself wondering is, is there an "intended" time to mess around with custom starts?
Like, if I notice some weird interaction, should I just go for it and see what happens, even though I'm not yet halfway through the current crop of Cruciballs?</p>
<p>I guess I'll ask around somewhere.
Right now, I need to wrap stuff up.</p>
<p>Good night.</p>
Diary 2023-06-092023-06-09T04:00:00-04:002023-06-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-09:/diary-2023-06-09<p class="first last">NABTO going off in some kind of direction.</p>
<p>It's possible that "unlock new orbs and relics", "unlock more Cruciball levels" and "unlock new characters" are goals that I shouldn't be trying to pursue all simultaneously.
Oh well.</p>
<p>Anyway, I ended up deciding to focus on learning OCaml for coding, at least for now.
My rationale is that the OCaml/Koka side of things is part of what I want to draw from for NABTO, with Python on the other side, and I want to have a better handle on OCaml, especially the module system, before I commit to any design decisions.
Like, I think there are a bunch of issues I have with Python that would be addressed by having ML-style modules instead of class-based inheritance, but I'm encountering some trade-offs when I imagine going all-in.</p>
<p>I don't want to speculate too much, but it <em>looks</em> like the next thing I'd want to look into, once I have a handle on OCaml (and I'm just now starting out, currently), is Julia.
But, like, one thing at a time.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">*cough* GDScript *cough*</p>
</div>
<p>Two-ish things at a time.</p>
<p>Anyway, it's getting late and I want to wrap things up for tonight.</p>
<p>Good night.</p>
Diary 2023-06-082023-06-08T04:00:00-04:002023-06-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-08:/diary-2023-06-08<p class="first last">Complete miracle that I won.</p>
<p>Peglinnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn...</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Use your words.</p>
</div>
<p>That was a really spicy build I just pulled off.
Sapper's Sack and a bunch of Ballwark orbs, as well as <em>a bunch</em> of other bomb relics.
Basically, I was constantly building bunkers around myself to compensate for the fact that I kept blowing up literally everything on screen.
I had no reliable in-battle healing.
I would have lost at the end if I hadn't kept an egg.</p>
<div class="admonition smiley smiley-glitchy">
<p class="first admonition-title">:) (glitchy)</p>
<p class="last">This is super fun and not at all terrifying.
You all should try it.</p>
</div>
<p>In any case, I unlocked some things, but not the stuff I was really hoping for.
And now, I'm going to make an effort to <em>not</em> stay on my laptop for another hour, so I'm ending this here.</p>
<p>Good night.</p>
Diary 2023-06-072023-06-07T04:00:00-04:002023-06-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-07:/diary-2023-06-07<p class="first last">I thought I wasn't going to do anything on Fair Fights, but then I did a little, not enough to change the category though.</p>
<p>Peglinnnnnnnnnn...</p>
<p>I unlocked the Roundrel.
Like, nearly six times over.
The final boss got down to a quarter health and then instantly died to the ridiculous amount of spinfection I stacked on it.</p>
<p>Writing stuff for the blog made me remember about Fair Fights, so I messed around with some word order stuff.
And, while writing this post, I got far enough for now, that I'm going to try to take what I've got so far, and put it together into names, see what I'm missing.</p>
<p>Once I've named, like, two monsters, I'll try to get back to game design and learning the tools.</p>
<p>Right now, though, I'm going to wind down.</p>
<p>Good night.</p>
Weekly Roundup 2023-06-062023-06-06T04:00:00-04:002023-06-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-06:/weekly-roundup-2023-06-06<p class="first last">It's hard to think when it's hot; fortunately we should be able to deal now.</p>
<ul class="simple">
<li>Wednesday: I messed around with stuff for the Fair Fights conlang.</li>
<li>Thursday: I was kind of out of it. I contemplated speedruns that may or may not be interesting.</li>
<li>Friday: I tried to do a bit more with the Fair Fights conlang, but I was really suffering through the heat.</li>
<li>Saturday: I convinced building management to send someone to look at the AC. Building management did not convince them to show up that day.</li>
<li>Sunday: The HVAC issues got explained and worked around, just in time for the heat to break. Oh well. I messed around some more with the Fair Fights conlang.</li>
<li>Monday: I mostly played a bunch of Peglin.</li>
</ul>
<p>Next week, I'm going to try to make some progress on the conlang, then put it on hold to learn GDScript.
I'm thinking I'll also mess around with OCaml and BQN.
That... probably won't be confusing.</p>
Diary 2023-06-052023-06-05T04:00:00-04:002023-06-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-05:/diary-2023-06-05<p class="first last">I've got to write something every day. This is something. Therefore, it was enough to write it.</p>
<p>So many things seem to be happening right now, and I haven't put in any real effort with that last Can of Wormholes level.
I did spend a bunch of today being... not super great at Peglin yet.</p>
<p>I then ended up spending a bunch of time, instead of writing this post, trying and failing to figure out a simple way to convert a GitHub Pages site that uses a bunch of non-ASCII characters into a format that I can get on my e-reader.
I may have something, but I'll have to look into it tomorrow.
Because it's tomorrow now...</p>
<p>Good night.</p>
Fair Fights 2023-06-042023-06-04T04:00:00-04:002023-06-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-04:/fair-fights-2023-06-04<p class="first last">Incremental but necessary progress.</p>
<p>A big thanks to the HVAC technician who showed up (a day late, but whatever...) and both noticed what was wrong with the system, and <em>explained it</em>.
This reflects really poorly on literally every other professional who has looked at the system over the past two years, but, again, whatever.</p>
<hr class="docutils" />
<p>Anyway, let's ponder how to make the Fair Fights Conlang sound the way I want it to.</p>
<p>I've elected to give its syllables a modest collection of codas, but more extensive a set than what the cipher produces naturally.
This is helpful, because I want to give the nouns some inflections based on gender and case.
That's reasonable for a naming language, right?
Because you have to know how you're using the nouns that you're naming stuff with.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">They can't respond before you send the post.</p>
</div>
<p>Everyone's in agreement, then.
Good.</p>
<p>Anyway, I want two or three genders here, and as far as cases go, the genitive for sure, dative is probably okay, and to round things out...</p>
<p>I am going to see how far I can get with ergative and absolutive.
Make absolutive the "dictionary" case, and express the others via suffixes of some kind.</p>
<p>I seem to have run out of inspiration for the night, so I'm going to just cut this off and wrap up for now.</p>
<p>Good night.</p>
Diary 2023-06-032023-06-03T04:00:00-04:002023-06-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-03:/diary-2023-06-03<p class="first last">It's going to rain for a week, but at least I'll be cool.</p>
<p>I've almost 100%ed Can of Wormholes.
Some of these puzzles are a bit much.
Like, not figuring out what shape I'm supposed to make until I paste a screenshot into an image editor and mess with it.
Just a bit more of this, and I should be done.
I don't quite understand one of the achievements, but whatever.</p>
<p>Oh, what's the status of the air conditioning?
WELL</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Hold please.</p>
</div>
<p>DON'T KNOW WHY THEY WOULDN'T BELIEVE ME IN THE FIRST PLACE</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Oh boy, there's some kind of glitching going on.</p>
</div>
<p>SAME ABILITY TO MAKE THE STATED TIME AS TO</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">We might be at this for a while.</p>
</div>
<p>COULD HAVE AVOIDED ALL OF THIS IF THEY'D DONE IT RIGHT TWO YEARS AGO</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Oof. Bring it in, would you.</p>
</div>
<p>HUFF</p>
<p>HUFF</p>
<p>So, that's been my day.</p>
<p>Oh yeah, last night, I came up with some phonotactics for the Fair Fights conlang, so I'll try applying those tomorrow to see if they help make things more palatable.
Maybe I'll try to get started on that after I publish this, maybe not.
Either way, I'm going to call this entry here.</p>
<p>Good night.</p>
Fair Fights 2023-06-022023-06-02T04:00:00-04:002023-06-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-02:/fair-fights-2023-06-02<p class="first last">I wish we could just skip ahead past the point where the AC cooks us.</p>
<p>I wasn't up for much today, and I won't be up for much tomorrow, because we're hitting high highs, and the HVAC in the apartment is [WORKING PERFECTLY FINE – source: people who aren't <em>in here</em> all day].</p>
<p>But I want to make some kind of progress on the Fair Fights conlang.
I'm going to look for patterns in the stuff I've labeled as good so far.</p>
<ul class="simple">
<li>Use of /u/</li>
<li>Detectable patterns in related words</li>
<li>Possibly, use of /ja/</li>
</ul>
<p>Unfortunately, it's pretty late, so I'm going to try to cut this short.
Looking at what I have, I think I need to put together proper phonology and phonotactics, because I skipped doing that due to the cipher.
That might give me a vaguely more principled way to reject some of the stuff I didn't like.</p>
<p>Anyway, time to flop over in bed and stew in my sweat.</p>
<p>Good night.</p>
Diary 2023-06-012023-06-01T04:00:00-04:002023-06-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-06-01:/diary-2023-06-01<p class="first last">I haven't really said much about Can of Wormholes. It's good.</p>
<p>The weather today wiped me out a little.
I did some writing, but not for Fair Fights.
Played more Can of Wormholes, which I've been playing a bunch; I'm currently at eighty-something percent, though all of the meaningful shortfall is in the final world.</p>
<p>... I wonder what the low% runs for Can of Wormholes look like.
Like, you can skip some puzzles I think, although every puzzle that you use for wires you have to solve anyway, and it doesn't seem necessary to get every rocket to at least get started on the final world.
Although, it's possible I'm overthinking this; I don't remember if I know the conditions for getting the credits...</p>
<p>Hm.
I'm watching an any% run now, and I'm clearly going to have to look up what actually gates the ending.
Looking at all of the stuff the runner <em>isn't</em> doing, I'm now not sure how interesting the low% routing can be.</p>
<p>Oh well.
I'll see if I'm up for more stuff tomorrow.</p>
<p>Good night.</p>
Fair Fights 2023-05-312023-05-31T04:00:00-04:002023-05-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-31:/fair-fights-2023-05-31<p class="first last">I really hope I'm only down this rabbit hole for, like, a week.</p>
<p>I'm still categorizing roots, but at this point, I should be good to rate the many roots, and look for common patterns in the ones I like.
Once I get some solid patterns in the parts of speech I'm considering, I'll start entering stuff into a database to hopefully be able to handle stuff like sound changes so I can get the conlang that I actually want.</p>
<p>For right now, I'm going to lie down and mess with the number system.
It's getting late and I want to stop looking at my screen.</p>
<p>Good night.</p>
Weekly Roundup 2023-05-302023-05-30T04:00:00-04:002023-05-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-30:/weekly-roundup-2023-05-30<p class="first last">Changing my focus around a bit.</p>
<ul class="simple">
<li>Wednesday: I decided to step away from MOTR in particular, and Python in my spare time in general, because I was having such a bad time with the <tt class="docutils literal">saltate</tt> lugin.</li>
<li>Thursday: I started learning Godot.</li>
<li>Friday: I made a little more progress following along with the Godot tutorials.</li>
<li>Saturday: Nothing really happened apparently.</li>
<li>Sunday: I made a new category, for a project which is already several layers deep in weird detours.</li>
<li>Monday: I hopefully made some progress within the weird detours.</li>
</ul>
<p>Next week, I'm going to try to get the Fair Fights stuff to the point where I can name a monster, finally.</p>
Fair Fights 2023-05-292023-05-29T04:00:00-04:002023-05-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-29:/fair-fights-2023-05-29<p class="first last">Currently taking a text file and just turning it into absolute nonsense.</p>
<p>Okay, here we go.
I've got a start on the roots, and they're ciphered.
At this point, I need to kind of rate the resulting roots and pick out any patterns.
As a run-up to this, I redid the part-of-speech classification for some of the roots.
It <em>maybe</em> would have made more sense to do that before I picked out roots and ciphered them, but whatever, it's fine.</p>
<p>The current status is, some of the roots look a little hard to pronounce, and I don't really like some of them, while some of them I like a lot, and others show some patterns I could work with.
I'm currently not up for rating and drawing connections for this stuff, but hopefully in the next few days.</p>
<p>Until then, I'm going to sleep.</p>
<p>Good night.</p>
Fair Fights 2023-05-282023-05-28T04:00:00-04:002023-05-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-28:/fair-fights-2023-05-28<p class="first last">A new category? I can do that? Um, anyway, this is why I'm eventually learning GDScript.</p>
<p>So, Fair Fights.
Here's the deal.</p>
<p>I've been messing around a bunch with the concept of a fakemon region.
However, in the end, I decided to step away from "fan content for an existing franchise", and tried to come up with something similar but distinct.
Playing a little bit of <a class="reference external" href="https://www.cassettebeasts.com/">Cassette Beasts</a> gave me the inspiration I needed to take the core combat mechanics in a different direction, and I ended up coming up with a few other ideas that further distinguished things.
I won't go over those just yet, because I want to learn enough Godot to put together a prototype to determine whether all of these ideas are actually... good.</p>
<p>In any case, right now I want to focus on designing monsters, and part of that is coming up with names for them.
As far as design goes, I want to consciously distance myself from Pokémon's design sensibilities, and to start with:</p>
<ul class="simple">
<li>Instead of "balancing cool and cute", I want to come up with designs that are "both ethereal and powerful"</li>
<li>I want some other system for naming, different from puns, words smashed together, or just the name or sound of an animal</li>
</ul>
<p>For the latter, I'm currently trying out "create a naming conlang", which feels like maybe a decision not made from an objective assessment of multiple alternatives, but oh well.</p>
<p>Here is my basic plan for attempting this:</p>
<ul class="simple">
<li>Get a list of root words that seem relevant for coming up with names.</li>
<li>Add roots relevant to Fair Fights.</li>
<li>Pick a source language so I can be kind of lazy about coming up with roots.</li>
<li>Apply an <a class="reference external" href="http://jbr.me.uk/crypto.html">Ostamer-style cipher</a> to the source language so the derivations aren't blatantly obvious.</li>
<li>Look for patterns in the limited set of roots I'll choose, and try to regularize according to those patterns.</li>
<li>Come up with morphological derivation rules that take advantage of those patterns, as well as paradigms for conjugation and declension.</li>
<li>A few rounds of sound change.</li>
</ul>
<p>All of these steps, except the last three, are either done or straightforward.
I'm not sure about the third-from-the last or the second-from-the-last; we'll have to see.
The last one could be a pain, because I'm not sure what the best way is to apply sound changes.
I'm aware of a few different software packages where I'm not sure how to pick between them, and just doing everything manually is a possibility that I can keep in mind, but I kind of don't want to.</p>
<p>Anyway, I'll get to that once I'm done with the rest.
Maybe it'll get me something I like, maybe it won't, but hopefully I'll be able to use what I learn in other projects.
For now, I'm going to wind down.</p>
<p>Good night.</p>
Diary 2023-05-272023-05-27T04:00:00-04:002023-05-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-27:/diary-2023-05-27<p class="first last">I've been having a lot of these lately. Oh well, safe to skip.</p>
<p>Um...</p>
<p>What did I do today?
Spaced out a bunch, I guess.</p>
<p>I think the best use of my time would be to cheap out on this entry, and try to find a good angle for designing stuff in Fair Fight.</p>
<p>Good night.</p>
Coding 2023-05-262023-05-26T04:00:00-04:002023-05-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-26:/coding-2023-05-26<p class="first last">Taking things slowly. Admittedly, very slowly, but whatever.</p>
<p>A few quick thoughts on the Godot tutorials I've worked through so far:</p>
<ul class="simple">
<li>Given my background, GDScript's syntax so far seems, like, aggressively approachable.
We'll see if that keeps up.</li>
<li>I remember reading blog posts that had strong opinions about interactions between simulation steps and framerate.
...
*websearch*
...
Ah, it looks like <a class="reference external" href="https://docs.godotengine.org/en/stable/tutorials/scripting/idle_and_physics_processing.html">I'm getting ahead of things</a>.</li>
<li>The movement example feels painfully janky to luck at.
I don't know if that's a result of running it in debug mode, having too many browser tabs open, or what, but I kind of expected my machine to be able to handle a simple scene.
...
Okay, yeah, it was the browser tabs.</li>
</ul>
<p>Hopefully, I won't run into too many issues in this area, since the game I want to make, codenamed Fair Fights (I need to find something with more unique initials) is turn-based-ish.
Stutter won't open up weird exploits, it'll just look kind of bad, so hopefully I'll be able to avoid it, but we'll see.</p>
<p>Anyway, that's enough for now.
I'm going to get to bed, and see what I'm up for tomorrow.</p>
<p>Good night.</p>
Coding 2023-05-252023-05-25T04:00:00-04:002023-05-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-25:/coding-2023-05-25<p class="first last">Not much to say; it's a little hard to think in this weather, with this pollen.</p>
<p>All right, I'm still getting up to speed on Godot.
It's late right now, but up next is actually learning about GDScript.</p>
<p>So, tomorrow, I'll hopefully be up for getting on with that.
For now, I'll sketch out ideas for the game I want to try to make.</p>
<p>And cool off, because it is roasting in here, and my laptop isn't helping.</p>
<p>Good night.</p>
Coding 2023-05-242023-05-24T04:00:00-04:002023-05-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-24:/coding-2023-05-24<p class="first last">Nothing says "cool feature request" like withdrawing it accompanied by "I cannot in good conscience ask for this"</p>
<p>Okay.
I'm going to take a break from MOTR and MOTR auxiliaries for a while, so I'm currently looking at programming languages besides Python.</p>
<p>There are a bunch of languages that I'm varying levels of interested in, but I'm focusing on Godot, because one thing I want to try doing more is talking about this stuff with my wife, and that's simply easier if I'm focused on making games, or something like them.</p>
<p>Right now, I'm still going over the basics of the documentation.</p>
<p>...</p>
<p>And spacing out.
Not going to get anything else done right now.</p>
<p>Good night.</p>
Weekly Roundup 2023-05-232023-05-23T04:00:00-04:002023-05-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-23:/weekly-roundup-2023-05-23<p class="first last">Really not a fan of how the current version of the <tt class="docutils literal">saltate</tt> plugin falls over and catches fire in the face of any mildly non-trivial usage of inheritance.</p>
<ul class="simple">
<li>Wednesday: I gave some thought to extending the <tt class="docutils literal">saltate</tt> plugin to handling <tt class="docutils literal">Union</tt>s. Which is not a thing I need it to handle, but it seems reasonable.</li>
<li>Thursday: I implemented <tt class="docutils literal">Union</tt> support, and wrote tests for a few other cases.</li>
<li>Friday: I noticed that the <tt class="docutils literal">saltate</tt> plugin introduces implicit typecasts (as opposed to the explicit ones) if you do stuff that I don't care about, and tried to figure out what to do about that.</li>
<li>Saturday: I noticed <em>another</em> issue with the <tt class="docutils literal">saltate</tt> plugin caused by inheritance. Absurd.</li>
<li>Sunday: Nothing worth writing about happened.</li>
<li>Monday: Nothing worth writing about happened.</li>
</ul>
<p>Next week, maybe I'll work myself up to sort of finishing the <tt class="docutils literal">saltate</tt> plugin, but also I'm thinking of messing with other programming languages than Python for a bit.</p>
Diary 2023-05-222023-05-22T04:00:00-04:002023-05-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-22:/diary-2023-05-22<p class="first last">Let's see how I feel after sleeping. (This post can also be skipped.)</p>
<p>Okay, I think I had something wrong with me these last few days.
I was kind of out of it, and then I felt much worse, and now, I'm... probably okay?
We'll see.</p>
<p>I did mess around getting some stuff set up earlier today, and maybe I'll play with it later in the week.</p>
<p>For now, I just want to lie down and relax.</p>
<p>Good night.</p>
Diary 2023-05-212023-05-21T04:00:00-04:002023-05-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-21:/diary-2023-05-21<p class="first last">Not sure exactly what happened to me today, but this is another post that it's safe to skip.</p>
<p>I'm not feeling great today.
Just... super out of it.</p>
<p>I've decided to deal with this by skimping on this post, and doodling ideas in my notebook.</p>
<p>Hm, yeah, okay, nothing else to say right now.</p>
<p>Good night.</p>
Coding 2023-05-202023-05-20T04:00:00-04:002023-05-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-20:/coding-2023-05-20<p class="first last">Trying to decide how much of a jerk I want to be to hypothetical future users of this stuff.</p>
<p>Iiii got distracted.</p>
<p>However, I also noticed and fixed another issue in the <tt class="docutils literal">saltate</tt> plugin.
I'm not sure how that code is handling being such a bundle of issues...</p>
<p>Anyway, the problem was, I was erasing types too aggressively.
<em>Technically</em>, this isn't a problem for my use case, because I barely use subclassing.
But from a theoretical perspective...</p>
<p>Basically, if you have a <tt class="docutils literal">class Base(Generic[T])</tt> and a <tt class="docutils literal">class Derived(Base[int])</tt>, then it can't be sound to treat a <tt class="docutils literal">Derived</tt> as a <tt class="docutils literal">Base[str]</tt>.
Or any other example you care to come up with.</p>
<p>The solution is simple: for the subtype check (which I mostly have in place to deal with unions), erase the types on the <tt class="docutils literal">inst</tt> arg, but not on the <tt class="docutils literal">typ</tt>.</p>
<p>I still need to work out what I want it to do for non-final classes.
I guess I can argue: "It might not be valid, but if it is, then the return value is of type <tt class="docutils literal">typ</tt>, and any attribute on <tt class="docutils literal">inst</tt> but not <tt class="docutils literal">typ</tt> is, let's say required and of type <tt class="docutils literal">Any</tt>, and if <tt class="docutils literal">inst</tt> is non-final, maybe add a <tt class="docutils literal">**kwargs: Any</tt> of some kind, except I'm not sure how to handle name collisions in that case..."</p>
<p>I'll think about it some more, but right now, I let things get way too late and I need to get to bed.</p>
<p>Good night.</p>
Coding 2023-05-192023-05-19T04:00:00-04:002023-05-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-19:/coding-2023-05-19<p class="first last">This nonsense is making me wish that NABTO existed...</p>
<p>Oh dear...
I realized that the <tt class="docutils literal">saltate</tt> plugin has some problems that the <tt class="docutils literal">evolve</tt> code it's based on does not, and I'm not quite sure what to do about them.</p>
<p>Basically, the saltation operation is not valid if the runtime type is a strict subtype of the analyzed type, because attrs subclasses can add attributes.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">That... sounds like a dealbreaker.</p>
</div>
<p>Not if I disallow passing subclassable types!</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">... Which of us is which, again?</p>
</div>
<p>Really, the only thing I'm not sure of is whether I want passing non-final types to be a hard error, or to simply complain.</p>
<p>But if it does fail, should I have it go all the way to <tt class="docutils literal">Any</tt>, or accept some kind of best guess for what the arguments would be?</p>
<p>And I thought of more issues while I was pondering this stuff.
Let's see which questions I need to answer...</p>
<ul class="simple">
<li>What guarantees are broken if just the <tt class="docutils literal">typ</tt> argument allows subclassing?</li>
<li>What guarantees are broken if the <tt class="docutils literal">inst</tt> argument allows subclassing?
Note that <tt class="docutils literal">inst</tt> should be a subclass of <tt class="docutils literal">typ</tt>, so it can't be the case that only <tt class="docutils literal">inst</tt> allows subclassing?</li>
<li>Does the union-related code I copied out of the attrs plugin have the desired behavior in the context of <tt class="docutils literal">saltate</tt>?</li>
</ul>
<p>I'll have to think about this more later...
For now, I need to wind down properly.</p>
<p>Good night.</p>
Coding 2023-05-182023-05-18T04:00:00-04:002023-05-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-18:/coding-2023-05-18<p class="first last">I feel like I should have more to say about this, but I... don't.</p>
<p>All right.
I've got support in for union types in <tt class="docutils literal">saltate</tt>.
I don't anticipate that I'll use it in MOTR, but it was going to bother me that it wasn't there.
Let's see what's next to boost coverage...</p>
<p>Bounded typevar?
Oh boy, that might actually break things?
Huh, it did okay.</p>
<p>Well, there are a few more execution paths to puzzle out.
I'll get those later.
For now, I'm going to take things easy.</p>
<p>Good night.</p>
Coding 2023-05-172023-05-17T04:00:00-04:002023-05-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-17:/coding-2023-05-17<p class="first last">Figuring out One Weird Trick for handling more cases, and incidentally cleaning up the overall structure of the code.</p>
<p>Okay, let's think about the <tt class="docutils literal">saltate</tt> plugin some more.
There are a few transformations and checks I want to do.
Currently, on line 131, it expects to receive a <tt class="docutils literal">typ</tt> that is a <tt class="docutils literal">TypeType</tt>, an <tt class="docutils literal">AnyType</tt>, or just wrong.
This needs to be extended to handling a <tt class="docutils literal">UnionType</tt>.
For a <tt class="docutils literal">UnionType</tt>, we basically need to handle any of the <tt class="docutils literal">items</tt> potentially being <tt class="docutils literal">Any</tt> or otherwise not <tt class="docutils literal">TypeType</tt>.</p>
<p>Something like:</p>
<div class="highlight"><pre><span></span><span class="n">return_permissive</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">magic_func</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
<span class="n">item</span> <span class="o">=</span> <span class="n">get_proper_type</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">TypeType</span><span class="p">):</span>
<span class="k">pass</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">AnyType</span><span class="p">):</span>
<span class="n">return_permissive</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">ctx</span><span class="o">.</span><span class="n">api</span><span class="o">.</span><span class="n">fail</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="n">return_permissive</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">break</span>
<span class="k">if</span> <span class="n">return_permissive</span><span class="p">:</span>
<span class="k">return</span> <span class="n">permissive_signature</span>
</pre></div>
<p>I'm not feeling great about the exact structure there, but anyway.
Line 136 converts the <tt class="docutils literal">TypeType</tt> or the <tt class="docutils literal">UnionType</tt> of <tt class="docutils literal">TypeType</tt>s into either the underlying type, or the union of the underlying types.
I can get that by augmenting the above lines.</p>
<div class="highlight"><pre><span></span><span class="n">return_permissive</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">items</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">magic_func</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
<span class="n">item</span> <span class="o">=</span> <span class="n">get_proper_type</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">TypeType</span><span class="p">):</span>
<span class="n">items</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">item</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">AnyType</span><span class="p">):</span>
<span class="n">return_permissive</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">ctx</span><span class="o">.</span><span class="n">api</span><span class="o">.</span><span class="n">fail</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="n">return_permissive</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">break</span>
<span class="k">if</span> <span class="n">return_permissive</span><span class="p">:</span>
<span class="k">return</span> <span class="n">permissive_signature</span>
<span class="n">typ_type</span> <span class="o">=</span> <span class="n">UnionType</span><span class="o">.</span><span class="n">make_union</span><span class="p">(</span><span class="n">items</span><span class="p">)</span>
</pre></div>
<p>The next code to handle is at 159.
I'm not quite sure what has to be done here.
There are two angles to take.
The actual type comparisons have to reach into the unions, and convert all args to <tt class="docutils literal">Instance</tt> types to <tt class="docutils literal">Any</tt>.
For diagnostics, I need to construct a sequence of names, and potentially do extra formatting to it.</p>
<p>I think I understand how all of this needs to be implemented, but I don't want to do it right now.
At least I'm pretty sure I know what to do.</p>
<p>And what to do now, is get ready for bed.</p>
<p>Good night.</p>
Weekly Roundup 2023-05-162023-05-16T04:00:00-04:002023-05-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-16:/weekly-roundup-2023-05-16<p class="first last">My hope with MOTR is that I can get it into a state where I can once again routinely get this kind of "switching projects" boost.</p>
<ul class="simple">
<li>Wednesday: I cooled off a little after getting the <tt class="docutils literal">saltate</tt> plugin not quite working. While I was messing around, I discovered that the site theme was a little illegible, according to Color Science.</li>
<li>Thursday: I got the new theme mostly done, but elected to hold off due to a few issues.</li>
<li>Friday: I fixed a bunch of problems, and got the theme to a point where I'm happier with it now than I ever was with the old one, so I pushed it out.</li>
<li>Saturday: I tried to work out exactly how deficient the <tt class="docutils literal">saltate</tt> plugin currently is. The answer is, just enough to bother me.</li>
<li>Sunday: We traveled.</li>
<li>Monday: We did not travel, but I didn't have anything to write about regardless, so eh.</li>
</ul>
<p>Next week, I can either try to finish up the <tt class="docutils literal">saltate</tt> plugin, or conclude that it's good enough for my current purposes, so I can push ahead using it.
Maybe both?</p>
Diary 2023-05-152023-05-15T04:00:00-04:002023-05-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-15:/diary-2023-05-15<p class="first last">Still nothing to see here.</p>
<p>I'm still taking things easy.
Playing puzzle games a bunch.</p>
<p>Not coming up with anything substantive to put in a post.</p>
<p>I'm going to just cut this off early again, because otherwise I'd probably spend half an hour not making this post any longer, when I could simply have it not be any longer now.</p>
<p>Good night.</p>
Diary 2023-05-142023-05-14T04:00:00-04:002023-05-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-14:/diary-2023-05-14<p class="first last">Nothing to see here.</p>
<p>And we traveled today, so I'm not sure what to write about.</p>
<p>I'm just going to try to take things easy, maybe doodle some stuff in my notebook.</p>
<p>For now, this is it.</p>
<p>Good night.</p>
Coding 2023-05-132023-05-13T04:00:00-04:002023-05-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-13:/coding-2023-05-13<p class="first last">Wait, have I already done this before?</p>
<p>Okay, here we are, looking at the <tt class="docutils literal">saltate</tt> plugin again.
The key thing here is, I need to understand exactly how the "proper types" in Mypy work, because there are a lot of them, and what I'm doing currently is not quite right.
I need to work out how to activate each type of proper type, the correct behavior for it, and to devise corresponding tests.</p>
<p>Let's see...</p>
<ul class="simple">
<li><tt class="docutils literal">TypeVarLikeType</tt><ul>
<li><tt class="docutils literal">TypeVarType</tt></li>
<li><tt class="docutils literal">ParamSpecType</tt></li>
<li><tt class="docutils literal">TypeVarTupleType</tt></li>
<li>I believe these should be treated as either their upper bound, or <tt class="docutils literal">Any</tt>.
Maybe fail?</li>
</ul>
</li>
<li><tt class="docutils literal">UnboundType</tt> I'm not sure what to do with this if it shows up.</li>
<li><tt class="docutils literal">CallableArgument</tt> Should not show up.</li>
<li><tt class="docutils literal">TypeList</tt> Should not show up.</li>
<li><tt class="docutils literal">UnpackType</tt> Should not show up.</li>
<li><tt class="docutils literal">AnyType</tt> Should already be handled.</li>
<li><tt class="docutils literal">UninhabitedType</tt> Should be treated as <tt class="docutils literal">Any</tt>. Maybe can obtain using <tt class="docutils literal">NoReturn</tt>?</li>
<li><tt class="docutils literal">NoneType</tt> It's <tt class="docutils literal">None</tt>. Should fail.</li>
<li><tt class="docutils literal">ErasedType</tt> Not sure how to hit this.</li>
<li><tt class="docutils literal">DeletedType</tt> I don't have an intuition for how this should interact with any of the plugin. Should probably just fail.</li>
<li><tt class="docutils literal">Instance</tt> I'm trying to handle this already.</li>
<li><tt class="docutils literal">FunctionLike</tt>: <tt class="docutils literal">CallableType</tt> and <tt class="docutils literal">Overloaded</tt> These should fail.</li>
<li><tt class="docutils literal">Parameters</tt> Probably should not show up.</li>
<li><tt class="docutils literal">TupleType</tt> Should fail.</li>
<li><tt class="docutils literal">TypedDictType</tt> Should fail.</li>
<li><tt class="docutils literal">RawExpressionType</tt> Should not show up.</li>
<li><tt class="docutils literal">LiteralType</tt> Should fail.</li>
<li><tt class="docutils literal">UnionType</tt> <strong>Needs special handling.</strong> Every argument of a union needs to be transformed recursively.</li>
<li><tt class="docutils literal">PartialType</tt> If it shows up, the correct action is... probably complicated? Like okay, from a "do the types match" perspective, the correct action is to replace the placeholders with <tt class="docutils literal">Any</tt>. When it comes to the <tt class="docutils literal">typ</tt> argument, this shouldn't show up, so as <tt class="docutils literal">inst</tt>, when the types match, we need something like an attrs class with a field of type <tt class="docutils literal">T | None</tt>. I <em>think</em> that makes a <tt class="docutils literal">PartialType</tt>.</li>
<li><tt class="docutils literal">EllipsisType</tt> Should not show up.</li>
<li><tt class="docutils literal">TypeType</tt> Must be handled, with specific cases for <tt class="docutils literal">Instance</tt>, <tt class="docutils literal">AnyType</tt>, <tt class="docutils literal">TypeVarType</tt>, <tt class="docutils literal">TupleType</tt>, <tt class="docutils literal">NoneType</tt>, <tt class="docutils literal">CallableType</tt>.</li>
<li><tt class="docutils literal">PlaceholderType</tt> Should not show up?</li>
</ul>
<p>So, to summarize:</p>
<p><tt class="docutils literal">typ</tt> argument must handle <tt class="docutils literal">TypeType</tt> and <tt class="docutils literal">UnionType</tt> of <tt class="docutils literal">TypeType</tt>.
Within the <tt class="docutils literal">TypeType</tt>, it needs special handling for <tt class="docutils literal">AnyType</tt> and <tt class="docutils literal">Instance</tt>.
<em>Maybe</em> convert <tt class="docutils literal">TypeVarType</tt> to its upper bound, but probably don't.
Actually, there's even more subtlety here, bleh.
I kind of hope a constrained typevar just gets checked with the concrete values so I don't have to think about it?
Everything else should fail and coerce to <tt class="docutils literal">Any</tt>.</p>
<p><tt class="docutils literal">inst</tt> argument needs to handle the same types as <tt class="docutils literal">typ</tt>, and maybe also <tt class="docutils literal">PartialType</tt>?</p>
<p>From this, we see that the plugin is mostly done, but it still needs work, <em>mostly</em> to cover the union cases.
I'll get to that whenever.
I'll at least write a test to see how messed up it all is.</p>
<p>Okay, it's definitely messed up, and I'm not currently up for fixing it, so, whenever.
For now...</p>
<p>Good night.</p>
Diary 2023-05-122023-05-12T04:00:00-04:002023-05-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-12:/diary-2023-05-12<p class="first last">Apparently, the secret to getting something done is complaining about how hard it is.</p>
<p>Well, here we are.
I'm posting this entry, and redoing all of the pages on this site, because I've finished updating the theme files.
Now, they're <a class="reference external" href="https://github.com/jan-warchol/selenized/tree/master">Selenized</a>.
While I was at it, I redid the light/dark mode theming to provide a proper fallback on low-end browsers what don't show up on <a class="reference external" href="https://caniuse.com/">Can I use</a>.
(I mean, I guess it shows up better on Internet Explorer.
(And Opera Mini.)
(I have not attempted to confirm this.))
And, lastly</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">At last!</p>
</div>
<div class="admonition smiley smiley-glitchy">
<p class="first admonition-title">:) (glitchy)</p>
<p class="last">Somewhat improved legibility!</p>
</div>
<div class="admonition smiley smiley-glitchier">
<p class="first admonition-title">:) (glitchier)</p>
<p class="last">The old version of this icon was too spicy to actually be used!</p>
</div>
<p>Yep, we've come so far.
Maybe I'll remember to actually use that later.</p>
<p>Anyway, at some point, I need to fix some bugs I discovered by rotating the <tt class="docutils literal">saltate</tt> plugin in my head, but for now, I should take things easy.
I'm going to be worrying enough about making sure there aren't any show-stoppers in this post.</p>
<p>Good night.</p>
Diary 2023-05-112023-05-11T04:00:00-04:002023-05-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-11:/diary-2023-05-11<p class="first last">Somehow, I've made my site even more minimal on low-end browsers than it already was.</p>
<p>All right.
I've made a bunch of progress updating the color scheme for the blog.
It's not quite ready to go; I need to tweak a few CSS rules before I can expect it to work right.</p>
<p>It's a little obnoxious that I can get so far basically on autopilot, and when it comes to a few finishing touches, those are seemingly going to take more effort than the rest of the work put together.</p>
<p>...</p>
<p>I just now <em>hopefully</em> got the CSS side of things right, and now what I need is to validate and remake some assets.
I think I'll just cut this entry here and take things easy.</p>
<p>Good night.</p>
Diary 2023-05-102023-05-10T04:00:00-04:002023-05-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-10:/diary-2023-05-10<p class="first last">Not sure what everyone else thinks of my idea of a "fun side project", but whatever.</p>
<p>I really went hard polishing the new plugin, so I'd like to take a bit of time to cool off.
I'll be trying to think about writing, but one other thing that I'm going to be thinking about is trying to make my blog more readable.
If you run <a class="reference external" href="https://www.ssa.gov/accessibility/andi/help/install.html">ANDI</a> on this blog, <em>some</em> things are okay, but it's not happy with the color scheme.
(And there are other issues, but it's really unhappy with the color scheme.)</p>
<p>I've got some ideas in mind to deal with that, but the first thing I thought of is not a drop-in replacement, so this may end up being some kind of a fun side project.</p>
<p>Anyway, it's a little late and I don't want to force myself to go further, so I'm going to call things here.
(Maybe I should look into getting back into longer-form posts sometime...)</p>
<p>Good night.</p>
Weekly Roundup 2023-05-092023-05-09T04:00:00-04:002023-05-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-09:/weekly-roundup-2023-05-09<p class="first last">The plugin is getting into a good position...</p>
<ul class="simple">
<li>Wednesday: I looked over how the <tt class="docutils literal">attrs</tt> plugin handles the <tt class="docutils literal">evolve</tt> function.</li>
<li>Thursday: I put together a weird implementation for <tt class="docutils literal">saltate</tt>.</li>
<li>Friday: I upgraded Mypy, and had trouble distringuishing between <tt class="docutils literal">Tuple</tt> and <tt class="docutils literal">tuple</tt> in the failure messages.</li>
<li>Saturday: As I spun up the plugin development, I realized that I'm going to want to pull this out into a separate package as soon as I can.</li>
<li>Sunday: I started writing tests, and using their failure details to refine the plugin design.</li>
<li>Monday: I got the broad details of the plugin pretty much locked in, so it's in a good shape now.</li>
</ul>
<p>Next week, I'm going to try to fully polish the plugin, as well as develop the generic motrfile enough to pull the plugins out into their own packages.</p>
Coding 2023-05-082023-05-08T04:00:00-04:002023-05-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-08:/coding-2023-05-08<p class="first last">Still not a fan of how all of this has caused a full run to balloon to almost a minute of runtime, but oh well.</p>
<p>I spent a lot of today smacking my head into Mypy plugin stuff, and I think things are coming together and making more sense to me.
I've got better error messages and the signatures being returned are in better shape.</p>
<p>From all of this, I now understand that I'm missing a specific case:</p>
<p><tt class="docutils literal">saltate(typ: type[T], inst: Any, **changes: Any)</tt>, when <tt class="docutils literal">T</tt> is an attrs class, should get typed like: <tt class="docutils literal">saltate(typ: type[T], inst: Any, **changs: <the attributes of T>) <span class="pre">-></span> T</tt></p>
<p>So, let's see if I can untangle that from the current plugin code.</p>
<p>...</p>
<p>Okay, that wasn't too bad.</p>
<p>I basically had to split apart a fancy conditional, and move a line up in the function, so I could construct a mediumly-permissive signature.
The result will sometimes construct somewhat peculiar signatures, but those edge cases should be accompanied by a type checking failure, so I don't believe there's a serious problem with that.</p>
<p>There are a few big misses remaining in the plugin code that will be filled in by the positive test cases, but I want to focus on the last thing I don't quite understand:</p>
<p>Is the length of <tt class="docutils literal">ctx.args</tt> determined solely by the function declaration, or does it somehow depend on the call being processed by the <tt class="docutils literal">get_function_signature_hook</tt>?</p>
<p>If it's the former, I don't understand how I'd write tests for that branch.
If it's the latter, I still haven't figured out how to go down that branch.
I'm going to take the slightly spicy option of just asserting that my library method will always have exactly three arguments, from the perspective of names available within it.</p>
<p>Anyway, once I have coverage on the hook function locked down, I'm going to work on expanding coverage in the helper functions.
This is likely to result in commenting out some blocks or something, but we'll see how that all goes when I take the time to do this stuff.
I'm also going to have to comment all of this code thoroughly.</p>
<p>But right now, I'm going to wind down.</p>
<p>Good night.</p>
Coding 2023-05-072023-05-07T04:00:00-04:002023-05-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-07:/coding-2023-05-07<p class="first last">I'm a little worried that at least some of the calls I'm making in the plugin are for no actual reason.</p>
<p>Okay.
I've got tests for the <tt class="docutils literal">saltate</tt> plugin.
They're not passing yet, because I haven't nailed down the desired behavior.
In order to get a proper idea of the desired behavior, I'm coming up with failing test cases, and inspecting the resulting failure messages.</p>
<p>Careful inspection of the error messages and the coverage data has allowed me to conclude...</p>
<p>That I still don't understand how Mypy represents types.</p>
<p>Anyway, I ended up reimplementing parts of the <tt class="docutils literal">attrs</tt> plugin.
At the rate this is going, I might accidentally make the plugin compatible with older versions of Mypy.
I did the reimplementation because I was pulling out helper functions from the <tt class="docutils literal">attrs</tt> plugin, and they really didn't expect to be used with anything that wasn't <tt class="docutils literal">evolve</tt>.
I'm still pulling out helper functions, just, less so.</p>
<p>Let's take a look at the improvements I want to make:</p>
<ul class="simple">
<li>Failures generated by the reimplemented helper functions are associated with the function, rather than the specific argument.</li>
<li>Failures associated with the <tt class="docutils literal">typ</tt> argument use the wrong type name.</li>
<li>Once the above fixes are made, I want to use a more permissive signature for the relevant returns, because then the plugin-generated type errors are handling everything that is needed.</li>
</ul>
<p>I don't know if the first one is possible.
I believe I handled the second one, because the attrs plugin code is flexible, and I just needed to change which arguments I'm passing.</p>
<p>I worry that the second one will result in more deep-dives into the Mypy source code, because I have to somehow go from "a function call context" to "the context of an argument to that function".
That sounds like something that someone would have needed at some point, but I really don't know, and I don't know what it would take to hack it together if people have gotten by without that somehow.
Hm.
I'm going to try retrieving the expression node from the function argument context, and...</p>
<p>There.
We.
Go.</p>
<p>I've got a few more tweaks I want to make to presentation, then I can get to work making tests of the updated parts of the plugin pass.</p>
<p>(I should maybe make sure that the positive tests pass, now that the negative tests are somewhat locked down...)
Anyway, it's late, I should wrap up.</p>
<p>Good night.</p>
Coding 2023-05-062023-05-06T04:00:00-04:002023-05-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-06:/coding-2023-05-06<p class="first last">It's basically arbitrary which category I put these in.</p>
<p>Last night, I figured out why updating Mypy in my test environment made some tests fail: the capitalization of some types changed.
This might have been easier to notice if the change markers were meaningfully aligned with anything, not sure what's up with that.</p>
<p>In any case, with that done, I have what I need to plan out the tests.
For that, I have a rough idea of the kinds of types and situations I need to handle, and given those, I just need to fill it all in.</p>
<p>However, I expect that at some point, the test times will end up being so painful that I'll end up switching focus back to the generic motrfile repo, so I can pull out the plugin-bearing code ASAP.</p>
<p>Anyway, maybe I'll get on writing the tests after this, maybe I'll do it tomorrow.
Either way, I'm going to wrap up now.</p>
<p>Good night.</p>
Diary 2023-05-052023-05-05T04:00:00-04:002023-05-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-05:/diary-2023-05-05<p class="first last">"Corporate needs you to find the difference between this [error message] and this [error message]."</p>
<p>Well, I'm in better shape than the last diary post.
I got carried away with a distraction, but I didn't, like, <em>injure myself</em> on it.</p>
<p>I'm going to not try to "make up lost time", and just let things go for the rest of tonight.
Maybe take some notes on paper for the <tt class="docutils literal">saltate</tt> plugin testing.
I'll at least update the requirements file that's relevant there...</p>
<p>Aw heck.
That more than doubles <tt class="docutils literal">motr <span class="pre">-t</span> nocov</tt> execution time, <em>and</em> makes the type tests fail for made-up looking reasons.</p>
<p>So, here's how things go:</p>
<ul class="simple">
<li>Tonight, sketch out the tests I'm going to have to write.</li>
<li>Later, hope that I can troubleshoot the existing test failures.</li>
<li>In general, anticipate the release of Mypy 1.4.0.</li>
</ul>
<p>For now, I have to get away from my screen.</p>
<p>Good night.</p>
Coding 2023-05-042023-05-04T04:00:00-04:002023-05-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-04:/coding-2023-05-04<p class="first last">I still don't quite believe that worked.</p>
<p>Well, I bashed out code for the <tt class="docutils literal">saltate</tt> <em>plugin</em> last night, but it turns out that trying to make the actual implementation have mildly reasonable annotations causes Mypy to raise a bunch of sensible objections that I don't really know what to do about.
I could loosen the annotations and try to put more type-checking smarts on the plugin, but that would mean that nearly anything would typecheck without the plugin.</p>
<p>One of the issues is, I'd really <em>like</em> to be able to bound a <tt class="docutils literal">TypeVar</tt> as "any attrs class", and according to my intuition and a cursory Google search, that's not a thing.</p>
<p>Let's review:</p>
<ul class="simple">
<li><tt class="docutils literal">typ: type[T]</tt>: hmm</li>
<li><tt class="docutils literal">inst: U</tt>: <em>hmm</em></li>
<li><tt class="docutils literal">**changes: Any</tt>: no notes</li>
<li><tt class="docutils literal"><span class="pre">-></span> T</tt>: I mean, that makes sense</li>
</ul>
<p>I don't <em>think</em> there's any sensible way to express the desired relationship between <tt class="docutils literal">T</tt> and <tt class="docutils literal">U</tt>.
If I could just express "Hey, this is <em>some</em> attrs class..."</p>
<p>Actually...
If I could just forbid it from typechecking without the plugin rewriting the signature?
Hm.</p>
<p>So, like, if I created a typing-only attrs class?
This is a silly idea; I have to try it.</p>
<p>...</p>
<p>That</p>
<p><em>worked</em></p>
<p>???</p>
<p>It all typechecks, despite clearly being objectively ludicrous.
"Here, reinstantiate this class that doesn't exist with arguments that it wouldn't take if it did."</p>
<p>Well, next up is seeing whether the plugin actually works.
I don't have the stamina to write the tests currently, and I also need to update the requirements file for testing, which is probably going to slow it down even more.</p>
<p>But, anyway, that's one obstacle knocked down.</p>
<p>We'll see when I'm up for more.
For now, I'm going to wind down and get to bed.</p>
<p>Good night.</p>
Coding 2023-05-032023-05-03T04:00:00-04:002023-05-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-03:/coding-2023-05-03<p class="first last">Just kind of work by analogy...</p>
<p>I don't feel like touching MOTR directly right now, so let's take a look at how Mypy supports <tt class="docutils literal">attrs.evolve</tt>.</p>
<p>It expects two <tt class="docutils literal">args</tt> (<tt class="docutils literal">inst</tt> and <tt class="docutils literal">**changes</tt>?).
Then it mostly focuses on <tt class="docutils literal"><span class="pre">args[0][0]</span></tt>.
Is Mypy's usage of nested lists documented anywhere?
I don't remember <em>understanding</em> it with the last plugin I wrote, just figuring out what made the test cases pass.</p>
<p>Anyway, it gets the type of <tt class="docutils literal">inst</tt>, and operates on that.
There's a helper function I'm going to have to get access to, which determines the types of the fields.
Once the fields are gotten, it does a bunch of stuff that's pretty straightforward for <tt class="docutils literal">evolve</tt>, and will be less so for <tt class="docutils literal">saltate</tt>.</p>
<p>Let's see what's different.</p>
<ul class="simple">
<li><tt class="docutils literal">saltate</tt> has two required positional arguments, <tt class="docutils literal">typ</tt> and <tt class="docutils literal">inst</tt>.</li>
<li>It needs to determine the type of <tt class="docutils literal">typ</tt>.
That is, given "this expression is of type <tt class="docutils literal">type[T]</tt>", it needs to get the representation of <tt class="docutils literal">T</tt>.</li>
<li>It needs to confirm that the base types of <tt class="docutils literal">T</tt> and <tt class="docutils literal">inst</tt> are the same; this should <em>not</em> fail if they aren't generic, because I'm pretty sure there's some way to make that case matter, even if it's not occurring to me just yet.</li>
<li>It needs to go through the overall flow for both types, eventually generating two different lists of fields.</li>
<li>The one from <tt class="docutils literal">typ</tt> should be used, but it needs to be compared against the <tt class="docutils literal">inst</tt> list, to determine which fields should be required instead of optional.
Maybe this can be done with simple equality, or maybe I need to try to unify the types.</li>
</ul>
<p>In any case, let's work through this in order.</p>
<ul class="simple">
<li>Probably look at <tt class="docutils literal"><span class="pre">ctx.args[0][0]</span></tt> and <tt class="docutils literal"><span class="pre">ctx.args[1][0]</span></tt>, after checking that <tt class="docutils literal">len(ctx.args) == 3</tt>, <tt class="docutils literal">len(ctx.args[0]) == 1</tt> and <tt class="docutils literal">len(ctx.args[1]) == 1</tt>.</li>
<li><tt class="docutils literal">typ</tt> should be a <tt class="docutils literal">TypeType</tt>?
The type we want is the <tt class="docutils literal">item</tt> field?</li>
<li>If both types are <tt class="docutils literal">Instance</tt>, then compare by the <tt class="docutils literal">type</tt> field, otherwise compare normally?
If the comparison fails, do no further processing, otherwise proceed.</li>
</ul>
<p>That gets us to fields, and the check we need to make is whether a given <tt class="docutils literal">inst</tt> field is a subtype of the corresponding <tt class="docutils literal">typ</tt> field.
Ah, that's what <tt class="docutils literal">mypy.subtypes.is_subtype</tt> is for.</p>
<p>I think that's all the information I need to write the hook for <tt class="docutils literal">saltate</tt>.
I'm going to hold off on writing it, because I still want to figure out stuff like where to put it.
Judging by how I positioned other general-purpose stuff, it looks like it should go in a module right under the <tt class="docutils literal">motr</tt> package.
(At least, until and if it gets its own package.)</p>
<p>Let's see if I'm up for working on this properly tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2023-05-022023-05-02T04:00:00-04:002023-05-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-02:/weekly-roundup-2023-05-02<p class="first last">Progress is taking things through a bunch of weird circles until your code suddenly typechecks.</p>
<ul class="simple">
<li>Wednesday: I started thinking about the <tt class="docutils literal">saltate</tt> concept, and worked on a workaround for a Mypy... I think it's confirmed as a bug, that I found.</li>
<li>Thursday: I filed the bug, and started working on wrapping pyinstrument.</li>
<li>Friday: I refined and updated the Placeholder concept.</li>
<li>Saturday: My efforts to get Placeholders working resulted in rewrites in other parts of the code.</li>
<li>Sunday: I wrote tests for the pyinstrument wrapper, and immediately became suspicious of my test primitives.</li>
<li>Monday: I looked over the diagnostic methods on <tt class="docutils literal">Compendium</tt>, concluded that I only need one more, and wrote it.</li>
</ul>
<p>Next week, I'm going to think about how to improve these tests, but also start taking notes on what's needed for the <tt class="docutils literal">saltate</tt> plugin.</p>
Coding 2023-05-012023-05-01T04:00:00-04:002023-05-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-05-01:/coding-2023-05-01<p class="first last">I feel like there needs to be some way to mark these methods that aren't meant to be used by the application code, but maybe there doesn't need to be?</p>
<p>So, I was focused on other stuff and generally kind of out of it today, but let's think a little about how I want to do <tt class="docutils literal">Compendium</tt> diagnostics.
Well, these ultimately focus on private fields of the <tt class="docutils literal">Compendium</tt> class, so I guess they have to be methods on it?</p>
<p>It's late and I have a few other things to do, so let's just take a quick look at what's in here that I need to deal with.</p>
<p>First off, let's switch to the future topic...</p>
<p>And what we have currently:</p>
<ul class="simple">
<li>"Which <tt class="docutils literal">Task</tt>s have no outputs?"</li>
<li>"Which <tt class="docutils literal">Task</tt>s are not transitively required by a named output?"</li>
</ul>
<p>Stuff that's used for other reasons:</p>
<ul class="simple">
<li>"What are the requirements for a <tt class="docutils literal">Task</tt>?"</li>
<li>"What outputs are referred to by a given name?"</li>
<li>"What <tt class="docutils literal">Task</tt> corresponds to a given output?"</li>
<li>"Which names are selected by default, and which are not?"</li>
</ul>
<p>I additionally want:</p>
<ul class="simple">
<li>"Provide all <tt class="docutils literal">Task</tt>s in the compendium, either as an iterator or a container."</li>
</ul>
<p>Beyond that, I'm not really sure.</p>
<p>Well, if I can't think of anything else, then I'll just... do it.</p>
<p>...</p>
<p>And, it's done.
That was one of the shorter ellipses.</p>
<p>Anyway, I'm tired and I'd like to wind down, so I'm going to wrap up now, and figure out how to actually use all of this stuff later.</p>
<p>Good night.</p>
Coding 2023-04-302023-04-30T04:00:00-04:002023-04-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-30:/coding-2023-04-30<p class="first last">"My tests passed immediately, so maybe they're not very good."</p>
<p>I've very quickly written "new" tests for the code I've added, and that all seems to work and hit the proper parts of the code.
<em>However</em>.</p>
<p>Looking at the tests, I see that they're very superficial.
There are very basic questions that I should be asking about the output of this code that I'm currently not sure how to ask.
I remember considering some of them in the past, so I'd better take a quick look at the relevant module...</p>
<p>So, the <tt class="docutils literal">Compendium</tt>, at least in this pre-future version where that's not actually what it's called, defines two diagnostic methods.
These methods help to track down basic issues with the <tt class="docutils literal">Compendium</tt>, and I should use them outside of the apparently just one test that they're currently in.</p>
<p>But I also need diagnostic stuff like: provide every command where the first argument ends with the given name.
From there, I can check over the remaining arguments.
This will let me confirm stuff like "commands will have everything installed required to <em>actually run</em>".
Tomorrow or later, I'll try to work out what kind of interface I want on that.
For now, I'm going to wind down again.</p>
<p>Good night.</p>
Coding 2023-04-292023-04-29T04:00:00-04:002023-04-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-29:/coding-2023-04-29<p class="first last">I only hope I'm still happy with this in the morning. Apologies for how vague this post is, but, eh, whatever.</p>
<p>I think I understand where I went wrong with some of the design I've been working with, but I want to make sure I don't cause myself even more problems trying to deal with it.</p>
<p>Basically, right now, I have a class called <tt class="docutils literal">command.Metadata</tt>, which is parametric over installer types, and I think I actually need to make it just accept any installer type.
It's already supposed to have the groundwork for this in there, sort of.
Now, what this is going to mean is that I need to redo the placeholder filling-in.
Here's how that looks, I think:</p>
<ul class="simple">
<li>Two different functions for filling in an executable.
One is strictly typed, and operates unconditionally.
This is what is currently used everywhere.
The other one needs to be loosely typed, and to take an additional parameter to condition whether to replace or not.
Basically, if that parameter matches what's in the executable exactly, then do the replacement.
Otherwise, leave it be.</li>
<li>The <tt class="docutils literal">command.Metadata</tt> class (which probably needs a new name) is no longer parametric.</li>
</ul>
<p>...</p>
<p>Okay, I did a bunch more work, some of it focused around undoing stuff I did before.
There's more work where that come from, and I need to think about some things.</p>
<p>Like, now that I'm just doing replacements at the level of one <tt class="docutils literal">PathWith</tt>, should I be using combine at the...
Wait, I'm already doing what I was considering doing.
Okay, this code is a little bit of a rat's nest.</p>
<p>...</p>
<p>Or.</p>
<p>Or I could get distracted and just do it.</p>
<p>At the very least, the various checks all pass, except for the one that I didn't expect to.</p>
<p>I'll leave things like actually testing this new code for later.
For now, I'm going to be glad that I seem to have pulled this together, and hopefully improved the design of this part of the code.</p>
<p>Good night.</p>
Coding 2023-04-282023-04-28T04:00:00-04:002023-04-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-28:/coding-2023-04-28<p class="first last">Solving problems with more problems.</p>
<p>Okay, I'm trying to reconsider how I'm handling the passing of requirements relevant to a command that needs a module argument passed.
I'm getting a sense that there's something a little iffy in how all of these components fit together, but I think I've figured out what I need to get unstuck for now.</p>
<p>Basically, I need to make it possible to instantiate and combine placeholder installers, but not to resolve with them.
Specifically, a placeholder should contain an instance of the corresponding installer type.
Then, the <tt class="docutils literal">_command.Metadata</tt> needs to retrieve the nested installer under the placeholder label, and merge it with the value under the new key, if any.</p>
<p>After that, my plan is to rework the helper code.
The point of the helper code is to define builder classes that get out of the way as soon as possible, by constructing instances of common classes.
There are two things that need to be done.
One is to convert a property to a method, and change a field on the class to an argument to that method.
The other is to add a distinct method that takes different argument types.</p>
<p>Let's try doing all of this, and see where I get tripped up.</p>
<p>...</p>
<p>Hm.
Looks like I need some way of knowing which labels are getting filled in.</p>
<p>...</p>
<p>Okay, so this function implementation is not <em>clean</em>, per se, because I'm running into some issues where some part of my thought process wanted to pretend I had dependent types, and that's simply not the case...</p>
<p>...</p>
<p>Okay, that's part of it done.
Let's make sure I didn't introduce any new typing issues. ...
I have introduced a new typing issue.
But I dealt with it. I just needed to make the updated function <em>even grodier</em>.</p>
<p>Anyway, now I just have to...
Hm.
Hm.
I'm going to need to think about this some more.
There's a helper method that assumes it's getting an executable, but if I just change how that helper is put together a little...</p>
<p>This should produce so many typing issues...</p>
<p>I'm paring down the typing issues, but I don't feel like putting in the work to deal with this last set right now.
Tomorrow, or over the weekend maybe.
And once I get this stuff to pass, I need to make a thorough check of whether the helper functions are actually helping.</p>
<p>Actually, I can see one thing I'd like to have: a map method on <tt class="docutils literal">PathWith</tt>.
That should alleviate a bunch of heartburn with these changes.</p>
<p>Okay, that was quick to write.
I'll make use of it later, and finish up the changes to the helpers.</p>
<p>For now, I really should wind down.</p>
<p>Good night.</p>
Coding 2023-04-272023-04-27T04:00:00-04:002023-04-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-27:/coding-2023-04-27<p class="first last">Getting into a fight with my past self about what the code should do.</p>
<p>With some fiddling, I managed to both get Mypy to accept my code for now, and to produce an actually decently-small example of what's going on to file a bug report.
It looks like that's getting looked at.</p>
<p>Anyway, let's take a look at some of the motrfile code I want to make an equivalent of in the new system.</p>
<div class="highlight"><pre><span></span><span class="k">yield from</span> <span class="n">run_pytest</span><span class="p">(</span>
<span class="s2">"profile"</span><span class="p">,</span>
<span class="s2">"profile"</span><span class="p">,</span>
<span class="p">(</span>
<span class="s2">"pyinstrument"</span><span class="p">,</span>
<span class="s2">"--renderer"</span><span class="p">,</span>
<span class="s2">"html"</span><span class="p">,</span>
<span class="s2">"--outfile"</span><span class="p">,</span>
<span class="n">profile_dir</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="n">INDEX</span><span class="p">)</span><span class="o">.</span><span class="n">as_output</span><span class="p">(</span><span class="s2">"profile"</span><span class="p">),</span>
<span class="s2">"-m"</span><span class="p">,</span>
<span class="s2">"pytest"</span><span class="p">,</span>
<span class="p">),</span>
<span class="s2">"pytest-profile"</span><span class="p">,</span>
<span class="p">(</span><span class="n">profile_dir</span><span class="p">,),</span>
<span class="p">)</span>
</pre></div>
<p>I... hm.
Just so we're clear, these functions that mostly take string arguments... kind of suck?
Anyway, let's break it down.</p>
<p>The stuff I care about the most is the tuple in the middle.</p>
<ul class="simple">
<li><tt class="docutils literal">pyinstrument</tt> the executable</li>
<li><tt class="docutils literal"><span class="pre">--renderer</span> html</tt> or <tt class="docutils literal"><span class="pre">--renderer=html</span></tt> is needed for output; other values are possible, but I'll leave it at this for the initial release</li>
<li><tt class="docutils literal"><span class="pre">--outfile</span> <path/to/file></tt> is the other part of output; the existing new-style code should handle the <tt class="docutils literal">profile_dir</tt> input stuff later on</li>
<li><tt class="docutils literal"><span class="pre">-m</span></tt> module runner argument; this is proven out with the Python wrapper</li>
</ul>
<p>I fiddled around, and got everything to a point that seems to make sense... and then it failed type checking because I hadn't accounted for placeholders in some of the utility code I'm trying to use.
(Side note from looking at the names I'm using: wow, some of these names are bad.
Like, there's a "Labeled" type that doesn't actually require a label???)
Anyway, placeholders.
In a fancier system, I would be lobbying for higher-kinded-typevars or something like that about now, but there's no point when there's only one instance to work with currently.</p>
<p>...</p>
<p>Hm.
I appear to have dug myself deeper into a hole here.
This helper code isn't really taking to the placeholders, and I'm going to need to think some more about how to address this, and avoid making any rash decisions.
(I mean, I could make some, like, alternative methods to handle placeholder versions, but that would... sort of suck.)</p>
<p>I'm going to take a few days to ponder this, and try to wind down for now.</p>
<p>Good night.</p>
Coding 2023-04-262023-04-26T04:00:00-04:002023-04-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-26:/coding-2023-04-26<p class="first last">You know I believe it's important to use gradual typing heavily, because I'm always complaining about it.</p>
<p>Okay, here we go...
I've got a bit to catch up on.</p>
<ul class="simple">
<li>I'm leaning towards closing my feature request, but I kind of want to see what other people think.</li>
<li>I figured out how to write the plugin to catch problematic class definitions.
It's a pretty gross implementation, though, so I'm looking into an alternative.</li>
<li>If I'm writing a plugin <em>anyway</em>, the discussion on the feature request made me realize what I'd want a plugin to do.</li>
</ul>
<p>Let's get right into it.</p>
<p>Code:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">saltate</span><span class="p">(</span><span class="n">typ</span><span class="p">:</span> <span class="nb">type</span><span class="p">[</span><span class="n">T</span><span class="p">],</span> <span class="n">inst</span><span class="p">:</span> <span class="n">Any</span><span class="p">,</span> <span class="o">**</span><span class="n">changes</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-></span> <span class="n">T</span><span class="p">:</span>
<span class="k">return</span> <span class="n">attrs</span><span class="o">.</span><span class="n">evolve</span><span class="p">(</span><span class="n">inst</span><span class="p">,</span> <span class="o">**</span><span class="n">changes</span><span class="p">)</span>
</pre></div>
<p>Plugin: ... like the new attrs plugin code, but unfortunately, more complicated.
Basically, it needs to do all of the legwork of the builtin plugin, but also check that the underlying types of <tt class="docutils literal">typ</tt> and <tt class="docutils literal">inst</tt> "match", but need not unify, derive all arguments from <tt class="docutils literal">typ</tt>, and mark any that are a different type from the attributes on <tt class="docutils literal">inst</tt> as mandatory.</p>
<p>The basic concept here is that, because what I want is a kind of "discontinuous evolution", it's "saltation", and it needs to provide a specific target, as if it's a cast.
This addresses some of the problems uncovered in the feature request discussion, and also hopefully makes it obvious that, hey, if you don't need to specify a type, probably just use <tt class="docutils literal">evolve</tt>.</p>
<p>Unfortunately, it is too late at night for me to puzzle out plugin code right now, so I'm going to go over what else I did today.</p>
<ul class="simple">
<li>After getting a bunch of helper functions written earlier, I finally put it all together, and moved code out of the <tt class="docutils literal">python</tt> module.
At this point, it should be safe to create profiling wrappers.</li>
<li>In order to have things work properly with the plugin I want to write, I finally unpinned Mypy from pre-1.0, addressed the type issues, one potentially valid and one that seems incredibly made-up to me, and then pinned to master, because otherwise I'd just have to pin to 1.1.*.
I've got to say, I <em>really hope</em> I get Mypy yelling at me about unused type ignores from this, because I can't figure out which case I'm supposed to be hitting.</li>
</ul>
<p>However, the more I think about it, the more I think "No, there has to be a way to make Mypy make sense here."
So I guess I'm going to be bouncing off of that for a bit.</p>
<p>...</p>
<p>Okay, that's weird.
I managed to get rid of one instance of the error by just annotating stuff until Mypy admitted there wasn't actually a problem, but it's not working a second time.</p>
<p>Okay, that's... not the greatest solution, but I can't find fault with it from a simple inspection perspective.</p>
<div class="highlight"><pre><span></span><span class="n">facts</span><span class="p">:</span> <span class="n">_requirements</span><span class="o">.</span><span class="n">Requirements</span><span class="p">[</span><span class="n">_cmd</span><span class="o">.</span><span class="n">EnvVar</span><span class="p">[</span><span class="n">_cmd</span><span class="o">.</span><span class="n">CmdArg</span><span class="p">]]</span>
<span class="n">facts</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">map_facts</span><span class="p">(</span><span class="n">map_func</span><span class="p">)</span>
<span class="n">facts</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">cast</span><span class="p">(</span>
<span class="s2">"_requirements.Requirements[_cmd.EnvVar[_cmd.CmdArg]]"</span><span class="p">,</span> <span class="n">facts</span>
<span class="p">)</span>
</pre></div>
<p>"What does the cast accomplish?"</p>
<p>It makes type-checking pass.</p>
<p>Anyway, now I've got a clean basis for working on <tt class="docutils literal">saltate</tt>, but before that, I should probably try to extend the code some.
It's possible I've forgotten some more improvements that I want to make.
But for now, it's late.</p>
<p>Good night.</p>
Weekly Roundup 2023-04-252023-04-25T04:00:00-04:002023-04-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-25:/weekly-roundup-2023-04-25<p class="first last">A bit of MOTR progress...</p>
<ul class="simple">
<li>Wednesday: I planned extensions to the high-level MOTR API.</li>
<li>Thursday: I decided to take a detour and try to unpin Mypy. This resulted in filing a bug.</li>
<li>Friday: Well, Mypy is fixed, the fix just isn't released yet. So I updated some of my Trio usage, and it went much smoother.</li>
<li>Saturday: I played a single game of Vampire Survivors for almost two hours. Do not play a single game of Vampire Survivors for almost two hours.</li>
<li>Sunday: I decided to try to address an issue with how I'm using attrs.</li>
<li>Monday: I ended up trying a few different tacks, and not really being satisfied with any of them yet.</li>
</ul>
<p>Next week, I'm going to spend a little more time trying to make some kind of plugin to detect what I want to detect, but so far it's not going great.</p>
<p>(I tried out one of those LLMs that's supposed to code for you.
<em>Absolutely uncanny</em> simulation of a sleazy used-car salesman who's been abducted, and is being forced at gunpoint to produce code samples.)</p>
<p>Besides that, I'll be working on the actual updates.</p>
Coding 2023-04-242023-04-24T04:00:00-04:002023-04-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-24:/coding-2023-04-24<p class="first last">So many things seemed worth a shot, but I'm not sure what's ultimately worth a shot.</p>
<p>So, I ended up tabling the "remove defaults" idea in favor of putting in a feature request to Mypy to see where that goes.
I can anticipate some potential objections to it, and I'm not sure how to address them, so I need people who understand Mypy better than I do to discuss it some.</p>
<p>There are two major reasons I swung around to a feature request:</p>
<ul class="simple">
<li>What I was trying to accomplish with the code changes was to make a worse version of <tt class="docutils literal">attrs.evolve</tt>.</li>
<li>I couldn't figure out a good way to get a linting framework to do what I wanted.<ul>
<li>Semgrep doesn't seem to support regex operators in token names, so if I want to account for all of the different reasons that the rule might or might not apply, I'd need a combinatorial explosion of rules.
Also, I couldn't find a way to make it detect "a type expression that uses any typevar".</li>
<li>Although Pylint gets me as far as detecting attrs classes, it's not obvious to me whether the information I actually want is present in the AST.</li>
<li>I honestly didn't even try with flake8.</li>
</ul>
</li>
</ul>
<p>My guess is that, with some effort, I could get Pylint working nicely with this idea, but I'd rather focus on the feature request for now.</p>
<p>Let's see about chasing down the information that got me down this tangent in the first place...</p>
<ul class="simple">
<li>I want to put a <tt class="docutils literal">Placeholder</tt> into an <tt class="docutils literal">Executable</tt>, and I have a means of taking it back out, given the proper data.</li>
<li>At the other end of the pipeline is the <tt class="docutils literal">ParametricCommandMeta</tt>, which needs to carry out updates to a <tt class="docutils literal">CommandBuilder</tt>.</li>
<li>The <tt class="docutils literal">CommandBuilder</tt> needs the ability to update an <tt class="docutils literal">Executable</tt>, which we have, and a <tt class="docutils literal">command.Metadata</tt>, which we don't.
Yet.</li>
<li>The <tt class="docutils literal">Metadata</tt> is the most troublesome to update, because it requires conditionally mapping the <tt class="docutils literal">Executable</tt> update over three different data structures.</li>
</ul>
<p>In terms of raw volume of code, it's not clear that doing this would constitute a win, but it would mean moving code out of the more data-y modules, so I at least want to evaluate how much of a mess it would make.</p>
<p>Let's treat the top-level data structures as mostly straightforward, and focus on the type fiddling.</p>
<ul class="simple">
<li><tt class="docutils literal">Args</tt> is one of the baselines, because it just has a <tt class="docutils literal">MaybeExecutable</tt>.</li>
<li><tt class="docutils literal">EnvVars</tt> looks a little scarier due to the use of <tt class="docutils literal">EnvVar</tt>, but I can just map a lambda over that, no problem.</li>
<li><tt class="docutils literal">IOSet</tt> is mainly confusing because it uses a more restrictive set of types in the left-hand side of the union.</li>
</ul>
<p>Now, the thing that hopefully makes this less confusing than the existing functions is, I don't need special handling for different entry point types.
Everything just gets passed through, no questions asked.</p>
<p>Before I mess around with new code, I want to investigate using the techniques from <a class="reference external" href="https://github.com/python/mypy/issues/8356#issuecomment-884548381">this comment</a> in the existing code.</p>
<p>(Update: Things aren't currently looking great for the Mypy feature request, so I'm trying to nail down what I'd want out of a plugin.
Like, the brief is, the constructor for a generic attrs class shouldn't have any optional arguments, and the question is just how to express that in terms of whatever I use to lint.)</p>
<p>Anyway, back to messing with the code...</p>
<ul class="simple">
<li>There's some nested code that doesn't need updating because it doesn't need <tt class="docutils literal">overload</tt>.</li>
<li>There's some code that can't work with this because I need to key off of the type parameters, but fortunately, this isn't an all-or-nothing thing.</li>
</ul>
<p>So, I've proved that this still works, and the behavior is preserved (up to and including the mystery errors from recent Mypy versions).</p>
<p>At the moment, I just want to wrap up and get to bed, but this was nice for proving out the approach for handling the placeholder updates.
I'll try to do that in the next few days, and hopefully it'll get me some data points for those mystery errors.</p>
<p>Good night.</p>
Coding 2023-04-232023-04-23T04:00:00-04:002023-04-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-23:/coding-2023-04-23<p class="first last">I'll probably share this rule after I've written it, since it seems like most people should run into problems if they write code that would trigger it.</p>
<p>I did a little work on MOTR after last night's entry, and I ended up with an idea that I'm not sure whether I should believe:</p>
<p>"Generic attributes should not have a default value in the base constructor, and the class can provide alternative constructors that do provide default values."</p>
<p>I may even consider a strong statement, starting instead with "Generic classes should not have default values for any attribute".</p>
<p>I'm pondering this, because I can't see a way to make <tt class="docutils literal">evolve</tt> handle changing the parameters to the type; this means that "modified" values <em>must</em> be instantiated from scratch, and that means that, if I add another field to the class definition, it will be silently dropped from the update if it has a default value.</p>
<p>This has implications for:</p>
<ul class="simple">
<li><tt class="docutils literal">io.Output</tt></li>
<li><tt class="docutils literal">python_helpers.PythonCmd</tt></li>
<li><tt class="docutils literal">artifact.Input</tt></li>
<li><tt class="docutils literal">artifact.LabeledConverter</tt>, technically, I guess.</li>
<li><tt class="docutils literal">artifact.BasicOutputConverter</tt></li>
<li><tt class="docutils literal">command_builder.CommandBuilder</tt></li>
<li><tt class="docutils literal">parametric_command.ParametricCommandMeta</tt></li>
<li><tt class="docutils literal">parametric.Parametric</tt></li>
<li><tt class="docutils literal">command.Metadata</tt></li>
</ul>
<p>Hm.
Let's see how much it hurts if I start changing these...</p>
<p>So far, it hasn't been a big deal, but this seems fiddly enough to remember and to deal with that I'm now looking into <a class="reference external" href="https://semgrep.dev/">semgrep</a>, or maybe something similar, to check the codebase for a highly specific pattern.
Like, "when a class has one of these decorators, and inherits from an expression involving instances of this type, make sure that any values set at the class level either have a specific type annotation, or the value is a call to a function that <em>does not</em> pass some specific arguments".
Sure.</p>
<p>It's a bit late to write that right now, but I'll get on it tomorrow.
For now, I want to wind down.</p>
<p>Good night.</p>
Diary 2023-04-222023-04-22T04:00:00-04:002023-04-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-22:/diary-2023-04-22<p class="first last">Ooooogh noooooogh...</p>
<p>Me several hours ago: "I wonder what it's like to play Vampire Survivors on Endless mode"</p>
<p>Me now: "I wholeheartedly regret that decision"</p>
<p>I would have given up much sooner if I hadn't been switching off hands to control movement as my wrists wore out...</p>
<p>Point is, my brain is <em>jangly</em> now, and I can't really do much tonight as a result.</p>
<p>Good night.</p>
Coding 2023-04-212023-04-21T04:00:00-04:002023-04-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-21:/coding-2023-04-21<p class="first last">It's really nice to have updating to deal with a new version just work...</p>
<p>People are working on fixing Mypy, so I'll see improvements there... after at least two more minor versions.
I'm going to put off the unpin until then, and maybe look into putting together something for the other errors I hit, just so I can pin down whether the changes are intended or not.</p>
<p>Aside from that, I got prepped for some future release of Trio, so that's pretty great.
I'm not sure <em>precisely</em> how valid my code to handle <tt class="docutils literal">ExceptionGroup</tt>s is, but the tests pass, at least for now, so eh.</p>
<p>Anyway, now that I've fully characterized the parameters of my tactical retreat from messing with Mypy, I'm all set to investigate the right places to define and use <tt class="docutils literal">Placeholder</tt> next time I touch the code.</p>
<p>Good night.</p>
Coding 2023-04-202023-04-20T04:00:00-04:002023-04-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-20:/coding-2023-04-20<p class="first last">I should try to distill Mypy tests out of MOTR's code.</p>
<p>I'm going to try and get Mypy unpinned.
Let's see what kind of shape it's in...</p>
<div class="highlight"><pre><span></span><span class="o">(</span>motr-dev<span class="o">)</span> ↪ hg diff
diff --git a/requirements/mypy.txt b/requirements/mypy.txt
--- a/requirements/mypy.txt
+++ b/requirements/mypy.txt
@@ -1,3 +1,3 @@
lxml
-mypy<span class="o"><</span><span class="m">1</span> <span class="c"># My weird code.</span>
+mypy
trio-typing
</pre></div>
<p>And when I run <tt class="docutils literal">motr <span class="pre">-t</span> mypy</tt>, it</p>
<p><tt class="docutils literal">src/motr/_api/cli_types/parametric.py:512: error: Argument "instantiate" to "evolve" of "Parametric[T]" has incompatible type <span class="pre">"Callable[[PerItemParametricMapping[motr._api.cli_types.box._Unlabel],</span> <span class="pre">PerItemParametricMapping[motr._api.cli_types.selection._Unlabel]],</span> Generator[Union[Action, ActionInput, ActionOutput, TargetName, SkippedName], None, <span class="pre">T]]";</span> expected <span class="pre">"Callable[[PerItemParametricMapping[motr._api.cli_types.box._Unlabel],</span> <span class="pre">PerItemParametricMapping[motr._api.cli_types.selection._Unlabel]],</span> Generator[Union[Action, ActionInput, ActionOutput, TargetName, SkippedName], None, <span class="pre">T_co]]"</span> <span class="pre">[arg-type]</span></tt></p>
<p>It</p>
<p><tt class="docutils literal">src/motr/_api/cli_types/parametric.py:512: error: Argument "instantiate" to "evolve" of "Parametric[T]" has incompatible type <span class="pre">"Callable[[PerItemParametricMapping[motr._api.cli_types.box._Unlabel],</span> <span class="pre">PerItemParametricMapping[motr._api.cli_types.selection._Unlabel]],</span> Generator[Union[Action, ActionInput, ActionOutput, TargetName, SkippedName], None, <span class="pre">T]]";</span> expected <span class="pre">"Callable[[PerItemParametricMapping[motr._api.cli_types.box._Unlabel],</span> <span class="pre">PerItemParametricMapping[motr._api.cli_types.selection._Unlabel]],</span> Generator[Union[Action, ActionInput, ActionOutput, TargetName, SkippedName], None, <span class="pre">T_co]]"</span> <span class="pre">[arg-type]</span></tt></p>
<p>I mean, I think that sounds straight-up incorrect, but</p>
<p><tt class="docutils literal">src/motr/_api/cli_types/parametric.py:512: error: Argument "instantiate" to "evolve" of "Parametric[T]" has incompatible type <span class="pre">"Callable[[PerItemParametricMapping[motr._api.cli_types.box._Unlabel],</span> <span class="pre">PerItemParametricMapping[motr._api.cli_types.selection._Unlabel]],</span> Generator[Union[Action, ActionInput, ActionOutput, TargetName, SkippedName], None, <span class="pre">T]]";</span> expected <span class="pre">"Callable[[PerItemParametricMapping[motr._api.cli_types.box._Unlabel],</span> <span class="pre">PerItemParametricMapping[motr._api.cli_types.selection._Unlabel]],</span> Generator[Union[Action, ActionInput, ActionOutput, TargetName, SkippedName], None, <span class="pre">T_co]]"</span> <span class="pre">[arg-type]</span></tt></p>
<p>Fiiiiine.</p>
<p>So, about two weeks ago, Mypy got another release, and I got <em>more errors</em>.
With some experimentation on a reproduction that doesn't recite the entire text of Moby Dick, I've determined that it's probably fine if the following two conditions are met:</p>
<ul class="simple">
<li>The call to <tt class="docutils literal">evolve()</tt> is in a method on the relevant class.</li>
<li>The typevars associated with <tt class="docutils literal">self</tt> exactly match the ones on the class line???
That is, from my testing, it appears that you can't annotate a method on a class defined with <tt class="docutils literal">class <span class="pre">MyAwesomeClass(Generic[T1]):</span></tt> like <tt class="docutils literal">def my_awesome_method(self: MyAwesomeClass[T2]) <span class="pre">-></span> T2:</tt> even if <tt class="docutils literal">T1</tt> and <tt class="docutils literal">T2</tt> are identical except for the name???</li>
</ul>
<p>There is no way that second one is intended behavior.
Ludicrous.
The first one is a little obnoxious, but I'm not confident that that wasn't intended?
Anyway, let's see what I need to handle this...</p>
<p>Okay, wait.
Hold on.
It instantiated the constraints on a typevar, then failed to unify the typevar with the constraints?
Okay.</p>
<p>Okay.</p>
<p>Okay.</p>
<p>Okay.</p>
<p>Okay.</p>
<p>Okay.</p>
<p>I've got to file this, because that is actually impossible to satisfy.</p>
<p>So, I guess I can consider trying to move the pin out, but I'm frankly not impressed by how Mypy 1+ has handled MOTR's code.
Kind of weird how the scrunkly plugin stuff hasn't posed any obvious problems, but whatever.</p>
<p>Anyway, getting all het up about how messed up the new <tt class="docutils literal">evolve()</tt> handling is ate up the night, so I guess I'm not doing this.
And I'm kind of skeptical about whether it's worth trying to get to 1.1+.</p>
<p>I'm going to wrap things up for now, and see what I'm up for later.</p>
<p>Good night.</p>
Coding 2023-04-192023-04-19T04:00:00-04:002023-04-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-19:/coding-2023-04-19<p class="first last">After I finished writing this entry, I remembered I should probably be trying to get Mypy unpinned, and, like... I don't wanna...</p>
<p>Okay, here we go.</p>
<p>I want to create a placeholder value for installer labels to allow me to convert a bunch of a function I've written into a combination of a utility function and some static data, so I can define <em>different</em> data in other contexts.</p>
<p>Here is a first shot...</p>
<div class="highlight"><pre><span></span><span class="nd">@attrs</span><span class="o">.</span><span class="n">frozen</span>
<span class="k">class</span> <span class="nc">Placeholder</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">_installer</span><span class="o">.</span><span class="n">TArgs</span><span class="p">]):</span>
<span class="n">uninstantiable</span><span class="p">:</span> <span class="n">NoReturn</span>
<span class="k">def</span> <span class="nf">resolve</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">__environment</span><span class="p">:</span> <span class="nb">object</span><span class="p">,</span> <span class="n">__cmd</span><span class="p">:</span> <span class="nb">object</span><span class="p">)</span> <span class="o">-></span> <span class="n">Facts</span><span class="p">[</span><span class="n">Input</span><span class="p">[</span><span class="n">Path</span><span class="p">]]:</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
<span class="k">def</span> <span class="nf">combine</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">__other</span><span class="p">:</span> <span class="n">Placeholder</span><span class="p">[</span><span class="n">_installer</span><span class="o">.</span><span class="n">TArgs</span><span class="p">]</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">Placeholder</span><span class="p">[</span><span class="n">_installer</span><span class="o">.</span><span class="n">TArgs</span><span class="p">]:</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
</pre></div>
<p>The basic idea is that there's some way to take a <tt class="docutils literal">ParametricCommandMeta[TEntry, TProgram, Placeholder[_installer.TArgs]]</tt>, pass it a <tt class="docutils literal">ParametricCommand[Module, Any, _installer.TArgs]</tt>, and synthesize them into a <tt class="docutils literal">ParametricCommand[TEntry, TProgram, _installer.TArgs]</tt>.</p>
<p>I'm pretty sure I can write the code to do that, no big deal.
I'm just not sure if it's a generally valid transformation, outside of the context where I want it.</p>
<p>All the same, it seems like a better idea to just go for it.</p>
<p>Now, how to lay this out.
I'm leaning towards, actual definition in <tt class="docutils literal">parametric_command</tt>, but re-export in the <tt class="docutils literal">installers</tt> namespace.
Some amount of support code to handle the type twiddles will probably be necessary, but I'm going to make a bold prediction that it won't be a big deal.</p>
<p>I'll get started on this tomorrow, because right now, I need to wind down.</p>
<p>Good night.</p>
Weekly Roundup 2023-04-182023-04-18T04:00:00-04:002023-04-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-18:/weekly-roundup-2023-04-18<p class="first last">Nearly done refactoring...</p>
<ul class="simple">
<li>Wednesday: I wrote a bunch of things that weren't a blog entry, thereby not leaving me the time to write a blog entry.</li>
<li>Thursday: I considered some changes to the layout of MOTR, including a few things that turned out not to matter.</li>
<li>Friday: I continued to consider the changes, and came to a decision.</li>
<li>Saturday: I tried to trace the flow of <tt class="docutils literal">MapOverSelection</tt> through <tt class="docutils literal">parametric_command</tt> and <tt class="docutils literal">artifact</tt>, which was... still obnoxious.</li>
<li>Sunday: I made all of the planned changes.</li>
<li>Monday: I backed out some of the changes in order to keep things usable, but I did keep the major improvements.</li>
</ul>
<p>Next week, I'm going to try to remember what I wanted to work on next.
I <em>think</em> I've managed to figure out some of it...</p>
Coding 2023-04-172023-04-17T04:00:00-04:002023-04-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-17:/coding-2023-04-17<p class="first last">A less painful merge than I expected.</p>
<p>Pro: The tests pass now.</p>
<p>Con: They were coupled to the old design, not in the sense of "They're doing things the old way, and need to be switched to the new way.", but in the sense of "There is no new way, so I need to walk back a bunch of my changes."</p>
<p>Pro: I didn't have to walk them all back, and I was able to keep a bunch of the major improvements.</p>
<p>Con: This merge is going to suck.</p>
<p>Let's see how that goes...</p>
<div class="highlight"><pre><span></span><span class="o">(</span>motr-dev<span class="o">)</span> ↪ hg up 39-documentation
switching to topic 39-documentation
<span class="m">56</span> files updated, <span class="m">0</span> files merged, <span class="m">20</span> files removed, <span class="m">0</span> files unresolved
maxchase at maxchase-ThinkPad-P1-Gen-5 <span class="k">in</span> ~/D/s/m/motr
<span class="o">(</span>motr-dev<span class="o">)</span> ↪ hg merge 87-test-coverage
file <span class="s1">'src/motr/_api/cli_types/map_over_selection.py'</span> was deleted <span class="k">in</span> other <span class="o">[</span>merge rev<span class="o">]</span> but was modified <span class="k">in</span> local <span class="o">[</span>working copy<span class="o">]</span>.
You can use <span class="o">(</span>c<span class="o">)</span>hanged version, <span class="o">(</span>d<span class="o">)</span>elete, <span class="k">or</span> leave <span class="o">(</span>u<span class="o">)</span>nresolved.
What do you want to do? d
merging src/motr/_api/cli_types/artifact.py
merging src/motr/_api/cli_types/command.py
merging src/motr/_api/cli_types/installer.py
merging src/motr/_api/cli_types/parametric.py
merging src/motr/_api/cli_types/parametric_command.py
warning: conflicts <span class="k">while</span> merging src/motr/_api/cli_types/parametric_command.py! <span class="o">(</span>edit, then use <span class="s1">'hg resolve --mark'</span><span class="o">)</span>
merging src/motr/_api/package.py
warning: conflicts <span class="k">while</span> merging src/motr/_api/package.py! <span class="o">(</span>edit, then use <span class="s1">'hg resolve --mark'</span><span class="o">)</span>
merging src/motr/_api/tasks/cmd.py <span class="k">and</span> src/motr/_api/actions/cmd.py to src/motr/_api/tasks/cmd.py
warning: conflicts <span class="k">while</span> merging src/motr/_api/tasks/cmd.py! <span class="o">(</span>edit, then use <span class="s1">'hg resolve --mark'</span><span class="o">)</span>
merging src/motr/_api/tasks/io.py <span class="k">and</span> src/motr/_api/actions/io.py to src/motr/_api/tasks/io.py
warning: conflicts <span class="k">while</span> merging src/motr/_api/tasks/io.py! <span class="o">(</span>edit, then use <span class="s1">'hg resolve --mark'</span><span class="o">)</span>
<span class="m">0</span> files updated, <span class="m">4</span> files merged, <span class="m">2</span> files removed, <span class="m">4</span> files unresolved
use <span class="s1">'hg resolve'</span> to retry unresolved file merges <span class="k">or</span> <span class="s1">'hg merge --abort'</span> to abandon
</pre></div>
<p>... Well, that probably could have gone worse?</p>
<p>...</p>
<p>That wasn't so bad.</p>
<p>I haven't made all of the changes that I could make, but I'm going to hold off on taking it further for now.
The thing to focus on after now, is to refresh my memory about what is a problem for the remaining wrapper code, because I've completely forgotten what was supposed to be problematic with this code.</p>
<p>I'll start on that in a few days.
For now, I need to wind down.</p>
<p>Good night.</p>
Coding 2023-04-162023-04-16T04:00:00-04:002023-04-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-16:/coding-2023-04-16<p class="first last">Just kind of gambling that all of those tests were coupled to the old design.</p>
<p>All right.
I ended up just jumping in and updating code until Mypy stopped complaining.
This resulted in something happening with the tests, and I'll try and get them passing again later.</p>
<p>Basically, I just did what seemed to make sense, and nothing obviously broke yet.
I should be able to delete a lot of code now, but I don't yet know for sure.</p>
<p>We traveled again today, and I feel like I was lucky to get this much done, and I don't have the energy to write this up in any more detail.</p>
<p>Good night.</p>
Coding 2023-04-152023-04-15T04:00:00-04:002023-04-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-15:/coding-2023-04-15<p class="first last">I may need to switch to documenting this stuff if it's going to keep being this confusing.</p>
<p>Okay, so, the next thing to work on is updating <tt class="docutils literal">parametric_command</tt> to use the new class I threw together.
I could try working methodically through the file, or making changes at random until Mypy stops yelling at me.</p>
<p>Or, I could try simulating that, but describing the code changes instead of trying to actually make them all at once.</p>
<ul class="simple">
<li>Let's start with the definition of <tt class="docutils literal">Part</tt>.
<tt class="docutils literal">Part</tt> now has to involve <tt class="docutils literal">_parametric.AdaptiveParametric[BlahBlahBlah]</tt>.
This requires a minor and obvious change to the <tt class="docutils literal">_optional_parametric</tt> helper.
In addition...</li>
<li>There is a method called <tt class="docutils literal">_selections()</tt>.
The inside is going to change, but also the return value, so we're going to have to look at how it's used.
Its usage ultimately ends up as an argument to <tt class="docutils literal">_build()</tt>, where it is eventually passed into... <tt class="docutils literal">_optional_parametric</tt>.
Huh.
Insert le funny Gandalf meme here.</li>
<li>Within <tt class="docutils literal">_optional_parametric</tt>, this value is only used to pass to <tt class="docutils literal">Part.build()</tt> by specifically extracting the values from it...</li>
<li>In there, it's passed to <tt class="docutils literal">Artifact.convert()</tt>.</li>
</ul>
<p>At this point, I kind of lose the plot, because this somehow diverts it through seemingly every part of the <tt class="docutils literal">artifact</tt> module.</p>
<p>...</p>
<p>I <em>think</em> it mainly ends up on the <tt class="docutils literal">Input</tt> type, which passes it back out via <tt class="docutils literal">exposed_selections()</tt>.
Which is used for <tt class="docutils literal">Part.selections()</tt>.
Which comes back to <tt class="docutils literal">_selections()</tt>.</p>
<p>Let's assume we should be replacing <tt class="docutils literal">MapOverSelection</tt> with <tt class="docutils literal">Parametric[PathStr]</tt>.</p>
<p>This represents a change in semantics in some fashion, but let's assume the way to update a sequence of these is to filter out incoming duplicates.
Maybe look into making callable types for the various <tt class="docutils literal">Parametric</tt> changes, so duplicates can be checked for structurally...</p>
<p>I'll look into trying to do this, maybe in the next few days, maybe next week.
We'll see.</p>
<p>Good night.</p>
Coding 2023-04-142023-04-14T04:00:00-04:002023-04-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-14:/coding-2023-04-14<p class="first last">It was less effort to do weird introspection stuff than to come up with distinct, self-explanatory names.</p>
<p>Okay, let's take a little time to consider how these decorators are supposed to work.
Ignoring <tt class="docutils literal">MappedParametric</tt> for now, because that's a whole thing, I've got two basic options for external interfaces to use:</p>
<ul class="simple">
<li><tt class="docutils literal">@_parametric.parametric</tt> and <tt class="docutils literal">@_parametric.adaptive</tt></li>
<li><tt class="docutils literal">@_parametric.Parametric.make</tt> and <tt class="docutils literal">@_parametric.AdaptiveParametric.make</tt></li>
</ul>
<p>Sadly, I do kind of need to consider the lengths involved, since there are valid reasons to use these inline as well as in decorator form.</p>
<p><tt class="docutils literal">MappedParametric</tt> is kind of an opposite situation, where I'm not quite sure what I want out of the decorator, but there's no reason to care how the decorator works inline when I can just use the default <tt class="docutils literal">attrs</tt> constructor.</p>
<p>I think the first question comes down to how committed I am to having all normal modules import modules instead of importing non-module items from modules.
I don't remember the rationale for that, so it's time to try to go back to first principles, apparently.
Now, where did I get that idea...</p>
<p>Let's see, my source was certainly the <a class="reference external" href="https://google.github.io/styleguide/pyguide.html#s2.2-imports">Google Python Style Guide</a>, which, granted, I don't follow perfectly even in this context...
Between that, and <tt class="docutils literal">import this</tt>, and a desire to not given in <em>completely</em> to Pokémon-speak, here is my general idea:</p>
<ul class="simple">
<li>Decorate to produce a <tt class="docutils literal">Parametric</tt> with <tt class="docutils literal">@_parametric.make</tt>, as well as a few other module-level functions that can be used as a decorator.</li>
<li>However, also consider adding fluent methods that forward to these functions when applicable.
For example, I may want a <tt class="docutils literal">.flattened</tt> method or property corresponding to the <tt class="docutils literal">flatten</tt> function.</li>
<li>Use <tt class="docutils literal">adaptive</tt> for <tt class="docutils literal">AdaptiveParametric</tt>.</li>
<li>Use either one or two decorators for <tt class="docutils literal">MappedParametric</tt>.
This is the remaining effort I need to put into thinking about this.</li>
</ul>
<p>Perhaps <tt class="docutils literal">@_parametric.map_over(func)</tt>...
No.
Here's a slightly wonky idea...</p>
<div class="highlight"><pre><span></span><span class="nd">@overload</span>
<span class="k">def</span> <span class="nf">map_over</span><span class="p">(</span>
<span class="n">func</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">T</span><span class="p">],</span> <span class="n">PathStr</span><span class="p">],</span> <span class="o">/</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">Callable</span><span class="p">[[</span><span class="n">Parametric</span><span class="p">[</span><span class="n">T</span><span class="p">]],</span> <span class="n">MappedParametric</span><span class="p">[</span><span class="n">T</span><span class="p">]]:</span>
<span class="o">...</span>
<span class="nd">@overload</span>
<span class="k">def</span> <span class="nf">map_over</span><span class="p">(</span>
<span class="n">parametric</span><span class="p">:</span> <span class="n">Parametric</span><span class="p">[</span><span class="n">T</span><span class="p">],</span> <span class="o">/</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">Callable</span><span class="p">[[</span><span class="n">Callable</span><span class="p">[[</span><span class="n">T</span><span class="p">],</span> <span class="n">PathStr</span><span class="p">]],</span> <span class="n">MappedParametric</span><span class="p">[</span><span class="n">T</span><span class="p">]]:</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">map_over</span><span class="p">(</span>
<span class="n">func_or_parametric</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">T</span><span class="p">],</span> <span class="n">PathStr</span><span class="p">]</span> <span class="o">|</span> <span class="n">Parametric</span><span class="p">[</span><span class="n">T</span><span class="p">],</span> <span class="o">/</span>
<span class="p">)</span> <span class="o">-></span> <span class="p">(</span>
<span class="n">Callable</span><span class="p">[[</span><span class="n">Parametric</span><span class="p">[</span><span class="n">T</span><span class="p">]],</span> <span class="n">MappedParametric</span><span class="p">[</span><span class="n">T</span><span class="p">]]</span>
<span class="o">|</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">Callable</span><span class="p">[[</span><span class="n">T</span><span class="p">],</span> <span class="n">PathStr</span><span class="p">]],</span> <span class="n">MappedParametric</span><span class="p">[</span><span class="n">T</span><span class="p">]]</span>
<span class="p">):</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">func_or_parametric</span><span class="p">,</span> <span class="n">Parametric</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">needs_func</span><span class="p">(</span><span class="n">func</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">T</span><span class="p">],</span> <span class="n">PathStr</span><span class="p">])</span> <span class="o">-></span> <span class="n">MappedParametric</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span>
<span class="k">return</span> <span class="n">MappedParametric</span><span class="p">(</span><span class="n">func_or_parametric</span><span class="p">,</span> <span class="n">func</span><span class="p">)</span>
<span class="k">return</span> <span class="n">needs_func</span>
<span class="k">def</span> <span class="nf">needs_parametric</span><span class="p">(</span><span class="n">parametric</span><span class="p">:</span> <span class="n">Parametric</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="o">-></span> <span class="n">MappedParametric</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span>
<span class="k">return</span> <span class="n">MappedParametric</span><span class="p">(</span><span class="n">parametric</span><span class="p">,</span> <span class="n">func_or_parametric</span><span class="p">)</span>
<span class="k">return</span> <span class="n">needs_parametric</span>
</pre></div>
<p>Can't really use it inline, but as I said, you don't need to, and it types cleanly enough, and saves you the bother of having to remember which way around things go by having them both be right.</p>
<p>In fact, I'll try to get it to work now.</p>
<p>...</p>
<p>Hm, it didn't quite work, but it was close.
Just needed to make some minor adjustments...</p>
<p>All set for tonight.
Later, I can look at this in the light of day, and ponder whether my actions made any sense at all.</p>
<p>Good night.</p>
Coding 2023-04-132023-04-13T04:00:00-04:002023-04-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-13:/coding-2023-04-13<p class="first last">Plenty of stuff just kind of happily shoves in wherever, and then I need to think about the actual external interfaces...</p>
<p>I was thinking about how to organize the new code in MOTR, and something occurred to me:
That higher-order decorator is <em>really</em> squirrelly, and I'd rather leave it as a module implementation detail than something that gets exposed to other modules.
Doing that requires pulling a bunch of code into the <tt class="docutils literal">parametric</tt> module, which is... probably fine?
The only real hurdle is that I'd need different names for the "fake value" classes.
Again, probably fine.
I can stick them inside the associated classes, even, probably.</p>
<p>Let's try that, actually...
I mean, it didn't break yet, with the obvious caveat that I'm not really testing these paths.</p>
<p>If it's not broken yet, let's stuff more things in to see if it does...</p>
<p>Well, now all that's left is to figure out the proper way to handle the decorators for <tt class="docutils literal">MappedParametric</tt>.
That, and to write the validation for <tt class="docutils literal">AdaptiveParametric</tt>.
I should be able to handle that...</p>
<p>And, the validation should be done now.
The big thing missing is the last constructor, and instead of rushing into that, I want to take some more time to consider whether to do this as top-level functions, or classmethods, or what.</p>
<p>Like, more cruft at the top level, versus longer access paths on decorators, and is that even the rate dimension to be comparing for tradeoffs...</p>
<p>Not something that I want to rush into.</p>
<p>For now, I'm going to get ready for bed.</p>
<p>Good night.</p>
Diary 2023-04-122023-04-12T04:00:00-04:002023-04-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-12:/diary-2023-04-12<p class="first last">Suddenly it's so good. No, you cannot see it.</p>
<p>I did a bunch of writing and I'm really excited about how it's going, but unfortunately I got so excited that now it's almost midnight, so, um.</p>
<p>Good night.</p>
Weekly Roundup 2023-04-112023-04-11T04:00:00-04:002023-04-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-11:/weekly-roundup-2023-04-11<p class="first last">Just keep on ratcheting things forwards...</p>
<ul class="simple">
<li>Wednesday: I started drafting out a new decorator for MOTR.</li>
<li>Thursday: I traced out the usage of some types in MOTR, and realized that I can't take as much out as I want, but I can at least improve the stuff that I have to leave in.</li>
<li>Friday: I tried to extend the implementation of the new decorator to handle the new type I realized I need. I also threw in some Dynamism Crimes.</li>
<li>Saturday: I took care of obligations. Hopefully, I'll be recovered by the time I have to do this again next year.</li>
<li>Sunday: I traveled.</li>
<li>Monday: I came up with some helpful ideas for some writing I'm doing, so that was good.</li>
</ul>
<p>Next week, I'm going to look for usages of the old <tt class="docutils literal">Parametric</tt> constructors, to see if I can replace any of them with the new decorator.
Also, I need to mark up the usages of the old <tt class="docutils literal">MapOverSelection</tt> stuff to make sure I can smoothly replace it.</p>
Diary 2023-04-102023-04-10T04:00:00-04:002023-04-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-10:/diary-2023-04-10<p class="first last">I have suspicions about what got my mind flexible enough to come up with these ideas, but they're <em>extremely</em> embarrassing.</p>
<p>Somehow or other, I got some ideas for some of the writing I'm doing.
I think they're solid ideas, but I need to review what little I have written currently to make sure I'm not writing myself into a corner.</p>
<p>Basically, I want to make sure that what the main character knows is consistent with what ends up being the case, but to give them as little information as possible within the parameters I'm setting, because there's no reason to make this easy for them.</p>
<p>I'll try to work on that later.
For now, I'm just glad that things are shaping up.
Now I ought to wrap things up for tonight.</p>
<p>Good night.</p>
Diary 2023-04-092023-04-09T04:00:00-04:002023-04-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-09:/diary-2023-04-09<p class="first last">Nothing to see here, oh well.</p>
<p>Traveled today, and did <em>a bunch</em> of pointless messing-around.</p>
<p>Maybe before I travel again tomorrow, I'll get some work done on MOTR, maybe I won't.</p>
<p>Either way, I'm going to take things easy, because I think I need to.</p>
<p>Good night.</p>
Diary 2023-04-082023-04-08T04:00:00-04:002023-04-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-08:/diary-2023-04-08<p class="first last">Just keep on doing things until I'm done with obligations...</p>
<p>I took care of a bunch of stuff today to, um, different levels of quality, but now I should be able take things a little easier.</p>
<p>Right now, though, I'm just kind of fried.</p>
<p>I'm unsure how much I'll get done over the weekend, so my overall plan/goal is to just take things easy for the next few days.</p>
<p>I don't have anything else in mind for this entry, so, it's done.</p>
<p>Good night.</p>
Coding 2023-04-072023-04-07T04:00:00-04:002023-04-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-07:/coding-2023-04-07<p class="first last">Did I forget to hit publish yesterday?</p>
<p>I thought some about what I want from the other decorator.
Something like...</p>
<div class="highlight"><pre><span></span><span class="c1"># parametric.py</span>
<span class="k">def</span> <span class="nf">make_deco</span><span class="p">(</span>
<span class="n">converter</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">Any</span><span class="p">],</span> <span class="n">Paramatric</span><span class="p">[</span><span class="nb">object</span><span class="p">]</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">Callable</span><span class="p">[[</span><span class="n">Callable</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="n">T</span><span class="p">]],</span> <span class="n">Parametric</span><span class="p">[</span><span class="n">T</span><span class="p">]]:</span>
<span class="k">def</span> <span class="nf">deco</span><span class="p">(</span><span class="n">function</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="n">T</span><span class="p">])</span> <span class="o">-></span> <span class="n">Parametric</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span>
<span class="n">signature</span> <span class="o">=</span> <span class="n">inspect</span><span class="o">.</span><span class="n">signature</span><span class="p">(</span><span class="n">function</span><span class="p">)</span>
<span class="n">instantiators</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">metadata</span> <span class="o">=</span> <span class="n">Metadata</span><span class="p">()</span>
<span class="k">for</span> <span class="n">param</span> <span class="ow">in</span> <span class="n">signature</span><span class="o">.</span><span class="n">parameters</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
<span class="n">default</span> <span class="o">=</span> <span class="n">converter</span><span class="p">(</span><span class="n">param</span><span class="o">.</span><span class="n">default</span><span class="p">)</span>
<span class="n">metadata</span> <span class="o">=</span> <span class="n">metadata</span><span class="o">.</span><span class="n">combine</span><span class="p">(</span><span class="n">default</span><span class="o">.</span><span class="n">metadata</span><span class="p">)</span>
<span class="n">instantiators</span><span class="p">[</span><span class="n">param</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">default</span><span class="o">.</span><span class="n">instantiator</span>
<span class="k">def</span> <span class="nf">instantiate</span><span class="p">(</span><span class="n">box</span><span class="p">,</span> <span class="n">selections</span><span class="p">):</span>
<span class="n">kwargs</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">instantiator</span> <span class="ow">in</span> <span class="n">instantiators</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
<span class="n">kwargs</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="k">yield from</span> <span class="n">instantiator</span><span class="p">(</span><span class="n">box</span><span class="p">,</span> <span class="n">selections</span><span class="p">)</span>
<span class="k">return</span> <span class="n">function</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">return</span> <span class="n">Parametric</span><span class="p">(</span><span class="n">instantiate</span><span class="p">,</span> <span class="n">metadata</span><span class="p">)</span>
<span class="k">return</span> <span class="n">deco</span>
<span class="nd">@make_deco</span>
<span class="k">def</span> <span class="nf">parametric</span><span class="p">(</span><span class="n">default</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-></span> <span class="n">Parametric</span><span class="p">[</span><span class="nb">object</span><span class="p">]:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">default</span><span class="p">,</span> <span class="n">FakeValue</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">ValueError</span>
<span class="k">return</span> <span class="n">default</span><span class="o">.</span><span class="n">parametric</span>
<span class="c1"># another module</span>
<span class="k">def</span> <span class="nf">adaptive</span><span class="p">(</span><span class="n">function</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="n">T</span><span class="p">])</span> <span class="o">-></span> <span class="n">AdaptiveParametric</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span>
<span class="n">segment_parametrics</span> <span class="o">=</span> <span class="p">[]</span>
<span class="nd">@_parametric</span><span class="o">.</span><span class="n">make_deco</span>
<span class="k">def</span> <span class="nf">deco</span><span class="p">(</span><span class="n">default</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-></span> <span class="n">Parametric</span><span class="p">[</span><span class="nb">object</span><span class="p">]:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">default</span><span class="p">,</span> <span class="n">SomeOtherFakeValue</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">ValueError</span>
<span class="n">mapped_parametric</span> <span class="o">=</span> <span class="n">default</span><span class="o">.</span><span class="n">value</span>
<span class="n">parametric</span> <span class="o">=</span> <span class="n">mapped_parametric</span><span class="o">.</span><span class="n">parametric</span>
<span class="n">segment_parametrics</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
<span class="n">_parametric</span><span class="o">.</span><span class="n">map_over_1_parametric</span><span class="p">(</span>
<span class="n">mapped_parametric</span><span class="o">.</span><span class="n">map</span><span class="p">,</span> <span class="n">parametric</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">parametric</span>
<span class="n">parametric</span> <span class="o">=</span> <span class="n">deco</span><span class="p">(</span><span class="n">function</span><span class="p">)</span>
<span class="k">return</span> <span class="n">AdaptiveParametric</span><span class="p">(</span><span class="nb">tuple</span><span class="p">(</span><span class="n">segment_parametrics</span><span class="p">),</span> <span class="n">parametric</span><span class="p">)</span>
</pre></div>
<p>It might look a little weird that I'm using the old mapping functions as part of implementing the new mapping functions, but the thing is, there are places where I feel like it doesn't make sense to switch from the old system, so I might as well keep it, and if I'm keeping it, I might as well use it in new places as well.</p>
<p>Aside from the corrections to obvious mistakes I made last-time-ish, I'm now considering what I want the new MappedParametric concept to look like.
The "problem" is, both of the things that go into it are functions, unlike the old way, which used a label instead of a parametric.
I can't think of which one I'd want to have set up in a decorator position, so maybe... both?</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">mapped_parametric</span><span class="p">(</span><span class="n">function</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="nb">map</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">parametric</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="n">none_count</span> <span class="o">=</span> <span class="p">(</span><span class="n">function</span><span class="p">,</span> <span class="nb">map</span><span class="p">,</span> <span class="n">parametric</span><span class="p">)</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span>
<span class="k">if</span> <span class="n">none_count</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span>
<span class="k">if</span> <span class="n">none_count</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="k">return</span> <span class="n">MappedParametric</span><span class="p">(</span>
<span class="nb">map</span><span class="o">=</span><span class="nb">map</span> <span class="ow">or</span> <span class="n">function</span><span class="p">,</span> <span class="n">parametric</span><span class="o">=</span><span class="n">parametric</span> <span class="ow">or</span> <span class="n">function</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">function</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span>
<span class="k">return</span> <span class="n">partial</span><span class="p">(</span><span class="n">mapped_parametric</span><span class="p">,</span> <span class="nb">map</span><span class="o">=</span><span class="nb">map</span><span class="p">,</span> <span class="n">parametric</span><span class="o">=</span><span class="n">parametric</span><span class="p">)</span>
</pre></div>
<p>That seems a little cursed, so it would be better to inventory how this would <em>actually be used</em>, before actually putting this in the code and trying to annotate it.
(A more restrained way to accomplish something similar would be to create alternative constructors with <tt class="docutils literal">classmethod</tt>, but that's not as funny as putting cartoon swearing in the parameter list.)</p>
<p>Anyway, that's enough for now.
I'm going to try to figure out what happened to last night's entry, then wind down.</p>
<p>Good night.</p>
Coding 2023-04-062023-04-06T04:00:00-04:002023-04-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-06:/coding-2023-04-06<p class="first last">These names won't make any more sense when I'm done, but maybe the structure of the code will.</p>
<p>Before I get into messing with code, let's take a look at what I need to know for one of the future steps, that of getting rid of <tt class="docutils literal">MapOverSelection</tt>.
First, let's see how it's used.</p>
<ul class="simple">
<li>In <tt class="docutils literal">artifact</tt>:<ul>
<li>I wrap it in an alias, which is, a bit unfortunate.
The alias is used only in the module, which helps.
The alias is used:<ul>
<li>In the signature of <tt class="docutils literal">Artifact.convert</tt>.
In this context, it is passed to <tt class="docutils literal">_selection_labels</tt>, which corresponds to one of the metadata fields on a parametric, but I'm not sure which one currently, and to a <tt class="docutils literal">Condenser</tt> and an <tt class="docutils literal">OutputConverter</tt>.</li>
<li>In the signature of <tt class="docutils literal">Condenser.__call__</tt>.
In this context, it is used directly, to alter a parametric through a folding operation.
The probable updated version of this usage is to directly have a set of parametrics, and pass that directly to the fold.</li>
<li>In the signature of <tt class="docutils literal">InternalConverter.__call__</tt>.
In this context, it is passed to the <tt class="docutils literal">Input</tt> constructor.</li>
<li>In the signature of <tt class="docutils literal">OutputConverter.__call__</tt>.
In this context, it is passed to <tt class="docutils literal">InternalConverter.__call__</tt> and the <tt class="docutils literal">Input</tt> constructor, as well as to <tt class="docutils literal">OutputConverter.__call__</tt>.</li>
</ul>
</li>
<li>Otherwise, it's held in the <tt class="docutils literal">Input</tt> object, and passed out via <tt class="docutils literal">Artifact.exposed_selections</tt>.
Which is called from...</li>
</ul>
</li>
<li>The <tt class="docutils literal">parametric_command</tt> module, specifically...<ul>
<li><tt class="docutils literal">Put.selections</tt>, which is accessed in...</li>
<li><tt class="docutils literal">ParametricCommand._selections</tt>, which passes individual items to <tt class="docutils literal">_update_labeled_maps</tt>, and also accesses a similarly-named attribute off of...</li>
<li><tt class="docutils literal">AdaptiveParametric</tt>, which dynamically constructs a parametric based off of its attributes, in a very unsafe way, by the standards of this layer.
The hope here is to replace this with bare <tt class="docutils literal">Parametric</tt>, or a much lighter wrapper.</li>
<li><tt class="docutils literal">_update_labeled_maps</tt> associates a selection label to a <tt class="docutils literal">MapOverSelection</tt>, and this is helpful because...</li>
<li>It is eventually passed to <tt class="docutils literal">_optional_parametric</tt>?
This confusing function only needs to pass it to <tt class="docutils literal">Put.build</tt>, which passes it back to <tt class="docutils literal">Artifact.convert</tt>.</li>
</ul>
</li>
</ul>
<p>From here, it looks like all I need to do is to make sure some of the types are properly restricted.
I think that can be accomplished by...</p>
<p>Using the type <tt class="docutils literal">Parametric[PathStr]</tt>.
Or maybe pairs of <tt class="docutils literal">Parametric[T]</tt> and <tt class="docutils literal"><span class="pre">Callable[[T],</span> PathStr]</tt>.
Which implies to me that maybe I don't rip out quite as much as I was thinking I would.
However...</p>
<p>I forgot my train of thought.</p>
<p>Anyway, I think I've got the information I need to plan out new versions.
The one wrinkle is, I want to figure out if it's possible to take the core <tt class="docutils literal">parametric()</tt> logic from yesterday, and have some of it in common somehow, since, unless I manage not to need the pair stuff, the pair is going to need its own decorator with an extremely similar implementation.</p>
<p>In any case, I should get ready for bed now.</p>
<p>Good night.</p>
Coding 2023-04-052023-04-05T04:00:00-04:002023-04-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-05:/coding-2023-04-05<p class="first last">Just kind of smoosh all of the metadata together, it's fine.</p>
<p>Okay, the magma is written, and I'll verify that it's "actually correct in general" later, hopefully after I've nailed down some requirements for it.</p>
<p>Let's start working on the next <tt class="docutils literal">parametric</tt> overhaul.</p>
<p>The first half of this has several parts:</p>
<ul class="simple">
<li>A wrapper class around <tt class="docutils literal">Parametric</tt> objects.</li>
<li>A property on <tt class="docutils literal">Parametric</tt> that is documented to return an object of the underlying type, but actually returns an instance of this wrapper class.</li>
<li>A decorator that takes the signature of the function it's passed, and makes sure that all arguments have a default value that's an instance of the wrapper class.
Then, map over all of them.</li>
</ul>
<p>It's probably worth calling the decorator just "<tt class="docutils literal">parametric</tt>".
The type should be called, um...
<tt class="docutils literal">FakeValue</tt>, or something.
Something that hopefully makes it really clear that it shouldn't work for most purposes.
And the property, just <tt class="docutils literal">value</tt>, maybe?</p>
<p>I don't know if I want to put these ideas into the actual module yet, but let's see what I can do in code blocks here.</p>
<div class="highlight"><pre><span></span><span class="c1"># Eventually, these will be replaced with "attrs.frozen"</span>
<span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">FakeValue</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">Generic</span><span class="p">[</span><span class="n">T_co</span><span class="p">]):</span>
<span class="n">parametric</span><span class="p">:</span> <span class="n">Parametric</span><span class="p">[</span><span class="n">T_co</span><span class="p">]</span>
<span class="o">...</span>
<span class="k">class</span> <span class="nc">Parametric</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">Generic</span><span class="p">[</span><span class="n">T_co</span><span class="p">]):</span>
<span class="o">...</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">value</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">T_co</span><span class="p">:</span>
<span class="k">return</span> <span class="n">typing</span><span class="o">.</span><span class="n">cast</span><span class="p">(</span><span class="n">T_co</span><span class="p">,</span> <span class="n">FakeValue</span><span class="p">(</span><span class="bp">self</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">parametric</span><span class="p">(</span><span class="n">function</span><span class="p">):</span>
<span class="n">signature</span> <span class="o">=</span> <span class="n">inspect</span><span class="o">.</span><span class="n">signature</span><span class="p">(</span><span class="n">function</span><span class="p">)</span>
<span class="n">instantiators</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">metadata</span> <span class="o">=</span> <span class="n">Metadata</span><span class="p">()</span>
<span class="k">for</span> <span class="n">param</span> <span class="ow">in</span> <span class="n">signature</span><span class="o">.</span><span class="n">parameters</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
<span class="n">default</span> <span class="o">=</span> <span class="n">param</span><span class="o">.</span><span class="n">default</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">default</span><span class="p">,</span> <span class="n">FakeValue</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">ValueError</span>
<span class="n">metadata</span> <span class="o">=</span> <span class="n">metadata</span><span class="o">.</span><span class="n">combine</span><span class="p">(</span><span class="n">default</span><span class="o">.</span><span class="n">metadata</span><span class="p">)</span>
<span class="n">instantiators</span><span class="p">[</span><span class="n">param</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">default</span><span class="o">.</span><span class="n">instantiator</span>
<span class="k">def</span> <span class="nf">instantiate</span><span class="p">(</span><span class="n">box</span><span class="p">,</span> <span class="n">selectors</span><span class="p">):</span>
<span class="c1"># I'm pretty sure Python is too strict to allow this, but eh.</span>
<span class="n">kwargs</span> <span class="o">=</span> <span class="p">{</span><span class="n">name</span><span class="p">:</span> <span class="p">(</span><span class="k">yield from</span> <span class="n">instantiator</span><span class="p">(</span><span class="n">box</span><span class="p">,</span> <span class="n">selectors</span><span class="p">))</span> <span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">instantiator</span> <span class="ow">in</span> <span class="n">instantiators</span><span class="o">.</span><span class="n">values</span><span class="p">()}</span>
<span class="k">return</span> <span class="n">function</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">return</span> <span class="n">Parametric</span><span class="p">(</span><span class="n">instantiate</span><span class="p">,</span> <span class="n">metadata</span><span class="p">)</span>
</pre></div>
<p>I hope this basically works, disregarding the syntactic gunk that I'll have to work around.
I'm going to wrap things up for now, and think about it.</p>
<p>Good night.</p>
Weekly Roundup 2023-04-042023-04-04T04:00:00-04:002023-04-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-04:/weekly-roundup-2023-04-04<p class="first last">I suppose I really should try to list, like, specific things blocking a release...</p>
<ul class="simple">
<li>Wednesday: I worked on updating the <tt class="docutils literal">cmd</tt> module in MOTR.</li>
<li>Thursday: I realized that the <tt class="docutils literal">cmd</tt> module is going to need to operate in some weird mixed mode for the time being.</li>
<li>Friday: I got the mixed mode stuff working, which gave me the confidence to try to address the Mypy 1 typing issues. Trying to address the issues removed the confidence.</li>
<li>Saturday: I finished with <tt class="docutils literal">cmd</tt>, and had a look at <tt class="docutils literal">command</tt>. That's... even less straightforward, even though there's no legacy path to worry about.</li>
<li>Sunday: I made a small addition to <tt class="docutils literal">cmd</tt> to handle the changes I'm making to <tt class="docutils literal">command</tt>.</li>
<li>Monday: I got <em>almost</em> done updating <tt class="docutils literal">command</tt>. Just a little tweaking left, and it's good to go.</li>
</ul>
<p>Next week, I'm going to wrap up the <tt class="docutils literal">command</tt> updates, and probably get into some weirder updating projects.</p>
Coding 2023-04-032023-04-03T04:00:00-04:002023-04-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-03:/coding-2023-04-03<p class="first last">No progress yet in understanding why this stuff breaks under Mypy 1.</p>
<p>I was messing with other stuff today, so let's give some quick thoughts to the conversion method I want to update.</p>
<p>The actual update should be pretty simple.
I "just" have to update a single type and fix the errors that bubble out...</p>
<p>Okay, that was actually pretty easy, except that I forgot to mark some usages as covariant, so I went add fixed that, and then it all, just, went.</p>
<p>That's addressing the types, but not the new combination logic, which just has to go in <tt class="docutils literal">command</tt>.
I don't feel like writing a magma for this right now, even though I basically know what it has to do.
There are a few things that I may need to think about.
Like, should it be possible to specify duplicate paths in an environment variable, and, if so, do I want some way to opt into deduplication?
For now, it's probably safe to ignore questions like that.</p>
<p>Once the magma is in, it'll be trivial to add a new type to <tt class="docutils literal">parametric_command</tt> to handle it.</p>
<p>In any case, the other thing I can be working on is, how to phase out the MapOverSelection stuff.</p>
<p>For now, I'm going to wind down and mess with other stuff.</p>
<p>Good night.</p>
Coding 2023-04-022023-04-02T04:00:00-04:002023-04-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-02:/coding-2023-04-02<p class="first last">Things that are necessary and also easy.</p>
<p>All right.
I've determined that the right way to handle the new environment variable format is to shove everything into the new wrapper types, and use map methods to apply the existing conversion method over the contents.</p>
<p>The wrinkle that I addressed with that was to write new methods to properly handle the whole "sort-of-effects-system" I have going.
So, I did that, and now I need to review the conversion method.
For reasons, it might make sense to pull it out into its own class.</p>
<p>I'll give this all a shot later.</p>
<p>For now, I'm going to take things easy again.</p>
<p>Good night.</p>
Coding 2023-04-012023-04-01T04:00:00-04:002023-04-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-04-01:/coding-2023-04-01<p class="first last">Given enough thought, this was easy. Next time, though...</p>
<p>I went back to the <tt class="docutils literal">cmd</tt> module, and finished updating the interfaces.
Everything beyond this point should be a case of switching over completely to the new interface.
If I'm remembering and reading the grep output correctly, that should be relatively minor of a change.
I think it should just be <tt class="docutils literal">command</tt> and <tt class="docutils literal">parametric_command</tt>.</p>
<p>...</p>
<p>Oof, "just".</p>
<p><tt class="docutils literal">parametric_command</tt> should be fine, but <tt class="docutils literal">command</tt> is a bit of a mess in this area.</p>
<p>Here's the deal...</p>
<p><tt class="docutils literal">command</tt> defines an <tt class="docutils literal">EnvVars</tt> type that is parametric over... stuff.
It's a map from strings to... stuff.
Where "stuff", in this case, is a <tt class="docutils literal">CmdArg</tt> and either nothing else, or an <tt class="docutils literal">Executable</tt>.</p>
<p>(Side note: I find myself wondering whether it's worth having the Path/NonPath distinction, but I still <em>need</em> the new logic to feel comfortable with this code, so let's go ahead with it anyway.)</p>
<p>Now, let's trace what this code is doing.
Not going to touch it tonight, but let's trace it.</p>
<p>The type ultimately gets used by <tt class="docutils literal">resolve_env</tt>.
This function currently produces a mapping from <tt class="docutils literal">str</tt> to <tt class="docutils literal">CmdArg</tt>.
It needs to produce a mapping from <tt class="docutils literal">str</tt> to <tt class="docutils literal">EnvVar[CmdArg]</tt>.
Which means that <tt class="docutils literal">_convert_segment</tt> needs to be producing <tt class="docutils literal">EnvVar[CmdArg]</tt>, which is a bit interesting, because it doesn't overlap with the other return types from <tt class="docutils literal">_convert_segment</tt>, so I ought to be able to split it out into a new method.
At that point, it makes sense to provide three private conversion methods instead of one combined one.</p>
<p>So, the first thing I need to do is to trace out what the other call sites do, and track down which types they need to handle.</p>
<p>That could be a lot.
So, I'm going to wrap things up for now, and wind down.</p>
<p>Good night.</p>
Coding 2023-03-312023-03-31T04:00:00-04:002023-03-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-31:/coding-2023-03-31<p class="first last">I genuinely can't tell if this stuff is a regression or a bugfix.</p>
<p>Okay, let's think about MOTR and the <tt class="docutils literal">Cmd.env</tt> field some more.
It's arguably inaccurate, but not in a way that matters, to shove everything into one mapping type in each place.
So, let's give that a shot.</p>
<p>...</p>
<p>Changing the code seemed to work, but it looks like I made it unhappy...</p>
<p>Okay, that was a legitimate error, a mistype.
Fixed easily enough.
Now, I'll get the other problem...</p>
<p>And, done.</p>
<p>Now, before I think about continuing the update path here, I should really try to update some of my dependencies.</p>
<p>When I run the latest version of Mypy against the MOTR code base...
It complains mightily because of some Extremely Normal code.</p>
<p>...</p>
<p>I slammed into it a few times.
Here are the basic issues:</p>
<ul class="simple">
<li>TypeVars that are restricted to a range of values including a (user-defined?) generic type parameterized with <tt class="docutils literal">Any</tt> no longer unify with that type parameterized with a specific type.</li>
<li>Sometimes, for some reason, a function that always defines a return type, is considered to not actually return.
The heavy use of <tt class="docutils literal">overload</tt> in this area of code may be confusing things.</li>
</ul>
<p>I can get around the former case by using an unrestricted type variable, which is <em>basically</em> harmless, but I can't even figure out which line is making it complain in the latter case.
Like, yes, there are line numbers in the error messages, but those are at <em>usage</em>, so it's kind of already too late, in that the idea that this function can fail to return is already locked in.</p>
<p>Anyway, I'll get back to that later, or not.
I made my choices for the <tt class="docutils literal">cmd</tt> module tonight, and I'll call that good enough.</p>
<p>Good night.</p>
Coding 2023-03-302023-03-30T04:00:00-04:002023-03-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-30:/coding-2023-03-30<p class="first last">"Development is going well, I just need to turn over this rock and—OH NO!"</p>
<p>All right.
Starting this entry early, because I've been considering some fiddly changes I want to make within MOTR.</p>
<p>Basically...</p>
<p>The problem with updating the <tt class="docutils literal">cmd</tt> module is that the current release of MOTR is operating at such a low level (relatively speaking, <em>do not</em> scoff) that the motrfiles that I'm currently writing need to reach into MOTR's guts in order to actually <em>accomplish</em> anything.
So, even though I have some ideas about changes I want to make (I'll explain those ideas in a moment), I need to make sure that I leave some way for the existing code to manage to accomplish stuff.</p>
<p>So, here's the issue.
As the reproduction code I pasted yesterday kind of indicates, I'm doing some stuff where I'm <em>basically</em> replacing <tt class="docutils literal">T</tt> with <tt class="docutils literal">T | tuple[T, <span class="pre">...]</span></tt>.
The problem with this type is that Mypy only allows me to accomplish anything with it, by, um, cheating.
The proper replacement is something like <tt class="docutils literal">NewWrapper[T] | tuple[T, <span class="pre">...]</span></tt> or <tt class="docutils literal">NewWrapper[T] | OtherNewWrapper[T]</tt>.</p>
<p>But if I do that, then the core code isn't supposed to handle <tt class="docutils literal">T</tt> any more, which means that existing callers get broken.</p>
<p>So here's the trick:
I only need to continue to support the old flow with the <tt class="docutils literal">cmd</tt> module.
Everything else is basically invisible to the motrfiles.
SO.</p>
<p>I have <tt class="docutils literal">EnvVar = Unique[T] | Paths[T]</tt>, <tt class="docutils literal">StrMap = Mapping[str, T]</tt>, <tt class="docutils literal">EnvVars = StrMap[EnvVar[T]]</tt>, <tt class="docutils literal">LegacyEnvVars = StrMap[T] | EnvVars[T]</tt>.
Something like that.
What this lets me do is to beef up support for <tt class="docutils literal">EnvVars</tt> until I can cut the internal consumers over to it, but leave the legacy code paths in place until after I finally cut a release.</p>
<p>I probably need to finagle this a bit to account for the fact that I'm specifying concrete types in a few places, but this shouldn't be hard to iron out.</p>
<p>Regardless, I don't feel like I'm going to get it done tonight; I'm just glad I ironed things out a bit in thinking about the way I want the types to be interacting.</p>
<p>That said, I do have the option to make everything a bit less... precise, in exchange for having fewer types kicking around.
This will need a bit of sketching to check, and right now I just want to take things easy for the rest of tonight again.</p>
<p>Good night.</p>
Coding 2023-03-292023-03-29T04:00:00-04:002023-03-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-29:/coding-2023-03-29<p class="first last">I can think of ways around this, but they're ridiculous.</p>
<p>All right...</p>
<p>Let's just do one of these things: the path environment variable work.</p>
<p>Actually, before that, let's see how bad the merge is currently.</p>
<p>...</p>
<p>Not too bad.</p>
<p>Back to the path environment variable stuff.</p>
<p>...</p>
<p>And nearly immediately, I run into trouble.</p>
<p>It was no big deal supporting this at the very bottom level, and I anticipate the levels above will be... mostly workable.
What I need to figure out is how to deal with the weird "shapes" that allowing multiple values into the environment mapping is creating.
Here's the deal...</p>
<p>The <tt class="docutils literal">cmd_</tt> wrapper is meant to unwrap values that may be IO-wrapped.
(If you know Haskell or a similar language, please try to ignore all possible connotations.
They're not the same thing, and if I come up with better terminology, I'll change it.)
These values are extract in three different places.</p>
<ul class="simple">
<li>The <tt class="docutils literal">Cmd</tt> constructor needs <em>the same structure</em>, but with all wrapping discarded, and individual values passed through <tt class="docutils literal">os.fspath</tt>.
The changes I just made make the structure more complex, and move around the concept of "individual values".</li>
<li>The <tt class="docutils literal">action</tt> (I assume this has a different name in the future topic, but I've forgotten) call needs the stream of individual values, as does the <tt class="docutils literal">_extra_targets</tt> call.</li>
</ul>
<p>The initial thought that I have is that this implies that the current system of unwrapping doesn't completely make sense.
The current system assumes that we can get sensible behavior by passing around streams of values.
Now, there's no way around this when it comes to filtering by IO wrapper type, unless whatever alternative system can handle discarding values, but there's no gain in implementing such a system currently.</p>
<p>So, the filtering behavior stands, but the "unwrapping" behavior has to move into a standalone function, and get mapped or comprehended.
Let's see...</p>
<ul class="simple">
<li>Write the unwrap function...</li>
<li>Use the unwrap function in <tt class="docutils literal">cmd_</tt></li>
<li>Remove the method...</li>
<li>Fix a mypy error that I introduced somehow...</li>
</ul>
<p>Okay, I'm going to need to puzzle over that.
But I know approximately what comes next:</p>
<ul class="simple">
<li>Write a function to emit all "individual values" from one of these fancy environment dictionaries.</li>
<li>Write a function to map over one of these fancy environment dictionaries.</li>
</ul>
<p>I'm going to try to get the error fixed, and then call things for tonight.</p>
<p>...</p>
<p>I sort of understand the error, but it...
It shouldn't happen?</p>
<p>I just confirmed that it's not because I'm pinning the mypy version back.</p>
<p>In any case, I'm using a cast to deal with this, but <em>really</em>, mypy should just get the right value itself.</p>
<p>Here is a reproduction.
My code is extremely normal.</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TypeVar</span><span class="p">,</span> <span class="n">Union</span>
<span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T"</span><span class="p">)</span>
<span class="n">Thing</span> <span class="o">=</span> <span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]</span>
<span class="n">MaybeTuple</span> <span class="o">=</span> <span class="n">Union</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">[</span><span class="n">T</span><span class="p">]]</span>
<span class="k">def</span> <span class="nf">untuple</span><span class="p">(</span><span class="n">item</span><span class="p">:</span> <span class="n">MaybeTuple</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="o">-></span> <span class="n">T</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
<span class="k">return</span> <span class="n">item</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">return</span> <span class="n">item</span>
<span class="n">var</span><span class="p">:</span> <span class="n">MaybeTuple</span><span class="p">[</span><span class="n">Thing</span><span class="p">]</span>
<span class="n">reveal_type</span><span class="p">(</span><span class="n">untuple</span><span class="p">(</span><span class="n">var</span><span class="p">))</span> <span class="c1"># object???</span>
</pre></div>
<p>I think I'm going to have to live with this <em>at least</em> until I can actually unpin the version, unless there's some way I'm "supposed to" be setting up these unions.</p>
<p>In any case, I want to wrap up for now.</p>
<p>Good night.</p>
Weekly Roundup 2023-03-282023-03-28T04:00:00-04:002023-03-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-28:/weekly-roundup-2023-03-28<p class="first last">I got stuff done, but I didn't feel great. Oh well.</p>
<ul class="simple">
<li>Wednesday: I started drafting the next round of changes to the <tt class="docutils literal">parametric</tt> module.</li>
<li>Thursday: I finished drafting those changes.</li>
<li>Friday: I got some feedback on my writing, and added more esoteric shell gunk to the build script.</li>
<li>Saturday: I dashed out something at approximately five to midnight.</li>
<li>Sunday: I thought a bit about my priorities.</li>
<li>Monday: I made the next round of changes to the <tt class="docutils literal">parametric</tt> module. It went well.</li>
</ul>
<p>Next week, I'm going to finally get a bit more feedback on my writing, and work on the other overhauls that I feel like MOTR needs.</p>
Coding 2023-03-272023-03-27T04:00:00-04:002023-03-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-27:/coding-2023-03-27<p class="first last">Ripping another bandaid off.</p>
<p>Okay, I did the renames to update the fields in the <tt class="docutils literal">parametric</tt> module.
The initial update was pretty smooth, although I did run into one weird issue with the attrs plugin for Mypy.
I need to take some time to go over the module and make sure the updates all make sense.</p>
<p>One thing I wasn't remembering yesterday is that I want to phase out one of the other modules.
Now that I have the new names in, I should be able to coherently reason about the replacement.</p>
<p>I suppose I should also merge up to the future topic, but, eeeh.
Maybe later.</p>
<p>So, looking at what's coming next:</p>
<ul class="simple">
<li>Verify name updates in <tt class="docutils literal">parametric</tt>.</li>
<li>Implement path environment variables.</li>
<li>Phase out <tt class="docutils literal">map_over_selection</tt>.<ul>
<li>Implement decorator-based parameter mapping.<ul>
<li>Write a specialized wrapper class and fake property.</li>
</ul>
</li>
<li>Document all usages of <tt class="docutils literal">MapOverSelection</tt>; this is going to be a bit of a pain, since it shows up in annotations nearly two dozen times.</li>
</ul>
</li>
</ul>
<p>Realistically speaking, the path environment variables is going to be less of a pain, but I'm really intrigued by the ergonomics wins from the overall process for phasing out <tt class="docutils literal">map_over_selection</tt>.</p>
<p>Anyway, I can't do any of that tonight, so I'm going to take things easy for the rest of the night, and then work on doing things properly over the rest of the week.</p>
<p>Good night.</p>
Diary 2023-03-262023-03-26T04:00:00-04:002023-03-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-26:/diary-2023-03-26<p class="first last">Stay tuned for: more stuff in this vein throughout the week.</p>
<p>All right, I'm not writing this entry on a stupid time crunch, but I'm going to try to get it done quickly anyway.
All day pretty much was taken up with sleep and some important things that we had to take care of.</p>
<p>Tomorrow, I hope to put in work on MOTR, prioritizing things between:</p>
<ul class="simple">
<li>Support for path environment variables</li>
<li>Reworking the parametric metadata label sets</li>
<li>Making any helpful adjustments to how the parametric module is laid out.</li>
</ul>
<p>The label sets probably come first, and then the other two as I feel like it.</p>
<p>Once all of these are handled, I should take stock of what I'll need in order to advance with work on the wrappers.</p>
<p>But for now, I'm going to put this entry in nice and early, and take things easy for the rest of the night.</p>
<p>Good night.</p>
Diary 2023-03-252023-03-25T04:00:00-04:002023-03-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-25:/diary-2023-03-25<p class="first last">Whoops. Don't bother reading this.</p>
<p>Oh wow, I made some bad time management decisions.
The best course of action I can take, if I want to publish an entry tonight, is to just publish this tiny little thing.</p>
<p>Good night.</p>
Diary 2023-03-242023-03-24T04:00:00-04:002023-03-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-24:/diary-2023-03-24<p class="first last">It's probably fine.</p>
<p>Okay, so, here's where the writing is...</p>
<p>My wife had a look over the current, very short draft.
Things sound mostly good so far, but the experimental stuff is making it a bit hard to follow.
So, I'm currently working on adding explanations of it.</p>
<p>The next thing I need to do is to clear up my workflow for generating uploadable drafts, because I'm running into spellcheck-related issues that are definitely an issue on my end rather than any other software.</p>
<p>Basically, because I'm adding a preface, I don't think I want to apply the same spell-checking stuff to the preface as to the main story.</p>
<p>Okay cool I just have to pipe the plaintext version through <tt class="docutils literal">sed <span class="pre">-n</span> <span class="pre">'/Preface/,/Main</span> <span class="pre">Story/!p'</span></tt> that's not going to be super confusing or anything later I bet.</p>
<p>Anyway, that's stuff accomplished for tonight, cool.
It's early, but I'm still tired, so I'm going to wrap up.</p>
<p>Good night.</p>
Coding 2023-03-232023-03-23T04:00:00-04:002023-03-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-23:/coding-2023-03-23<p class="first last">Just about comfortable locking these ideas in.</p>
<p>All right, let's move through more parametric stuff...</p>
<p>The next function defines a helper, which I'd like to move into the helper module related to "parametric maps".
Basically, I want a few different example magma functions, and one of them will be "bail if the values don't match".
All together, this should result in something like:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">combine</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="n">Metadata</span><span class="p">)</span> <span class="o">-></span> <span class="n">Metadata</span><span class="p">:</span>
<span class="k">return</span> <span class="n">Metadata</span><span class="p">(</span>
<span class="n">box_labels</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">box_labels</span> <span class="o">|</span> <span class="n">other</span><span class="o">.</span><span class="n">box_labels</span><span class="p">,</span> <span class="c1"># I, uh, missed adding this to the other constructors.</span>
<span class="n">selection_labels</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">selection_labels</span> <span class="o">|</span> <span class="n">other</span><span class="o">.</span><span class="n">selection_labels</span><span class="p">,</span>
<span class="n">iterated_labels</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">iterated_labels</span> <span class="o">|</span> <span class="n">other</span><span class="o">.</span><span class="n">iterated_labels</span><span class="p">,</span>
<span class="n">exclusive_labels</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">exclusive_labels</span> <span class="o">|</span> <span class="n">other</span><span class="o">.</span><span class="n">exclusive_labels</span><span class="p">,</span>
<span class="n">multivalue_labels</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">multivalue_labels</span> <span class="o">&</span> <span class="n">other</span><span class="o">.</span><span class="n">multivalue_labels</span><span class="p">,</span>
<span class="nb">input</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">input</span><span class="o">.</span><span class="n">update_with</span><span class="p">(</span>
<span class="n">_per_item_parametric_mapping</span><span class="o">.</span><span class="n">reject_if_different</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">input</span>
<span class="p">),</span>
<span class="p">)</span>
</pre></div>
<p>The next function is... not named well...
Let's change it to...</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">iterated_labels_except_for</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">labels</span><span class="p">:</span> <span class="n">_selection</span><span class="o">.</span><span class="n">Labels</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">_selection</span><span class="o">.</span><span class="n">Labels</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">labels</span> <span class="o"><=</span> <span class="bp">self</span><span class="o">.</span><span class="n">iterated_labels</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">iterated_labels</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">labels</span><span class="p">)</span>
</pre></div>
<p>And now, the last bits of code for the <tt class="docutils literal">Metadata</tt> class:</p>
<div class="highlight"><pre><span></span><span class="nd">@property</span>
<span class="k">def</span> <span class="nf">singleton_labels</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">_selection</span><span class="o">.</span><span class="n">Labels</span><span class="p">:</span>
<span class="k">return</span> <span class="p">(</span>
<span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">exclusive_labels</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">iterated_labels</span><span class="p">)</span>
<span class="o">|</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">selection_labels</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">multivalue_labels</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">selections</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">box</span><span class="p">:</span> <span class="n">_box</span><span class="o">.</span><span class="n">Box</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterator</span><span class="p">[</span><span class="n">_selection</span><span class="o">.</span><span class="n">Selection</span><span class="p">]:</span>
<span class="k">for</span> <span class="n">box_label</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">box_labels</span><span class="p">:</span>
<span class="k">if</span> <span class="n">box_label</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">box</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span>
<span class="c1"># Maybe check that every selection label maps to a non-empty value?</span>
<span class="k">for</span> <span class="n">singleton_label</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">singleton_labels</span><span class="p">:</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">box</span><span class="p">[</span><span class="n">singleton_label</span><span class="p">]</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="o">></span> <span class="mi">1</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span>
<span class="k">return</span> <span class="n">_selection</span><span class="o">.</span><span class="n">selections</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">iterated_labels</span><span class="p">,</span> <span class="n">box</span><span class="p">)</span>
</pre></div>
<p>Let's see, the next really interesting one is "include_box", which.
Hm.
That should fail if the included box has a non-empty intersection with <tt class="docutils literal">selection_labels</tt>, and it should set <tt class="docutils literal">box_labels</tt> to the difference.</p>
<p>I think that all gets me to a good place with the <tt class="docutils literal">parametric</tt> module.
If the rest of the code has a problem with the changes I'm proposing, then that, um... that's a problem with the code that's not in the module, frankly.</p>
<p>Now, I'm going to take a break from working on this for a day or so, then get into either this or the common motrfile concept.
In the meantime, I'm going to get in some work on the draft for my writing.</p>
<p>For now, it's too late again, and I need to get to bed.</p>
<p>Good night.</p>
Coding 2023-03-222023-03-22T04:00:00-04:002023-03-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-22:/coding-2023-03-22<p class="first last">This overall makes a lot more sense.</p>
<p>Well, I'm not sick any more.</p>
<p>So, let's take a look at MOTR's code and imagine updating it.</p>
<p>Going through in order, we have the helper method <tt class="docutils literal">not_accumulable_because</tt>, which is...
Only called from <tt class="docutils literal">not_flex_out_because</tt>?
Which is only called from <tt class="docutils literal">artifact._parametric_not_flex_out</tt>.
Which is used as a validator for <tt class="docutils literal">artifact.Condenser</tt> and <tt class="docutils literal">artifact.BasicOutputConverter</tt>.
For now, let's ignore what's going on in <tt class="docutils literal">artifact</tt>, except insofar as this code is actually being used...</p>
<p>Putting all of this together, and keeping in mind that I want to relax the restrictions on multivalue labels, the final result is: one function like so:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">not_flex_out_because</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterator</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">input</span><span class="p">:</span>
<span class="k">yield</span> <span class="s2">"Unexpected use of parametric with associated inputs."</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">iterated_labels</span><span class="p">:</span>
<span class="k">yield</span> <span class="p">(</span>
<span class="s2">"The base parametric for an Output should not force iteration."</span>
<span class="p">)</span>
</pre></div>
<p>I dropped the restriction on required/exclusive labels, because I think the singleton reforms handle that, as well.</p>
<p>The definition of <tt class="docutils literal">expected_labels</tt> changes to <tt class="docutils literal">return self.iterated_labels | self.exclusive_labels</tt>, and it probably needs a name change.</p>
<p>Next, we have <tt class="docutils literal">providing</tt> and <tt class="docutils literal">also_providing</tt>, which change like so:</p>
<div class="highlight"><pre><span></span><span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">iterating_over</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">labels</span><span class="p">:</span> <span class="o">...</span><span class="p">)</span> <span class="o">-></span> <span class="n">Metadata</span><span class="p">:</span>
<span class="n">label_set</span> <span class="o">=</span> <span class="nb">frozenset</span><span class="p">(</span><span class="n">labels</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span><span class="n">iterated_labels</span><span class="o">=</span><span class="n">label_set</span><span class="p">,</span> <span class="n">selection_labels</span><span class="o">=</span><span class="n">label_set</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">also_iterating_over</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">label</span><span class="p">:</span> <span class="o">...</span><span class="p">)</span> <span class="o">-></span> <span class="n">Metadata</span><span class="p">:</span>
<span class="k">return</span> <span class="n">attr</span><span class="o">.</span><span class="n">evolve</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">iterated_labels</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">iterated_labels</span><span class="o">.</span><span class="n">union</span><span class="p">([</span><span class="n">label</span><span class="p">]),</span>
<span class="n">selection_labels</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">selection_labels</span><span class="o">.</span><span class="n">union</span><span class="p">([</span><span class="n">label</span><span class="p">]),</span>
<span class="p">)</span>
</pre></div>
<p>Next, we have <tt class="docutils literal">as_maximal</tt>, which maybe needs a name change, but I also have some simplifications planned.
Something like...</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Universe</span><span class="p">(</span><span class="n">enum</span><span class="o">.</span><span class="n">Enum</span><span class="p">):</span>
<span class="n">UNIVERSE</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="k">def</span> <span class="fm">__and__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">return</span> <span class="n">other</span>
<span class="fm">__rand__</span> <span class="o">=</span> <span class="fm">__and__</span>
<span class="k">def</span> <span class="fm">__rsub__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">frozenset</span><span class="p">()</span>
<span class="c1"># Don't know if this one is needed.</span>
<span class="k">def</span> <span class="fm">__contains__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">item</span><span class="p">):</span>
<span class="k">return</span> <span class="kc">True</span>
</pre></div>
<p>Which would be used as the default value of <tt class="docutils literal">multivalue_labels</tt>.
So <tt class="docutils literal">as_maximal</tt> becomes:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">as_maximal</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">Metadata</span><span class="p">:</span>
<span class="k">return</span> <span class="n">attr</span><span class="o">.</span><span class="n">evolve</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">multivalue_labels</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">multivalue_labels</span> <span class="o">&</span> <span class="bp">self</span><span class="o">.</span><span class="n">selection_labels</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
<p>Similar changes to <tt class="docutils literal">as_requiring</tt>:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">as_exclusive</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">Metadata</span><span class="p">:</span>
<span class="k">return</span> <span class="n">attr</span><span class="o">.</span><span class="n">evolve</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">iterated_labels</span><span class="o">=</span><span class="nb">frozenset</span><span class="p">(),</span>
<span class="n">exclusive_labels</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">expected_labels</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
<p>Then we get into <tt class="docutils literal">narrow_labels</tt>, which becomes...</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">reduce_iteration_to</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">labels</span><span class="p">:</span> <span class="n">_selection</span><span class="o">.</span><span class="n">Labels</span><span class="p">)</span> <span class="o">-></span> <span class="n">Metadata</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">labels</span> <span class="o"><=</span> <span class="bp">self</span><span class="o">.</span><span class="n">iterated_labels</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span>
<span class="n">no_longer_iterated_labels</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">iterated_labels</span> <span class="o">-</span> <span class="n">labels</span>
<span class="k">return</span> <span class="n">attr</span><span class="o">.</span><span class="n">evolve</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">iterated_labels</span><span class="o">=</span><span class="n">labels</span><span class="p">,</span>
<span class="n">exclusive_labels</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">exclusive_labels</span> <span class="o">-</span> <span class="n">no_longer_iterated_labels</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
<p>And I think I'll leave it there, because something is pretty suspicious about this, in a way that's making me suspect that my model is incomplete or incorrect.
There's a few things going on that look suspicious:</p>
<ul class="simple">
<li>Given this logic, which is identical to the previous logic except for the names, I can't tell how the <tt class="docutils literal">forbid_narrowing</tt> concept from elsewhere in the code is supposed to work.
Like, this code is, um, pretty insistent...</li>
<li>Oh, wait, I sort of get it.
<tt class="docutils literal">forbid_narrowing</tt> can't directly affect what happens to <tt class="docutils literal">exclusive_labels</tt>, but it does reduce the <tt class="docutils literal">iterated_labels</tt>...
In other words, "You can't squeeze this if I stomp it flat first."
I'm now provisionally okay with all of this except for the names.</li>
</ul>
<p>In any case, I need to think about this a bit more, then change things if I feel the need, or just move on down through the rest of the methods and functions.</p>
<p>Good night.</p>
Weekly Roundup 2023-03-212023-03-21T04:00:00-04:002023-03-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-21:/weekly-roundup-2023-03-21<p class="first last">A good week. Pity about today, though.</p>
<ul class="simple">
<li>Wednesday: I got some work done writing, in spite of some of the software I'm using.</li>
<li>Thursday: I did a bit more work, and reached an important milestone.</li>
<li>Friday: I considered how to move forward with the writing.</li>
<li>Saturday: Hunspell gave me <em>problems</em>.</li>
<li>Sunday: I worked on some of the changes I want to make to MOTR, focusing on planning.</li>
<li>Monday: I got some names improved in MOTR, and locked in the plan to evaluate these changes and then apply them if they work out.</li>
</ul>
<p>Next week, I'm going to try and make some more progress on these projects.
It's hard to say when I'll get started on that or just how much I'll accomplish, because I seem to be at least a little sick right now.
I also want to get back to working on the TWaW review backlog.
I may need to rethink that project in some way...</p>
Coding 2023-03-202023-03-20T04:00:00-04:002023-03-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-20:/coding-2023-03-20<p class="first last">Staring at my documentation and pondering what those words should actually mean.</p>
<p>I just did some quick work sketching stuff out for MOTR, and I think I've got what I need to try moving forward with the code:</p>
<ul class="simple">
<li><strong>ghost labels</strong> are now <strong>exclusive labels</strong></li>
<li>I have a tentative mapping from the old label names to the new label names</li>
</ul>
<p>I don't think I have much time to work on this tonight, but the next step is to go through all of the operations I have defined on these sets, and make sure that the new names make intuitive sense with what the operations do.
In some cases, I'll need to tweak the definitions slightly, to deal with the fact that I'm trying to allow more possible metadata.</p>
<p>The logic for determining singletons is also a bit up in the air.
I need to do some combination of set operations on <em>four</em> of these sets.</p>
<p>Anyway, I'll work that out later.
Here's hoping it all goes smoothly.
I'm going to wrap up early.</p>
<p>Good night.</p>
Coding 2023-03-192023-03-19T04:00:00-04:002023-03-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-19:/coding-2023-03-19<p class="first last">I'm still working through this logic...</p>
<p>Okay, so, I'm writing this late, so this is kind of "Hey, I should work on this more tomorrow," but...</p>
<p>I'm thinking more about the <tt class="docutils literal">Parametric</tt> rework in MOTR, and the more I think about it, the more I realize that I need to nail down some of the terminology.</p>
<p>I'm right now leaning towards four different kinds of data that can go into a command:</p>
<ul class="simple">
<li>Arguments, which have an optional prefix.
These have values like <tt class="docutils literal"><span class="pre">--fail-under=100</span></tt>, <tt class="docutils literal"><span class="pre">--show-contexts</span></tt>, <tt class="docutils literal"><span class="pre">-d</span></tt> <tt class="docutils literal">reports/coverage</tt>.</li>
<li>Non-path environment variables.
This isn't a great name.
It refers to stuff like <tt class="docutils literal">{"TERM": "xterm"}</tt>.</li>
<li>Path environment variables.
As above.
This is the newest concept in this space, and refers to stuff like <tt class="docutils literal">{"PYTHONPATH": <span class="pre">"/a/b/c:/d/e/f"}</span></tt>, in which the code, not yet written, should synthesize the combined path list from the component paths.</li>
<li>Implicit input and output.
Basically, sometimes a command's input or output is not present in the command's text, but MOTR still needs to be able to reason about it.
This is stuff like "the command accepts an output directory, but from downstream commands' perspectives, the outcome is that now the file <tt class="docutils literal">index.html</tt> in that directory exists".</li>
</ul>
<p>These are all collected into a <tt class="docutils literal">ParametricCommand</tt>, and the <em>usual</em> case for <tt class="docutils literal">ParametricCommand</tt> is that every combination of parameter values corresponds to a single command.
However, this is not the case for commands that are supposed to aggregate data from several different versions of some other command.</p>
<p>In order to convert the relevant <tt class="docutils literal">Parametric</tt> values in this situation, the values have to undergo a process currently called "reduction".
This selectively overrides the default behavior of combining <tt class="docutils literal">Parametric</tt> values.
Now, some variables, instead of duplicating and altering the command invocations, are <strong>combined</strong> within a single invocation.
The way <strong>combination</strong> is accomplished depends on the type of value.</p>
<p>Thinking about this, we can get the following vocabulary concepts:</p>
<ul class="simple">
<li><strong>reduction</strong> makes it possible for a <tt class="docutils literal">Parametric</tt> to produce values for some <em>subset</em> of its selections, instead of the full set</li>
<li><strong>combination</strong> is the process that allows reduction to occur</li>
<li>some selections must be <strong>singleton</strong> for various reasons, including in order to implement combination by, um, not combining anything</li>
<li><strong>box labels</strong> are all of the labels that must be passed to a <tt class="docutils literal">Parametric</tt> to instantiate its values</li>
<li><strong>selection labels</strong> are a subset of box labels, and something will iterate over them at some point</li>
<li><strong>iterated labels</strong> are a subset of selection labels: these labels contribute a dimension to the final output matrix</li>
</ul>
<p>The overall desired behavior for <tt class="docutils literal">Parametric</tt> labels is found by looking at the ranges of behavior for:</p>
<ul class="simple">
<li>arguments, non-path environment variables, path environment variables, implicit IO</li>
<li>static data, inputs, outputs</li>
<li>multiadic maps, reductions</li>
</ul>
<p>There are two main things here that relatively less obvious:</p>
<ul class="simple">
<li>What controls which labels need to be singleton, and what's the right way to represent this?</li>
<li>What are all of the requirements around implicit IO?</li>
</ul>
<p>The trick to implicit IO is that it doesn't distinguish the command that is actually run, so any selection label used by implicit IO either must be singleton, or must be an iteration label.
Otherwise, the same command will get added to the compendium multiple times with <em>different</em> edge data, which is</p>
<p>bad.</p>
<p>It's like, there's something that will collide with itself unless separated by something else.
I don't think <strong>ghost labels</strong> is a great name for this concept, but it's better than the weird patchwork I have currently.</p>
<p>So, I think the last thing I need to get parity with what the current system models is something that can handle maps over output values.
The thing about output values is that any label that any label that an output value doesn't iterate over can't be a non-singleton iterated label.</p>
<p>I'm not happy with iteration/iterated/whatever yet, but I think this all provides a basis to work with.
I'm going to wrap up for tonight.</p>
<p>Good night.</p>
Diary 2023-03-182023-03-18T04:00:00-04:002023-03-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-18:/diary-2023-03-18<p class="first last"><em>Unfortunately, computers,</em></p>
<p>The current situation with Hunspell is Some Serious Bullshit, so if anyone has an alternative to pitch, please reply to <a class="reference external" href="https://im-in.space/@mwchase/110041239294474217">this post</a>.
Nevertheless, I'm making progress on the draft, so that's good.</p>
<p>I'll be asking friends for feedback over the next few days.</p>
<p>For now, I'm going to take things easy for the rest of tonight.</p>
<p>Good night.</p>
Diary 2023-03-172023-03-17T04:00:00-04:002023-03-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-17:/diary-2023-03-17<p class="first last">A little work, and then some good ideas for later.</p>
<p>Filling in details in the writing...
I did a little work there, but not much.</p>
<p>I guess I'll have to wait until the weekend to try and make a serious effort.
For now, I'd rather try to put all of my conviction that "I should be working on something" into thinking about process improvements or figuring out how to discuss this skeleton of a story with other people.</p>
<p>Okay, I was brushing my teeth and there was one thing I thought of to improve this outline: convert as much of the comments as feasible into [bracketed text] describing what the final version should look like, so the exports have more useful data in them.</p>
<p>I'll start on that tomorrow, because I am tired, and I think I can feel it messing me up right now.</p>
<p>Good night.</p>
Diary 2023-03-162023-03-16T04:00:00-04:002023-03-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-16:/diary-2023-03-16<p class="first last">I did stuff, really quickly, and had basically no time to write about it.</p>
<p>Okay, I've transferred over the important bits from my original "outline", and now I need to work on filling in details or moving forward.
And by "now" I mean "later", because I zoned out for <em>quite some time</em> before getting on this, so I need to wrap this up as soon as possible.</p>
<p>Now.
Now is good.</p>
<p>Good night.</p>
Diary 2023-03-152023-03-15T04:00:00-04:002023-03-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-15:/diary-2023-03-15<p class="first last">Unfortunately, computers, but fortunately the experience of writing is winning out.</p>
<p>The personal writing is going really well, I feel like.
I've been refining (and debugging, sigh) the automation for the personal writing I've been mentioning.</p>
<!-- I want this to be at "glitchy", but it doesn't play nice with dark mode -->
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">"Hunspell is the spell checker of LibreOffice" is definitely a helpful statement that allows you to make sensible predictions about the behavior of the one, given information about the behavior of the other.</p>
</div>
<p>Those bumps in the road aside, I spent a bunch of today retyping and updating my initial draft, and, it's like, I guess I'm always going to be happy working on this, because right now nothing else makes me feel like this.</p>
<p>Here's how things look for what to work on now:</p>
<ul class="simple">
<li>Finish retyping.</li>
<li>Fill in whichever bits I want to fill in next.</li>
<li>Work on the motrfile, then work on other coding projects.</li>
<li>Figure out whether I can roll back some of the compromises I made.</li>
</ul>
<p>Anyway, I should definitely wrap up for tonight.</p>
<p>Good night.</p>
Weekly Roundup 2023-03-142023-03-14T04:00:00-04:002023-03-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-14:/weekly-roundup-2023-03-14<p class="first last">I really really hope this pans out...</p>
<ul class="simple">
<li>Wednesday: I didn't do much.</li>
<li>Thursday: I started considering some somewhat drastic changes to MOTR. Like, adding new capabilities to core, released types.</li>
<li>Friday: I started to realize just how drastic the changes were.</li>
<li>Saturday: I didn't do much.</li>
<li>Sunday: I started drafting a motrfile that should work with several projects. The hope is to take less effort now than it would take to push MOTR over the line; <em>and</em> less effort than it would take to maintain many copies of a task runner configuration file (regardless of task runner), in order to let me work on other projects, and also to evaluate how I should write the bits of MOTR that aren't written yet.</li>
<li>Monday: I made a little progress there...</li>
</ul>
<p>Next week, I'm going to work on some writing (which I worked on automation for today), which will hopefully help me deal better with stage fright, which should eventually get us to a point where I can work on the TWaW reviews.</p>
Coding 2023-03-132023-03-13T04:00:00-04:002023-03-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-13:/coding-2023-03-13<p class="first last">This had better get easier, geez...</p>
<p>Okay, let's see.
I'm working on a motrfile that should work with the projects I want to work on.
It will eventually be available through my Pijul Nest page, but I'm mainly putting it there as a backup, as I don't expect it to be useful to anyone else, unless someone got really excited about MOTR for some reason, and needs a reality check about the current state of the software.</p>
<p>The current state of it is that I'm close to having it ready for running flake8.
Next, I'll look into setting stuff up with mypy, then pytest, profiling, and coverage.
Next up, shiv or some similar packaging.</p>
<p>The big thing to work out is how to hook up stuff like virtualenv and pyproject-build.
This is stuff that I believe should be working in the current development version, but I kind of forget what I did...
And, in any case, I can't <em>use</em> the current development version.
Or, I don't want to, not until I've come to a decision on those changes I was considering.</p>
<p>Anyway, it's getting late and I'm tired; I should get ready for bed.</p>
<p>Good night.</p>
Coding 2023-03-122023-03-12T05:00:00-04:002023-03-12T05:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-12:/coding-2023-03-12<p class="first last">"Short post". Anyway, I'm looking forward to doing some weird stuff with Python without needing to mess with a config file to get nice task runner stuff.</p>
<p>I was pretty much just decompressing all day, but I did get some of the work I was thinking of done.</p>
<p>Basically, I want to investigate using the current release of MOTR with the hobby projects that it's supposed to help with.
This would be a bad idea if I were writing one motrfile per project.</p>
<p>Which is why my plan is to write the motrfile once in a pijul repository, and then merge that repository into other repositories.
The idea is that the functional changes to the code should be entirely orthogonal to the updates I make to the motrfile, so the patches should be completely independent.</p>
<p>Here's how things look for my plans:</p>
<ul class="simple">
<li>Re-implement the MOTR motrfile, but using the lessons I learned writing the higher-level interface, so it's a bit more flexible.</li>
<li>Redo my virtual tabletop project, with a focus first on simpler code, and next on making sure I'm comfortable with what I'm uploading, from a perspective of licensing/fair use.
(Nobody reached out to me about this, and I assume nobody knew.)
(I may look into aggressively factoring out textual content into external data files that aren't part of the repo. This is more than I <em>think</em> I need to do for some, and seems reasonable for others.)</li>
<li>Make sure the file is reusable by trying it out with stuff like my attempt at Cryptopals.</li>
<li>Find other projects to mess with, now that the main obstacle to using MOTR is hopefully dealt with.
(I'm using MOTR instead of Nox because MOTR is, for obvious reasons, better conformed to my mental model for how this stuff "should" work, and also it should be faster.)</li>
</ul>
<p>The basic goal here is to get around feeling like any Python work I do "has to" be for MOTR.
It will make sense to keep working on it, because I want to make it easier to edit the motrfile, but writing it once should be okay, I hope.</p>
<p>Anyway, it's way too late right now.</p>
<p>Good night.</p>
Diary 2023-03-112023-03-11T05:00:00-05:002023-03-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-11:/diary-2023-03-11<p class="first last">Okay, let's try to do... not what I've been doing lately.</p>
<p>Okay, I was messing around and let this get too late, so.
Not much writing or other stuff today, and I'm thinking I shouldn't try to fit anything in after I publish.</p>
<p>I've been kind of tired lately, so I'm going to sleep in tomorrow, but try to get stuff done once I'm up.</p>
<p>Good night.</p>
Coding 2023-03-102023-03-10T05:00:00-05:002023-03-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-10:/coding-2023-03-10<p class="first last">Stuff I missed</p>
<p>Additional notes on the whole "more ways to handle environment variables" thing.</p>
<ul class="simple">
<li>The correct place to do all of the necessary conversions in probably in <tt class="docutils literal">cmd.cmd</tt></li>
<li>The place where I need to check for compatibility with that call is in <tt class="docutils literal">command_builder</tt></li>
</ul>
<p>I think those are the last missing pieces of the puzzle.
Now that I have all of this together, I'm going to take a break and think about whether this is how I want to do things.</p>
<p>I'm pretty sure this all makes sense, but still only pretty sure.</p>
<p>For now, I'm going to wind down.</p>
<p>Good night.</p>
Coding 2023-03-092023-03-09T05:00:00-05:002023-03-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-09:/coding-2023-03-09<p class="first last">It will probably be fine. Probably.</p>
<p>Okay, I'm not going to commit to making these changes, but let's see what I'm thinking about doing in MOTR.
Here's the initial code in the <tt class="docutils literal">command.py</tt> module.
<tt class="docutils literal">EnvVars = pyrsistent.typing.PMap[str, MaybeExecutable[TMaybeExecutable]]</tt>.
This relies on: <tt class="docutils literal">TMaybeExecutable = <span class="pre">typing.TypeVar("TMaybeExecutable",</span> typing.NoReturn, Executable[typing.Any, typing.Any])</tt> and <tt class="docutils literal">MaybeExecutable = typing.Union[_cmd.CmdArg, TMaybeExecutable]</tt>.</p>
<p>What I'm looking into messing with is to allow the map values to potentially contain a sequence of paths, and... hm.
Something looks a bit fishy here.
Okay, that <tt class="docutils literal">CmdArg</tt> is <tt class="docutils literal">_io.MaybeIO[PathStr]</tt>.
So, it should be all right to say "let's add the ability to stick this in a tuple instead, and rewrite the update logic".</p>
<p>And then to actually use this, let's take a look at <tt class="docutils literal">parametric_command.py</tt>
It has an <tt class="docutils literal">EnvVar</tt> class, which currently assumes that the values don't really combine.
I <em>believe</em> to support this idea, I'd need another class that needs the tuple version of the values, or that provides an adaptor from non-tuple to tuple.
Now, that part is seemingly straightforward, but let's see...
So, instead of the <tt class="docutils literal">Artifact</tt> in this new class matching the type in question, the <tt class="docutils literal">Artifact</tt> needs to be the basic version, and the <tt class="docutils literal">build()</tt> method needs to... um...</p>
<p>I regret to inform you that... I am confused.</p>
<p>...</p>
<p>Okay, I <em>think</em> it's enough to just change how single items get processed in the other class, and turn them into singleton tuples.</p>
<p>At this point, I'm <em>pretty sure*</em> that if I go through all of this stuff and carry out the "obvious steps", then this stuff "should work".</p>
<p>But, um, "should work" is a scary phrase.</p>
<p>Anyway, I want to wind down now, maybe do some more writing.</p>
<p>Good night.</p>
Diary 2023-03-082023-03-08T05:00:00-05:002023-03-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-08:/diary-2023-03-08<p class="first last">Just kind of messed around, w/e</p>
<p>Another day where I just kind of took things easy.
I'm going to try to write a bit after I publish this, and I have some questionable ideas about MOTR queued up to investigate later.</p>
<p>I wrote this post earlier and then spaced out, so, um, let's wrap it up.</p>
<p>Good night.</p>
Weekly Roundup 2023-03-072023-03-07T05:00:00-05:002023-03-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-07:/weekly-roundup-2023-03-07<p class="first last">Trying to get a handle on the right way to move forward with stuff.</p>
<ul class="simple">
<li>Wednesday: I messed around a bit with MOTR's design, and I found... either a new requirement, or a valid relaxation of existing requirements.</li>
<li>Thursday: I tried to approach the requirement changes in a principled way, and, eh. We'll see how this goes when I get back into coding.</li>
<li>Friday: I got a few things done, but nothing that would really fill up a post.</li>
<li>Saturday: I tried to take things easy.</li>
<li>Sunday: I started working on trying out GODEATER, and it went well, until it didn't. Entirely a me problem.</li>
<li>Monday: I tried to deal with that problem, and I guess I'm going to have to keep trying.</li>
</ul>
<p>Next week, I'm going to either push through the MOTR work, or try out an idea I've been turning around to try and extract some value from it now without making terribly much work for myself later.
I also want to take down some of my source code repositories and put up slimmed-down versions, but I don't know if I'll actually get to that.
Also also, I'm still doing the experimental writing thing.</p>
Diary 2023-03-062023-03-06T05:00:00-05:002023-03-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-06:/diary-2023-03-06<p class="first last">Shoutout to Mythic V2 for helping me name, like, everything in this story.</p>
<p>I didn't get too far with the plan to address stage fright, but I did lay the groundwork some, and that went well.
I'm using the experimental writing for this, and the experimental stuff still just feels, like, really good.
Would probably really annoy most other people, but I deserve this.</p>
<p>Anyway, I should wrap things up for tonight, or I will <em>extremely</em> regret it.</p>
<p>Good night.</p>
Diary 2023-03-052023-03-05T05:00:00-05:002023-03-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-05:/diary-2023-03-05<p class="first last">Well, that's a pain.</p>
<p>We did some stuff with the core of GODEATER today, and then... I got... stage fright?
Anyway, I'm going to need to work through that if we're going to get anywhere with this project.</p>
<p>I have some plans for dealing with that, and I'll try to put them into action tomorrow.
For now, I'm going to take things easy.</p>
<p>Good night.</p>
Diary 2023-03-042023-03-04T05:00:00-05:002023-03-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-04:/diary-2023-03-04<p class="first last">Something has been telling me I need to take things easy.</p>
<p>Welp.
I didn't get anything else done today.
My plan is to get a bit more done tomorrow.</p>
<p>It's getting late again.</p>
<p>Good night.</p>
Diary 2023-03-032023-03-03T05:00:00-05:002023-03-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-03:/diary-2023-03-03<p class="first last">Researched setting stuff, read programming stuff, installed some software... *shrug*</p>
<p>I did a bunch of research and prep work for various projects and ideas, but nothing that translates into much to talk about <em>right now</em>.</p>
<p>I'm going to wrap up now so it's not suddenly midnight.</p>
<p>Good night.</p>
Coding 2023-03-022023-03-02T05:00:00-05:002023-03-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-02:/coding-2023-03-02<p class="first last">I've been researching space operas and space-opera-adjacent fiction</p>
<p>Taking things slow, thinking about MOTR.
I worked out last night that the conditions under which a label is required to be a singleton are somewhat complicated, so there <em>probably</em> needs to be new fields to track the state.</p>
<p>However.</p>
<p>Rather than just throwing fields at it to try to approximate the correct behavior, let's try laying out the final semantics, starting in very general terms.</p>
<ul class="simple">
<li>The most obvious check to make at runtime is, are all of the necessary labels defined?</li>
<li>The next most obvious check is, which of those labels must be singletons?</li>
</ul>
<p>This second check is trickier.
On the one hand, every label <em>not</em> iterated over by <em>every</em> output must be a singleton, so we effectively have an allow list.
On the other hand, every label that is iterated over by an environment variable must be either iterated over at the top level, or a singleton.
(Inclusive or.)
On the gripping hand, every label that is <em>only</em> iterated over by implicit values must be a singleton.</p>
<p>Currently, I believe this last requirement is satisfied by <em>not allowing those labels to exist</em>.
There are two "big things" that need to be done in this area.
One is to allow all of these scenarios.
The other is to give the metadata the ability to notice "hey, here are these selections being used, but forced to be singletons", and emit some kind of diagnostics.</p>
<p>Anyway, I got distracted and it's late, so I'm done for now.</p>
<p>Good night.</p>
Coding 2023-03-012023-03-01T05:00:00-05:002023-03-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-03-01:/coding-2023-03-01<p class="first last">Rehash, rehash, uh-oh, I found a new requirement.</p>
<p>I'm taking a break from GODEATER prep to reconsider what invariants MOTR's <tt class="docutils literal">Parametric</tt> type will want to track.
Here's the general outline I need to work through:</p>
<ul class="simple">
<li>The <tt class="docutils literal">Parametric</tt> class exists in order to produce <tt class="docutils literal">Command</tt> objects, which produce a set of <tt class="docutils literal">Fact</tt>s relating a <tt class="docutils literal">Command</tt> to other <tt class="docutils literal">Task</tt>s via <tt class="docutils literal">Input</tt>s and <tt class="docutils literal">Output</tt>s.</li>
<li>A <tt class="docutils literal">Command</tt> will have arguments, environment variables, and implicit inputs and outputs (as well as better-behaved values).</li>
<li>There can be any number of arguments.</li>
<li>Each environment variable must have just one value.</li>
<li>Of the <tt class="docutils literal">Command</tt>s produced by a <tt class="docutils literal">Parametric</tt>, no two can produce identical <tt class="docutils literal">Output</tt>s.</li>
<li>Of the <tt class="docutils literal">Command</tt>s produced by a <tt class="docutils literal">Parametric</tt>, no two can differ only in implicit <tt class="docutils literal">Output</tt>s or <tt class="docutils literal">Input</tt>s.</li>
</ul>
<p>So, some components are outputs, and need to ensure that the actual parameterization does not vary over any multi-valued label that the output does not vary over.</p>
<p>Some components are environment variables, and the final output must vary over at least as many labels as the environment variable.</p>
<p>Some components are implicit, and if they vary, the final output must vary over those labels in a non-implicit component.</p>
<p>I believe these cases cover the existing fields.</p>
<p>These are handled with the methods <tt class="docutils literal">as_maximal</tt>, <tt class="docutils literal">as_requiring</tt>, as well as a few others.</p>
<p>So, we need fields like:</p>
<ul class="simple">
<li>"These fields are the only multi-valued labels that the final output can vary over"</li>
<li>"These fields must be iterated over by the final output [if they have multiple values]" oh no I think I just found a new requirement</li>
<li>"This output is of one type, and these fields need to be iterated over by an output of the other type"</li>
</ul>
<p>I'm going to need to ponder how to handle the new requirement I just noticed.
Or, technically, maybe it's a relaxation of a requirement?
A new requirement of what to accept?</p>
<p>Anyway, I'm done for now, but I'm going to note this stuff down so I know I need to tweak stuff.</p>
<p>Anyway, I should wrap up for now.</p>
<p>Good night.</p>
Weekly Roundup 2023-02-282023-02-28T05:00:00-05:002023-02-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-28:/weekly-roundup-2023-02-28<p class="first last">Really nice to put together some concrete artifacts that probably mostly work.</p>
<ul class="simple">
<li>Wednesday: I worked on figuring out what I need to include for a GM emulation reference.</li>
<li>Thursday: I tested out my draft reference, and had some issues with speed. Something to keep in mind for later.</li>
<li>Friday: I figured out most of what I want for reference material, but I had trouble getting it into a small form factor.</li>
<li>Saturday: The printer aggressively did not work, but in a way that isn't immediately obvious, and kept on taunting me with hope.</li>
<li>Sunday: I took a break from this prep work, and did prep work for something else.</li>
<li>Monday: I put together the bulk of the reference material, having solved most of the issues I was grappling with earlier.</li>
</ul>
<p>Next week, I'm going to take notes on GODEATER, and try to get through a session 0 and maybe a session 1.
We'll see.</p>
Diary 2023-02-272023-02-27T05:00:00-05:002023-02-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-27:/diary-2023-02-27<p class="first last">Another day without much time/focus for writing...</p>
<p>I managed to put together much of the reference material I'll need for the first round of reviews, so I'll start taking notes on the actual stuff under review tomorrow.</p>
<p>Beyond that, I don't know, travel and research for other stuff.
I took a lot of time to see if I'd think of something else to put, and I didn't, so I'm not going to try to force it any further.</p>
<p>Good night.</p>
Diary 2023-02-262023-02-26T05:00:00-05:002023-02-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-26:/diary-2023-02-26<p class="first last">A day without much time/focus for writing...</p>
<p>I traveled a bunch today, and didn't start writing this entry until late.
I'd been hoping to mess with some code that I haven't touched in a while, but I guess that's not happening today.</p>
<p>I'm messing around with some other writing that might or might not see the light of day.
It's kind of a mix of very conventional elements with some experimentation that's very important to me, and the whole point is just to see how I come out the other side.</p>
<p>Anyway, I should get ready for bed now.</p>
<p>Good night.</p>
Diary 2023-02-252023-02-25T05:00:00-05:002023-02-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-25:/diary-2023-02-25<p class="first last">I had heretofore avoided printer issues by simply not using the printer.</p>
<p>Printer... bad...</p>
<p>Nevertheless, I've put together a collection of pages to print out.
It's a little... big, but it should get us through next week, when I'll finally start tracking time for this review project.</p>
<p>(Everything before now was what should be one-time prep work, and I didn't want to skew the numbers.)</p>
<p>Anyway, I'm going to try to take things easy for now.
We might get a new printer later, but I'm pondering looking for a thermal printer, in the hopes that it won't jam so much.
(And also I won't raise my anxiety just looking at the cost of ink refills.)</p>
<p>Good night.</p>
Diary 2023-02-242023-02-24T05:00:00-05:002023-02-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-24:/diary-2023-02-24<p class="first last">I tried to make a flowchart, and it turned into a huge mess.</p>
<p>I got distracted all night trying to come up with a concise format for the reference work I've been doing.
I think I've got all of the content drafted, but I'm having trouble condensing it nicely.</p>
<p>Tomorrow, I'm going to print out everything I think I need from the books, and then try harder to condense stuff.</p>
<p>For now, I need to get to bed.</p>
<p>Good night.</p>
Diary 2023-02-232023-02-23T05:00:00-05:002023-02-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-23:/diary-2023-02-23<p class="first last">I should be ready to test this soon, but probably not quite as soon as I'd like...</p>
<p>Okay, so, with just a bit more effort, I should be able to put together my concept for reference material.
The problem is, I just tried to test run a scenario, and the result was pretty unwieldy.
Or, it went fine, although a bit slow, but then I messed with it a bit and lost motivation.
Part of the problem was that I managed to get <em>the same</em> plot point twice, which kind of muddled things for me.
Hopefully that shouldn't be a common thing using this in practice.</p>
<p>In any case, I've got a draft of the new guidelines for integrating the charts.
I'm going to look into two areas later:</p>
<ul class="simple">
<li>Finally setting up the planned flag and highlight layout on the piles of charts I need to print out.</li>
<li>Look into expressing the flows for the guidelines more concisely, and possibly including charts inline somehow.</li>
</ul>
<p>For now, I need to wind down and take things easy.</p>
<p>Good night.</p>
Diary 2023-02-222023-02-22T05:00:00-05:002023-02-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-22:/diary-2023-02-22<p class="first last">Unlike MOTR, I've got reasonable-looking bounds on how much prep work I'm doing to facilitate more interesting stuff.</p>
<p>Well, I'm not buffering stuff yet.
I'm working on the planning for a revision to my reference material for GM emulation.
This is a mix of narrowing down Mythic's share to the new core (which is then expanded), redoing my referencing system for the plotlines table, and updating and rewriting the reference material.</p>
<p>While I'm in here, I want to see if it makes sense to write up flowcharts for any of this, and whether it's possible to condense some of these tables onto one page.</p>
<p>I've just about used up my thoughts for the night, so I guess I should get ready for bed.</p>
<p>Good night.</p>
Weekly Roundup 2023-02-212023-02-21T05:00:00-05:002023-02-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-21:/weekly-roundup-2023-02-21<p class="first last">It's a little annoying taking things this methodically, but hopefully next week, we should just be able to dive in as needed.</p>
<ul class="simple">
<li>Wednesday: I came up with a writing project: reviewing the contents of the Trans Witches are Witches bundle on Itch.</li>
<li>Thursday: I worked on the planning for it, apparently.</li>
<li>Friday: I began taking notes on the contents of the bundle, to set my expectations for, like, some things are really long, and most things aren't.</li>
<li>Saturday: I finished the first round of notes, and tried to work out just how much effort it's going to take to <em>read</em> all this.</li>
<li>Sunday: I went into a bit more detail in the notes, looking more at the rules.</li>
<li>Monday: I got the notes <em>hopefully</em> complete enough to prioritize things.</li>
</ul>
<p>Next week, I'm going to focus on redoing some work I did before, to create reference binders for a GM oracle.
That way, we should be able to play the games that specify a GM.</p>
Diary 2023-02-202023-02-20T05:00:00-05:002023-02-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-20:/diary-2023-02-20<p class="first last">I'm getting a better understanding of most of these games...</p>
<p>So, here's how it went:</p>
<p>I took a few more notes on all of the tabletop games.
Starting tomorrow, we should be good to review the notes and prioritize things.
When that's done, then I can work on buffering stuff up.</p>
<p>I can't think of anything else relevant to today, so I'm just going to wrap things up now because it's late.</p>
<p>Good night.</p>
Diary 2023-02-192023-02-19T05:00:00-05:002023-02-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-19:/diary-2023-02-19<p class="first last">The vibes are pretty important, I guess.</p>
<p>I'm working on categorizing the roleplaying games still.
I'm just kind of classifying some of the rules engagement based on vibes; the main thing missing from this currently is Our Minerva, which I haven't yet had enough focus to properly understand.</p>
<p>The main thing I've determined from the vibes-based classification is that probably none of these have as involved a character creation system as Traveller, which is... probably not surprising?</p>
<p>Tomorrow, I'll try to figure out which multiplayer games to focus on, but I'm going to wrap things up for now.</p>
<p>Good night.</p>
Diary 2023-02-182023-02-18T05:00:00-05:002023-02-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-18:/diary-2023-02-18<p class="first last">Like a thousand pages to read... I'll be fine...</p>
<p>I've sorted the tabletop games by approximate length; comparison between different games is <em>kind of</em> fake, but order of magnitude is <em>probably</em> generally useful for the ones that are more than a few pages.</p>
<p>After that, I tried reading through one of the games that looked like it was in the middle of the pack.
That took about a half hour, so I'll have that as my baseline for now.</p>
<p>One thing that I think helps when I remember to do it is, to set my PDF viewer to 100% instead of fitting width, because having the pages blown up like that makes them intimidating to look at, and hard to read all at once.</p>
<p>The big thing I'm considering now is how we're going to play some of these games.
I'm maybe going to have to just review some of them in the abstract, oh well.
We'll see if I come up with something else when the time comes.</p>
<p>Right now, I want to wrap things up.</p>
<p>Good night.</p>
Diary 2023-02-172023-02-17T05:00:00-05:002023-02-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-17:/diary-2023-02-17<p class="first last">Some kind of power-law distribution here</p>
<p>I'm still taking notes on the different entries in the Trans Witches are Witches bundle.
I think some of these will end up taking much more time than others, just because of the sometimes-extreme differences in length.
Like, if something is over 200 pages long, I expect it'll take a lot more time to review it than something that's 5 pages long.</p>
<p>Also, as I look through these, I have to admit that I'm way more excited about some of these games than others.
This isn't, like a commentary on the quality of anything.
Like, it's good for a bundle like this to have stuff for people with all kinds of different tastes.
It's just, I'll have to see what I think about some of the games that I'm feeling apprehensive or awkward about.</p>
<p>Anyway, yeah, still in planning, so I'm not going to rush ahead yet.</p>
<p>Good night.</p>
Diary 2023-02-162023-02-16T05:00:00-05:002023-02-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-16:/diary-2023-02-16<p class="first last">Seriously, what did I do today?</p>
<p>I did a small amount of planning for the review stuff today, and... I have no memory of what else.</p>
<p>That's a shame, but oh well, at least I got something done.</p>
<p>Good night.</p>
Diary 2023-02-152023-02-15T05:00:00-05:002023-02-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-15:/diary-2023-02-15<p class="first last">It's short, okay?</p>
<p>I came up with something to write about.
Unfortunately, I ended up spending a lot of time today planning it, so this entry is going to have to be pretty rushed.</p>
<p>Here is the general idea:</p>
<p>Right now, the Internet Discourse around Hogwarts Legacy is Extremely Normal.
For my part, rather than spend $60 on a game in a franchise I no longer pay attention to (Johnny Depp was in some of the movies I guess? I don't care?), I put $60 in <a class="reference external" href="https://itch.io/b/1712/trans-witches-are-witches">a related but very different direction</a>.
Nobody wants me to provide a take on Hogwarts Legacy, and I don't want to formulate one, so what if I focused on other games?
After all, I've got... four-ish tabletop supplements, thirty-eight-ish tabletop games, twenty-three-ish video games, a poem, a soundtrack, and a set of tarot cards in there.
I also want to look into a few things not in the bundle that are directly related to it, and a few things not related to the bundle, but I thought of them because of it.</p>
<p>And if this goes well, there are plenty more bundles from the past for me to look through and see what I've got...</p>
<p>So, my plan right now is to pick, say, four things to write drafts on, and see what kind of time frame that gets me.
My goal is to figure out some whole number multiple of a week to put stuff out on.
If this all ends up being a reasonable set of things to do, then I'll be making posts here, probably under a category of, like, "reviews" or something, and putting reviews on the relevant store pages.
I'll be bringing in my wife for additional commentary and for player-two stuff as needed for the tabletop games.</p>
<p>Things are late enough tonight, so I'll wrap up for now, and later I'll finish planning the first round of drafts.</p>
<p>Good night.</p>
Weekly Roundup 2023-02-142023-02-14T05:00:00-05:002023-02-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-14:/weekly-roundup-2023-02-14<p class="first last">Having hurt a bunch of the muscles in my torso, I would recommend <em>not</em> doing that.</p>
<ul class="simple">
<li>Wednesday: I was sick(?) but I was still able to think about MOTR some.</li>
<li>Thursday: Still sick, and I decided to switch gears to interpreter stuff.</li>
<li>Friday: I got a bit further with the interpreter stuff.</li>
<li>Saturday: I relaxed.</li>
<li>Sunday: I came up with some parts of my interpreter code that need to work better.</li>
<li>Monday: Things broke, and it was pretty much my fault, but at least I got some better error reporting out of trying to figure out just what was wrong.</li>
</ul>
<p>Next week, maybe I'll write tests for the interpreter code, or maybe I'll change gears again.
We'll see.</p>
Coding 2023-02-132023-02-13T05:00:00-05:002023-02-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-13:/coding-2023-02-13<p class="first last">It did not Just Work when I tried to use it...</p>
<p>I'm going to need to thoroughly document how my attempt to put together a higher-level system from a box of scraps actually works, because the failures are all pretty inscrutable.</p>
<p>...</p>
<p>Fortunately, I was able to fix it through the simple expedient of <em>reading the dang code</em>, and realizing that my assumptions weren't lining up with how I'd written one module.</p>
<p>So I fixed that, and things started working.
Then I kept on wiring in new modules, and things kept working, and I kind of don't trust it all?
I'm going to have to write a bunch of tests to actually verify all of this behavior, and I don't wanna...</p>
<p>Instead, I wrote more code that I'm going to have to test later.
Oh well.</p>
<p>All right, it's getting late and I want to wrap up.
For now, I'm going to take things easy.</p>
<p>When I come back to this, I should go over all of the modules and make sure I write tests for them.</p>
<p>Good night.</p>
Coding 2023-02-122023-02-12T05:00:00-05:002023-02-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-12:/coding-2023-02-12<p class="first last">This stuff had better Just Work when I try to use it...</p>
<p>It can be a bad sign when, while working on code in one language, you try to replicate the behavior of another language.
Different languages make different tradeoffs, and this (hopefully) guides the design of what is easy to accomplish in that language.
Attempts to import behavior from another context are likely to produce inefficiencies, or even bugs.</p>
<p>So anyway, I've drafted an implementation of Python-tuple-like objects in pure Lua.</p>
<p>...</p>
<p>That's it.
That's the joke.</p>
<p>...</p>
<p>Anyway, sure, maybe all of these attempts at immutability are kind of pointless if I'm not going to be changing stuff, but it does also cache the immutable value, which means that identical calls will produce the same table, so hashing and equality will work the way I want them to.</p>
<p>Here's what I want to do next with this code:</p>
<ul class="simple">
<li>Fix up the "frozen class" draft to use this new "frozen array" code.</li>
<li>Figure out how to integrate this with the "enum class" code.</li>
<li>Roll that out where I'm using enum classes currently.</li>
<li>Also, update some of the enum classes to make proper use of the "class" side of things.</li>
<li>I should really bake some reasonable stringification logic into classes somehow.
Maybe add a helper function to the <tt class="docutils literal">disinherit</tt> module that can be used to produce a <tt class="docutils literal">__tostring</tt> value.</li>
</ul>
<p>Anyway, I'll work on that when I feel like it.
I'm trying to figure out what I'm really motivated to work on right now, and I'm not sure.
I'll think about it some more, I guess.</p>
<p>Good night.</p>
Diary 2023-02-112023-02-11T05:00:00-05:002023-02-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-11:/diary-2023-02-11<p class="first last">I'm not going to wrack my brains this time.</p>
<p>I'm still recovering from whatever has been messing me up all week, so I'm just not going to bother writing anything substantial right now.</p>
<p>This weekend, I should have some time to mess with coding, because hopefully I'll finally be able to focus.</p>
<p>For now, it's time to relax.</p>
<p>Good night.</p>
Coding 2023-02-102023-02-10T05:00:00-05:002023-02-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-10:/coding-2023-02-10<p class="first last">I think I'll be able to make some kind of real progress on this soon...</p>
<p>Well, I didn't come up with the greatest interface for the class-enum thing, but it works for now, and maybe I can tweak it later.</p>
<p>Anyway, let's get into what it was for.
It looks like I'm getting into things near the beginning of the <a class="reference external" href="https://loup-vaillant.fr/tutorials/earley-parsing/recogniser">tutorial</a> I'm looking at.
So, let's see...</p>
<p>Earley grammars can be expressed as a list of rules, which have a left-hand side (a single non-terminal symbol), and a right-hand side (a sequence of terminal and non-terminal symbols).
Later on, it should also have stuff like a constructor for the non-terminal given on the left, but let's stick to the recognizer for now.
(One obvious attempt at optimization would be to store the rules in a table that indexes them by left-hand side.)</p>
<p>Being very careful about reading the example in the tutorial, we see that there's also "groups of (specifically terminal?) symbols".</p>
<p>Anyway, as we move on through the tutorial, we see that there is a concept of "items", which derive from individual rules.
It seems to me most natural to build them up by stages, starting with a rule, and then adding the starting index in the parse, and then the progress through the right-hand side.
This is because the natural derivation of an item over time is to advance the progress through the right-hand side, but this has no effect on the starting position.</p>
<p>Next, we get to state sets, which I <em>believe</em> I wrote the <tt class="docutils literal">otable</tt> module for.
Here it is:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span>
<span class="normal">74</span>
<span class="normal">75</span>
<span class="normal">76</span>
<span class="normal">77</span></pre></div></td><td class="code"><div><pre><span></span><span class="kd">local</span> <span class="n">m</span> <span class="o">=</span> <span class="p">{}</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">non_numeric</span><span class="p">(</span><span class="n">k</span><span class="p">)</span>
<span class="kr">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"number"</span> <span class="kr">then</span>
<span class="nb">error</span> <span class="s2">"Indirect index cannot be numeric"</span>
<span class="kr">end</span>
<span class="kr">return</span> <span class="n">k</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">get_by_index</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">k</span> <span class="o">=</span> <span class="n">non_numeric</span><span class="p">(</span><span class="n">t</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
<span class="kr">return</span> <span class="n">k</span><span class="p">,</span> <span class="n">t</span><span class="p">[</span><span class="n">k</span><span class="p">]</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">get_by_key</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">k</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">v</span> <span class="o">=</span> <span class="n">t</span><span class="p">[</span><span class="n">non_numeric</span><span class="p">(</span><span class="n">k</span><span class="p">)]</span>
<span class="kr">if</span> <span class="n">v</span> <span class="kr">then</span>
<span class="kr">return</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span>
<span class="kr">end</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">o_it</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">control</span><span class="p">)</span>
<span class="n">control</span> <span class="o">=</span> <span class="n">control</span> <span class="o">+</span> <span class="mi">1</span>
<span class="kd">local</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="o">=</span> <span class="n">get_by_index</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">control</span><span class="p">)</span>
<span class="kr">if</span> <span class="n">k</span> <span class="kr">then</span>
<span class="kr">return</span> <span class="n">control</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span>
<span class="kr">end</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">opairs</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
<span class="kr">return</span> <span class="n">o_it</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="mi">0</span>
<span class="kr">end</span>
<span class="n">m</span><span class="p">.</span><span class="n">opairs</span> <span class="o">=</span> <span class="n">opairs</span>
<span class="kr">function</span> <span class="nc">m</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">i_or_k</span><span class="p">)</span>
<span class="kr">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">i_or_k</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"number"</span> <span class="kr">then</span>
<span class="kr">return</span> <span class="n">get_by_index</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">i_or_k</span><span class="p">)</span>
<span class="kr">end</span>
<span class="kr">return</span> <span class="n">get_by_key</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">i_or_k</span><span class="p">)</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">add</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
<span class="kr">if</span> <span class="n">v</span> <span class="o">==</span> <span class="kc">nil</span> <span class="kr">then</span>
<span class="kr">return</span> <span class="n">t</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="n">_</span><span class="p">,</span> <span class="n">v_existing</span> <span class="o">=</span> <span class="n">get_by_key</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">k</span><span class="p">)</span>
<span class="kr">if</span> <span class="n">v_existing</span> <span class="o">==</span> <span class="kc">nil</span> <span class="kr">then</span>
<span class="nb">table.insert</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">k</span><span class="p">)</span>
<span class="n">t</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span>
<span class="kr">elseif</span> <span class="n">v_existing</span> <span class="o">~=</span> <span class="n">v</span> <span class="kr">then</span>
<span class="nb">error</span> <span class="s2">"Cannot change associated value"</span>
<span class="kr">end</span>
<span class="kr">return</span> <span class="n">t</span>
<span class="kr">end</span>
<span class="n">m</span><span class="p">.</span><span class="n">add</span> <span class="o">=</span> <span class="n">add</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">move</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">dest</span><span class="p">)</span>
<span class="n">dest</span> <span class="o">=</span> <span class="n">dest</span> <span class="ow">or</span> <span class="p">{}</span>
<span class="kr">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="kr">in</span> <span class="n">opairs</span><span class="p">(</span><span class="n">src</span><span class="p">)</span> <span class="kr">do</span>
<span class="n">add</span><span class="p">(</span><span class="n">dest</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
<span class="kr">end</span>
<span class="kr">return</span> <span class="n">dest</span>
<span class="kr">end</span>
<span class="n">m</span><span class="p">.</span><span class="n">move</span> <span class="o">=</span> <span class="n">move</span>
<span class="kr">function</span> <span class="nc">m</span><span class="p">.</span><span class="nf">merge</span><span class="p">(...)</span>
<span class="kd">local</span> <span class="n">dest</span> <span class="o">=</span> <span class="p">{}</span>
<span class="kr">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">src</span> <span class="kr">in</span> <span class="nb">ipairs</span> <span class="p">{...}</span> <span class="kr">do</span>
<span class="n">move</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">dest</span><span class="p">)</span>
<span class="kr">end</span>
<span class="kr">return</span> <span class="n">dest</span>
<span class="kr">end</span>
<span class="kr">return</span> <span class="nb">require</span> <span class="s2">"readonly"</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
</pre></div></td></tr></table></div>
<p>One thing I realize as I look over this code is, I'm going to have to make sure that everything handles <tt class="docutils literal">__eq</tt>, or that I pull some shenanigans to make sure that specific functions produce the exact same values every time.</p>
<p>Another possibility is to just ignore that module for now, and accept some probably-quadratic behavior in the prototype: just implement <tt class="docutils literal">__eq</tt>, and make sure to always scan the target table before inserting.</p>
<p>Okay, I had a proper look over the rest of the tutorial, and realized that I can probably adapt the code from the tutorial into the framework I'm putting together.
Here are the big differences:</p>
<ul class="simple">
<li>Instead of text characters for terminal symbols, I'm going to use the existing <tt class="docutils literal">token</tt> class.</li>
<li>I'm going to have to decide how to represent non-terminals, since the actual classes being generated won't correspond neatly to the rules.
Probably just using strings would make sense.
I want to take some time to consider whether there's anything that would strongly recommend an alternative, so I'm going to take some time to think about this.</li>
</ul>
<p>Anyway, that's enough for right now.</p>
<p>Good night.</p>
Coding 2023-02-092023-02-09T05:00:00-05:002023-02-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-09:/coding-2023-02-09<p class="first last">Coding while loopy is not a good idea, but, oh well.</p>
<p>Overall, I'm doing about the same as yesterday I think.
The soreness is kind of moving upwards in my body, and I don't know when it's going to let up.</p>
<p>Anyway, I did manage to remember where I was with regards to the Crafting Interpreters stuff: on a completely different website because I didn't want to do recursive descent stuff.
Here's what I ended up deciding:</p>
<p>Instead of trying to have a stripped-down representation for inputs to some of the functions, I had the functions take a more structured format, and make helpers that produce that more structured format.
The result is apparently sensible.</p>
<p>I'm going to try to put together the combination of <tt class="docutils literal">class{}</tt> and the new <tt class="docutils literal">enum{}</tt>.</p>
<p>I'll mess with that later, but I don't have the focus to describe anything else.</p>
<p>Good night.</p>
Coding 2023-02-082023-02-08T05:00:00-05:002023-02-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-08:/coding-2023-02-08<p class="first last">So hard to think...</p>
<p>I'm feeling</p>
<p>interesting</p>
<p>in the aftermath of last weekend, so I can't really focus on any one thing for too long, but I did want to take some notes on another bit of metadata that... I think MOTR currently has, but the names are <em>so bad</em>.</p>
<p>Anyway, there's selections that must be defined in order to produce output, and there's selections that will contribute dimensions to the output matrix.
The latter is a subset of the former.</p>
<p>I'm not sure if this information is as important to surface to the user (probably there's some reason to want to calculate how many different commands an input will actually create, although you could also just... run the generation code), but accurately tracking it is vital to making the output coherent.</p>
<p>Still missing good names for these, but my hope is to re-evaluate all of the opportunities for tracking relevant information here, since, as the first two labels I described show, I am currently leaving a lot on the table.</p>
<p>Anyway, I'm going to leave that here for now, and try to relax.</p>
<p>Good night.</p>
Weekly Roundup 2023-02-072023-02-07T05:00:00-05:002023-02-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-07:/weekly-roundup-2023-02-07<p class="first last">Good times until they were really bad times.</p>
<ul class="simple">
<li>Wednesday: I reviewed the existing Parametric metadata in MOTR.</li>
<li>Thursday: I tried to figure out how many things were wrong with the existing metadata.</li>
<li>Friday: I found some metadata that <em>should</em> be in there.</li>
<li>Saturday: I took a look at the helper functions and methods that need to account for the metadata.</li>
<li>Sunday: I had a really bad, like, few hours. I've resolved to do some things in response, that I have not done yet, but I'm working on it.</li>
<li>Monday: I was still kind of out of it, so eh.</li>
</ul>
<p>Next week, I'm going to try to work on other coding or writing stuff besides MOTR, and tweak plans and specification for it in the background.</p>
Diary 2023-02-062023-02-06T05:00:00-05:002023-02-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-06:/diary-2023-02-06<p class="first last">So much bad air...</p>
<p>Well, I was traveling today and yesterday, and right now I'm out of it.
So, today, I'm going to try to take things easy, and tomorrow, I'll try to act on those ideas from yesterday.</p>
<p>Right now, I just want to relax.</p>
<p>Good night.</p>
Diary 2023-02-052023-02-05T05:00:00-05:002023-02-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-05:/diary-2023-02-05<p class="first last">We're all being treated like a fucking rounding error.</p>
<p>I ended up feeling really bad today, and I couldn't tell what was going on.
I was guessing all kinds of environmental factors.
Maybe the air was too dry.
Maybe it was some dust that I wasn't used to.</p>
<p>But eventually, I think I figured it out.
I was <em>pissed off</em>.
I was pissed off at the state of pandemic response.
That brand new variants are raging all around me, and by and large the measures being taken are woefully inadequate.
Basic precautions are advised, then ignored.
Massive in-person gatherings.</p>
<p>I am, of course, pissed off at myself for not behaving more sensibly myself, but systemic problems require systemic action.
I can keep myself a little safer by having more common* sense in the future, and not behaving recklessly, but the important thing is what happens to everyone.</p>
<p>Maybe I'll get covid, maybe I won't (yet), but the real fucking tragedy of all of this is what the <em>continued</em> pandemic means for people without a support net like I have, and just in general the fucked up way this has gone on for so long, some of the ghoulish things I'm hearing about being done by people with the power to make a difference.</p>
<p>How is anyone supposed to feel when they realize that they, and everyone around them, basically constitute acceptable losses in the minds of the people in charge?</p>
<p>...</p>
<p>The test came back negative, for what it's worth.
My run of luck apparently remains unbroken.
Good for me.
For now.</p>
<p>We shouldn't be forced to rely on luck like this.
It's just not right.
My heart goes out to the hundreds of millions (hundreds of millions! preposterous!) that we know didn't dodge the bullet, and the families of the millions who didn't make it through.</p>
<p>For the moment, I'll be taking care of myself, because I'm really not prepared to take care of anyone else.
And when I'm feeling better, I've got to make some noise.</p>
<p>(PS I rejiggered my upload script a few times to deal with payload sizes and server-side changes so hopefully this actually uploads properly byyyyee.)</p>
<p>Good night.</p>
Coding 2023-02-042023-02-04T05:00:00-05:002023-02-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-04:/coding-2023-02-04<p class="first last">Pondering more reorganization...</p>
<p>Light day today.
Here's what I did:</p>
<p>I noted down all of the methods and functions in the <tt class="docutils literal">parametric</tt> module that deal with the invariants I'm trying to work out.
One of these, I can probably get rid of, but I'm also trying to work out how to change things up so that other modules stop reaching into the metadata.
That should basically be to add more helper functions, although...</p>
<p>Since these functions specifically require their inputs to have the exact right type, maybe I should switch them to methods?
Something to think about.</p>
<p>Anyway, it's late and I want to take things easy before the weekend, which I expect to also be light.</p>
<p>Good night.</p>
Coding 2023-02-032023-02-03T05:00:00-05:002023-02-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-03:/coding-2023-02-03<p class="first last">"That's too obvious, there's no way it wasn't handled." Friend, I regret to inform you,</p>
<p>I mostly messed with other stuff today, but I'm going to put in a small amount of work on MOTR now:</p>
<p>The parametric metadata should track "the Box must specify a value for these labels".
This should be populated by <tt class="docutils literal">from_box</tt> and <tt class="docutils literal">from_selection</tt>, should be left unchanged by <tt class="docutils literal">flatten</tt>, <tt class="docutils literal">map_over_1_parametric</tt> and <tt class="docutils literal">reduce_parameterization</tt>, unioned by <tt class="docutils literal">map_over_2_parametric</tt> (as well as a planned decorator that will replace the map functions in some contexts), and <tt class="docutils literal">include_box</tt> is... complicated.
<tt class="docutils literal">include_box</tt> should remove any value that <em>is not</em> iterated over.</p>
<p>So we also need to track "this label gets iterated over", which is populated by <tt class="docutils literal">from_selection</tt>, and passed through everything else in the expected fashion.
In <tt class="docutils literal">include_box</tt>, it prevents the removal of the requirement to be explicitly specified.</p>
<p>It's... a little mindblowing that I haven't defined these exact fields before...
Anyway, I've written them down in my notes with the date of this post, so I should be able to get myself up to speed when I want to try to implement these.</p>
<p>Anyway, I'm going to call it here and mess with other stuff before I get ready for bed.</p>
<p>Good night.</p>
Coding 2023-02-022023-02-02T05:00:00-05:002023-02-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-02:/coding-2023-02-02<p class="first last">Now I know what it feels like to write something that explains why something doesn't work, and it's probably opaque to anyone else.</p>
<p>I'm not touching MOTR's code, but I did think some about how I want to reason about the different sets of labels, and I came up with some ideas that I think will be helpful.</p>
<p>Considering a <tt class="docutils literal">Parametric</tt> in isolation, there are four basic possibilities when it comes to extracting a value from it:</p>
<ul class="simple">
<li>The metadata is <strong>overspecified</strong>.
This happens when the metadata requires iteration over a selection that is not allowed to have multiple values, but it does have multiple values.</li>
<li>The metadata is <strong>underspecified</strong>.
This happens when the metadata requires iteration over a selection, but nothing iterates over the selection.</li>
<li>The metadata is <strong>incompatible</strong> with the input Box.
This happens when the metadata requires iteration over a selection, but the selection is not defined by the Box.</li>
<li>The metadata is <strong>compatible</strong> with the input Box.
This happens when the metadata is not underspecified, and the Box contains a superset of the required values, which is no overspecified in conjunction with the metadata.</li>
</ul>
<p>This is helpful to think about, because I'm realizing that some of the information required to track this stuff <em>could</em> be tracked, but isn't.</p>
<p>Also, this is all in terms of selections, but there should be a compatible/incompatible check around non-selection labels.
Furthermore, iterating over a label that is added via <tt class="docutils literal">include_box</tt> should render the parametric <strong>incoherent</strong>.</p>
<p>Fun note to myself because I keep forgetting: <tt class="docutils literal">include_box</tt> prefers the upstream values over the included ones, which means that, actually, it just sort of cancels out and turns into a requirement.
Whether this is "the right choice" is a question that, like, needs more usage data to answer.
It's hard for me to work out from first principles whether I care about the behavior of "two different values get included under the same label in different parts of the Parametric".
One possible mitigation would be to pass the included box <em>up</em> and have a sentinel value for collisions.
I'll keep that in mind as something I <em>can</em> do, but the bigger win right now is in formalizing the relationships between the different outcomes.
(Like, you can use parametric reduction to stop a Parametric from being overspecified.)</p>
<p>The tl;dr of this is that I need to make sure that I'm actually tracking all of the data required to carry out the proper runtime checks; at this point, I highly doubt that that's the case.</p>
<p>For now, I'm going to mess with other stuff, and get generally towards bed.</p>
<p>Good night.</p>
Coding 2023-02-012023-02-01T05:00:00-05:002023-02-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-02-01:/coding-2023-02-01<p class="first last">Again, you will notice that these names only occasionally and glancingly, like, signify properties of the things they're supposed to represent.</p>
<p>Okay, so.
I should have expected that I wouldn't be up for much today, but whatever.
Let's take a look at the code.</p>
<p>I define four sets of labels that control whether a parametric metadata is valid for various purposes.
There is an additional generated set.
To extend the scope of validation I need to:</p>
<ul class="simple">
<li>Verify the intended usage of each set.</li>
<li>Update the names to use a clearer metaphor.</li>
<li>Check on the semantics of the helper functions.</li>
<li>Make any required fixes.</li>
<li>Track additional sets.</li>
<li>Create further invariants.</li>
</ul>
<p>Let's look at the sets:</p>
<ul class="simple">
<li><tt class="docutils literal">provided_labels</tt>: "the Parametric <strong>will</strong> iterate over these labels."</li>
<li><tt class="docutils literal">required_labels</tt>: "the Parametric <strong>needs</strong> these labels to be iterated over."</li>
<li><tt class="docutils literal">handled_labels</tt>: "the Parametric <strong>can</strong> handle these labels being iterated over."</li>
<li><tt class="docutils literal">multivalue_labels</tt>: "the Parametric <strong>cannot</strong> handle labels <em>besides</em> these being iterated over." (Technically, it's fine if the other labels don't contain more than one value. I think. At least, it works like that in the code, probably.)</li>
<li><tt class="docutils literal">expected_labels</tt>: "the minimal set of labels expected in the final product." (the definition is <tt class="docutils literal">provided_labels | required_labels</tt>)</li>
</ul>
<p>"Product" is actually kind of an interesting word there, because the idea is to form a cartesian product over all of the selections.
I don't know if I can work that in.
Although, calling them "factors" might help.
Or it might not.</p>
<p>Anyway, it's getting late, so I'll have to pick this up later.
First, I want to try to explain why there are all of these different sets.</p>
<ul class="simple">
<li>A "provided" label refers to the label's value correlating with an <em>explicit</em> value in the final result.</li>
<li>A label that is only "required" correlates to a value that is <em>implicit</em> in the final result.
This is acceptable in intermediate calculations, but leads to problems if it gets all the way out, because that situation corresponds to <tt class="docutils literal">Cmd</tt> objects that only differ in their implicit IO, which is broken sometimes, and I don't think corresponds to any desirable state, so I try to forbid it.</li>
<li>A "handled" label might not be iterated over by the metadata that contains the set, but if other metadata <em>does</em> iterate over that label, then that situation is handled gracefully.</li>
<li>The set of "multivalue" labels, if present, represents a hard limit on the labels that the metadata will allow iteration over.
This addresses a similar issue to the "implicit" stuff above, in that multiple <tt class="docutils literal">Cmd</tt> objects should not produce the same output artifact.</li>
<li>A label is "expected" if either it is explicitly iterated over, or if something else should iterate over it, even though this metadata doesn't.</li>
</ul>
<p>That's a lot to unpack; I'm looking at this and kind of wondering if sorting this stuff out would be a good use case for formal methods.
For now, I've written these field names down and suggested clunky but descriptive new names; the goal from that is to come up with something better than either, in each case.
And now that I've done that, I'm going to get ready for bed.</p>
<p>Good night.</p>
Weekly Roundup 2023-01-312023-01-31T05:00:00-05:002023-01-31T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-31:/weekly-roundup-2023-01-31<p class="first last">Trying to make the code better, still...</p>
<ul class="simple">
<li>Wednesday: I started changing my mind about how to reorganize <tt class="docutils literal">artifact.Output</tt>.</li>
<li>Thursday: I noticed even more ways I could potentially simplify the code...</li>
<li>Friday: I took a little break to ponder effect systems.</li>
<li>Saturday: I started planning ahead to the next set of changes I want to make, which I want to make because they mean deleting code, which means I wouldn't have to document it.</li>
<li>Sunday: The MOTR update got... a little out of hand.</li>
<li>Monday: I got the MOTR update under control, and then started planning for other things.</li>
</ul>
<p>Next week, I'm going to look over the parametric metadata fields and try to improve them.</p>
Coding 2023-01-302023-01-30T05:00:00-05:002023-01-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-30:/coding-2023-01-30<p class="first last">There is still so much left to fix this up...</p>
<p>I got the <tt class="docutils literal">Output</tt> stuff updated and qualified.
The merge was <em>shockingly</em> uneventful, all things considered.</p>
<p>I could try to work on several different fronts now:</p>
<ul class="simple">
<li>Try to fix the new names I came up with, because there's a bunch of "well I needed to call it <em>something</em>" classes, and they really don't make things clear.</li>
<li>Try to add new wrappers using the current state of things.</li>
<li>Remove the <tt class="docutils literal">MapOverSelection</tt> class.</li>
</ul>
<p>I really want to do that last one, then loop around to the beginning.
It's late now, so I'm going to just quickly lay out some knowledge I'll need later:</p>
<ul class="simple">
<li><tt class="docutils literal">parametric.Metadata</tt> currently does not track <tt class="docutils literal">box.Label</tt> status; I did the hard stuff first with <tt class="docutils literal">selection.Label</tt>.</li>
<li><tt class="docutils literal">box.Label</tt> should be just "here are the labels it needs".</li>
<li>The <tt class="docutils literal">selection.Label</tt> stuff is going to need the names re-evaluated.
Like, "provided", "required", "handled", and "multivalue"?
I could try to defend those names, but I guarantee it wouldn't be persuasive.</li>
<li>Once I re-familiarize myself with the <tt class="docutils literal">selection.Labels</tt> meanings, I should be able to figure out the required relationships between the metadatas in what is currently called <tt class="docutils literal">AdaptiveParametric</tt>.</li>
<li>Also, the different parts of <tt class="docutils literal">parametric_command</tt> should be named to properly correspond to the unique/parametric/artifact distinction.</li>
</ul>
<p>Okay, I did a little thinking, and I really need to figure out how <tt class="docutils literal">selection.Label</tt> stuff should interact with <tt class="docutils literal">include_box</tt>, and I'm still on "yeah, it probably shouldn't allow that".
But I should figure out how to express that in terms of the existing metadata.</p>
<p>One last note: once I have this all converted to use <tt class="docutils literal">Parametric</tt>s, then I should be ready to assess whether to try doing the <tt class="docutils literal">ContextVar</tt> stuff.</p>
<p>For now, though, I should get ready for bed.</p>
<p>Good night.</p>
Coding 2023-01-292023-01-29T05:00:00-05:002023-01-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-29:/coding-2023-01-29<p class="first last">The concept: simplicity itself. The execution: twelve-dimensional summoning runes engraved on the surface of a hypercube. Like, anyone would look at this and go "this code is kind of confusing" and <strong>I KNOW</strong>.</p>
<p>Uuuuuuugh.</p>
<p>I ran into, and continue to run into, issues with updating the artifact module.</p>
<p>I have been bouncing off this all day, and I've made a lot of progress, but getting past this last bit is a pain because it's confusing.
This is exactly why I wanted to do this kind of work before I consider adding more wrappers.</p>
<p>There's a lot that happened, but the short version is that my initial design got sort of fractured into even more classes, and some of my assumptions got challenged, but that part is okay.
What remains to update, as far as getting the code to typecheck, is a worryingly large function that is just two statements.</p>
<p>...</p>
<p>I've got something that looks like it fixes that function, but now I've got other weird stuff to fix.</p>
<p>...</p>
<p>And, it's fixed, thanks to... stuff.</p>
<p>Sometimes I can understand typing stuff, but other times, eh.</p>
<p>Here is the plan for later, definitely not now:</p>
<ul class="simple">
<li>Get flake8 to pass over the code, because I was not bothering to fix style issues.</li>
<li>Get pytest to pass over the code, because it seems extremely likely that I regressed <em>something</em>.</li>
<li>Confirm that the old code paths are dead and I can delete them.</li>
<li>Mer...</li>
</ul>
<p>Mer...</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">merge</p>
</div>
<p>Y-yeah...</p>
<p>I can tell from here that that's going to <em>hurt</em>.</p>
<p>But for now, I'm just going to wind down and get to bed, because I <em>need</em> rest after all of that.</p>
<p>Good night.</p>
<p>PS I had to walk back the glitchiness on the smiley because the glitchy versions don't look as good on my new laptop, and I'm not sure what to do about that.
I guess there's a theme update coming down the pipe.</p>
Coding 2023-01-282023-01-28T05:00:00-05:002023-01-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-28:/coding-2023-01-28<p class="first last">The problem I want to fix with this system is not that other people "aren't smart enough to use it" (and even if I agreed with that statement, it'd still be a me problem), but that it currently "expects" the end user to be able to <em>read my mind</em>.</p>
<p>All right, I'm not touching the code for MOTR, but I want to plan things out for later.</p>
<p>Here are the modules that should guide my changes later:</p>
<ul class="simple">
<li><tt class="docutils literal">artifact</tt></li>
<li><tt class="docutils literal">parametric</tt></li>
<li><tt class="docutils literal">parametric_command</tt></li>
</ul>
<p>The goal is to eliminate the <tt class="docutils literal">map_over_selection</tt> module.
I've got a two-ish part plan to do this.
First, as I've said, I want to rework the <tt class="docutils literal">artifact</tt> module to stop using the <tt class="docutils literal">*Accumulator</tt> classes, by reorganizing the <tt class="docutils literal">Output</tt> class.
The other part is to replace the <tt class="docutils literal">MapOverSelection</tt> class.
The <tt class="docutils literal">MapOverSelection</tt> basically associates a <tt class="docutils literal">Label</tt> with a function that maps that label's associated value to a <tt class="docutils literal">PathStr</tt>.</p>
<p>The thing I realized is that this is basically equivalent to a <tt class="docutils literal">Parametric[PathStr]</tt> with a bunch of restrictions on its metadata.
My goal is to eliminate the usages of this class by figuring out the actual metadata restrictions, and having the code require those restrictions, where applicable.
This will actually make the code more reliable than it is now, because some of those restrictions are currently enforced, at best, by convention, which makes this code even more useless than one might reasonably expect for anyone who isn't me.</p>
<p>Here's some background:</p>
<p>There's sort of a latent mental model I have, of a division of the files that MOTR works with, into two categories: source, and artifacts.
Source files are the background or basis for the operations that MOTR carries out, and are expected to be tracked in a source control system like Mercurial, Pijul, Darcs, Fossil, Bazaar, Perforce, Subversion, etc.
Artifacts are anything that MOTR creates based on its configuration and the source files.
This includes generated constraint files, static analysis, test results, coverage reports, profile data, and, like, anything else that could make sense there.</p>
<p>The <tt class="docutils literal">parametric_command</tt> module divides the paths that are fed into command constructors into three categories:</p>
<ul class="simple">
<li>artifacts</li>
<li>unique source files</li>
<li>groups of related source files</li>
</ul>
<p>The first two groups are in better shape than the third.
The way the third group is represented is a bit wonky, so I'm just going to describe what I think it should be doing:</p>
<p>There is a <tt class="docutils literal">Parametric[T_co]</tt> and one or more <tt class="docutils literal">Parametric[PathStr]</tt>s.
All <tt class="docutils literal">Parametric</tt>s that are any more than mildly complicated have metadata relating to selection labels.
These two groups of <tt class="docutils literal">Parametric</tt>s <em>must</em> have metadata requirements that are, um, complementary?
Basically, the latter group feeds into the pipeline that creates artifacts, so whenever there's a different value from the <tt class="docutils literal">Parametric[T_co]</tt>, the <tt class="docutils literal">Parametric[PathStr]</tt>s should collectively have a different value.</p>
<p>This system kind of breaks down if the functions that make up a <tt class="docutils literal">Parametric</tt> end up mapping two possible <tt class="docutils literal">Selection</tt> values to the same output, and my advice is to simply, not do that.
This, kind of sucks, but I have no idea how to express "this function must be injective" as a Mypy-compatible annotation.
To be fair, I don't think this is a particularly unique shortcoming of Python.</p>
<p>Anyway, it's getting late, and I'm getting tired.</p>
<p>Good night.</p>
Coding 2023-01-272023-01-27T05:00:00-05:002023-01-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-27:/coding-2023-01-27<p class="first last">I'm not saying this code is "the right way" or "a good idea". It's just what I came up with.</p>
<p>In the previous entry, I got diverted into thinking about whether I want to try using <tt class="docutils literal">ContextVar</tt>s in some places that I'm currently basically saying "pass through these parameters everywhere".
The reason I'm pondering this is because I've read Koka's documentation, and I saw some connections between concepts in Python that don't obviously map to "the same underlying thing".
This post could be pretty rough.</p>
<p>Here's the background:
Koka uses effects for a lot of things, and provides various possible behaviors that an effect handler can apply to the effectful code.
Basically, part of an effect in Koka is a set of functions that code that <em>has</em> the effect can call.
The result of calling these functions is determined by the dynamic scope of how the function is called: most effects are not handled by <tt class="docutils literal">main()</tt>, so they have to be handled by other code.
A handler is an expression (I think...) that evaluates to a value of some type.
This is done either by having its associated block execute to completion, or as part of an implementation of a function required for the effect.</p>
<p>The simplest thing to put in a handler implementation is an expression that does not resume the effectful computation.
Let's compare the example from the Koka documentation with the equivalent code in Python:</p>
<div class="highlight"><pre><span></span><span class="k">fun</span><span class="w"> </span><span class="nf">raise</span><span class="o">-</span><span class="n">const</span><span class="p">()</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">int</span>
<span class="w"> </span><span class="k">with</span><span class="w"> </span><span class="na">handler</span>
<span class="w"> </span><span class="na">ctl</span><span class="w"> </span><span class="na">raise(msg)</span><span class="w"> </span><span class="mi">42</span>
<span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">safe</span><span class="o">-</span><span class="n">divide</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">)</span>
</pre></div>
<p>If we ignore the fact that the Koka documentation is defining some effects and functions explicitly for pedagogical purposes, the equivalent in Python is</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">raise_const</span><span class="p">()</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">8</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">/</span> <span class="mi">0</span>
<span class="k">except</span> <span class="ne">ZeroDivisionError</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">42</span>
</pre></div>
<p>There are some syntactic things that stick out, like that Python doesn't have an equivalent to Koka's <tt class="docutils literal">with</tt>, so the indentation is, like, more severe?
(Even ignoring that I 2-spaced Koka.
Count the levels of indentation between the <tt class="docutils literal">def</tt> and the <tt class="docutils literal">+</tt>.)</p>
<p>The next thing the Koka documentation talks about is resuming, and I'm actually not sure what the idiomatic translation of their basic examples is.
The reason I'm not sure actually gets into why I'm interested in working with effect systems.</p>
<p>Here's the Koka code I'm looking at...</p>
<div class="highlight"><pre><span></span><span class="n">effect</span><span class="w"> </span><span class="n">ask</span><span class="o"><</span><span class="n">a</span><span class="o">></span>
<span class="w"> </span><span class="n">ctl</span><span class="w"> </span><span class="n">ask</span><span class="p">()</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">a</span>
<span class="k">fun</span><span class="w"> </span><span class="nf">add</span><span class="o">-</span><span class="n">twice</span><span class="p">()</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">ask<int></span><span class="w"> </span><span class="na">int</span>
<span class="w"> </span><span class="na">ask()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">ask</span><span class="p">()</span>
</pre></div>
<p>If I wanted to surface the resumptive behavior to Python's type system, I think I'd end up with something like...</p>
<div class="highlight"><pre><span></span><span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T"</span><span class="p">)</span>
<span class="n">R</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"R"</span><span class="p">)</span>
<span class="n">Ask</span> <span class="o">=</span> <span class="n">Generator</span><span class="p">[</span><span class="kc">None</span><span class="p">,</span> <span class="n">T</span><span class="p">,</span> <span class="n">R</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">add_twice</span><span class="p">()</span> <span class="o">-></span> <span class="n">Ask</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
<span class="k">return</span> <span class="p">(</span><span class="k">yield</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="k">yield</span><span class="p">)</span>
</pre></div>
<p>But I could also hide this distinction from the runtime (and, as a consequence in this case, the type system) using <tt class="docutils literal">ContextVar</tt>s:</p>
<div class="highlight"><pre><span></span><span class="n">ask</span><span class="p">:</span> <span class="n">ContextVar</span><span class="p">[</span><span class="n">Callable</span><span class="p">[[],</span> <span class="nb">int</span><span class="p">]]</span> <span class="o">=</span> <span class="n">ContextVar</span><span class="p">(</span><span class="s2">"ask"</span><span class="p">)</span> <span class="c1"># need to hardcode result type</span>
<span class="k">def</span> <span class="nf">add_twice</span><span class="p">()</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
<span class="k">return</span> <span class="n">ask</span><span class="o">.</span><span class="n">get</span><span class="p">()()</span> <span class="o">+</span> <span class="n">ask</span><span class="o">.</span><span class="n">get</span><span class="p">()()</span>
</pre></div>
<p>The latter option definitely looks a bit strange to me, but the reason I'm interested in it is because of function color.
I can either give an example that works with these functions, or make them look a little more realistic...</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">add_to_input_gen</span><span class="p">(</span><span class="n">var</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="n">Ask</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
<span class="k">return</span> <span class="n">var</span> <span class="o">+</span> <span class="k">yield</span>
<span class="k">def</span> <span class="nf">add_to_input_ctx</span><span class="p">(</span><span class="n">var</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
<span class="k">return</span> <span class="n">var</span> <span class="o">+</span> <span class="n">ask</span><span class="o">.</span><span class="n">get</span><span class="p">()()</span>
</pre></div>
<p>(I did say <em>a little</em>.)</p>
<p>The point is, these new functions, at least conceptually, can be passed to higher-order functions or nice syntactic constructs.
Let's pretend we have a reason to want to add numbers to a stream of data, but we want to be able to dynamically change the logic that generates the added numbers.
For the latter function we do...</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">add_to_stream_ctx</span><span class="p">(</span><span class="nb">vars</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="nb">int</span><span class="p">])</span> <span class="o">-></span> <span class="n">Iterable</span><span class="p">[</span><span class="nb">int</span><span class="p">]:</span>
<span class="k">return</span> <span class="nb">map</span><span class="p">(</span><span class="n">add_to_input_ctx</span><span class="p">,</span> <span class="nb">vars</span><span class="p">)</span>
</pre></div>
<p>For the former, we, um...
Look, I know I sometimes (very rarely) pretend to not notice something for attempted pedagogical purposes, but I'm really not sure what you'd do.
I want to be missing something, but when I try to sketch something out, it just turns into a mess.</p>
<p>There's a lot more to Koka, but it's a combination of stuff that relatively-straightforwardly follows from all of this, or stuff that I can't imagine working well in Python, like the ability to resume from the same point multiple times.</p>
<p>For completeness, I'll try to translate my "more realistic" code back to Koka:</p>
<div class="highlight"><pre><span></span><span class="k">fun</span><span class="w"> </span><span class="nf">add</span><span class="o">-</span><span class="n">to</span><span class="o">-</span><span class="n">input</span><span class="p">(</span><span class="n">input</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">int</span><span class="p">)</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">ask<int></span><span class="w"> </span><span class="na">int</span>
<span class="w"> </span><span class="na">input</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">ask</span><span class="p">()</span>
</pre></div>
<p>This signature is in some sense even more specialized than the <tt class="docutils literal">Ask[int, int]</tt> stuff, which was, in the end, nothing but standard library types mushed together.
The difference is the higher-order functions in Koka's standard libraries are generic over effects.
This gives you guarantees like "mapping over a total function is total" and its converse, "mapping over a non-total function is non-total".
Or use custom effects like <tt class="docutils literal">ask<a></tt> explicitly.
To do that in Python, you either need a new higher-order library, or you need to make Python "not see them", except to the extent that you need to provide implementations.</p>
<p>(Like, I didn't actually <em>set</em> the <tt class="docutils literal">ContextVar</tt> anywhere, and if you don't set it, then, um, it's going to fall over in a way that I believe is imperceptible to static analysis.)</p>
<p>I'm interested in all of this not because I really want to choose different numbers to add to other numbers under various circumstances (at least, that's not the main thing I want), but because it seems really neat to be able to say "Here is a shiny new concurrency library. It is fully compatible with the higher-order functions in the standard library."</p>
<p>For this post specifically, I just wanted to think about some of the ways that Python surfaces the concept of effects, and how they don't really gel in Python, and I'm not really sure they could be made to gel in Python without a compatibility break that would make the transition from 2 to 3 look like a tea party.</p>
<p>And that's why I want to learn OCaml.
(I haven't tried very hard yet, but I will.)</p>
<p>Good night.</p>
Coding 2023-01-262023-01-26T05:00:00-05:002023-01-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-26:/coding-2023-01-26<p class="first last">Questioning the need for still more of the code. Which is a good impulse, but I have to be careful following it.</p>
<p>All right, let's see where I want to take MOTR's <tt class="docutils literal">artifact</tt> module.
The key thing I realized thinking about the reorganization is that I can corral some functionality into the "constructor" idea I had, so it can be a helper class that, instead of unpacking all of that into an <tt class="docutils literal">Output</tt>, it gets included into the class, and delegated to for the following flow:</p>
<ul class="simple">
<li>Given a sequence of <tt class="docutils literal">MapOverSelection[object]</tt> objects...</li>
<li>Produce a <tt class="docutils literal">Parametric[io.Input[T_co]]</tt> object.</li>
</ul>
<p>So, what do I want to <em>call</em> this?</p>
<p>(Horrible diversion: there are legitimate reasons to try to retire the concept of the <tt class="docutils literal">MapOverSelection</tt> and make this code work directly with <tt class="docutils literal">Parametric[PathStr]</tt> objects, but <em>oh boy</em> I do not have the bandwidth for that currently.)</p>
<p>Actually, can I run with that parenthetical?
It takes several <tt class="docutils literal">Parametric</tt>s and, I want to say, it <em>condenses</em> them into one?</p>
<p>"Condense" is the word that my gut wants me to use, and I need to ponder what sense it has in this context.
I think the reference is to the idea of condensing a piece of writing, and not directly to anything involving physical substances.</p>
<p>I guess what I'm wondering is, can I come up with a nicer name than <tt class="docutils literal">Parametric</tt>?
Aside from the classes that I'm actively attempting to remove in the current effort, <tt class="docutils literal">Parametric</tt> seems like pretty low-hanging fruit.
Its point now is that you give it a <tt class="docutils literal">Box</tt> and it uses metadata to create <tt class="docutils literal">Selection</tt>s from that <tt class="docutils literal">Box</tt>, and passes them in together to a function.</p>
<p>Slightly alarming idea: I've been looking at some of the code I've written, and wondering if using <tt class="docutils literal">ContextVar</tt>s would be a cleaner way to handle shared data/behavior.</p>
<p>A somewhat-related idea that occurs to me is that the implementations for, um, <tt class="docutils literal">Parametric.instantiate</tt>, in some sense, "should" be written with the keys they access in their signatures somehow.
Maybe something really straightforward like <tt class="docutils literal">def instantiate(box_var: Annotated[int, SOME_BOX_INT_LABEL], selection_var: Annotated[str, SOME_SELECTION_STR_LABEL]) <span class="pre">-></span> ResultType:</tt>.</p>
<p>I don't have a sense for whether these are unambiguously good ideas I'm tossing around; they do seem like they would improve some things, but I can't tell if there are any major caveats.</p>
<p>...</p>
<p>I took some time to trace the implications of what I want to change, and they're frankly too complicated.
If I can convince myself that some invariants that the code currently maintains don't actually matter, then I can cut down on the number of classes used.</p>
<p>I think the play to make is, this weekend, put together the required changes to <tt class="docutils literal">artifact</tt>, and try not to worry too hard about the names.
Then, switch to the documentation branch and start documenting the invariants of the <tt class="docutils literal">parametric</tt>, <tt class="docutils literal">parametric_command</tt>, and <tt class="docutils literal">artifact</tt> modules.</p>
<p>My suspicion is that those modules in particular are dragging around some outdated simplifying assumptions.
If I can nail down what those modules need, I can work out the feasibility of cutting down on the number of high-level concepts in the code.</p>
<p>Independently of that, I also want to mess around with context variables a bit, because I think they can substitute for most but not all of the uses of a heavily-forked variant of the <a class="reference external" href="https://punq.readthedocs.io/en/latest/">punq</a> library I'm using in another hobby project.</p>
<p>I think that's all for now.</p>
<p>Good night.</p>
Coding 2023-01-252023-01-25T05:00:00-05:002023-01-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-25:/coding-2023-01-25<p class="first last">I needed to put <em>even more</em> thought in.</p>
<p>Okay, taking another look at how I want to tweak the construction of <tt class="docutils literal">artifact.Output</tt>.
Basically...
There are three things exclusive to <tt class="docutils literal">artifact.Output</tt>:</p>
<ul class="simple">
<li>A seed <tt class="docutils literal">Parametric</tt> that currently has to produce a <tt class="docutils literal">PathStr</tt>.</li>
<li>A <tt class="docutils literal"><span class="pre">Callable[[PathStr,</span> PathStr], PathStr]</tt> to combine other values into it.</li>
<li>A <tt class="docutils literal"><span class="pre">Callable[[PathStr],</span> T_co]</tt>.</li>
</ul>
<p>Currently, the first two get bundled up.
I'm <em>thinking</em> I might want to bundle the third one in with the others.
It's either bundle stuff up <em>more</em>, or <em>less</em>, and I don't know which way is better to go...</p>
<p>I'm going to try to bundle them up, but today, and the next few days, I'm a little booked as far as things to do.
I hope to try this out sooner, but it might end up waiting until the weekend.
We'll see.</p>
<p>I can't delay things any longer.</p>
<p>Good night.</p>
Weekly Roundup 2023-01-242023-01-24T05:00:00-05:002023-01-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-24:/weekly-roundup-2023-01-24<p class="first last">Let's wrap this stage up and see what it takes to cut a release!</p>
<ul class="simple">
<li>Wednesday: I kept on renaming stuff in MOTR.</li>
<li>Thursday: I finished the name updates, and then dealt with the merge.</li>
<li>Friday: I planned some test speedups and coverage improvements.</li>
<li>Saturday: The speedups worked.</li>
<li>Sunday: I sped things up a little more, and dealt with the merges.</li>
<li>Monday: I did some evaluation and planning of how I want to improve <tt class="docutils literal">artifact.Output</tt>, and I've got some interesting ideas, for sure...</li>
</ul>
<p>Next week, I'm going to try to execute on my latest plans for improving MOTR.
After that, I should be good to try implementing more wrappers.</p>
Coding 2023-01-232023-01-23T05:00:00-05:002023-01-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-23:/coding-2023-01-23<p class="first last">Why use two classes, when you can use two classes <em>and</em> a Protocol?</p>
<p>All right, I want to figure out how to redo the <tt class="docutils literal">artifact.Output</tt> class so it's like, less janky, but it's not obvious to me how to get from here to there.
Let's take a look at what it has and what I want.</p>
<div class="highlight"><pre><span></span><span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Output</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T_co</span><span class="p">]):</span>
<span class="n">input_accumulator</span><span class="p">:</span> <span class="s2">"This is basically an initial Parametric[io.Input[PathStr]] plus a fold operation over PathStr. Going forward, I want to break this into two fields."</span>
<span class="nb">map</span><span class="p">:</span> <span class="s2">"A function from PathStr to T_co. I'm going to keep this, and it should be helpful in eliminating some of the weird cruft I ended up adding."</span>
<span class="n">output</span><span class="p">:</span> <span class="s2">"This is misnamed; it is a Parametric[Sequence[str]]. It should probably have a default value that just evaluates to the empty tuple. Its name should include 'name' somehow."</span>
<span class="n">target_label</span><span class="p">:</span> <span class="s2">"I don't know if 'target' is the right word, but the only change to make here is to probably make it optional."</span>
<span class="n">make_parent</span><span class="p">:</span> <span class="s2">"Here's the big change. This is currently an optional data-y value that produces various kinds of outputs. I want to replace it with a data-y type that combines a function from T_co to a Datum subclass with an InputLabel of that subclass, and has a helper function to wire that all up in the only way that really makes sense."</span>
<span class="o">...</span>
<span class="c1"># So, the dream is something like...</span>
<span class="n">TDatum</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"TDatum"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="n">Datum</span><span class="p">)</span>
<span class="c1"># I have no complaints about the new attrs module, but I'd rather wait to</span>
<span class="c1"># switch until after I've stopped maintaining two topics in parallel.</span>
<span class="c1"># Also, maybe I need to make TDatum covariant or something.</span>
<span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">ExtraImplicit</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="n">TDatum</span><span class="p">]):</span> <span class="c1"># Formerly, this would have been "ExtraExtra" 🤢</span>
<span class="n">label</span><span class="p">:</span> <span class="n">InputLabel</span><span class="p">[</span><span class="n">TDatum</span><span class="p">]</span>
<span class="nb">map</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">T</span><span class="p">],</span> <span class="n">TDatum</span><span class="p">]</span>
<span class="c1"># Fairly straightforward helper functions go here-ish.</span>
<span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Output</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T_co</span><span class="p">]):</span>
<span class="n">initial_parametric</span><span class="p">:</span> <span class="n">Parametric</span><span class="p">[</span><span class="n">io</span><span class="o">.</span><span class="n">Input</span><span class="p">[</span><span class="n">PathStr</span><span class="p">]]</span>
<span class="n">pathstr_accumulator</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">PathStr</span><span class="p">,</span> <span class="n">PathStr</span><span class="p">],</span> <span class="n">PathStr</span><span class="p">]</span>
<span class="nb">map</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">PathStr</span><span class="p">],</span> <span class="n">T_co</span><span class="p">]</span>
<span class="n">names</span><span class="p">:</span> <span class="n">Parametric</span><span class="p">[</span><span class="n">Sequence</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span>
<span class="n">input_label</span><span class="p">:</span> <span class="n">InputLabel</span><span class="p">[</span><span class="n">T_co</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span>
<span class="n">extra_implicit</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="n">ExtraImplicit</span><span class="p">[</span><span class="n">T_co</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span> <span class="o">...</span><span class="p">]</span>
</pre></div>
<p>My main concern, looking at all of that stuff, is how to put together a sensible constructor interface.
Part of me wants to just slap a basic fluent interface over top of it all and call it a day, but that doesn't feel good to the rest of me.
Perhaps if I consider what the other majorly reworked class would look like...</p>
<div class="highlight"><pre><span></span><span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">OutputFromInput</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T_co</span><span class="p">]):</span>
<span class="nb">input</span><span class="p">:</span> <span class="n">Input</span><span class="p">[</span><span class="n">T_co</span><span class="p">]</span>
<span class="n">names</span><span class="p">:</span> <span class="n">Parametric</span><span class="p">[</span><span class="n">Sequence</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span>
<span class="n">input_label</span><span class="p">:</span> <span class="n">InputLabel</span><span class="p">[</span><span class="n">T_co</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span>
<span class="n">extra_implicit</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="n">ExtraImplicit</span><span class="p">[</span><span class="n">T_co</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span> <span class="o">...</span><span class="p">]</span>
</pre></div>
<p>This implies that, from a code organization perspective, we need a class representing "how a <tt class="docutils literal">Parametric[io.Input[T_co]]</tt> gets converted to a <tt class="docutils literal">Parametric[io.Output[T_co]]</tt>, and, with the help of a callback, then to a <tt class="docutils literal">Parametric[command.Metadata[installer.TArgs]]</tt>, although, I've just realized...</p>
<p>I need an additional option on this thing for handling the "make parent" case, because that's an implicit <em>input</em> rather than an implicit <em>output</em>.
So, the helper class is something like...</p>
<div class="highlight"><pre><span></span><span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">OutputConverter</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span>
<span class="n">names</span><span class="p">:</span> <span class="n">Parametric</span><span class="p">[</span><span class="n">Sequence</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span>
<span class="n">input_label</span><span class="p">:</span> <span class="n">InputLabel</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span>
<span class="n">make_parent</span><span class="p">:</span> <span class="n">ParentMaker</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span>
<span class="n">extra_implicit</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="n">ExtraImplicit</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span> <span class="o">...</span><span class="p">]</span>
<span class="n">ParentMaker</span> <span class="o">=</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">T</span><span class="p">],</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">]</span>
</pre></div>
<p>Or something.
I don't know if there's an idiomatic way to have "a boolean variable that can only take a <tt class="docutils literal">True</tt> value if a type parameter has a specific value"...
Like, this is seeming like a <em>really tempting</em> case for subclassing, even by my standards.
I suppose the alternative would be to define a protocol based on its inputs and outputs, and write a wrapper class around the basic converter, then add a fluent method that requires <tt class="docutils literal">T</tt> to be <tt class="docutils literal">pathlib.Path</tt>, and then... yeah, at that point, it should Just Work.</p>
<p>I'm not getting this done tonight, but I'm glad I've got a pretty solid plan now.</p>
<p>Good night.</p>
Coding 2023-01-222023-01-22T05:00:00-05:002023-01-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-22:/coding-2023-01-22<p class="first last">I think I may have regressed coverage on the future topic, but, um, that's a Future Max problem.</p>
<p>I squeezed out the last two seconds of speedup left on the table, and grabbed about four more.
After that, there's about 4 that I can get later, but I can't get now.
The merges required are getting a little frustrating, but it's probably fine.
I also put up the coverage a little.
Currently hovering at or above 97.5%.</p>
<p>I'm guessing that both of the things I want to work on next will do something horrifying in terms of merge conflicts, so I'll just try to focus on what should be the smaller one.</p>
<p>That's going to be basically taking apart the <tt class="docutils literal">artifact</tt> classes and putting them back together in a way that makes more sense.</p>
<p>For now, I'm going to wrap things up.</p>
<p>Good night.</p>
Coding 2023-01-212023-01-21T05:00:00-05:002023-01-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-21:/coding-2023-01-21<p class="first last">Some of the weird stuff I ran into would have made a good post. Too bad I'm super tired.</p>
<p>I ended up "only" speeding things up by ten or so seconds, but that's not nothing.
I think there's about four seconds I can save easily, and four more that I can take care of down the line.</p>
<p>As far as what to do next, wiping out the coverage misses that just got opened up is a solid choice, but I also want to look into the <tt class="docutils literal">artifact.Output</tt> rework.</p>
<p>Anyway, for now, I want to zone out for a while, then go to bed.</p>
<p>Good night.</p>
Coding 2023-01-202023-01-20T05:00:00-05:002023-01-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-20:/coding-2023-01-20<p class="first last">Talking about these test rewrites like I'm a speedrunner. "Yeah, I've got a potential 12-second time save on my hands here"</p>
<p>I forget how or whether I prioritized things for MOTR recently.
Now that I've got a round of renames done, I was like "what do I feel like working on?" and the answer was apparently "remove the usages of <a class="reference external" href="https://pyrsistent.readthedocs.io/">pyrsistent</a> that aren't <tt class="docutils literal">PMap</tt>s".
Which, I wanted to do that at some point.
It might have been prudent to do it on the "future" side, since the merges were all gross, but, eh...
Offhand, I can remember a few other things to look into:</p>
<ul class="simple">
<li>Reduce the dependence of tests on subprocesses.</li>
<li>Rework the <tt class="docutils literal">artifact.Output</tt> layout and creation workflow.</li>
<li>Work on splitting up the API into logical layers.</li>
</ul>
<p>Looking over these, the first is good to do when I feel like it, since it <em>shouldn't</em> involve a bunch of soul-searching or wide-ranging changes, and getting it done should shave a few seconds off of the run time of the tests, which is several percent improvement.</p>
<p>The other options both take some careful planning, and I wouldn't be surprised if they caused interesting things to happen in terms of merges.</p>
<p>...</p>
<p>Wait a sec, I was going by memory for the expected speedup, and it's more like, if I can get just one test to run at a similar speed to nearly every other test, the tests will be nearly three times faster?!?!
However, it's right in the middle of "future" changes.
At the same time, getting the logic relevant to this test mocked would make it easier to increase coverage, so I think implementing the mocking twice, more or less, would be less painful than trying to legitimately force a failure state to trigger the unused branches.</p>
<p>All right, this is clearly the play.
It speeds up iteration, and gets me closer to full coverage.
Then I can work on these other changes.
Probably planning out the different layers as I feel like it, but focusing on the <tt class="docutils literal">artifact</tt> rework.</p>
<p>Anyway, I should get ready for bed.</p>
<p>Good night.</p>
Coding 2023-01-192023-01-19T05:00:00-05:002023-01-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-19:/coding-2023-01-19<p class="first last">I should maybe have expected some trouble from making all of these changes on adjacent lines in different topics.</p>
<p>I had a rough day at work today, but now I'm</p>
<p><em>FINE</em></p>
<p>Because I got the name updates finished in MOTR, and then I merged them, and then I fixed the merge conflicts, and then I updated all of the things that the merge didn't update, and when I'm feeling a little less tired and twitchy I can start working on more significant updates.</p>
<p>Right now, though, I desperately need to wind down.</p>
<p>Good night.</p>
Coding 2023-01-182023-01-18T05:00:00-05:002023-01-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-18:/coding-2023-01-18<p class="first last">Polishing...</p>
<p>I have been <em>so</em> in the zone propagating renames through MOTR's code base.
I'm stopping and writing this post, not because I got to any kind of natural stopping point (I absolutely did not), but because I don't have it in me to update any more code tonight.</p>
<p>I ended up stumbling across some really nice improvements to make while I was working through these files, and I have a few ideas for further tweaks to try out later.</p>
<p>For now, I need to take a few more days to get these renames done, then to run flake8 on the result, then to test the results.
Then merge.
And probably do this all a few more times.</p>
<p>Progress...
Yay...</p>
<p>Anyway, it's late.</p>
<p>Good night.</p>
Weekly Roundup 2023-01-172023-01-17T05:00:00-05:002023-01-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-17:/weekly-roundup-2023-01-17<p class="first last">I had a bunch of trouble focusing on my projects, but when I got started, hoo boy.</p>
<ul class="simple">
<li>Wednesday: I was focused on the CtC hunt.</li>
<li>Thursday: I finished the hunt.</li>
<li>Friday: I started thinking about MOTR again, and getting bits of the code to make more sense.</li>
<li>Saturday: I didn't get much done.</li>
<li>Sunday: My face hurt.</li>
<li>Monday: I started making changes to MOTR.</li>
</ul>
<p>Next week, I'm going to try to get MOTR to a state where it can pass its tests again, then merge to the future (which will suck), then make a few more changes, then see if I feel ready to write more support code.</p>
Coding 2023-01-162023-01-16T05:00:00-05:002023-01-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-16:/coding-2023-01-16<p class="first last">Once again, not on top of time management</p>
<p>All right, I didn't really focus on much today, but I did work out something to get more work done <em>later</em>.
I did the beginning of a bunch of naming updates.</p>
<p>So, now the new code is pretty thoroughly broken (though I plan to break it more), and I can easily call up a list of everything that needs to be updated.</p>
<p>So, with these changes, it's simple: fix type issues until it thinks things work again.</p>
<p>I can't think of anything else, so I'm going to make a few more name changes, to queue up the checklist for later.</p>
<p>For now, I need to get to bed.</p>
<p>Good night.</p>
Diary 2023-01-152023-01-15T05:00:00-05:002023-01-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-15:/diary-2023-01-15<p class="first last">Ow, my face.</p>
<p>Oh man, I feel so bad right now.
Like, my sinuses are doing something that they definitely shouldn't.</p>
<p>I don't feel up for anything too intense, but I did take a few notes for the Other Project.
And I can probably handle taking paper notes on MOTR changes, now that I've managed to grasp how the scope should be narrowed.</p>
<p>But other than that, I need to make a sincere effort to do better at winding down.</p>
<p>Good night.</p>
Diary 2023-01-142023-01-14T05:00:00-05:002023-01-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-14:/diary-2023-01-14<p class="first last">Hellraiser: Revelations all like, "What if there was a movie that made you think about the first Hellraiser, but it like, wasn't very good?"</p>
<p>Took another light day.</p>
<p>Over the weekend, I'll hopefully have a chance to lay out all of my thoughts for MOTR and get them to make sense, but right now, I should wind down.</p>
<p>I did at least put together some stuff for the Other Project.
At some point, I should figure out if the Other Project needs, like, legal advice.
But that's not right now.</p>
<p>Good night.</p>
Coding 2023-01-132023-01-13T05:00:00-05:002023-01-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-13:/coding-2023-01-13<p class="first last">Fortunately, I can scale back some of my ambitions.</p>
<p>Instead of touching any code today, I'm going to try to fully lay out my thoughts on the general area I was talking about last time.</p>
<p>For context, I'm trying to rework the structure of the class that will be call <tt class="docutils literal">artifact.Output</tt> once I've renamed everything.
The various classes in the <tt class="docutils literal">artifact</tt> module are (okay, fine, <em>will be</em>) implementations of the <tt class="docutils literal">Artifact</tt> protocol, which defines a method that takes a callback which converts some value to a <tt class="docutils literal">Parametric[command.Metadata]</tt> (or something along those lines.
<tt class="docutils literal">artifact.Output</tt> currently has provisions to inject other values in specific circumstances, which end up making it hard for me to determine which intermediate values are "supposed to" be used at various stages.</p>
<p>Now, I was thinking of putting together something <em>really elaborate</em> to replace this system, but I think the specific <em>really elaborate</em> thing I had in mind had its own problems.
So, let's take it slow...</p>
<ul class="simple">
<li>The current system is required to work with pathlike objects for the "accumulation" phase that happens before anything else.
It also has an optional "mapping" step that's required to stay pathlike, and could in theory be removed, so eh.</li>
<li>Once the final pathlike is produced from the accumulation, an additional mapping step is carried out, and the relevant "PCM" object is constructed using the callback.</li>
<li>The instance may contain information relevant to adding information about the parent path of the "final" pathlike to the "PCM", and if so, that pathlike is passed in.
The mapped value cannot be used, because its type is not statically known.</li>
<li>This could all be drastically simplified and address some of the problems, except for the case currently referred to as <tt class="docutils literal">Extra</tt> (which will be <tt class="docutils literal">Implicit</tt>).
The callback passed in that case accepts a type that <em>partially</em> overlaps with MOTR's definition of pathlike, and we <em>really want</em> to be able to use the types outside of that overlap.
While the type in question sometimes does contain path information, at least sort of, it's not guaranteed.</li>
</ul>
<p>So, going from there...
I don't think there's a sensible definition of "parent" for these "<tt class="docutils literal">Token</tt>" objects, but unless I can formalize the types in question, I need the code to do <em>something</em> when this overlap happens, and I'd rather not stick <tt class="docutils literal">isinstance</tt> checks in there.</p>
<p>So, I want to change this code both from a usage perspective, and from an implementation perspective.
From a usage perspective, I want the "final" accumulated value to be what is passed to the command if possible (so, ideally not <tt class="docutils literal">Extra</tt>/<tt class="docutils literal">Implicit</tt>), and I want the other values to be <tt class="docutils literal">Extra</tt>/<tt class="docutils literal">Implicit</tt>.</p>
<p>This actually really helps, because it gets me that these extra values are only expected when the produced value is known to be pathlike.
So, if there are update methods that restrict their validity based on the type parameter, then <em>those</em> methods are allowed to use the fact that the data is pathlike.
I don't know if I should exercise that option, but it's there.</p>
<p>Anyway, a few other notes:</p>
<ul class="simple">
<li>Only the "explicit" value needs to be named, because the names will always sort of refer to the same things.</li>
<li>However, it would be good to allow <em>any</em> output to have its own <em>label</em>.</li>
</ul>
<p>These involve maps like <tt class="docutils literal">PathLike <span class="pre">-></span> T_co</tt> and <tt class="docutils literal">T_co <span class="pre">-></span> Datum</tt>, but the latter is only expected with <tt class="docutils literal">T_co == PathLike</tt>.</p>
<p>Something else I need to keep in mind is that I believe I want to add these capabilities to the <tt class="docutils literal">OutputFromInput</tt> class, which... hm...
Basically, all of this logic "should" be neatly encapsulated somewhere, and the question of how to do that feels like maybe it should wait for after I've done the previous rounds of rewrites.</p>
<p>So, the plan for the coming days: take my existing plans, convert them into TODO comments in the code, then grind through them and take notes on what to do differently.</p>
<p>For now, though, I really need to sleep.</p>
<p>Good night.</p>
Diary 2023-01-122023-01-12T05:00:00-05:002023-01-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-12:/diary-2023-01-12<p class="first last">Hunt over.</p>
<p>Hunt is <em>done</em>.
I kind of want to jump right back into other stuff <em>right now</em>, but that would be a bad idea.</p>
<p>Aside from the hunt, I did take some notes on the other project, and now I'm ready to start planning how I'm going to actually produce stuff for it.
I'm thinking I'll try to figure out what kind of techniques I want to work with, and use them with other topics.
We'll see.</p>
<p>Anyway, I should wrap up for tonight.</p>
<p>Good night.</p>
Diary 2023-01-112023-01-11T05:00:00-05:002023-01-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-11:/diary-2023-01-11<p class="first last">Still staring at Sudoku puzzles until they suddenly solve themselves.</p>
<p>All right.
I was still focused on the CtC hunt, so no hobby coding stuff.
I'm closing in on the end of it, but there's still one and a bit puzzles to go.</p>
<p>I'm also gradually assembling resources for The Other Project, which I will properly announce at some point.
I just don't feel comfortable saying "Here is my idea for a thing I'm doing. If that sounds interesting... too bad, lol, check back in like a year."
So just, trust me that I'm trying to put something out, and I won't make people wait for anything <em>specific</em> until after I've put part of it out.</p>
<p>In any case, it's too late currently, and I'm not going to get anything else written tonight, so this is done.</p>
<p>Good night.</p>
Weekly Roundup 2023-01-102023-01-10T05:00:00-05:002023-01-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-10:/weekly-roundup-2023-01-10<p class="first last">Somewhat light week, and now I'm out of it.</p>
<ul class="simple">
<li>Wednesday: I came up with a possible reason that I'm having trouble with one of the classes in MOTR.</li>
<li>Thursday: I mostly focused on the Cracking the Cryptic puzzle hunt.</li>
<li>Friday: I looked a bit more at MOTR, and tried to figure out how to make some of the code make fewer assumptions, in order to be clearer.</li>
<li>Saturday: I tried to work on another project...</li>
<li>Sunday: I dunno.</li>
<li>Monday: I roughed out some possible ways to rework the <tt class="docutils literal">artifact</tt> implementation.</li>
</ul>
<p>Next week, I'm going to try to flesh out the other project, and take notes on changes to MOTR.</p>
Coding 2023-01-092023-01-09T05:00:00-05:002023-01-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-09:/coding-2023-01-09<p class="first last">I need to work through the use cases here, or I might accidentally come up with something really complicated.</p>
<p>All right.
I got some work done on one project today, let's sketch stuff out for MOTR.</p>
<p>My idea for generalizing <tt class="docutils literal">artifact.Output</tt> is to have a helper class that looks something like</p>
<div class="highlight"><pre><span></span><span class="nd">@attrs</span><span class="o">.</span><span class="n">frozen</span>
<span class="k">class</span> <span class="nc">Converter</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span>
<span class="n">label</span><span class="p">:</span> <span class="n">Label</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span>
<span class="n">names</span><span class="p">:</span> <span class="n">Parametric</span><span class="p">[</span><span class="n">Sequence</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="n">attrs</span><span class="o">.</span><span class="n">field</span><span class="p">(</span>
<span class="n">default</span><span class="o">=</span><span class="n">no_parameters</span><span class="p">(()),</span>
<span class="n">validator</span><span class="o">=</span><span class="n">RejectBecause</span><span class="p">(</span><span class="n">parametric_not_flex_out</span><span class="p">),</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">convert</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">parametric</span><span class="p">:</span> <span class="n">Parametric</span><span class="p">[</span><span class="n">Input</span><span class="p">[</span><span class="n">T</span><span class="p">]])</span> <span class="o">-></span> <span class="n">PCM</span><span class="p">[</span><span class="o">...</span><span class="p">]:</span>
<span class="c1"># Things get a little problematic here.</span>
<span class="c1"># This needs some way to either use a provided converter callable</span>
<span class="c1"># OR to use the Implicit converter.</span>
<span class="c1"># I think the steps there are to move the "logic" of Implicit to</span>
<span class="c1"># the top level, and write overrides for this method.</span>
<span class="c1"># Anyway, once that's done, porting over the main logic from</span>
<span class="c1"># artifact.Output is a cinch.</span>
<span class="c1"># One thing that I realize I should do first is, check how aligned</span>
<span class="c1"># the different implementations of the Artifact protocol end up</span>
<span class="c1"># looking.</span>
<span class="c1"># I may want to look into reducing the degree of runtime</span>
<span class="c1"># polymorphism somehow, although there are some hurdles there.</span>
<span class="c1"># Like the fact that there are three separate implementations on</span>
<span class="c1"># both sides of the interface boundary.</span>
<span class="c1"># Anyway...</span>
<span class="nd">@attrs</span><span class="o">.</span><span class="n">frozen</span>
<span class="k">class</span> <span class="nc">AdditionalOutput</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T_contra</span><span class="p">,</span> <span class="n">T_co</span><span class="p">]):</span>
<span class="nb">map</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">T_contra</span><span class="p">],</span> <span class="n">T_co</span><span class="p">]</span>
<span class="n">converter</span><span class="p">:</span> <span class="n">Converter</span><span class="p">[</span><span class="n">T_co</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">convert</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">parametric</span><span class="p">:</span> <span class="n">Parametric</span><span class="p">[</span><span class="n">Input</span><span class="p">[</span><span class="n">T_contra</span><span class="p">]]</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">PCM</span><span class="p">[</span><span class="o">...</span><span class="p">]:</span>
<span class="c1"># Map types over the parametric, then pass it to the converter.</span>
<span class="c1"># This raises the question of whether the artifact.Output should derive</span>
<span class="c1"># all of its outputs from the basal combined value, or if it should</span>
<span class="c1"># apply a map to that value, and then additional maps on top of the</span>
<span class="c1"># first.</span>
<span class="c1"># I'm thinking about this, and not coming up with anything compelling,</span>
<span class="c1"># so I think the tiebreaker is ease of implementation, which would mean</span>
<span class="c1"># merging those classes into one and constraining T_contra when using</span>
<span class="c1"># them with artifact.Output</span>
<span class="c1"># ...</span>
<span class="c1"># One possibility is to allow nesting AdditionalOutputs inside each</span>
<span class="c1"># other.</span>
<span class="c1"># This would allow quite a bit of flexibility, while also simplifying</span>
<span class="c1"># the implementation of Output...</span>
</pre></div>
<p>I think I should keep on thinking about this.
Before I make any changes one way or the other, I should switch topics to the coverage topic, and work on marking up all of the code that I decided to change.</p>
<p>This entry is finished a bit earlier than most of the recent ones, so let's just call it there and let me wind down properly for a change.</p>
<p>Good night.</p>
Diary 2023-01-082023-01-08T05:00:00-05:002023-01-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-08:/diary-2023-01-08<p class="first last">Just kind of spaced out all day, apparently?</p>
<p>Not a great day for accomplishing stuff.
I'm going to have to really try to work on my various projects tomorrow.</p>
<p>As for right now, I'm going to get to bed, and maybe take some notes on projects while I'm over there.</p>
<p>Good night.</p>
Diary 2023-01-072023-01-07T05:00:00-05:002023-01-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-07:/diary-2023-01-07<p class="first last">Secrets</p>
<p>Okay, let's see what I did...</p>
<p>I'm letting some ideas for MOTR kind of percolate.
I'm also trying to get started on another project, and it's just...
Ugh, the writer's block is so intense.</p>
<p>I'm going to have to figure out a way around it, but not right now.
Like, tomorrow.
I need to wind down for now.</p>
<p>Good night.</p>
Coding 2023-01-062023-01-06T05:00:00-05:002023-01-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-06:/coding-2023-01-06<p class="first last">Gradually discovering the form that the code "should have" been in.</p>
<p>My planned changes to MOTR's top layer are getting a bit more ambitious.
Basically, I want to abstract out the logic of "what actual operations get performed on <tt class="docutils literal">artifact.Output</tt>'s data".</p>
<p>The basic idea is to make the core logic kind of transducer-y, and have supplementary classes that can add additional behavior for specific output types.
This is much cleaner in my head than the current system, which kind of mingles different stages of computation, and gets it all to "work" because the types are constrained.
If I can pull out the type-specific stuff and make the remainder generic, then I should be able to ignore "what specific stuff the code does in the main methods", because the methods themselves can't act on that information; they can only pass stuff to helper objects with a matching parametric type.</p>
<p>I'm going to need more time to work through these ideas, but I think this is all going in the right direction.
I need to get to bed for now, though.</p>
<p>Good night.</p>
Diary 2023-01-052023-01-05T05:00:00-05:002023-01-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-05:/diary-2023-01-05<p class="first last">Another day that was more-or-less productive, but not in the areas I blog about.</p>
<p>I was distracted working through the Cracking the Cryptic hunt.
That's one puzzle past the intro, and it was, um, tougher.
And the one after that... I don't even know.
We'll see.</p>
<p>Anyway, nothing more to talk about tonight.
I'll get back to work on MOTR when I feel like it.</p>
<p>Good night.</p>
Coding 2023-01-042023-01-04T05:00:00-05:002023-01-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-04:/coding-2023-01-04<p class="first last">"This class has a bad name. If I can get rid of the class, I won't have to think of a better one."</p>
<p>I have a hypothesis about why <tt class="docutils literal">InputAccumulator</tt> is troublesome to rename.
Let's see if it makes sense in text as well as in my head.</p>
<p>The problem is that it's basically a reified right fold (hey, spell check is back! Too bad it doesn't know that "reified" is a word.)
Anyway, that's not the whole story, but I don't think the bits I'm leaving out matter, except insofar as they make everything more awkward.</p>
<p>The point is, let's have a look at how a right fold is typed in, say, Haskell.
<tt class="docutils literal">(a <span class="pre">-></span> b <span class="pre">-></span> b) <span class="pre">-></span> b <span class="pre">-></span> [a] <span class="pre">-></span> b</tt>
The <tt class="docutils literal">InputAccumulator</tt> is like this, except the types are specialized and I pretended that I can have existential types.
The "list" basically doesn't exist in any explicit sense, and only implicitly exists in terms of the object that gets built up.
So, it's like, let's pass the function and the initial value to <tt class="docutils literal">foldr</tt>, but it's not really <tt class="docutils literal">foldr</tt>.
It's like...
<tt class="docutils literal">(a <span class="pre">-></span> b <span class="pre">-></span> b) <span class="pre">-></span> b <span class="pre">-></span> wait actually I don't know if it's possible to express this in Haskell's type system, and I'm fairly sure most people wouldn't want to</tt>
I guess the closest equivalent would be
<tt class="docutils literal">((a <span class="pre">-></span> b <span class="pre">-></span> b), b) <span class="pre">-></span> a <span class="pre">-></span> ((a <span class="pre">-></span> b <span class="pre">-></span> b), b)</tt> or something, subject to additional constraints that I believe the types involved are expressive enough to <em>not</em> give us for free...
I'm not saying that the fact that this concept is awkward in Haskell <em>necessarily</em> means I shouldn't do it in <em>Python</em> the way I'm doing it, but given the way that my hobby Python sometimes ends up looking, it does legitimately raise the question.
Because the actual fold stuff is only done in one place in the code, it's not a great burden to rewrite it.
(Except that I would also need to surface the possibility of mapping over the final value, which is a thing that I do sometimes because of reasons, but surely there's a more sensible way to do that, as well...)</p>
<p>What this would basically entail would be pulling implementation details of <tt class="docutils literal">InputAccumulator</tt> into <tt class="docutils literal">artifact.Output</tt>, and replacing its methods with some helper functions.
This would have some side effects in which error messages <em>make more sense</em>, because the failures are coming from the "correct" class all of a sudden.
The main issue then is how to package this up and then unpackage it for the <tt class="docutils literal">artifact.Output</tt>, when there's no longer a single class to work with.
This is going to take some more thought.</p>
<p>And right now, it's already way too late.</p>
<p>Good night.</p>
Weekly Roundup 2023-01-032023-01-03T05:00:00-05:002023-01-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-03:/weekly-roundup-2023-01-03<p class="first last">It's a little rough how I thought about some of these things <em>a lot</em>, and it still wasn't enough.</p>
<ul class="simple">
<li>Wednesday: I continued to plan renamings for MOTR.</li>
<li>Thursday: More renaming stuff...</li>
<li>Friday: I had trouble renaming one module, at least temporarily.</li>
<li>Saturday: I sketched out ideas for making one part of MOTR's interface make a little more sense, which unfortunately entails a lot of changes under the hood.</li>
<li>Sunday: I moved on to renaming other things, and had trouble with that again. Maybe I should be approaching this like... if I got rid of this module, what functionality would that impede?</li>
<li>Monday: On the road again...</li>
</ul>
<p>Next week, I'm going to try to keep up with what I've been doing.
Maybe change some things up, maybe not.
(Ugh, what did I do to Neovim to break my spellcheck under some circumstances?)</p>
Diary 2023-01-022023-01-02T05:00:00-05:002023-01-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-02:/diary-2023-01-02<p class="first last">Let's see how trying to get back to normal goes. I should maybe take notes.</p>
<p>All right.
We did some traveling today, and I am super happy to take that excuse to have a short post.
I'm going to work hard to decompress, because, despite my genuine efforts, my sleep health ended up... questionable, over vacation.</p>
<p>I can't think of anything else to mention.
I mean, I've been tearing through Cracking The Cryptic's hunt for January, but I assume it's going to get harder now that I'm past the intro.</p>
<p>Anyway, nothing else to waffle about, so let's finish this.</p>
<p>Good night.</p>
Coding 2023-01-012023-01-01T05:00:00-05:002023-01-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2023-01-01:/coding-2023-01-01<p class="first last">The names are <em>less</em> abstract, but they still feel <em>too</em> abstract...</p>
<p>I'm going to write a quick post tonight, and try to finish up with plenty of time until the new year.</p>
<p>I was focusing on renaming the <tt class="docutils literal">input_accumulator</tt> stuff.
Once I feel good about those names, I'll put the commentary from the last post into the <tt class="docutils literal">flex</tt> source, and then get to work on updating names.</p>
<p>Right now, I'm thinking that <tt class="docutils literal">ValueAdaptor</tt> gets renamed to <tt class="docutils literal">Selector</tt>, and the <tt class="docutils literal">InputAccumulator</tt> protocol maybe gets renamed to <tt class="docutils literal">MultiSelector</tt>.
I may also consider collapsing the implementations back into a single class that handles mapping somehow, I'm not sure.
<tt class="docutils literal">MultiSelector</tt> is probably not quite right.
The idea is that a <tt class="docutils literal">Selector</tt> combines a <tt class="docutils literal">select.Label</tt> and a function to map the wrapped value to a path segment, and the other class is responsible for folding the segments together with an initial value.
So, <em>ideally</em>, there should be something more descriptive of that than <tt class="docutils literal">MultiSelector</tt> or <tt class="docutils literal">Selectors</tt>.
<tt class="docutils literal">CombinedSelectors</tt>?
<tt class="docutils literal">SelectorCombiner</tt>?</p>
<p>I hope it's clear why I think this needs some time to bake.</p>
<p>Anyway, I'm about done with this for now.
I'll think about it more next year.</p>
<p>Good night.</p>
Coding 2022-12-312022-12-31T05:00:00-05:002022-12-31T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-31:/coding-2022-12-31<p class="first last">This is going to make the implementation ever so slightly squirrellier than the Platonic ideal, but, um, tough.</p>
<p>All right, starting the entry a little early today, because I just came up with a breakthrough, and I need to document it to get it all the way fleshed out.</p>
<p>Basically, I've got a provisional name replacement for <tt class="docutils literal">flex</tt>: <tt class="docutils literal">artifact</tt>.
Once I had that, I started looking over the various bits defined in the module, and I realized something about some of the helper classes I wrote: they're not so much misnamed, as they <strong>maybe</strong> shouldn't exist at all.</p>
<p>This turns out to be trickier than I thought it was before I started typing.
Let's have a look at two <tt class="docutils literal">Part</tt> definitions that illustrate what I need to work through.</p>
<p>Here's how they look currently:</p>
<div class="highlight"><pre><span></span><span class="n">HTML_DIR</span> <span class="o">=</span> <span class="n">_parametric_command</span><span class="o">.</span><span class="n">Extra</span><span class="p">(</span>
<span class="n">_flex</span><span class="o">.</span><span class="n">FlexOut</span><span class="p">[</span><span class="nb">str</span><span class="p">](</span>
<span class="n">_reports</span><span class="o">.</span><span class="n">accumulator</span><span class="p">(</span><span class="s2">"coverage"</span><span class="p">,</span> <span class="n">suffix</span><span class="o">=</span><span class="s2">"index.html"</span><span class="p">),</span>
<span class="nb">str</span><span class="p">,</span>
<span class="n">_parametric</span><span class="o">.</span><span class="n">no_parameters</span><span class="p">((</span><span class="s2">"mypy"</span><span class="p">,)),</span>
<span class="n">HTML_LABEL</span><span class="p">,</span>
<span class="n">_flex</span><span class="o">.</span><span class="n">ArgParent</span><span class="p">(</span><span class="s2">"--html-report"</span><span class="p">),</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="o">...</span>
<span class="n">JUNIT_XML</span> <span class="o">=</span> <span class="n">_parametric_command</span><span class="o">.</span><span class="n">Argument</span><span class="p">(</span>
<span class="n">_flex</span><span class="o">.</span><span class="n">FlexOut</span><span class="p">[</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">](</span>
<span class="n">_reports</span><span class="o">.</span><span class="n">accumulator</span><span class="p">(</span><span class="n">suffix</span><span class="o">=</span><span class="s2">"junit.xml"</span><span class="p">),</span>
<span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">,</span>
<span class="n">_parametric</span><span class="o">.</span><span class="n">no_parameters</span><span class="p">(()),</span>
<span class="n">JUNIT_LABEL</span><span class="p">,</span>
<span class="n">_flex</span><span class="o">.</span><span class="n">ExtraParent</span><span class="p">(),</span>
<span class="p">),</span>
<span class="s2">"--junit-xml"</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
<p>And then let's update the names in those and make a few other tweaks:</p>
<div class="highlight"><pre><span></span><span class="n">HTML_DIR</span> <span class="o">=</span> <span class="n">_parametric_command</span><span class="o">.</span><span class="n">Implicit</span><span class="p">(</span>
<span class="n">_artifact</span><span class="o">.</span><span class="n">Output</span><span class="p">(</span>
<span class="n">_reports</span><span class="o">.</span><span class="n">accumulator</span><span class="p">(</span><span class="s2">"coverage"</span><span class="p">,</span> <span class="n">suffix</span><span class="o">=</span><span class="s2">"index.html"</span><span class="p">),</span>
<span class="nb">str</span><span class="p">,</span>
<span class="n">_parametric</span><span class="o">.</span><span class="n">no_parameters</span><span class="p">((</span><span class="s2">"mypy"</span><span class="p">,)),</span>
<span class="n">HTML_LABEL</span><span class="p">,</span>
<span class="n">_artifact</span><span class="o">.</span><span class="n">ArgParent</span><span class="p">(</span><span class="s2">"--html-report"</span><span class="p">),</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="o">...</span>
<span class="n">JUNIT_XML</span> <span class="o">=</span> <span class="n">_parametric_command</span><span class="o">.</span><span class="n">Argument</span><span class="p">(</span>
<span class="n">_artifact</span><span class="o">.</span><span class="n">Output</span><span class="p">(</span>
<span class="n">_reports</span><span class="o">.</span><span class="n">accumulator</span><span class="p">(</span><span class="n">suffix</span><span class="o">=</span><span class="s2">"junit.xml"</span><span class="p">),</span>
<span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">,</span>
<span class="n">_parametric</span><span class="o">.</span><span class="n">no_parameters</span><span class="p">(()),</span>
<span class="n">JUNIT_LABEL</span><span class="p">,</span>
<span class="n">_artifact</span><span class="o">.</span><span class="n">ImplicitParent</span><span class="p">(),</span>
<span class="p">),</span>
<span class="s2">"--junit-xml"</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
<p>Some things that come to mind are relatively minor, such as that <tt class="docutils literal">Argument</tt> should probably have an alternative constructor called something like <tt class="docutils literal">prefixed</tt>.</p>
<p>But the big issue that I need to figure out is those <tt class="docutils literal">ArgParent</tt> and <tt class="docutils literal">ImplicitParent</tt> classes.
What I hope to do is to essentially turn the <tt class="docutils literal">HTML_DIR</tt> definition "inside-out", so that the description of how the command is actually constructed lives at the top level.
I think technically this changes the semantics because the <tt class="docutils literal">Artifact</tt> instance has less control over how it's "rendered", but I also think that doesn't matter, because the <tt class="docutils literal">Output</tt> instance should only appear in one context anyway.</p>
<p>(Also of note, there's <em>another</em> <tt class="docutils literal">Artifact</tt> implementation that corresponds to output, and it should <em>also</em> have access to whatever the main one does in this area; currently, it does not.)</p>
<p>Comparing these usages, the <tt class="docutils literal">HTML_DIR</tt> is saying "if we ensure that this <em>directory</em> exists, we can predict the file that will be written to it".
The <tt class="docutils literal">JUNIT_XML</tt> is saying "let's write a file to this path, and we had better make sure the parent exists".
In the former case, the <em>child</em> is implicit in the constructed command.
In the latter case, the <em>parent</em> is implicit.</p>
<p>Let's try changing things up modestly.</p>
<div class="highlight"><pre><span></span><span class="n">HTML_DIR</span> <span class="o">=</span> <span class="n">_parametric_command</span><span class="o">.</span><span class="n">Argument</span><span class="o">.</span><span class="n">prefixed</span><span class="p">(</span>
<span class="s2">"--html-report"</span>
<span class="n">_artifact</span><span class="o">.</span><span class="n">Output</span><span class="p">(</span>
<span class="n">_reports</span><span class="o">.</span><span class="n">accumulator</span><span class="p">(</span><span class="s2">"coverage"</span><span class="p">,</span> <span class="n">suffix</span><span class="o">=</span><span class="s2">""</span><span class="p">),</span>
<span class="nb">str</span><span class="p">,</span>
<span class="n">_parametric</span><span class="o">.</span><span class="n">no_parameters</span><span class="p">((</span><span class="s2">"mypy"</span><span class="p">,)),</span>
<span class="n">HTML_LABEL</span><span class="p">,</span>
<span class="n">_artifact</span><span class="o">.</span><span class="n">ImplicitChild</span><span class="p">(</span><span class="s2">"index.html"</span><span class="p">),</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="o">...</span>
<span class="n">JUNIT_XML</span> <span class="o">=</span> <span class="n">_parametric_command</span><span class="o">.</span><span class="n">Argument</span><span class="o">.</span><span class="n">prefixed</span><span class="p">(</span>
<span class="s2">"--junit-xml"</span><span class="p">,</span>
<span class="n">_artifact</span><span class="o">.</span><span class="n">Output</span><span class="p">(</span>
<span class="n">_reports</span><span class="o">.</span><span class="n">accumulator</span><span class="p">(</span><span class="n">suffix</span><span class="o">=</span><span class="s2">"junit.xml"</span><span class="p">),</span>
<span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">,</span>
<span class="n">_parametric</span><span class="o">.</span><span class="n">no_parameters</span><span class="p">(()),</span>
<span class="n">JUNIT_LABEL</span><span class="p">,</span>
<span class="n">_artifact</span><span class="o">.</span><span class="n">ImplicitParent</span><span class="p">(),</span>
<span class="p">),</span>
<span class="p">)</span>
</pre></div>
<p>The relevant changes to the interface look <em>really small</em> from this perspective, but they represent a pretty involved change to the implementation.
Let's skip over the <tt class="docutils literal">prefixed</tt> stuff, because that's trivial.</p>
<p>Including line-numbers for some reference to myself later...</p>
<p>It's hard to say how these changes should relate to lines 265-7, because the <tt class="docutils literal">map</tt> fields aren't typically doing anything <em>interesting</em>.
When we get to 268, there's the <tt class="docutils literal">Input</tt> creation, which needs to be modified in the case of an <tt class="docutils literal">ImplicitChild</tt>, but left alone if there is nothing or an <tt class="docutils literal">ImplicitParent</tt>.
The expression from 269-78 would similarly need to use the possibly-updated value.
Lines 280-2 apply the <em>outer</em> specification, so should use the parametric from before the <tt class="docutils literal">ImplicitChild</tt> is applied.
In the event that <tt class="docutils literal">ImplicitParent</tt> is passed, the block starting at line 284 should be entered, but the method calls to the object can be inlined.</p>
<p>Let's now have a look at <tt class="docutils literal">OutputFromInput</tt>.
The current implementation is... <em>aggressively</em> golfed in terms of pure statement count, so it's possible I'll need to break it up if I want to replicate this logic.
<tt class="docutils literal">OutputFromInput.convert</tt> starts by pulling the <tt class="docutils literal">Parametric</tt> from the wrapped input.
This should correspond to line 264.
Note that the <tt class="docutils literal">OutputFromInput</tt> expects the <tt class="docutils literal">Parametric</tt> to have been updated beforehand.
I might need to change this, because I can't use these new <tt class="docutils literal">Implicit</tt> ideas if I don't have a <tt class="docutils literal">PathStr</tt> to apply them to, which is not guaranteed.
Alternatively, the <tt class="docutils literal">OutputFromInput</tt> could <em>require</em> the caller to pass a <tt class="docutils literal">PathStr</tt>, and then have a separate <tt class="docutils literal">map</tt> step...
So, assume the wrapped <tt class="docutils literal">Input</tt> <em>must</em> have a compatible type, and then operate on that in the same general way as <tt class="docutils literal">Output</tt>.
It looks like 265 onward could work the same, and maybe be a common function.
Question: should <tt class="docutils literal">OutputFromInput</tt> accept the injected values?
I forget why I had it discard that argument...
For what it's worth, it also happens with <tt class="docutils literal">Input</tt>.
I'm also looking at the way I'm putting this together and thinking it it would make sense to just move the <tt class="docutils literal">inject_registry</tt> calls off of the "accumulator" classes, to reduce the API surface.
However, doing that <em>might</em> break things...
Anyway, I believe that <tt class="docutils literal">OutputFromInput</tt> would need to keep some of the logic that's in <tt class="docutils literal">Input</tt>.
I think the logic common to <tt class="docutils literal">OutputFromInput</tt> and <tt class="docutils literal">Output</tt> is from 176-86, which replaces lines 118-20 in <tt class="docutils literal">Input</tt>.</p>
<p>I think this is all of the information I need to fix this stuff up.
As of this writing, there's time tonight for me to attempt this, but I'd rather focus on continuing to plan.</p>
<p>First thing I'd like to try: removing the <tt class="docutils literal">inject_registry</tt> wrappers and try doing the injection after the parametric is extracted.
I kind of want to try that before any more planning, then get into planning seriously.</p>
<hr class="docutils" />
<p>It's later now. I'm going to try a quick rewrite and see what breaks, if anything.</p>
<hr class="docutils" />
<p>All right, it looks like that was clean.</p>
<p>I'm not going to put in much more work on this tonight, so let's switch to seeing which files I want to hit next.</p>
<ul class="simple">
<li><tt class="docutils literal">validators</tt>: Looks good to me.</li>
<li><tt class="docutils literal">command</tt>: Needs the extra -> implicit rewrite; <tt class="docutils literal">base_cmd</tt> can probably be deleted and noted in case I decide I actually need it; <tt class="docutils literal">Metadata</tt> should maybe be called <tt class="docutils literal">Command</tt>?</li>
<li><tt class="docutils literal">input_accumulator</tt>: Needs a few passes to get it to make sense.</li>
<li><tt class="docutils literal">installer</tt>: Needs to be split into two or three modules, which can then be evaluated individually.</li>
<li><tt class="docutils literal">label</tt>: Is totally fine, no need to worry.</li>
<li><tt class="docutils literal">parametric</tt>: I'm punting on.</li>
</ul>
<p>I'll try looking at <tt class="docutils literal">input_accumulator</tt>, then <tt class="docutils literal">installer</tt>, then <tt class="docutils literal">command</tt>.
For now, though, I'm going to wrap up.</p>
<p>Good night.</p>
Coding 2022-12-302022-12-30T05:00:00-05:002022-12-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-30:/coding-2022-12-30<p class="first last">It turns out there may have been a reason I haven't come up with a better name yet?</p>
<p>Well, I'm still thinking about what to call the <tt class="docutils literal">flex</tt> classes instead of <tt class="docutils literal">Flex*</tt>, and I feel like I haven't gotten anywhere yet.
I'm still looking for some kind of unified metaphor, but given the somewhat odd way they're created to be passed (outputs have to be created from function or class calls, which look near enough the same, but inputs have to be retrieved from a <tt class="docutils literal">Parametric</tt>), I haven't found anything that really ties any of this up with a bow.</p>
<p>I once again let things get too late, so I'm going to just do a short entry.</p>
<p>Good night.</p>
Coding 2022-12-292022-12-29T05:00:00-05:002022-12-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-29:/coding-2022-12-29<p class="first last">Finding problems, looking for solutions.</p>
<p>I got distracted, so this is late again.
Let's have a look at some minor tweaks to <tt class="docutils literal">parameters</tt>.</p>
<p>I want to remove some of the repetition of the module names in the class and function names.
Now, that could also bleed out into renaming the alias, because it's currently a little Pokémon-speak-y.
(Granted, that isn't stopping me in most places, so it's not a high priority.)</p>
<p>Let's have a look at the <tt class="docutils literal">generate_parameters</tt> function, though.
That takes a set of labels, a, let's call it <tt class="docutils literal">constants</tt> for now, and optionally a set of parameters to augment.
The result is an iterator over a set of updated <tt class="docutils literal">parameters</tt> objects.</p>
<p>I don't think there's another meaningful way to iterate over <tt class="docutils literal">parameters</tt> objects, so the current way the name works is</p>
<p>fine.</p>
<p>But I wonder if there's a more explicit way to describe what it does.</p>
<p>Like the point is, you pass in a set of labels to iterate over, the constants to draw the values from, and an existing set of selected variables...</p>
<p>In some sense the point of all of these data structures is that they represent <em>selections</em> out of multiple possible values.
So, what if we had <tt class="docutils literal">select.Label</tt>, <tt class="docutils literal">select.Labels</tt>, <tt class="docutils literal">select.Selections</tt>, <tt class="docutils literal">select.SELECTIONS</tt>, and <tt class="docutils literal">select.select</tt>?
I'll let those ideas stand for now, and move on to other things for the moment.</p>
<p>On the <tt class="docutils literal">registry</tt>/<tt class="docutils literal">constants</tt> side of things, the big change I'd make would be to re-export <tt class="docutils literal">Label</tt> to provide a module interface that's consistent with <tt class="docutils literal">parameters</tt>/<tt class="docutils literal">select</tt>/whatever.</p>
<p>Next up: whether to make any big changes to <tt class="docutils literal">flex</tt>.
I feel like it does need some changes, but I'm not sure what those changes look like.
One thing of note is that it's not a run-time dependency of <tt class="docutils literal">parametric</tt>, so it's free to draw in many other dependencies...</p>
<ul class="simple">
<li><tt class="docutils literal">validators</tt></li>
<li><tt class="docutils literal">command</tt></li>
<li><tt class="docutils literal">input_accumulator</tt></li>
<li><tt class="docutils literal">installer</tt></li>
<li><tt class="docutils literal">parametric</tt></li>
<li><tt class="docutils literal">cmd</tt></li>
<li><tt class="docutils literal">mkdir</tt></li>
<li><tt class="docutils literal">parameters</tt>/<tt class="docutils literal">variables</tt>/<tt class="docutils literal">select</tt>/whatever</li>
<li><tt class="docutils literal">registry</tt>/<tt class="docutils literal">constants</tt>/whatever</li>
<li><tt class="docutils literal">facts</tt> (<tt class="docutils literal">requirements</tt>)</li>
<li><tt class="docutils literal">io</tt></li>
</ul>
<p>Let's ignore <tt class="docutils literal">cmd</tt>, <tt class="docutils literal">mkdir</tt>, <tt class="docutils literal">facts</tt>, and <tt class="docutils literal">io</tt> off the bat, because they're in more core positions.
It's a bit much to go into the remainder of those, so let's focus on <tt class="docutils literal">flex</tt>.
The basic purpose of the <tt class="docutils literal">flex</tt> classes is to interact with the <tt class="docutils literal">parameters</tt>/<tt class="docutils literal">variables</tt>/<tt class="docutils literal">select</tt> systems to make sure that a given output file is specified once per command and is different for each set of selections used to generate a command, and that related inputs can be passed multiple times to a single command if desired.
There are two main classes there, and a bunch of auxiliary classes.
Let's see what's needed to instantiate these main classes:</p>
<ul class="simple">
<li><tt class="docutils literal">FlexOut</tt> needs:<ul>
<li>a "<tt class="docutils literal">PathStrAccumulator</tt>, which is basically a way to take a base path, and update it according to a value derived from a selection.</li>
<li>a mapping function that takes the final path from the above and converts it to the desired type.</li>
<li>a parametric that produces the output names; this field is both poorly named, and should be made optional.</li>
<li>the label corresponding to the <tt class="docutils literal">FlexIn</tt> that gets created; the caller is currently responsible for creating this, but should not be.</li>
<li>The helper for potentially requiring a parent directory to exist; this has to go somewhere, and I'm ambivalent about its current status.</li>
</ul>
</li>
<li><tt class="docutils literal">FlexIn</tt> needs:<ul>
<li>a <tt class="docutils literal">parametric</tt> that produces an <tt class="docutils literal">Input</tt> wrapped around the ultimately-desired type.</li>
<li>an ordered collection of <tt class="docutils literal">ValueAdaptor</tt>s, which are what's responsible for deriving <tt class="docutils literal">Path</tt>s from selections to pass into the accumulator mentioned above.</li>
<li>An additional field that I don't think callers are supposed to care about.
Since <tt class="docutils literal">FlexIn</tt> objects don't seem to be instantiated outside of the <tt class="docutils literal">flex</tt> module, this seems like a safe assumption.</li>
</ul>
</li>
</ul>
<p>This stuff is all kind of named after how it behaves in the context of multiple configurations.
It's "flexible" because you can define a command-line argument once, and it will automatically adjust to the pool of parameters it's supposed to select from.</p>
<p>As such, this is a bad name, because what most people will care about is how it behaves in the context of a single configuration.
In a single configuration, these classes need to be produced or obtained in various ways to pass into helper functions that create a <tt class="docutils literal">Part</tt> for a parametric command.</p>
<p>I'm going to have to think about this.
For now, it's late.</p>
<p>Good night.</p>
Coding 2022-12-282022-12-28T05:00:00-05:002022-12-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-28:/coding-2022-12-28<p class="first last">Starting to rework more names</p>
<p>All right, I'm going to try to review the names in my new modules.
So, starting in <tt class="docutils literal">parametric</tt>...</p>
<ul class="simple">
<li><tt class="docutils literal">label</tt></li>
<li><tt class="docutils literal">parameters</tt></li>
<li><tt class="docutils literal">registry</tt></li>
<li><tt class="docutils literal">typed_mapping</tt></li>
<li><tt class="docutils literal">flex</tt></li>
</ul>
<p>I'm feeling pretty good about <tt class="docutils literal">label</tt>, so let's start by considering <tt class="docutils literal">typed_mapping</tt>.
The basic <em>concept</em> of the "typed mapping" is really more like it's a function that conforms to some protocol, and the function can be updated to produce new functions.
Something about functions, maps, finite domains...</p>
<p>Honestly, <tt class="docutils literal">FunctionOnFiniteSet</tt> seems reasonable, since the modules and classes are intended to be used with aliases, so there's no concern about length.</p>
<p>So, next up, <tt class="docutils literal">registry</tt> and <tt class="docutils literal">parameters</tt>.
These need to be on the short side.
One is a function from a typed label to a value of that type.
The other is a function from a typed label of a collection of objects to a member of a corresponding collection.
I'm a little bit wondering if I want to change them back to <tt class="docutils literal">objects</tt> and <tt class="docutils literal">items</tt>?
My problem with that is, I don't think it really communicates the intended readings of "any instance whatsoever" and "an item of a collection".</p>
<p>I could have <tt class="docutils literal">constants</tt> instead of <tt class="docutils literal">registry</tt>, maybe?</p>
<p>I got distracted so it's getting late, but let's leave that there for now.
I'll mull this over and try to expand things out.</p>
<p>Good night.</p>
Weekly Roundup 2022-12-272022-12-27T05:00:00-05:002022-12-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-27:/weekly-roundup-2022-12-27<p class="first last">Weird, self-inflicted problems...</p>
<ul class="simple">
<li>Wednesday: I audited MOTR's dependencies, and put together some general plans for handling updates to them.</li>
<li>Thursday: I reviewed the lines of missed coverage in MOTR.</li>
<li>Friday: I put in some work improving the test coverage.</li>
<li>Saturday: I ended up derailed into trying to remove <tt class="docutils literal">isinstance</tt> checks.</li>
<li>Sunday: Some of the <tt class="docutils literal">isinstance</tt> checks came out easily, and some...</li>
<li>Monday: I continued to try to pull out the <tt class="docutils literal">isinstance</tt> checks, and it continued to be a pain.</li>
</ul>
<p>Next week, I've got a few more checks I want to pull out, and then I can get back to addressing coverage.
I actually finally figured out the """right""" way to remove the ones that were giving me trouble, which <em>may</em> have ended up doing some implicit casts, unfortunately, but oh well.
<em>Hopefully</em>, the type annotations are all honest...</p>
Coding 2022-12-262022-12-26T05:00:00-05:002022-12-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-26:/coding-2022-12-26<p class="first last">Feature request if I ever work on NABTO seriously: type checking should provide some visibility into how it's reasoning, because where I am right now just feels awful.</p>
<p>I had a good day today, and got some work done on MOTR, but right now, it feels like Mypy got me a reasonable distance and fixed some bugs, and then it, like, betrayed me.</p>
<p>I was working on replacing <tt class="docutils literal">isinstance</tt> checks inside one module, where part of the implementation was stubbed out because nothing needed that part yet.
I was having some persistent troubles writing a function to deal with the stubbed-out code, until I worked out that I was getting type errors when I implemented the stubs, because the type signatures on the stub were wrong, and the stub was papering over that.</p>
<p>Once I'd addressed that, I would have liked Mypy to accept all of the code, but it's rejecting <em>something</em> about the remaining code, and I'm unclear about how to fix it.</p>
<p>I'm going to keep on trying to make sense of the errors I'm getting, and also I'm going to look into whether it's possible to regain some conciseness, after my attempt to remove some nested conditionals resulted in <em>a lot</em> of method signatures.</p>
<p>For now, I should wrap things up, and I might pick at these errors a bit more, even if I probably shouldn't at the moment.</p>
<p>Good night.</p>
Coding 2022-12-252022-12-25T05:00:00-05:002022-12-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-25:/coding-2022-12-25<p class="first last">I really appreciate, I think, how some of the stuff that I'm doing to Mypy that probably <em>shouldn't</em> work, just... does.</p>
<p>Dealing with these <tt class="docutils literal">isinstance</tt> calls is hairier than I wanted it to be.
I took care of some of them earlier today, and had to reconsider my approach for others later.
I haven't tried to fix those yet, maybe tomorrow, maybe next week.</p>
<p>In any case, I did replace some imprecise types with mildly more specific ones, and pulled the relevant logic out of the function and stuck it at the top level.
That should open up some similar refactorings later, to help flatten out some methods even more.</p>
<p>At the end of the day, it is the end of the day, and I didn't take enough time to write this post up beforehand, so I'm going to cut this off abruptly now.</p>
<p>Good night.</p>
Coding 2022-12-242022-12-24T05:00:00-05:002022-12-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-24:/coding-2022-12-24<p class="first last">It's a good thing I'm not competing with anything, because <em>wow</em>, this is some careful deliberation.</p>
<p>I had a look at the missing coverage in <tt class="docutils literal">command_builder.py</tt>, and I concluded that, while it should be relatively straightforward to throw together a test at some level of abstraction, I feel like there should be some way to encode the checks that aren't being hit into the type system and remove them from the runtime code.</p>
<p>So, what would that look like:</p>
<ul class="simple">
<li>Create a new typevar for representing the <tt class="docutils literal">module_args</tt> value.</li>
<li>This propagates to the usages of the <tt class="docutils literal">CommandBuilder</tt> in <tt class="docutils literal">parametric_command</tt>, and secondarily to the client-style modules.</li>
<li>The immediate change would be through the addition of a new parameter to <tt class="docutils literal">ParametricCommandMeta</tt>.</li>
<li>One question this raises is whether commands that accept a module argument should be <em>required</em> to be passed one, but it should be safe to err on the side of strictness to start with.</li>
<li>The key point is that the <tt class="docutils literal">module_or_adaptor</tt> field would also need to become parameterized, and I haven't yet thought of anything that seems like a <em>good</em> way to do that.
A <em>way</em> to do that is to create a parameterized protocol, and two classes that implement it, somehow scoping the implementation of each to a different value of the variable (probably by using self annotations of the protocol? Does that even work?), which should then localize the <tt class="docutils literal">with_module</tt> calls to the paths where it's statically asserted to succeed.</li>
</ul>
<p>Thinking about what would improve the codebase, I think the thing to do is to try to eliminate the <tt class="docutils literal">isinstance</tt> checks that have test coverage.
That makes the typing a bit easier to reason about, and also eliminates some conditionals, so the behavior of the code should be less squirrelly.
If all of that works, then I can look into propagating the type information like I was talking about.</p>
<p>For now, I'm going to wind down, and I'll see what I can do in the next few days.</p>
<p>Good night.</p>
Coding 2022-12-232022-12-23T05:00:00-05:002022-12-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-23:/coding-2022-12-23<p class="first last">Just do the thing.</p>
<p>All right, I pushed up test coverage on MOTR a little bit.
I added some error path tests, and improved the errors they're looking for.
I deleted some functions that weren't accomplishing anything.
It shouldn't be <em>hard</em> to put them back if I discover I need them, but I don't <em>think</em> I'll need them.</p>
<p>I didn't get much done today because of travel; we'll see how I do in the next few days, but I hope to cut down on the coverage misses, then work on renaming and reorganizing, then rework some of the high-level usages, and expand the highest-level wrappers until it's ready for a release.</p>
<p>I don't know how much of that I can get down in the next week, or in the next month.
I'm just going to have to take it a bit at a time.</p>
<p>Good night.</p>
Coding 2022-12-222022-12-22T05:00:00-05:002022-12-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-22:/coding-2022-12-22<p class="first last">I just realized I missed some test and plugin code. Oh well, not too important.</p>
<p>After I thought through those changes yesterday, I decided to prioritize increasing coverage and other improvements for now.</p>
<p>One of the "other improvements" centers around test execution time.
I hadn't realized it before, but the test execution is not <em>just</em> taken up by the type tests (which I'll address by splitting the relevant module out into its own set of packages).
There are also tests of the customized <tt class="docutils literal">Build</tt> task (which should maybe be called <tt class="docutils literal">PythonBuild</tt>?).
These tests take up about half of the execution time, and the type tests take up basically the other half.
I can probably speed up the build tests by mocking the <tt class="docutils literal">cmd</tt> module so the <tt class="docutils literal">Cmd</tt> class doesn't actually hit the filesystem.
I'll look into that later.</p>
<p>Coverage misses review:</p>
<ul class="simple">
<li><tt class="docutils literal">parametric_command</tt> is missing one line.
That line looks like it could be factored out, but I don't think it's worth it.
The required test is to create two <tt class="docutils literal">ValueAdaptor</tt> objects with the same <tt class="docutils literal">Label</tt>, and put them on the same <tt class="docutils literal">ParametricCommandMeta</tt> object, then have a <tt class="docutils literal">ParametricCommand</tt> attempt to <tt class="docutils literal">build()</tt> given that metadata.</li>
<li><tt class="docutils literal">python_helpers</tt> is missing one line.
I think this line will be relevant for running coverage.py.
Perhaps the thing to do is to make stub implementations for coverage, and have tests that just import those modules.</li>
<li><tt class="docutils literal">input_accumulator</tt> is missing one line of coverage, and I'm not comfortable trying to add it until I've audited the relevant names, because the data flow around that line is confusing, and it's more or less my fault.</li>
<li><tt class="docutils literal">flex</tt> is missing three lines of coverage.
One of them appears to be unnecessary and can probably be deleted.
One of them can probably be deleted with some care.
The remaining line requires a simple dummy test to cover.</li>
<li><tt class="docutils literal">command_builder</tt> is missing one line, that requires a simple dummy test to cover.</li>
<li><tt class="docutils literal">build</tt> is missing two lines, which will be much easier to cover if I figure out the mocking I want to use.</li>
<li><tt class="docutils literal">installer</tt> is missing two lines, which can be tested relatively easily.</li>
<li><tt class="docutils literal">pip</tt> is missing six lines, of which five can be tested trivially, and one needs a little more thought to test properly.</li>
<li><tt class="docutils literal">parametric</tt> is missing twelve lines, and probably needs a thorough review to plan tests for them.</li>
<li><tt class="docutils literal">command</tt> is missing seven lines.
I can reduce or eliminate six of them with some careful rewrites, and the remaining line...
I honestly think it's best to just delete it, because it doesn't really look like it would pull its weight if I <em>did</em> use it.</li>
<li><tt class="docutils literal">not_output</tt> is missing four lines, and those lines are easy to cover, but I'd like to consider, later, what it would take to hit those lines in an integrated sense.</li>
<li><tt class="docutils literal">validators</tt> is missing five lines.
Many of the tests above would hit one of them, and I'm interested in writing tests for the other four, just because it'd be a nasty shock if someone were somehow debugging MOTR interactively, and suddenly something's <tt class="docutils literal">repr</tt> was broken.</li>
</ul>
<p>All right, let's call this here.
I'll be on the road tomorrow, so I don't know if I'll be up for writing any of those tests, but hopefully over the next week...</p>
<p>Good night.</p>
Coding 2022-12-212022-12-21T05:00:00-05:002022-12-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-21:/coding-2022-12-21<p class="first last">Collating five different sources of information to conclude that what I want to do is <em>probably</em> easy and fine.</p>
<p>I was thinking about working on MOTR, and I realized that, before I do anything else, I want to audit my dependencies to check for urgent updates.
I know Trio has some stuff coming down the pipe that I need to be ready for.
And I can make some improvements to how I'm requiring Cement if I use a newer version.
Here are MOTR's direct dependencies, and notes on them:</p>
<ul class="simple">
<li><tt class="docutils literal">attrs</tt>: has a new interface that I would like to switch to at some point.</li>
<li><tt class="docutils literal">blessed</tt>: It looks like nothing breaking is happening. I'll have to revisit it when I look at some issues with the templates.</li>
<li><tt class="docutils literal">cement</tt>: newer versions provide a nicer way to pull in the following dependencies:<ul>
<li><tt class="docutils literal">colorlog</tt></li>
<li><tt class="docutils literal">jinja2</tt></li>
<li><tt class="docutils literal">pyyaml</tt>: I want to figure out what it takes to drop this dependency, because it's for reading configuration files, and I don't... I'm not... You can't <em>fit</em> a motrfile in yaml.</li>
</ul>
</li>
<li><tt class="docutils literal">pyrsistent</tt>: I think I want to cut down on the usage of this slightly, because I'm fairly sure I'm not playing to the strengths of <tt class="docutils literal">PVector</tt> or <tt class="docutils literal">PSet</tt>.</li>
<li><tt class="docutils literal">tqdm</tt>: I have some ideas for trying to make the progress bar a little nicer, but I'm going to hold off on trying them out for now.</li>
<li><tt class="docutils literal">trio</tt>: Some of the interfaces I'm using are changing, and also there are some interactions with Cement that I want to address.</li>
<li><tt class="docutils literal">virtualenv</tt></li>
<li><tt class="docutils literal"><span class="pre">wheel-filename</span></tt></li>
</ul>
<p>Let's have a quick look at the Trio changes.</p>
<p>The upcoming change is to <tt class="docutils literal">trio.MultiError</tt> creation, or lack thereof.
In order to handle everything properly, I need to:</p>
<ul class="simple">
<li>add <tt class="docutils literal">strict_exception_groups=True</tt> to the <tt class="docutils literal">trio.run</tt> call</li>
<li>replace the <tt class="docutils literal">contextlib.suppress(_exc.MOTRTaskError)</tt> with, um, <tt class="docutils literal"><span class="pre">exceptiongroup.catch({_exc.MOTRTaskError:</span> noop})</tt>, or something?</li>
<li>Figure out what Cement does when it gets a <tt class="docutils literal">BaseExceptionGroup</tt></li>
<li>Fix any tests that this breaks. Like, can I write catch handlers that will preferentially reraise any error besides the expected one, and reraise the expected error type if there are no others? Is pytest getting changes to handle exception groups? I don't think these off-the-cuff ideas are quite enough...</li>
</ul>
<p>The other Trio-related change I want to make is to stop telling Cement to handle SIGINT.
This requires getting a small number of changes just right, which shouldn't be <em>hard</em>, but it took a bunch of effort to verify that this was the case.
And I'm still not totally sure.</p>
<p>Anyway, I'll look into making those changes later.
For now, I should wind down.</p>
<p>Good night.</p>
Weekly Roundup 2022-12-202022-12-20T05:00:00-05:002022-12-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-20:/weekly-roundup-2022-12-20<p class="first last">Bouncing around, but making progress.</p>
<ul class="simple">
<li>Wednesday: I carefully traced the data flow required to instantiate an environment in MOTR's high-level interface, because it's really not obvious how it all fits together.</li>
<li>Thursday: With that information at hand, I was able to improve the quality of the new tests in MOTR.</li>
<li>Friday: I reviewed how some of the code paths I want to test are meant to be invoked, and planned some stuff out.</li>
<li>Saturday: We watched the MST3K season finale. That was a lot.</li>
<li>Sunday: I got sidetracked by Jerma's holiday stream(s), so, no normal post.</li>
<li>Monday: I tossed together the tests, and got MOTR up above 97% coverage. I concluded that the names at the high level really need to change.</li>
</ul>
<p>Next week, I'm going to relax for a few days, try to work on MOTR, relax a bit more, then work a bit more.</p>
Coding 2022-12-192022-12-19T05:00:00-05:002022-12-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-19:/coding-2022-12-19<p class="first last">(Before looking at the code.) "I don't understand why it needs this step in the middle." (After looking at the code.) "I understand why it needs this step in the middle, and I <em>hate</em> it."</p>
<p>I did a bunch of other stuff today, but at long last, I managed to grind out the tests to increase coverage for the <tt class="docutils literal">flex.py</tt> module.
In the process, I established that "bundle related arguments together" seems to work fine, but also that a bunch of my names don't get any more intuitive the more I stare at them, so I really need to look into changing them around.</p>
<p>I guess I'll try to take notes on that starting some time next week.
Anyway, not going to dwell on this stuff right now.
Best get things wrapped up.</p>
<p>Good night.</p>
Diary 2022-12-182022-12-18T05:00:00-05:002022-12-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-18:/diary-2022-12-18<p class="first last">Wasn't expecting to be watching TV for like four hours.</p>
<p>Hm, I didn't anticipate how things were going to go in terms of stuff to do today, so I don't have anything much to write about.</p>
<p>I did do some reorganization in a side project, and messed around in a different side project, but nothing really worth writing about yet.</p>
<p>I'm going to try to wrap things up for now, and actually get stuff done for MOTR tomorrow.</p>
<p>Good night.</p>
Diary 2022-12-172022-12-17T05:00:00-05:002022-12-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-17:/diary-2022-12-17<p class="first last">Why did the fake British accents in this movie sound like Monty Python's fake American accents?</p>
<p>I'm not sure I can process anything after the MST3K season finale.
That movie was very, very little, until it was so, so much, and then it went back to being nothing.
Like the movie blew its entire <em>emotion</em> budget on one scene at the end?
Bizarre, on so many levels.</p>
<p>Anyway, let's see what I'm up for doing tomorrow; I really need to wrap up right now.</p>
<p>Good night.</p>
Coding 2022-12-162022-12-16T05:00:00-05:002022-12-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-16:/coding-2022-12-16<p class="first last">Stumbling across my old ideas of what "best practices" might be, that turned out not to pan out.</p>
<p>The next step for increasing test coverage for MOTR, is to refresh my memory.
I see that the next stuff I want to exercise is currently, in existing code, kind of just tossing around <tt class="docutils literal">FlexIn</tt> objects in a way that isn't quite satisfying, according to my gut reaction.</p>
<p>Like, this shouldn't be relevant to the tests, but it feels a little weird to have the same <tt class="docutils literal">FlexIn</tt> object appear twice in the expressions going into the command...
Like... the <tt class="docutils literal">FlexIn</tt> and its derived <tt class="docutils literal">LessFlexOut</tt> should <em>always</em> be paired, but I guess I don't have enough examples to decide on how to do it generally.
Although, it doesn't have to be general.
It could just as well be a function that returns a <em>sequence</em> of <tt class="docutils literal">Part</tt>s, and I just call it like <tt class="docutils literal"><span class="pre">.add_parts(*func(...))</span></tt>.</p>
<p>When I have time to work on the tests, I'll have to experiment with making interfaces like that, and update the existing code if the result is satisfying.</p>
<p>Anyway, I let things go way too late again, so I have to cut this off here.
I'm not sure I'll get anything done tomorrow, so let's see how the weekend goes.</p>
<p>Good night.</p>
Coding 2022-12-152022-12-15T05:00:00-05:002022-12-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-15:/coding-2022-12-15<p class="first last">Improving the test revealed that I was missing some key data in the metadata objects I was creating, so it's good I got that out of the way.</p>
<p>All right, I've properly juiced up the test that I wrote.
It turned out to, um, not need the helper functions I wrote, because those make sense in the context of MOTR's python- and pip- related hooks, and when I'm literally faking every part of the commands, it doesn't really make a difference.</p>
<p>My goal now is to extend this test to run through more elaborate logic, feeding command outputs to inputs in a secondary command, and mapping those inputs back to outputs.
I'm not going to try to do that now; I finished this up a little earlier than usual, and I'd rather take the extra time than extend this work out tonight.</p>
<p>Good night.</p>
Coding 2022-12-142022-12-14T05:00:00-05:002022-12-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-14:/coding-2022-12-14<p class="first last">My code's not <em>magic</em>. I just... I needed to verify that...</p>
<p>All right, let's take a look at MOTR's code...</p>
<p>My goal here is to trace things back from the flake8 test.
Let's see how this breaks down...</p>
<ul class="simple">
<li><tt class="docutils literal">test_flake8.make_changes</tt> defines a function called <tt class="docutils literal">make</tt>, which takes two arguments: <tt class="docutils literal">parametric</tt> and <tt class="docutils literal">package_data</tt>.<ul>
<li><tt class="docutils literal">package_data</tt> is passed into <tt class="docutils literal">api.cli.build.build</tt> to return <tt class="docutils literal">Facts[Objects]</tt>, and inject information about which Python versions to use for <tt class="docutils literal">flake8</tt>.
The <tt class="docutils literal">package_data</tt> comes from <tt class="docutils literal">api.package.combine_packages</tt>.
This is a <tt class="docutils literal">PythonPackages</tt> object, and the relevant behavior partially lives in the constants defined in that package, and partly in <tt class="docutils literal">api.cli.build.build()</tt>, which puts the necessary values under the necessary keys.
<strong>TODO:</strong> make a helper function in <tt class="docutils literal">package</tt> for carrying out the changes, rather than having them done in the return statement of <tt class="docutils literal">api.cli.build.build()</tt>.</li>
<li><tt class="docutils literal">parametric</tt> pulls in the information from the modified <tt class="docutils literal">Objects</tt>, and the argument further down is from <tt class="docutils literal"><span class="pre">api.cli.flake8.BASE.add_parts(...).build()</span></tt>.
This <tt class="docutils literal">add_parts()</tt> return value is a <tt class="docutils literal">ParametricCommand</tt>.
Its <tt class="docutils literal">build()</tt> method calls the <tt class="docutils literal">command_builder.CommandBuilder.facts()</tt> method from the <tt class="docutils literal">_build()</tt> method, which is really complicated, but I think the important thing is the <tt class="docutils literal">ParametricCommandMeta</tt> that had <tt class="docutils literal">with_adaptor()</tt> called on it.</li>
</ul>
</li>
</ul>
<p>Okay, I'm lost again.
Let's check out the <tt class="docutils literal">facts()</tt> method?
Oh, wow, my names for these things got <em>janked</em>.
Basically, at some point, parametric information about how to construct the specific strain of environment required for the operation is injected into the <tt class="docutils literal">ParametricCommand</tt> via <tt class="docutils literal">with_adaptor()</tt>, and the <tt class="docutils literal">build()</tt> method on that object retrieves it, and passes it to <tt class="docutils literal">facts()</tt>, which combines it with the <tt class="docutils literal">installer_registry</tt> data to pass it to <tt class="docutils literal">installer.install()</tt>.
The <tt class="docutils literal">installer_registry</tt> is on the <tt class="docutils literal">command.Metadata</tt>, and is, in these specific cases, populated from the <tt class="docutils literal">PythonCmd</tt> helper.</p>
<p>So, for a synthetic version to work, I need to create a <tt class="docutils literal">command.Metadata</tt> that has the desired installer data stored under a known key.
In addition, I need a versions adaptor wrapped around a known key, which needs to be explicitly passed in, associated with a <tt class="docutils literal">PVector[installer.PathWith[EnvironmentArgs]]</tt>.</p>
<p>I apologize for how completely and thoroughly opaque that was, but I needed to go over this really thoroughly in order to remind myself where everything actually gets instantiated.</p>
<p>Maybe tomorrow, I can actually do something with all of this.
For now, I'm done.</p>
<p>Good night.</p>
Weekly Roundup 2022-12-132022-12-13T05:00:00-05:002022-12-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-13:/weekly-roundup-2022-12-13<p class="first last">This is one of the things that you know it's good for you because it's unpleasant.</p>
<ul class="simple">
<li>Wednesday: I tried to figure out the proper interface for a test helper function.</li>
<li>Thursday: I got the proper interface, by splitting the function in two. I also made a slight organizational change to the tests directory.</li>
<li>Friday: I confirmed that the helper functions worked, and cleaned up <tt class="docutils literal">conftest.py</tt> a little.</li>
<li>Saturday: I realized that I've forgotten how (and <em>whether</em>) the various interfaces required for using a high-level wrapper around a Python script actually get invoked.</li>
<li>Sunday: Travel out. Fried.</li>
<li>Monday: Travel back. Fried.</li>
</ul>
<p>Next week, I'm going to <em>very methodically</em> document the flow of data through my tests, so I can figure out how this code is currently "supposed to be written", and whether I want to change that.
And other stuff.</p>
Diary 2022-12-122022-12-12T05:00:00-05:002022-12-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-12:/diary-2022-12-12<p class="first last">On the road again, again, again, again...</p>
<p>Okay, we traveled again today, so I just didn't plan to do much to write about.
My plan for the coming week is to nail down whether and how the current high-level tests for MOTR are creating correct <tt class="docutils literal">Compendium</tt> objects, and to pick up some side stuff that I got unblocked on a technical level yesterday.</p>
<p>For now, I'm going to wind down and get ready for bed.</p>
<p>Good night.</p>
Diary 2022-12-112022-12-11T05:00:00-05:002022-12-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-11:/diary-2022-12-11<p class="first last">One step forward, two steps back...</p>
<p>We traveled today, and I spaced out.</p>
<p>On the plus side, I did manage to finally fix some abstruse technical issues in a side project, so now I can get back to working on that.</p>
<p>Besides that, I've been working on the latest puzzle hunt from the Cracking the Cryptic patreon.
I've <em>sort of</em> solved it.
I've got the last puzzle solved, but I keep messing up the second-to-last puzzle, which is supposed to be a prerequisite for the last puzzle.
I should hopefully get things done reasonably within a week.
Anyway, I let things go way too late and I desperately need to wrap up.</p>
<p>Good night.</p>
Coding 2022-12-102022-12-10T05:00:00-05:002022-12-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-10:/coding-2022-12-10<p class="first last">Expert on relevant code shrugs and says "lol i dunno"</p>
<p>All right, let's see <em>what I was doing</em> with these high levels of abstractions...</p>
<p>The "pattern" for interacting with with the code seems to be as follows:</p>
<ul class="simple">
<li>Given the label associated with the versions, also have a <tt class="docutils literal">PVector[PathWith[EnvironmentArgs]]</tt>.</li>
<li>Also, construct a <tt class="docutils literal">Parametric[Objects]</tt> that contains the proper data to run the commands, which is...
um...</li>
</ul>
<p>Okay, so this all made sense at the time.
I think.
I've got a fake <tt class="docutils literal">Executable</tt> which contains a label, which needs to be used as an index in the <em>installer</em> registry...</p>
<p>You can tell this code isn't ready for anyone else to use, because it kind of seems like it's not ready for <em>me</em> to use it...</p>
<p>Okay, here's the plan.
I'm going to take things easy this weekend.
Maybe work on something else.
Then next week, I'm going to document the data flow very, <em>very</em> carefully, and take notes on any names that could be different, because the fact that so many of these names lack any semantic content doesn't <em>help</em> anything.
For now, I need to rest up and get ready to travel.</p>
<p>Good night.</p>
Coding 2022-12-092022-12-09T05:00:00-05:002022-12-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-09:/coding-2022-12-09<p class="first last">I appreciate that the code was simple enough that it all worked on the first try (modulo errors at the <em>usage site</em> that had nothing to do with the way I wrote the code)</p>
<p>The new test helper code I added is in good shape now.
Running <tt class="docutils literal">motr</tt> on itself results in everything being good except for missing about 50 lines of coverage, out of 2360.</p>
<p>I wired the new helper functions into some existing tests, and the result is... I don't feel strongly, but I'm not changing it back.
Now, I just need to look over those old tests, and figure out what I need to get the new tests to exercise more code paths.
Basically, to take the existing tests, and copy their logic.
This may end up requiring some of the code that I removed in revision 672 because the current low-power tests didn't need it.
Which is exactly why I made sure to have a separate commit removing it; this way it's easy to bring it back.</p>
<p>Anyway, that's what I'll try to work on the next chance I have, which, I don't know for sure when that's going to be, but whatever.</p>
<p>Good night.</p>
Coding 2022-12-082022-12-08T05:00:00-05:002022-12-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-08:/coding-2022-12-08<p class="first last">Just a little bit at a time, just a little bit at a time...</p>
<p>Okay, I managed my time poorly once again, so here's what I dashed out quickly, and then I'm going to publish:</p>
<p>I added a <tt class="docutils literal">__init__.py</tt> file to the tests directory so I can do a relative import of the helpers module I just added.
Maybe I'll reorder that a little later, but there's no time right now.
Inside the helper file, I put two functions.
One takes a <tt class="docutils literal">Facts[Objects]</tt> and an <tt class="docutils literal">Objects</tt>, and calls <tt class="docutils literal">.update()</tt> on the <tt class="docutils literal">Objects</tt> that it gets from the <tt class="docutils literal">Facts[Objects]</tt>, with the other <tt class="docutils literal">Objects</tt> that was passed.
The other function takes a <tt class="docutils literal">Facts[Objects]</tt> and any number of <tt class="docutils literal">Parametric</tt> arguments.
It extracts the <tt class="docutils literal">Objects</tt> from the <tt class="docutils literal">Facts[Objects]</tt>, then calls <tt class="docutils literal">.facts()</tt> on each <tt class="docutils literal">Parametric</tt> that was passed in.</p>
<p>Together, these sidestep the API design issues I was having by having two smaller functions that do less each than the one large function I was visualizing, and are less awkward to lay out the parameters for, thanks to the level of nesting this adds.</p>
<p><em>Anyway</em>, I'll actually have a chance to try this stuff out later.
For now, I just wanted it put together and ready to think about.
No more writing for now.</p>
<p>Good night.</p>
Coding 2022-12-072022-12-07T05:00:00-05:002022-12-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-07:/coding-2022-12-07<p class="first last">Not sure what "a good interface" even looks like in this context.</p>
<p>All right, I ended up spacing out and it's late, so here are some quick notes about the helper functions I want to consolidate:</p>
<ul class="simple">
<li>There is an initial call that produces a <tt class="docutils literal">Facts[Objects]</tt>, followed by merging a limited amount of data into the <tt class="docutils literal">Objects</tt>.</li>
<li>Then, for each <tt class="docutils literal">Parametric</tt> passed in, just yield from the <tt class="docutils literal">Facts</tt>, given the <tt class="docutils literal">Objects</tt>.</li>
<li>I was interested in verifying the <tt class="docutils literal">Objects</tt> against the stated requirements of the <tt class="docutils literal">Parametric</tt>s.</li>
</ul>
<p>I'm not sure how much caching I want to do.
I guess, on reflection, I could get away with making this a helper function, but it's a little tricky to visualize the right interface.
Like, is <tt class="docutils literal">def __call__(self, facts: Facts[Objects], overrides: Objects, *parametrics: Parametric[object]) <span class="pre">-></span> Facts[None]:</tt> reasonable?
I'll need to think about it.</p>
<p>For now, I'll get ready for bed.</p>
<p>Good night.</p>
Weekly Roundup 2022-12-062022-12-06T05:00:00-05:002022-12-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-06:/weekly-roundup-2022-12-06<p class="first last">It's nice to finally be in a mood to increase the coverage.</p>
<ul class="simple">
<li>Wednesday: I wrote down the apparent requirements to make a fake program module in MOTR.</li>
<li>Thursday: I implemented most of those requirements, except for the last one.</li>
<li>Friday: I put together something that may or may not implement the final requirement.</li>
<li>Saturday: We watched Species.</li>
<li>Sunday: I started planning tests for the uncovered code.</li>
<li>Monday: I added the most basic of coverage, and immediately found a bug.</li>
</ul>
<p>Next week, I'm going to try to improve the quality of the new test in MOTR, and tighten up existing tests.</p>
Coding 2022-12-052022-12-05T05:00:00-05:002022-12-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-05:/coding-2022-12-05<p class="first last">Maybe there's some kind of sampling bias, because the "obviously correct" code is usually easy to cover, so if I haven't covered a function completely, it's probably doing <em>something</em> horrible. Even if that's the case, I, um, don't care.</p>
<p>I added a small amount of code coverage today, and it immediately revealed a bug that had eluded all other checks.
This has happened a bunch before.
Whenever I write tests for some squirrelly bit of code, it seems to always turn out it was accidentally making bad type assumptions, or has a critical bit of logic inverted, or whatever.</p>
<p>I've read stuff online talking about how full code coverage isn't valuable, but I'd really rather exercise these weird code paths before I ship something.
Maybe other people can write this kind of code with no bugs.
If so, good for them, and when they're working on their code bases, they're free to apply standards to their work that match up with that track record.
For my hobby projects, I'll be applying standards that apply to my track record with these hobby projects, and that means 100% coverage as table stakes.</p>
<p>Now, as it turns out, the test I wrote, that one that found the bug that I had to fix, is actually kind of on the weak side of things, and I'm going to need to extend things in several ways, some of which will increase coverage, and some of which won't, at least outside of the sense of "tests should have 100% coverage, so adding a new test should move the coverage percentage closer to 100%".</p>
<ul class="simple">
<li>I need to test the <tt class="docutils literal">EnvVar</tt>-related code paths for the other <tt class="docutils literal">Flex</tt> implementations besides <tt class="docutils literal">FlexOut</tt>.</li>
<li>I need to generate a proper <tt class="docutils literal">Compendium</tt> from test data.</li>
</ul>
<p>I may prioritize the latter, just because it'll make existing and new tests much stronger.</p>
<p>Actually, that's a good thing for me to consider while I work on the tests: should it always be the case that a valid <tt class="docutils literal">ParametricCommand</tt>'s <tt class="docutils literal">build()</tt> method should produce a <tt class="docutils literal">Parametric</tt> that, when passed all required (and possibly some additional, unnecessary) data to its <tt class="docutils literal">facts()</tt> method, produces a <tt class="docutils literal">Facts</tt> that, when passed to <tt class="docutils literal">api.build()</tt>, produces a <tt class="docutils literal">Compendium</tt> without erroring on any step?
I <em>think</em> that's a reasonable correctness criterion, so, either later tonight, or sometime next week, I'll see about writing a helper to handle that.</p>
<p>The helper would have to do stuff like validate that all necessary data is passed, because right now, the code doesn't really establish that.
(It would also need to precompute some of the facts to actually get that far, but, um, oh well.)</p>
<p>Anyway, I'm going to wrap this up and post it a little early, so I can relax later tonight.</p>
<p>Good night.</p>
Coding 2022-12-042022-12-04T05:00:00-05:002022-12-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-04:/coding-2022-12-04<p class="first last">Just a little bit at a time, and it adds up.</p>
<p>Well, it turns out I was taking things easy again today, so let's see about the kinds of things I need to be able to run the tests I want to write.
Starting with the attempts to just exercise the code.</p>
<p>I need to create a label object, and from there, the first thing I want is to create something like <tt class="docutils literal"><span class="pre">parametric_command.EnvVar(flex.FlexOut(reports.accumulator(suffix="test.txt"),</span> lambda x: x, <span class="pre">parametric.no_parameters(()),</span> label), "TEST_VAR")</tt>.
Let's see if it likes having that code in there, not executed yet.</p>
<p>I could try to adapt the existing tests into versions that interact with this new stub code, but I don't feel like pushing myself further right now, and I'm going to hold on to feeling satisfied with the amount of work that I happen to have done at any given time.</p>
<p>So, I'm done for now, and we'll see what I manage tomorrow.</p>
<p>Good night.</p>
Diary 2022-12-032022-12-03T05:00:00-05:002022-12-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-03:/diary-2022-12-03<p class="first last">"What if humans are the real monsters?" (Narrator: "Actually, monsters were the real monsters.")</p>
<p>Okay, I didn't get anything done today that I want to write about.
We saw a movie.
It was silly.</p>
<p>I'm spacing out, and I don't have anything else to say.</p>
<p>Good night.</p>
Coding 2022-12-022022-12-02T05:00:00-05:002022-12-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-02:/coding-2022-12-02<p class="first last">It looks really complicated, but actually it can be very simple, unless I'm badly mistaken and it has to be extremely complicated.</p>
<p>So, I might have been kind of out of it again today.
The air is really harsh and makes it hard to breathe and stuff like that.
Anyway, let's crack open my... unreleased legacy code?</p>
<p>The core question here is, what do the first two arguments to <tt class="docutils literal">CommandBuilder</tt> need to be?
The first argument is an <tt class="docutils literal">Executable</tt>, which includes a script name.
The second argument is a <tt class="docutils literal">command.Metadata</tt>, and it is <em>optional</em>, so I might be able to get away with not passing anything.</p>
<p>...</p>
<p>Sadly, maybe not.
The existing examples pass installer information in the <tt class="docutils literal">Metadata</tt> instance, which...
Wait...
They're only passing that because the pip command has to actually accomplish something.
The installer information doesn't establish any task dependency relationships, so it should be safe to leave the installer be.
So, let's see what I think will work...</p>
<p>Okay, I have some syntactically valid Python code here.
The goal now is to exercise unused code paths in my new wrapper code, and <em>hopefully</em> figure out the correctness criteria for writing the tests, because I confused myself badly the last time I tried to work that out.</p>
<p>I think the fundamental goal is: no matter what combination of parametric labels and parametric combinators, I'm never trying to put two different values into the same environment variable.</p>
<p>Anyway, we'll see when I'm able to put all of that together.
For now, I'm going to wind down again.</p>
<p>Good night.</p>
Coding 2022-12-012022-12-01T05:00:00-05:002022-12-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-12-01:/coding-2022-12-01<p class="first last">Maybe I should re-evaluate the names before I work on the coverage? I don't know...</p>
<p>I didn't really focus on MOTR today, so I'm going to try to make some quick work around what I worked out yesterday.</p>
<p>...</p>
<p>All right, that's enough for now.
I've gotten nearly everything I wrote up yesterday sketched out, and what remains is... unintuitive.
There's a bunch of ... stuff ... that the wrappers I've written up all use, but the helper code is ostensibly Python-specific.
So, what I need to do is, when I'm feeling better and more focused, is to re-work-out the types and values involved in constructing the arguments to these functions.</p>
<p>For now, I'm going to wind down again.</p>
<p>Good night.</p>
Coding 2022-11-302022-11-30T05:00:00-05:002022-11-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-30:/coding-2022-11-30<p class="first last">The bad names are still bad.</p>
<p>Okay, it's late, and I'm trying to get up to speed with how I put things together in MOTR's wrappers.
I'm going to list the stuff that looks necessary to see if it gets everything I need to know, into my head.</p>
<ul class="simple">
<li>A subclass of <tt class="docutils literal">Program</tt>.</li>
<li>An <tt class="docutils literal">adaptor</tt> around a <tt class="docutils literal">ParameterLabel[PathWith[SomeEnvironmentArgs]]</tt>.</li>
<li>A <tt class="docutils literal">Label[PathWith[SomeInstallerArgs]]</tt>.</li>
<li>Specify the type of entry point.</li>
<li>An alias to <tt class="docutils literal">CommandBuilder[EntryType, ProgramSubclass, SomeInstallerArgs]</tt>.</li>
<li>An alias to <tt class="docutils literal">OptionBuilder[ProgramSubclass]</tt></li>
<li>An executable wrapper around the installer args label, the command name, and an instance of the entry point type.</li>
<li>The final absolutely-required bit is kind of hard to describe; it pulls together most of the above.</li>
</ul>
<p>Things I'm noticing:</p>
<ul class="simple">
<li>There are some names that I didn't update yet.</li>
<li>Others of the names don't yet have something to update to, but they need to be changed. There are a lot of methods that are (obliquely) named after internal concepts, and it's not obvious from these names why you'd want to ever call the methods.</li>
</ul>
<p>Tomorrow, I'm either going to try to fill in dummy versions of that stuff in the test code, or do something else entirely.
We'll see then.
For now...</p>
<p>Good night.</p>
Weekly Roundup 2022-11-292022-11-29T05:00:00-05:002022-11-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-29:/weekly-roundup-2022-11-29<p class="first last">I think this went pretty well for this time of year. I will not check to confirm.</p>
<ul class="simple">
<li>Wednesday: I didn't get much done because we were on the road.</li>
<li>Thursday: I roughed out some code that I'm really not sure whether it would have worked.</li>
<li>Friday: I figured out that there were other issues with the code, unrelated to whether it would actually work, so I scaled back my changes. I started updating the code base...</li>
<li>Saturday: ...and finished up those updates, had a slightly tricky merge, then started planning where to go next.</li>
<li>Sunday: I started working on those plans, and quickly realized that I'm going to need to rework the public interface of MOTR to make more sense.</li>
<li>Monday: I didn't get much done because we were on the road.</li>
</ul>
<p>Next week, I want to consider making a few more changes to MOTR's code, but maybe I'll just move ahead with writing the tests.</p>
Diary 2022-11-282022-11-28T05:00:00-05:002022-11-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-28:/diary-2022-11-28<p class="first last">On the road again again.</p>
<p>We traveled some more today, so I'm not going to try to spin things up for MOTR.</p>
<p>What happened today...
We watched the Roger Corman <em>House of Usher</em>.
It was pretty good, especially by the standards of Roger Corman Poe movies.</p>
<p>Let's see...
Nothing else to report.</p>
<p>Good night.</p>
Coding 2022-11-272022-11-27T05:00:00-05:002022-11-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-27:/coding-2022-11-27<p class="first last">It'd be cool if this were obvious <em>a priori</em>, but <em>a posteriori</em> is better than nothing.</p>
<p>I started putting together dummy instances of the various protocols that need to be implemented for a new MOTR... um... middle-end?
There are two directions to go from here:</p>
<ul class="simple">
<li>Let's see what's absolutely necessary from looking at the existing modules for wrapping third-party utilities.</li>
<li>If it's a little inconvenient and fiddly for me to implement this stuff in an internal testing library, it'll be so much worse for hypothetical third-party maintainers.</li>
</ul>
<p>Now, I'm not imagining that anyone else is going to want to use MOTR—certainly not in its current state, and, in terms of simple probability, probably not after I've tried to polish it up some—but the <em>entire point</em> of MOTR is for me to get deep into its guts for the past few years or whatever, so I can avoid going to the same effort for other projects.</p>
<p>A quick review of the general user profiles:</p>
<ul class="simple">
<li>Someone who doesn't care about any of the internals; some other project is using MOTR, and they rely on the maintainer to work out how it should all fit together, and document any quirks of usage.</li>
<li>A project maintainer, who should be able to write a concise motrfile from built-in and third-party wrappers, which provide well-defined extension points for things like plugin arguments.</li>
<li>A wrapper developer, who should be able to write straightforward wrappers around third-party utilities.
(The current state of the wrappers shows the "straightforward" part to be, um, <em>deeply</em> aspirational.)</li>
<li>Me, who is secretly all of the others as well.</li>
</ul>
<p>The problem with the current <tt class="docutils literal">api</tt> module is that it's approximately the motrfile helper code that you need if the wrapper code <em>does not exist</em>, which it didn't at the time, but now it does.
Mostly.</p>
<p>Anyway, I think in order to move forward, I'm going to want some kind of separate modules for the two use cases.
Ideally, the built-in wrappers can simply use the module for third-party wrappers.</p>
<p>Something like...</p>
<ul class="simple">
<li>Here is a module that allows you to define environments and installers</li>
<li>Here is a module that allows you to write wrappers around Python scripts</li>
<li>Here is a module that allows you to write a motrfile using wrappers</li>
</ul>
<p>And the existing monolithic folder that contains basically all of that needs to be split up.</p>
<p>I'll look into that after I've gotten coverage properly up.
For now, I want to finish this entry <em>before</em> it gets really late.</p>
<p>Good night.</p>
Coding 2022-11-262022-11-26T05:00:00-05:002022-11-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-26:/coding-2022-11-26<p class="first last">It's really gratifying that there weren't problems where there weren't supposed to be problems.</p>
<p>Okay, I got some solid work in on MOTR today.
I finished up the typing issues, fixed some minor formatting issues, and had no test issues, which is a good sign, because I shouldn't have been changing any behavior.</p>
<p>There were some issues with the merges.</p>
<ul class="simple">
<li>The first merge had the issue that it was not a merge, because I hadn't diverged from an ancestor, so instead I had to, from the changed topic, mark the current topic as the ancestor topic, and add an empty commit.
I feel like there should be a better way to do that, in terms of ergonomics, and there probably is; I just didn't ask.</li>
<li>The second merge was more of a straightforward "there are pervasive changes in the code that are right next to each other, and the diff algorithm decided to be cautious".</li>
</ul>
<p>Anyway, now I'm feeling good to add tests around this code, now that the types for it make a bit more sense.
To review what I need to start with:</p>
<ul class="simple">
<li><tt class="docutils literal">InstallerArgs</tt> instance</li>
<li><tt class="docutils literal">EnvironmentArgs</tt> instance</li>
</ul>
<p>There are some other things, but I don't want to think too hard right now.
Once I've had some more sleep, I can review the relevant code, now that I've messed with it, and figure out the right way to access the relevant classes and functions.</p>
<p>For now, I need to get ready for bed.</p>
<p>Good night.</p>
Coding 2022-11-252022-11-25T05:00:00-05:002022-11-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-25:/coding-2022-11-25<p class="first last">Discarding ideas that didn't quite work. Maybe I'll be able to re-satisfy their purpose, if I can show that I need to.</p>
<p>Okay, I wasn't able to focus all that well today, and I'm going to blame Thanksgiving for that.
Now, let's see what I've got...</p>
<p>I thought some about that snippet I posted yesterday, and tried to fix it up a bit.</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MultiInstaller</span><span class="p">(</span><span class="n">Protocol</span><span class="p">[</span><span class="n">TInstaller_contra</span><span class="p">]):</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">MultiInstaller</span><span class="p">[</span><span class="n">TInstaller</span><span class="p">],</span> <span class="n">__key</span><span class="p">:</span> <span class="n">Type</span><span class="p">[</span><span class="n">TInstaller</span><span class="p">])</span> <span class="o">-></span> <span class="n">TInstaller</span><span class="p">:</span>
<span class="o">...</span>
</pre></div>
<p>All right, let's see what it takes to make this happen...</p>
<p>...</p>
<p>Well, I'm trying to do sensible things here, but there are limits.
I'm not totally sure if this is all going to work, but if it does, I'm going to need to rethink some of my decisions.</p>
<p>Either I need to rethink my earlier decisions, or I need to rein in the scope of my changes, which is... not a huge problem, because that means deleting a bunch of code that I don't trust.
Actually, let's try reining stuff in now...</p>
<p>...</p>
<p>Changes are rippling outward.
Either this will end up completely unworkable, or it will be poised to make a lot more sense.
We'll see...</p>
<p>Anyway, it's too late.</p>
<p>Good night.</p>
Coding 2022-11-242022-11-24T05:00:00-05:002022-11-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-24:/coding-2022-11-24<p class="first last">What does this code do? Breaks everything, probably.</p>
<p>So my focus today was... bad.</p>
<p>Let's see what I can do for MOTR, quickly.</p>
<p>So, I took some notes earlier, and there's one idea that they just kind of glossed over, and there's a chance the quick-and-easy implementation of this idea would not work...</p>
<p>Basically, I want a typed mapping <tt class="docutils literal">Protocol</tt> argument that looks something like</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MultiInstaller</span><span class="p">(</span><span class="n">Protocol</span><span class="p">[</span><span class="n">TInstaller_contra</span><span class="p">]):</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">MultiInstaller</span><span class="p">[</span><span class="n">TInstaller</span><span class="p">],</span> <span class="n">__key</span><span class="p">:</span> <span class="n">Label</span><span class="p">[</span><span class="n">TInstaller</span><span class="p">])</span> <span class="o">-></span> <span class="n">Installer</span><span class="p">[</span><span class="n">TInstaller</span><span class="p">]:</span>
<span class="o">...</span>
</pre></div>
<p>This code is pretty fiddly, even if you ignore the fact that it needs weird plugins to work with Mypy.
My major task in the coming days is to evaluate whether that code would actually work; it doesn't quite fit with the other usages of <tt class="docutils literal">TypedMapping</tt>, and it could be just different enough to fail typechecking.</p>
<p>If that doesn't work, I'm going to need to work out some of the <tt class="docutils literal">TypedMapping</tt>-like stuff that I want from scratch.</p>
<p>It's kind of a pain, but if I can get this to work, it will make some of the new code both more robust and powerful, and easier to understand, in an area that sorely needs robustness and comprehensibility.</p>
<p>Anyway, it's way late and I need to wrap up.</p>
<p>Good night.</p>
Diary 2022-11-232022-11-23T05:00:00-05:002022-11-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-23:/diary-2022-11-23<p class="first last">On the road <em>again</em>...</p>
<p>We traveled <em>more</em> today, and so I'm kind of out of it.
On the plus side, I've got some experimental changes to MOTR planned that should address some of the misgivings I have about the current versions of the type hints.
Hopefully, I'll be up for trying them out in a side topic tomorrow.</p>
<p>Anyway, I shouldn't be procrastinating like I am, so this post is getting the short end of things, as it were.</p>
<p>Good night.</p>
Weekly Roundup 2022-11-222022-11-22T05:00:00-05:002022-11-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-22:/weekly-roundup-2022-11-22<p class="first last">So close to making test improvements! How exciting!</p>
<ul class="simple">
<li>Wednesday: I made some obvious improvements to MOTR's code.</li>
<li>Thursday: I started to refresh my memory on how some of MOTR's new code holds together. I came up with some unfortunately-complicated ideas about how to make certain areas of the code reusable.</li>
<li>Friday: I came up with some much less complicated ideas, that should suffice for now.</li>
<li>Saturday: After focusing on the improvements side of things, I decided to take a look at the uncovered code in MOTR. In my experience, such code is suspect, because it tends to be the case that I'm not <em>manually</em> exercising uncovered code. Sadly, this part of the code is very elaborate and hard for me to follow without walking myself back through things.</li>
<li>Sunday: I started planning out how to write tests for specific areas of uncovered code.</li>
<li>Monday: I was not up for working on this stuff, so I tried to take things as easy as I could manage, which is... eh, not very, when I only think to check how I'm doing at the end of the day.</li>
</ul>
<p>Next week, I'm going to be traveling some for the holidays, but hopefully I'll get some time to actually touch the code.</p>
Diary 2022-11-212022-11-21T05:00:00-05:002022-11-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-21:/diary-2022-11-21<p class="first last">Sometimes life messes with you in tiny, insignificant ways that still add up.</p>
<p>I could start on the work I set myself for improving MOTR's tests, but I don't feel like it currently.
I've got a headache right now, and I just want to lie down and shut out the world for a bit.</p>
<p>I sat around for a bit to see if I'd think of something else to write, and I did not, so I'm going to stop pushing myself for tonight.</p>
<p>Good night.</p>
Coding 2022-11-202022-11-20T05:00:00-05:002022-11-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-20:/coding-2022-11-20<p class="first last">It would be cool if I could <em>remember</em> that this is how stuff works, but oh well.</p>
<p>Unfortunately, I didn't get started until late today.
Fortunately, I have a bit of time.
So, I'm going to try to lay out what I need to make a <tt class="docutils literal">ParametricCommand</tt> where I don't need to think about how the pip-related stuff works.</p>
<p>The basic <tt class="docutils literal">ParametricCommand</tt> comes from calling <tt class="docutils literal">ParametricCommandMeta.with_adaptor()</tt>.
The argument is a <tt class="docutils literal">ValueAdaptor[PathWith[EnvironmentArgs]]</tt>.
The calling object is a <tt class="docutils literal">ParametricCommandMeta[TEntry, TProgram, TInstallerArgs]</tt>.
So, to make a version of this with test hooks, I need to pick an <tt class="docutils literal">Entry</tt> type, subclass <tt class="docutils literal">Program</tt>, and create custom implementations of <tt class="docutils literal">InstallerArgs</tt> and <tt class="docutils literal">EnvironmentArgs</tt>.
(It seems slightly unfortunate that the types of <tt class="docutils literal">InstallerArgs</tt> and <tt class="docutils literal">EnvironmentArgs</tt> implementations don't interrelate in any sensible way, but I don't think I can deal with that without higher-kinded types or a deep redesign, which may be called for.)</p>
<p>There's a bit more to be done around this stuff, but it should be really easy to make basic implementations, since I don't <em>think</em> the implementations need to "actually do anything".</p>
<p>In any case, I've run out of time for now, so I'm going to wrap up for now, and try to work on this in the coming days and weeks.</p>
<p>Good night.</p>
Coding 2022-11-192022-11-19T05:00:00-05:002022-11-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-19:/coding-2022-11-19<p class="first last">At least I know what these bits of dead code are <em>for</em>.</p>
<p>Okay, I've got a bit more time.
Let's see about improving MOTR.</p>
<p>After doing some planning for rewrites, I decided to take a look at coverage misses, because I'm currently blocking these rewrites on getting the coverage up.</p>
<p>One really prominent set of coverage misses focuses around the <tt class="docutils literal">EnvVar</tt> class, which it looks like I'm currently not using at all.
<tt class="docutils literal">EnvVar</tt> is one of three wrapper classes that go around a <tt class="docutils literal">Flex</tt>.
These wrapper classes take the value in the <tt class="docutils literal">Flex</tt>, and inject it into the generated command in various places.
<tt class="docutils literal">EnvVar</tt> is for injecting a <tt class="docutils literal">Flex</tt> value into an environment variable.
I don't know offhand of a program that works that way, but I think I shouldn't discount the possibility.</p>
<p>As far as testing this behavior, I <em>could</em> try to verify the actions of the functions directly, but I should be looking into verifying the design, and I'd like to try and verify the intended higher-level behavior, which is that you can't "double up" on a <tt class="docutils literal">Flex</tt>'s value by parameterizing <em>fewer</em> variables than the <tt class="docutils literal">Flex</tt> contains.</p>
<p>Let's see what this looks like...</p>
<p>The <em>fundamental</em> range of behavior is between <tt class="docutils literal">FlexIn</tt> and <tt class="docutils literal">FlexOut</tt>, because <tt class="docutils literal">LessFlexOut</tt> should mostly act like a <tt class="docutils literal">FlexIn</tt>.</p>
<p><tt class="docutils literal">FlexIn</tt>: here is a specific range of values that something else generated.</p>
<p><tt class="docutils literal">FlexOut</tt>: here is a means of generating values.</p>
<p>The basic check here is that there is:</p>
<ul class="simple">
<li>Every command gets exactly one value for the <tt class="docutils literal">EnvVar</tt>, and no <tt class="docutils literal">EnvVar</tt> of a <tt class="docutils literal">FlexOut</tt> produces the same value twice.</li>
</ul>
<p>Thinking about this, I'd kind of rather have some kind of framework for testing this rather than trying to put stuff together ad-hoc.
I'm going to have to spend some time thinking about that.</p>
<p>Anyway, it's late.</p>
<p>Good night.</p>
Coding 2022-11-182022-11-18T05:00:00-05:002022-11-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-18:/coding-2022-11-18<p class="first last">It's unfortunate that I figured this all out hours ago, and then <em>didn't write the post</em>.</p>
<p>Time management mess-up write post quick go!</p>
<p>I figured out a less disruptive way to handle "this use case requires reaching deep into a nested data structure to swap out a sentinel value": because the actual value is a <tt class="docutils literal">Label</tt> that corresponds to a structure involving the implementation of a particular interface, I can implement that interface with a class that's not instantiable.
I don't know for sure if that's how I want to do this long term, but the resulting code should be very close to what I have now, except now I have proper access to "this complicated nested state with a hole in the middle".</p>
<p>Anyway I have to stop writing now.</p>
<p>Good night.</p>
Coding 2022-11-172022-11-17T05:00:00-05:002022-11-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-17:/coding-2022-11-17<p class="first last">Shockingly complicated.</p>
<p>Let's see.
The quickest way to get plans for updating code is to see what corresponds to the updates on the code I haven't written yet.</p>
<p>Um.
I'll try again.</p>
<p>I have three-ish groups of modules that aren't implemented in either topic.
These modules have some correspondence with other modules that <em>are</em> implemented, but I would like to rewrite to some degree.
I feel like it would be "more efficient" if I did the rewrites before bringing in more code that would need equivalent rewrites.</p>
<p>So.</p>
<ul class="simple">
<li>pyinstrument</li>
<li>limit-coverage</li>
<li>coverage subcommands</li>
</ul>
<p>I'm going to try putting detailed notes in the Kanban board, but I'll summarize things here as I go.</p>
<p>Two of these modules will work similarly to <tt class="docutils literal">_api.cli.python</tt>.
So, refresh my memory about what's in there...</p>
<p>Well, this is a little unpleasant.
I look at a helper function with a single statement, and there's just <em>so much</em> to unpack about making the code in question reusable.</p>
<p>Like either I need to break up the data at several levels of abstraction, or I have to create a placeholder that's never supposed to be emitted...
If I could mark the placeholder as "not-supposed-to-be-used", maybe I'd feel better...</p>
<p>Why is this so <em>hard</em>?
Anyway, I'll have to think about this.</p>
<p>Good night.</p>
Coding 2022-11-162022-11-16T05:00:00-05:002022-11-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-16:/coding-2022-11-16<p class="first last">I completely forgot about some of the pointless code in here. So strange.</p>
<p>I did some basic cleanup to MOTR's code today.
The first thing I did was to remove some test code that wasn't accomplishing anything.
The second thing I did was to touch up some of the documentation to remove references to outdated terminology.</p>
<p>Looking over what I have queued up for myself, there are two obvious courses of action:</p>
<ul class="simple">
<li>Triage the majority of modules that I wasn't quite sure what to do with.</li>
<li>Look over the empty files, and figure out what I need to know before I feel comfortable filling them in.</li>
</ul>
<p>In any case, that's not happening tonight.
Maybe later.</p>
<p>Good night.</p>
Weekly Roundup 2022-11-152022-11-15T05:00:00-05:002022-11-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-15:/weekly-roundup-2022-11-15<p class="first last">Once again, definite progress, but <em>really frustrating</em> how much downtime there was.</p>
<ul class="simple">
<li>Wednesday: I started listing files in MOTR that I need to look over.</li>
<li>Thursday: I decided to move those files into a kanban board instead of a blog post. I ended up getting distracted complaining about the various options I found.</li>
<li>Friday: I ended up settling on the option that I had the least complaints about. (Basically, since I'm not planning to share this board, I don't think it should be on Trello taking up space. Much better to take up space on my hard drive, NAS, onsite backups, and offsite backups. (... If you were wondering how I was able to get my laptop working again <em>relatively quickly</em>...))</li>
<li>Saturday: I was stressed out so I tried to take things easy.</li>
<li>Sunday: We traveled, so I tried to take things easy.</li>
<li>Monday: We traveled, so I tried to take things easy.</li>
</ul>
<p>Next week, I'm going to try to actually work through the kanban board, now that I've loaded every file into it.</p>
Diary 2022-11-142022-11-14T05:00:00-05:002022-11-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-14:/diary-2022-11-14<p class="first last">Travel continues to be rough.</p>
<p>And we're back.
Traveling in the opposite direction does not have the opposite effect, unfortunately.</p>
<p>I don't really want to look at my screen, so I'm going to keep the waffling to a minimum.
Hopefully I'll be up for writing more in the coming week.</p>
<p>Good night.</p>
Diary 2022-11-132022-11-13T05:00:00-05:002022-11-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-13:/diary-2022-11-13<p class="first last">This was entirely predictable. Doesn't mean I have to like it.</p>
<p>We traveled today.
I'm not up for writing stuff.</p>
<p>Yesterday, I made some good progress on the task tracking for MOTR.
The big thing I ended up realizing/remembering is that I can't just get the coverage to be all the way up, I also have to actually write a bunch of these modules.
Hopefully, I can also delete some of them.</p>
<p>Anyway, I'm going to shut things down for now.</p>
<p>Good night.</p>
Diary 2022-11-122022-11-12T05:00:00-05:002022-11-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-12:/diary-2022-11-12<p class="first last">Let's see how much I can focus on anything...</p>
<p>I'm writing this entry early, because I want to be ready to go to bed as soon as possible later tonight.
I've been under some stress recently, probably due to the time change, some unusual travel, and a few other factors.</p>
<p>I'd really like to be able to get work done on my various projects, but I can no longer ignore the results of pushing myself to get stuff done.
So, my plan for now is to publish this entry, and get any work that I feel up to done, all around dinner, and then.</p>
<p>Just.</p>
<p>Take.</p>
<p>Things.</p>
<p>Easy.</p>
<p>Good night.</p>
Coding 2022-11-112022-11-11T05:00:00-05:002022-11-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-11:/coding-2022-11-11<p class="first last">I'm starting to really respect the idea of making a function (er, "message receiver"?) into a sentence.</p>
<p>This is quick because I was distracted, but I've added a few more of the files in the project to the board, and one thing I'm noticing about my code is, regardless of whether you believe in self-documenting code, some of the stuff I've written is clearly not.</p>
<p>Like, when these functions have four or five arguments, it should be at least a little clearer what the dang <em>deal</em> is.</p>
<p>I just now got an offline Kanban app working, so we'll see what I think of that going forward.</p>
<p>Anyway, I absolutely have to get ready for bed now, and I'm not sure how much more I'll get done tomorrow or over the weekend, but whatever.</p>
<p>Good night.</p>
Coding 2022-11-102022-11-10T05:00:00-05:002022-11-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-10:/coding-2022-11-10<p class="first last">I should get "I completely forget what I was doing, and cannot justify this situation to my satisfaction." on a t-shirt. Nobody would be able to read it without getting deep inside my personal bubble, but <em>I'd</em> know what it said.</p>
<p>So, I decided to track the files to look at in a kanban board, rather than copy around lists in blog posts.
I've already copied the previous post's information into a Trello board, but then I got distracted because, like,</p>
<p>Trello is <em>fine</em>, and it definitely makes sense if I want to share my board, but for something like this, I feel like ideally I'd like something that:</p>
<ul class="simple">
<li>Is offline and saves to a local file that I can back up myself</li>
<li>Gives me all of the features out of the box without trying to upsell me</li>
<li>Successfully launches</li>
<li>Bonus: lets me pull in my boards from Trello (/Zenkit, which appears to have... a bunch of the same boards as my Trello? I completely forget what I was doing, and cannot justify this situation to my satisfaction.)</li>
</ul>
<p>For some reason, this intersection of requests seems to be <em>overly strict</em>.
And that's gotten me distracted.</p>
<p>At some point, I think I need to try to build this myself, if I think it should be possible to write an offline kanban app that actually works instead of crashing and saying vague and mean things about my GPU, or trying to upsell me.</p>
<p>Anyway, I'm going to try and add a few more cards to the Trello, because Trello is <em>fine</em>.
I should wrap up this post now.</p>
<p>Good night.</p>
Coding 2022-11-092022-11-09T05:00:00-05:002022-11-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-09:/coding-2022-11-09<p class="first last">It doesn't feel great throwing myself under the bus.</p>
<p>A bunch of stuff happened today, but it's all wrapped up.
Now, I want to do <em>something</em> with MOTR.</p>
<p>I ran the tests again to see if anything had broken in the last few days, and it <em>did</em>.
A bunch of the typing tests broke because I had a helper function that, as of today, needs a <tt class="docutils literal">#type: ignore</tt> line on the definition.
But, that was simple to take care of once I figured out that the error that was <em>failing</em> every test wasn't coming <em>from</em> every test.</p>
<p>And now, I've got all of this code to look over.</p>
<p>Nothing specific:</p>
<ul class="simple">
<li>The type plugin code</li>
<li><tt class="docutils literal">_api/cli_types/command_builder.py</tt></li>
<li><tt class="docutils literal">_api/cli_types/entry.py</tt></li>
<li><tt class="docutils literal">_api/cli_types/flex.py</tt></li>
<li><tt class="docutils literal">_api/cli_types/input_accumulator.py</tt></li>
<li><tt class="docutils literal">_api/cli_types/label.py</tt></li>
<li><tt class="docutils literal">_api/cli_types/not_output.py</tt></li>
</ul>
<p>Something specific:</p>
<ul class="simple">
<li><tt class="docutils literal">_api/build.py</tt> needs a documentation update.</li>
<li><tt class="docutils literal">_api/cli_types/command.py</tt> has that helper function that I'm not sure whether it should exist.</li>
<li><tt class="docutils literal">_api/cli_types/installer.py</tt> I vaguely remember thinking that this module should be split up. Maybe.</li>
</ul>
<p>It's late and I'm not up to going over the rest of these.
I ended up getting a little distracted by how weird some of the code I've written looks.
Like, normally, suite of a <tt class="docutils literal">for</tt> loop makes up <em>at least</em> half of the lines of code in the loop.</p>
<p>I'm too tired to process a lot of this for now, so I'm going to just push this onto tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2022-11-082022-11-08T05:00:00-05:002022-11-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-08:/weekly-roundup-2022-11-08<p class="first last">Unpleasant but productive. Let's see about getting rid of that first one, hm?</p>
<ul class="simple">
<li>Wednesday: My attempts to get back to working on MOTR were hindered by the fac that the tests ended up failing, but only sometimes.</li>
<li>Thursday: The bug that was breaking the tests got fixed promptly. I started renaming things.</li>
<li>Friday: I kept up with that, but tried to keep things short because I was writing that entry very late.</li>
<li>Saturday: I took a day off from this coding stuff, and I maybe should have written the post ahead of time, but I didn't.</li>
<li>Sunday: I ended up doing most of the work after I posted, which... not ideal, for various reasons, but it is what it is.</li>
<li>Monday: I did some final cleanup that was needed around the renames.</li>
</ul>
<p>Next week, I've got a bunch of stuff happening <em>during</em> the week, so we'll have to see how I work around that.</p>
Coding 2022-11-072022-11-07T05:00:00-05:002022-11-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-07:/coding-2022-11-07<p class="first last">Simple updates and fixes.</p>
<p>After the last entry, I zoned out and finished the renaming.
Towards the end, I realized that I'd made some changes on the documentation topic that touch code not yet released in the coverage topic.
So, to do The Right Thing in terms of the new interfaces, I switched to the coverage topic and made updates to just those classes, then merged and fixed the conflicts.
The merge was pretty painless, and I'd really like to attribute it to using Mercurial, but realistically, it was probably because I made sure to get it out of the way as soon as I could.</p>
<p>Anyway, next up I'll either be carefully going through each individual file, or I'll think of something new to change that's more targeted.</p>
<p>Either way, I'm done for now.</p>
<p>Good night.</p>
Diary 2022-11-062022-11-06T04:00:00-05:002022-11-06T04:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-06:/diary-2022-11-06<p class="first last">And once again, trying to unwind knocks me flat for a day.</p>
<p>All right.
I spent most of today just kind of relaxing, but I'm feeling okay right now.
Sadly, there isn't time to do much.</p>
<p>I'm going to try to make some updates to MOTR after I publish this, but I'm not feeling up to writing much coherent yet.</p>
<p>I'm just going to cut this here, and encourage everyone not to push themselves too hard, and then I'll try to follow that advice myself.</p>
<p>Good night.</p>
Diary 2022-11-052022-11-05T04:00:00-04:002022-11-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-05:/diary-2022-11-05<p class="first last">I can't think of what to put here.</p>
<p>I was only so-so at taking things easy for most of the day, but oh boy am I taking things easy right now.</p>
<p>I ended up feeling up to doing some work on the latest MOTR rewrite, but I'm going to take a break from that now.</p>
<p>If I can focus tomorrow, I'll get to work on it again.
If I can't, oh well.</p>
<p>Good night.</p>
Coding 2022-11-042022-11-04T04:00:00-04:002022-11-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-04:/coding-2022-11-04<p class="first last">Getting really tempted to start dating these one minute before midnight.</p>
<p>Time management messed up again.
In order to recover, I'm going to need to not work on MOTR tomorrow, then work on it Saturday afternoon.</p>
<p>(Regular reminder that the dates on these posts don't make it very clear which day of the week I'm writing them on.)</p>
<p>Anyway, I am continuing to rework the names in MOTR's core.
I shouldn't try to go into too much more detail now.
(In fact, I should <em>stop working on it for now</em>, but, eh.)
I'll try to summarize how things are going in the entry that I write on Saturday, which will be dated Sunday.</p>
<p>Good night.</p>
Coding 2022-11-032022-11-03T04:00:00-04:002022-11-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-03:/coding-2022-11-03<p class="first last">Adding metaphors to the code so it hopefully takes less work to interpret.</p>
<p>I figured out what was breaking MOTR, and filed a bug upstream.
I'm not proud of the bug, but it got the job done, many thanks to the maintainers.</p>
<p>So, I've got a few minutes, let's see about breaking the tests on purpose.
The big overall change I want to put in for legibility, is to switch from adding "requirements" to a "registry", whatever that is, to putting "facts" into a "compendium".</p>
<p>...</p>
<p>I've gotten the code to typecheck, but there is much more to do, and no time now to do it in.
Over the next few days, I'm going to divide my time between getting other checks to pass, and doing more renames.
There is plenty more to do there, and it feels good to have finally gotten started on all of this.</p>
<p>Good night.</p>
Coding 2022-11-022022-11-02T04:00:00-04:002022-11-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-02:/coding-2022-11-02<p class="first last">I left my code alone for a bit, and when I came back, it was <em>haunted</em>.</p>
<p>I thought I was going to be able to get a little quick work on MOTR, but it ended up not being the quick work I expected.</p>
<p>It seems Pytest made some changes that broke a plugin I was using, until I added an additional requirement, but now I'm getting test failures that feel totally random, even though they're sort of reproducible.</p>
<p>Okay, no, somehow these tests that execute a linear series of actions are behaving non-deterministically.
This is going to bother me for <em>days</em>.</p>
<p>I don't deserve this treatment.</p>
<p>Anyway, I'll work on this later, when I'm better-rested to handle these mysteries.</p>
<p>Good night.</p>
Weekly Roundup 2022-11-012022-11-01T04:00:00-04:002022-11-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-11-01:/weekly-roundup-2022-11-01<p class="first last">Still a little freaked out from whatever broke my old laptop.</p>
<ul class="simple">
<li>Wednesday: I tried to implement a little of what I want for the parser code.</li>
<li>Thursday: Bad time management.</li>
<li>Friday: I tried to rough out a bit more of the support code for parsing.</li>
<li>Saturday: I watched MST3K.</li>
<li>Sunday: I... worked on tabletop roleplaying stuff, apparently.</li>
<li>Monday: I didn't do much worth writing about.</li>
</ul>
<p>Next week, I want to get back to messing around with MOTR, now that my laptop seems to be working somewhat reliably.</p>
Diary 2022-10-312022-10-31T04:00:00-04:002022-10-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-31:/diary-2022-10-31<p class="first last">Another one that's safe to skip.</p>
<p>I ended up messing with other stuff today, and I think I made some interesting progress, but I'll have to give it a bit more time.</p>
<p>I'd like it if I could get myself to put in work on the stuff I have blog tags for, but at least I put in some work on <em>something</em>.</p>
<p>If I can get motivation to work on code stuff, I should try to make changes to MOTR, since I came up with some changes that should clarify things, or at least make them less generic.</p>
<p>Anyway, I let things slip badly again, oh well.</p>
<p>Good night.</p>
Diary 2022-10-302022-10-30T04:00:00-04:002022-10-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-30:/diary-2022-10-30<p class="first last">Apparently, I took things easy today.</p>
<p>I ended up not doing <em>much</em> today, so I'll just pretty much accept that.</p>
<p>One thing I did work some on is something that I've started working on recently with my wife.
I'm trying to start a game of Ironsworn: Starforged, with the idea that I'll be playing it mostly solo, but asking my wife for oracle decisions.
Right now, I'm pinning down the setting and my character's backstory.
This morning, I copied in the setting truths from my notebook to my laptop, so now I can work on collating them and figuring out the implications.</p>
<p>Having my wife make the choices worked out all right in setting up the truths, but I haven't yet tried it with much larger tables.</p>
<p>Anyway, I'm reading over the beginning of the rulebook again to see if there are elements I should be incorporating into my notes.
A bit more work on this stuff, and I should be able to get started.</p>
<p>Anyway, that's all I've got, and I really shouldn't try to come up with more.</p>
<p>Good night.</p>
Diary 2022-10-292022-10-29T04:00:00-04:002022-10-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-29:/diary-2022-10-29<p class="first last">Movies that are shot partially in 3D are weird. Like, separated by decades, they still need to tell the audience when to put on their glasses? Like, you're poking stuff at the screen, you don't need to also break the fourth wall at the same time.</p>
<p>More MST3k tonight.
That movie was a lot (in terms of the special effects sequences) and a little (in terms of the plot).</p>
<p>I'm actually not quite sure when I'll be able to properly ramp up in the things I want to work on.
Stuff is happening this weekend, I think, and over the next few weeks.
Maybe I should just work on getting stuff done in the morning.</p>
<p>Either way, nothing's happening now, and if I don't wrap up, nothing's happening later.</p>
<p>Good night.</p>
Coding 2022-10-282022-10-28T04:00:00-04:002022-10-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-28:/coding-2022-10-28<p class="first last">Apparently, what makes me happy is to just <em>commit</em> to an approach.</p>
<p>Minor technical issue: worked around!</p>
<p>Time management: still in terrible shape!</p>
<p>The next step in my quest to carefully design the environment on which to build stuff in Lua, is to figure out how I want to do stuff like "annotate fields with their name".</p>
<p>My general feeling is that things should work like <tt class="docutils literal">{ { field = <span class="pre">{...}</span> } }</tt>, where there could be many "field" tables, and the <tt class="docutils literal"><span class="pre">{...}</span></tt> corresponds to a table that gets passed to <tt class="docutils literal">converter_function_passed_by_client_code(table.unpack(v))</tt>.
That way, the current behavior of the enum module could be approximated by mapping <tt class="docutils literal">function(field) for k, v in field do table.insert(v, k) end return field end</tt> over <tt class="docutils literal">ipairs(fields_table)</tt>.</p>
<p>There are some issues here.
I think I want to have similar power to <tt class="docutils literal">table.insert</tt>, but doing it like this means that the field tables get modified in place, then collected into a new table, which feels not-quite right.
Like, either it should return a new table without touching the original, or it should update the original table and return the same table.
I don't know which of those I prefer from a pragmatic perspective.
(My gut says "avoid mutations as much as possible", but if I felt that was worth basing my pragmatic stances off of, <em>I wouldn't be doing this in Lua</em>.)</p>
<p>The "don't look inside the sausage factory answer" is to come up with an alternative to mapping over an ipairs that just loops over the table and assigns the result of the mapping function over the existing value, regardless of whether they're the same.</p>
<p>I'm cutting this entry off for now, but now I've got the next question for later:</p>
<p>Is that idea something I'd want to reuse in other contexts, or just some form of utility function I'd want for building up this kind of data?</p>
<p>I'm going to need to phrase this question very carefully, due to the nested structure of the tables, and the number of functions I'd like to have in play.
I'll take about a day to think about this, at least.
For now, I need to get ready for bed.</p>
<p>Good night.</p>
Diary 2022-10-272022-10-27T04:00:00-04:002022-10-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-27:/diary-2022-10-27<p class="first last">It's safe to skip this.</p>
<p>My time management slipped again.
There's no way for me to get out an entry that's any better than this.
I still want to post something daily, technology permitting, but sometimes it's not going to be all that much.</p>
<p>Good night.</p>
Coding 2022-10-262022-10-26T04:00:00-04:002022-10-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-26:/coding-2022-10-26<p class="first last">I'm going to need my laptop to stop being weird for a bit...</p>
<p>Okay, my laptop is still giving me some technical issues, but I'm going to put them in the "annoying, with a planned workaround" bucket for now.</p>
<p>Anyway, I'm still not ramping up super quickly, so for now, I'm just working on parts of the stuff I was planning out two days ago.
I decided to start small, and implement the "ordered fields" helper.
With that, I can have my arbitrary criterion satisfied ("I shouldn't need to quote the field names when I define them") without having to explode out the creation process into a bunch of metamethods that may or may not fully make sense.
While I was at it, I made sure it's possible to have arguments that don't do anything in terms of the final result, so they can act as spacers between groups.</p>
<p>I'm going to have to wait to see what I think of using this code, because it's late, but, like, just make a bit of progress at a time.</p>
<p>Good night.</p>
Weekly Roundup 2022-10-252022-10-25T04:00:00-04:002022-10-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-25:/weekly-roundup-2022-10-25<p class="first last">I am gradually progressing from "painfully stressed" to "just really, really annoyed".</p>
<ul class="simple">
<li>Wednesday: [FOOTAGE MISSING]</li>
<li>Thursday: [FOOTAGE MISSING]</li>
<li>Friday: [FOOTAGE MISSING]</li>
<li>Saturday: I had everything together enough to be comfortable trying to post again.</li>
<li>Sunday: I tried to get back into the Crafting Interpreters stuff, and promptly ended up kind of confused.</li>
<li>Monday: I decided to try biting the bullet and settling on an enum representation that wasn't <em>absolutely as theoretically concise as possible</em>.
Note that I just <em>decided</em>, I didn't actually write any code.
I'm not coming back into this stuff at full speed.</li>
</ul>
<p>Next week, I'm going to try to ramp back up, but maybe I'll just mess around and see if that makes me feel better.</p>
Coding 2022-10-242022-10-24T04:00:00-04:002022-10-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-24:/coding-2022-10-24<p class="first last">Preparing to sacrifice extreme terseness, because otherwise it'll be a pain to implement and have a bunch of mystery bugs.</p>
<p>I know it's pretty basic, but every time I think about this enum stuff, I end up going in circles.</p>
<p>I'm currently leaning towards "the stuff I'm thinking of doing with metamethods is too confusing at every level", so I'm considering other ways to have names in order.
Like, let's compare...</p>
<div class="highlight"><pre><span></span><span class="kd">local</span> <span class="n">ordered</span> <span class="o">=</span> <span class="n">fields</span><span class="p">().</span><span class="n">abc</span><span class="p">.</span><span class="n">def</span><span class="p">.</span><span class="n">ghi</span> <span class="c1">-- Complicated under the covers</span>
<span class="kd">local</span> <span class="n">ordered</span> <span class="o">=</span> <span class="n">fields</span><span class="p">{{</span><span class="n">abc</span> <span class="o">=</span> <span class="p">{}},</span> <span class="p">{</span><span class="n">def</span> <span class="o">=</span> <span class="p">{}},</span> <span class="p">{</span><span class="n">ghi</span> <span class="o">=</span> <span class="p">{}}}</span> <span class="c1">-- A bit wordy</span>
</pre></div>
<p>On reflection, it is wordier, for sure, but it's mostly going to end up on distinct lines anyway, and it gives me a convenient way to make things that contain their name: define a function to process each table, and run it over the table.</p>
<p>I think that gives me something good to try next time around.</p>
<p>I wish I'd gotten further, but to be honest, I'm still not totally sure my laptop isn't going to suffer some horrible failure, only <em>mostly</em> sure.</p>
<p>Anyway, I need to get ready for bed.</p>
<p>Good night.</p>
Coding 2022-10-232022-10-23T04:00:00-04:002022-10-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-23:/coding-2022-10-23<p class="first last">Don't remember what I was doing <em>a month ago</em>? That's okay, neither do I.</p>
<p>I'm not going to get too far with anything tonight, but I want to refresh my memory on the Earley parser stuff.
Looking at the last entry in this tag through the website, I see that I was in the middle of writing some changes to the enum modules I wrote.</p>
<p>My notes there just talk about "taking an iterator", so that's just, like, okay, take the values returned by an iterator function, and then feed them into the... ah, good, the previous Lua post actually explains this stuff.</p>
<p>Let's see, what do I want to call this stuff?</p>
<ul class="simple">
<li>The table that either accumulates or chains names and potentially values can be called <tt class="docutils literal">fields</tt>.
From a purity craze perspective, I'd try for the chaining, but it's probably easier to implement with it just accumulating into a table.
Remembering that the fields need to be required to be strings.</li>
<li>From there, the <tt class="docutils literal">opairs</tt> function I've already written can be used to <em>extract</em> the data.</li>
<li>Something in there needs to handle defaulting arguments that aren't given, but I'm not sure what's the best way to handle that.</li>
</ul>
<p>I think I need to do some planning on paper to properly hash a lot of this out.</p>
<p>Anyway, it's late, and I need to wrap things up.
It wouldn't do to stay up too late on this laptop just as soon as it becomes possible again.</p>
<p>Good night.</p>
Diary 2022-10-222022-10-22T04:00:00-04:002022-10-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-22:/diary-2022-10-22<p class="first last">If you're in my situation, just don't be. *taps forehead*</p>
<p>Well, that <em>sucked</em>.
Several days after my laptop appeared to be working again, it started showing the same issue as before.
At that point, I gave up on it.</p>
<p>I'm writing this entry on a new laptop that I installed linux on from scratch.
Here are some notes:</p>
<ul class="simple">
<li>Not going to get anywhere without disabling secure boot in the BIOS.</li>
<li>I had a number of issues around resume, that may or may not be fixed.
The last thing I tried was to switch from hybrid to discrete graphics in the BIOS, and that <em>seems</em> to have fixed horrible screen issues on resume.
I also disabled the nvidia suspend and resume services, which <em>may</em> have been causing a different set of resume issues.
The other thing I kept was to switch to the proprietary drivers.</li>
</ul>
<p>No obvious problems yet; hopefully I'll manage to publish this entry tonight.</p>
<p>Anyway, the broad takeaway from this isn't any particular technical advice, but "Try to avoid having to do non-mainstream tech stuff to your main electronic device when you don't have some kind of fallback available."</p>
<p>Good night.</p>
Weekly Roundup 2022-10-182022-10-18T04:00:00-04:002022-10-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-18:/weekly-roundup-2022-10-18<p class="first last">Pushing for an update Saturday night ("Sunday" in the entry) was maybe not the best idea, but, um, oh well.</p>
<ul class="simple">
<li>Wednesday: I tried to figure out a proper middle ground between Python and Koka for representing variables.</li>
<li>Thursday: I thought a bit more about that, and concluded I need some more experience with other programming languages.</li>
<li>Friday: I had a bad day for writing/working, so I just kind of punted.</li>
<li>Saturday: I punted deliberately.</li>
<li>Sunday: My laptop got broken so badly that I elected to reinstall the OS from scratch. Getting this done and recovering most of my files took most of the day.</li>
<li>Monday: I wasn't quite done with restoring everything.</li>
</ul>
<p>Next week, I'm going to try to ramp back up on NABTO related stuff and MOTR.
I'll be keeping an eye out for any performance degradation like my laptop was experiencing like before it really broke, but that doesn't seem to be happening.
Which, on the one hand, is good, but on the other hand, I don't know which factors to worry about, since it's mostly the same files, on all the same hardware, and all that's changed is that the system is freshly installed with a new distro version, and the disk layout is different.</p>
Diary 2022-10-172022-10-17T04:00:00-04:002022-10-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-17:/diary-2022-10-17<p class="first last">Still recovering...</p>
<p>I'm still reconstituting my laptop, so I'm not pushing myself too hard yet.
I've taken care of most of the low-hanging fruit, and the backup did <em>a lot</em> of work, so there are only a few notable omissions that I'm just going to leave be for now.</p>
<p>I need to cool off properly, so I'm going to take that time out of writing this entry.
Hopefully, I'll be able to ramp back up soonish.</p>
<p>Good night.</p>
Diary 2022-10-162022-10-16T04:00:00-04:002022-10-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-16:/diary-2022-10-16<p class="first last">Laptop fixed. Updates unpaused indefinitely.</p>
<p>I spent literally all day wrangling my laptop back into a usable state, so I'm not going to do much more for now.
(I haven't actually confirmed that it'll stand up to my typical usage, but it's holding up to stuff that seems <em>comparable</em> to what I was doing when everything broke down.)</p>
<p>I did make some progress planning renames for MOTR, so I can get on with that tomorrow if I'm actually done with fixing things.</p>
<p>(I am not done with fixing things. Publishing this entry is going to require a bizarre command-line invocation, and possibly changes to the publishing script to make it more robust.)</p>
<p>Anyway, I'm going to try to cool off now.</p>
<p>Good night.</p>
Diary 2022-10-152022-10-15T04:00:00-04:002022-10-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-15:/diary-2022-10-15<p class="first last">Trying to get off my own back.</p>
<p>I was planning to take things easy today, and that comes into play now.
We're going to watch a bad movie a few minutes from now, and I'm just going to relax.</p>
<p>Tomorrow, I'll try to have things together, but the plan for now is to chill out.
I'm not going to overthink other stuff to put in this entry.</p>
<p>Good night.</p>
Diary 2022-10-142022-10-14T04:00:00-04:002022-10-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-14:/diary-2022-10-14<p class="first last">Not a very organized day, oh well.</p>
<p>Ugh, where does the time go?
Both in the day, and between the months?</p>
<p>Anyway, I shook things up a very small amount today, and that may or may not explain why I messed up my end-of-the-day schedule.
An alternative explanation is just that I don't have anything new to say about NABTO currently, and so I ended up kind of stalling for a while.
Perhaps there are multiple factors in play.</p>
<p>Anyway I didn't do stuff worth writing about today, but I can plan things out for the next few days:</p>
<ul class="simple">
<li>I'm going to take things easy tomorrow.</li>
<li>After that, I'm going to either catch myself back up on the Earley parser, or start doing programming language tutorials.
Ideally both, I think.</li>
</ul>
<p>Anyway, I should not be writing this this late.</p>
<p>Good night.</p>
Coding 2022-10-132022-10-13T04:00:00-04:002022-10-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-13:/coding-2022-10-13<p class="first last">The low-level details of language design are <em>really complicated</em>, sheesh.</p>
<p>After writing some more jank Koka, I <em>believe</em> that the state of local variables is the same after each call to <tt class="docutils literal">resume()</tt> in Koka.
Maybe there's an obvious reason that it has to be that way, but I was frankly pulling my mind in too many directions at once to be able to tell.</p>
<p>So, let's think some more about how variables should act.
The big hurdle if I <em>do</em> go with "all stack variables are predictably-sized fat pointers to arbitrarily shaped objects on the heap, and there's a reference count somewhere", is that it gets kind of hard to to write a pure function, at least I think so.</p>
<p>Supposing we have a list/vector type that works kind of like in Python, because I think I want that.
It's <em>possible</em> to express read-only semantics for the fat pointers here, but it doesn't actually <em>help</em>, because something else can take a reference to the object and mutate it.
This is what has me thinking "hm, maybe capabilities would be useful somehow".
Like, if a function relies on <tt class="docutils literal">val</tt>, <tt class="docutils literal">box</tt>, and <tt class="docutils literal">tag</tt> type references to external data, then it shouldn't be possible to break purity by changing the objects behind those references, because they can't change from the perspective of the function.</p>
<p>This is complicated, so I'm going to try to break it down into reasonable steps.</p>
<ul class="simple">
<li>"Hey, I want a language that's similarly dynamic to Python, but it has an effet system."</li>
<li>"Well, it's not obvious how to reconcile the effect system with how Python handles writing functions, so it doesn't make sense to work on the object system before addressing that."</li>
<li>"So, I want to be able to write a Koka-pure function that relies on module-level variables."<ul>
<li>This has some weird implications even before I get into trying to implement it, because it implies some way of saying "unlike other functions, this functions is <em>not</em> callable immediately after it is defined, but only after some external condition is met".</li>
</ul>
</li>
<li>"I bet something like Rust or Pony could help with this."</li>
</ul>
<p>So, if I want things to work the way I think I want them to, then I need to be able to implement the following setup:</p>
<ul class="simple">
<li>Variables that are referenced via (probably fat) pointers, to data on the heap that contains some necessary metadata, and the actual data.</li>
<li>The ability to construct mutable variables.</li>
<li>The ability to define functions.</li>
<li>A basic type system.</li>
<li>A basic effect system.<ul>
<li>Which handles mutability of shared state.</li>
</ul>
</li>
</ul>
<p>I won't say that's <em>a lot</em> of the work, but if I can't do that much, then I need to reconsider the entire big picture of the design.</p>
<p>The near-term stuff to do goes as follows, but not in any particular order:</p>
<ul class="simple">
<li>Take more of these notes</li>
<li>Go through Rust tutorials</li>
<li>Go through Pony tutorials</li>
<li>Get back to Crafting Interpreters, and therefore, my Earley parser yak shave.</li>
</ul>
<p>It's good that I have goals, but next up, I need a plan to make sure I actually work on them.
I'll see how that goes.
Anyway, no more to do for today.</p>
<p>Good night.</p>
Coding 2022-10-122022-10-12T04:00:00-04:002022-10-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-12:/coding-2022-10-12<p class="first last">Trying to take things slowly with language design. Very, very slowly.</p>
<p>While I let renaming stuff for MOTR percolate a little, I'm going to consider some thoughts about how NABTO "should" work.
The current topic: how even do variables work?</p>
<p>Let me see if I can explain what has me so unsure.
Consider the following Python code:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">getter_and_setter</span><span class="p">(</span><span class="n">value</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span> <span class="o">-></span> <span class="nb">tuple</span><span class="p">[</span>
<span class="n">Callable</span><span class="p">[[],</span> <span class="nb">int</span><span class="p">],</span> <span class="n">Callable</span><span class="p">[[</span><span class="nb">int</span><span class="p">],</span> <span class="kc">None</span><span class="p">]</span>
<span class="p">]:</span>
<span class="k">def</span> <span class="nf">getter</span><span class="p">()</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
<span class="k">return</span> <span class="n">value</span>
<span class="k">def</span> <span class="nf">setter</span><span class="p">(</span><span class="n">new_value</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
<span class="k">nonlocal</span> <span class="n">value</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">new_value</span>
<span class="k">return</span> <span class="n">getter</span><span class="p">,</span> <span class="n">setter</span>
</pre></div>
<p>Now, I understand Koka just well enough to expect that the relevant type signatures in an equivalent function definition would look somewhat different.
Let's see how things shake out...</p>
<p>So.
This doesn't compile.
But the error it produces is very informative.</p>
<div class="highlight"><pre><span></span><span class="k">fun</span><span class="w"> </span><span class="nf">getter</span><span class="o">-</span><span class="n">setter</span><span class="p">(</span><span class="w"> </span><span class="n">initial_value</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">int</span><span class="w"> </span><span class="k">=</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na na-Variable">_</span><span class="w"> </span><span class="na">(()</span><span class="w"> </span><span class="na">-></span><span class="w"> </span><span class="na na-Variable">_</span><span class="w"> </span><span class="na">int,</span><span class="w"> </span><span class="na">int</span><span class="w"> </span><span class="na">-></span><span class="w"> </span><span class="na na-Variable">_</span><span class="w"> </span><span class="na">())</span>
<span class="w"> </span><span class="k">var</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="k">:=</span><span class="w"> </span><span class="n">initial_value</span>
<span class="w"> </span><span class="p">({</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="n">fn</span><span class="p">(</span><span class="w"> </span><span class="n">new_value</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">int</span><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="k">:=</span><span class="w"> </span><span class="n">new_value</span><span class="w"> </span><span class="p">})</span>
</pre></div>
<p>It would be worth figuring out if it's possible to get this to compile, because I think I want code like this to work in NABTO, but I also want it to have sensible effect typing.</p>
<p>Anyway, the basic thing I learned about Koka from writing that code is that Koka distinguishes between local variables, and heap variables, in terms of the effect system.
My initial, probably faulty read of the compiler error is that a variable has to be allocated on the heap in order to close over it.
I'd be more confident of this, or alternatively know that I have it wrong, if I had a better understanding of how variable allocation is controlled in Koka.</p>
<p>Anyway, this may or may not be moot, because one thing I'm not sure of is whether values in NABTO should act more like Python values, or Koka values.
I'm leaning towards Python (heap allocated, reference counted), but I'm not sure what knock-on effects that has on the design.</p>
<p><em>In any case</em>, my thinking on the above code snippets is that equivalent code <em>should</em> be possible in NABTO, but it <em>should have effects attached to the types</em>.
This is because the returned functions <em>cannot</em> be pure in the Koka sense, so they must have some effect other than raising an exception or diverging.</p>
<p>My intuition about this is, I need to get some experience with how variables work in Koka, and, say, Rust and Pony.
I believe that would cover a good portion of the relevant design space.</p>
<p>Anyway, I need to wrap up for now.</p>
<p>Good night.</p>
Weekly Roundup 2022-10-112022-10-11T04:00:00-04:002022-10-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-11:/weekly-roundup-2022-10-11<p class="first last">It's probably going to take at least a few more weeks before I can be properly proud of MOTR's quality.</p>
<ul class="simple">
<li>Wednesday: I took care of some confusing names in MOTR's core.</li>
<li>Thursday: I updated a type definition and set myself up to fix code for quite a while.</li>
<li>Friday: I got most of the way (or possibly just "most of the way", I don't quite remember) fixing the type errors.</li>
<li>Saturday: I fixed up the types, and set myself the next level of work: fixing the <em>tests</em>.</li>
<li>Sunday: I finished a few other sundry checks and got to work prioritizing other tasks.</li>
<li>Monday: I drilled down from that into prioritizing the TODO comments littering the code.</li>
</ul>
<p>Next week, I'm going to try to nail down the details on some of these TODOs.
And whatever else I feel like.
Maybe try to sketch some stuff out for NABTO.</p>
Coding 2022-10-102022-10-10T04:00:00-04:002022-10-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-10:/coding-2022-10-10<p class="first last">It's not a dealbreaker if I can't come up with better names, but I definitely want to try.</p>
<p>The first thing on that list I put together yesterday was fixing <tt class="docutils literal"># TODO:</tt> comments.
Instead of jumping in at random, I'm going to try to prioritize them.
Some are good to work on now, and others should go on the "release" topic once I've fixed up the coverage.</p>
<p>Soon:</p>
<ul>
<li><p class="first">Reconsider the name of "requirements", at both a type and module level.</p>
</li>
<li><p class="first">Reconsider the name of "registry", at both a type and module level.</p>
</li>
<li><p class="first">Rename <tt class="docutils literal"><span class="pre">(Input|Output).path</span></tt> to <tt class="docutils literal">value</tt>.</p>
</li>
<li><p class="first">Reconsider the names of <tt class="docutils literal">Input</tt> and <tt class="docutils literal">Output</tt>.</p>
</li>
<li><p class="first">I was thinking of renaming <tt class="docutils literal">Target</tt> and related classes to <tt class="docutils literal">Outcome</tt>, but maybe what I want to do is call them <tt class="docutils literal">Artifact</tt>, or something?
I feel like any choice I make is going to have some terminological issues.
Like, <tt class="docutils literal">Target</tt> isn't <em>inaccurate</em>, but doesn't communicate much.
Contrastingly, <tt class="docutils literal">Artifact</tt> gives a clearer picture of the general usage, but doesn't really fit some critical cases.
Looking at both of those choices, <tt class="docutils literal">Outcome</tt> actually just feels like a bad compromise...
Basically, this name should refer to something that can be thought of in three related contexts:</p>
<blockquote>
<ul class="simple">
<li>An effect of a task that can be reasoned about in other contexts, an <tt class="docutils literal">Outcome</tt>.</li>
<li>A condition that must hold in order for a task to start, a <tt class="docutils literal">Prerequisite</tt>.</li>
<li>An externally visible result that the user can request MOTR to provide, currently a <tt class="docutils literal">NamedOutcome</tt>.</li>
</ul>
</blockquote>
</li>
</ul>
<p>Later:</p>
<ul class="simple">
<li>Clean up the pip installer code</li>
<li>Reconsider the name of the <tt class="docutils literal">base_cmd</tt> helper function.</li>
<li>I've got a TODO in the <tt class="docutils literal">parametric</tt> module that I don't remember the context for what I was saying...
Basically, one of the validation helpers on the parametric metadata is meant to determine whether the metadata can be used in an <tt class="docutils literal">InputAccumulator</tt>.
The case in question triggers when the <tt class="docutils literal">multivalue_labels</tt> field has a non-<tt class="docutils literal">None</tt> value.
When that field has a non-<tt class="docutils literal">None</tt> value, that means it contains a collection of labels.
No labels <em>except for</em> the ones in that collection are allowed to take more than one.
That means it's acceptable for the <tt class="docutils literal">InputAccumulator</tt> to accumulate more labels, as long as ultimately, only the <tt class="docutils literal">multivalue_labels</tt> take on multiple values.
I <em>think</em> that means I can just remove the branch that emits the message?
Maybe?</li>
<li>Speaking of <tt class="docutils literal">InputAccumulator</tt>...
Oh yeah, I added a bunch of classes and protocols, and now I don't know if my terminology makes any sense.
But anyway, the only TODO comment I have in there is, <em>I think</em>, about how I'm calling a validation helper where the name of the helper doesn't match the context it's called in, which implies that I need to reconsider the name of the <tt class="docutils literal">not_flex_out_because()</tt> helper, or write an explanatory comment justifying its usage.</li>
<li>There's a pretty basic and more-or-less self-explanatory TODO in <tt class="docutils literal">parametric_command</tt> that's waiting for proper test coverage.</li>
<li>Bonus thought: <tt class="docutils literal">cli_types</tt> doesn't seem like a good name?</li>
</ul>
<p>I can make some of the "soon" changes easily enough, but others I feel like I need to take more time to consider them.</p>
<p>...</p>
<p>Update from the end of the night: I did the <tt class="docutils literal">path</tt> to <tt class="docutils literal">value</tt> renames because they were trivial, but I need to give some more thought to the others.</p>
<p>Good night.</p>
Coding 2022-10-092022-10-09T04:00:00-04:002022-10-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-09:/coding-2022-10-09<p class="first last">Sure, it all acts basically the same, but it's all, like, cleaner on the inside.</p>
<p>I got MOTR to run on the new branch as well as it's going to, after fixing up <em>a lot</em> of code and tests.
And now I'm figuring, why not just hit the rest of the TODOs next, and clean everything up as well as I can?</p>
<p>This is a little unfortunate.
I did a bunch of work earlier today, but now I'm writing it up at the last moment, so I'm just kind of like "Yeah, I did a lot of stuff, a few hours ago, so it's not fresh in my mind any more."</p>
<p>I do remember that I did run into some issues with how I was doing mocking, but it was fortunately pretty isolated, and I came up with a not-great solution that's good enough.
The fundamental issue there is that I didn't have "code that I owned" at the place that I wanted to mock.
Actually, that does suggest a possibility for addressing this in a more principled way: create an internal-ish helper function that wraps the third-party code in question, and mock that.
Before I get into that, I should see if there's a better way to write the tests in question.</p>
<p>See, one thing that I ended up discovering while I was fixing test code, is that I've let the test code kind of lag behind how I want to use this stuff, and when I make the sensible updates to make it consistent, it also gets a bit more robust to the changes I was making, which is fortunate.</p>
<p>So, here's the general idea for what kind of changes I want to make next:</p>
<ul class="simple">
<li>Address <tt class="docutils literal"># TODO:</tt>s.</li>
<li>Re-evaluate tests.</li>
<li>Maybe tweak the code a bit more.</li>
<li>Address all pylint messages.
(Possibly by adding more ignores.)</li>
<li>Set up documentation generation.</li>
<li>Develop plan for extending test coverage on "release" topic.</li>
<li>Execute plan, then merge to "future" and address any conflicts.</li>
<li>Cut patch release.</li>
<li>Update motrfile from release.</li>
<li>Merge to "future".</li>
<li>Cut minor release.</li>
</ul>
<p>That seems like a lot, but all of these quality improvements should hopefully make it easier to handle writing new tests against the "release" topic's code.
Not in any kind of direct material sense, just that I won't get distracted going "But the code could be so much better", because it <em>already is</em>.</p>
<p>Anyway, I let things go too late, so I'm going to cut things off awkwardly and abruptly.</p>
<p>Good night.</p>
Coding 2022-10-082022-10-08T04:00:00-04:002022-10-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-08:/coding-2022-10-08<p class="first last">Just needed some time to be totally sure that the easy solution was probably the right one.</p>
<p>Okay, the code in MOTR passes type checking.
Now, I need to fix a whole bunch of test failures as a result of messing with all of the interfaces.</p>
<p>It turns out that fixing the type errors wasn't too bad, because I punted on "how do I tell the user what went wrong in the event of a task aborting the execution?".
I think the answer there is to take some of the code I wrote for the custom build task, and turn that into proper library code.</p>
<p>Anyway, I had too much screen time today, and it's late, so I'm going to wrap up earlier than usual and try to recover.</p>
<p>Good night.</p>
Coding 2022-10-072022-10-07T04:00:00-04:002022-10-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-07:/coding-2022-10-07<p class="first last">Closing in on being ready for a commit.</p>
<p>Another day of spotty time management.
I did, however, fix all of the easy type errors around switching MOTR to using multiplexers.
What remains now is the entry point that actually uses all of this.
I'm going to need to make some decisions about how the data <em>gets back out</em> of the tasks, now that I've completely changed how it's handled inside them.
This might need some new helper methods, we'll see.</p>
<p>Anyway, progress, that's good.</p>
<p>Good night.</p>
Coding 2022-10-062022-10-06T04:00:00-04:002022-10-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-06:/coding-2022-10-06<p class="first last">After this, I might finally try to fix signals just to get that over with.</p>
<p>I messed up time management, so let's see if there's anything I can do quickly.</p>
<p>Well, I can update the type definitions of a <tt class="docutils literal">Task</tt> and break everything...</p>
<p>And now everything is broken, but it looks like generally a pretty simple fix.
One thing I've held off on is deciding whether or not the <tt class="docutils literal">Execution.multiplexer</tt> field should have a default.
I can't think of a reason not to, but I want to hold off from committing to it for now.</p>
<p>So, plan for tomorrow:</p>
<ul class="simple">
<li>Fix the messages out of Mypy.
This will be interesting in terms of fixing the callers into the code, because I've just completely changed the interface for retrieving completed streams.</li>
<li>Decide whether I want to default the multiplexer field.</li>
</ul>
<p>Once those are taken care of, it's time to start documenting until I find something that offends my sensibilities again.</p>
<p>Anyway, it's way too late and I'm going to try to get ready for bed as soon as I can.</p>
<p>Good night.</p>
Coding 2022-10-052022-10-05T04:00:00-04:002022-10-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-05:/coding-2022-10-05<p class="first last">The chaos is settling down, for the moment.</p>
<p>All right, let's see...
I completed a round of renaming, but I still want to work through more.</p>
<p>Right now, I'm trying to figure out what to name two internal and low-level classes, because the current names are really unintuitive.</p>
<p>Basically, one class represents, I guess, the ambient state of a single run of MOTR, relating the registry, a reporting interface, the results, and a reference to each running task.
Later, it'll have a stream multiplexer attached to it.</p>
<p>That class uses another class as a helper.
The point of the helper class is to wrap a bunch of helpful boilerplate around the execution of a task; this makes it easier to write task classes or functions, because there's no reason to change this behavior, so third-party (ish) code shouldn't be responsible for implementing it.</p>
<p>I ended up calling them <tt class="docutils literal">Execution</tt> and <tt class="docutils literal">Step</tt>, and renaming some internal classes.
The results are leaps and bounds beyond what there was before, which were the same names as related, but <em>completely different</em> classes elsewhere in the application.
(Some of those classes were also renamed, but just making the name unique wasn't enough.)</p>
<p>That's some good work for today, but there are many more passes to do.
Before I move around, I should probably work on beefing up the documentation here to make sure I still like the names after I've tried to really use them.</p>
<p>Anyway, it's late and I want to wrap up for tonight, so...</p>
<p>Bye.</p>
<p>Good night.</p>
Weekly Roundup 2022-10-042022-10-04T04:00:00-04:002022-10-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-04:/weekly-roundup-2022-10-04<p class="first last">I did stuff! Some of it was probably not worth the opportunity cost in, like, sleep.</p>
<ul class="simple">
<li>Wednesday: Now that I can make any change to MOTR that I want to, without worrying about breaking the motrfile, I fixed what is basically a tiny cosmetic issue with the code.</li>
<li>Thursday: I started laying out the types that I want to use with MOTR going forward.</li>
<li>Friday: I realized that I wasn't <em>done</em> laying that stuff out.</li>
<li>Saturday: I fixed the most obvious issues I saw with my initial ideas there.</li>
<li>Sunday: I, unfortunately, did things all at the wrong time, but I put together a prototype of those new classes.</li>
<li>Monday: I took the time to figure out what was <em>definitely</em> wrong with that code that I prototyped as fast as I could, late at night.
Then I started renaming classes and attributes in the broader codebase.
Everything in this topic is all messed up, but that's what it's <em>for</em>.</li>
</ul>
<p>Next week, I'm going to continue on with the cleanup, and hopefully <em>try</em> to handle screentime and sleep better.</p>
Coding 2022-10-032022-10-03T04:00:00-04:002022-10-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-03:/coding-2022-10-03<p class="first last">I think some of this is not getting a good night's sleep after the latest round of vaccines.</p>
<p>MOTR status: I fixed the obvious issues with the code I prototyped last night, and then I got excited about doing renames, and everything is broken, but I'm already happy with how it'll be when I get it to <em>stop</em> being broken.</p>
<p>I'm not going to try to push this past the hour mark, so that's about it.</p>
<p>Good night.</p>
Coding 2022-10-022022-10-02T04:00:00-04:002022-10-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-02:/coding-2022-10-02<p class="first last">I'll be honest, I can't think of anything to say here, and the actual post isn't doing much better.</p>
<p>Quick status update on MOTR, because my time management is backsliding.</p>
<p>I've drafted out the improved ideas I had for the multiplexed stream stuff.
It all looks like it should mostly work, and my goal now is to make that statement less qualified.
I need tests of the behavior, that cover all of the ways things could go wrong.</p>
<p>I think there are also some edge cases that I'm not properly handling, because I'm not sure what properly handling them looks like.</p>
<p>It probably wasn't the best decision to put in all of this work so late at night, but I wanted stuff to be put together and working <em>now</em>, dangit.</p>
<p>Anyway, no point in messing around any longer.
I'll try to explain what I did in proper detail later.</p>
<p>Good night.</p>
Coding 2022-10-012022-10-01T04:00:00-04:002022-10-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-10-01:/coding-2022-10-01<p class="first last">Taking things a bit slow, partly because I didn't get very good sleep last night.</p>
<p>Okay, after I published yesterday's entry, I spent some time thinking, and found a way to make the public interface nicer, and the internal interface easier to implement.</p>
<p>So, the other side of things is how to set up the <tt class="docutils literal">ReceiveStream</tt> interface.
I was testing earlier today, and attrs classes, even frozen ones, appear to work fine as keys of <tt class="docutils literal">WeakKeyDictionary</tt>s
So, that'll work for my purposes, in concert with a few other options.</p>
<p>I don't have time to try this stuff out right now, since there are some other things planned for tonight, but I should be able to put it all together by tomorrow afternoon.</p>
<p>For now, I'm going to take things easy, as planned.</p>
<p>Good night.</p>
Coding 2022-09-302022-09-30T04:00:00-04:002022-09-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-30:/coding-2022-09-30<p class="first last">Try something out. Instantly encounter problems.</p>
<p>I tried to dive right into the stream multiplexer stuff, and I discovered that my initial sketch of a design has... problems.
So far, I've identified two major things that need to be addressed.</p>
<p>One is that I'm trying to express the underlying keys in terms of tuples of strings, but the public interface in terms of strings.
So does the protocol just, like, have methods with <em>both</em> signatures?</p>
<p>The other is that I hadn't thought too hard about how to implement "a <tt class="docutils literal">trio.abc.ReceiveStream</tt> subclass where instances are backed by a concrete multiplexer, and each instance pulls from the same memoized bytes, keeps track of its place, and awaits more data if it reaches the end".</p>
<p>I've got some ideas here, but I don't think they're going to come together in the next few minutes, so I'm just going to sleep on this for a bit.</p>
<p>Good night.</p>
Coding 2022-09-292022-09-29T04:00:00-04:002022-09-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-29:/coding-2022-09-29<p class="first last">Still working on finding the right pace, but at least I can ramble.</p>
<p>All right, I had some fun yesterday, time to have a bit more.</p>
<p>Right now, the definition I want to mess with is <tt class="docutils literal">RuntimeAction = <span class="pre">typing.Callable[[],</span> typing.Awaitable[tuple[_result.Result, typing.Mapping[str, <span class="pre">str]]]]</span></tt>.
I want it to look more like <tt class="docutils literal">Task = <span class="pre">typing.Callable[[Something],</span> typing.Awaitable[_result.Result]]</tt>, where <tt class="docutils literal">Something</tt> is an interface that takes a stream name and a stream.</p>
<p>So, since this stuff is pretty tightly wedded to trio internals, then we have that the "stream" argument must be a <tt class="docutils literal">trio.abc.ReceiveStream</tt>, and there are a few operations that I want to support using them.
One is for calling code to enter a stream name, and block until that stream completes, then cache and return the result.
The other is to have some kind of "wrapper" implementation of the interface, that has a "prefix" that it adds to calls of the underlying implementation.
So, let's suppose that stream names are non-empty tuples of strings.</p>
<p>And...</p>
<p>I got distracted by other things.
So, let's plan this for later:</p>
<ul class="simple">
<li>New module defining the interface, and two implementations:
Concrete and wrapper.</li>
<li>Interface handles associating the streams to a key, and caching their data.
Consumers of the interface <em>should not</em> interact with the stream directly after they pass it in.</li>
<li>Call it <tt class="docutils literal">StreamMultiplexer</tt> or something.</li>
<li>The module goes in <tt class="docutils literal">core</tt>.</li>
</ul>
<p>I think this all makes sense.
At least, I think so now.
We'll see about later.</p>
<p>Good night.</p>
Coding 2022-09-282022-09-28T04:00:00-04:002022-09-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-28:/coding-2022-09-28<p class="first last">Nice to get rid of these lines that I didn't write, that don't do anything useful. A little annoying that I didn't notice they were there for quite some time.</p>
<p>All right, making changes to the future branch of MOTR.
I could work on the documentation, or I could address some bits in the code that just annoy me when I think about them...</p>
<div class="highlight"><pre><span></span><span class="gh">diff --git a/src/motr/motr_app.py b/src/motr/motr_app.py</span>
<span class="gd">--- a/src/motr/motr_app.py</span>
<span class="gi">+++ b/src/motr/motr_app.py</span>
<span class="gu">@@ -15,7 +15,6 @@ if typing.TYPE_CHECKING:</span>
<span class="w"> </span># configuration defaults
<span class="w"> </span>CONFIG = init_defaults("motr")
<span class="gd">-CONFIG["motr"]["foo"] = "bar"</span>
<span class="w"> </span>class MOTR(App):
<span class="gh">diff --git a/src/motr/templates/command1.jinja2 b/src/motr/templates/command1.jinja2</span>
deleted file mode 100644
<span class="gd">--- a/src/motr/templates/command1.jinja2</span>
<span class="gi">+++ /dev/null</span>
<span class="gu">@@ -1,4 +0,0 @@</span>
<span class="gd">-</span>
<span class="gd">-Example Template (templates/command1.jinja2)</span>
<span class="gd">-</span>
<span class="gd">-Foo => {{ foo }}</span>
</pre></div>
<p>Aw, yeah, that's the good stuff.</p>
<p>The next thing I'd really like to look into is fixing up the signal handling interactions, but that could take a while and it's late, so instead, I'll figure out what I want to focus on first.
Probably the revamp of runtime actions/tasks/whatever.
That should be fiddly, and break everything before making it better, and I want to be sure it actually works.</p>
<p>First I get that working, then I get it documented.
Then I start documenting things one level up.</p>
<p>For now, I'm going to wind down for a while.
Still working on getting a good schedule together...</p>
<p>Good night.</p>
Weekly Roundup 2022-09-272022-09-27T04:00:00-04:002022-09-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-27:/weekly-roundup-2022-09-27<p class="first last">I finally got tired of putting off fixing the names.</p>
<ul class="simple">
<li>Wednesday: I planned out a more general way of creating "enums" for the Lox interpreter.</li>
<li>Thursday: I did a little work on that plan.</li>
<li>Friday: I got back to MOTR, and investigated the coverage gaps.</li>
<li>Saturday: I tried to come up with a good way to address some coverage gaps.</li>
<li>Sunday: I tried to come up with a different way. When I tried actually plugging the gap, the result did not bring me joy, which kind of calls into question how helpful these "helpers" are.</li>
<li>Monday: I decided to change tack a bit, by documenting the code as I want it to be, and introducing changes to the release-like code that accord with insights I gain from documentation.</li>
</ul>
<p>Next week, I'm going to slowly work on spinning up documentation stuff.
And maybe get back to Crafting Interpreters.</p>
Coding 2022-09-262022-09-26T04:00:00-04:002022-09-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-26:/coding-2022-09-26<p class="first last">Thinking I'm wrestling with Mercurial, when actually I'm wrestling with <em>my intuitions</em>.</p>
<p>I was thinking about how bad it feels that I'm trying to push through covering code that I no longer fully understand, <em>but</em>, if I try to make the code clearer, that means breaking internal compatibility post-release, until I re-update my motrfile.</p>
<p>So, I can't update my code if I don't understand it, but I can't make it understandable without updating it.</p>
<p>Right now, I'm going to see if I can make a way around that conflict.</p>
<p>First off, I'm considering full test coverage non-negotiable.
I find horrible bugs in non-covered lines shamefully often, so I'm going to keep that check on.</p>
<p>Now, going forward, I want full Pylint runs.</p>
<p>But here's the thing I'm going to try changing: I'm going to develop in multiple topics.
Here's what I'm thinking:
I branch a "future" topic off of the current horribly bloated main development topic.
In that topic, I focus on documentation and code updates.
Whenever I properly understand some high-level code, I switch back to the topic I'm on now, which is called, um, <tt class="docutils literal"><span class="pre">input-map</span></tt>, and appears to contain... the majority of the commits in the repository... and is nearly a year old.</p>
<p>All right, so <em>first</em> I'm going to try to close out the related bugs, make a tracking issue for test coverage, and make a new topic based off that.
I'll disable pylint in the test-coverage branch, then make the "future" branch, and re-enable pylint there.
This new topic is for source code changes only.
Increases to test coverage go in the test coverage topic, and then get merged into future.
The desired end state is that both topics pass MOTR completely, and future is descended from every commit in test coverage.
That way, I can cut an 0.1.6 release from test coverage, then create a new tracking issue to update the motrfile.
Merge that into future, address the conflicts, and cut 0.2.0 from the future, turning it into the past!</p>
<p>It couldn't be simpler!
... To gloss over a large amount of work, especially for just one developer, but whatever, I feel better about this plan than about what I was doing before.</p>
<p>Let's break this down a little.
Regardless of what I do in the medium term, it can only improve things to clean up the state of the issue tracker and get the towncrier files in order.
I'm going to just list the bugs it looks like I need to close out:</p>
<p>51 through 55 are questionable, and I'd rather put them in the 0.2.0 push, in that I've started on them, but I'm not <em>entirely</em> done until the motrfile is rewritten.
Note that this is excepting 53, which is <em>complete</em>, and the thing that the current topic is <em>named after</em>.
I also haven't done 66, and that kind of needs to happen at some point.</p>
<p>56, 57, technically 58, technically 59, 60, 62, 63, 64, 65 I think, 77 is started but I'll be able to do much better when I bump the Python version requirement.</p>
<p>So, it'll be pretty quick to get that housekeeping done, so I'll take care of it now...</p>
<p>On further reflection, I ended up only marking a few issues as properly done, but I should be able to move forward now.</p>
<p>Okay, I made the topics, and... I am having trouble.
I forget how to make changes show up in multiple topics, or if that even makes sense, so let's see...</p>
<p>I'm very confused, and this might not be an intended workflow.
A bunch of things I tried didn't work, so let's see if I can reason my way to something that does.</p>
<p>...</p>
<p>Dangit.
I was doing everything fine, but I was getting tripped up because the "future" branch is labeled with its issue number, and I <em>already had</em> a documentation issue, so I just used that, so the merge commit is <em>supposed to</em> be in the lower number topic.
This will mess something up at some point, I guess.</p>
<p>But yeah, this all seems to work the way I wanted it to, when I'm not making it overly fancy and confusing myself.</p>
<p>I think I've been trying to pack too much work into my days, so I'm going to space things out.</p>
<p>All right, time to wrap up.
Next time I get to work on this stuff, I'm going to try out some rewrites I've had in my back pocket for months, just waiting for a chance to mess with.</p>
<p>Anyway, I should start winding down now.</p>
<p>Good night.</p>
Coding 2022-09-252022-09-25T04:00:00-04:002022-09-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-25:/coding-2022-09-25<p class="first last">Well, that was a bit disappointing...</p>
<p>With the benefit of a good night's sleep, I realize that it doesn't really make sense for MOTR to support flake8-json, so my next guess for "what is this helper function for" is a pytest plugin of some kind.</p>
<p>Ideally I wouldn't be do this kind of guesswork because I would have <em>written down my reasoning somewhere I can find it</em>, but the best I can do is to try to come up with a plan to avoid this scenario in the future.</p>
<p>Anyway, looks like there are a bunch of candidates in terms of Pytest plugins...
Do I see anything I like...</p>
<p><tt class="docutils literal"><span class="pre">pytest-codestyle</span></tt> isn't something I'd use, but it fits with how MOTR works better than other things I've looked at.</p>
<p>Hm...</p>
<p>The integration looks good in terms of what the code does, but using these interfaces is horribly awkward, which is on me, either then, or now.</p>
<p>It's a pain, but I don't think I can progress on this unless I get the documentation written so I can see a summary of how and why any of this stuff is supposed to be used.</p>
<p>I don't know how much I'll get down tomorrow, but I'll maybe try it over the next week.</p>
<p>For now, I need to wrap up.</p>
<p>Good night.</p>
Coding 2022-09-242022-09-24T04:00:00-04:002022-09-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-24:/coding-2022-09-24<p class="first last">Forcing myself to do something, just, not very much.</p>
<p>Let's see if there are any quick hits I can do with MOTR.
For now, I'm going to sort by <em>least</em> lines missing, and skip the Mypy plugin, as well as validation logic.
So, by those standards, the first module to hit is...
<tt class="docutils literal">python_helpers</tt>.
Okay, let's see what the deal is...</p>
<p>I've got two helper things in here, and I can't remember precisely what either of them is <em>for</em>.
One of them extends the command to be given, and the other creates a <tt class="docutils literal">Static</tt> containing an option for some program.</p>
<p>With the context I'm seeing for the latter one, it looks like the point of that is to bundle up a flag and a plugin package.
I'm blanking on which thing this could be for, but it kind of sounds like a flake8 plugin might fit the bill?
Nothing really jumped out at me as "yes, that is what I was thinking of" when I checked, but <a class="reference external" href="https://github.com/PyCQA/flake8-json">flake8-json</a> looks like a reasonable thing to support.</p>
<p>Sadly, time, and so I'm going to leave this for myself to work on in the morning</p>
<p>Good night.</p>
Coding 2022-09-232022-09-23T04:00:00-04:002022-09-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-23:/coding-2022-09-23<p class="first last">Carefully trying to redefine "late" to mean something sensibly earlier. Also, I forget if I already did this, but whatever.</p>
<p>Ugh, I didn't get things done with the Lox code today, so instead, how about I try to refresh my memory about MOTR's code on the way into the weekend?</p>
<p>Okay, I've got thirteen files that need to have improved coverage:</p>
<ul class="simple">
<li><tt class="docutils literal">motr._api.cli.build</tt>: Missing some failure paths that it's going to take either a rewrite, or some "interesting" mocking to hit...</li>
<li><tt class="docutils literal">motr._api.cli_types.command</tt>: I think this was involved in all of the renames I wanted to do.
There are several paths missing.
Resolving <tt class="docutils literal">Executable</tt> values as environment variables and extra IO, and some unimplemented paths that look obvious from context...
There's also a helper function that needs to be either deleted or renamed.</li>
<li><tt class="docutils literal">motr._api.cli_types.command_builder</tt>: Missing error case, and extending an <tt class="docutils literal">OptionBuilder</tt>, which seems like a sensible thing to do, I think...</li>
<li><tt class="docutils literal">motr._api.cli_types.flex</tt>: Missing unprefixed parent argument, protocol methods on some of the classes, <tt class="docutils literal">FlexOut</tt> with no parent.</li>
<li><tt class="docutils literal">motr._api.cli_types.input_accumulator</tt>: Missing some validation code.</li>
<li><tt class="docutils literal">motr._api.cli_types.installer</tt>: Missing some validation failures.</li>
<li><tt class="docutils literal">motr._api.cli_types.not_output</tt>: These functions are validation helpers, and just need to exercise some failure and happy paths.
Some of the names should be updated as well, which should have mercifully little fallout.</li>
<li><tt class="docutils literal">motr._api.cli_types.parametric</tt>: This is one of the major support modules for the new system.
It's mostly missing coverage on its validation paths, but it's also got partial coverage on a block that I'll need to think about how to address...</li>
<li><tt class="docutils literal">motr._api.cli_types.parametric_command</tt>: Needs to use one of the helper classes it defines, and it's missing an error path.</li>
<li><tt class="docutils literal">motr._api.helpers.python_helpers</tt>: Missing coverage on a helper method and a helper function.
Hopefully it's not too hard to determine when they'd merit usage.</li>
<li><tt class="docutils literal">motr._api.installers.pip</tt>: This module is pulling double duty and should be pulled apart, but in any case, it's mostly missing validation, and the usage of a Python version specified as a string.</li>
<li><tt class="docutils literal">motr.validators</tt>: A validation helper that needs to raise a validation failure, have its documentation retrieved when the decorated function is documented, and when it is <em>not</em> documented.</li>
</ul>
<p>Outside of the main source tree, there's also some Mypy plugin code missing a branch that I'll need to know Mypy better to know if I should write a test or convert it to an assertion.</p>
<p>Aside from the plugin code, I could probably get okay results just writing tests for the files in ascending order of absolute coverage misses.
I just need some order to work through this stuff, that makes enough sense that I don't second-guess myself.</p>
<p>Anyway, it's late, and I want to wrap up.</p>
<p>Good night.</p>
Coding 2022-09-222022-09-22T04:00:00-04:002022-09-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-22:/coding-2022-09-22<p class="first last">Frantically triaging my sleep schedule, but I still got <em>something</em> done. Next time around, I'll try to prioritize sleep, but I panicked.</p>
<p>I let time get away from me today and I need to shut things down asap to recover, so I'm just going to list what I did from the stuff I laid out yesterday:</p>
<ul class="simple">
<li><strong>Prototype of</strong> helper function to create a table that adds names in order, and can optionally associate values to those names.
(Missing: special casing for numerical indices, and detection of duplicate indices.)</li>
</ul>
<p>Still to be done:</p>
<ul class="simple">
<li>New enum module that uses a single-shot callable table, taking an iterator.</li>
<li>enum class</li>
<li>Use the new enum module</li>
<li>Use enum classes</li>
</ul>
<p>Good night.</p>
Coding 2022-09-212022-09-21T04:00:00-04:002022-09-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-21:/coding-2022-09-21<p class="first last">If enum is so great, why isn't there an enum 2?</p>
<p>All right, let's see what I can manage for the Earley parser setup.
I'm focusing on how to represent the rules, which is basically the following structure:</p>
<ul class="simple">
<li><strong>symbols</strong> are either <strong>nonterminals</strong> or <strong>terminals</strong>.</li>
<li><strong>terminals</strong> are token types, and this might finally be what convinces me to try to wire up enum and class stuff.</li>
<li><strong>nonterminals</strong> are keys in the rules table, where the corresponding values are <strong>ordered tables</strong> of <strong>key arrays</strong> mapped to <strong>semantic actions</strong>.</li>
<li><strong>semantic actions</strong> are just callbacks that take the corresponding matches and return <em>something</em>, which is considered to be the value of whatever matches.</li>
</ul>
<p>Well then.
If I think I need to combine enums and classes, let's see how that looks...</p>
<p>There are some other uses of enums that would be simplified if I could figure out some way to pass arguments to the constructor.</p>
<p>The conclusion that I ultimately come to is that my current enum implementation is placing too much effort on semantic minimalism in the calling context.
It can express one style of things very concisely, but it's very difficult to deviate from this.</p>
<p>I'm going to try prototyping something that requires a little more syntax, but should work better with the general code base.</p>
<p>Hm, something's not clicking for me, and I think I need to work through some logic.
There are basically several different ways to assign values to the members of an enum:</p>
<ul class="simple">
<li>The value is a function of just the member's name</li>
<li>The value is a function of the member's position in the overall sequence of members</li>
<li>The value is a function of arbitrary data associated with the member</li>
</ul>
<p>Now, if I want to keep up with my motif of "use iterators a bunch", I could say "instead of a table, the enum constructor should take an iterator, that produces indices, names, and optionally values; if the value is absent, it uses the name".
Then, I can split the current syntactic sugar into a table that accumulates names into an array, a normal table, and applying iterator combinators over existing iterators.</p>
<p>Then, the question is, what combining this decomposed concept with the class code looks like.</p>
<p>So, the New Enum doesn't take an argument, it just returns a table that can be called, exactly once.
This table, and the return value of calling it, is the enum.
It needs to be smuggled into the class creation function, so it can be marked as the type of the instances that will be created when it is called, but it needs to be delegating to the original constructor.</p>
<ul class="simple">
<li>Create the enum constructor</li>
<li>Allocate a local to hold the original class constructor</li>
<li>Write a function to store the constructor in the local, and return the enum constructor</li>
<li>Add this constructor to the class creation arguments, and then return the resulting class, which is actually the enum constructor (which is actually the enum)</li>
<li>The caller must now invoke the constructor with an iterator that provides triples of the form <tt class="docutils literal">index, name, {args}</tt></li>
</ul>
<p>I guess it would kind of make sense for the enum constructor to set itself up like an ordered table, so that the <tt class="docutils literal">opairs</tt> function I wrote can iterate over its members in order.</p>
<p>So, here are the things I need to write:</p>
<ul class="simple">
<li>Helper function to create a table that adds names in order, and can optionally associate values to those names</li>
<li>New enum module that is based around a callable-once table that takes an iterator</li>
<li>Prove these out by replacing the existing enum usages; write any necessary helper functions</li>
<li>New enum class module that properly combines classes and the new enum</li>
<li>Update the usages to switch to the class-based enum</li>
</ul>
<p>Sadly, I was a bit out of it today, so I've once again just got planning, and I don't feel like trying to actually care out these plans right now.
We'll see how tomorrow goes.</p>
<p>Good night.</p>
Weekly Roundup 2022-09-202022-09-20T04:00:00-04:002022-09-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-20:/weekly-roundup-2022-09-20<p class="first last">I decided to take things easy, which meant that my posts got generally longer. This actually makes perfect sense.</p>
<ul class="simple">
<li>Wednesday: I came up with some plans for object-oriented code in my version of the Lox interpreter.</li>
<li>Thursday: I implemented those plans.</li>
<li>Friday: I prepared to add some runtime correctness checks to the interpreter code.</li>
<li>Saturday: I added those checks.</li>
<li>Sunday: I decided that I was tired of implementing top-down parsers, for this, and in general, so let's see how far I can get trying to implement an Earley parser instead.</li>
<li>Monday: I started prototyping the support classes for implementing an Earley parser in pure Lua.</li>
</ul>
<p>Next week, I'm going to try to keep up writing and publishing these posts earlier than before.
It's not, like, a miracle cure, but I think it's helping me regain my focus.</p>
Coding 2022-09-192022-09-19T04:00:00-04:002022-09-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-19:/coding-2022-09-19<p class="first last">One step at a time...</p>
<p>I got some things done today.
Basically, just a prototype for a set of functions for a data structure on top of Lua tables, to store keys and values, but also to maintain insertion order.</p>
<p>That should be part of what I need to be able to incrementally construct the grammar.
I just need to write some more functions that delegate to that as keys in a higher-order table.
And also to work out some way to represent sequences in a way that indexing is comprehensible.
I've done stuff along those lines before, but I'm going to need to think about how I want to do it.</p>
<p>Like, I need a mapping from sequences of values to a canonical representation that (I think) needs to be able to retrieve the values.</p>
<p>Hopefully, I'll have a plan there in a few days.
For now, I need to wind down.</p>
<p>Good night.</p>
Coding 2022-09-182022-09-18T04:00:00-04:002022-09-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-18:/coding-2022-09-18<p class="first last">I feel like my excuse is slightly better this time, but only slightly.</p>
<p>I was thinking pretty hard about trying to beef up my <tt class="docutils literal">enum</tt> function, but initial efforts didn't work, and I decided that trying to combine enums and classes wasn't worth it for now.</p>
<p>Anyway, then I spent most of today in a haze, so I didn't get much else done before now.
I have concluded that I want to change up the stuff that I try to do relative to the tutorial, not because I refuse to do things that way because I know better, but because I've <em>done</em> things that way, and I want a change of pace.</p>
<p>So, I'm trying to figure out what it would take to parse Lox with an Earley parser instead of recursive descent.</p>
<p>Now, I tried to get some hands-on experience with Earley parsers, um, at the beginning of <em>this year</em>, apparently...
Based on <a class="reference external" href="https://loup-vaillant.fr/tutorials/earley-parsing/">this series</a>, which I'll be working from again.</p>
<p>I'm going to take things as they go, so maybe I'll get stuff done tonight, but what I want most is to <em>plan</em> this stuff properly.</p>
<p>Let's see what the current Lox expression grammar looks like in Earley parser terms:</p>
<ul class="simple">
<li><tt class="docutils literal">expression <span class="pre">-></span> equality</tt> (identity)</li>
<li><tt class="docutils literal">equality <span class="pre">-></span> equality <span class="pre">["!="</span> <span class="pre">"=="]</span> comparison</tt> (expr.binary)</li>
<li><tt class="docutils literal">equality <span class="pre">-></span> comparison</tt> (identity)</li>
<li><tt class="docutils literal">comparison <span class="pre">-></span> comparison <span class="pre">[">"</span> <span class="pre">">="</span> "<" <span class="pre">"<="]</span> term</tt> (expr.binary)</li>
<li><tt class="docutils literal">comparison <span class="pre">-></span> term</tt> (identity)</li>
<li><tt class="docutils literal">term <span class="pre">-></span> term <span class="pre">["+"</span> <span class="pre">"-"]</span> factor</tt> (expr.binary)</li>
<li><tt class="docutils literal">term <span class="pre">-></span> factor</tt> (identity)</li>
<li><tt class="docutils literal">factor <span class="pre">-></span> factor <span class="pre">["/"</span> <span class="pre">"*"]</span> unary</tt> (expr.binary)</li>
<li><tt class="docutils literal">factor <span class="pre">-></span> unary</tt> (identity)</li>
<li><tt class="docutils literal">unary <span class="pre">-></span> <span class="pre">["!"</span> <span class="pre">"-"]</span> unary</tt> (expr.unary)</li>
<li><tt class="docutils literal">unary <span class="pre">-></span> primary</tt> (identity)</li>
<li><tt class="docutils literal">primary <span class="pre">-></span> NUMBER</tt> (identity)</li>
<li><tt class="docutils literal">primary <span class="pre">-></span> STRING</tt> (identity)</li>
<li><tt class="docutils literal">primary <span class="pre">-></span> ["true" "false" "nil"]</tt> (identity)</li>
<li><tt class="docutils literal">primary <span class="pre">-></span> "(" expression ")"</tt> (expr.grouping or just identity, except it has to discard the parentheses)</li>
</ul>
<p>Basically, each rule is going to be a non-terminal symbol on the left-hand-side, zero or more symbols on the right-hand-side, and a callback to construct the expression once it knows it has a parse.</p>
<p>(Now, if I can get all of this to work, that means I can drop the final "accumulate" step from the scanner and build everything in an iterator.)</p>
<p>Actually, to make this parse totally work, I do need to <em>handle</em> the EOF token somehow...</p>
<p>Anyway, I let this go too late, so I'm going to cut this here, and think about how to handle the data structures later.</p>
<p>Good night.</p>
Coding 2022-09-172022-09-17T04:00:00-04:002022-09-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-17:/coding-2022-09-17<p class="first last">The code is longer now, but at least it's all optional...</p>
<p>I've wired in a bunch of the stuff I was working on yesterday, and so now the interpreter code has a bunch of run-time correctness checks.
Getting those checks in means that the code is relatively more verbose.
It turns out I don't get to flex <em>as hard</em> on Java if I try to actually deliver all of the functionality that the book's code is relying on.</p>
<p>It occurs to me that, if I put in the work to rework things in a... somewhat confusing way, I can fit my "enum" code into the paradigm of my "class" code, and then I'd get access to isinstance checks for enums.</p>
<p>Anyway, I can't do that right now, because I've got too much else that I want to do right now.
Hopefully I'll get it all together tomorrow.
I'll at least try to plan things out after I post this.
Once this is either implemented or scrapped, I'll try to get into the parser.
I'm not ready to mess with that yet.</p>
<p>Anyway, best wrap things up over here.</p>
<p>Good night.</p>
Coding 2022-09-162022-09-16T04:00:00-04:002022-09-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-16:/coding-2022-09-16<p class="first last">Me working with my own code: "These precious and delicate flowers must be protected from external mutation." Me working with other people's code: "So, I figured out how to install an unoptimized package so I could write breakpoints into the code in site-packages."</p>
<p>Reverse Polish Notation challenge is complete... ish...
I didn't think of a way to disambiguate how many arguments an operator takes, so I just didn't implement the unary case.</p>
<p>I'm reading over stuff on parsing, and I'm not sure how exactly I want to handle it.
It seems like I could set things up internally in a similar manner to the scanner, but I can't really give "function that produces a tree" an iterator interface in this context, so it might look kind of weird(er).</p>
<p>Anyway, I want to finish up soon, so I'm just going to try to tweak the interface for contracts, and add "decorator" support to classes if I get that done quickly.</p>
<p>...</p>
<p>Okay, contracts interface tweak went fine.
Now for class decoration.</p>
<p>...</p>
<p>Okay, that code seems to be in place.
My priority over the next few days is to shore up contract usage over the codebase.
I may also want to add a <tt class="docutils literal">destructured</tt> higher-order-function so I can skip some explicit destructurings in the protocol methods.</p>
<p>Actually, one last module to add, won't even test it yet, and then I'll post.
It's a thing for generating read-only proxies around tables.</p>
<p>...</p>
<p>Okay, that's all set for now, but I need, like, a spell-checker for metatable fields :/</p>
<p>Enough messing around, time to publish and work on the other stuff I want to get done.</p>
<p>Good night.</p>
Coding 2022-09-152022-09-15T04:00:00-04:002022-09-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-15:/coding-2022-09-15<p class="first last">I flex on Java. I'm pretty sure nothing that can in any way be thought of as representing Java cares.</p>
<p>All right, good work, me.</p>
<p>I've got a basic single-dispatch multi-function-y thing with no inheritance.
Nice and lean.</p>
<p>...</p>
<p>Like, I know it's not <em>fair</em> to compare my Lua version to the Java version, since the Java code is constrained for pedagogical reasons, but it takes less Lua code to put together the functionality I need <em>from scratch</em> than it does to force Java to sort of have metaprogramming.
Just look:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span></pre></div></td><td class="code"><div><pre><span></span><span class="kd">local</span> <span class="n">ephemeron</span> <span class="o">=</span> <span class="nb">require</span> <span class="s2">"ephemeron"</span>
<span class="kd">local</span> <span class="n">class_from_instance</span> <span class="o">=</span> <span class="n">ephemeron</span><span class="p">()</span>
<span class="kd">local</span> <span class="n">m</span> <span class="o">=</span> <span class="p">{}</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">make_destructor</span><span class="p">(</span><span class="n">slots</span><span class="p">)</span>
<span class="kr">return</span> <span class="kr">function</span><span class="p">(</span><span class="n">instance</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">instance_args</span> <span class="o">=</span> <span class="p">{}</span>
<span class="kr">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">v</span> <span class="kr">in</span> <span class="nb">ipairs</span><span class="p">(</span><span class="n">slots</span><span class="p">)</span> <span class="kr">do</span>
<span class="n">instance_args</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">instance</span><span class="p">[</span><span class="n">v</span><span class="p">]</span>
<span class="kr">end</span>
<span class="kr">return</span> <span class="nb">table.unpack</span><span class="p">(</span><span class="n">instance_args</span><span class="p">)</span>
<span class="kr">end</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="n">destructors</span> <span class="o">=</span> <span class="n">ephemeron</span><span class="p">()</span>
<span class="kd">local</span> <span class="n">protocol</span> <span class="o">=</span> <span class="kr">function</span><span class="p">(</span><span class="n">implementations</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">impls</span> <span class="o">=</span> <span class="n">ephemeron</span><span class="p">()</span>
<span class="kr">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="kr">in</span> <span class="nb">pairs</span><span class="p">(</span><span class="n">implementations</span><span class="p">)</span> <span class="kr">do</span>
<span class="n">impls</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span>
<span class="kr">end</span>
<span class="kr">return</span> <span class="kr">function</span><span class="p">(</span><span class="n">instance</span><span class="p">,</span> <span class="p">...)</span>
<span class="kr">return</span> <span class="n">impls</span><span class="p">[</span><span class="n">class_from_instance</span><span class="p">[</span><span class="n">instance</span><span class="p">]](</span><span class="n">instance</span><span class="p">,</span> <span class="p">...)</span>
<span class="kr">end</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="n">class</span> <span class="o">=</span> <span class="kr">function</span><span class="p">(</span><span class="n">body</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">slots</span> <span class="o">=</span> <span class="nb">table.move</span><span class="p">(</span><span class="n">body</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">#</span><span class="n">body</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="p">{})</span>
<span class="kd">local</span> <span class="n">instance_meta</span> <span class="o">=</span> <span class="p">{}</span>
<span class="kr">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="kr">in</span> <span class="nb">pairs</span><span class="p">(</span><span class="n">body</span><span class="p">)</span> <span class="kr">do</span>
<span class="kr">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"string"</span> <span class="kr">then</span>
<span class="n">instance_meta</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span>
<span class="kr">end</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">build</span><span class="p">(...)</span>
<span class="kd">local</span> <span class="n">instance</span> <span class="o">=</span> <span class="p">{}</span>
<span class="kd">local</span> <span class="n">args</span> <span class="o">=</span> <span class="p">{...}</span>
<span class="kr">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">v</span> <span class="kr">in</span> <span class="nb">ipairs</span><span class="p">(</span><span class="n">slots</span><span class="p">)</span> <span class="kr">do</span>
<span class="n">instance</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">args</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
<span class="kr">end</span>
<span class="n">class_from_instance</span><span class="p">[</span><span class="n">instance</span><span class="p">]</span> <span class="o">=</span> <span class="n">build</span>
<span class="kr">return</span> <span class="nb">setmetatable</span><span class="p">(</span><span class="n">instance</span><span class="p">,</span> <span class="n">instance_meta</span><span class="p">)</span>
<span class="kr">end</span>
<span class="n">destructors</span><span class="p">[</span><span class="n">build</span><span class="p">]</span> <span class="o">=</span> <span class="n">make_destructor</span><span class="p">(</span><span class="n">slots</span><span class="p">)</span>
<span class="kr">return</span> <span class="n">build</span>
<span class="kr">end</span>
<span class="n">m</span><span class="p">.</span><span class="n">class</span> <span class="o">=</span> <span class="n">class</span>
<span class="n">m</span><span class="p">.</span><span class="n">protocol</span> <span class="o">=</span> <span class="n">protocol</span>
<span class="kr">function</span> <span class="nc">m</span><span class="p">.</span><span class="nf">destructure</span><span class="p">(</span><span class="n">instance</span><span class="p">)</span>
<span class="kr">return</span> <span class="n">destructors</span><span class="p">[</span><span class="n">class_from_instance</span><span class="p">[</span><span class="n">instance</span><span class="p">]](</span><span class="n">instance</span><span class="p">)</span>
<span class="kr">end</span>
<span class="kr">return</span> <span class="n">m</span>
</pre></div></td></tr></table></div>
<p>I'm <em>not even using all of that code yet</em>, and it's still shorter than the initial version of <tt class="docutils literal">GenerateAst.java</tt>.
And, of course, it's regular Lua.
That said, there are a few things I want to add.
I've got the weird <tt class="docutils literal">local X = function</tt> construct because I'm planning to add contract enforcement to the public API, which will add a few lines.</p>
<p>This is all used like</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span></pre></div></td><td class="code"><div><pre><span></span><span class="kd">local</span> <span class="n">disinherit</span> <span class="o">=</span> <span class="nb">require</span> <span class="s2">"disinherit"</span>
<span class="kr">return</span> <span class="p">{</span>
<span class="n">binary</span> <span class="o">=</span> <span class="n">disinherit</span><span class="p">.</span><span class="n">class</span> <span class="p">{</span><span class="s2">"left"</span><span class="p">,</span> <span class="s2">"operator"</span><span class="p">,</span> <span class="s2">"right"</span><span class="p">},</span>
<span class="n">grouping</span> <span class="o">=</span> <span class="n">disinherit</span><span class="p">.</span><span class="n">class</span> <span class="p">{</span><span class="s2">"expression"</span><span class="p">},</span>
<span class="n">literal</span> <span class="o">=</span> <span class="n">disinherit</span><span class="p">.</span><span class="n">class</span> <span class="p">{</span><span class="s2">"value"</span><span class="p">},</span>
<span class="n">unary</span> <span class="o">=</span> <span class="n">disinherit</span><span class="p">.</span><span class="n">class</span> <span class="p">{</span><span class="s2">"operator"</span><span class="p">,</span> <span class="s2">"right"</span><span class="p">},</span>
<span class="p">}</span>
</pre></div></td></tr></table></div>
<p>and</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span></pre></div></td><td class="code"><div><pre><span></span><span class="kd">local</span> <span class="n">expr</span> <span class="o">=</span> <span class="nb">require</span> <span class="s2">"lox/expr"</span>
<span class="kd">local</span> <span class="n">printast</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">parenthesize</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="p">...)</span>
<span class="kd">local</span> <span class="n">builder</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"("</span><span class="p">,</span> <span class="n">name</span><span class="p">}</span>
<span class="kr">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">v</span> <span class="kr">in</span> <span class="nb">ipairs</span> <span class="p">{...}</span> <span class="kr">do</span>
<span class="nb">table.insert</span><span class="p">(</span><span class="n">builder</span><span class="p">,</span> <span class="s2">" "</span><span class="p">)</span>
<span class="nb">table.insert</span><span class="p">(</span><span class="n">builder</span><span class="p">,</span> <span class="n">printast</span><span class="p">(</span><span class="n">v</span><span class="p">))</span>
<span class="kr">end</span>
<span class="nb">table.insert</span><span class="p">(</span><span class="n">builder</span><span class="p">,</span> <span class="s2">")"</span><span class="p">)</span>
<span class="kr">return</span> <span class="nb">table.concat</span><span class="p">(</span><span class="n">builder</span><span class="p">)</span>
<span class="kr">end</span>
<span class="n">printast</span> <span class="o">=</span> <span class="nb">require</span><span class="s2">"disinherit"</span><span class="p">.</span><span class="n">protocol</span> <span class="p">{</span>
<span class="p">[</span><span class="n">expr</span><span class="p">.</span><span class="n">binary</span><span class="p">]</span> <span class="o">=</span> <span class="kr">function</span><span class="p">(</span><span class="n">binary</span><span class="p">)</span>
<span class="kr">return</span> <span class="n">parenthesize</span><span class="p">(</span><span class="n">binary</span><span class="p">.</span><span class="n">operator</span><span class="p">.</span><span class="n">lexeme</span><span class="p">,</span> <span class="n">binary</span><span class="p">.</span><span class="n">left</span><span class="p">,</span> <span class="n">binary</span><span class="p">.</span><span class="n">right</span><span class="p">)</span>
<span class="kr">end</span><span class="p">,</span>
<span class="p">[</span><span class="n">expr</span><span class="p">.</span><span class="n">grouping</span><span class="p">]</span> <span class="o">=</span> <span class="kr">function</span><span class="p">(</span><span class="n">grouping</span><span class="p">)</span>
<span class="kr">return</span> <span class="n">parenthesize</span><span class="p">(</span><span class="s2">"group"</span><span class="p">,</span> <span class="n">grouping</span><span class="p">.</span><span class="n">expression</span><span class="p">)</span>
<span class="kr">end</span><span class="p">,</span>
<span class="p">[</span><span class="n">expr</span><span class="p">.</span><span class="n">literal</span><span class="p">]</span> <span class="o">=</span> <span class="kr">function</span><span class="p">(</span><span class="n">literal</span><span class="p">)</span>
<span class="kr">return</span> <span class="nb">tostring</span><span class="p">(</span><span class="n">literal</span><span class="p">.</span><span class="n">value</span><span class="p">)</span>
<span class="kr">end</span><span class="p">,</span>
<span class="p">[</span><span class="n">expr</span><span class="p">.</span><span class="n">unary</span><span class="p">]</span> <span class="o">=</span> <span class="kr">function</span><span class="p">(</span><span class="n">unary</span><span class="p">)</span>
<span class="kr">return</span> <span class="n">parenthesize</span><span class="p">(</span><span class="n">unary</span><span class="p">.</span><span class="n">operator</span><span class="p">.</span><span class="n">lexeme</span><span class="p">,</span> <span class="n">unary</span><span class="p">.</span><span class="n">right</span><span class="p">)</span>
<span class="kr">end</span><span class="p">,</span>
<span class="p">}</span>
<span class="kr">return</span> <span class="n">printast</span>
</pre></div></td></tr></table></div>
<p>I'm going to have to think about this some, because setting up contracts as-is will do Bad Things to the protocol function.
Like, if you put contracts on a constructor, as-is, that'll break protocols because now you don't have access to the base constructor.
Either the protocol method needs to have some way of getting the "underlying function", or the <tt class="docutils literal">class</tt> function needs to have some way of taking an optional callback to transform the constructor before it ever gets called.
I'm inclined to do things the latter way, although, to get that ergonomic, it'd need some tweaks to the contracts interface, which is no big deal.</p>
<p>Anyway, it's getting late, although not as late as it's gotten before, and I want to wrap up, so I'm going to post this, consider this other stuff later, and try to knock out the Reverse Polish Notation challenge tomorrow.</p>
<p>Good night.</p>
Coding 2022-09-142022-09-14T04:00:00-04:002022-09-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-14:/coding-2022-09-14<p class="first last">"I don't like the problems with this approach, so I'll invent new problems :)"</p>
<p>I'm trying something a little different today by writing this up earlier, so I have fewer excuses to stay up at night, because my sleep was just... so messed up.
Anyway, I completed the multiline comment challenge, after a few hiccups.</p>
<p>So, next up is "Representing code", and it's actually a good thing I'm trying to write this earlier in the day, because I'm going to need to think about how I implement this stuff this time.</p>
<p>That's because this chapter talks about different programming paradigms and ways of laying out classes, and how to bridge gaps between different styles, and let's see how what I'm doing kind of messes with all of that...</p>
<p>I'm implementing as little as possible when it comes to "object-oriented features".
Currently, the way I'm writing "classes" in my code doesn't handle any reuse.
The point is more to avoid downstream consumers of an object needing to explicitly require a module to get at basic operations on that object.
Another potential motivation that would get me to write something would be if I had polymorphism; that is, if multiple kinds of object implemented the same operation in different ways
However, that's not what I'd use for what Robert Nystrom is using the visitor pattern for, for exactly the reason that he's using the visitor pattern.</p>
<p>The other issue here is that Lua doesn't do static type-checks (unless something really fancy came out when I wasn't looking), and missing fields just resolve to <tt class="docutils literal">nil</tt>, so my best hope there is to error out as early as possible.</p>
<p>Thinking about these problems, a solution begins to take shape:</p>
<ul class="simple">
<li>"classes" somehow involves a callable constructor, which creates "instances", and somehow provides access to the <tt class="docutils literal">__index</tt> table for the type of the instances.</li>
<li>These constructors can use the contracts code I wrote earlier.</li>
<li>Those contracts can be defined inline using a function factory that takes a key name as input.</li>
<li>The "visitors" should be Python-style protocol functions like <tt class="docutils literal">len</tt>.
They should be defined <em>unlike</em> how Python does them.
Instead, they should mostly use a table associating the constructor callable to the implementation for the instances of that callable.</li>
<li>Just realized the <tt class="docutils literal">__index</tt>-like table should be an ephemeron table, which is no big deal.</li>
</ul>
<p>The big thing I need to work out before I start writing code is, what kind of callable should the constructors be, and how it should relate to the <tt class="docutils literal">__index</tt> table (which need not actually hook into the metatable system in that way).</p>
<p>Anyway, I'll ponder that for a while, and try to take things easy for the rest of the day.</p>
<p>Good night.</p>
Weekly Roundup 2022-09-132022-09-13T04:00:00-04:002022-09-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-13:/weekly-roundup-2022-09-13<p class="first last">These entries are really helpful for contextualizing to myself <em>when I did something</em></p>
<ul class="simple">
<li>Wednesday: I started working on Crafting Interpreters in Lua, again.</li>
<li>Thursday: Since I'm starting fresh, I realized I could vary up my approach a little.</li>
<li>Friday: I got some work done...</li>
<li>Saturday: I finished the chapter, but I decided I wanted to polish the code some before moving on.</li>
<li>Sunday: I made changes that make it possible to test the interpreter, which is convenient, since I'm using it as the entry point for all of the internals.</li>
<li>Monday: I got everything taken care of for now, except for the challenges.</li>
</ul>
<p>Next week,</p>
Coding 2022-09-122022-09-12T04:00:00-04:002022-09-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-12:/coding-2022-09-12<p class="first last">I wonder if I'll end up with some kind of weird functional Lua library from all of this.</p>
<p>Okay, here's the deal:</p>
<ul class="simple">
<li>Test coverage is maxed out.</li>
<li>Functions in the scanner module are rewritten to make more sense.
(The problems with them were all my fault.)</li>
<li>I've gotten documentation sort of working, I think.
I'm not sure what to document, but at least I've got the infrastructure to do so.</li>
</ul>
<p>I'm not feeling super excited to document the core modules, since those are potentially going to get all changed around in later chapters.
I guess I can look into documenting the supporting modules I'm writing.</p>
<p>For now, though, I want to take things easy and get back to this later.</p>
<p>Good night.</p>
Coding 2022-09-112022-09-11T04:00:00-04:002022-09-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-11:/coding-2022-09-11<p class="first last">I didn't work on Python stuff today because ???</p>
<p>The code is a little tidier now.
I created an object to act as a proxy to the file system and the shell, and converted the interpreter to delegate to that object.
This means I should be able to test the interpreter without it trying to exit the test runner, which, maybe Lunit can stop those shenanigans, but I'd much rather just not bother.
If I can cut this off before it needs the tooling to intervene, I might as well.</p>
<p>I fixed some errors that I introduced in the rewrite, so now the majority of this stuff basically works.</p>
<p>What's missing:</p>
<ul class="simple">
<li>The remainder of the test coverage<ul>
<li>General test mocks for the host system abstraction</li>
</ul>
</li>
<li>Documentation<ul>
<li>Figuring out what documentation should look like</li>
<li>And whether it's compatible with my habit of returning functions instead of tables from modules.</li>
</ul>
</li>
<li>Doing the challenges <em>on a branch</em>.</li>
</ul>
<p>Anyway, that's that for now.</p>
<p>Good night.</p>
Coding 2022-09-102022-09-10T04:00:00-04:002022-09-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-10:/coding-2022-09-10<p class="first last">I think I'm going to have to rename or reconsider some of my functions, because the relation between the meaning of the name and the behavior is... confusing.</p>
<p>The chapter on the scanner is done, but I'm not ready to move on.
The test coverage is way too low, I hit all sorts of errors testing things manually, and there are a bunch of questionable choices that I made in the service of getting things done.</p>
<p>I ended up writing more code to interact with Lua's native protocols, and this just feels sensible to me.
If you write code to work with an object system, then it works with that object system, but if you write code to transform iterators, then it works with <em>everything</em>.</p>
<p>I've been tweaking things pretty hard as far as auto-formatting goes, and I'm still not really satisfied.
Currently, I'm using <a class="reference external" href="https://github.com/Koihik/LuaFormatter">LuaFormatter</a> with a bunch of custom configuration, which overall gives me <em>most</em> of what I want.</p>
<p>But yeah, I need to take a break from getting code in, and work on verifying and documenting the stuff that's in there now.</p>
<p>Good night.</p>
Coding 2022-09-092022-09-09T04:00:00-04:002022-09-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-09:/coding-2022-09-09<p class="first last">Spacing out and then cramming is not the best strategy for anything, but it's what I did, so...</p>
<p>I just put together what I believe is the minimal implementation for how I want the interpreter object to work.</p>
<p>I wasn't focusing on much stuff today, so I didn't have much time for this, and I'm dashing out this entry way too late.</p>
<p>Tomorrow, I'll try to finish up the chapter, and if I do, I'll write tests in order to get the coverage up, and maybe try documenting some stuff.</p>
<p>Anyway, I have to go, now.</p>
<p>Good night.</p>
Coding 2022-09-082022-09-08T04:00:00-04:002022-09-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-08:/coding-2022-09-08<p class="first last">Trying to push my Lua code closer to the metal. The moon-metal. Whatever.</p>
<p>I was looking over my previous code for Crafting Interpreters, and I found an interesting comment.</p>
<div class="highlight"><pre><span></span><span class="c1">-- Can this be switched to the iterator protocol?</span>
<span class="c1">-- Don't try yet. That kind of speculative refactoring can go... poorly.</span>
<span class="kr">function</span> <span class="nc">scanner_index</span><span class="p">:</span><span class="nf">scan_tokens</span><span class="p">()</span>
</pre></div>
<p>And I thought...
It's a fresh codebase.
Why not try it now?</p>
<div class="admonition smiley smiley-glitchy">
<p class="first admonition-title">:) (glitchy)</p>
<p class="last">Dewit.</p>
</div>
<p>To do this right, I need to get a handle on just what this would entail.
Basically, I want to think of jlox's <tt class="docutils literal">scanTokens()</tt> method instead as a top-level function that takes a source string and returns a Lua iterator of tokens.
Now, the end goal (for now) is to accumulate this iterator state into a table, so I put together a little module that I think looks reasonable:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span></pre></div></td><td class="code"><div><pre><span></span><span class="kr">return</span> <span class="kr">function</span><span class="p">(</span><span class="n">func</span><span class="p">,</span> <span class="n">iterator_function</span><span class="p">,</span> <span class="n">state</span><span class="p">,</span> <span class="n">initial_value</span><span class="p">,</span> <span class="n">_closing_value</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">accumulator</span> <span class="o">=</span> <span class="p">{}</span>
<span class="kd">local</span> <span class="n">control_variable</span> <span class="o">=</span> <span class="n">initial_value</span>
<span class="kr">while</span> <span class="n">control_variable</span> <span class="o">~=</span> <span class="kc">nil</span> <span class="kr">do</span>
<span class="kd">local</span> <span class="n">loop_variables</span> <span class="o">=</span> <span class="p">{</span><span class="n">iterator_function</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">control_variable</span><span class="p">)}</span>
<span class="n">control_variable</span> <span class="o">=</span> <span class="n">loop_variables</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="kr">if</span> <span class="n">control_variable</span> <span class="o">==</span> <span class="kc">nil</span> <span class="kr">then</span>
<span class="kr">break</span>
<span class="kr">end</span>
<span class="nb">table.insert</span><span class="p">(</span><span class="n">accumulator</span><span class="p">,</span> <span class="p">(</span><span class="n">func</span><span class="p">(</span><span class="nb">table.unpack</span><span class="p">(</span><span class="n">loop_variables</span><span class="p">))))</span>
<span class="kr">end</span>
<span class="kr">return</span> <span class="n">accumulator</span>
<span class="kr">end</span>
</pre></div></td></tr></table></div>
<p>I'm not sure if I'll actually use this, but it all basically makes sense.
It essentially handles the Lua iterator protocol, and uses a function to condense the possibly-multiple return values into a single result.</p>
<p>Anyway, the basic picture of what I'm going for with <tt class="docutils literal">scan_tokens()</tt> is to make that into an iterator that uses the source code as the invariant state, and packs the <tt class="docutils literal">start</tt>, <tt class="docutils literal">current</tt>, and <tt class="docutils literal">line</tt> values into a table in the control variable.
Then the methods translate into functions that take arguments of <tt class="docutils literal">source</tt> and the control variable.</p>
<p>Okay, that all went smoothly, except for right at the end:
The <tt class="docutils literal">scanToken()</tt> method reaches out to the static <tt class="docutils literal">error()</tt> method on the core <tt class="docutils literal">Lox</tt> class, and that...
It makes me feel...
I don't like doing that...</p>
<p>Last time around, I passed the whole interpreter to the <tt class="docutils literal">Scanner</tt> class I wrote, so it could call the method.
And this is vaguely annoying to do with the way I wrote this, because I guess I'd need to change the state variable...</p>
<p>Okay, updating the state variable wasn't too hard, and now there's just two things I want to do currently:</p>
<ul class="simple">
<li>Wrap the various bits where I construct a control variable in functions, so I know where to update if I add more fields to the control variable.</li>
<li>Make the <tt class="docutils literal">Lox</tt> class that the state variable needs an instance of... exist.</li>
</ul>
<p>But I can't work on those right now, because it is late.</p>
<p>Good night.</p>
Coding 2022-09-072022-09-07T04:00:00-04:002022-09-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-07:/coding-2022-09-07<p class="first last">Getting flashbacks to I-don't-know-how-many years ago.</p>
<p>Well, I started grinding through the Scanning chapter of Crafting Interpreters, and as can be expected, there's just a bunch of "Okay, Java is doing this, so the rough equivalent in Lua is ..."</p>
<p>I'm referring a bunch to my previous attempt, because I don't think anything was fundamentally wrong with it, I just got a little... messy.</p>
<p>Oh, also, I got a wrapper written around one of the tools called <a class="reference external" href="https://www.npmjs.com/package/lua-fmt">lua-fmt</a>, so now I can write complete garbage formatting and then tell my laptop to fix it for me.
It doesn't mind.</p>
<p>Anyway, I'm coming up on a bit where I feel like I put a bunch of effort into it in the previous iteration, but I don't remember how that effort was directed.
Like, what was I trying to do?
Presumably, it had something to do with switching variables between being top-level locals and instance values?
I can only assume?</p>
<p>In general, I'm not sure I trust these static variables.
They feel... singleton-y?</p>
<p>Anyway, I'll try to get on with this more tomorrow.
Hopefully writing some tests will illuminate the situation.</p>
<p>Good night.</p>
Weekly Roundup 2022-09-062022-09-06T04:00:00-04:002022-09-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-06:/weekly-roundup-2022-09-06<p class="first last">I made some mistakes which I am trying to recover from.</p>
<ul class="simple">
<li>Wednesday: I'm not sure what happened before writing the post, but I did think about NABTO during it.</li>
<li>Thursday: I worked out some stuff that I'd like to work in Python's types, and, by extension, that I'd like to work in NABTO's types. It's likely to be pretty hard to implement, unfortunately.</li>
<li>Friday: I tried to translate the Lox interpreter to Rust, and gave up on that because that's just too many different not-familiar-enough things to juggle.</li>
<li>Saturday: I made an effort to learn tooling for Lua, and put together something that seems promising.</li>
<li>Sunday: I got back into Python code, and did a little work on MOTR, and <em>way too much</em> work on one of my other projects, trying to diagnose an issue that was ultimately either a bug in attrs or a limitation of Python; either way, not my fault, but not hard to fix once I understood what was going wrong.</li>
<li>Monday: After all of that, I was catastrophically tired, and didn't get much done. Oh well.</li>
</ul>
<p>Next week, I'm going to try to get more done on various coding fronts.
Per Lua's philosophy of "build the stuff you need yourself", I'm putting together some interesting scaffolding for development.
I'll try to describe that some once I've really used it, rather than writing so-so tests for it.</p>
Coding 2022-09-052022-09-05T04:00:00-04:002022-09-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-05:/coding-2022-09-05<p class="first last">Uuuuuuuuuuugh.</p>
<p>I didn't actually get much done today.
I did clean things up from yesterday a bit.</p>
<p>But, because I was up so late working on this stuff last night, I was totally wiped out today and couldn't focus on anything.</p>
<p>So, cleaned stuff up, and I don't want to repeat that experience, so I'm going to just take the L for today.</p>
<p>Good night.</p>
Coding 2022-09-042022-09-04T04:00:00-04:002022-09-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-04:/coding-2022-09-04<p class="first last">By the way, shout out to attrs for fixing a bug I was hacking around. Minus shoutout for not fixing it all the way.</p>
<p>Well, I tried to work on MOTR and another project today, and the results were so-so at best.
Maybe if I had a pomodoro and switched off.
Anyway, I did make some progress.
I added a few lines of coverage to MOTR, and upgraded the Python version of the other project so I could use some newer typing features.</p>
<p>My plan with the other project is to strip out a shockingly large amount of code in the service of relying on the standard library for more things.
Before I'm ready to delete that code, I need to get the replacement code to work, and as to how that's going... it's going...</p>
<p>...</p>
<p>Since then, I've gotten most tests to pass, deleted the majority of the rest, and the remainder are... confounding.
It's some weird tension between, yes, the original intention of the tests is completely invalidated, and the documentation is all horribly out of date...
But on the other hand, I'm staring daggers at the test code, and I can't see why the tests aren't passing.</p>
<p>...</p>
<p>I fixed it, and it sucked, and it was completely not my fault.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">This is all true.
Quick summary, since it's late?</p>
</div>
<p>Attrs tries to make get_type_hints work by populating the <tt class="docutils literal">__globals__</tt> attribute on the generated <tt class="docutils literal">__init__</tt>.
It does this using <tt class="docutils literal">dict.update()</tt>, so further updates to the module namespace have no effect.
Ergo, can't use forward references.</p>
<p>Fortunately, I was already calculating all of the necessary information for the old system, so I didn't actually need to figure out how to do anything differently, I just hooked up the seemingly-dead code, and the tests just started working.</p>
<p>That said, there's a bunch more to be done here.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Excellent.
Now, SLEEP!</p>
</div>
<p>... Not sure I like your tone.
Nevertheless...</p>
<p>Good night.</p>
Coding 2022-09-032022-09-03T04:00:00-04:002022-09-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-03:/coding-2022-09-03<p class="first last">Just a stunning amount of setup, oh well.</p>
<p>I got a bunch of tooling more-or-less working for developing with Lua.
We'll see if it all actually works out, because I was just focusing on getting things to more-or-less pass.
Right now, I'm trying out:</p>
<ul class="simple">
<li><a class="reference external" href="https://github.com/boolangery/sphinx-lua">sphinx-lua</a> with <a class="reference external" href="https://pradyunsg.me/furo/">Furo</a>, and using <a class="reference external" href="https://www.pyinvoke.org/">Invoke</a> instead of the makefiles.
I haven't actually tried to document code with this yet, and if it doesn't work, I'll just switch to <a class="reference external" href="https://stevedonovan.github.io/ldoc/">LDoc</a>.
Getting sphinx-lua to run right took some weird additions to the requirements file, so I'm not super-attached to it yet, but given the ability to use Furo's dark mode, I'll try to take it.</li>
<li><a class="reference external" href="https://github.com/dcurrie/lunit">lunitx</a> and <a class="reference external" href="https://github.com/lunarmodules/luacov">LuaCov</a>.
Notes on getting this working: I had to add <tt class="docutils literal">LUA_INIT=require 'luacov'</tt> to the environment for the <tt class="docutils literal">lunit.sh</tt> call, because I didn't see another way to make it load the module, but it all seemed to work, once I created a proper <tt class="docutils literal">.luacov</tt> file.
Update: while I was writing the stuff down below, I realized I could just call <tt class="docutils literal">lua <span class="pre">-llunitx</span> tests/*</tt>, so I did that instead, because I'm not sure what the wrapper does in comparison, and I'd rather call Lua directly I think?
<strong>Late-breaking update: That did weird stuff to coverage, so I switched it back.
Not sure what was going on there...</strong>
The other part of it was getting lunitx tests happy with how <a class="reference external" href="https://github.com/mpeterv/luacheck">Luacheck</a> wants me to write modules.
Here's the pattern that I settled on:</li>
</ul>
<div class="highlight"><pre><span></span><span class="kd">local</span> <span class="n">t</span> <span class="o">=</span> <span class="nb">require</span> <span class="s2">"lunit"</span>
<span class="kd">local</span> <span class="n">m</span> <span class="o">=</span> <span class="n">t</span><span class="p">.</span><span class="n">TEST_CASE</span> <span class="s2">"<test file name>"</span>
<span class="kr">function</span> <span class="nc">m</span><span class="p">.</span><span class="nf">test_etc</span><span class="p">()</span> <span class="kr">end</span>
<span class="kr">return</span> <span class="n">m</span>
</pre></div>
<p>With this, I'm not creating any globals, and it's all working through lunitx's compatibility layers, so it can discover the tests.
Now, I need to get to writing some code so I can test it.</p>
<p>Some of that code may end up being random bits of scaffolding, because, Lua.
Anyway, I feel like I've written enough, and I don't want to delay this post any.</p>
<p>Good night.</p>
Coding 2022-09-022022-09-02T04:00:00-04:002022-09-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-02:/coding-2022-09-02<p class="first last">Painfully little progress, painfully much pain</p>
<p>Okay, so, I'm really not feeling great right now, so I'm going to explain what I tried to do, then I'm going to lie down or something for a while.</p>
<p>I mentioned <a class="reference external" href="http://craftinginterpreters.com/">Crafting Interpreters</a> yesterday, and I decided to pick it back up.
Now, I've got a few attempted projects that try to port the first half to other languages.
One in Lua that's in a weird state because I left a bunch of the challenge code in, so that's not a great baseline.
One in Python that I don't quite remember what I was doing, but I don't want to get back into Python code right now, because I'm on some kind of Quixotic quest for perfection with MOTR.</p>
<p>A quixotic quest for perfection, hm?
That sounds like some of the descriptions of Rust.
I thought, maybe I could pick Rust back up, and translate the Java code to Rust code.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Max could not.</p>
</div>
<p>I don't know whether it's that I'm, uh, rusty with Rust, that it's uniquely annoying to translate from Java to Rust, or just that I'm <em>extremely tired</em>, but currently I'm just not feeling it.
At least I know this wasn't anything to do with the borrow checker, because I did not get the code far enough for that to matter.</p>
<ul class="simple">
<li>In support of "I'm out of practice with Rust"; well, I just... am.</li>
<li>In support of "The translation is annoying"; so, I guess I should be converting these <tt class="docutils literal">throws</tt> declarations to <tt class="docutils literal">Result</tt>s?
Maybe?
I'm not sure?</li>
<li>In support of "I'm extremely tired"; I <em>am</em> extremely tired.</li>
</ul>
<p>There are a few different tacks I can and should take to deal with this:</p>
<ul class="simple">
<li>Work through a proper Rust tutorial.</li>
<li>Read the current chapter to the end, developing a plan for translation.</li>
<li>Potentially, for now use a language I'm more familiar with, like Lua.</li>
<li>Get some dang sleep.</li>
</ul>
<p>I know what I should be working on to start with, so I'm going to try to wrap up earlier than usual tonight.</p>
<p>Good night.</p>
Coding 2022-09-012022-09-01T04:00:00-04:002022-09-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-09-01:/coding-2022-09-01<p class="first last">Just sticking various words on the front of "types" and going "Oh, <em>no</em>."</p>
<p>I'm a little out of it again, so I'm going to focus on one particular thing that I want in NABTO, but I also, just, want in general.</p>
<p>Okay, so this is seemingly simple to describe in plain language, but it looks to me like it inevitably brings in a lot of complication when I try to formalize it.</p>
<p>So, it's a type, that takes three variables.
Two of them are normal type variables.
The other one is...
A higher-kinded type that takes two arguments.
In Python runtime terms, it's easiest to express the whole type as a tuple, so let's go with that.
Call the higher-kinded variable <tt class="docutils literal">HKT</tt>, and then there are two possible ways to inhabit this type:</p>
<p><tt class="docutils literal">MagicType[HKT, T, V] = tuple[HKT[T, V]] | MagicType[HKT, T, U] + tuple[HKT[U, V]]</tt></p>
<p>Where <tt class="docutils literal">+</tt> between types indicates "the type of the concatenation of tuples of these two types" which I'm pretty sure isn't ever going to be a thing.
Functionally, it's something like variadic generics, so it's as if we could define a union of variadic generics...</p>
<p><tt class="docutils literal">MagicVariadic[HKT, T, V] = (HKT[T, <span class="pre">V],)</span> | (*MagicVariadic[HKT, T, U], HKT[U, V])</tt></p>
<p>Which is still not a thing that the syntax is likely to permit.
(This would be used like <tt class="docutils literal"><span class="pre">tuple[*MagicVariadic[HKT,</span> T, V]]</tt>)</p>
<p>I could imagine trying to write a plugin that would make that all sort of work, possibly in conjunction with existing plugins.
But I don't think that's happening until Python 3.11 comes out.</p>
<div class="admonition smiley smiley-glitchy">
<p class="first admonition-title">:) (glitchy)</p>
<p class="last">Not that it's not fun to imagine people trying to process that crazy syntax, but you should probably explain what this is <em>for</em>.</p>
</div>
<p>All right, so, I've got two motivating examples, and one of them kind of reduces to the other, so I'll do the other one first.</p>
<p>Suppose <tt class="docutils literal">HKT[T, U]</tt> is <tt class="docutils literal"><span class="pre">Callable[[T],</span> U]</tt>.
Now if you have a <tt class="docutils literal">T</tt> and a <tt class="docutils literal"><span class="pre">tuple[*MagicVariadic[OneArgCall,</span> T, V]]</tt>, then you can loop or <tt class="docutils literal">functools.reduce()</tt> the tuple over the variable to obtain a <tt class="docutils literal">V</tt>.</p>
<p>(In NABTO, the effect type would need to be tracked somehow.)</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last"><em>Someone's</em> going to want to know whether looping or <tt class="docutils literal">functools.reduce()</tt> is better.</p>
</div>
<p>"Better".
Anyway, I was messing around earlier, and using <tt class="docutils literal">functools.reduce()</tt> was always slower than an explicit loop, <em>but</em> I was able to get them pretty close by binding <tt class="docutils literal">functools.reduce()</tt> as a default argument.
I'm not going to give actual percentages, because if the functions are heavy enough, they'll swamp the difference.
So, if you find yourself in this situation, go with whatever solution you're more comfortable with, and be ready to profile the code if it does seem slow.</p>
<p>Anyway, the other place I ended up wanting something like this was in the graph code I was messing with.
I had the idea of a <em>composed</em> edge, an edge that follows an <tt class="docutils literal">Edge[T, U]</tt> to an <tt class="docutils literal">Edge[U, V]</tt>.
And why stop at one composition, hmm?
Or allow the compositions to form some kind of binary tree.
Better to just lean on the associative property and collapse them all together.
I can't prove I need this from a performance perspective, but it's just <em>unaesthic</em> to allow arbitrary binary structures that all "mean the same thing".</p>
<p>(Actually, from that perspective, there definitely needs to be a <em>canonical</em> form.)</p>
<p>Let's chase that thought for a sec.</p>
<p><tt class="docutils literal">MagicTuple[HKT, T, V] = tuple[HKT[T, V]] | tuple[HKT[T, U], MagicTuple[HKT[U, <span class="pre">V]]]</span></tt></p>
<p>I just realized that the <tt class="docutils literal">U</tt> is kind of coming out of nowhere in literally all of these.
Throw "existential types" on the pile...</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p>Hooray!</p>
<p class="last">Suffering!</p>
</div>
<p>I know, I know.</p>
<p>Anyway, however it's represented, we then want the conceptual ability to map as follows:</p>
<p><tt class="docutils literal">Edge[T, U] <span class="pre">-></span> <span class="pre">Callable[[T],</span> frozenset[U]] <span class="pre">-></span> <span class="pre">Callable[[frozenset[T]],</span> frozenset[U]]</tt></p>
<p>Just a bunch of Haskell-inspired nonsense that I'm pretty sure Haskell wouldn't even let you do.</p>
<p>There are two wolves inside of me.
One of them knows, intellectually, that trying to implement all of this type <em>stuff</em> is probably a bad idea.
The other one <em>really wants it, come ooon</em>.</p>
<p>Meh, at least it's only my problem if I try to do this.</p>
<p>Thinking over this, I think the way forward is to consider a bunch of problems separately:</p>
<ul class="simple">
<li>Get back into Koka in order to better learn effect systems and to get a handle on the types.</li>
<li>Try to implement features of interest, such as my ideas about inheritance, in smaller, specific-purpose experimental languages.</li>
<li>Maybe start over with Crafting Interpreters or something similar.</li>
</ul>
<p>Anyway, I'm tired and I have other things I want to do, so I'm going to cap this off for now.</p>
<p>Good night.</p>
Diary 2022-08-312022-08-31T04:00:00-04:002022-08-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-31:/diary-2022-08-31<p class="first last">Apparently I just kind of zoned out for a while?</p>
<p>I have no memory of where the time went today, at least, not after I "fixed" the technical difficulties that kept me from publishing yesterday.
Basically, my home folder was too big, so I made some drastic adjustments that fit with how I actually <em>use</em> the files that I moved around, so the result should be fine.
We'll see.
There's a bit more that I <em>can</em> do to alleviate the situation, but I don't need to.
I probably should though.</p>
<p>Anyway, there's some work to be done on this still that's in other areas, and I don't want to think about that right now.</p>
<p>ANYWAY.</p>
<p>I've been thinking about NABTO, and there are some scary interdependencies there.
Like, when you have imports as a <em>runtime</em> concept, then that means that the import system needs to handle <tt class="docutils literal">st<h></tt> effects, and I'm not totally sure what that looks like.
It's <em>possible</em> that trying to combine "dynamic language" with "Koka-style effect types" will result in something completely unrecognizable for reusing code, but I'm not really sure yet.
I don't want to give up on the idea before I've thoroughly explored it.
Sadly, I don't have time right now, because it's late and I'm struggling not to make weird typos.</p>
<p>Anyway, that's enough time spent trying to write more of this post.</p>
<p>Good night.</p>
Weekly Roundup 2022-08-302022-08-30T04:00:00-04:002022-08-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-30:/weekly-roundup-2022-08-30<p class="first last">It was definitely nice to get the site design stuff out of the way.</p>
<ul class="simple">
<li>Wednesday: I pondered some facets of programming language design.</li>
<li>Thursday: I gave a terrible working title to the vague collection of language ideas I've been messing with in my head, and laid out some of the details of it, or at least possibilities of the details.</li>
<li>Friday: I tried to describe basic programs, and rather quickly ran into some esoteric-feeling issues.</li>
<li>Saturday: I rolled out the updated stylesheet and templates, at long last.</li>
<li>Sunday: I got work done on MOTR.</li>
<li>Monday: I did some more work on MOTR, and ran into weird snags writing tests that were technically (very technically, I feel) my fault.</li>
</ul>
<p>Next week, I'm going to keep on with MOTR, and other stuff, and I've had enough technical difficulties before writing this entry that I frankly don't want to think too hard about it right now.</p>
Coding 2022-08-292022-08-29T04:00:00-04:002022-08-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-29:/coding-2022-08-29<p class="first last">Trust nobody, <em>especially</em> not yourself.</p>
<p>The package tests are improved, and I'm trying to get the <tt class="docutils literal">Build</tt> tests working.
It's slow going, because the <tt class="docutils literal"><span class="pre">pyproject-build</span></tt> command is failing.
After I wired stuff up enough that I could actually see the errors, I'm pretty sure they're indicating that there's something wrong with the synthetic packages I'm having it build, but...</p>
<p>Wait.
It's trying to find the package name instead of the module name.</p>
<p>...</p>
<p>Ugh, TOML, why?</p>
<p>Well, in any case, I shouldn't have too much trouble testing the error case.</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">You should explain.</p>
</div>
<p>Wh—</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">You should explain what was going wrong.
After all, everything was spec-conformant except for your code.</p>
</div>
<p>Ugh, <em>fine</em>.</p>
<p>So, here's the code that was broken:</p>
<div class="highlight"><pre><span></span><span class="p">{</span>
<span class="c1"># ...</span>
<span class="s2">"tool.flit.module"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"name"</span><span class="p">:</span> <span class="n">module_name</span><span class="p">},</span>
<span class="p">}</span>
</pre></div>
<p>And here's what worked:</p>
<div class="highlight"><pre><span></span><span class="p">{</span>
<span class="c1"># ...</span>
<span class="s2">"tool"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"flit"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"module"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"name"</span><span class="p">:</span> <span class="n">module_name</span><span class="p">}}},</span>
<span class="p">}</span>
</pre></div>
<p>That dict is an argument to the <tt class="docutils literal">tomli_w.dumps</tt> function.
As I saw it, I had two basic options for how to generate the synthetic <tt class="docutils literal">pyproject.toml</tt> file.
Either I could substitute into a template, or I could generate the data corresponding to the contents of the file, and convert it to a string.
I decided to manipulate the data, because I figured that would be less of a pain than setting up templating or a big format string.
I'm... not sure that was the case, but at least now I've cleared what's hopefully the biggest hurdle to that.</p>
<p>See, the difference between those two snippets is, one works, and the other doesn't, and the one that works, works because it's writing data that corresponds to this block from the examples in Flit's documentation:</p>
<div class="highlight"><pre><span></span><span class="k">[tool.flit.module]</span>
<span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"nsist"</span>
</pre></div>
<p>In TOML, this corresponds to a table containing a key called "name", and that table is described by one of the above snippets.
See, TOML has a bunch of <a class="reference external" href="https://toml.io/en/v1.0.0#table">syntactic sugar</a>, and those dots in the file don't correspond to the dots in the first snippet.
They correspond to the <em>table nesting</em> in the second snippet.</p>
<p>So, before I fixed this, I was writing the table I needed to write, to some weird gibberish key in the top level, rather than the nice telescoping whatever that's going on there.</p>
<p>I'd read this in the documentation back when TOML was taking off, but I didn't think through the implications this had for generating TOML from data rather than from text.</p>
<p>So, there it is, one of the hurdles I had to clear was that I wasn't thinking hard enough about the format that my data was in.
Happy?</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">Always.</p>
</div>
<p>O...kay.</p>
<p>Anyway, I let this go late and I need to get to bed now.</p>
<p>Good night.</p>
Coding 2022-08-282022-08-28T04:00:00-04:002022-08-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-28:/coding-2022-08-28<p class="first last">I was actually a little surprised at how broken the existing code was. Oh well, that's how it is when there aren't tests.</p>
<p>Well, I got a little bit done on MOTR.
I added some tests, and deleted the code that the test was exercising.
I admit the test coverage for both versions of the code paths involved is... not great.</p>
<p>Tomorrow, I'll try to shore up those tests a little, then get on with the next major test coverage hole: running the <tt class="docutils literal">Build</tt> action against synthetic data.</p>
<p>We'll see how that goes, but for now, I really really need to get to bed.</p>
<p>Good night.</p>
Site Design 2022-08-272022-08-27T04:00:00-04:002022-08-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-27:/site-design-2022-08-27<p class="first last">I wonder how this looks on real phones now, instead of the simulator I was using.</p>
<p>I gave the redesign a few days to sit, and made a few final tweaks.
It's time to push it out the door!
Time for a slightly wider central column, slight tweaks to the color scheme, more big chunky lines with rounded bits, and</p>
<div class="admonition smiley smiley-normal">
<p class="first admonition-title">:)</p>
<p class="last">And me!</p>
</div>
<p>Yep, I decided to spin off my whole unsettling smiley bit that I've done a few times since... a year ago, and turned it into one of those little character avatars that I see Rust blogs and other blogs use.</p>
<p>...</p>
<p>This was a good idea.</p>
<div class="admonition smiley smiley-glitchy">
<p class="first admonition-title">:) (glitchy)</p>
<p class="last">This <em>is</em> a good idea!</p>
</div>
<p>In all seriousness, I think this has some potential for Missable Mysteries, if I ever, um, get back to it.</p>
<p>Anyway, I want to take care of some other things, so this is just going to be a quick entry showing off the changes.</p>
<p>Good night.</p>
Coding 2022-08-262022-08-26T04:00:00-04:002022-08-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-26:/coding-2022-08-26<p class="first last">I have so many different ideas for what "some boilerplate" could be like...</p>
<p>I've been thinking a bit more about NABTO, and I realized that there's something I need to address entirely before anything remotely object-oriented enters the picture.</p>
<p>Here is a Hello World program in Koka:</p>
<div class="highlight"><pre><span></span><span class="k">fun</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span>
<span class="w"> </span><span class="n">println</span><span class="p">(</span><span class="s2">"Hello world!"</span><span class="p">)</span><span class="w"> </span><span class="c1">// println output</span>
</pre></div>
<p>Here is a Hello World program in Python:</p>
<div class="highlight"><pre><span></span><span class="nb">print</span><span class="p">(</span><span class="s2">"Hello world!"</span><span class="p">)</span>
</pre></div>
<p>The Koka code has the <tt class="docutils literal">println()</tt> call inside the main function, while the Python version has it at the top level of the module.
In Koka, module-level code is analyzed and acted on at compile time, while in Python, it's executed when the module is imported at run time.
This means that either we need to restrict which effects are permissible at the module level, or we need to allow imports in NABTO to potentially emit arbitrary effects, once.</p>
<p>Hm, that "once" makes something occur to me.
The <tt class="docutils literal">import</tt> statement in Python and the <tt class="docutils literal">require()</tt> function in Lua are, due to the way they memoize their results, kind of like delayed values that immediately get forced.</p>
<p>Okay, it just occurred to me that I probably don't want to go down this road.
If the importing module is responsible in any way for handling the effects from the module that it imports, then that means that the values <em>in</em> a module can depend on <em>where it's first imported</em>.
That seems less than ideal to me.
To counter that, there could be some kind of runtime service that handles the effects from importing a module.
Suppose some user code <em>wants</em> to mess with the effect handling, though?</p>
<p>I don't know if I'm satisfied with this idea, but maybe if there were some kind of sandboxed execution facility, so that someone who wanted custom effect handling could "simply" create an object to emulate the runtime, and within that emulated runtime, imports would be done completely freshly.</p>
<p>I'm tempted to see if the syntax could be made to support Lua's function call syntax, so that there's just a function instead of a statement.
If this were a function, it would effectively only propagate errors and non-termination to the calling code, and all other effects would "pass through" the intervening layers to the runtime.</p>
<p>Final question to consider for tonight: does the fact that call trees all trace back to the <tt class="docutils literal">__main__</tt> module, combined with the ideas I've been going over, come together in a way that's elegant, inelegant, or pointless?</p>
<p>Well, let's look at the Hello World program for NABTO.
It's going to be something like <tt class="docutils literal"><span class="pre">println("Hello</span> <span class="pre">World!")</span></tt> (probably with some boilerplate at the beginning).
The runtime will import the module, and the import system will handle the text output effect.
Then, it will finish with the module, and exit.</p>
<p>A more complex program will end up importing multiple modules, and suspending execution during the imports, then resuming, possibly with an error.</p>
<p>This all seems to make sense to me, but I really should sleep on it before I think I'm sure.</p>
<p>Good night.</p>
Coding 2022-08-252022-08-25T04:00:00-04:002022-08-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-25:/coding-2022-08-25<p class="first last">Oh boy, I sure have been thinking about this, apparently.</p>
<p>I figured I'd keep on thinking about the programming language concept I sort of mentioned last night.
Before I do anything else, I want to name it so I can have something convenient to refer to, but I don't want to commit to a name yet.
As such, I'll use a working title that practically demands to be replaced, once a suitable replacement suggests itself:</p>
<p>Name Already Been Thought Of, or NABTO.
This is an allusion to trying to come up with some punchy, memorable name, and oops, it's already in use.
With its somewhat unusual combination of different points of articulation and voicing, NABTO is the programmer art of names, which is what I need, psychologically, to get on with it.</p>
<p>So, one of the major inspirations for NABTO is Python.
I use Python a lot, and I wonder what it would be like to use a language that is like Python, but, at a few points, does things the way I would do them, seeing how they worked out in Python.</p>
<p>Two big pain points for me in Python are inheritance and <tt class="docutils literal">__init__</tt> methods.
As of the last few years, when I'm left to my own devices, I use inheritance rarely, and explicit <tt class="docutils literal">__init__</tt> methods less.
Here are the statistics from the current MOTR codebase:</p>
<ul class="simple">
<li>Classes that inherit:<ul>
<li>From <tt class="docutils literal">typing.Generic</tt>: 20</li>
<li>From <tt class="docutils literal">typing.Protocol</tt>: 16</li>
<li>From <tt class="docutils literal">enum.Enum</tt>: 3</li>
<li>Internally: 9</li>
<li>From third-party code: 3</li>
<li>From an exception: 2</li>
<li>Not at all: 41 (+2 required to exist by third-party code, but with no inheritance)</li>
</ul>
</li>
<li>Explicit definitions of <tt class="docutils literal">__init__</tt>: 0 (thank you, <a class="reference external" href="https://www.attrs.org/">attrs</a>)</li>
</ul>
<p>So, from looking over these, we have 39 instances of inheriting from the standard library to get specific functionality, most of the internal ones and the exceptions are cases of ontological inheritance, and the third-party stuff is to hook into third-party functionality by inheriting a bunch of functionality.</p>
<p>Ontological inheritance is one of three kinds laid out in <a class="reference external" href="https://www.sicpers.info/2018/03/why-inheritance-never-made-any-sense/">this post</a>.
The others are abstract data type inheritance and implementation inheritance.
For my purposes, I'm going to separately consider <em>inheriting the implementation from a concrete class</em> and <em>inheriting the implementation from an abstract class</em>.
I like this distinction because I generally distrust the former, and I apparently do the latter <em>a lot</em>.</p>
<p>So, if I want NABTO to reflect my own ideas about how to code, how do these different types of inheritance look?</p>
<p>Suppose we consider different types of inheritance to be associated with different types of type.</p>
<p>We can have <strong>concrete types</strong> that represent some data in memory and a set of associated behaviors.
We can have <strong>ontological types</strong> that represent open or closed sets of values.
We can have <strong>abstract data types</strong> that represent the contracts that a value upholds.
We can have <strong>mixin types</strong> that provide implementations of behavior without reference to state.</p>
<p>As to how these types can relate to each other:</p>
<ul class="simple">
<li><strong>concrete types</strong> can have their instances point to other values, which will also be instances of <strong>concrete types</strong>.</li>
<li><strong>concrete types</strong> can be added to open <strong>ontological types</strong>; multiple inheritance imposes no constraints on ordering.</li>
<li><strong>concrete types</strong> can implement the contracts of <strong>abstract data types</strong>; multiple inheritance imposes no constraints on ordering.</li>
<li><strong>concrete types</strong> can inherit from <strong>mixin types</strong>; multiple inheritance imposes constraints on ordering, and I think the safe bet is C3.</li>
<li><strong>ontological types</strong> can relate to each other, and I'm not sure they should relate to anything else?</li>
<li><strong>abstract data types</strong> can require that their operations take values of specific <strong>concrete types</strong>, or that conform to other <strong>abstract data types</strong>, but I don't know if it makes sense for them to care about <strong>ontological types</strong> or <strong>mixin types</strong>; they can also inherit from each other to express relations like "a sequence is also a container" or whatever.</li>
<li><strong>mixin types</strong> can inherit from each other, and their methods can specify <strong>concrete types</strong>, or ideally <strong>abstract data types</strong>, in their signatures.</li>
</ul>
<p>Right, signatures.
I kind of want to see how gradual typing looks when it isn't bolted on after-the-fact.
Maybe there are languages out there that are trying that, but after all of the languages I name-checked yesterday, I feel a little researched-out.</p>
<p>That off-hand reference I made to open <em>or closed</em> ontological types earlier made me realize something.
Exception handlers in Python are like match statements that only work on instances of a particular type, passing through specific mechanisms.
I'm really interested in Koka's ideas about minimalism; seeing them in action caused some ideas that have been kicking around in my head for over a decade to make sense, so let's see if anything inspires me there...</p>
<p>First off, I had some ideas for using one type <em>like</em> another type.
Like, <strong>concrete types</strong> and <strong>abstract data types</strong> could be used as ontological types for some purposes, and a <strong>concrete type</strong> could be used as an <strong>abstract data type</strong>.
My gut feeling is that using <strong>concrete types</strong> like that is likely to be a problem a lot of the time, but I think experience is worth more than feelings, so I think it should be allowed, but warned against.
That way, if someone really needs it, they've got it.</p>
<p>(This sort of clarifies some of the uses of <strong>concrete types</strong>, above.
<em>Actually</em>, it's a <strong>concrete type</strong> being interpreted as an <strong>abstract data type</strong>.)</p>
<p>It's getting late, and this post is apparently quite long, so I'm just going to spitball some thoughts about how different types of types could interact with match constructs.</p>
<ul class="simple">
<li>Only <strong>concrete types</strong> could perform destructuring match, since the other types don't specify a structure.
I haven't gone over the aspects of <strong>concrete types</strong> that should make destructuring possible.</li>
<li><strong>Ontological types</strong> could check for membership, which is straightforward enough.</li>
<li>I'm not clear on what <strong>abstract data types</strong> or <strong>mixin types</strong> could do in the context of a match.</li>
</ul>
<p>After thinking about this a little more, my feeling is that <strong>concrete types</strong> should handle their own destructuring, so the language- or library- level matches should deal with <strong>ontological types</strong>.</p>
<p>In any case, this doesn't quite feel fully baked, but I want to be done with writing tonight.
I think what I need to do is put together a Sphinx project for documenting how I think this all should work, before I try to prototype it.</p>
<p>Good night.</p>
Coding 2022-08-242022-08-24T04:00:00-04:002022-08-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-24:/coding-2022-08-24<p class="first last">This is going to look so much nicer after I roll out the new stylesheet.</p>
<p>I figured I'd talk some about something that's been on my mind, something that got me looking into Koka.
It's <a class="reference external" href="https://eev.ee/blog/2015/02/28/sylph-the-programming-language-i-want/">this post</a>.
There are a bunch of interesting ideas in there, and I'm interested in seeing, more or less, what happens if I aim for a point in the design space somewhere in the convex hull of this post, Koka, Python, and the CLOS (n.b. I do not know Common Lisp, so I'm trying to get this through reading The Art of the Metaobject Protocol).</p>
<p>There are <em>a lot</em> of fiddly points to consider.
Like, should there be a Python-style descriptor protocol?
Koka (and Perl, I think, and presumably other things) style nullary functions with implicit parens?
Both, somehow?</p>
<p>But I want to focus on one bit from Eevee's post, where she's talking about Python, and I'm not sure she's correct.</p>
<p>Let's quote the relevant bit.</p>
<blockquote>
Magic methods work differently from other methods, in that they only work when assigned to the class and not when assigned to an instance. It turns out there’s not actually a good reason for this.</blockquote>
<p>This is going to need a bit of unpacking.</p>
<p>To start with, let's talk specifically about infix operators, like <tt class="docutils literal">+</tt>.
Haskell and Koka implement infix operators with a bunch of syntactic sugar, that allows the representation of the operator to be named in prefix form.
So, if you crack open the definition of, say, list concatenation, you get</p>
<div class="highlight"><pre><span></span><span class="p">(</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="kt">[]</span><span class="w"> </span><span class="n">ys</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">ys</span>
<span class="p">(</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="kt">:</span><span class="n">xs</span><span class="p">)</span><span class="w"> </span><span class="n">ys</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="n">xs</span><span class="w"> </span><span class="o">++</span><span class="w"> </span><span class="n">ys</span>
</pre></div>
<p>or</p>
<div class="highlight"><pre><span></span><span class="c1">// Append two lists.</span>
<span class="n">pub</span><span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">(++)</span><span class="p">(</span><span class="n">xs</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">list<a></span><span class="p">,</span><span class="w"> </span><span class="n">ys</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">list<a></span><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">list<a></span>
<span class="w"> </span><span class="na">append(xs,ys)</span>
<span class="c1">// Append two lists.</span>
<span class="na">pub</span><span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">append</span><span class="p">(</span><span class="n">xs</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">list<a></span><span class="p">,</span><span class="w"> </span><span class="n">ys</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">list<a></span><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">list<a></span>
<span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">xs</span>
<span class="w"> </span><span class="ge">Cons</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">xx</span><span class="p">)</span><span class="w"> </span><span class="k">-></span><span class="w"> </span><span class="ge">Cons</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">append</span><span class="p">(</span><span class="n">xx</span><span class="p">,</span><span class="n">ys</span><span class="p">))</span>
<span class="w"> </span><span class="ge">Nil</span><span class="w"> </span><span class="k">-></span><span class="w"> </span><span class="n">ys</span>
</pre></div>
<p>Unlike Haskell or Koka, Python implements "define an implementation of an infix operator" by having the class in question define a method named with <tt class="docutils literal">__double_underscores__</tt>, like <tt class="docutils literal">+</tt> with <tt class="docutils literal">__add__</tt>.
(And <tt class="docutils literal">__radd__</tt>, and there's also <tt class="docutils literal">__iadd__</tt>, which should do something <em>similar</em> to <tt class="docutils literal">__add__</tt> but not the same, and...)</p>
<p>Python also uses this kind of mechanism for unary operations, and various other bits of built-in functions and syntax.
Now, what "works" here is the mapping between "fancy syntax" and "the actual method implementation".
If you have</p>
<div class="highlight"><pre><span></span><span class="n">my_var</span> <span class="o">+</span> <span class="mi">3</span>
</pre></div>
<p>then executing that code is going to result in the <tt class="docutils literal">__add__</tt> method being looked up on the <em>type</em> of <tt class="docutils literal">my_var</tt>, and passed <tt class="docutils literal">my_var</tt> and <tt class="docutils literal">3</tt>.
You can get similar behavior by invoking the method directly on the instance, although this is brittle in certain ways:</p>
<div class="highlight"><pre><span></span><span class="k">assert</span> <span class="n">my_var</span><span class="o">.</span><span class="fm">__add__</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="o">==</span> <span class="n">my_var</span> <span class="o">+</span> <span class="mi">3</span>
</pre></div>
<p>(If we used a user-defined type for the right-hand side, this would not necessarily hold.
This is getting into that <tt class="docutils literal">__radd__</tt> stuff from earlier.)</p>
<p>What Eevee is pondering is the equivalent of</p>
<div class="highlight"><pre><span></span><span class="n">my_var</span><span class="o">.</span><span class="fm">__add__</span> <span class="o">=</span> <span class="n">custom_add_function</span>
<span class="k">assert</span> <span class="n">my_var</span><span class="o">.</span><span class="fm">__add__</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="o">==</span> <span class="n">my_var</span> <span class="o">+</span> <span class="mi">3</span>
</pre></div>
<p>This is not likely to work, because Python doesn't look up the "magic" method on the instance at all.</p>
<p>As to why I'm not currently comfortable with the statement that "there's not actually a good reason for this", we'll have to look at the reasons that I do see for it.</p>
<p>If I'm understanding my experiments correctly, attribute access in Python essentially "looks" in two different directions.</p>
<p>On an instance that is not a type, <tt class="docutils literal">instance.attr</tt> will check the instance dictionary for <tt class="docutils literal">attr</tt>, and the instance dictionary of its type, and its type's ancestors.
The behavior is eerily configurable if you're determined, and the default behavior is slightly more involved than I feel like summarizing currently.</p>
<p>On an instance that is a type, the <tt class="docutils literal">my_type.attr</tt> situation is similar, except that now the <em>instance</em> has type ancestors to contend with, as well as the ancestors of its types.
(The type of a type should be a subtype of the type of its supertypes, so there's no problem only checking the type of the instance itself.)</p>
<p>Where things get hairy is not necessarily <tt class="docutils literal">__add__</tt>, but one of the more commonly invoked operations of a type.</p>
<p>Suppose we want to create a type whose instances can be called like a function.
This looks like</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyClass</span><span class="p">:</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="o">...</span>
</pre></div>
<p>Now, one type whose instances are often called like a function is... <tt class="docutils literal">type</tt>.</p>
<div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">class</span> <span class="nc">TalkyMeta</span><span class="p">(</span><span class="nb">type</span><span class="p">):</span>
<span class="gp">... </span> <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="s2">"Hi there!"</span><span class="p">)</span>
<span class="gp">... </span> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__call__</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">>>> </span><span class="k">class</span> <span class="nc">Talky</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">TalkyMeta</span><span class="p">):</span>
<span class="gp">... </span> <span class="k">pass</span>
<span class="gp">...</span>
<span class="gp">>>> </span><span class="n">Talky</span><span class="p">()</span>
<span class="go">Hi there!</span>
<span class="go"><__main__.Talky object at 0x7fd4850de110></span>
</pre></div>
<p>As long as we have types acting as the main entry point for constructing their instances, using the <tt class="docutils literal">__call__</tt> method, then we can't look up all "magic" methods on the instance without making it <em>highly inconvenient</em> to construct an instance of a type that overrides <tt class="docutils literal">__call__</tt> so its instances can emulate functions.</p>
<p>For what it's worth, Lua's metamethods avoid taking a stand on this by not allowing the instance to access the metamethods via instancing unless you specifically hook it up like that.
There's one table for metamethods, and another table for extra attributes visible on the instance, and maybe they're the same table, but they don't <em>have to be</em>.</p>
<p>It's getting late, so I'll just say that my gut feeling is that, instead of trying to make the magic method lookup take the instance dictionary into account, it should (somehow) get its own mapping on the type, distinct from the "stuff that the instance delegates to explicitly".</p>
<p>This raises a bunch of questions in the context of language design, so this idea is way more of a starting point than an ending point, so there's plenty more for me to think about, later.</p>
<p>Good night.</p>
Weekly Roundup 2022-08-232022-08-23T04:00:00-04:002022-08-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-23:/weekly-roundup-2022-08-23<p class="first last">Soon™</p>
<ul class="simple">
<li>Wednesday: I looked into the blog's mobile usability issues, since apparently the blog is in the mobile crawler bucket.</li>
<li>Thursday: I did a bunch of work on the draft changes to the templates and stylesheet, and virtually no work on the post.</li>
<li>Friday: I made a bunch of progress on the redesign.</li>
<li>Saturday: I didn't get too much done, because I was watching a baseball game on Twitch.</li>
<li>Sunday: Some work done, but it didn't really feel like much.</li>
<li>Monday: I basically finished my stretch goals for the redesign.</li>
</ul>
<p>Next week, I'm going to take a few days off from the redesign, check over it, and roll it out, let's say, over the weekend.
Ish.
I've got other stuff I want to mess around with in the meantime, but I'm not sure how much I'm up for, since I was sick yesterday and didn't fully realize it.</p>
Site Design 2022-08-222022-08-22T04:00:00-04:002022-08-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-22:/site-design-2022-08-22<p class="first last">Closing in...</p>
<p>I've been tweaking things, and now I think I just need some time to consider any further changes I may want to change.</p>
<p>When I tested out the Bonus Content, I ran into some issues that imply to me that I need to remake it.
Fortunately, it's just the assets, all of the code and styling is done.
I might have time to redo this after this post, but I don't want to block this post on that.</p>
<p>I didn't get to the Python code I wanted to update, but oh well.
Not sure about next weekend, but we'll see.</p>
<p>Anyway, I want to wrap up for now.</p>
<p>Good night.</p>
Diary 2022-08-212022-08-21T04:00:00-04:002022-08-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-21:/diary-2022-08-21<p class="first last">I'm not sure what <em>happened</em> to today, but sure, whatever.</p>
<p>All right, the blog code is handling the new directive for the Bonus Content.
I still need to create the theming to go along with it, and make sure I can properly integrate it with the stylesheet, but at least I know I won't trip over my shoelaces at the finish line.</p>
<p>I finished my stretch goals for the tooling stuff for my other writing today, so that's good.</p>
<p>And I took some design notes on the Bonus Content.</p>
<p>Sadly, I didn't have time to work on the Python code or the writing, but I'll at least try to lay the groundwork for the writing tomorrow.
I just created the project file that I'm going to import the current draft into.
That's a small step, and I could do it at any time, so why not now, I figure.</p>
<p>That doesn't apply to anything else, because I have like half an hour to midnight, and I'd rather not spend all of it on these entries.</p>
<p>Basic tasks for tomorrow:</p>
<ul class="simple">
<li>Refresh my memory on the Python code, maybe start fixing stuff up.</li>
<li>Sketch concrete designs for the Bonus Content.</li>
<li>Get on with importing the draft.</li>
</ul>
<p>The big thing I need to handle that is to try and actually do stuff in the morning.
For now, I'm going to get ready for bed.</p>
<p>Good night.</p>
Diary 2022-08-202022-08-20T04:00:00-04:002022-08-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-20:/diary-2022-08-20<p class="first last">CONFUSED blogger HELD HOSTAGE by PSYCHO UMPIRE</p>
<p>Okay, so, this isn't going to be a long entry because I didn't have time to come up with anything.
I like that things are coming together with the site design, but I've got other stuff I want to be working on.</p>
<p>I think my best bet there is to get to bed as soon as I can, then make sure I have a properly relaxing morning.
We'll see how that plan works out for me.</p>
<p>Basically, I want to take care of the following things:</p>
<ul class="simple">
<li>Art design for the remaining parts of the site rework.</li>
<li>Code support for the remaining parts of the site rework.</li>
<li>Final tweaks to some of the support tooling for my other writing.</li>
<li>Begin the next editing pass on the other writing.</li>
<li>Juggle python projects.</li>
</ul>
<p>Yeah, this seems somewhat... ambitious.
But we'll see tomorrow.
For now, I need to sleep.</p>
<p>Good night.</p>
Site Design 2022-08-192022-08-19T04:00:00-04:002022-08-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-19:/site-design-2022-08-19<p class="first last">Readying all sorts of cursed nonsense...</p>
<p>Things are coming together on the redesign.
More accent colors showing things off and spacing things out, better scrolling behavior, local fonts so my fonts get served from the same CDN as my content, tags overhauled to show up properly...</p>
<p>By the way, I don't <em>mind</em> if anyone tries to copy stuff from this site's CSS, either before or after I roll out the update, but if it does occur to you, keep in mind that I'm self-taught, and using trial and error on a small set of browser configurations.
While I believe the style and template updates will represent a net improvement in presentation quality, there could be all kinds of regressions or unaddressed issues.</p>
<p>I want to take a few days to poke around for additional issues, and work on the Sweet Bonus Feature that I was prioritizing everything else over.
At some point, I should maybe try to put together some kind of automated tool for evaluating drafts of the blog without having to click around myself to find every issue like "Oh no, this rule is applying too much", or "this element still has the wrong width if the screen is too narrow" or "there are too many scroll bars".</p>
<p>Anyway, yeah, a better phone experience is coming.
At least, assuming that "smush it into a smaller viewport than apparently anything on the market, and assume it works at all intermediate resolutions" is valid <em>enough</em> as a way of improving the phone experience.</p>
<p>Good night.</p>
Site Design 2022-08-182022-08-18T04:00:00-04:002022-08-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-18:/site-design-2022-08-18<p class="first last">Tags are coming back.</p>
<p>I made a bunch of improvements or changes to the site layout and templates on a branch, and I'll hopefully be able to roll it out soon.</p>
<p>I spent too long working on that to have anything more substantive to write in this entry byyyyye</p>
<p>Good night.</p>
Site Design 2022-08-172022-08-17T04:00:00-04:002022-08-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-17:/site-design-2022-08-17<p class="first last">Pondering some shakeups and improvements...</p>
<p>While I was thinking about stuff to do, I remembered that Google was yelling at me about mobile usability.
(I don't know, the blog works fine on <em>my</em> phone...)</p>
<p>Anyway, that got me thinking about updates to make to the site.</p>
<p>For myself, I want to look into a few possibilities:</p>
<ul class="simple">
<li>Make the main content area wider, mainly to fit more code on the screen when I'm messing with code blocks.
So, my maximum goal there is 76 characters.</li>
<li>Add previous/next controls to the <em>top</em> of pages that only have them at the bottom (and vice versa, if applicable)</li>
<li>SECRET BONUS STUFF</li>
<li>Maybe I can try to get tags working again?</li>
</ul>
<p>Google is raising a bunch of usability issues, but it's not raising them about any pages <em>currently</em>, and it only raises them about <em>a few pages at a time</em>, which...
That's weird, right?
I'm not doing anything radically different on different pages that would result in <em>exactly seven</em> pages having issues with:</p>
<ul class="simple">
<li>Small text (it can't be complaining about the main body text, right? That's 18px)</li>
<li>Clickable elements too close together</li>
<li>Viewport not set</li>
</ul>
<p>I guess I'm going to have to research viewport stuff.
Like, what's the viewport to set for "it's a static blog, I don't care"?</p>
<p>From further messing-around, I haven't gotten it to pin down a specific broken page, so I'm going to ignore the text and clickable elements for now, and look into the viewport, because I could believe that's an issue even if it doesn't show up when I have it test a page (???).</p>
<p>In any case, I'm going to finish up and publish this post, then queue up some reading for later on responsive web design, because I guess I need to look into that.</p>
<p>Good night.</p>
Weekly Roundup 2022-08-162022-08-16T04:00:00-04:002022-08-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-16:/weekly-roundup-2022-08-16<p class="first last">An entirely predictable slowdown.</p>
<ul class="simple">
<li>Wednesday: I planned out some stuff for generating HTML with Koka.</li>
<li>Thursday: I went a little further with that, speculating about various representations that would make sense at different stages.</li>
<li>Friday: I did work on the HTML stuff and other stuff, mostly the HTML stuff.</li>
<li>Saturday: I was wiped out from traveling.</li>
<li>Sunday: I revisited some of the code that MOTR is <em>for</em>, and updated it.</li>
<li>Monday: I was wiped out from traveling again, so I decided to mess with a new project that I'd picked up over the weekend.</li>
</ul>
<p>Next week, I don't know, I'm not quite up for planning I guess.
Try to get spun back up with Koka, maybe.</p>
Coding 2022-08-152022-08-15T04:00:00-04:002022-08-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-15:/coding-2022-08-15<p class="first last">*Waves hands erratically, muttering about "monotone"*</p>
<p>Uuuugh...</p>
<p>We were wiped out by travel today, so I'm going to just focus on the graph stuff I was working on earlier.</p>
<p>Basically, I don't have a specific usage in mind for this, but I feel like it'd be interesting to have a <tt class="docutils literal">Graph[T]</tt> data type that can hold many different types of data (so it's functionally going to end up as a <tt class="docutils literal">Graph[T | U | V | W | <span class="pre">...]</span></tt>, and I admit I'm not sure if I can strike a good balance between useful interface and type safety here...), that takes typed edges to move between vertices.
(The likely endpoint for this, if it makes any significant progress, is "not-very-good database".)</p>
<p>One thing that I wanted was to have a distinction between "edges added explicitly" and "edges calculated from other edges".
(And potentially, some of these "calculated" edges could have the ability to act as a shortcut for adding explicit edges, provided there's a unique minimal graph satisfying "this edge goes between these points".)
Now, something that I hadn't fully worked out until recently, and I think it's going to be significant, is that "calculated" edges can't just produce an arbitrary value; it has to be an actual vertex in the graph, and the only way to guarantee that is to only work with the graph structure, and ignore the actual contents of the vertices.</p>
<p>The thing that I'm trying to figure out right now is, when does it make sense to talk about following an edge backwards?
Explicit edges can always be followed backwards.</p>
<p>Let's do a hand-wavey induction thing and consider, supposing we have some collection of "reversible" edges, how can they be composed?</p>
<p>Basically, an edge takes a vertex in a graph to a set of other vertices, so "calculated" edges need to just combine and work with these sets.</p>
<ul class="simple">
<li>We can produce an edge by intersecting the sets of two edges, and reverse that edge by intersecting their reversals; similarly for unions.</li>
<li>We can also compose two edges and union the resulting set of sets; I'm not sure that intersecting the set of sets makes sense.
... Rather, it's that I <em>think</em> the union reverses cleanly, and the intersection doesn't.
With the union, you're basically saying "this edge, then this edge".
With the intersection, I was going to try to work through some stuff, but then I realized, wait; you can make the intersection of the composition <em>shrink</em> by <em>adding edges</em>.
That's wrong, I think.</li>
<li>We can extend an existing edge with a predicate function that takes two variables; this does allow us to reach into the vertex data, but only for the purpose of choosing a course of action regarding vertices that exist.</li>
<li>Now, maybe there's some way to extend that concept, because I know I want something like:<ul>
<li>An edge that exists if underlying edge <tt class="docutils literal">E1</tt> exists</li>
<li>But only if the target vertex has an edge <tt class="docutils literal">E2</tt> to vertex <tt class="docutils literal">V</tt>.</li>
<li>This is fundamentally just a predicate that requires the graph in order to define it, so let's just throw another variable in there.</li>
</ul>
</li>
</ul>
<p>I realized the stuff in that list, not quite in the order that I placed it up there, so now I've got two things:</p>
<ul class="simple">
<li>Confidence that every edge type I've thought of should be reversible.</li>
<li>Knowledge that I have to be careful with the graph-based predicate idea.
Like, that's going to break if it's possible to express the idea of "express this edge if this other edge <em>doesn't</em> exist".</li>
</ul>
<p>An incomplete list of things that should probably work with that:</p>
<ul class="simple">
<li>Reasoning about the unions of arbitrary sets</li>
<li>Reasoning about the intersections of predefined sets</li>
<li>Filtering a set based on a predicate that doesn't refer to the graph</li>
</ul>
<p>A lot of this graph stuff is basically a recreation of the "calculated" edge stuff, which implies that it should be possible to express these "graph" predicates <em>as</em> edges, and instead of "three-argument predicate", have something that's just "if this edge exists, and this other edge leads from the [start/end] of that edge, to at least one other vertex".
(Maybe allow reasoning about cardinality in order to be <em>fancy</em>, but it's not obvious to me why the threshold should ever be higher than 1.)</p>
<p>This has been some good rubber-ducking for a project that I don't have any idea what I'm going to do with it, and frankly, I'll take that.</p>
<p>Good night.</p>
Coding 2022-08-142022-08-14T04:00:00-04:002022-08-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-14:/coding-2022-08-14<p class="first last">Hate to see it when a bunch of stuff failed, and the only thing that changed on my end was the passage of time.</p>
<p>I'm still kind of out of it, so instead of holding myself to grinding out some improvements to MOTR, I had a look at one of the projects I intend to use it with.
The project had suffered some bitrot, so I took the time to update the things that had changed.</p>
<p>Basically:</p>
<ul class="simple">
<li>It was using my old fork of flake8-html, so I pushed my local copy to GitHub, and pointed both MOTR and this project's requirements files to the branch, so that other people could, in theory, run the test suites and see the failures for themselves.
I also updated the fork with the latest commits from master.
And pinned the flake8 version for now.</li>
<li>Mypy got some good updates that I had to update some of my code to deal with.
The result probably makes more sense.</li>
<li>The shiv build step included an argument being passed to pip that broke the build because it wasn't recognized.
So I removed it, and it seems fine?
I wonder why I had it in the first place...
Ah, looks like I was checking for any fallout from a then-upcoming change to pip, that went in, so they took out the option to enable it.</li>
</ul>
<p>Anyway, one reason I'd been looking at this repo is that it hosts my punq fork (which I'm going to rename, for sure).
The fork relies on the behavior of PEP 563 to construct nicely namespaced types in a registry for dependency injection.
My impression of the plans for annotations is "switch to PEP 649, once we figure out how", so I figured I'd investigate things in this area.
I'm aware that the switch will break the punq fork in fascinating ways (and I'm not totally clear on how original punq will handle it when it comes around), but my impression from looking at some of this code, and thinking about the rest, is that I can probably just get rid of a bunch of non-standard behavior, replace it with <tt class="docutils literal">NewType</tt>s, and delete a whole bunch of code that I barely remember writing, but that I know for a fact isn't anybody else's fault.</p>
<p>I'm thinking I'll mostly write this weekend off and mess around with other stuff, but once I've got my energy back, I think it'd make sense to alternate between updating MOTR and this other repository.
Like, make changes to one repository, run tests, spend a few minutes on the other, run tests, go back to check the first set of tests...</p>
<p>That seems like it makes sense.
Next week, or later, I'll see how it shakes out in practice.</p>
<p>I've got a bit more time tonight, so I'm going to mess around with something else for now, to blow off steam.</p>
<p>Good night.</p>
Diary 2022-08-132022-08-13T04:00:00-04:002022-08-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-13:/diary-2022-08-13<p class="first last">One hundred miles of travel. Head full of swirling thoughts that are getting jammed trying to leave, because they're all trying to go at once.</p>
<p>We were on the road for a while, so I'm not really capable of focusing on stuff.
My short-term plan is to write this entry, then scribble some ideas on paper.</p>
<p>There are a bunch of ideas swirling around in my head, and I need to take some time to crystallize them, and hopefully I'll be able to pursue them later, either in Python once I have MOTR in an acceptable condition, or in some other language if it'd be a better fit.</p>
<p>Stuff about graph data types, and what inheritance should accomplish in a programming language idea I'm messing with.
And probably other things that I'm not remembering offhand.
There's no direct relationship between any of these ideas, but I'm thinking about them at the same time.</p>
<p>Good night.</p>
Learning Koka 2022-08-122022-08-12T04:00:00-04:002022-08-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-12:/learning-koka-2022-08-12<p class="first last">I'm going to need to write more stuff down and stop trying to get this done in my head.</p>
<p>I'm having a kind of distracting few days, so I might not get much written for a few entries.</p>
<p>I did mess with some other stuff in Koka earlier today, but I didn't have much luck; it looks like some of the generics stuff I wanted to do is not super obvious in the documentation, if it's even possible.</p>
<p>Anyway, I'll write some quick obvious code for the HTML stuff.</p>
<p>Hm, wasn't as quick as I thought, and also I found some limitations in the vim plugin for Koka, which isn't a surprise, since I think it's a third-party thing.</p>
<p>I don't want to stay up overlong, so I'm going to start winding down now.</p>
<p>Good night.</p>
Learning Koka 2022-08-112022-08-11T04:00:00-04:002022-08-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-11:/learning-koka-2022-08-11<p class="first last">Not totally confident about this approach, but let's see how it shakes out...</p>
<p>I'm going to stick to the HTML stuff for now, rather than switching with the structuring concurrency.</p>
<p>I have a feeling that I'm doing something kind of imprecise with my mental models of this tag rendering stuff, so let's see what happens if I try to lay down some details.</p>
<div class="highlight"><pre><span></span><span class="ge">Tag</span><span class="p">(</span>
<span class="w"> </span><span class="s2">"html"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[],</span>
<span class="w"> </span><span class="ge">Just</span><span class="p">(</span>
<span class="w"> </span><span class="p">(</span>
<span class="w"> </span><span class="s2">""</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="p">(</span><span class="ge">Tag</span><span class="p">(</span><span class="s2">"head"</span><span class="p">,</span><span class="w"> </span><span class="p">[],</span><span class="w"> </span><span class="ge">Just</span><span class="p">((</span><span class="s2">""</span><span class="p">,</span><span class="w"> </span><span class="p">[]))),</span><span class="w"> </span><span class="s2">""</span><span class="p">),</span>
<span class="w"> </span><span class="p">(</span><span class="ge">Tag</span><span class="p">(</span><span class="s2">"body"</span><span class="p">,</span><span class="w"> </span><span class="p">[],</span><span class="w"> </span><span class="ge">Just</span><span class="p">((</span><span class="s2">""</span><span class="p">,</span><span class="w"> </span><span class="p">[]))),</span><span class="w"> </span><span class="s2">""</span><span class="p">),</span>
<span class="w"> </span><span class="p">]</span>
<span class="w"> </span><span class="p">)</span>
<span class="w"> </span><span class="p">)</span>
<span class="p">)</span>
</pre></div>
<p>Which should turn into</p>
<div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">html</span><span class="p">><</span><span class="nt">head</span><span class="p">></</span><span class="nt">head</span><span class="p">><</span><span class="nt">body</span><span class="p">></</span><span class="nt">body</span><span class="p">></</span><span class="nt">html</span><span class="p">></span>
</pre></div>
<p>Obviously, the Koka code is not how stuff should be written out manually...</p>
<p>And to tweak the output a bit...</p>
<div class="highlight"><pre><span></span><span class="ge">Tag</span><span class="p">(</span>
<span class="w"> </span><span class="s2">"html"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[],</span>
<span class="w"> </span><span class="ge">Just</span><span class="p">(</span>
<span class="w"> </span><span class="p">(</span>
<span class="w"> </span><span class="s2">""</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="p">(</span><span class="ge">Tag</span><span class="p">(</span><span class="s2">"head"</span><span class="p">,</span><span class="w"> </span><span class="p">[],</span><span class="w"> </span><span class="ge">Just</span><span class="p">((</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span><span class="w"> </span><span class="p">[]))),</span><span class="w"> </span><span class="s2">""</span><span class="p">),</span>
<span class="w"> </span><span class="p">(</span><span class="ge">Tag</span><span class="p">(</span><span class="s2">"body"</span><span class="p">,</span><span class="w"> </span><span class="p">[],</span><span class="w"> </span><span class="ge">Just</span><span class="p">((</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span><span class="w"> </span><span class="p">[]))),</span><span class="w"> </span><span class="s2">""</span><span class="p">),</span>
<span class="w"> </span><span class="p">]</span>
<span class="w"> </span><span class="p">)</span>
<span class="w"> </span><span class="p">)</span>
<span class="p">)</span>
</pre></div>
<p>Which should produce</p>
<div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">html</span><span class="p">></span>
<span class="p"><</span><span class="nt">head</span><span class="p">></span>
<span class="p"></</span><span class="nt">head</span><span class="p">></span>
<span class="p"><</span><span class="nt">body</span><span class="p">></span>
<span class="p"></</span><span class="nt">body</span><span class="p">></span>
<span class="p"></</span><span class="nt">html</span><span class="p">></span>
</pre></div>
<p><em>How it gets there</em> doesn't feel straightforward to me.
Like, maybe there can be a list of lines, where each line is a list of elements, and once the line includes a line break, it gets split up into a bunch of lines?</p>
<p>So there's then another representation like</p>
<div class="highlight"><pre><span></span><span class="p">[</span>
<span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="ge">StartTag</span><span class="p">(</span><span class="s2">"html"</span><span class="p">,</span><span class="w"> </span><span class="p">[]),</span>
<span class="w"> </span><span class="ge">StartTag</span><span class="p">(</span><span class="s2">"head"</span><span class="p">,</span><span class="w"> </span><span class="p">[]),</span>
<span class="w"> </span><span class="ge">EndTag</span><span class="p">(</span><span class="s2">"head"</span><span class="p">),</span>
<span class="w"> </span><span class="ge">StartTag</span><span class="p">(</span><span class="s2">"body"</span><span class="p">,</span><span class="w"> </span><span class="p">[]),</span>
<span class="w"> </span><span class="ge">EndTag</span><span class="p">(</span><span class="s2">"body"</span><span class="p">),</span>
<span class="w"> </span><span class="ge">EndTag</span><span class="p">(</span><span class="s2">"html"</span><span class="p">),</span>
<span class="w"> </span><span class="p">],</span>
<span class="p">]</span>
</pre></div>
<p>I've drafted out basic code for representing this stuff, but I should figure out how to represent stuff like "tags that don't reflow their content in a templating context".</p>
<p>I'll have to think about that some, maybe switch gears again later.
For now, I'm tired.</p>
<p>Good night.</p>
Learning Koka 2022-08-102022-08-10T04:00:00-04:002022-08-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-10:/learning-koka-2022-08-10<p class="first last">All of this <em>stuff</em> going on with HTML that I usually don't think about...</p>
<p>I thought about stuff to do with Koka, and I ended up deciding to try to focus on one subsystem from the hypothetical CGI idea: just generating HTML.</p>
<p>The basic thing I'm interested in trying to do, is to make the generated HTML indent nicely.
If you ask around online, people will tell you this is "not important" and such, but I'm looking for something that interests me, rather than that addresses any burning need.</p>
<p>I'm thinking some kind of library of functions that lets you write all of this as code.
Have functions for each tag.
So, what we need to know about how this stuff all works?</p>
<p>Well, there's the doctype thing.
Some tags can only appear in specific contexts, which it <em>might</em> make sense to express in the type system.
For now, I'll just think about that in terms of the <tt class="docutils literal"><html></tt>, <tt class="docutils literal"><head></tt>, and <tt class="docutils literal"><body></tt> tags, since those are simple.</p>
<p>Maybe try to separately address "this is how to convert this tag object to a string" and "this is how tag objects are allowed to relate to each other".</p>
<p>Like, a generic representation of "HTML tags, but ignoring all semantics"...
That looks something like:</p>
<ul class="simple">
<li>a tag name</li>
<li>an alist of attribute-value pairs</li>
<li><tt class="docutils literal">maybe<></tt> a structure that represents the tag contents, which can be, say, <tt class="docutils literal">maybe<></tt> a string, followed by a vector or list of tag-text pairs.</li>
</ul>
<p>I believe a few tags would need special-casing (I'm thinking <tt class="docutils literal"><pre></tt> and <tt class="docutils literal"><script></tt> at least), but the majority should be able to work from just that.</p>
<p>Anyway, I let this get late.
I'll actually try to code stuff later.</p>
<p>Good night.</p>
Weekly Roundup 2022-08-092022-08-09T04:00:00-04:002022-08-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-09:/weekly-roundup-2022-08-09<p class="first last">Computers are weird.</p>
<ul class="simple">
<li>Wednesday: I tried to explain what interests me about Koka.</li>
<li>Thursday: I talked about using Koka for a specific practical-ish application.</li>
<li>Friday: I speculated about what a structured concurrency library in Koka would look like.</li>
<li>Saturday: I did some more work on CGI in Koka, and ran into bizarre issues that kind of make me want to come up with some other project for Koka, and I'll mess with rolling my own CGI library in Lua or whatever.</li>
<li>Sunday: I started reviewing MOTR's codebase to look for obvious problems, and sorted them in rough order of when I want to be working on them.</li>
<li>Monday: I finished the review, though I'm going to need a few more passes.
I also made some of the changes, and got to see how justified they were because I was squinting at some lines going "Wait, <em>which</em> of these attribute accesses is broken?"</li>
</ul>
<p>Next week, I guess I'll look for some other project to switch off with for the structured concurrency stuff.</p>
Coding 2022-08-082022-08-08T04:00:00-04:002022-08-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-08:/coding-2022-08-08<p class="first last">Got to get rid of the Smurf-oriented programming.</p>
<p>Starting again, picking up from yesterday...</p>
<ul class="simple">
<li>Change ASAP<ul>
<li>Names<ul>
<li><tt class="docutils literal">CommandBuilder</tt> needs a different name for the <tt class="docutils literal">command</tt> attribute, which needs a new name for its type.</li>
<li>In fact, I believe the type should be renamed <tt class="docutils literal">Executable</tt>, after the fact that the <tt class="docutils literal">x</tt> bit is set on the file, and <em>its</em> <tt class="docutils literal">command</tt> attribute should be <tt class="docutils literal">name</tt> instead.
The same file has some type aliases that derive from the type, and they should be updated as well.
Consider renaming <tt class="docutils literal">Metadata</tt>, mainly because it's not a very descriptive name.
It might fare better if I moved it to the <tt class="docutils literal">command_builder</tt> module.
Consider that.</li>
<li>The <tt class="docutils literal">entry</tt> module seems reasonable, but come back to it later.</li>
<li>The <tt class="docutils literal">flex</tt> module feels like it needs an overhaul, but I'm not sure what to replace anything with.
Changes may propagate to the <tt class="docutils literal">parametric</tt> module.</li>
<li>A lot of the class names in <tt class="docutils literal">input_accumulator</tt> are kind of awkward, but I don't have a clear idea of what to replace them with, because I think I need to figure out more about the usage.
All the same, it's worth seeing if the decorators can be turned into classmethods.</li>
<li>In <tt class="docutils literal">installers</tt>, I think maybe <tt class="docutils literal">Environment</tt> should be <tt class="docutils literal">ExecutionEnvironment</tt>.
I'm not really sure, though.</li>
<li>Not sure if the <tt class="docutils literal">parameters</tt> module needs anything.</li>
<li>A bunch of the functions in the <tt class="docutils literal">parametric</tt> module could be converted to methods.
I'm not sure about "should"...</li>
<li><tt class="docutils literal">motr._api.cli_types.registry</tt> could do with some renames.
Like, the point of it is just that these are the constants, maybe, to go with the parameters.</li>
<li>The <tt class="docutils literal">typed_mapping</tt> module and protocols could also do with a rename.</li>
<li><tt class="docutils literal">motr._api.cli.build</tt> could do with the same classmethod rewrite I'm considering elsewhere, if I go through with it.</li>
<li>The <tt class="docutils literal">cli</tt> modules have the general thing of, I should probably combine the python versions adaptor and the pip arguments label into a single object of some kind.
And there are other changes I want to make, that I've laid out elsewhere.
I'm skimming over this stuff, so I'm going to have to go into more detail again later.</li>
<li>The <tt class="docutils literal">python_helpers</tt> module needs the <tt class="docutils literal">requirement_invocation</tt> function to be renamed.
Not sure about anything else.</li>
<li>The <tt class="docutils literal">reports</tt> module could have the <tt class="docutils literal">acumulator</tt> function renamed, or not.
We'll see.</li>
<li>Don't know about the <tt class="docutils literal">pip</tt> module, name-wise.
Or otherwise.</li>
<li>The <tt class="docutils literal">package</tt> module has some functions that I should see if I can get rid of.</li>
</ul>
</li>
<li>Everything else<ul>
<li><tt class="docutils literal">isinstance()</tt> calls in the <tt class="docutils literal">command</tt> module.</li>
<li>I'm considering dropping many uses of <tt class="docutils literal">PVector[T]</tt>, since I'm not really, like, using any part of the interface beyond what I'd get from a <tt class="docutils literal">Tuple[T, <span class="pre">...]</span></tt>.</li>
<li><tt class="docutils literal">isinstance()</tt> calls in the <tt class="docutils literal">parametric_command</tt> module.
Also, there are some types that could be improved with a typed mapping.</li>
<li><tt class="docutils literal">reduce_parameterization()</tt> could have the arguments reorganized a little so that <tt class="docutils literal">reducer</tt> and <tt class="docutils literal">initial_value</tt> are in a single container object.</li>
<li>Some of the internal strings in <tt class="docutils literal">motr._api.cli.build</tt> are wrong, and need to be fixed before the next release.</li>
</ul>
</li>
</ul>
</li>
<li>Change after the next release<ul>
<li>Names<ul>
<li>The <tt class="docutils literal">cmd_</tt> function is somewhat unfortunate.
Consider converting to a classmethod?</li>
<li>I'm a little iffy on whether to keep the <tt class="docutils literal">Input</tt> and <tt class="docutils literal">Output</tt> names.
They could be <tt class="docutils literal">Prerequisite</tt> and <tt class="docutils literal">Outcome</tt>, for example, but those are mega long.
This would spill over into the <tt class="docutils literal">not_output</tt> module.</li>
<li><tt class="docutils literal">mkdir</tt> and <tt class="docutils literal">make_parent</tt> could be moved if <tt class="docutils literal">cmd_</tt> is, for consistency.</li>
<li>Same for <tt class="docutils literal">write_bytes</tt>.</li>
<li>I think there could be a better name for <tt class="docutils literal">motr._api.build</tt> and its <tt class="docutils literal">build()</tt> function, but I think to find it, I'd also need to find a better name for <tt class="docutils literal">motr.core.registry</tt>.
Which, to be fair, it definitely needs a better name.</li>
<li>I've got a note to rename <tt class="docutils literal">motr._api.requirements.action</tt> to <tt class="docutils literal">task</tt>.
This would go along with some changes to <tt class="docutils literal">core</tt>.</li>
<li>Similarly, <tt class="docutils literal">name_target</tt> to <tt class="docutils literal">name_outcome</tt>.</li>
<li>About <tt class="docutils literal">requirements</tt> overall...
I feel like something should change, but I've got time to figure things out.</li>
<li>And, <tt class="docutils literal">target</tt> to <tt class="docutils literal">outcome</tt>.</li>
<li>I've got a rename queued up for <tt class="docutils literal">motr.core.target_name</tt> as well.</li>
<li>And <tt class="docutils literal">motr.core.target</tt>.</li>
</ul>
</li>
<li>Everything else<ul>
<li>The <tt class="docutils literal">motr._api.actions</tt> modules, as well as <tt class="docutils literal">motr._api.cli.build</tt> need an overhaul to their interfaces, which is going to start with changes in <tt class="docutils literal">motr.core.runner</tt>.
Basically, I want to change from "return a mapping of output when done" to "pass in some kind of callback for registering output streams".</li>
<li>I want to beef up the details of some of the <tt class="docutils literal">typed_mapping</tt> stuff, and also I want to spin it out into its own package.
Making it into a package would allow me to use it in other projects, and also make the test runs faster in MOTR.</li>
<li>I'm not sure if this counts as "name" or "everything else", but I'm not totally sold on the way I'm doing re-exports from the <tt class="docutils literal">api</tt> module.
Like, is this confusing to people who aren't me?
I need to figure that out.</li>
<li>The <tt class="docutils literal">base</tt> controller is huge and needs to be broken up.
I don't know how, exactly, but it's too big.</li>
<li>I should see whether I want to add any classes to the <tt class="docutils literal">exc</tt> module.</li>
<li>I've got a bunch of renames cued up in <tt class="docutils literal">motr.core.registry</tt>.
The thing I'd like to figure out is, what's a better name for all of this than "registry"?
<tt class="docutils literal">DependencyGraph</tt>?
Let's go with that for now.</li>
<li>As I said, I want to tweak some things in <tt class="docutils literal">motr.core.runner</tt>.
Like, renaming <tt class="docutils literal">RuntimeAction</tt> to <tt class="docutils literal">Task</tt>, and <tt class="docutils literal">Target</tt> and <tt class="docutils literal">Action</tt> to, um...
Apparently, <tt class="docutils literal">Request</tt>, and, let's say...
<tt class="docutils literal">RequestTask</tt>.</li>
<li><tt class="docutils literal">motr.ext.ext_maybe_format</tt> I think needs to be broken up into multiple extensions, but we'll see.</li>
<li>Paired changes to <tt class="docutils literal">motr.main</tt> and <tt class="docutils literal">motr.motr_app</tt> around disabling Cement's ctrl-c signal handling so Trio can have it.</li>
<li>The line <tt class="docutils literal"><span class="pre">CONFIG["motr"]["foo"]</span> = "bar"</tt> needs to go.</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Well, that's a good start for noting this stuff down.
I did this earlier in the day, so maybe I'll feel like making some of these changes later.
We'll see.</p>
<p>Okay, it's later, and I did some updates.
Things are better, but there's more to be done.</p>
<p>Good night.</p>
Coding 2022-08-072022-08-07T04:00:00-04:002022-08-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-07:/coding-2022-08-07<p class="first last">Sometimes it's <em>really obvious</em> what I should have named things, sometimes not.</p>
<p>All right, let's start another pass through the MOTR code, to see what changes I want to make.
I'm going to divide this into two pairs of categories: changes to make as soon as possible versus after the next release; and changes to names, and everything else.
My plan is to hold off on "everything else" until I have full test coverage, rather than 94%.</p>
<p>But let's break this down:</p>
<ul class="simple">
<li>ASAP<ul>
<li>Names<ul>
<li><tt class="docutils literal">CommandBuilder</tt> needs a different name for the <tt class="docutils literal">command</tt> attribute, which needs a new name for its type.</li>
<li>In fact, I believe the type should be renamed <tt class="docutils literal">Executable</tt>, after the fact that the <tt class="docutils literal">x</tt> bit is set on the file, and <em>its</em> <tt class="docutils literal">command</tt> attribute should be <tt class="docutils literal">name</tt> instead.
The same file has some type aliases that derive from the type, and they should be updated as well.
Consider renaming <tt class="docutils literal">Metadata</tt>, mainly because it's not a very descriptive name.
It might fare better if I moved it to the <tt class="docutils literal">command_builder</tt> module.
Consider that.</li>
<li>The <tt class="docutils literal">entry</tt> module seems reasonable, but come back to it later.</li>
<li>The <tt class="docutils literal">flex</tt> module feels like it needs an overhaul, but I'm not sure what to replace anything with.
Changes may propagate to the <tt class="docutils literal">parametric</tt> module.</li>
<li>A lot of the class names in <tt class="docutils literal">input_accumulator</tt> are kind of awkward, but I don't have a clear idea of what to replace them with, because I think I need to figure out more about the usage.
All the same, it's worth seeing if the decorators can be turned into classmethods.</li>
<li>In <tt class="docutils literal">installers</tt>, I think maybe <tt class="docutils literal">Environment</tt> should be <tt class="docutils literal">ExecutionEnvironment</tt>.
I'm not really sure, though.</li>
<li>Not sure if the <tt class="docutils literal">parameters</tt> module needs anything.</li>
<li>A bunch of the functions in the <tt class="docutils literal">parametric</tt> module could be converted to methods.
I'm not sure about "should"...</li>
</ul>
</li>
<li>Everything else<ul>
<li><tt class="docutils literal">isinstance()</tt> calls in the <tt class="docutils literal">command</tt> module.</li>
<li><tt class="docutils literal">isinstance()</tt> calls in the <tt class="docutils literal">parametric_command</tt> module.
Also, there are some types that could be improved with a typed mapping.</li>
<li><tt class="docutils literal">reduce_parameterization()</tt> could have the arguments reorganized a little so that <tt class="docutils literal">reducer</tt> and <tt class="docutils literal">initial_value</tt> are in a single container object.</li>
</ul>
</li>
</ul>
</li>
<li>Post-next-release<ul>
<li>Names<ul>
<li>The <tt class="docutils literal">cmd_</tt> function is somewhat unfortunate.
Consider converting to a classmethod?</li>
<li>I'm a little iffy on whether to keep the <tt class="docutils literal">Input</tt> and <tt class="docutils literal">Output</tt> names.
They could be <tt class="docutils literal">Prerequisite</tt> and <tt class="docutils literal">Outcome</tt>, for example, but those are mega long.
This would spill over into the <tt class="docutils literal">not_output</tt> module.</li>
<li><tt class="docutils literal">mkdir</tt> and <tt class="docutils literal">make_parent</tt> could be moved if <tt class="docutils literal">cmd_</tt> is, for consistency.</li>
<li>Same for <tt class="docutils literal">write_bytes</tt>.</li>
<li>I think there could be a better name for <tt class="docutils literal">motr._api.build</tt> and its <tt class="docutils literal">build()</tt> function, but I think to find it, I'd also need to find a better name for <tt class="docutils literal">motr.core.registry</tt>.
Which, to be fair, it definitely needs a better name.</li>
</ul>
</li>
<li>Everything else<ul>
<li>I didn't get to this normally, but the line <tt class="docutils literal"><span class="pre">CONFIG["motr"]["foo"]</span> = "bar"</tt> needs to go, for obvious reasons.</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>I got distracted with stuff today, so I didn't have time to get through all of this.
Tomorrow, I'll pick back up from the <tt class="docutils literal">parametric</tt> module.</p>
<p>It's nearly midnight.</p>
<p>Good night.</p>
Learning Koka 2022-08-062022-08-06T04:00:00-04:002022-08-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-06:/learning-koka-2022-08-06<p class="first last">Still at the stage where I can do a bunch of fancy stuff that makes complete sense, then comprehensively trip over my shoelaces at the last possible moment, apparently.</p>
<p>Okay, I didn't get much done today, but I did sketch out some helper functions that seem to work, at least with the interactive compiler.
I seem to be having some issues using them in compiled code; I'll have to look into that later.</p>
<p>Anyway, my basic plans here are to really firm up the environment variable processing, focus on the response headers after that, and then just start messing around with writing templates or some other form of document generation.</p>
<p>For now, though, I'm going to get to sleep and wonder what I'm doing wrong in my <tt class="docutils literal">main()</tt> function.</p>
<p>Good night.</p>
Learning Koka 2022-08-052022-08-05T04:00:00-04:002022-08-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-05:/learning-koka-2022-08-05<p class="first last">Explaining what I'm doing in order to lay out how it's completely wrong.</p>
<p>So, I don't think I really explained this, but I'm sort of alternating what I'm focusing on in looking into in Koka.
Yesterday, I was seeing how much of the script side of CGI could be implemented in Koka.
Now, I'm sketching out how to handle structured concurrency.</p>
<p>So, let's see about that.</p>
<p>So far, I've got two distinct effects that I think need to be supported.
One for "resume the current execution at some future point" or, in other words "schedule the resumption of the current code in the future".
And one for "schedule an additional execution, and ensure that all such executions have completed at some future point".</p>
<p>These are the equivalents of <tt class="docutils literal">await</tt> and <tt class="docutils literal">nursery.start_soon()</tt> in Trio.</p>
<p>I poked around with this a little, and I am not sure I'm writing things correctly.
I currently don't have an argument to the <tt class="docutils literal">await</tt> function in the <tt class="docutils literal">async</tt> effect, and I think it actually needs an argument to describe when to resume.
Like, a higher-order function that takes the resume function as an argument.
And some kind of queue to put them in, I guess...</p>
<p>Anyway, we'll see how much focus I have to put into this later.
For now, I need to get to bed.</p>
<p>Good night.</p>
Learning Koka 2022-08-042022-08-04T04:00:00-04:002022-08-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-04:/learning-koka-2022-08-04<p class="first last">Here's a project, and here's why it won't work. Let's see how much of it I can still try to do.</p>
<p>I'd mentioned yesterday that I want to think about more concrete problems before I mess with trying to do structured concurrency in Koka.</p>
<p>As to the specific thing I'm choosing, it's not a good fit, I don't think, but I'm interested in at least laying out why it's not.
And what is it?</p>
<p>Okay, so, I never used <abbr title="Common Gateway Interface">CGI</abbr> scripts directly.
I used to see other people use them all over the place, but by the time I was working on web server stuff for work, I was doing things that used the <abbr title="Web Server Gateway Interface">WSGI</abbr>.
I don't know why, but I just decided, let's see how any of this actually worked.</p>
<p>So, I've got <a class="reference external" href="https://datatracker.ietf.org/doc/html/rfc3875">RFC 3875</a>, and I'm looking over it and comparing what it wants to what's possible in Koka (assuming I don't write extensions).</p>
<p>Here's what I've concluded from what I've looked at so far:</p>
<ul class="simple">
<li>CGI deals with standard input, standard output, and environment variables.
The environment variables are expected to have a bunch of structure that the script should interpret before it performs any other I/O.</li>
<li>Koka should be entirely able to handle the standard output side of things.
Writing CGI scripts in Koka would benefit from a library to generate HTML, and, I think, HTTP headers.</li>
<li>Koka should be able to handle the environment variables.
The main thing I would need, is to have a case insensitive comparison for traversing the association list.
(Which I later realized, after mentioning the concept earlier, that Koka's standard library <em>does</em> expect and support.)
And then a bunch of processing steps.</li>
<li>I think the big stumbling block is the <tt class="docutils literal">CONTENT_LENGTH</tt> variable.
This is in octets, which is what you call bytes if you don't want to get well-actually-ed.
The RFC states "the script MUST NOT attempt to read more than CONTENT_LENGTH bytes".
Right now, Koka's facilities for reading from standard input are... limited.
The standard library provides the <tt class="docutils literal">readline()</tt> function, which reads from standard input, in UTF-8, either a line of text (discarding the newline), or 1023 code points, whichever is shorter; I'm not clear on what happens if it doesn't get an explicit end to the line within 1023 code points.
In any case, the point is, CGI really wants the script to be working in bytes at the boundary, and I don't think Koka is up for that yet.
I don't know if supporting this kind of thing is on the radar.</li>
</ul>
<p>So, Koka, which is, keep in mind, experimental and under development, appears to not be ready for the entirety of a use case that it's not explicitly meant to support.
I think that's fine for now, and I'd like to mess with the areas that it can support.
If it works well, maybe I'll end up with a little static site generator.
I don't see such a thing replacing Pelican for me, but it could be neat.</p>
<p>Anyway, I didn't exactly use my time super well today, so I'm not going to go much further for now.
I'll try to break things down in a little more detail later.</p>
<p>Good night.</p>
Learning Koka 2022-08-032022-08-03T04:00:00-04:002022-08-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-03:/learning-koka-2022-08-03<p class="first last">I'm missing some subtleties around imports in Koka. Oh well, more to research.</p>
<p>So, Koka.
Why am I interested in it?
The main thing that's special about Koka vs the other languages I know, is its effect system.
As far as I'm currently aware, the effect system does two-ish things.
At least one and a half.
It allows library writers to define new flow control concepts, and customize existing ones.
This is because it's sort of like exceptions, but resumable, and, if you opt into the fancy code generation, resumable multiple times.
The other thing is, unhandled effects are part of the signature for the function that's not handling them, so they can be used to mark side effects.</p>
<p>Now, what has me interested is, well...</p>
<div class="highlight"><pre><span></span><span class="n">pub</span><span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">map</span><span class="p">(</span><span class="n">xs</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">list<a></span><span class="p">,</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">a</span><span class="w"> </span><span class="na">-></span><span class="w"> </span><span class="na">e</span><span class="w"> </span><span class="na">b</span><span class="p">)</span><span class="w"> </span><span class="na">:</span><span class="w"> </span><span class="na">e</span><span class="w"> </span><span class="na">list<b></span>
<span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">xs</span>
<span class="w"> </span><span class="ge">Cons</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">xx</span><span class="p">)</span><span class="w"> </span><span class="k">-></span><span class="w"> </span><span class="ge">Cons</span><span class="p">(</span><span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">),</span><span class="w"> </span><span class="n">xx</span><span class="k">.</span><span class="n">map</span><span class="p">(</span><span class="n">f</span><span class="p">))</span>
<span class="w"> </span><span class="ge">Nil</span><span class="w"> </span><span class="k">-></span><span class="w"> </span><span class="ge">Nil</span>
</pre></div>
<p>The precise details of the code aren't too important, what's interesting is the signature.
<tt class="docutils literal">map</tt> takes a list of objects of some type, applies a function to each element, and produces a list of the results.
So far, so normal.
But the other thing going on here is the <tt class="docutils literal">e</tt>, representing the effects of the input function <tt class="docutils literal">f</tt>.
Those effects are passed along and emitted by the call to <tt class="docutils literal">map</tt>.</p>
<p>So, if you wrap a <tt class="docutils literal">map</tt> call in a handler for a custom effect that is emitted by <tt class="docutils literal">f</tt>...
You should be able to use the same library function to map using a function that, say, does cooperative multitasking, as not.
Basically, what I'm seeing here, is higher-order functions that are transparent to <a class="reference external" href="https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/">function color</a>.</p>
<p>Koka's an experimental language, and that's the experiment I'm interested in.
I want to see what happens if you put <a class="reference external" href="https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/">structured concurrency</a>'s new primitive into a language that's designed to be tiny and extensible, and make a bunch of decisions differently from Python.
(I am <a class="reference external" href="https://github.com/koka-lang/koka/issues/169">not the first person</a> who's been curious what this would be like.)</p>
<p>Before I design too much of that, I want to get some more experience with Koka, so my plan is to mess around with Koka trying to solve a somewhat more concrete problem.
More on that tomorrow...</p>
<p>Good night.</p>
Weekly Roundup 2022-08-022022-08-02T04:00:00-04:002022-08-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-02:/weekly-roundup-2022-08-02<p class="first last">Major milestones, achieved quietly.</p>
<ul class="simple">
<li>Wednesday: It was a slow day, but I did what I could.</li>
<li>Thursday: I got some stuff done, but also I got really distracted.</li>
<li>Friday: I got a bit more done, and started turning my distraction into blog posts.</li>
<li>Saturday: I messed around a little with Koka, and didn't quite get anywhere impressive.</li>
<li>Sunday: I did some planning for improvements to MOTR.</li>
<li>Monday: I executed on the planning of the improvements to MOTR, and I only had one of the functions do the exact opposite of what it was supposed to once!</li>
</ul>
<p>Next week, I'm going to take a break from writing, and focus on process improvements there.
I don't know that I'll blog about that, so I might end up mixing things up a little as far as what categories I use during the week.</p>
Coding 2022-08-012022-08-01T04:00:00-04:002022-08-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-08-01:/coding-2022-08-01<p class="first last">Documentation for the <tt class="docutils literal">frobnicator</tt> parameter: "This is the frobnicator. The function needs it in order to frobnicate." :(</p>
<p>I wrote up the helper methods for MOTR, and after some <em>slight</em> implementation issues, I got them added to one of the tests.</p>
<p>Then, I got back into documenting stuff.
I think it's time for me to start reconsidering the names of some of this stuff, because some of this code is hard to document when the names clearly have nothing to do with the purpose.</p>
<p>So, that's going to be the next stretch of work I do with this code: collect all of my misgivings about class and function names into a single place so I can prioritize them.
I may also take notes on some functionality changes I want: stuff like removing <tt class="docutils literal">isinstance()</tt> calls and streamlining the command wrappers.</p>
<p>Anyway, I'm exhausted for some reason, so I guess I'm getting to bed now.</p>
<p>Good night.</p>
Coding 2022-07-312022-07-31T04:00:00-04:002022-07-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-31:/coding-2022-07-31<p class="first last">Not much code work because movie, but I still ratcheted stuff along.</p>
<p>Okay, I did a bit more documentation just now, but the other thing I want to work on in tandem, is to set up diagnostic methods on the <tt class="docutils literal">core.registry.Registry</tt> class.</p>
<p>Basically, let's see...</p>
<ul class="simple">
<li>"Does every action have an output?"</li>
<li>"Is every action transitively reachable from a named output?"</li>
</ul>
<p>Or, more detailedly, "<em>Which actions do not satisfy</em> etc etc"</p>
<p>I can put in more work orders to my future self, but I believe those two would feed into the tests I want to write, and would be a good starting point for further improvements.
Best to put in minimal effort to the code itself, until I find specific deficiencies to address.</p>
<p>Anyway, I wanted to draft that tonight, but it's late, and I should get to this tomorrow.</p>
<p>Good night.</p>
Learning Koka 2022-07-302022-07-30T04:00:00-04:002022-07-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-30:/learning-koka-2022-07-30<p class="first last">If it compiles, it flexes on me.</p>
<p>Hey, guess what I remembered I could do!</p>
<p>Anyway, I messed around with some advice on "first programs to write in any language".
The second thing it had me do was code up a subtraction game and an AI for it.
It took me a long time to get it to compile, but once it compiled, everything worked perfectly and it beat me.</p>
<p>My impressions from getting it working were that using <tt class="docutils literal">var</tt> and <tt class="docutils literal">while</tt> together isn't worth it, and I ended up avoiding <em>both</em> by just rewriting everything as tail calls.
I think I'm going to need to experiment with <tt class="docutils literal">var</tt>, and later <tt class="docutils literal">while</tt>, and try to get a handle on when to use them.
Lastly, it seems to be better to write small functions, so they rack up fewer effects and it's easier to see where they're coming from.</p>
<p>I bet I could also make the code a bit nicer by cutting down on the mutual tail recursion, and coordinating stuff at a higher level, but I'm not going to try to figure that out right now.</p>
<p>One thing I'm interesting in figuring out is "the right" way to handle mapping objects.
My gut feeling is that, if I try this, I should see how far I can get with association lists, unless I missed something that already does mapping.</p>
<p>Anyway, I'm wiped out and I'm going to <em>try</em> to get to bed earlier.</p>
<p>Good night.</p>
Diary 2022-07-292022-07-29T04:00:00-04:002022-07-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-29:/diary-2022-07-29<p class="first last">Wanting to put some of my creative energy into writing some code that is probably just absolutely useless.</p>
<p>Writing is going well.
I've gotten to the point where there's a little bit that I feel like I <em>need</em> to fill in for the current draft, and besides that, it's just as much as I feel like adding on.
Then I'll take a break, because I'm pretty sure I can't just grind away at this constantly.</p>
<p>Anyway, I mentioned some programming language stuff yesterday.
I've been looking at <a class="reference external" href="https://koka-lang.github.io/koka/doc/index.html">Koka</a> recently.
It's an experimental language that is built around the concept of an "effect system", which is basically a generalization of exceptions, coroutines, output, non-termination...</p>
<p>It's a pretty ambitious idea, basically, and I'm curious to see what I can do with it; I've got some somewhat ambitious ideas in mind, so I'm trying to figure out a good limited-scope project to start teaching myself how to use it first.
I might try out some of the ideas I had for messing with BQN...
One thing I need to clear up for myself first, is when to be using a linked list, and when to be using a vector.</p>
<p>Anyway, I had plenty of time to wind down when I started this entry, but I went <em>really slowly</em>, so I'm going to just stop abruptly.</p>
<p>Good night.</p>
Diary 2022-07-282022-07-28T04:00:00-04:002022-07-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-28:/diary-2022-07-28<p class="first last">This feels like how I got sometimes a decade ago, in a bad way.</p>
<p>Writing is still a bit slow.
Partly this is because I'm trying to rewrite things in order, and I got to a tricky bit.</p>
<p>Partly this is because I was catastrophically tired all day and my ability to focus is effectively random.
Like, I could try to push through this bit of writing.
Oooor I could read the documentation of an experimental programming language.</p>
<p>Anyway, I'm not going to do any better if I stay up, so this entry is over now.</p>
<p>Good night.</p>
Diary 2022-07-272022-07-27T04:00:00-04:002022-07-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-27:/diary-2022-07-27<p class="first last">Secret basement level to Maslow's pyramid: teeth no hurty.</p>
<p>I got a little writing done today.
Very little.
But some important reorganization happened.</p>
<p>Two things gave me trouble accomplishing much today.
For one thing, I just had a lot of trouble focusing, and for another, I had a headache; I kind of still have it, in fact.
I can feel parts of my teeth that I'm not used to feeling, and it is doing <em>terrible</em> things for my mood.</p>
<p>Hopefully I get to focus better tomorrow and accomplish more things.
I shouldn't dawdle on getting to bed now, so let's wrap this up.</p>
<p>Good night.</p>
Weekly Roundup 2022-07-262022-07-26T04:00:00-04:002022-07-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-26:/weekly-roundup-2022-07-26<p class="first last">Distracting myself from unpleasant events by wondering whether I should tweak the timestamps and day names on my posts...</p>
<ul class="simple">
<li>Wednesday: I got distracted writing stuff that was not the post, and barely wrote the post.</li>
<li>Thursday: I wrote a bit and made some plans for Friday, which is Saturday in this list because of The Reasons.</li>
<li>Friday: I had a rough day, and vented about it. Things subsequently got rougher, but at least <em>those specific things I was venting about</em> are basically done for now.</li>
<li>Saturday: The Gamera movies continue to be bonkers.</li>
<li>Sunday: I stared at MOTR's code, and worked out some relatively simple changes needed to make the tests pass. I also messed around with the tooling.</li>
<li>Monday: I made some progress on documentation.</li>
</ul>
<p>Next week, I'm going to try to finish up this last stretch of revisions, then go over everything and make a list of things to revise before this is ready to show to anyone.</p>
Coding 2022-07-252022-07-25T04:00:00-04:002022-07-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-25:/coding-2022-07-25<p class="first last">Seriously though, how am I supposed to document the yield type of a function, when, because the function's signature is an alias defined in another module, the yield type <em>isn't in scope</em>?</p>
<p>I'm adding basic documentation to the code.
I also <em>may</em> be forking yet more code from tools that other people wrote.
I'm going to have to work on contributing this stuff upstream.</p>
<p>Like, I've got:</p>
<ul class="simple">
<li>flake8-html, but I made certain things display in multiple lines somehow, I forget</li>
<li>towncrier, but it works on Mercurial repositories</li>
<li>The pylint docparams extension, but it <em>should</em> properly respect <tt class="docutils literal"><span class="pre">no-docstring-rgx</span></tt>; that one is at least simple enough that I already described it on GitHub</li>
</ul>
<p>(In my fork, I also attempted to make it parse the hecked-up docstring style I devised, but that didn't work because of mystery reasons.
I think pylint's docstring parsing logic is maybe collapsing """valid""" inputs to invalid ones.
Like omitting a section break from a Numpy style docstring.)</p>
<p>Anyway, I've got other stuff to take care of right now, so I'm going to wrap this up.</p>
<p>Good night.</p>
Coding 2022-07-242022-07-24T04:00:00-04:002022-07-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-24:/coding-2022-07-24<p class="first last">Staring at the code like "I guess it mostly <em>is</em> that simple?"</p>
<p>Okay, I think I've addressed the issues with MOTR enough to make all of the tests pass.
I've also managed to figure out a possible fix for some of the pylint issues I was seeing, but I want someone who knows the code in question to comment on my suggestions, in case I'm totally off-base.
They'll get to it when they get to it.</p>
<p>For now, I've got a lot of documentation to update.
I think for now, I'll tweak the configuration a little, and start documenting stuff tomorrow, maybe changing stuff tomorrow if the documentation inspires me.
Hopefully restricting those changes to covered code.</p>
<p>Anyway, right now I need to get ready for bed.</p>
<p>Good night.</p>
Diary 2022-07-232022-07-23T04:00:00-04:002022-07-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-23:/diary-2022-07-23<p class="first last">Imagine fighting a dude and there's a bunch of mice or something trying to give you a pep talk, that'd be so weird.</p>
<p>Well, I executed my plan for tonight nigh-flawlessly.
I'm not feeling too talkative, so I'm going to finish up this post as soon as I can, and then play video games that will probably freak me way out.</p>
<p>I'm looking at Wikipedia and going, oh wow, I think there's still a few more Shōwa period Gamera movies that MST3K could cover, that's crazy.</p>
<p>Anyway, going to take it easy for the rest of today.</p>
<p>Good night.</p>
Diary 2022-07-222022-07-22T04:00:00-04:002022-07-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-22:/diary-2022-07-22<p class="first last">What does this year want from me? Blood?</p>
<p>Writing...
I would have liked to have gotten further, but if I'm replacing any of the original draft, that's still progress.</p>
<p>I haven't really been talking about it here, but my personal life has been kind of rough lately.
Nothing that's anyone's fault.
I don't feel like it's been affecting the blog in any direct fashion, but my intuitions as to how a week of posting went have been sort of shaky, so I could be totally wrong.</p>
<p>I know there's plenty more the world could throw at me, but it feels like I deserve a respite.
Like, world, see this year?
<em>Don't do that again.</em></p>
<p>I'm in a funk now, and I'm going to try to sleep it off.</p>
<p>Good night.</p>
Diary 2022-07-212022-07-21T04:00:00-04:002022-07-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-21:/diary-2022-07-21<p class="first last">This rate of progress is a little frustrating, but I have plans for the weekend...</p>
<p>Closing in on a major milestone with writing, and there's not much more to say about that.
I'll try to finish up the current segment tomorrow, and we'll see how that goes.</p>
<p>As far as Friday night...
If there weren't any particular plan, I'd be trying to finally make some simple bug fixes to MOTR, but there's going to be an MST3K premiere, so that's going to be the main focus.</p>
<p>One thought about writing, actually...
I'm planning to take a break from revising stuff soonish, and while I'm doing that, I'm going to think about changes to my various processes.
So that'll be interesting, I guess.</p>
<p>Anyway, it's late and I shouldn't dawdle.</p>
<p>Good night.</p>
Diary 2022-07-202022-07-20T04:00:00-04:002022-07-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-20:/diary-2022-07-20<p class="first last">It's a shame that I used up all of my writing juice, or whatever.</p>
<p>I made some good progress on writing, but I ended up doing it until really late, and legitimately forgetting about this post.</p>
<p>I wanted to get in some work on MOTR, but I'm trying to keep that at a low priority during the week.</p>
<p>I can't think of anything else to say, and it's midnight, so I'll try to make things up tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2022-07-192022-07-19T04:00:00-04:002022-07-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-19:/weekly-roundup-2022-07-19<p class="first last">Progress, not all of it exciting.</p>
<ul class="simple">
<li>Wednesday: I did some writing.</li>
<li>Thursday: I worked through an annoying patch with writing, and planned stuff for MOTR.</li>
<li>Friday: The MOTR stuff concerned a design bug that turned out to be pretty subtle, so I'm trying to take things slow there.</li>
<li>Saturday: I couldn't write much because I needed to read, and before I work on the MOTR bug stuff, I want to work on documentation.</li>
<li>Sunday: I came up with some docstring syntax that Napoleon seems to process just fine, but so horrible that it looks like nobody tells you <em>not</em> to do it because why would they, but also none of the linters I've tried would accept it because why would they.</li>
<li>Monday: I set up two different parameterization doc linters, and settled on Pylint's for now because it seems more featureful, though seemingly a little buggy?</li>
</ul>
<p>Next week, I'm going to grind through some more writing, and make changes and documentation to MOTR.</p>
Coding 2022-07-182022-07-18T04:00:00-04:002022-07-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-18:/coding-2022-07-18<p class="first last">I will not fork darglint, I will not fork darglint, I will not fork darglint...</p>
<p>So, it turns out that Napoleon will happily parse my messed-up hybrid docstrings, but apparently every checker out there wants me to "use a single style" for some reason, so I'm trying out something that's close enough to numpy style for pylint to accept it.</p>
<p>Also, the motrfile is running pylint now.
I shoved <em>a lot</em> of ignores into the rc, because the default checkers for pylint have... problems...
As do the checkers I'm using on purpose, really.
Pylint wasn't my first choice for checking my parameter documentation, but it seems to be doing better than my first choice on most metrics.
I just need them to fix a few bugs for really real, and I can wait, since I have plenty of legitimate warnings to address.</p>
<p>My basic plan is to address all of the issues relevant to <em>understanding</em> the code that needs to change to fix the tests, then fix the tests, then fix the remaining legitimate issues, then disable pylint until they get some bug fixes in, maybe comment out some of the disables in the rc while I'm at it.</p>
<p>Anyway, I'm going to try to do some quick writing after I publish this.
No more time for this post...</p>
<p>Oh also I guess I should add a pylint wrapper?
But the relative ease I had just shoving the new code into the motrfile has me wondering if I should be re-evaluating the design of the highest-level wrappers...</p>
<p>Good night.</p>
Coding 2022-07-172022-07-17T04:00:00-04:002022-07-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-17:/coding-2022-07-17<p class="first last">Napoleon is, like, so vital to making me tolerate using Sphinx for docstrings...</p>
<p>Okay, I did some work on writing today, and I did some more, but mostly I was working on getting an idea of how to write these docstrings.
Here's where I ended up:</p>
<ul class="simple">
<li>Need to have autodoc, so use <tt class="docutils literal">sphinx.ext.autodoc</tt></li>
<li>Sphinx-style docstrings are painful, so use <tt class="docutils literal">sphinx.ext.napoleon</tt>.</li>
<li>I think I prefer numpy-style docstrings for most things...</li>
<li>But I don't want to double-annotate types, so I messed around and discovered that it's possible to <em>mix</em> docstring styles, to have google-style for <tt class="docutils literal">Returns</tt> and <tt class="docutils literal">Yields</tt> and numpy style for everything else.</li>
<li>I think <tt class="docutils literal">autodoc_typehints = "signature"</tt> in <tt class="docutils literal">conf.py</tt> is doing <em>something</em>.</li>
</ul>
<p>Other things I found:</p>
<ul class="simple">
<li><a class="reference external" href="https://github.com/tox-dev/sphinx-autodoc-typehints">sphinx_autodoc_typehints</a> and <a class="reference external" href="https://sphinx-toolbox.readthedocs.io/en/latest/extensions/more_autodoc/typehints.html">sphinx_toolbox.more_autodoc_typehints</a> offer similar functionality (I believe one is a fork of the other), but I don't remember if I ran into a solid difference in my limited testing</li>
<li>I couldn't get <tt class="docutils literal">TypeVar</tt>s to consistently do what I wanted, but things might be different in a proper codebase.</li>
<li>These packages don't seem to put types on <tt class="docutils literal">Yields</tt> fields.</li>
<li>Apparently none of this code supports <tt class="docutils literal">Receives</tt>, which is <a class="reference external" href="https://numpydoc.readthedocs.io/en/latest/format.html">documented in the numpy style guide</a>, but doesn't seem to exist in autodoc.
So, it doesn't look nice no matter what I do.</li>
<li>It is, however, possible to add custom fields, so I added these lines to <tt class="docutils literal">napoleon_custom_sections</tt> in <tt class="docutils literal">conf.py</tt>: <tt class="docutils literal">("Receives", "params_style")</tt>, and <tt class="docutils literal">("Type Parameters", "returns_style")</tt>.
I figure the <tt class="docutils literal">Type Parameters</tt> should go between <tt class="docutils literal">Extended Summary</tt> and <tt class="docutils literal">Parameters</tt>.</li>
<li>autodoc just generally doesn't seem to match up with how the styleguides think you should be documenting generators.</li>
</ul>
<p>With all of this research, now there's just a little more I want to check before I try to document MOTR...</p>
<ul class="simple">
<li>Starting in Python 3.9, I can do stuff like <tt class="docutils literal">list[int]</tt></li>
<li>I believe it should be possible for me to use <tt class="docutils literal">int | str</tt> style syntax <em>in annotations</em>; I may look into bumping MOTR's minimum Python version after the next release.</li>
</ul>
<p>Anyway, all of that gives me stuff to guide my attempts to actually properly document MOTR.
The general idea I have there is to write documentation that's good enough for fixing the design issues I hit, then look into adding a pylint stage to the current motrfile, unless I can find a flake8 plugin for stuff like "documented names match the names in the code".
Maybe do those in the other order, actually, so I have a checklist to work through.</p>
<p>Anyway, I'm going to take care of some things, and then do a bit more writing.
I don't want the night to get completely away from me again.</p>
<p>Good night.</p>
Diary 2022-07-162022-07-16T04:00:00-04:002022-07-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-16:/diary-2022-07-16<p class="first last">I think I used all of my focus today on work.</p>
<p>Well, things were kind of disorganized today, so I'm going to just take this entry easy and plan for tomorrow:</p>
<ul class="simple">
<li>I need to read stuff before I can get back to the writing.</li>
<li>Before I document more about MOTR, I want to evaluate a few different options for documenting attrs-decorated classes, because I'm not sure what strikes the right balance in terms of generated documentation vs the raw file vs the runtime introspected data.</li>
</ul>
<p>Anyway, I've got some completely unrelated writing that I want to do as soon as I can, so I'm going to wrap this up now and get back to that.</p>
<p>Good night.</p>
Coding 2022-07-152022-07-15T04:00:00-04:002022-07-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-15:/coding-2022-07-15<p class="first last">I don't think the rabbits were supposed to dig this deep...</p>
<p>Nothing dramatic on writing today, because I've got to do a little research.</p>
<p>As far as <em>drama</em> goes...
I got to work on that bug in MOTR, and in solving it, uncovered a much bigger design issue.
Let's see if I can explain it...</p>
<p>So, <tt class="docutils literal">Parametric</tt> objects are wrappers around a function, and bring in associated metadata that allow the library to <em>basically</em> construct product iterators, but iterating over a variable twice is basically the same as iterating over it once.
Now, these functions can technically produce anything, but they have affordances around producing the <tt class="docutils literal">IO</tt> types that handle coordination between actions in the core.
Basic things they try to support:</p>
<ul class="simple">
<li>"Act like <em>this</em> variable takes on <em>this</em> value, for this function"
I didn't run into this when I was hitting bugs, but there's some subtlety here</li>
<li>"Conceal iteration over a variable, unless the outer function also iterates over it"
This is needed for things like "here are twelve outputs; they must all be used as inputs to the <em>same</em> action"</li>
<li>"Prevent iterating over any variable that this function doesn't know about"
This is needed to prevent multiple actions from producing the same output</li>
</ul>
<p>If you read that last one carefully, you might be able to figure out how my initial implementation can, and just now, <em>did</em> go wrong...</p>
<p>My initial implementation said "You can iterate over variables that this function doesn't know about."
But, it's actually totally valid to iterate over "extra" variables, <em>as long as they don't take on more than one value</em>.
Now, the fields involved are just obscure enough now that I think I should take this opportunity to document them...</p>
<ul class="simple">
<li><tt class="docutils literal">provided_labels</tt> represents the variables that the wrapped function should vary with respect to</li>
<li><tt class="docutils literal">required_labels</tt> represents the variables that something should iterate over; either this function, or something else</li>
<li><tt class="docutils literal">handled_labels</tt> represents the variables that the function will gracefully handle iterating over</li>
<li><tt class="docutils literal">allowed_labels</tt> represents the variables that it is <em>acceptable</em> for something to iterate over</li>
<li><tt class="docutils literal">flexible</tt> is an auxiliary variable required by the user interface, and not terribly interesting for these purposes.</li>
</ul>
<p>Relationships between these variables:</p>
<ul class="simple">
<li><tt class="docutils literal">handled_labels</tt> and <tt class="docutils literal">allowed_labels</tt> are both supersets of <tt class="docutils literal">provided_labels</tt> and <tt class="docutils literal">required_labels</tt>.
One of the validators responsible for maintaining this is oddly-named, and I need to investigate it.</li>
<li>It's permissible to basically "copy" <tt class="docutils literal">handled_labels</tt> into <tt class="docutils literal">allowed_labels</tt>, to cut down on the acceptable options for iteration.</li>
<li>It's permissible to "move" everything from <tt class="docutils literal">provided_labels</tt> into <tt class="docutils literal">required_labels</tt> (roughly speaking), to create a function that "doesn't provide" the variables that it needs something to iterate over.</li>
<li>It's permissible to add information to <tt class="docutils literal">flexible</tt>.</li>
<li>It's permissible to cut down on the <tt class="docutils literal">provided_labels</tt>, but the logic involved is somewhat elaborate.</li>
</ul>
<p>The basic things I need to handle are:</p>
<ul class="simple">
<li>Instead of <em>not allowing</em> iteration over variables not in <tt class="docutils literal">allowed_variables</tt>, I need to require that those labels take on only one value.</li>
<li>Something similar needs to happen with the <tt class="docutils literal">inject_registry</tt> helper function.
For each key it injects, it needs to make sure that either both values are length one when the key is used in iteration, or that both values are the same when the key is used in iteration.</li>
</ul>
<p>It's not immediately obvious to me how to do this, because the documentation is so bad right now.
I'm basically going to have to do some documentation and renaming passes in order to make sense of everything.
One code change I'm considering, is to create a custom container type for parameterizable values, but I'm not sure if that's necessary.
Documentation first.</p>
<p>Well, sleep first, documentation later.</p>
<p>Good night.</p>
Diary 2022-07-142022-07-14T04:00:00-04:002022-07-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-14:/diary-2022-07-14<p class="first last">I wonder if this is what it feels like to spend all that time sanding those knives made of things that no sane person would make a knife out of.</p>
<p>I got a bunch of stuff taken care of early-ish today, so I had plenty of time to write.
I got to what seemed like a major milestone back when I was planning these edits, but functionally what it means is, I'll hopefully be done with the current pass in a few days, and then I can review everything and plan <em>more</em> editing passes.</p>
<p>Anyway, I'm done with that for tonight, let's see what else...</p>
<p>I'm going to try to work on MOTR a bit tomorrow, and after I fix the <tt class="docutils literal">Flex</tt>-related bugs I identified, I'm going to try to put some code in core to improve the test assertions for the higher-level code.
Basically, I want to be able to guarantee some properties of the dependency graph, and the code to calculate those properties should live with the code that defines the graph.
I feel like those checks should be available to the main program logic somehow, but I'm not sure what the right interface to that is.</p>
<p>Anyway, I'm tired and I ought to wrap up.</p>
<p>Good night.</p>
Diary 2022-07-132022-07-13T04:00:00-04:002022-07-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-13:/diary-2022-07-13<p class="first last">"Wait, this <em>new</em> scene only fits with the <em>previous</em> draft. Bleh."</p>
<p>I ran into some trouble with writing, so I switched gears to some other writing that I can come back to later.</p>
<p>Besides that, I've been poking at some stuff related to MOTR, but not doing any of the big work there yet.</p>
<p>I guess I mostly just focused on the kinds of stuff that I don't really blog about, once again.
I'm tired, so I'm going to try to get to bed a little earlier.</p>
<p>Good night.</p>
Weekly Roundup 2022-07-122022-07-12T04:00:00-04:002022-07-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-12:/weekly-roundup-2022-07-12<p class="first last">Everything I need to do is clear. Now I just need to do it.</p>
<ul class="simple">
<li>Wednesday: Was chill, though I did have to work through some technical issues.</li>
<li>Thursday: A little more technical stuff, and it seems to be basically settled at this point.</li>
<li>Friday: I worked on writing.</li>
<li>Saturday: I did some writing, and rambled about software metrics that are in this weird space of people at conferences going "Wow! Cool tooling!" and every paper I find on it managing to include a sentence to the effect of "Nobody knows what some of the words required to define this metric actually mean."</li>
<li>Sunday: I noted some work I'm going to have to do on MOTR.</li>
<li>Monday: I prioritized that work.</li>
</ul>
<p>Next week, I'm going to try to make enough progress writing that I feel okay taking a break.</p>
Coding 2022-07-112022-07-11T04:00:00-04:002022-07-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-11:/coding-2022-07-11<p class="first last">I let this slip today, but I took care of everything else, I think.</p>
<p>Fortunately, I made good progress on most things today.
Unfortunately, coding stuff was not part of "most things".
Still, I'm used to doing it like this on the weekends...</p>
<p>Instead of touching the code, I did mess around with software metrics stuff.
The main conclusion I reached was that I should stop messing around with software metrics stuff.</p>
<p>Reviewing the notes I took yesterday, and making guesses about priority:</p>
<ul class="simple">
<li>Review <tt class="docutils literal">FlexOut</tt> and compare usage with <tt class="docutils literal">LessFlexOut</tt></li>
<li>Inline globals that are only used once</li>
<li>Unify creating the pip args label and the python version adaptor</li>
<li>Mark low-content flake8 wrapper code for removal, but do not touch it yet</li>
<li>Prototype a unification of creating <tt class="docutils literal">Put</tt> objects and their associated <tt class="docutils literal">Label</tt>s, but do not change the code yet; evaluate how the prototype would handle arguments for other wrappers</li>
</ul>
<p>The first one is the highest priority, because it represents a bug arising from the... "design".
Everything else is "how can we make it more convenient for library writers to deal with this code?"</p>
<p>Anyway, I should not hold off on getting to bed.</p>
<p>Good night.</p>
Coding 2022-07-102022-07-10T04:00:00-04:002022-07-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-10:/coding-2022-07-10<p class="first last">It's functional, but is it <em>functional</em>, you know?</p>
<p>I made some nice progress on writing, but I'm used to doing coding entries on the weekend, so let's talk about where I am with MOTR.</p>
<p>I wrote the first test of the pytest wrapper, which also represents a test of the python wrapper.
Here's what's left to test, in approximate priority order:</p>
<ul class="simple">
<li>pyinstrument (I looked into some alternatives, and they weren't satisfactory; I may end up filing some bugs later, once I've closed out some issues on my end)</li>
<li>coverage (including several output formats)</li>
<li>limit-coverage</li>
<li>Proper coverage of "build", which should be renamed to "pyproject_build", for both clarity and correctness</li>
</ul>
<p>pyinstrument should be really straightforward, the rest, somewhat less so.</p>
<p>Now that I've done a few rounds of iteration on the existing wrappers, it might also make sense to revisit how I'm laying out these modules.
I'll try to take some quick notes on that now...</p>
<ul class="simple">
<li>The python versions adaptor and the pip arguments label always accompany each other; this didn't use to be true, but I had to do some refactoring that made it true.</li>
<li>Sometimes the <tt class="docutils literal">Entry</tt> alias is used just a little, and sometimes it's used a little more.</li>
<li>The <tt class="docutils literal">Program</tt> subclass does not always accompany the adaptor and label.</li>
<li>Some of these globals, like <tt class="docutils literal">COMMAND</tt>, could be inlined without hurting anything.</li>
<li>The <tt class="docutils literal">BASE</tt> global looks like it should be possible to write a helper for.</li>
<li>The python wrapper's <tt class="docutils literal">base()</tt> function looks like a candidate for writing a helper function, but I'll need to compare it to the other runner wrappers' implementations, so I'll have to write them first.</li>
<li>The flake8 wrapper has some options that should be replaced with a variadic function of extra dependencies.</li>
<li>There are some issues with <tt class="docutils literal">HTML_LABEL</tt> in the junit2html wrapper that indicate that I need to revisit the new <tt class="docutils literal">LessFlexOut</tt> class.</li>
<li>There are a variety of paired <tt class="docutils literal">parametric_command.Put</tt> objects and <tt class="docutils literal">Label</tt>s, and I should take another shot at unifying them.</li>
</ul>
<p>Okay, that's a bunch of work that I can't prioritize right now.
Tomorrow, hopefully.
For now, it is late and I should sleep.</p>
<p>Good night.</p>
Diary 2022-07-092022-07-09T04:00:00-04:002022-07-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-09:/diary-2022-07-09<p class="first last">It seems that today I was very distracta</p>
<p>So, I got distracted from writing.
With other writing.
On the on hand, it's good practice.
On the other hand, this is just doing a mix of not tackling my existing editing workload, and adding more for later, so that's a little obnoxious.</p>
<p>What else have I been thinking about...
Well, the more I've thought about Halstead metrics, the more I think to myself "I'm not sure these can produce directly comparable metrics between languages, and maybe each language or language family should have metrics derived from a set of principles" because I'm genuinely not sure how you'd come up with a coherent way of classifying tokens that accounts for all of "pure functional language that doesn't allow you to bind anything to a name", "tape-based language that also doesn't allow you to bind anything to a name", and "stack-based language that allows for quoting; like, either quoting somehow turns an operator into an operand, or <em>not</em> quoting is an operator!"</p>
<p>I wouldn't think about this so much if I didn't watch people singing the praises of Radon for measuring Python code, and if Radon weren't so... questionable.</p>
<p>I'm going to try working through some of these on my own code, just for the heck of it.
That's going to take a bit, so I'm going to publish now.</p>
<p>Good night.</p>
Diary 2022-07-082022-07-08T04:00:00-04:002022-07-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-08:/diary-2022-07-08<p class="first last">Definite progress, once again.</p>
<p>I got to some rough bits in writing, so this was a bit of a slow day.
Although, it's a little hard to judge, because I'm tracking net counts, and part of the editing I did was to delete old stuff that I don't need to refer to any more, so I <em>probably</em> made a little more progress than a naive count would indicate.</p>
<p>Anyway, maybe like another week or two of working on this, and then I can collate all of the TODOs I left for myself, and then basically do it all again.
Yaaaaay...</p>
<p>It turns out I can't think of anything else to do in the next few minutes, so I should publish this and get ready for bed.</p>
<p>Good night.</p>
Diary 2022-07-072022-07-07T04:00:00-04:002022-07-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-07:/diary-2022-07-07<p class="first last">Progress on several fronts</p>
<p>Writing went well again.</p>
<p>After I messed around with Firefox's new download flow, I switched some stuff back how they wanted it, and some stuff how they didn't.
At this point, I'm genuinely not sure if I'm actually using the new flow, but it <em>says</em> I am, and all of the overrides I have set up are <em>supposed to be supported</em>, so I think I'm prepared to not be nervous about getting the rug yanked out from under me.</p>
<p>I'm also pondering some software stuff, but I should really see about finishing up the current, months-long push on MOTR before I focus on working on the tooling.</p>
<p>Aside from all of that...
I don't know, I should try to be a little more on top of the stuff that I do every day and don't really talk about in these entries?
We'll see.</p>
<p>Anyway, time to wind down.</p>
<p>Good night.</p>
Diary 2022-07-062022-07-06T04:00:00-04:002022-07-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-06:/diary-2022-07-06<p class="first last">A good relaxed day.</p>
<p>I had a good day of writing; I <em>probably</em> won't be able to replicate that on days that I don't have off, but we'll see...</p>
<p>I updated Firefox, and that seems to have done some weird things to my extensions.
Hopefully, that clears itself up later as more people use them.
The other thing I'm expecting from this update is that they redid the downloads workflow in response to user feedback, so I'm giving that a chance.
I just need to have something to download in order to test it.
I'll figure that out later.</p>
<p>...</p>
<p>I poked around a bit, and stuff that I thought wasn't working before, period, now seems to be working, so, um, confused but happy shrug to all of that?
I'll need to use it in anger to see if the download panel bothers me, but I think I've got the rest of the workflow the way I'd like it.</p>
<p>Anyway, I'm going to take care of some other things after I publish this post, and then try to take things easy.</p>
<p>Good night.</p>
Weekly Roundup 2022-07-052022-07-05T04:00:00-04:002022-07-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-05:/weekly-roundup-2022-07-05<p class="first last">Another satisfying pace of work.</p>
<ul class="simple">
<li>Wednesday: I worked on MOTR and writing.</li>
<li>Thursday: I did some work on the writing, and figured out one of the bugs in MOTR.</li>
<li>Friday: I worked on stuff, sort of, but mostly took it easy.</li>
<li>Saturday: I reviewed some of the high-level wrappers in MOTR.</li>
<li>Sunday: I did some work on MOTR, and it was kind of a mess, but things came together.</li>
<li>Monday: I worked on writing, and a bit on MOTR.</li>
</ul>
<p>Next week, I'm going to try to get over humps with the writing and with MOTR.</p>
Coding 2022-07-042022-07-04T04:00:00-04:002022-07-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-04:/coding-2022-07-04<p class="first last">I should probably work at a lower pace overall, but I just want to get all of this stuff <em>done</em>.</p>
<p>I was mostly focused on stuff besides code today, and I made good progress on those things, so that's good overall, but let's see what I can do right now.</p>
<p>In general, I should be working on writing helper code to inspect MOTR's core dependency graph.
That's going to take some careful thought, though, so what's something I can work on quickly for now?</p>
<p>Well, the obvious solution is to update the python wrapper so it can handle the pytest wrapper.
I think that basically, all I need to do there is update the <tt class="docutils literal">BASE</tt> object to be the correct type.</p>
<p>All right, that was pretty straightforward.
With a few tweaks as I go, that should have me ready to finish testing the wrappers.</p>
<p>For now, though, I just want to take a break before I get to bed.</p>
<p>Good night.</p>
Coding 2022-07-032022-07-03T04:00:00-04:002022-07-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-03:/coding-2022-07-03<p class="first last">"I just need to code more."</p>
<p>All right, I got the code to apparently work.
I'm a little out of it as a result of all of the weird special cases I added to paper over the issues I was finding.
I started documenting the experience <a class="reference external" href="https://im-in.space/@mwchase/108579105298895923">here</a>.</p>
<p>Basically, I added a bunch of extra wrapper classes to try to more accurately model the behavior I want out of the code.</p>
<p>Aside from the fact that I can't really describe any of the new code right now as "something I'd like to show off", the diff from today is so big that I'm not sure I can pick out any part of it as representative.</p>
<p>In any case, I'm going to publish this, consider some other things I wanted to work on today, and when I get back to it, start thinking about how to make the tests more thorough.</p>
<p>Good night.</p>
Coding 2022-07-022022-07-02T04:00:00-04:002022-07-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-02:/coding-2022-07-02<p class="first last">Oh yeah, I only got partway through some of this stuff last time.</p>
<p>I was poking at MOTR with new metrics stuff, and it had some recommendations, but making such changes isn't worth it until I've done a round of normal refactoring.
I have a few other things I want to do today, so I'm going to try to get through this entry quickly.</p>
<p>My basic goal for now is to re-assess the pytest wrapper, and figure out what's going to need to change.</p>
<p>Comparing against other wrappers, I need, in approximate order:</p>
<ul class="simple">
<li><tt class="docutils literal">Program</tt> subclass</li>
<li>Python versions <tt class="docutils literal">ValueAdaptor</tt></li>
<li>Pip args <tt class="docutils literal">Label</tt></li>
<li><tt class="docutils literal">Entry</tt> alias</li>
<li><tt class="docutils literal">CommandBuilder</tt> alias</li>
<li><tt class="docutils literal">OptionBuilder</tt> alias</li>
<li><tt class="docutils literal">COMMAND</tt> global</li>
<li><tt class="docutils literal">BASE</tt> global; things get tricky here, because as part of my paranoia about letting these programs touch the disk willy-nilly, I right now have it try to default to providing <tt class="docutils literal"><span class="pre">-p</span> no:cacheprovider</tt>; on balance, it probably makes sense to ditch this and move that to the pytest config file</li>
<li>So, assume that <tt class="docutils literal">NO_CACHE</tt> and <tt class="docutils literal">DEFAULT</tt> get deleted, and <tt class="docutils literal">BASE</tt> gets the same niceties as the other wrappers</li>
<li>The last thing in the wrapper, then, is the <tt class="docutils literal">junit_xml</tt> function, which I now remember I never finished updating the code so that didn't need to be a function.</li>
</ul>
<p>So, there are some fairly mechanical updates to the pytest wrapper, but before I deal with those, I need to:</p>
<ul class="simple">
<li>Disable caching in the pytest config</li>
<li>Rework <tt class="docutils literal">motr._api.helpers.reports.accumulator</tt> to get data from a parameter and also inject additional segments, forcing the file argument to be just a basename; this is technically less flexible, but I don't think it matters</li>
</ul>
<p>Anyway, I'll try to get to those this weekend, and try to handle other things now.</p>
<p>Good night.</p>
Diary 2022-07-012022-07-01T04:00:00-04:002022-07-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-07-01:/diary-2022-07-01<p class="first last">This is a new day to be taking things easy, but I'm not inclined to ponder why that should be.</p>
<p>I was feeling kind of out of it today, so I didn't do any editing, outlining, or writing, and instead messed around with tightening things up in MOTR.</p>
<p>Just messing around a bunch with removing <tt class="docutils literal">typing.Any</tt>, mostly in favor of <tt class="docutils literal">object</tt>.
I think this isn't always possible, but when it is, I might as well.</p>
<p>Aside from that, I did <em>think</em> a little about writing, but, eh.</p>
<p>I'm going to try to get serious about MOTR's test coverage tomorrow.
Once that's done, I can start making some of the improvements I've had in mind.</p>
<p>Anyway, I don't want to prolong things too much, so I'm done with this entry for now.</p>
<p>Good night.</p>
Diary 2022-06-302022-06-30T04:00:00-04:002022-06-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-30:/diary-2022-06-30<p class="first last">"700 lines?" "Yeah, that's a lot of lines." "Just what are you even <em>doing</em> with Trio?" "Plenty."</p>
<p>I did the outlining.
I'm going to have to wait a bit to see if I missed anything, but the majority of it should be in a good enough raw form.</p>
<p>Earlier today, I investigated some long-standing issues with MOTR, but I didn't try to fix them yet.
Basically... <a class="reference external" href="https://builtoncement.com/">Cement</a> and <a class="reference external" href="https://trio.readthedocs.io/">Trio</a> both try to register a signal handler, and the consequences of Trio not registering its handler is nearly 700 lines worth of traceback on a ctrl-c, and if I stop Cement from registering its handler, then that means I need to add another except block to the main module.
I haven't tried it yet, but this seems like a pretty straightforward tradeoff.</p>
<p>I'd like to wrap up for now, but it's nice to have made various bits of progress today.</p>
<p>(This post's summary is a reference that virtually nobody can be expected to get.
Oh well.)</p>
<p>Good night.</p>
Diary 2022-06-292022-06-29T04:00:00-04:002022-06-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-29:/diary-2022-06-29<p class="first last">Just when I thought I understood variance...</p>
<p>I got a little caught up making obvious fixes to MOTR, and now it's at the point where I want to step back for a few days, then come back to it and see if it's ready for the pytest wrapper tests.
Some of the code I ended up putting in there feels a little questionable.
Like, hold on, why does mypy allow this?
But whatever.</p>
<p>I did a small amount of rewriting today.
I think what I want to do in the time I have left tonight, is to rough out the skeleton for this first part.</p>
<p>...</p>
<p>All right, good, got that together.
Part of the next thing to do is work on another parallel outline that'll fit into gaps in this one.
This makes sense, but I don't want to explain how.
Anyway, I'm making progress, even if it's not reflected in the metrics I'm messing with recording.
Give it a few days.</p>
<p>And with that, I'm going to wrap up so I can collapse in bed.</p>
<p>Good night.</p>
Weekly Roundup 2022-06-282022-06-28T04:00:00-04:002022-06-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-28:/weekly-roundup-2022-06-28<p class="first last">I'm still incredulous that there are injuries for "lying down too much"</p>
<ul class="simple">
<li>Wednesday: I was in pain.</li>
<li>Thursday: I continued to be in pain, but I tried to figure out how I'm going to move forward with my projects.</li>
<li>Friday: I started shifting my focus more towards MOTR.</li>
<li>Saturday: I took a break from MOTR, and did... stuff. Not particularly polished, but it "works".</li>
<li>Sunday: I managed to make a bit of progress on MOTR.</li>
<li>Monday: In continuing with that progress, I once again ended up wanting to rip out and replace some code.</li>
</ul>
<p>Next week, I'm going to try to make good progress on this stuff, but we'll see how it all goes.</p>
Coding 2022-06-272022-06-27T04:00:00-04:002022-06-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-27:/coding-2022-06-27<p class="first last">Progress!...?</p>
<p>The high-level layer on top of MOTR is somehow in even worse of a mess than usual right now, because I was putting stuff together, and I realized that there should be a way to make things easier to use, but it's running into some friction.</p>
<p>Basically, I think I'm once again running into helper functions that are no longer being helpful.
I'm not certain, but I think the way out here is to add some helper methods to the classes that some of this code was wrapping, and expose those classes directly...</p>
<p>The difficulty I'm going to need to resolve, though, is that, for a runner-type command, we start with the command, add the args, and go, but for non-runner-type commands, we start with the command, <em>and the python version</em>, so I guess I need a little helper class for that.
I'm getting confused enough thinking about this that I'm going to take a break, and try the following when I get back to it:</p>
<ul class="simple">
<li>Make a minimal helper class for these purposes.</li>
<li>Replace all uses of the current helper class with the new/existing classes.</li>
<li>Make a note of what's awkward.</li>
<li>Address that awkwardness if it's really obvious how, otherwise gather more data, by implementing more wrappers.</li>
</ul>
<p>I let things get late so now I am once again cutting off the entry awkwardly.</p>
<p>Good night.</p>
Coding 2022-06-262022-06-26T04:00:00-04:002022-06-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-26:/coding-2022-06-26<p class="first last">Did work that I'm not feeling up to describing.</p>
<p>All right, I did some work on MOTR.
The recursive methods are untangled and another one added.
The main thing missing from <tt class="docutils literal">ParametricCommand</tt> is the change-up of the type annotations.</p>
<p>Anyway, I'm a little out of it, so I'm going to cut things off and see if I can get more done.</p>
<p>Good night.</p>
Coding 2022-06-252022-06-25T04:00:00-04:002022-06-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-25:/coding-2022-06-25<p class="first last">I <em>seriously</em> disclaim all warranties on this, in case someone sees this post and somehow gets the idea "yes!" "that!" "that is what I will base my entire homebrew enterprise toolchain around!". Do not get that idea.</p>
<p>I did something else today, instead of working on MOTR.
As exhibit A against myself, I present, the first cell of the newly created Jupyter notebook, <tt class="docutils literal">crimes.ipynb</tt>:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">base_call</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">return</span>
<span class="n">SENTINEL</span> <span class="o">=</span> <span class="nb">object</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">inner</span><span class="p">:</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="n">sup</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">SENTINEL</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__super</span> <span class="o">=</span> <span class="n">sup</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__default</span> <span class="o">=</span> <span class="n">default</span>
<span class="k">def</span> <span class="fm">__getattribute__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">getattr</span><span class="p">(</span><span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__getattribute__</span><span class="p">(</span><span class="s2">"_inner__super"</span><span class="p">),</span> <span class="n">name</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
<span class="n">default</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__getattribute__</span><span class="p">(</span><span class="s2">"_inner__default"</span><span class="p">)</span>
<span class="k">if</span> <span class="n">default</span> <span class="ow">is</span> <span class="n">SENTINEL</span><span class="p">:</span>
<span class="c1"># Should inject name info</span>
<span class="k">return</span> <span class="n">base_call</span>
<span class="k">return</span> <span class="n">default</span>
<span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">instance</span><span class="p">,</span> <span class="n">owner</span><span class="p">):</span>
<span class="n">old_super</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__getattribute__</span><span class="p">(</span><span class="s2">"_inner__super"</span><span class="p">)</span>
<span class="n">new_super</span> <span class="o">=</span> <span class="n">old_super</span><span class="o">.</span><span class="fm">__get__</span><span class="p">(</span><span class="n">instance</span><span class="p">,</span> <span class="n">owner</span><span class="p">)</span>
<span class="k">if</span> <span class="n">new_super</span> <span class="ow">is</span> <span class="n">old_super</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span>
<span class="k">return</span> <span class="n">inner</span><span class="p">(</span><span class="n">new_super</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">BetaMeta</span><span class="p">(</span><span class="nb">type</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">mro</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="k">for</span> <span class="n">base</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__bases__</span><span class="p">:</span>
<span class="k">assert</span> <span class="n">base</span> <span class="ow">is</span> <span class="nb">object</span> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">base</span><span class="p">,</span> <span class="n">BetaMeta</span><span class="p">)</span>
<span class="n">base_mro</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">mro</span><span class="p">()</span>
<span class="k">return</span> <span class="n">base_mro</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">base_mro</span><span class="p">[:</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">base_mro</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">:]</span>
<span class="k">class</span> <span class="nc">Beta</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">BetaMeta</span><span class="p">):</span>
<span class="k">pass</span>
</pre></div>
<p>I'm not sure if this always works, but when I tried it with a basic example, it seemed to work.
This code is really brittle.
In particular, I kept on having trouble trying to find a way to not need to do <tt class="docutils literal"><span class="pre">inner(super())</span></tt>, which was pretty annoying.
Various things not working that kind of seemed like they should have.
Oh, well.</p>
<p>Anyway, the goal of all of that nonsense is to allow for <a class="reference external" href="https://beta.cs.au.dk/">BETA</a>-style inheritance.
Is that a good idea?
Well, with all of that code, there's a way to find out.
Once it's cleaned up and gets some proper invocations of the descriptor protocol.</p>
<p>Anyway, I don't want to ponder whether that's "something anybody should have attempted", or whatever, so I'm going to publish this and wind down extra-early.</p>
<p>Good night.</p>
Diary 2022-06-242022-06-24T04:00:00-04:002022-06-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-24:/diary-2022-06-24<p class="first last">Kind of wondering if my rambling about the higher-level abstractions I'm building on top of MOTR sounds, like... real.</p>
<p>I'm still putting together editing plans based on the feedback I got.
I hope I get to the point where I'm done planning stuff out for a bit.
Then, take a break for at least a few days.
Then start doing the rewrites.
This is supposed to be fun, so I don't want to force myself into the meat of it.</p>
<p>Anyway, moving on from that for now, I took a look at MOTR's codebase, and it should be no problem to change the report path code.
It means removing a usage of a helper function, but if the helper function isn't being helpful then... don't use it.
Here's about what needs to happen:</p>
<ul class="simple">
<li>Factor the recursive code in <tt class="docutils literal">ParametricCommand</tt> into independent methods</li>
<li>Add a field for representing "segments" of the reports path</li>
<li>Add that field to the relevant <tt class="docutils literal">ParametricCommand</tt> instances, or into the helpers</li>
<li>Write a recursive method to combine the field</li>
<li>(It may be possible to write some kind of decorator to abstract out the recursion but that is <em>not a priority right now</em>)</li>
<li>Inject the field into a label that is re-exported by the reports helper module</li>
<li>Rewrite the reports helper to retrieve the injected label, combine it with an optional argument, and use that as the base parametric for an <tt class="docutils literal">InputAccumulator</tt></li>
</ul>
<p>That's some of the tricky stuff worked out.</p>
<p>Other things that occurred to me as I looked into this:</p>
<ul class="simple">
<li>It should be possible to wrap stuff relating to junit into a helper function</li>
<li>... which has to be applied to a <tt class="docutils literal">Parametric</tt>, so <em>after</em> <tt class="docutils literal">ParametricCommand.build()</tt> is called</li>
<li>Because the version information propagates "outward" from modules, it should work to convert the module field into a union that either has a module or an adaptor; doing this removes a line of boilerplate from various parts of the API, and might simplify things even more than that suggests</li>
<li>It may be possible to put all of this into a callable object, such that it's reasonable for a motrfile to have no explicit control flow.
(Users could then choose to add control flow that keys off of environment variables or something.
I'm not going to bother trying to stop these hypothetical users.)</li>
</ul>
<p>All in all, exciting times ahead for MOTR, which is good, since I'd like to feel comfortable focusing on <em>any other python project</em> at some point.
Anyway, it's late, and I should wrap up.</p>
<p>Good night.</p>
Diary 2022-06-232022-06-23T04:00:00-04:002022-06-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-23:/diary-2022-06-23<p class="first last">Suffering for my art. Puzzling for my code.</p>
<p>Ugh...
Feedback...
So hard to take...
I'll have another draft together in, like a few months?
Seriously?
That's what it feels like...</p>
<p>Anyway, I also did some planning for MOTR, and I think there are a few places I need to refactor and then augment, and then I can work on some of the logic required to handle generating paths for reports.
This whole... thing... might be an argument, at least as far as most people are concerned, against trying too hard to generalize something.
Because this has been... a lot.
My basic plan is to break down <tt class="docutils literal">ParametricCommand._build()</tt> so its internal structure isn't as fragile to change.
The problem with it right now is that the method is recursive, and the stuff <em>around</em> the recursion can't be easily rearranged, but this doesn't look obvious to me.
Basically, the function does two things, that are both recursive.
I'd rather split this into two recursive functions that do one thing, and then I can coordinate them in <tt class="docutils literal">ParametricCommand.build()</tt>, and also add <em>other</em> recursive functions that are required for report path generation.</p>
<p>I also need to figure out how I want to assemble the commands that will take advantage of this functionality.
I have something in mind that seems like it's powerful enough, but it's probably too complicated.</p>
<p>Anyway, I'm still out of it from all of that feedback, and also trying to deal with hurting myself over the weekend, so I'm going to call it here and try to chill out.</p>
<p>Good night.</p>
Diary 2022-06-222022-06-22T04:00:00-04:002022-06-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-22:/diary-2022-06-22<p class="first last">Trying to figure which should-have-been-innocuous thing is messing up my body.</p>
<p>Good news: I got some really helpful editing feedback on my writing.
Bad news: I messed up my knees over the weekend and I can't figure out how to make them not hurt.</p>
<p>All right, let's see what else is on my mind.
Now that I can look at MOTR and think "this part isn't working how I want it to", I can work on nailing down requirements.
Sadly, part of this process will involve getting my knees to feel better so I can use my laptop for more than a few minutes at a time.</p>
<p>All right, I'm not thinking of more to write here by standing here; I'm just annoying myself.
Time to call it.</p>
<p>Good night.</p>
Weekly Roundup 2022-06-212022-06-21T04:00:00-04:002022-06-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-21:/weekly-roundup-2022-06-21<p class="first last">Mo' MOTR Mo' Problems</p>
<ul class="simple">
<li>Wednesday: I got sidetracked by the obnoxious behavior of the "enter" key in Jupyter Lab.</li>
<li>Thursday: I did some writing, and planned to work on MOTR over the weekend.</li>
<li>Friday: I figured out that the Jupyter stuff isn't worth looking into now.</li>
<li>Saturday: I poked at MOTR a little.</li>
<li>Sunday: Travel took a lot out of me, so I made one small improvement to MOTR.</li>
<li>Monday: I realized that the interface I'm building right now is kind of wrong, and tried to figure out how to fix it.</li>
</ul>
<p>Next week, I've got some writing that's nearly ready to go into editing, so I'm going to try to work on that.
I'm also going to look into changing the higher-level concepts in MOTR to see if I can come up with something cleaner.</p>
Coding 2022-06-202022-06-20T04:00:00-04:002022-06-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-20:/coding-2022-06-20<p class="first last">Surely I'll run out of problems at some point...</p>
<p>All right, I tweaked the code some more today, and updated the prototype for the pytest wrapper.
I think I have the wrong interface there for now, so I'm trying to figure out how to make it better.</p>
<p>Basically, when pytest runs and creates XML results, those results have to <em>go</em> somewhere, and currently that's being specified by passing a path explicitly.
To make that work better... there's a concept I had in here; it was called something like "segments", and it might still be, I don't remember for sure...
Ah-ha, it's the <tt class="docutils literal">path</tt> attribute on the <tt class="docutils literal">python_helpers.PythonCmd</tt>, which could pass them to the <tt class="docutils literal">command.Metadata</tt> in some way that would allow it to inject it into argument...</p>
<p>One potentially confusing possibility is to rework the <tt class="docutils literal">installer</tt> concept to be for any path generated along these lines...</p>
<p>Okay, this is a bit too much to consider right now.
I'm going to need to take some time to consider how to make this work.</p>
<p>By the way, to clarify what's wrong with the current system: the ideal here is that the motrfile creates a <em>single</em> object that can be combined with other "runner" objects, and each combination should put its output in a different directory.
Right now, the mechanism for changing the output directory is buried inside several layers of wrapped objects, so this doesn't work.</p>
<p>I want to just mess around and let this percolate in my head for a while, so I'm going take things easy for now.</p>
<p>Good night.</p>
Coding 2022-06-192022-06-19T04:00:00-04:002022-06-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-19:/coding-2022-06-19<p class="first last">TRAFFIC</p>
<p>I was traveling today, for longer than I expected, and I'm a little messed up.
So, I'm not up for doing much, and I got just one thing done:
I inlined some private globals that were only used once.
This makes the code a little less cluttered.</p>
<p>I have various improvements planned, and one of them is to create a helper class that will make it possible to inline more of these variables, and hopefully make the interfaces created with these building blocks a little more regular.</p>
<p>Anyway, I want to get ready for bed now.</p>
<p>Good night.</p>
Coding 2022-06-182022-06-18T04:00:00-04:002022-06-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-18:/coding-2022-06-18<p class="first last">A little bit of work...</p>
<p>After I realized just how out-of-date a version of CodeMirror Jupyter Lab is using, and that there's an active effort to update it, I decided to hold on on writing code for it until they've ironed out the major version jump there.</p>
<p>I'm feeling a little tired right now, so I'm just going to see what I can get done or planned for MOTR.</p>
<p>Let's see what happens if I try to combine the python version stuff...
It messed with things a little, but I think it's better this way.
Better keep going...</p>
<p>Okay, I made those simplifications.
The next logical steps are to rename some of the remaining globals to remove redundant information, and to inline some other globals that are only used once and not meant to be exported.
It might also make sense to write <tt class="docutils literal">__all__</tt> lists for these modules for documentation.</p>
<p>I think the thing to do is write a bunch of my ideas down by hand, and work on them over the next few days if I have time.
Let's see about that...</p>
<p>Okay, it's written down, and I want to wrap up for now.</p>
<p>Good night.</p>
Diary 2022-06-172022-06-17T04:00:00-04:002022-06-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-17:/diary-2022-06-17<p class="first last">Embarrassing but useful discoveries.</p>
<p>All right, I did a bit of writing and editing today, so there's that.</p>
<p>I am blanking on anything else to say right now.</p>
<p>Maybe I'd like to do a little more research into my Jupyter/CodeMirror complaints.</p>
<p>So, according to CodeMirror, I need a custom command to do what I want.
So, that's "adding [a property] to the <tt class="docutils literal">CodeMirror.commands</tt> object".
Specifically, I need to change the <tt class="docutils literal">newlineAndIndent</tt> command.</p>
<p>Before I get too much further, I need to figure out which version of CodeMirror Jupyter Lab is using.
Looks like... <tt class="docutils literal">~5.61.0</tt>?
So, I should see what the code is like at version <tt class="docutils literal">5.61.1</tt>, probably.</p>
<p>Anyway, in order to use that information, I need to have access to the relevant CodeMirror object, which seems a bit confusing to me, currently.</p>
<p>I think I need to write some TypeScript that exports a function; eventually in its own tiny module.
Then, a Jupyter extension that wraps that function by... injecting it into the CodeMirror object associated with cells using the ipython mode?
(For bonus points, figure out how to change the <tt class="docutils literal">tokenLexer</tt> function to dedent on <tt class="docutils literal">...</tt> and <tt class="docutils literal">raise</tt> as well (but perhaps not <tt class="docutils literal">raise NotImplementedError</tt>))</p>
<p>I think I'm understanding this a bit better; the key insight that's bringing lots of things together is that Jupyter appears to be using a version of CodeMirror that's over a year old, which made my bug report, um, incredibly pointless?
Oops.
Sorry.</p>
<p>Anyway, I'll get back to all of this later; for now, I should get ready for bed.</p>
<p>Good night.</p>
Diary 2022-06-162022-06-16T04:00:00-04:002022-06-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-16:/diary-2022-06-16<p class="first last">Things came together today, but it'd be nice if I could get them to come together <em>sooner</em>.</p>
<p>I caught up on a few other things today, and worked on some writing.
The big roadblock right now is, I need to do some editing, but I don't <em>want</em> to do some editing.
Like, why won't the text spontaneously rewrite itself into a form that makes more sense?
Rude.</p>
<p>Anyway, I'm going to be traveling a bit this weekend, but it shouldn't be as crazy as the last bit of travel.
We'll see how much I can work on MOTR like that.
I think I'll want to focus on writing tests for the pytest wrappers.
I'll see, as I work on those, whether I want to focus on cleaning up the code or covering more use cases.
Like, once I have tests for the other three cases in the motrfile, that <em>should</em> give me coverage over most of the non-error paths, so I'll get some confidence in its behavior.</p>
<p>I think sometime, I'd like to look more into claims that additional test coverage isn't really helpful, because I feel like there must be some nuance missing.
Because it just doesn't seem to match up for me.
Is it because I try to be cautious and write tests before using the code when possible, so code issues manifest as test failures rather than debugging sessions?
Maybe.
Maybe it's something else.
But regardless, either my subjective experience is an outlier or doesn't match up with a quantified measurement, or there's some reason that what I'm doing doesn't match up with the circumstances of the studies I've heard about that are supposed to show that increasing test coverage doesn't help.</p>
<p>Either way, I should get ready for bed.</p>
<p>Good night.</p>
Diary 2022-06-152022-06-15T04:00:00-04:002022-06-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-15:/diary-2022-06-15<p class="first last">Requesting help with multiple APIs I don't know, in a language I don't know, to solve a problem... <em>similar</em> to one that I've solved before.</p>
<p>I don't recall that I did anything in particular today, besides trying to catch up on various tasks.
I think I'm basically caught up at this point, so that feels good.</p>
<p>I did mess around with code a little, trying to document my untested Unlambda interpreter, and polishing MOTR's tests slightly.
They could do with a bit more polish...
And I may have gotten <em>slightly</em> sidetracked from writing the interpreter in Jupyter Lab, and encountering behavior that only makes sense to me if the top-most multi-line statement in a cell, if any, is "supposed to" be the last thing in that cell.
I've written up a <a class="reference external" href="https://im-in.space/@mwchase/108479152263134617">question</a> that summarizes my current state of knowledge relevant to this.
If anybody knows about "the right way" or "a way" to make CodeMirror behave differently from Jupyter Lab, I'd appreciate the help.</p>
<p>Okay, it's getting late, and there's a <em>bit</em> more I'd ideally like to get doe tonight, so I'm cutting this off here.</p>
<p>Good night.</p>
Weekly Roundup 2022-06-142022-06-14T04:00:00-04:002022-06-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-14:/weekly-roundup-2022-06-14<p class="first last">Looks like whatever part of me that decides what I have the focus to work on is <em>really</em> stubborn.</p>
<ul class="simple">
<li>Wednesday: I was physically and emotionally tired.</li>
<li>Thursday: I figured out how to make the debate over <tt class="docutils literal"><span class="pre">0.99999...</span></tt> worse.</li>
<li>Friday: I didn't have the bandwidth to write a long entry.</li>
<li>Saturday: I started getting distracted by Unlambda.</li>
<li>Sunday: I kept getting distracted by Unlambda, but I was able to plan a bit for MOTR.</li>
<li>Monday: I still got distracted by Unlambda, but I was able to execute some of the plans.</li>
</ul>
<p>Next week, I've got some writing I really want to finish up.
And, of course, I want to make progress on MOTR.</p>
Coding 2022-06-132022-06-13T04:00:00-04:002022-06-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-13:/coding-2022-06-13<p class="first last">Constantly sabotaged by my fascination with basically useless things.</p>
<p>All right, I... got distracted.</p>
<p>Point is, I did get things together enough to start working on the report helpers for MOTR.
I've written the code, so if that doesn't just outright break, I'll work on bringing it into the existing wrappers.</p>
<p>Let's see...
Looks like I got flake8 updated...
And mypy updated...
And... junit2html.</p>
<p>Okay, good job, me, that cut out a few of the giant block of imports at the top of all of these modules.
It is kind of a drag to start working on a new one of these, and need to bring in like a dozen other modules.</p>
<p>In any case, it's way too late right now, so I'm out.</p>
<p>Good night.</p>
Coding 2022-06-122022-06-12T04:00:00-04:002022-06-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-12:/coding-2022-06-12<p class="first last">I <em>wrote</em> yesterday's entry on time, I just couldn't <em>post</em> it.</p>
<p>So, I <em>slightly</em> got caught up in updating Unlambda interpreter code.
The biggest issues currently are:</p>
<ul class="simple">
<li>Haven't ported the parser and main loop yet</li>
<li>The implementation of the S combinator <em>looks</em> wrong, but testing it against one of the old implementations, appears to work</li>
</ul>
<p>Anyway, let's ignore that for now.</p>
<p>It's late, so I'm going to see how quickly I can put together something helpful for MOTR.</p>
<p><em>Currently</em>, I have the label for the python versions, and the adaptor associated with it.
Now, that can be consolidated into just the adaptor, and the convention is to pull the label off of it.</p>
<p>Similarly, the command object groups with the label for pip arguments.
That consolidation should wait until I've written tests against the pytest wrapper, to avoid over-specializing.</p>
<p>For the reports stuff, that needs a new module under the helpers package.
For now, that can also hold the common code for the functions that get used for adaptors.</p>
<p>Those should all be good to look into tomorrow.</p>
<p>Good night.</p>
Diary 2022-06-112022-06-11T04:00:00-04:002022-06-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-11:/diary-2022-06-11<p class="first last">Not sure how many people share my standard of "relaxing".</p>
<p>First opportunity at me-time: chilling out, which apparently involves trying to relearn how <a class="reference external" href="http://www.madore.org/~david/programs/unlambda/">Unlambda</a> works, and trying to hold the whole model in my head.
Didn't go so well, but I had fun.</p>
<p>To try to get a handle on this stuff, I went searching around for previous attempts I'd made.
I found a few, but I think I was in the middle of stuff with them, so they don't necessarily... make sense...</p>
<p>Anyway, I'd be interested in coming back to them later, but I don't know if I'll go for them tomorrow.
I'm trying not to plan too far ahead, or very far ahead at all really.
Nonetheless, I hope I manage to scrape together the focus to make some API improvements to MOTR.</p>
<p>Anyone, nothing like that for now.</p>
<p>Good night.</p>
Diary 2022-06-102022-06-10T04:00:00-04:002022-06-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-10:/diary-2022-06-10<p class="first last">I can't do as much as I'd like to yet, but I can do enough, more or less.</p>
<p>I'm still really tired from traveling, so it's hard for me to think of an idea for a post.</p>
<p>I'm generally getting stuff done, even though I'm tired, but I should probably stop pushing it.
I'm going to get some sleep, and try to have some fun me-time over the weekend.</p>
<p>Good night.</p>
Diary 2022-06-092022-06-09T04:00:00-04:002022-06-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-09:/diary-2022-06-09<p class="first last">This is not polished, and is absolutely going to make some things worse. :)</p>
<p>Still super tired and out of it, but something interesting occurred to me earlier today.</p>
<p>As you may know, there are recurring arguments over whether <tt class="docutils literal"><span class="pre">0.99999...</span></tt> is "really" equal to <tt class="docutils literal">1</tt>.
I noticed an interesting perspective to take on this.
In decimal notation, it's not just <tt class="docutils literal">1</tt> that has this issue.
There's <tt class="docutils literal">0.5</tt> and <tt class="docutils literal"><span class="pre">0.499999...</span></tt>, and <tt class="docutils literal">0.2</tt> and <tt class="docutils literal"><span class="pre">0.19999...</span></tt>.
And it extends to any product of powers of one half and one fifth, and any integer.</p>
<p>But it's different, for example, in ternary.
In ternary, besides <tt class="docutils literal">1</tt> and <tt class="docutils literal"><span class="pre">0.222222...</span></tt>, there's any power of <tt class="docutils literal">0.1</tt> times an integer.</p>
<p>But it's different in <em>balanced</em> ternary.
Suppose we use the digits <tt class="docutils literal">-</tt>, <tt class="docutils literal">0</tt>, <tt class="docutils literal">+</tt>.
Now, the highest balanced ternary number with a <tt class="docutils literal">0</tt> in the ones place is <tt class="docutils literal"><span class="pre">0.++++++...</span></tt>, which corresponds to <tt class="docutils literal"><span class="pre">0.11111...</span></tt>, which should be one half.
Flip the digits and add one, and we get that there's another representation of one half: <tt class="docutils literal"><span class="pre">+.--------...</span></tt>.
And one is only <tt class="docutils literal">+</tt>.
By switching around the notation, we've ended up with a completely non-overlapping set of problem numbers!
This means that either the "problem" isn't real, or it's happening with literally every rational number, and it's simply obscured by the choice of notation.</p>
<p>If the "problem" isn't real, then we should understand the multiple representations to form equivalence classes.
Which isn't so strange.
Consider that <tt class="docutils literal">1/2</tt> and <tt class="docutils literal">3/6</tt> have no digits in common in those representations, yet they're normally treated as the same number.</p>
<p>In the alternative...
There are infinitely many distinct numbers that are collapsed into a single representation by typical positional notation.
To handle the difference between these distinct numbers, some more precise representation is required to track them.
In other words, if you believe that <tt class="docutils literal">1 ≠ <span class="pre">0.99999...</span></tt>, then point notation is literally not good enough for you, and you should be looking for alternatives!</p>
<p>*mic drop*</p>
<p>Good night.</p>
Diary 2022-06-082022-06-08T04:00:00-04:002022-06-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-08:/diary-2022-06-08<p class="first last">Can I be done freaking out over things for just a little bit?</p>
<p>Ugh, wow.
I'm way out of it now that the weekend is over.
Like, all of that was necessary, but I am emotionally and physically drained right now.</p>
<p>I want to get back into working on things, but I also want to collapse, and I also think I should work on getting back up to speed with some things that I did a bit less of when I was traveling.
I think the best way to handle that is to just accept that this will be a short entry, and work on those other things after I post this.</p>
<p>Make sure to let the important people in your life know that you love them.</p>
<p>Good night.</p>
Weekly Roundup 2022-06-072022-06-07T04:00:00-04:002022-06-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-07:/weekly-roundup-2022-06-07<p class="first last">This was never going to be a standout week, but I'm glad with what I got done.</p>
<ul class="simple">
<li>Wednesday: I had a slightly rough day.</li>
<li>Thursday: I had a slightly annoying day, but I decided to focus on relaxing, because that's important.</li>
<li>Friday: I got a little work done on MOTR, and freaked out a bit from other things.</li>
<li>Saturday: I had a rough day, that's probably going to be comparably rough to things after I publish this entry, but oh well.</li>
<li>Sunday: I got more tests passing in MOTR, and tried to consider what I need to do to give it a good interface for third-party developers.</li>
<li>Monday: I made notes about common code in MOTR. The problem with this code is not just that it's repeated, but that it's not really obvious why all of it is there, which makes it hard to write.</li>
</ul>
<p>Next week, I'm going to try to clean things up a bit in MOTR.
And get back to various pieces of writing.</p>
Coding 2022-06-062022-06-06T04:00:00-04:002022-06-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-06:/coding-2022-06-06<p class="first last">Trying to figure out how much of this I can shove into nice-ish class definitions.</p>
<p>All right, let's see what kind of common functionality I can pick out of these four-to-six modules...</p>
<p>Common things include:</p>
<ul class="simple">
<li>The <tt class="docutils literal">Label</tt> object for representing pip args</li>
<li>Specifying which type of entry point for the command</li>
<li>Putting this information together into a <tt class="docutils literal">Command</tt> object</li>
<li>The <tt class="docutils literal">Label</tt> object for representing python versions to install a set of packages under</li>
<li>Turning that label into a <tt class="docutils literal">ValueAdaptor</tt></li>
<li>Subclassing <tt class="docutils literal">_program.Program</tt></li>
<li>Putting together the <tt class="docutils literal">Command</tt>, a helper function, and allowed exit code data into a <tt class="docutils literal">python_helpers.CommandBuilder</tt></li>
<li>Designating the reports prefix</li>
<li>Designating a directory within a reports prefix</li>
<li>Labeling that directory</li>
<li>Creating an output file under the labeled path, using some basically-identical function implementations</li>
<li>Assembling everything into a <tt class="docutils literal">Part</tt> object of some kind</li>
</ul>
<p>The remaining bits of unique code are sooooort of hacks around inadequacies in the high-level design.
It should be possible to streamline some of this code by creating helper functions to put together <tt class="docutils literal">ValueAdaptor</tt> instances given a starting path.</p>
<p>It also kind of seems like it would make sense to bundle together the reducer function and initial value arguments to the <tt class="docutils literal">reduce_parameterization</tt> helper.
I've also got the urge to break up the <tt class="docutils literal">parametric.py</tt> module into several smaller modules, and convert the nested function definitions into classes with <tt class="docutils literal">__call__</tt> methods, but I'm not quite sure there's a concrete objective that would be <em>satisfied</em> by doing that, so I'll hold off on that for now.</p>
<p>In any case, it's late, and I'm tired, so I'm just going to kind of... end this post now.</p>
<p>Good night.</p>
Coding 2022-06-052022-06-05T04:00:00-04:002022-06-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-05:/coding-2022-06-05<p class="first last">F in the chat for the inboxes of everyone who ever thought about using Unreal Engine for any purpose whatsoever. This has nothing to do with the post, but hoo boy, was that PR something.</p>
<p>Okay, I made a bit more progress on MOTR, partially by doing weird hacks to the code.
I've now got a basic test working for the mypy workflow.
At this point, I could either try to plug some coverage holes by copying this approach with the pytest workflow code I've written, or I could step back and try to figure out which bits of the code I've written should be their own functions, etc.</p>
<p>For the latter course of action, I've got five-ish modules to review and see if I can make modules like them more pleasant to write.
Making those modules more pleasant is important because...
Okay, so, imagining a hypothetical future where MOTR takes off, I've categorized developers who will do things with MOTR into 4 groups:</p>
<ul class="simple">
<li>Core developers, aka just me for now.</li>
<li>Extension developers, aka just me for now.</li>
<li>Developers configuring MOTR to run against a repository, aka just me for now.</li>
<li>Developers running tests against a repository that uses MOTR, aka just me for now.</li>
</ul>
<p>MOTR is right now good enough for the fourth category, and I'm getting there for the third one, but it could be better, for sure.</p>
<p>These five-ish modules are important to the first two categories because the third category needs high-level representations of automatable tasks to be able to write a concise and clear motrfile.
(Sadly, judging by the tests I've written, I can't expect any improvements in clarity just yet.)
Right now, there are two ways these modules can be improved:</p>
<ul class="simple">
<li>Factor out common code to cut down on boilerplate that the second group has to write.</li>
<li>Write helper functions to cut down on the freeform nature of the current interface.
Some of the test code is "obvious" conversions from input types, and there's no "static" analysis of whether the generated commands make sense.
I think it should be possible to address these shortcomings together, but I should plan the details carefully.</li>
</ul>
<p>For now, I'm going to take things easy, and pick back up with planning the boilerplate reduction first.</p>
<p>Good night.</p>
Diary 2022-06-042022-06-04T04:00:00-04:002022-06-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-04:/diary-2022-06-04<p class="first last">Should be through the worst of things.</p>
<p>Okay, I got through the toughest part of the weekend, I think.
I don't think I have it in me to write anything interesting, so I'm going to just publish now and work on relaxing.</p>
<p>Good night.</p>
Diary 2022-06-032022-06-03T04:00:00-04:002022-06-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-03:/diary-2022-06-03<p class="first last">Hurting myself by approaching automated systems like "What's the worst thing they could do to me that would still be considered defensible?"</p>
<p>Ugh.
I did my best to have a nice, relaxing day today.
I think I really did.
But a few things were working against me.</p>
<p>Just now, I had a bunch of tech issues:
The travel website was, I think, gratuitously confusing, and I had trouble getting stuff to print after I got through the website.
That <em>should</em> be all set, but maybe we will find a <strong>[FUN]</strong> surprise tomorrow.</p>
<p>Anyway, that's that taken care, as best I can do.</p>
<p>I also did a bit more work on MOTR today.
I haven't gotten the new tests passing, but it should be straightforward to finish up.
Emphasis on <em>should</em>.
Getting as far as I got today involved writing a ~twenty-line helper function and making code changes that I really <em>hope</em> were justified and principled.</p>
<p>Oh wow, I think I'm crashing from freaking out over that website.
Stupid neurochemistry.
Okay, yeah, feeling bad; I'd better wrap this up.</p>
<p>Good night.</p>
Diary 2022-06-022022-06-02T04:00:00-04:002022-06-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-02:/diary-2022-06-02<p class="first last">Attempting, once again, to just relax.</p>
<p>Work went a little rough today.
I figured some things out, and then... technical difficulties.
Completely out of my hands.
Really annoying.</p>
<p>Anyway, now I'm off, and I'm ready to relax a little, and get ready to travel.</p>
<p>For now, though, I'm going to revisit some of the writing I was doing earlier, because I found myself really enjoying it, and I want to keep that up.</p>
<p>At the same time, I should probably try to get plenty of sleep, so I'm going to see about wrapping stuff up soon.</p>
<p>Good night.</p>
Diary 2022-06-012022-06-01T04:00:00-04:002022-06-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-06-01:/diary-2022-06-01<p class="first last">"I know my actions have consequences, but I feel like that consequence didn't have an action."</p>
<p>Today I had an okay day, until I suddenly had a very rough day, then I worked on getting it back to okay.
Nothing very bad, just gross and painful.</p>
<p>Anyway, I poked at MOTR a little because I felt like it, and played some games.
My plan for now is to post this, and get some other writing done.</p>
<p>I'd best actually do that instead of spacing out for ten more minutes.</p>
<p>Good night.</p>
Weekly Roundup 2022-05-312022-05-31T04:00:00-04:002022-05-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-31:/weekly-roundup-2022-05-31<p class="first last">Another rough week, but I got stuff done.</p>
<ul class="simple">
<li>Wednesday: I wasn't up for doing much, so I didn't do much.</li>
<li>Thursday: I picked up a random side project from a few years ago, in order to unwind.</li>
<li>Friday: I continued on with that.</li>
<li>Saturday: I started working on the code that's needed for the MOTR rework.</li>
<li>Sunday: I apparently finished the rework. We'll see how it shakes out within the next few weeks.</li>
<li>Monday: I did some minor cleanups to MOTR's code.</li>
</ul>
<p>Next week, I've got some travel happening, so I'm going to keep on taking things easy.
After next week, I hope I'll be able to ramp back up, but I'll have to take things as they come.</p>
Coding 2022-05-302022-05-30T04:00:00-04:002022-05-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-30:/coding-2022-05-30<p class="first last">Working on what it feels like I can control.</p>
<p>I'm feeling kind of bleh, so I'm going to go over what I did today as quickly as I can.</p>
<p>I didn't think of any major updates to make to the tests, so I just focused on updating the mypy tests.
From that, I now have a todo list of functionality to implement to stop the test from failing immediately.
I'll look into that at some point.
I anticipate this week will be a little hard on me, so I'm going to try to avoid going, like "I'm going to put in this much work", or "I'll do it by this time".</p>
<p>Right now, I just want to feel better, and I think part of that is going to be getting off the laptop for a while.</p>
<p>Good night.</p>
Coding 2022-05-292022-05-29T04:00:00-04:002022-05-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-29:/coding-2022-05-29<p class="first last">It does feel kind of good to break down functions to the point where the type signature makes it obvious what they "should" do, then just slap those primitives together.</p>
<p>And, here we go.
After a bunch of confused swearing and writing more weird helper functions, I've managed to <em>seemingly</em> update the code and the active tests to use the new logic I planned out.
The proof of this will be in updating the other tests and seeing how they work, but I ended up realizing something as I was working on this:</p>
<p>These tests are nowhere near thorough enough.
I was only getting failures because I was managing to trigger weird errors.
I need to update these existing tests to actually make assertions about the shape of the output.</p>
<p>I just improved the tests a little, but I think they need some more work.
I'll look into that tomorrow, and then see about updating the other tests to the new API.
Hopefully, that will prove things out, given that the tests that need to be rewritten, were a major part of the <em>motivation</em> for the rewrite.</p>
<p>Anyway, it's late and I'm tired.
Again.</p>
<p>Good night.</p>
Coding 2022-05-282022-05-28T04:00:00-04:002022-05-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-28:/coding-2022-05-28<p class="first last">I wish this were the fun kind of code crimes.</p>
<p>All right.
I'm a little tired and out of it, but I got started updating MOTR.</p>
<p>I've got some of the infrastructure required to create the values that will be passed into the new <tt class="docutils literal">build()</tt> method.
The major thing I still need to add is something to create a bunch of <tt class="docutils literal">PathWith[VirtualenvArgs]</tt>s from a bunch of <tt class="docutils literal">VirtualenvArgs</tt>.
I could get elaborate, but I think I'll do what sounds like the least effort to me:</p>
<ul class="simple">
<li>Default the input to just the default interpreter.</li>
<li>If the default interpreter is passed, don't allow any other interpreters.</li>
<li>Copy some logic from elsewhere in the code to convert the path data in the interpreter info into a common prefix and different suffixes.</li>
</ul>
<p>I'm trying to implement that right now, but I'm roughing out the code and it's kind of a mess.
I'm going to publish this post and hack on the code a bit more, but it's not going to get <em>much</em> cleaner for now.</p>
<p>Good night.</p>
Diary 2022-05-272022-05-27T04:00:00-04:002022-05-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-27:/diary-2022-05-27<p class="first last">Still not sure what I'm going to <em>do</em> with all of that information...</p>
<p>The data entry is done for now.
Just got to keep relaxing, and try to get some satisfying work done over the weekend.</p>
<p>For now, I can't seem to focus on much, so I'm going to just publish this.</p>
<p>Good night.</p>
Diary 2022-05-262022-05-26T04:00:00-04:002022-05-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-26:/diary-2022-05-26<p class="first last">Continuing to do things that, for reasons I don't think I can articulate, I find fulfilling.</p>
<p>I've been trying to unwind more, and it seems that today, that meant picking up a data entry project I was working on, a few years ago, apparently.
I don't have a concrete use case in mind for all of this data once it's entered.
Sometimes you just want to enter some data, you know?</p>
<p>Anyway, I do want to come up with something to do that's, like, adjacent to the information I'm collating, but I'm not going to rush it.</p>
<p>For now, I'm just going to have to resign myself to recording some mildly interesting metadata and... there is no and.
Just space.</p>
<p>Good night.</p>
Diary 2022-05-252022-05-25T04:00:00-04:002022-05-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-25:/diary-2022-05-25<p class="first last">Progress on fixing my ability to focus. Agonizing, slow, progress.</p>
<p>Hm...</p>
<p>On paper, I'm doing okay at taking things easy, but, like... I really want to work on code or whatever...</p>
<p>But it's too late at night as I write this.
That would not be a good idea.</p>
<p>Best I can do for now is putter around cleaning up my browser tabs a bit more.</p>
<p>Okay, that's enough for tonight.
Time to wrap things up and get to bed.</p>
<p>Good night.</p>
Weekly Roundup 2022-05-242022-05-24T04:00:00-04:002022-05-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-24:/weekly-roundup-2022-05-24<p class="first last">The AC is getting looked at on Thursday. Hooray...</p>
<ul class="simple">
<li>Wednesday: I did some planning for sci-fi writing.</li>
<li>Thursday: I was stressed out about the AC not working. Or, it sort of works, but in a way that's usually not <em>useful</em>.</li>
<li>Friday: I spontaneously wrote a few hundred words complaining about games that I end up playing <em>a lot</em> when I play them.</li>
<li>Saturday: ...</li>
<li>Sunday: I put in a little more work planning out MOTR changes.</li>
<li>Monday: I <em>think</em> I figured out all of the high-level aspects of the plan for MOTR.</li>
</ul>
<p>Next week, I think I need to step back from pretty much everything for a little bit.
I think I'm feeling burnt out some.
I'll hopefully be up for working on MOTR, but I've got most of the really hard stuff done there; now it's just a matter of changing bits of code to how they "obviously" should be.</p>
Coding 2022-05-232022-05-23T04:00:00-04:002022-05-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-23:/coding-2022-05-23<p class="first last">The steps make sense, but there sure are a lot of them.</p>
<p>Well, I basically had "Objective: Survive" for today, and I did that, so, it's time to relax and wait for the air outside to cool off.</p>
<p>While I wait, let's see if I can take some quick notes on MOTR.
Yesterday, I determined that <tt class="docutils literal">ParametricCommand.build()</tt> should take a <tt class="docutils literal">ValueAdaptor[PathWith[EnvironmentArgs]]</tt>.</p>
<p>Now, the flip side of that is that the corresponding <tt class="docutils literal">Label</tt> needs to be populated in the <tt class="docutils literal">Registry</tt>.
Right now, <tt class="docutils literal">Registry</tt> population looks like <tt class="docutils literal">yield from api.cli.build.build(package_data)</tt>.
And creating the information that would be stored in the label looks something like <tt class="docutils literal">py = <span class="pre">api.cli.flake8._installer.PathWith(pathlib.Path(),</span> <span class="pre">api.cli.flake8._pip.VirtualenvArgs())</span></tt>.
Please ignore the encapsulation violations I stuck in there because I don't want to think about that part of the API yet.
To get things up and running, I need a helper function that creates a vector of that kind of data, and to have an idiom for adding that data to the <tt class="docutils literal">Registry</tt>.</p>
<p>Something that occurs to me, looking at this code, is that it might make sense to separate the current <tt class="docutils literal">changes()</tt> implementation into a <tt class="docutils literal"><span class="pre">Callable[[Sequence[Parametric[None]],</span> <span class="pre">Requirements[Registry]],</span> Requirements[None]]</tt>, or something like that.
Basically, indicating "It's not expected that instantiating <tt class="docutils literal">Parametric</tt>s be interleaved with building the <tt class="docutils literal">Registry</tt>."
That kind of reorganization is only appropriate after I've written some more tests, and I want to fix up the tests that I have, first.</p>
<p>Anyway, I think the last piece of the puzzle is the implementation of the <tt class="docutils literal"><span class="pre">ValueAdaptor[PathWith[...]]</span></tt>, and that should just be <tt class="docutils literal">return path_with.path</tt>.
So, I just need a function to bundle that up with a <tt class="docutils literal">Label</tt>, and that should be the whole plan to get this working.</p>
<p>I can't work on it now, because the air is soup.</p>
<p>Good night.</p>
Coding 2022-05-222022-05-22T04:00:00-04:002022-05-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-22:/coding-2022-05-22<p class="first last">Some bits of this look a little suspicious, but it should be fine overall.</p>
<p>Ugh, the temperature is spiking and the AC just sort-of works.
Gosh, who could have predicted this?
Besides me.
A week ago.</p>
<p>Let me see what I can do in terms of nailing down the changes to MOTR.</p>
<p>So, <tt class="docutils literal">ParametricCommand.build()</tt> must pass a dict in the form <tt class="docutils literal"><span class="pre">{Label():</span> <span class="pre">ValueAdaptor()}</span></tt>, where... the <tt class="docutils literal">Label</tt> is probably a <tt class="docutils literal">ParameterLabel[PathWith[EnvironmentArgs]]</tt>, and the <tt class="docutils literal">ValueAdaptor</tt> is a <tt class="docutils literal">ValueAdaptor[PathWith[EnvironmentArgs]]</tt>.
<em>I think</em>.
Now, that dict can be trivially derived from a <tt class="docutils literal">ValueAdaptor[PathWith[EnvironmentArgs]]</tt>.
And the <tt class="docutils literal">ValueAdaptor[PathWith[EnvironmentArgs]]</tt> can be created by decorating a <tt class="docutils literal"><span class="pre">Callable[[PathWith[EnvironmentArgs]],</span> PathStr]</tt> with <tt class="docutils literal">@adaptive(LABEL)</tt> where <tt class="docutils literal">LABEL</tt> is a <tt class="docutils literal">ParameterLabel[PathWith[EnvironmentArgs]]</tt>.
Because of the common logic, it probably makes sense to create a factory function that converts labels appropriately.</p>
<p>Now, at the other end of <tt class="docutils literal">ParametricCommand.build()</tt>, I've got a <tt class="docutils literal"><span class="pre">Parametric[CommandBuilder[...]]</span></tt>.
That needs to get properly converted, which can be done by mapping a basic parametric extraction over the relevant label and passing that into the <tt class="docutils literal">requirements</tt> method.</p>
<p>I'm going to get some low-hanging fruit before I go too far.</p>
<p>Got it.
Simple method on <tt class="docutils literal">Parametric</tt> to pull out some redundant code.</p>
<p>Anyway, let's see...
I think this needs some helper functions to create simple <tt class="docutils literal">Parametric</tt> objects given <tt class="docutils literal">Label</tt>s...</p>
<p>Given those helpers, I can map <tt class="docutils literal">CommandBuilder.requirements()</tt> over the <tt class="docutils literal">Parametrics</tt>, and lastly, I need to convert the resulting <tt class="docutils literal">Parametric[Requirements[None]]</tt> to a <tt class="docutils literal">Parametric[None]</tt>, which should be another simple helper function.</p>
<p>There's still more to sketch out, but it's getting late, so I'm going to quickly put out the helper functions that I'm pretty sure I'll need.</p>
<p>Okay, that's done.
The next areas to really focus on are:</p>
<ul class="simple">
<li>Creating the <tt class="docutils literal">ValueAdaptor</tt>s that will be needed for the new interface.</li>
<li>Figuring out what I need to be adding to the <tt class="docutils literal">Registry</tt> objects in the tests.</li>
<li>Actually updating the interface.</li>
</ul>
<p>Hopefully, I'll be thinking a bit clearer tomorrow.
We'll see.</p>
<p>Good night.</p>
Diary 2022-05-212022-05-21T04:00:00-04:002022-05-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-21:/diary-2022-05-21<p class="first last">There is no one available to take your call. Please try again later.</p>
<p>I am in no shape to write tonight.
I need to take things easy.</p>
<p>Good night.</p>
Diary 2022-05-202022-05-20T04:00:00-04:002022-05-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-20:/diary-2022-05-20<p class="first last">Apparently I had a lot of words in me.</p>
<p>Well, I kind of spun my wheels a bit today.
There's supposed to be an idea of a plan of a schedule for getting the AC properly set up, so that's as nice as can be, I guess.</p>
<p>I think I might try sketching out some of the stuff I stuck in the summary two days ago.</p>
<p><a class="reference external" href="https://prokopetz.tumblr.com/post/189138745277/it-kind-of-bothers-me-that-has-procedurally">Relevant background</a>.</p>
<p>Now, I read over that, and I think about Nova Drift, Slay the Spire, Solitairica, and Vampire Survivors.</p>
<p>Technically speaking, that post only half applies to Solitairica, because you don't unlock within-a-run upgrades in Solitairica, so it's "just" really grindy.
Like, come on, I can clear normal mode with a basic deck pretty much at will, apparently.
Just give me the rest of the dang game, please.</p>
<p>Also, the first half of the post doesn't describe Vampire Survivors, since it actually does have fixed maps, so good on it.
Second half is super applicable, though.</p>
<p>I'm sort of thinking of this now because my save files for Nova Drift (which I was playing a few months ago) and Solitairica, which I just picked up recently, didn't survive the laptop migration, so I ground things up in Nova Drift, which is a little annoying, and I ground a little in Solitairica, and that's giving me this weird double sensation of "Oh, the flow!" and "Please just let me have all characters, six slots, and all power cards, this is <em>busywork</em>".</p>
<p>Having established that I'm complaining, I'll now think about why these games might be like this.
I think the draw of these games lies in part in the combination of "bite-sized play times" with "long-term progression".
So, you're not signed up to anything that requires long-term investment or understanding, and you can just knock out a play session, potentially in an afternoon or so, but you're still making progress every time you do.</p>
<p>So, <em>assuming I'm right about this being the reason for stapling together RPG progression and roguelite runs</em>, is there a way to do this that I'd prefer?</p>
<p>Now, "not having the whole game" bothers me from a gameplay perspective, but there's kind of a symbolic issue here: When we upgrade things between runs, what are we playing as?
We get some experience points or make some purchases, and somehow this... changes the options available to the <em>brand new</em> iteration of the character in the next run?
Like, I'm making persistent progress, but I also have to re-buy all the potions and such that I want each time.
Something that occurred to me as a flavoring possibility for these "per-run" upgrades is tactical modifications to the area the run takes place in.
Like, you can set up traps and trip-wires or whatever, and when you move on to the next area, you don't get back the stuff that you deployed, because you used it.</p>
<p>Let's see how this idea interacts with the points in the linked post.</p>
<p>First off, I'm assuming that this is presented as a vaguely RPG-ish with very forgiving death mechanics by roguelike standards, in order to maintain the "bitesized run" concept.
You have save files, each save file has a series of cleared zones, you advance by clearing a zone, which takes no more than a few hours, and if you die, it punts you back to the beginning of the zone.</p>
<p>"B-but permadeath!"
"There's no way for dying to gum up your meta-progression in these games, so something's clearly off-kilter anyway."</p>
<p>Each zone starts with a shop that has a random inventory of tools for helping you clear the zone.
Clearing the zone in certain ways can give you bonuses of some kind.</p>
<p>So, you've got a save file, the character is advancing in ways gated by the random shop inventory, I don't have strong thoughts about the zones, but it's a better decision to design a bunch of "levels that work" than to try to work out the principles for good level design from nothing and program them into the game, (if I want proc-gen for levels later, it will help to have examples), and the part about optimization vs crazy runs has me thinking of something else...</p>
<p>Suppose the kinds of items available from the shops were tied to some kind of "chaos meter" like from Mythic, where low chaos made it easier to obtain lower-tier and reliable items, while high chaos made available items "swingier" in various ways.
Then, player conduct could influence the chaos meter up and down, to try and tailor the overall experience to match the play style.
I don't know if this is a good idea, but it's an idea, to be sure.</p>
<p>Anyway, I'm really tired, so I'm wrapping things up for now.</p>
<p>Good night.</p>
Diary 2022-05-192022-05-19T04:00:00-04:002022-05-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-19:/diary-2022-05-19<p class="first last">Getting some good zingers out of this situation, at least.</p>
<p>Uuuuugh.
Didn't really manage to focus on anything today.
I wrote <em>a little</em>.</p>
<p>I think I was in a funk because I'm having trouble getting building management to acknowledge that, hey, they should probably schedule that yearly maintenance that the AC here seems to need, <em>before</em> the weather turns completely intolerable this weekend.</p>
<p>Call me pedantic if you must, but I don't think the AC should be blowing air above room temperature.</p>
<p>Watch this space to see how angry I am in the third entry after this one.</p>
<p>Anyway, I let things get late, and the only thing to do now, really, is to get to bed.</p>
<p>Good night.</p>
Diary 2022-05-182022-05-18T04:00:00-04:002022-05-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-18:/diary-2022-05-18<p class="first last">I've got a rant in me for sometime about games that go "Hey, let's have long-term progression like an RPG, but it's more of a checklist to determine what you have access to in otherwise isolated runs, like a roguelite." I am begging you, pick a lane.</p>
<p>Gaaaaames...
And writing that I won't describe here.</p>
<p>"Let's see if I can spin up something in fifteen minutes or so." is the first thing that occurred to me writing that sentence, and also a <em>terrible</em> idea.</p>
<p>For now, let's just quick review the writing I'm trying to focus on.
I've got concepts for nine characters currently, but they're not very well-defined beyond skillsets.
I think for each character I'm going to want to work out:</p>
<ul class="simple">
<li>Background, including connections to off-screen characters</li>
<li>Appearance</li>
<li>Associated genre, including stories to read for reference.</li>
</ul>
<p>Once that's filled in a bit, I think I should work on outlining.</p>
<p>For now, though, I'm very tired and I should get ready for bed.</p>
<p>Good night.</p>
Weekly Roundup 2022-05-172022-05-17T04:00:00-04:002022-05-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-17:/weekly-roundup-2022-05-17<p class="first last">Got caught off-guard by the heat.</p>
<ul class="simple">
<li>Wednesday: I worked on MOTR because I wanted to unwind some.</li>
<li>Thursday: I made a small amount of progress on writing.</li>
<li>Friday: VIDYAGAMES and a headache.</li>
<li>Saturday: I did some planning for working on MOTR, and had a feeling I was missing something. This turned out to be foreshadowing.</li>
<li>Sunday: I wasn't up for doing much work before I published the post, but I got a bit done afterwards...</li>
<li>Monday: And, thinking it over, realized that the code needed another minor rewrite, which I started sketching out a plan for.</li>
</ul>
<p>Next week, I want to take some notes about that rewrite, and get more prose writing done.</p>
Coding 2022-05-162022-05-16T04:00:00-04:002022-05-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-16:/coding-2022-05-16<p class="first last">I'm kind of curious how intensely frustrating this code would be for anyone else to work with. Some of my process here has felt like how, if I'm not being careful when I do math on paper, the work ends up flowing in essentially random directions that only I can follow.</p>
<p>Okay, after the last entry, I drafted out a test using the not-yet-written modules that will be needed.
Some of it will need to be updated to match the interfaces, but first, there's something pretty serious that I need to work on.</p>
<p>Recently-ish, I was having trouble accounting for the different Python versions that will be used by the various commands.
At the time, I punted on them, by pulling them out of some of the higher-level data structures, and making them a parameter to the <tt class="docutils literal">map</tt> method.</p>
<p>As has been kind of a recurring thing, I'd forgotten part of the design goals.
The choice of interpreter is supposed to be recapitulated by the <tt class="docutils literal">FlexIn</tt> object, which means it has to be stored under a <tt class="docutils literal">ParametricLabel[PathWith[VirtualenvArgs]]</tt> in the <tt class="docutils literal">Registry</tt>.
I didn't work on this earlier today, but let's see if I can put together a quick sketch of what this would entail, in the next fifteen minutes or so.</p>
<p>Right now, the data is injected like so: <tt class="docutils literal">lambda command: command.requirements(python)</tt>.
After the changes, that site is going to look like <tt class="docutils literal">lambda command: command.requirements()</tt> (or potentially just passing the unbound method).
An additional line will need to be added to get the relevant data into the registry.</p>
<p>So, let's have a look at the <tt class="docutils literal">requirements()</tt> method...</p>
<p>Hm.
I'm not seeing a way to dramatically change this part of the code.
I think I need to look into the <tt class="docutils literal">ParametricCommand</tt> class.
That's where I <em>thought</em> this stuff was supposed to live, I think.
That's the level of code that handles injecting information into the <tt class="docutils literal">Flex</tt> objects, so let's see...</p>
<p>One possible way in is a pre-processing step in <tt class="docutils literal">ParametricCommand.build()</tt>.
Let's see where that's called from...</p>
<p><tt class="docutils literal">python_helpers.CommandBuilder.parametric()</tt>
From an API perspective, this looks like an excellent place to add an argument for this purpose.
Now, it's just a question of figuring out what that argument looks like...</p>
<p>So, here's what I've got:</p>
<ul class="simple">
<li><tt class="docutils literal">ParametricCommand.build()</tt> gets some kind of new argument, and takes on responsibilities to code that argument so <tt class="docutils literal">ParametricCommand._build()</tt> can use it, and process the result of <tt class="docutils literal">ParametricCommand._build()</tt> so that the outer function now directly handles the <tt class="docutils literal">requirements()</tt> call.</li>
<li><tt class="docutils literal">Parametric.map()</tt> gets trimmed down and renamed.</li>
<li><tt class="docutils literal">python_helpers.CommandBuilder.parametric()</tt> gets a new argument.</li>
</ul>
<p>I'm not done sketching this out, but I think I'm done for the night.
I want to try and cool off.</p>
<p>Good night.</p>
Coding 2022-05-152022-05-15T04:00:00-04:002022-05-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-15:/coding-2022-05-15<p class="first last">The sun is a deadly laser.</p>
<p>I'm kind of stuck taking things easy until the AC gets set up or the heat breaks.
The heat's going to <em>kind of</em> do that over some of the next few days, so I should be good as long as the AC is working before next Saturday.</p>
<p>For now, I've done some of the preparatory re-organization for the Mypy testing.
I think I'd like to post now, and see if I'm up for more work after.</p>
<p>Good night.</p>
Coding 2022-05-142022-05-14T04:00:00-04:002022-05-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-14:/coding-2022-05-14<p class="first last">Remembering that "Oh, yeah! I implemented all of that stuff for a <em>reason</em>."</p>
<p>Okay, I did a little work on writing, but not much.
I need the air to be less harsh before I can really focus.</p>
<p>For now, I want to make plans for testing the Mypy wrapper.</p>
<p>So, Mypy is the next logical step, because it has xUnit output, so there are additional post-processing steps.
The things that need to be linked up are:</p>
<ul class="simple">
<li>Run mypy, create coverage report and xUnit file</li>
<li>Merge all xUnit files</li>
<li>Convert merged file to HTML</li>
</ul>
<p>Parts of the command line wrapper should include:</p>
<ul class="simple">
<li>The base command</li>
<li>HTML report output option</li>
<li>XML report output option</li>
<li>Source directory (should be same logic as flake8)</li>
</ul>
<p>Looking over the relevant code, I wonder if the definition of <tt class="docutils literal">FlexOut</tt> should be tweaked so it creates its own labels without them being passed in.
That seems reasonable to me.</p>
<p>Then, we get into the combination.
This needs:</p>
<ul class="simple">
<li>The base command</li>
<li>A function to convert from a <tt class="docutils literal">FlexIn</tt> to an <tt class="docutils literal">Arg</tt></li>
<li>Output option</li>
</ul>
<p>Then, converting to html:</p>
<ul class="simple">
<li>The base command</li>
<li>Input option (should take an input path argument)</li>
<li>Output option</li>
</ul>
<p>It'll be interesting to see what weird oversights are lurking in the code, because I think most of this should be straightforward, and that makes me feel like I'm missing something.</p>
<p>Anyway, I'm not awake for much longer, so I'll wrap this here.</p>
<p>Good night.</p>
Diary 2022-05-132022-05-13T04:00:00-04:002022-05-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-13:/diary-2022-05-13<p class="first last">"Oh well."</p>
<p>Any plans to do anything with my projects today were sacrificed on the twin altars of "My head kind of hurts" and "Just one more game".</p>
<p>So, um, this is late, and I'm pushing it out as fast as I can.
Oh well.</p>
<p>Good night.</p>
Diary 2022-05-122022-05-12T04:00:00-04:002022-05-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-12:/diary-2022-05-12<p class="first last">I hope these names grow on me. I don't want to get caught up tinkering with them.</p>
<p>I ended up doing other stuff and vegging out today, but I did have time to name all of the characters.
After using the technique of "generate random words and derive puns or references from them" to make names, a whole bunch, I wonder if these names need some tweaking.
But for now, I'm going to forge ahead.</p>
<p>And by "forge ahead now" I mean "Try to work on sketching out these characters in more detail, <em>tomorrow</em>", because I am really tired and I want to lie down.</p>
<p>Good night.</p>
Coding 2022-05-112022-05-11T04:00:00-04:002022-05-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-11:/coding-2022-05-11<p class="first last">Awkward category switch mid-post, oh well.</p>
<p>I had a rough couple of days, so I finished the basics of the planned renames to blow off steam.
This was a little bit of a double-edged sword, because it turns out getting the renames done was <em>a lot</em> of typing, and I was trying to do it <em>fast</em>, so my hands feel mildly weird after all of that.</p>
<p>Anyway, I'm going to let that sit and come back to it on the weekend.
I think I'll work on writing tests, unless something else comes up.</p>
<p>Anyway, thinking about writing.
I'm not in the best shape right now for ~*~creativity~*~, but I can put together some plans, some stuff to fill in.</p>
<p>For the setting I'm focusing on, one way to sum it up is that a small group of people with very different fields of expertise are gearing up to fight off an alien invasion.
So, I want to come up with a few different areas of expertise.
So far I've got:</p>
<ul class="simple">
<li>"The leader", who focuses on administration and recruitment, and <em>probably</em> won't be a viewpoint character.</li>
<li>"The investigator", who is there to solve mysteries.
There will be some opportunity for normal crimes mysteries, but I want the focus to be on stuff like "what could have been the purpose of this weird artifact?"</li>
<li>"The technologist", who does general-purpose repair and development.
The focus there is on "how can we use this new alien thing, or fix this weird problem that showed up in the alien thing that we're already using?"</li>
</ul>
<p>Here are some roles that, on reflection, seem like <em>kind of good ideas</em>:</p>
<ul class="simple">
<li>Farmer/general life support</li>
<li>Military experience seems really really important in the context of <em>fighting a war</em></li>
<li>Theft/infiltration, maybe?</li>
<li>Propaganda/persuasion.
This <em>will</em> come up with the direction I want to take things.</li>
</ul>
<p>I think I'll call things there for now, and try and flesh this out and see what else I feel like is missing later.</p>
<p>For now, I want to unwind properly.</p>
<p>Good night.</p>
Weekly Roundup 2022-05-102022-05-10T04:00:00-04:002022-05-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-10:/weekly-roundup-2022-05-10<p class="first last">I wanted to take some time today to continue the renames, but I had to stare into infinity <em>very quickly</em>.</p>
<ul class="simple">
<li>Wednesday: I made some progress on writing stuff.</li>
<li>Thursday: I thought about where I want to take this writing, and spitballed some ideas for conlang tooling.</li>
<li>Friday: I put together some ideas for representing glosses for conlanging, in a form that's easier to edit than writing a giant table manually.</li>
<li>Saturday: I started to draft out the grammar, using those ideas.</li>
<li>Sunday: I came up with new and hopefully better names for some, but not all, of the higher-level API concepts in MOTR.</li>
<li>Monday: I started on the renames.</li>
</ul>
<p>Next week, I'll try to get more stuff done with writing.
I don't know how much I'll be up for, because something got me <em>painfully</em> keyed up today, and I don't know how much I'll be capable of if that keeps up.</p>
Coding 2022-05-092022-05-09T04:00:00-04:002022-05-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-09:/coding-2022-05-09<p class="first last">Renaming modules is a necessary evil.</p>
<p>And, traveled again.
I don't know if I'll manage all of the changes that I came up with, but I'd like to get started.</p>
<p>So...</p>
<p>I handled the first two I wrote up, but I know that updating <tt class="docutils literal">Dynamic</tt> to <tt class="docutils literal">Parametric</tt> is going to be a really big change.
I think it's better to cut things short for now, and come back to this later when I have more time.</p>
<p>Good night.</p>
Coding 2022-05-082022-05-08T04:00:00-04:002022-05-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-08:/coding-2022-05-08<p class="first last">Hindsight is... not quite 20/20, but close enough.</p>
<p>Okay, traveled today, but I still want to try and do the work I had planned for MOTR, which was to...</p>
<p>Oh no.</p>
<p>It was to evaluate all of the ill-fitting names in the upper layers of the API and try to come up with better alternatives.</p>
<p>All right, let's work through these modules alphabetically...</p>
<ul class="simple">
<li><tt class="docutils literal">arguments.py</tt>: Rename to <tt class="docutils literal">command_builder.py</tt>, see how it treats me from there.
Could stick <tt class="docutils literal">Builder</tt> on the end?</li>
<li><tt class="docutils literal">command.py</tt>: Oof, not really sure.
Also, this module contains one of the <tt class="docutils literal">*Meta</tt> classes, which really need something nicer.
I mean, maybe just renaming all of those classes to <tt class="docutils literal">Metadata</tt> would help things?</li>
<li><tt class="docutils literal">dynamic.py</tt>: Ooooof.
Another <tt class="docutils literal">*Meta</tt>, that one should just get whatever treatment the others get.
The bigger puzzle is <tt class="docutils literal">Dynamic</tt> itself.
Like, <tt class="docutils literal">Dynamic</tt> is a <em>pretty questionable</em> name for a concept in this context.
What is it?
Well, it combines a bunch of metadata with a function that has a particular signature; and this lets it...
Um...
<tt class="docutils literal">ThisIsUsefulISwear</tt>.
Okay, stepping back for a sec.
The <em>point</em> is to call the function with every valid combination of parameters.
So the various names involved should say <em>something</em> about parameters.
Let's try and consider <tt class="docutils literal">Dynamic</tt>, <tt class="docutils literal">Objects</tt>, and <tt class="docutils literal">Items</tt> together, and oof.
Now, whatever <tt class="docutils literal">Objects</tt> is, it's agnostic to all of this parameterization <em>stuff</em>, so it might deserve to get the <tt class="docutils literal">Registry</tt> name back.
<tt class="docutils literal">Items</tt> can be <tt class="docutils literal">ParameterRegistry</tt> if I don't think of something better.
(And <tt class="docutils literal">ItemLabel</tt> turns into <tt class="docutils literal">ParameterLabel</tt>.)
And <tt class="docutils literal">Dynamic</tt> can change to <tt class="docutils literal">Parametric</tt>, or something better.
The helper methods should mention <tt class="docutils literal">parametric</tt>.
<tt class="docutils literal">inject_into_parametric</tt>, <tt class="docutils literal">map_1_over_parametric</tt>, <tt class="docutils literal">map_2_over_parametric</tt>, <tt class="docutils literal">NoParameters</tt>, <tt class="docutils literal">no_parameters</tt>, <tt class="docutils literal">reduce_parameterization</tt>...</li>
<li>I can't <em>tell</em> whether the <tt class="docutils literal">flex.py</tt> names are good or not, so let's put a pin in those...</li>
<li>Something feels off with the <tt class="docutils literal">input_accumulator.py</tt> stuff (like that the core type is accumulating specifically into a <tt class="docutils literal">_cmd.PathStr</tt>, and using adaptors to make types of other values work with that, but I'm again not sure what to do differently.</li>
<li><tt class="docutils literal">installer.py</tt> feels like maybe I want to divide it up.
Before I changed the code to make the new tests... work... this module had much fewer classes in it.</li>
<li><tt class="docutils literal">invocation.py</tt> is confounding because somehow I've written <em>another</em> command builder, and it doesn't <em>replace</em> the others, it just builds on them, with an interface that is "nicer" in some sense that I'm not sure how to quantify.
I guess the point is that this bridges the <tt class="docutils literal">command</tt> stuff and the <tt class="docutils literal">dynamic</tt>/<tt class="docutils literal">parametric</tt> stuff, like a kind of... <tt class="docutils literal">ParametricCommand</tt>.
That's definitely clearer, in that you can look at it and mentally break it down into the questions of "what does 'parametric' mean?" and "what is a 'command'?".</li>
<li><tt class="docutils literal">items.py</tt>: the "Item-to-Parameter" change should handle all of this.</li>
<li><tt class="docutils literal">objects.py</tt>: the "Objects-to-Registry" change should handle it.</li>
</ul>
<p>Also, for those last two, and maybe some others, I want to roll the "use <tt class="docutils literal">TypedMapping</tt>" change out so I don't have to worry about code drifting out of synch.</p>
<p>So, I'll think this over in the morning or next week, and see what I think.
For now, I really want to wrap things up.</p>
<p>Good night.</p>
Diary 2022-05-072022-05-07T04:00:00-04:002022-05-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-07:/diary-2022-05-07<p class="first last">Situation: I have notes in 5 different places. "I know! I'll copy them all into one unified location!" Situation: I have notes in 6 different places.</p>
<p>I didn't get as much done as I'd like today, but I translated some of my notes on conlanging into the format I was roughing out yesterday.
I think I found some issues with one of the sentences, so I'll need to come back to it.
Probably the course of action that makes the most sense is to consolidate all of my notes into a single repo, making sure to note anything that needs to be reworked.
Before I copy in more glosses, I need to review the things I can do with custom directives, and see if I want to change anything about the processing.</p>
<p>Anyway, I didn't get much done today because I'm way out of it, so I'm not going to try to drag this out any further.</p>
<p>Good night.</p>
Coding 2022-05-062022-05-06T04:00:00-04:002022-05-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-06:/coding-2022-05-06<p class="first last">Searching for Minimum Viability.</p>
<p>For the stuff in the last coding entry, I worked out some stuff with Hatchling.
I'm really not confident I'm planning to use it as intended, but, like, whatever.</p>
<p>For this entry, I'm not touching that, or MOTR.
Instead, I'm doing a little sketching of stuff for conlanging.
Basically, I'm trying to figure out the right way to support glosses.</p>
<p>To start with, I'm thinking about Sphinx, and figuring I'll go for something like this:</p>
<pre class="literal-block">
:word:`gloss()-SG-gloss(stem)`
.. gloss:: Free translation.
- `gloss(stem)`
- `gloss(stem)-AFF`
- etc
</pre>
<p>Where the <tt class="docutils literal">:word:</tt> role has a parser to convert the given minilanguage into helpful Python objects that then get rendered in various ways, and the <tt class="docutils literal">.. gloss::</tt> directive performs further validation.
Specifically, that either all of the roots are filled in, or none of them are.</p>
<p>With these ideas and simple dummy implementations, I should be able to get started writing up glosses under source control, in a format that doesn't involve overmuch tedious fiddling with control characters, or manually aligning things.</p>
<p>Anyway, I'm still feeling iffy (it might be the pollen) so I'm going to get to bed now.</p>
<p>Good night.</p>
Diary 2022-05-052022-05-05T04:00:00-04:002022-05-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-05:/diary-2022-05-05<p class="first last">I almost wonder if "too humid" and "not humid enough" <em>overlap</em>...</p>
<p>I wasn't terribly focused today.
There's something weird and gross in the air; it might just be heat and humidity.</p>
<p>I took a few more notes for writing.
I'm fired up about this concept now that I want to do some kind of like... goal-directed outlining.
My mental image of how it would be presented is, like, a series of short stories that could, conceptually, be grouped into volumes.
So, I should be able to iterate on process in a somewhat straightforward fashion, once I have the focus to really get into this.</p>
<p>I also tried to sort things out when it comes to conlanging, and it kind of feels like I've somehow circled around in terms of tooling.
Like "It sure would be nice to have a table format that works well with version control, so I guess that needs to be some kind of text, but I <em>know</em> I hated laying out these tables in ReStructuredText, so I guess I want to represent them in Python somehow, so I guess I <em>do</em> need a representation of at least the glosses..."</p>
<p>I'm fine putting that together at some point, but I want some idea of how I'll get the data back <em>out</em>.
I'm sort of wondering if there's some way to pull data from a Jupyter notebook into Sphinx...</p>
<p>Anyway, I'm done for tonight.
I can't be up much longer.</p>
<p>Good night.</p>
Diary 2022-05-042022-05-04T04:00:00-04:002022-05-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-04:/diary-2022-05-04<p class="first last">I guess I'm going to have to explain these writing hacks some time.</p>
<p>Let's see about doing some quick writing.
I've got these sci-fi settings I'm interested in.
Let's see about fleshing out my notes a bit more.</p>
<p>...</p>
<p>Dang, that was quick but effective in moving things in a direction that interests me.</p>
<p>If the techniques I'm messing with can get me results this quickly, I think that means I should set myself some goals for "what needs to be decided before I start drafting", and then get to it.</p>
<p>Anyway, I'm going to wrap up for now.</p>
<p>Good night.</p>
Weekly Roundup 2022-05-032022-05-03T04:00:00-04:002022-05-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-03:/weekly-roundup-2022-05-03<p class="first last">Not great summaries this time, but whatever.</p>
<ul class="simple">
<li>Wednesday: I had more problems than usual with technology.</li>
<li>Thursday: I tinkered with code that could potentially help with some stuff I want to try out.</li>
<li>Friday: I messed around with other code, then worked on story concepts and got those somewhere interesting.</li>
<li>Saturday: I, um, relaxed.</li>
<li>Sunday: I cleaned up MOTR's test code a little, and took some notes on how to improve the interfaces.</li>
<li>Monday: I acted on those notes, and decided on the next thing that needs work: the dang names.</li>
</ul>
<p>Next week, I'm going to try to focus on writing more.</p>
<p>Also, I was messing with mypycify earlier today, and I'm still having trouble finding a sweetspot of "easy to configure", "allows using mypyc", and "can turn mypyc <em>off</em> to create a pure python wheel".
I'll try not to focus on that too hard, because I'll probably be most interested in it once MOTR is in better shape.</p>
Coding 2022-05-022022-05-02T04:00:00-04:002022-05-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-02:/coding-2022-05-02<p class="first last">Maybe I should look into using Hatchling instead.</p>
<p>I got a bit distracted earlier today learning about using <a class="reference external" href="https://mypyc.readthedocs.io/en/latest/getting_started.html">mypycify</a>.
I managed to get it working with setup.py, but I kind of don't want to deal with setup.py files.
I tried to get it working with <a class="reference external" href="https://github.com/dholth/enscons">enscons</a>, but I didn't find anything that seemed to work out of the box, so I'm going to have to learn more about setting stuff up with SCons.
Or suck it up and write a setup.py when I want to mess with mypyc.
Eeeennh.</p>
<p>Anyway, let's shelve that for now and see about improving my test code over in MOTR.
But first, <a class="reference external" href="https://im-in.space/@mwchase/108229848686430527">thread</a>.</p>
<p>Okay, just did the easy quick one.
That looks like:</p>
<div class="highlight"><pre><span></span><span class="nd">@pytest</span><span class="o">.</span><span class="n">fixture</span><span class="p">(</span><span class="n">scope</span><span class="o">=</span><span class="s2">"session"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">make_changes</span><span class="p">(</span><span class="n">api</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Create a factory function for making requirements generators.</span>
<span class="sd"> The motivation for this was, admittedly, mostly to get rid of a coverage</span>
<span class="sd"> miss.</span>
<span class="sd"> """</span>
<span class="k">def</span> <span class="nf">make</span><span class="p">(</span><span class="n">python</span><span class="p">,</span> <span class="n">dynamic</span><span class="p">,</span> <span class="n">package_data</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">changes</span><span class="p">():</span>
<span class="n">objects</span> <span class="o">=</span> <span class="k">yield from</span> <span class="n">api</span><span class="o">.</span><span class="n">cli</span><span class="o">.</span><span class="n">build</span><span class="o">.</span><span class="n">build</span><span class="p">(</span><span class="n">package_data</span><span class="p">)</span>
<span class="k">yield from</span> <span class="n">dynamic</span><span class="o">.</span><span class="n">map</span><span class="p">(</span>
<span class="k">lambda</span> <span class="n">command</span><span class="p">:</span> <span class="n">command</span><span class="o">.</span><span class="n">requirements</span><span class="p">(</span><span class="n">python</span><span class="p">),</span> <span class="n">objects</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">changes</span>
<span class="k">return</span> <span class="n">make</span>
</pre></div>
<p>Now for the other one.</p>
<p>Okay, that's done-ish, but I don't want to copy a snippet to show off, because the changes are spread across three different files.</p>
<p>Basically, I made a helper class that bundles up a bunch of common operations to reduce the amount of irrelevant details exposed via the API.</p>
<p>Anyway, the code is more concise, but the bad names are starting to really grate on me, so that's what I want to focus on next.</p>
<p>For now, I'd better get ready for bed.</p>
<p>Good night.</p>
Coding 2022-05-012022-05-01T04:00:00-04:002022-05-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-05-01:/coding-2022-05-01<p class="first last">Incremental progress, and setting up for future work.</p>
<p>All right, how did things go today?
Well, I did a bit of work with error cases, then cleaned up some of the parameter id stuff so that the test names aren't excessively long.
Now, I'm looking back at the coverage data.</p>
<p>It looks like the major avenues I can take are to focus on error cases, or on expected cases.
The issue with the expected cases is that doing that is going to require writing more code to work with the external interface.
(Under the logic that it makes sense to not know how to hit the error cases given reasonable input, but that expected cases should focus on the external interfaces when possible.)
But that means looking at the existing tests and figuring out what kinds of rewrites they need.</p>
<p>Let's see if I can find anything promising in the error cases to knock out quickly.</p>
<p>Mmm, there's just so much that would do better given high-level tests, so let's see what shortcomings I can identify in the flake8 tests...</p>
<ul class="simple">
<li>Need to explicitly call <tt class="docutils literal">pyrsistent.v</tt></li>
<li>Need to explicitly retrieve <tt class="docutils literal">Invocation</tt> class</li>
<li>Need to combine <tt class="docutils literal">flake8.BASE</tt> with compatible <tt class="docutils literal">Static[Option]</tt> objects</li>
<li>Need to explicitly call <tt class="docutils literal">invoke()</tt></li>
</ul>
<p>If I can write a helper class that addresses those issues, I'll be able to rewrite the flake8 tests to look nicer, and I'll feel comfortable writing tests for, say, mypy, which should shake out a lot of the issues with the tests.
The other issue I can see with the tests could be addressed by writing some helper functions/classes to factor out common test code.</p>
<p>I'll try to get on these ideas tomorrow.
For now, I want to get ready for bed.</p>
<p>Good night.</p>
Diary 2022-04-302022-04-30T04:00:00-04:002022-04-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-30:/diary-2022-04-30<p class="first last">Extremely relaxed.</p>
<p>Well, I didn't really get much done today.
I was kind of focused on taking things easy, and now I'm really out of it.</p>
<p>I seriously can't think of anything to say, so I should call this here, such as it is, and assume that I'll be up for much more tomorrow.</p>
<p>Good night.</p>
Diary 2022-04-292022-04-29T04:00:00-04:002022-04-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-29:/diary-2022-04-29<p class="first last">Trying to have agency over how I feel when I wake up in the morning.</p>
<p>Time management is still in an eeeeeh kind of place, but I can work on that right now thus:</p>
<p>I messed a tiny bit with MOTR today, because I idly ran the tests to get an idea of the behavior (the typing tests seem to be doing some kind of painful things to the overall execution time), and I discovered that, since I last ran them, it seems like Mypy got some new behavior?
Whatever, it was a bunch of quick fixes.</p>
<p>Anyway, I also made sure to focus a little on writing.
I filled in the general outline I came up with for one of my story concepts, and got it from "making fun of part of the concept of a specific other story" to "other things are going on that set it apart enough that it's not 'obviously just' any particular thing", at least, not that I know of.</p>
<p>So, I'm happy with that, and now I want to make sure I have plenty of time to wind down, so I'm going to publish this.</p>
<p>Good night.</p>
Diary 2022-04-282022-04-28T04:00:00-04:002022-04-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-28:/diary-2022-04-28<p class="first last">Time management slipping a little. Oh well.</p>
<p>No writing done today.
I got python/jvm interop working just well enough to convince myself that I should be trying literally anything else when it comes to working on tooling in the short term.</p>
<p>I've got a limited amount of time, so I think I'll spend it doing outline/background work for some of my story ideas.</p>
<p>Okay, I've done that.
More to do, but it definitely clarified some choices that I needed clarified.</p>
<p>I don't want to procrastinate too much on getting to bed, so I'm going to wrap this up as quickly as I can.</p>
<p>Good night.</p>
Diary 2022-04-272022-04-27T04:00:00-04:002022-04-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-27:/diary-2022-04-27<p class="first last">This post brought to you in part by reading a bunch of documentation <em>that really could have been clearer</em>.</p>
<p>Hahaha, I thought I was done with the work stuff.
Oh well, at least I don't have to look for stuff to do while I'm slogging through this.</p>
<p>Anyway, I didn't do much today, I don't think, so, status update on stuff I was talking about last time...
Entering this data into a spreadsheet was annoying, because the spreadsheet</p>
<p>Insisted on treating the cell contents</p>
<p>As sentences</p>
<p>Sure.</p>
<p>And I lost like ten, twenty minutes to write this post because I managed to freeze my laptop opening the relevant options dialog in LibreOffice too many times because it didn't open at first.
And then I had to remember how to restore the file, because neovim doesn't seem to handle it well.
I swear tech usually treats me better.</p>
<p>Anyway, my experience there inspired me to plan out ways to handle this stuff in code.
I've got some preliminary notes that could be used to handle sound changes myself, but I'd rather come up with some kind of interface around Lexurgy.
I think I'd like to use it as a library, but failing that, I can either generate data for it, or hardcode a lot of the interactions and parse stuff out of the output.</p>
<p>So, maybe that'll be what I look into at some point: do Python 3/JVM interop options work for this?</p>
<p>Anyway, it's late and I've got a busy morning tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2022-04-262022-04-26T04:00:00-04:002022-04-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-26:/weekly-roundup-2022-04-26<p class="first last">Stuff is being accomplished that I'm not sure how to summarize.</p>
<ul class="simple">
<li>Wednesday: I futzed around with various writing-related things.</li>
<li>Thursday: I complained about how work was going.</li>
<li>Friday: I started planning how to "worse-is-better" my tools for working on conlangs.</li>
<li>Saturday: I messed around with MOTR, and decided to put in what seemed like the least effort required to get the test to pass while still doing <em>something</em>.</li>
<li>Sunday: That did not feel like the least effort.</li>
<li>Monday: I wrote up every coverage miss in MOTR's testing.</li>
</ul>
<p>Next week, I want to make more progress in either editing, story planning, or conlanging.
In the near term, I need to take a break from MOTR, because those last few days were a lot.</p>
Coding 2022-04-252022-04-25T04:00:00-04:002022-04-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-25:/coding-2022-04-25<p class="first last">A full accounting of all of the code that is potentially broken.</p>
<p>No thread again.
I focused on writing up all of the cases missing for coverage, and my notes ended up something like:</p>
<blockquote>
<p>Misc:</p>
<ul class="simple">
<li>Missing branch in plugin code</li>
<li><tt class="docutils literal">pytest.testdir_builder</tt> (just write a test)</li>
<li><tt class="docutils literal">package.combine_packages</tt> (empty, and multiple)</li>
<li><tt class="docutils literal">pip.package</tt> (leading dash)</li>
<li><tt class="docutils literal">pip.python_version_string</tt> (absolute path, multi-part path, valid input)</li>
<li><tt class="docutils literal">dynamic.inject</tt> normal and error case</li>
<li><tt class="docutils literal">dynamic.reduce</tt></li>
</ul>
<p>Validators:</p>
<ul class="simple">
<li><tt class="docutils literal">input_accumulator.accumulator</tt> decorator</li>
<li><tt class="docutils literal">installer.PathWith</tt></li>
<li><tt class="docutils literal">not_output</tt> cases for:<ul>
<li><tt class="docutils literal">Output</tt></li>
<li><tt class="docutils literal">CmdMeta</tt> with env</li>
<li><tt class="docutils literal">CmdMeta</tt> with extra io</li>
<li><tt class="docutils literal">Command</tt></li>
</ul>
</li>
<li><tt class="docutils literal">dynamic.DynamicMeta</tt></li>
</ul>
<p>Methods:</p>
<ul class="simple">
<li><tt class="docutils literal">python_helpers.PythonCmd.add_sub_cmds</tt></li>
<li><tt class="docutils literal">arguments.Option.with_option</tt></li>
<li><tt class="docutils literal">arguments.Command.with_module</tt> success case</li>
<li><tt class="docutils literal">arguments.Command.with_module</tt> failure case</li>
<li><tt class="docutils literal">validators.RejectBecause.__repr__</tt></li>
<li>(Corresponding <tt class="docutils literal">__call__</tt> should be handled by other cases for now)</li>
<li><tt class="docutils literal">invocation.Argument.build</tt> (with and without prefix)</li>
<li><tt class="docutils literal">invocation.EnvVar.build</tt></li>
<li><tt class="docutils literal">invocation.Invocation.invoke</tt> (module non-<tt class="docutils literal">None</tt>, and another with adaptor conflicts)</li>
<li><tt class="docutils literal">flex.ExtraParent.map</tt></li>
<li><tt class="docutils literal">flex.Argparent.map</tt> (<tt class="docutils literal">prefix</tt> is <tt class="docutils literal">None</tt>)</li>
<li><tt class="docutils literal">flex.FlexIn.convert</tt></li>
<li><tt class="docutils literal">flex.FlexIn.metadata</tt></li>
<li><tt class="docutils literal">flex.FlexIn.forbid_narrowing</tt></li>
<li><tt class="docutils literal">flex.FlexOut.convert</tt> (<tt class="docutils literal">make_parent</tt> is <tt class="docutils literal">None</tt>)</li>
<li><tt class="docutils literal">flex.FlexOut.metadata</tt></li>
<li><tt class="docutils literal">flex.FlexOut.forbid_narrowing</tt></li>
<li><tt class="docutils literal">pip.VirtualenvArgs.setup_environment</tt> (with python version string)</li>
<li><tt class="docutils literal">pip.PipArgs.arguments</tt> (with <tt class="docutils literal">Constraint</tt>, with <tt class="docutils literal">Requirement</tt>)</li>
<li><tt class="docutils literal">command.CmdMeta.resolve_*</tt> with <tt class="docutils literal">Module</tt> arguments and sometimes <tt class="docutils literal">str</tt> arguments</li>
<li><tt class="docutils literal">command.base_cmd</tt></li>
<li><tt class="docutils literal">build.Build.__call__</tt> in various configurations</li>
<li><tt class="docutils literal">dynamic.DynamicMeta.not_accumulable_because</tt> (used as validator elsewhere)</li>
<li><tt class="docutils literal">dynamic.DynamicMeta.not_flex_out_because</tt> (used as validator elsewhere)</li>
<li><tt class="docutils literal">dynamic.DynamicMeta.with_flex</tt> error case</li>
<li><tt class="docutils literal">dynamic.DynamicMeta.narrow_labels</tt> normal and error case</li>
<li><tt class="docutils literal">dynamic.DynamicMeta.combine</tt> same and different value</li>
<li><tt class="docutils literal">dynamic.DynamicMeta.iter_labels</tt> normal and error case</li>
</ul>
<p>Decorators:</p>
<ul class="simple">
<li><tt class="docutils literal">python_helpers.requirement_invocation</tt></li>
</ul>
</blockquote>
<p>For now, some of this overlaps, but in any case, getting the 8% or so (116 statements) coverage this all represents is clearly going to be A Thing, and I'm going to have to take <em>more</em> notes to figure out what the tests for these are going to look like, and therefore what kind of tests I should be writing.</p>
<p>Ugh, I just compared the flake8 tests to the current motrfile.
I really hope the approach I'm pursuing currently pays serious dividends when it comes to invoking pytest, because on the flake8 side of things, it's breaking even at best.
Like, what if the biggest saving here just comes from no longer defining package and builder concepts in the motrfile?
To be clear, that would still be a major win, but I really want to see something more dramatic out of this effort.</p>
<p>Anyway, it won't do to stress out over this.
I need to relax and take a break from staring at my screen.</p>
<p>Good night.</p>
Coding 2022-04-242022-04-24T04:00:00-04:002022-04-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-24:/coding-2022-04-24<p class="first last">So much pain from mixing up "covariant" and "contravariant".</p>
<p>No thread today.
I ended up banging my head against mypy errors pretty much all day.
On the plus side, I got the tests to pass, though there was a certain level of weakening involved.</p>
<p>Anyway, I'm a little worn out from all of that, so I don't know if I'll get back into things tomorrow, but here's what needs to happen next:</p>
<ul class="simple">
<li>Finish up flake8 module coverage.</li>
<li>Catalog remaining coverage misses.</li>
<li>Figure out what I need to address those misses.</li>
<li>Prioritize additional tests.</li>
<li>Write additional tests.</li>
<li>Once I hit 100% coverage, start cleaning up test code (switch a bunch of parameterization stuff to fixtures, mainly, and look into preparing the layout for limit-coverage).</li>
</ul>
<p>I'm feeling a little loopy right now, so I think I'm done for today.</p>
<p>Good night.</p>
Coding 2022-04-232022-04-23T04:00:00-04:002022-04-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-23:/coding-2022-04-23<p class="first last">Best to get this off the ground quickly, but not immediately.</p>
<p>I put together <a class="reference external" href="https://im-in.space/@mwchase/108179024355256729">a quick mastodon thread</a>, but the work isn't done.</p>
<p>I spent a little time thinking about how to do things really elegantly and magically, before deciding that that's not worth it now.
So, the plan is to implement as little as possible, and then revisit my decisions once I've got more complex logic that I want to support.</p>
<p>For now, I'm going to get to bed and try to wake up a bit more refreshed than I have been lately.</p>
<p>Good night.</p>
Diary 2022-04-222022-04-22T04:00:00-04:002022-04-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-22:/diary-2022-04-22<p class="first last">Thinking about conlanging and preparing to commit workflow crimes.</p>
<p>Close-ish to do done with that work stuff.
Anyway.</p>
<p>Right now, my focus is kind of ping-ponging back to conlanging, and my feeling on that is, okay, sure, do what feels good.</p>
<p>Right now, I'm reviewing the kind of stuff I put together for one of my attempts at conlanging, and trying to figure out what kind of tooling I want.
Here's how I'm looking at that:</p>
<ul class="simple">
<li>For the early work on a language, I don't know what works for me, and I need something that obviously-sort-of-works, so I can temporarily avoid thinking about tooling in order to have content.</li>
<li>As I get more done, I want to use that as a guideline for refining tooling, but make sure that whatever tooling I come up with is appropriate for the earlier stages of completion.</li>
</ul>
<p>My basic hunch is that I should be able to get by in the early stages with a mixture of text files and spreadsheets.
The reference grammars I want to put together will look like:</p>
<ul>
<li><p class="first">Introduction:
Plain text.</p>
</li>
<li><p class="first">Phonology:
Some tables, some text explanations.</p>
</li>
<li><p class="first">Morphology:
Some tables, some text explanations.</p>
</li>
<li><p class="first">Derivational morphology:
Some tables, some text explanations.</p>
</li>
<li><p class="first">Syntax:
Text, not sure if tables will come up; I'll need to investigate that.</p>
</li>
<li><p class="first">Semantic fields and pragmatics:
Text, with maybe some minor tables</p>
</li>
<li><p class="first">Writing system:
Text, with maybe some minor tables</p>
</li>
<li><p class="first">Examples:
Maybe some text, focused on tables, and requiring facilities for:</p>
<ul class="simple">
<li>Converting text from a simple-to-type romanization to a more expressive one</li>
<li>Converting text from a simple-to-type romanization to the native writing system</li>
<li>Converting text from a simple-to-type romanization to a phonetic representation</li>
<li>Validating that a gloss is associated with a given root</li>
<li>Validating that a root is realized correctly?</li>
<li>Linking a root to the lexicon</li>
<li>Linking a morphological component to the proper section</li>
<li>If I wanted to make things very "straightforward" for me, I could try to set this up as "provide the intended root along with the intended gloss notation, and derive the other sections"</li>
<li>Have a free translation below all of that.<ul>
<li>Could there be facilities for selecting different writing systems?</li>
</ul>
</li>
</ul>
</li>
<li><p class="first">Lexicon:
Tables, possibly using some of the above facilities.
They should include:</p>
<ul class="simple">
<li>root</li>
<li>part of speech</li>
<li>glosses</li>
</ul>
<p>In addition, my ideal wishlist is to track multiple stages of development and somehow maintain derivational links between roots at different points in the history of the language.</p>
</li>
</ul>
<p>I'm... not sure how much of that can be properly done in Sphinx, like I'm hoping for as an endpoint.
Like, at some point, do the requirements basically force me to be writing a Python file that essentially generates ReST nodes which somehow get awkwardly crowbared in.
I think I wouldn't like that.</p>
<p>In any case, I'm going to start off with, plain text, plus either a spreadsheet, Python code, Lua code, or maybe try to make the tables in SQLite?
I have to admit I feel some sort of weird interest in the idea of throwing away all formatting concerns and just typing stuff in DB Browser, buuuut some of these tables are going to need merged cells, so I can't use <em>just</em> SQLite.
(Although, to be fair, the merged cells are for stuff that wouldn't really fit in a relational database <em>anyway</em>, so...)</p>
<p>Anyway, it's late, as usual, so I should wrap up and get to bed.</p>
<p>Good night.</p>
Diary 2022-04-212022-04-21T04:00:00-04:002022-04-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-21:/diary-2022-04-21<p class="first last">Not going to get beaten down, at least not all the way.</p>
<p>Uuuuuuuuuuugh.
Work has given me some tasks that I am entirely capable of grinding through, but they're <em>awful</em>.
Making progress, but I have to take breaks to rant incoherently.</p>
<p>I'm going to put some information into my personal project management stuff, and publish this post, and see what else I'm up for.</p>
<p>Okay, that was quick, let's see if I can do a <em>little</em> more...</p>
<p>All right, I did a bit more, and I'm glad I did it, and I am <em>done</em> now.</p>
<p>Good night.</p>
Diary 2022-04-202022-04-20T04:00:00-04:002022-04-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-20:/diary-2022-04-20<p class="first last">The editing will continue until morale improves.</p>
<p>Oh boy.
Even the slightest bit of editing is hard work.
I am exhausted just from taking notes on stuff that I'm going to want to change.</p>
<p>I don't have anything else to note about that work, so, um, other stuff...</p>
<p>I recently started noting down ideas based around some idle thoughts I had about potential science fiction settings.
I'm going to try to develop them, because I feel like I care about the ideas enough for them to work as a core for my writing experiments.
They're all kind of about putting different twists on established science fiction concepts, and being overall different degrees of serious.</p>
<p>Anyway, it's getting late and I should get ready for bed.</p>
<p>Good night.</p>
Weekly Roundup 2022-04-192022-04-19T04:00:00-04:002022-04-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-19:/weekly-roundup-2022-04-19<p class="first last">A rough week, but I managed to redeem it.</p>
<ul class="simple">
<li>Wednesday: I got some unlocks in Vampire Survivors, and it was really frustrating because I insisted on playing out the level once I'd gotten them.</li>
<li>Thursday: I was feeling rough, but I went back to one writing project after... a while.</li>
<li>Friday: I was sick, apparently.</li>
<li>Saturday: I wasn't up for writing, but I did a little planning.</li>
<li>Sunday: I shook things up with my format for coding posts. We'll see what I think of it.</li>
<li>Monday: I kept on with the change in format, and refined things a little.</li>
</ul>
<p>Next week, I'm going to start working on editing that writing I've been doing, and, on the weekend, I should have some good work on MOTR teed up.</p>
Coding 2022-04-182022-04-18T04:00:00-04:002022-04-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-18:/coding-2022-04-18<p class="first last">With each passing day, my process for these posts gets slightly better.</p>
<p>All right, that's <a class="reference external" href="https://im-in.space/@mwchase/108149482599320040">another mastodon thread</a> on this.
And here's the code I added and updated tonight.
With this, I should be ready to switch the protocol usages from the old to the new and vet them out, and to update the existing protocol implementations.</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">resolve_path</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">)</span> <span class="o">-></span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">:</span>
<span class="k">return</span> <span class="n">path</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
<span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Environment</span><span class="p">:</span>
<span class="n">root</span><span class="p">:</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span> <span class="o">=</span> <span class="n">attr</span><span class="o">.</span><span class="n">field</span><span class="p">(</span><span class="n">converter</span><span class="o">=</span><span class="n">resolve_path</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">bin</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cmd</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">_io</span><span class="o">.</span><span class="n">Input</span><span class="p">[</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">]:</span>
<span class="k">return</span> <span class="n">_io</span><span class="o">.</span><span class="n">Input</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">root</span> <span class="o">/</span> <span class="s2">"bin"</span> <span class="o">/</span> <span class="n">cmd</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Combinable</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">Protocol</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Protocol for classes whose instances can be combined."""</span>
<span class="k">def</span> <span class="nf">combine</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">TCombinable</span><span class="p">,</span> <span class="n">__other</span><span class="p">:</span> <span class="n">TCombinable</span><span class="p">)</span> <span class="o">-></span> <span class="n">TCombinable</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Combine two instances of the same type."""</span>
<span class="k">class</span> <span class="nc">EnvironmentArgs</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">Protocol</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Protocol for setting up an environment."""</span>
<span class="k">def</span> <span class="nf">setup_environment</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">__root</span><span class="p">:</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">_requirements</span><span class="o">.</span><span class="n">Requirements</span><span class="p">[</span><span class="n">Environment</span><span class="p">]:</span>
<span class="o">...</span>
<span class="k">class</span> <span class="nc">InstallerArgs</span><span class="p">(</span><span class="n">Combinable</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Protocol for installing software in an environment."""</span>
<span class="k">def</span> <span class="nf">resolve</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">environment</span><span class="p">:</span> <span class="n">Environment</span><span class="p">,</span> <span class="n">cmd</span><span class="p">:</span> <span class="nb">str</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">_requirements</span><span class="o">.</span><span class="n">Requirements</span><span class="p">[</span><span class="n">_io</span><span class="o">.</span><span class="n">Input</span><span class="p">[</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">]]:</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">install</span><span class="p">(</span>
<span class="n">env_part</span><span class="p">:</span> <span class="n">PathWith</span><span class="p">[</span><span class="n">EnvironmentArgs</span><span class="p">],</span>
<span class="n">installer_part</span><span class="p">:</span> <span class="n">PathWith</span><span class="p">[</span><span class="n">InstallerArgs</span><span class="p">],</span>
<span class="n">cmd</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">_requirements</span><span class="o">.</span><span class="n">Requirements</span><span class="p">[</span><span class="n">_io</span><span class="o">.</span><span class="n">Input</span><span class="p">[</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">]]:</span>
<span class="n">root</span> <span class="o">=</span> <span class="n">installer_part</span><span class="o">.</span><span class="n">path</span> <span class="o">/</span> <span class="n">env_part</span><span class="o">.</span><span class="n">path</span>
<span class="n">environment</span> <span class="o">=</span> <span class="k">yield from</span> <span class="n">env_part</span><span class="o">.</span><span class="n">val</span><span class="o">.</span><span class="n">setup_environment</span><span class="p">(</span><span class="n">root</span><span class="p">)</span>
<span class="k">return</span> <span class="p">(</span><span class="k">yield from</span> <span class="n">installer_part</span><span class="o">.</span><span class="n">val</span><span class="o">.</span><span class="n">resolve</span><span class="p">(</span><span class="n">environment</span><span class="p">,</span> <span class="n">cmd</span><span class="p">))</span>
<span class="n">TCombinable</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">TypeVar</span><span class="p">(</span><span class="s2">"TCombinable"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="n">Combinable</span><span class="p">)</span>
<span class="o">...</span>
<span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">PathWith</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">Generic</span><span class="p">[</span><span class="n">T_co</span><span class="p">]):</span>
<span class="n">path</span><span class="p">:</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span> <span class="o">=</span> <span class="n">attr</span><span class="o">.</span><span class="n">field</span><span class="p">(</span><span class="n">validator</span><span class="o">=</span><span class="n">_path_is_well_behaved</span><span class="p">)</span>
<span class="n">val</span><span class="p">:</span> <span class="n">T_co</span>
<span class="k">def</span> <span class="nf">combine</span><span class="p">(</span>
<span class="bp">self</span><span class="p">:</span> <span class="n">PathWith</span><span class="p">[</span><span class="n">TCombinable</span><span class="p">],</span> <span class="n">__other</span><span class="p">:</span> <span class="n">PathWith</span><span class="p">[</span><span class="n">TCombinable</span><span class="p">]</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">PathWith</span><span class="p">[</span><span class="n">TCombinable</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Combine two PathWith instances with compatible wrapped values."""</span>
<span class="k">return</span> <span class="n">PathWith</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">path</span> <span class="o">/</span> <span class="n">__other</span><span class="o">.</span><span class="n">path</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">val</span><span class="o">.</span><span class="n">combine</span><span class="p">(</span><span class="n">__other</span><span class="o">.</span><span class="n">val</span><span class="p">)</span>
<span class="p">)</span>
</pre></div>
<p>Let's lay this out.</p>
<p>I wrote a simple wrapper around <tt class="docutils literal">pathlib.Path.resolve</tt> because mypy complained when I used the method itself as a converter.</p>
<p>The convert is used by the <tt class="docutils literal">Environment</tt> class I added to represent the environment that commands are run from.
It has a fairly obvious method there, to create <tt class="docutils literal">Input[Path]</tt> objects from a command name.</p>
<p>Next up, the protocols.
These <em>could</em> end up needing to change when I actually implement them, but they're... probably fine.
I might end up coming up with a sensible <tt class="docutils literal">combine()</tt> implementation for <tt class="docutils literal">EnvironmentArgs</tt> instances, or at least some of them, but I'm just not going to bother for now.</p>
<p>The idea of these bits is to factor out the unique logic of the different protocol implementations, and stick them together with the general flow of "set up environment, then install stuff in environment".
There is one insight that I didn't have the perspective to realize before today:</p>
<p>Just because two parts of the implementation are coupled at the moment, that does not mean that specifying "what one part requires" and "what one part provides" <em>separately</em> is a duplication.
I'm currently expecting both implementations to specify pip <em>independently</em>.
This way, if hypothetical implementations that work off of some other installer are created, then putting together mismatched implementations will fail <em>at configuration time</em>, so the user will get immediate feedback rather than cryptic file-not-found errors.</p>
<p>Lastly, if the wrapped value in a <tt class="docutils literal">PathWith</tt> implements <tt class="docutils literal">Combinable</tt>, then so does the <tt class="docutils literal">PathWith</tt>.
This will be important later.</p>
<p>All right then.
I'm excited to see where this leads me, but right now I'm mostly tired.</p>
<p>Good night.</p>
Coding 2022-04-172022-04-17T04:00:00-04:002022-04-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-17:/coding-2022-04-17<p class="first last">Writing these posts continues to be a great way to improve the code after I thought I was done.</p>
<p>Okay, I'm trying something a bit different, where I had a <a class="reference external" href="https://im-in.space/@mwchase/108144781696953803">short mastodon thread</a> that I was writing as I worked on the code, and I'll start off this post with the end result, and talk about it some.</p>
<div class="highlight"><pre><span></span><span class="nd">@_validators</span><span class="o">.</span><span class="n">RejectBecause</span>
<span class="k">def</span> <span class="nf">_path_is_well_behaved</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterator</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="k">if</span> <span class="n">path</span><span class="o">.</span><span class="n">is_absolute</span><span class="p">():</span>
<span class="k">yield</span> <span class="sa">f</span><span class="s2">"The following path is absolute: </span><span class="si">{</span><span class="n">path</span><span class="si">}</span><span class="s2">"</span>
<span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="n">part</span> <span class="o">==</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">pardir</span> <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">path</span><span class="o">.</span><span class="n">parts</span><span class="p">):</span>
<span class="k">yield</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">"The following path includes parent or current directory parts:"</span>
<span class="sa">f</span><span class="s2">" </span><span class="si">{</span><span class="n">path</span><span class="si">}</span><span class="s2">"</span>
<span class="p">)</span>
<span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">PathWith</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">Generic</span><span class="p">[</span><span class="n">T_co</span><span class="p">]):</span>
<span class="n">path</span><span class="p">:</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span> <span class="o">=</span> <span class="n">attr</span><span class="o">.</span><span class="n">field</span><span class="p">(</span><span class="n">validator</span><span class="o">=</span><span class="n">_path_is_well_behaved</span><span class="p">)</span>
<span class="n">val</span><span class="p">:</span> <span class="n">T_co</span>
</pre></div>
<p>So, first observation: this isn't much code.
This might be from getting used to the different process, but there's also the fact that today was just kind of tiring, even if I did get some good relaxation in.
I'm going to keep this up for now, and hope for better results next weekend.
If that doesn't work out, I'll reconsider things.</p>
<p>So, that out of the way, the next question to ask is, what <em>is</em> most of this?</p>
<p>From the top:</p>
<ul class="simple">
<li>The <tt class="docutils literal">_validators</tt> module is a local helper file I wrote to streamline writing validators for <a class="reference external" href="https://www.attrs.org">attrs</a>.
The <tt class="docutils literal">RejectBecause</tt> class is a decorator that wraps a function that checks a value for reasons <em>not</em> to use it in the validated field.
I'm still feeling things out with naming conventions around it.
In another module, I've got it used in the <tt class="docutils literal">attr.field()</tt> argument instead of as a decorator, so the functions are named by what they return.
Here, it's being used as a decorator, so I named the function after the overall logic of the validator.</li>
<li>The <em>particular</em> function here, <tt class="docutils literal">_path_is_well_behaved</tt>, performs a few checks regarding the paths being associated with values.
The first check is that the path is relative; in fact, it might be relative to an <em>unknown starting point</em>, which is why I didn't use <tt class="docutils literal">Path.resolve()</tt> anywhere in this.
The second check makes sure there are no parts of the path that are parent separators.
This is not robust in the face of symlinks, and frankly, I don't care.</li>
<li>Lastly, <tt class="docutils literal">PathWith[T_co]</tt> is going to be one of the building blocks of my replacement system for building up environment information.
This is a little involved, so let's break out of the bullets.</li>
</ul>
<p>Currently, the <tt class="docutils literal">Installer</tt> protocol only has one implementation, which uses virtualenv and pip together.
This class bundles together "what arguments get passed to pip" and "what arguments get passed to virtualenv", which turns out to be the wrong thing to do, at least for how I'm using the <tt class="docutils literal">Installer</tt> protocol.
The problem is, nothing in this system allows for <em>multiple</em> Python versions to be selected, which is a pretty major feature.
My goal is to pull things out into a protocol for setting up the environment, and a protocol for installing stuff in the environment.
(I've thought so much about trying to make this idea generic in the type of installer, but I've just confused myself, so I need a simplified prototype I can tweak.)
These protocols would not be concerned with the question of "where is this done on the file system"?
Instead, instance of each would be put in a <tt class="docutils literal">PathWith[T_co]</tt>, and helper functions would be written to process that concrete code, independent of how any of the protocol implementations would work; they would simply receive the calculated environment path.</p>
<p>So, when I pick this back up, I can write those protocols, then the helper functions to consume them, then implement the protocols, then sub the new protocols in, and chase type errors until mypy thinks it should all work.
If I find myself messing with typed mappings, I will take that excuse to start using that helper class in earnest.</p>
<p>For now, though, I just want to publish this entry and cap off the thread.</p>
<p>Good night.</p>
Diary 2022-04-162022-04-16T04:00:00-04:002022-04-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-16:/diary-2022-04-16<p class="first last">Being a bundle of nerves doesn't help me do <em>anything</em>, <em>body</em>.</p>
<p>Well, I wasn't obviously sick today, but I do seem to have ended up keyed up, and not really up for doing much.</p>
<p>I can't really predict how much I'll be up for this weekend, and I'm not going to hold myself to anything, besides that I want to make some progress in Satisfactory, and progress in Vampire Survivors is fine too.</p>
<p>I'll try to work on MOTR over the next few days, but I've been thinking of shaking up the format of my code posts a little.
Basically, I'd be live-blogging my process on my Mastodon (linked somewhere in the footer), and posting summaries to the blog when I'm done for the night.
Maybe I'll try that the next time I'm up for coding.</p>
<p>In any case, for now, I just need to take things easy and wind down.</p>
<p>Good night.</p>
Diary 2022-04-152022-04-15T04:00:00-04:002022-04-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-15:/diary-2022-04-15<p class="first last">Uuuuuugh...</p>
<p>Oh hey, looks like I got some kind of sickness today.
I really want to do stuff, but I'm not sure how much stuff I'm actually capable of doing.</p>
<p>I think it makes the most sense for me to just do a short entry and see what I'm up for after it publishes.
It feels like if I did anything else, there's a high probability that I'd just sit around trying to think about what to do, and end up publishing "Uh, nothing, I guess".</p>
<p>I don't know when the situation will change.
I'll see what I'm up for in the coming days, but right now my expectations are calibrated at "maybe I'll be up for doing more, like, next week".</p>
<p>Good night.</p>
Diary 2022-04-142022-04-14T04:00:00-04:002022-04-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-14:/diary-2022-04-14<p class="first last">Some things take time.</p>
<p>Switching from the treadmill to walking outside has been... a little rough on me.
One possible factor for why I've been kind of out of things in the past few days.</p>
<p>I'm making some serious progress on the writing I think I mentioned earlier.
At this rate, I should soon be ready to verify that the rough draft is complete, then start marking it up so I know which bits still need work.</p>
<p>I'm not going to go into too much detail about this project.
I'll just note that it just goes to show that, sometimes you just need a break from something, and you can come back to it refreshed.
Now, ideally, I wouldn't have taken <em>over six years</em> on this project so far, but, um, oh well.</p>
<p>Just got to take things one day at a time.
And this day is nearly over.</p>
<p>Good night.</p>
Diary 2022-04-132022-04-13T04:00:00-04:002022-04-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-13:/diary-2022-04-13<p class="first last">I'm pretty sure they couldn't even <em>hurt</em> me, they were just <em>really annoying</em>.</p>
<p>Oh boy.
I feel like the new Vampire Survivors update <em>hurt</em> me.
I'll look into finishing up the achievements later.</p>
<p>Anyway, I've got a bit of writing that I'd like to make some progress on, so I'm going to try to work on that for the next ten minutes or so.</p>
<p>All right, I made some good progress there, and I'd like to keep it up for a bit.
I'm calling this entry now, because I don't really know what to say besides "Wow, I hated some of those one-off enemies in Vampire Survivors".</p>
<p>Good night.</p>
Weekly Roundup 2022-04-122022-04-12T04:00:00-04:002022-04-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-12:/weekly-roundup-2022-04-12<p class="first last">Feels like I'm on the fifth or so 80% of this project...</p>
<ul class="simple">
<li>Wednesday: I took things somewhat easy, apparently. I don't really remember.</li>
<li>Thursday: I did some writing. *shrug*</li>
<li>Friday: I beat a game and did some more writing.</li>
<li>Saturday: I souped up MOTR's typing plugin.</li>
<li>Sunday: I ran into a problem testing MOTR that is really just a problem with generally <em>using</em> the new code, so I've got to rethink stuff.</li>
<li>Monday: I continued to rethink stuff.</li>
</ul>
<p>Next week, I'm going to try and work on some writing, and take notes on the MOTR redesign.</p>
Coding 2022-04-112022-04-11T04:00:00-04:002022-04-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-11:/coding-2022-04-11<p class="first last">Re-litigating the same bit of logic over and over...</p>
<p>After considering my options from last night, I want to break apart the <tt class="docutils literal">Installer</tt> protocol.
I was trying to do this all in my head for some reason, and the problem I was running into there was, I wasn't sure what to call the protocols and instances that would get spun out from that.
So, let's try and think things through a bit.</p>
<p>The <em>python version</em> is consumed by <tt class="docutils literal">virtualenv</tt>.
The <em>packages</em> are consumed by <tt class="docutils literal">pip</tt>.</p>
<p>The path to <tt class="docutils literal">pip</tt> doesn't exist until <tt class="docutils literal">virtualenv</tt> runs.</p>
<p>In the event that I support other kinds of environment/installers, it's possible that there could be a scenario like "here is a <tt class="docutils literal">conda</tt> env that needs both <tt class="docutils literal">conda</tt> and <tt class="docutils literal">pip</tt> run against it, or something".
All the same, the means of locking in the packages is predicated on <em>having an executable</em>.</p>
<p>So, the constant information is which packages are installed and which scripts we expect to get as a result.</p>
<p>The <em>environments</em> can be thought of as providing scripts to the <em>installer args</em>.
So, I think, to implement that, the <tt class="docutils literal">Environment</tt> protocol needs to provide some kind of callback-ish method that takes an <tt class="docutils literal">InstallerArgs</tt> class and returns the corresponding path to the executable, modulo that it would actually return a <tt class="docutils literal">Requirements[Input[Path]]</tt>.</p>
<p>I'm going to try writing that down for later, because I want to wrap things up early-ish.</p>
<p>Hm, writing things down, I think those initial ideas about the interface aren't quite right.
I'll have to take some time to refine them.</p>
<p>Well, I'm not ready to go yet, but I'm confident things will go more easily once I get past this.
We'll see if that confidence is warranted.
Anyway, I'm done for tonight.</p>
<p>Good night.</p>
Coding 2022-04-102022-04-10T04:00:00-04:002022-04-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-10:/coding-2022-04-10<p class="first last">Unexpected complications.</p>
<p>Well, I suppose if I'd been <em>expecting</em> this issue, I would have <em>accounted for it</em>.
Unless I've forgotten something, the current code is missing the ability to pass multiple—or indeed, any—Python versions into the <tt class="docutils literal">Pip</tt> installer object, so it's not capable of actually generating the requirements.</p>
<p>Right now, I have two basic ideas for how to deal with this.
One is to hack additional <tt class="docutils literal">Pip</tt> objects into the code flow, so one object contains the requirements, and the other contains the version information.
The other is to separate out the relevant field on the <tt class="docutils literal">Pip</tt> class into a separate class, and make that class be an argument to <tt class="docutils literal">Pip.resolve()</tt>.</p>
<p>The former object is worth it if I want a bunch of flexibility.
The latter option is worth it if I think I don't <em>need</em> all that flexibility.
I don't want to choose just yet, hopefully tomorrow, so for now I'm going to try to develop the pros and cons a bit more.</p>
<p>The first question is, how strongly would I be committing with either choice?
My feeling is the latter option puts the code into a simpler shape.</p>
<p>In the former case, there'd be more flexibility in terms of ways to inject the version information, but I don't see what that flexibility would help with, and it would mean two different ways to inject the information, with different overall capabilities.
That sounds to me like some kind of trap for the unwary.</p>
<p>So, unless I change my mind, the plan for tomorrow is to rework the code and provide one interface for specifying versions.</p>
<p>For now, I'd like to wrap up a little earlier than I have been lately.</p>
<p>Good night.</p>
Coding 2022-04-092022-04-09T04:00:00-04:002022-04-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-09:/coding-2022-04-09<p class="first last">Coding isn't about "Why?", it's about "Why not?"!</p>
<p>Okay, so, I've been tweaking MOTR's typing plugin a bit, and I think I know <em>generally</em> how to make some improvements, but not yet how to handle the exact details.
I'll work on the other tests tomorrow, hopefully.</p>
<p>For now, let's get some plans together for the plugin.</p>
<p>First off, here's what I'm trying to solve:</p>
<ul class="simple">
<li>The <tt class="docutils literal">get()</tt> method defines two overloads.
One with no default, and one with a default.</li>
<li>The existing plugin code, which focuses on rewriting the <em>signature</em>, can handle the first case, but not the second.</li>
<li>This manifests as a <tt class="docutils literal">Union[V, T]</tt> getting treated everywhere as <tt class="docutils literal">V</tt>, which is unhelpfully restrictive.</li>
</ul>
<p>Various ways of reworking the existing signature rewrite code have done nothing to change this, but at least they didn't break the other cases.</p>
<p>I've come to the conclusion that I need to make the following changes:</p>
<ul class="simple">
<li>At signature rewrite time, convert the default and return types to <tt class="docutils literal">Any</tt>.
I could just change the code, but I think leaving the code as-is will be easier to understand.
At minimum, the default type needs to be changed.</li>
<li>Add a method rewrite hook that, when the default argument is present, constructs a union type manually to be the return type.</li>
</ul>
<p>Let's see what happens when I try...</p>
<p>...</p>
<p>All right, I've generated an <tt class="docutils literal">Any</tt>, now let's see about the return value.</p>
<p>I found a function called <tt class="docutils literal">make_simplified_union</tt> that seems to do exactly what I want, so it looks like I'm in business.
Some of mypy's internals kind of confuse me, so I'm probably doing something wrong, but I've gotten the tests to pass.</p>
<p>Speaking of tests, I really should get to work on the flake8 wrapper tests tomorrow.
For now though, I've spaced out enough while finishing this.</p>
<p>Good night.</p>
Diary 2022-04-082022-04-08T04:00:00-04:002022-04-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-08:/diary-2022-04-08<p class="first last">Games, and some not-game stuff.</p>
<p>Brain is not fried.
I managed to work on stuff at a good pace, but it's mostly not stuff I blog about.</p>
<p>In fact, mostly it was Patrick's Parabox and Vampire Survivors.</p>
<p>Right now, I've beaten Patrick's Parabox and gotten all of the current achievements and unlocks in Vampire Survivors.
I was checking out some custom levels in Patrick's Parabox, and I don't know what to make of them.
One of them, I managed to beat it while avoiding engaging with like half the level, including the gimmick that inspired it.
The other, I'm going to tentatively believe the author's claim that it <em>is</em> beatable.
I'm also going to consider changing the color palette to something that lets me <em>actually see the level</em>.</p>
<p>I pondering stuff I could do for custom levels, and I have some ideas that I'm going to jot down.
Now that I've written stuff down, I'm not totally sure where to go next.
I'm going to need to think about it some more.</p>
<p>Also, I did a bit more writing experiment stuff.
This definitely works, but it's really hard to maintain my focus.
I'm thinking about other directions I could approach things from.</p>
<p>Anyway, it's late, and I don't want to delay anything too much longer.</p>
<p>Good night.</p>
Diary 2022-04-072022-04-07T04:00:00-04:002022-04-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-07:/diary-2022-04-07<p class="first last">*Extreme thinking*</p>
<p>I managed to fry my brain a little today, entirely my fault, so I once again don't really have much to talk about.</p>
<p>Just now did a bit more writing.
I feel like maybe what I'm experimenting with needs a bit more of a hook, or I need to work better to communicate the hook to... myself?</p>
<p>Anyway, I'm going to publish early and doodle some stuff for coding in BQN.
Hopefully, I'll be all set to get to bed whenever.</p>
<p>Good night.</p>
Diary 2022-04-062022-04-06T04:00:00-04:002022-04-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-06:/diary-2022-04-06<p class="first last">I thought about stuff a bunch, I guess.</p>
<p>I don't remember what I did today that's worth writing about.
I... played Vampire Survivors?
I've got one achievement left before I'm caught back up, and it's kind of a doozy so far.
I'll probably go for it again tomorrow.</p>
<p>Anyway, other stuff...
I was messing with other games...
I didn't get writing done.
I should maybe try to get back into scheduling my days a little more thoroughly.</p>
<p>Anyway, nothing happening for the rest of the night, so I'm going to wrap up for now.</p>
<p>Good night.</p>
Weekly Roundup 2022-04-052022-04-05T04:00:00-04:002022-04-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-05:/weekly-roundup-2022-04-05<p class="first last">A bit stressful at times, but overall this felt like a good week.</p>
<ul class="simple">
<li>Wednesday: I had a rough day that was productive in ways that I didn't find interesting.</li>
<li>Thursday: Patrick's Parabox.</li>
<li>Friday: As above, and also notes several levels removed from Missable Mysteries.</li>
<li>Saturday: As above, and some venting.</li>
<li>Sunday: Games, and a small amount of work on planning for MOTR.</li>
<li>Monday: I improved and debugged MOTR's tests.</li>
</ul>
<p>Next week, I'm going to try and get into writing more, for a bit.</p>
Coding 2022-04-042022-04-04T04:00:00-04:002022-04-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-04:/coding-2022-04-04<p class="first last">I'm thankful that I got everything figured out.</p>
<p>All right!
I've got negative tests written for the typing plugin for MOTR, so I should be ready to integrate the new protocol at any time.</p>
<p>As such, I'm comfortable putting that to the side until I manage to actually increase the test coverage some.
It's hovering a bit above 80% right now.</p>
<p>Since I've got the tests written, and also I fixed up some of the other tests so that they're more consistent and, like, more correct, I'm done for today and I'm thinking about how I want to handle things in the week to come.
(I may also want to tweak some of those tests to be a little less awkwardly written, now that they actually test what they're supposed to.)</p>
<p>I think it would make the most sense to return to some of the writing experiments I was doing yesterday.
If I'm up for it during the week, I can return to taking notes on The Document, but I think I need to detox from that a bit more.
Best to get back into higher volumes of writing, then devote time on the weekends to getting MOTR closer to ready for a release.</p>
<p>For now, I'm going to wrap things up for tonight.</p>
<p>Good night.</p>
Diary 2022-04-032022-04-03T04:00:00-04:002022-04-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-03:/diary-2022-04-03<p class="first last">Once again, I ended up taking things easy without really consciously deciding to.</p>
<p>Ended up doing a little writing today, and playing a bunch of games.
It would have been cool if I'd worked on MOTR, but I guess I needed to decompress a bit.</p>
<p>Now that I've brought it up, let me see if I can figure out what to focus on tomorrow, if I'm up for MOTR.</p>
<p>Right, the two areas to look into are writing negative type tests, and writing tests around the command-line wrappers.</p>
<p>I'm going to just write that stuff down so I can refer to it in the morning.</p>
<p>I don't think I have anything else to say tonight, so I'm going to make sure I get this published as soon as I can.</p>
<p>Good night.</p>
Diary 2022-04-022022-04-02T04:00:00-04:002022-04-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-02:/diary-2022-04-02<p class="first last">A good portion of the notes is just confused swearing.</p>
<p>I think I should try to take a break from Patrick's Parabox.
I've beaten the main campaign and a few of the bonus puzzles.
The appendices are <em>extremely</em> confusing.</p>
<p>Anyway, I've got some more notes on The Document.
This is <em>so bad</em>, y'all.
This book is edited so ineptly, I wish I could have seen the editing process play out.
Would have been good for a laugh.</p>
<p>Things The Document is not edited for:</p>
<ul class="simple">
<li>Clarity</li>
<li>Factual accuracy</li>
<li>Spelling</li>
</ul>
<p>Anyway, I think taking these notes is a decent fallback when I don't manage other writing or coding, but The Document is really hard to read.
Mentally and emotionally.</p>
<p>Here's to getting some work done on MOTR or with BQN tomorrow.</p>
<p>Good night.</p>
Diary 2022-04-012022-04-01T04:00:00-04:002022-04-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-04-01:/diary-2022-04-01<p class="first last">I'm getting pretty far in this game.</p>
<p>So...
Patrick's Parabox.</p>
<p>I also took some more notes on The Document for Missable Mysteries.
Most of the notes were venting, owing to the fact that The Document's author embarked on a roller-coaster misunderstanding of chemistry, nuclear physics, electricity, linguistics, and probably some other stuff that I blocked out, in the space of a few pages.
This is dire stuff, and I'm going to have to push through to get to equally dire stuff that will give me lesson ideas.</p>
<p>(One reason I'm not naming The Document is that I don't want to let the identity of the author distract from the author's misunderstandings.
The other main reason is that the title <em>technically</em> uses notation that doesn't exist in unicode.)</p>
<p>Anyway, it's late, so I should publish this and get ready for bed.</p>
<p>Good night.</p>
Diary 2022-03-312022-03-31T04:00:00-04:002022-03-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-31:/diary-2022-03-31<p class="first last">In-depth work canceled on account of video games.</p>
<p>I didn't get much done today, because, um, Patrick's Parabox.</p>
<p>As such, I'm just going to publish this entry and do a little note-taking for long-term plans on Missable Mysteries.</p>
<p>Good night.</p>
Diary 2022-03-302022-03-30T04:00:00-04:002022-03-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-30:/diary-2022-03-30<p class="first last">Let's see what I'm going to do... later...</p>
<p>Okay, okay, let's see...</p>
<p>I did a bunch of things that I had to do today, which left, not as much time for things that I want to do.</p>
<p>Something I did, which was potentially just "sitting wrong", has given me a headache, so I think I'll just try to take things easy for now and pick things back up tomorrow.</p>
<p>It should probably be some kind of writing that I do starting tomorrow, but I'm not sure what I want to go for specifically.
I think maybe I need to wait to even consider which to prioritize.</p>
<p>For now, I'm wiped out.</p>
<p>Good night.</p>
Weekly Roundup 2022-03-292022-03-29T04:00:00-04:002022-03-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-29:/weekly-roundup-2022-03-29<p class="first last">Going from sensible to... not...</p>
<ul class="simple">
<li>Wednesday: I decided to devote more time to working on MOTR. I took an inventory of the flake8 packages I'm using, and tried to move flags into config for a more reliable experience.</li>
<li>Thursday: I thought I was ready to write tests, until I realized that there isn't a good interface to access all of this code from outside of MOTR.</li>
<li>Friday: I took a break from MOTR to mess around with BQN.</li>
<li>Saturday: I messed a little more with BQN, and took an inventory of some of MOTR's code to see which modules I want to move around.</li>
<li>Sunday: I reorganized and exposed all of the command-line wrappers for MOTR, including the ones I haven't written yet, which is most of them.</li>
<li>Monday: I put together type testing as part of an effort to actually use the "registry" code I wrote for the higher-level interface, because that code is the only non-trivial module that my tests don't exercise at all. After writing some tests, I concluded that the plugin code required to make this all work is sufficiently weird that this is a sign that I'm pushing Mypy too far and I should back off, which is a decision that I definitely held to today.</li>
</ul>
<p>Next week, I'm going to see about having a good balance between MOTR and not-MOTR, but no promises.</p>
Coding 2022-03-282022-03-28T04:00:00-04:002022-03-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-28:/coding-2022-03-28<p class="first last">"Cons: Not as flexible. Pros: Actually works with my project."</p>
<p>So, I looked into setting up pytest to test my Mypy plugin.
I knew of two pytest plugins that are meant for that.
Here is a quick rundown:</p>
<ul class="simple">
<li><a class="reference external" href="https://github.com/typeddjango/pytest-mypy-plugins">pytest-mypy-plugins</a><ul>
<li>Pros:<ul>
<li>Flexible</li>
<li>Extensible</li>
<li>Expressive</li>
</ul>
</li>
<li>Cons:<ul>
<li>It turns out I don't like embedding Python in YAML</li>
<li>Many fiddly levers that might result in something bad happening if you have the wrong combination of settings.</li>
<li>I never figured out how to get it to work under MOTR, and I don't remember if I got it working with virtualenvs without forking it, and I definitely did fork it</li>
</ul>
</li>
</ul>
</li>
<li><a class="reference external" href="https://github.com/davidfritzsche/pytest-mypy-testing">pytest-mypy-testing</a><ul>
<li>Pros:<ul>
<li>Runs with minimal configuration, both outside of and under MOTR</li>
<li>Test sources are just Python</li>
<li>I checked to see if it handles all of the issues that pytest-mypy-plugins expected me to coordinate myself, and from inspecting the source, it looks like the answer is yes</li>
</ul>
</li>
<li>Cons:<ul>
<li>Can't handle some of the more advanced cases that pytest-mypy-plugins does.
For what it's worth, I have not needed this yet.</li>
<li>Lines can get really long, and if you run black on the file, it will probably break the tests, so, that's not ideal.</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>I just made that last point a little less bad by reading a bit more of the documentation.</p>
<p>Anyway, all of this testing is revealing that I'm pushing Mypy far enough past what's "supposed to" work, that for now, I should focus on tests based on my target motrfile layout.</p>
<p>So, I'm going to have to take a bit of a break to clear my head, and then I should absolutely be writing those tests.
Until then...</p>
<p>Good night.</p>
Coding 2022-03-272022-03-27T04:00:00-04:002022-03-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-27:/coding-2022-03-27<p class="first last">Sculpting the code into a more pleasing form</p>
<p>This pace feels a little frustrating, but whatever.
Before I can write tests, I need to expose the modules through the public interface to MOTR, and I want the way I expose them to make sense.</p>
<p>The idea I currently have in mind is to expose the contents of the <tt class="docutils literal">motr._api.cli</tt> package under <tt class="docutils literal">motr.api.cli</tt>, but doing that means making sure that all of the contents of <tt class="docutils literal">motr._api.cli</tt> make sense to export.
So, let's take a look at that.</p>
<ul class="simple">
<li><tt class="docutils literal">cli.coverage</tt> contains modules for each coverage subcommand.
I think I want <tt class="docutils literal">cli.coverage</tt> to contain helper functions, and this be called something like <tt class="docutils literal">cli.coverage_commands</tt>; it can re-export the modules as well for convenience.</li>
<li><tt class="docutils literal">cli.junitparser</tt> contains modules for the only junitparser subcommand.
I'll probably do something similar to coverage, above.</li>
<li><tt class="docutils literal">cli.build</tt> is needed to build the wheels that will be tested.
I seem to have not hooked this up to anything, but it's going to be needed in order to set up the constraints files that will power everything.
I'm not sure if it's necessary to expose it to the API, but I might as well.</li>
<li><tt class="docutils literal">flake8</tt>, <tt class="docutils literal">junit2html</tt>, <tt class="docutils literal">limit_coverage</tt>, <tt class="docutils literal">mypy</tt> are all straightforward and should stay as-is.</li>
<li><tt class="docutils literal">cli.pip</tt>, while it does wrap a command-line utility, does so in a more restricted way because it's part of the basis of the other wrappers.
It should be moved to <tt class="docutils literal">motr._api.installers.pip</tt>.</li>
<li><tt class="docutils literal">pyinstrument</tt> and <tt class="docutils literal">pytest</tt> should stay as-is.
As should <tt class="docutils literal">python</tt>.</li>
<li><tt class="docutils literal">cli.python_helpers</tt> should be moved to something like <tt class="docutils literal">motr._api.helpers.python_helpers</tt>.</li>
<li><tt class="docutils literal">cli.types</tt> should be moved to <tt class="docutils literal">motr._api.cli_types.not_output</tt>.</li>
</ul>
<p>Let's see about making these changes...</p>
<p>Well, before I touched anything, I discovered that <tt class="docutils literal"><span class="pre">flake8-html</span></tt>, or at least my fork, got broken.
On further investigation, it's my fork.
Let's see about fixing this up...</p>
<p>It was a little unfortunate that "flake8 crashed because of your hacked-up plugin" apparently has the same exit code as "the code had issues".
But that was a pretty straightforward fix, thanks upstream.</p>
<p>Okay, let's actually start rearranging this...</p>
<p>Okay, done moving the files.
Let's see how many Mypy errors this gives me.
Huh.
Only 8.</p>
<p>I addressed those and some other issues, then worked on exporting the CLI interfaces.
There were... some issues, but it looks like the situation is improving...</p>
<p>Anyway, with all of that, I've got much better coverage numbers now.
Still not ready, but the only file only non-executed lines in it...</p>
<p>Is my experimental generic protocol for replacing the registries.</p>
<p>Oh boy.</p>
<p>I really don't want to throw that away, so I guess I'm going to have to write mypy tests for that so I can qualify it enough to feel safe using it in the rest of the app.</p>
<p>It's getting late, so I'm going to publish this post now, and work on adding mypy tests the next time I pick this code up.</p>
<p>Good night.</p>
Coding 2022-03-262022-03-26T04:00:00-04:002022-03-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-26:/coding-2022-03-26<p class="first last">Figuring out how much I've been over-complicating this.</p>
<p>Okay, so I spent a good portion of today tinkering with BQN programs, but I want to make some progress on MOTR.
Let's see about cataloging the commands and arguments, and if there are any that I want to rewrite into config options.</p>
<ul class="simple">
<li><tt class="docutils literal">pytest</tt><ul>
<li><tt class="docutils literal"><span class="pre">-p</span> no:cacheprovider</tt>; I think this should stay as an argument generated from within MOTR.</li>
<li><tt class="docutils literal"><span class="pre">--junitxml</span></tt>; this can't work in config, so that's all set...</li>
</ul>
</li>
<li><tt class="docutils literal">junitparser merge</tt> and <tt class="docutils literal">junit2html</tt> basically work out of the box, so they're all set once I actually write the modules.</li>
<li><tt class="docutils literal">flake8</tt> now just has the related <tt class="docutils literal"><span class="pre">--format=html</span></tt> and <tt class="docutils literal"><span class="pre">--htmldir</span></tt> flags, and I don't have any idea how to make them into config, so they're all set.</li>
<li><tt class="docutils literal">mypy</tt> has <tt class="docutils literal"><span class="pre">--html-report</span></tt> and <tt class="docutils literal"><span class="pre">--junit-xml</span></tt>, which both need special support.</li>
<li><tt class="docutils literal">coverage</tt><ul>
<li><tt class="docutils literal">erase</tt> looks all set.</li>
<li><tt class="docutils literal">run</tt> probably needs configuration to be <em>generated</em>, and needs the output to be directed somehow.</li>
<li><tt class="docutils literal">combine</tt> doesn't need much.</li>
<li><tt class="docutils literal">html</tt> and <tt class="docutils literal">xml</tt> need to specify their outputs, but I bet some of the stuff I'm passing on the command line currently could live in a config file.
Let's say I'm... pretty sure that <tt class="docutils literal"><span class="pre">--fail-under</span></tt> and <tt class="docutils literal"><span class="pre">--show-contexts</span></tt> can be moved to the config, and it would work fine.
But MOTR does need support for <tt class="docutils literal"><span class="pre">-d</span></tt>/<tt class="docutils literal"><span class="pre">--directory</span></tt> and <tt class="docutils literal"><span class="pre">-o</span></tt>.
(I might look into supporting JSON and LCOV output, since they don't look like that much extra effort. I only really bothered to think about XML output because I was messing with SonarQube earlier... this... week... I think...)</li>
</ul>
</li>
<li><tt class="docutils literal">pyinstrument</tt> has <tt class="docutils literal"><span class="pre">--renderer</span> html</tt> and <tt class="docutils literal"><span class="pre">--outfile</span></tt>, which work together, and need to be handled by MOTR.</li>
</ul>
<p>So, this should work out to not all that much work, once I have a flow for actually doing any of this.</p>
<p>Anyway, it's getting late, so I'm going to publish and try to figure out BQN some more, then get to bed.</p>
<p>Good night.</p>
Coding 2022-03-252022-03-25T04:00:00-04:002022-03-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-25:/coding-2022-03-25<p class="first last">Maybe I already talked about this? Whatever, it's still cursed yet intriguing.</p>
<p>Well, this is awkward.
I just spent quite a bit of time working on something that is definitely coding, but is also definitely <em>not</em> MOTR.</p>
<p>I was messing around in <a class="reference external" href="https://mlochbaum.github.io/BQN/index.html">BQN</a>, which I might have mentioned before, and I might have said something like "I forget exactly how I heard about this language".
Regardless of whether I said it, it remains true.</p>
<p>Anyway, I decided to come up with extremely over-engineered solutions to coding challenges, and it's... kind of slow going.
Lots of "Okay, but how does <cite>(∨`⌾⌽0⊸≠)⊸/</cite> <em>accomplish what it does</em>?" and "There must be some way to simplify <cite>{Strip 𝕨 𝔽○((𝕨 MaxLen 𝕩)⊸↑) 𝕩}</cite>, aside from the functions I can inline."</p>
<p>I'm sure I'll get somewhere with this, especially if I, like, ask for help at some point, but in the near term, I want to focus more on building up my understanding of basic concept, and in the nearer term I want to get to bed because it is <em>late</em>.</p>
<p>Good night.</p>
Coding 2022-03-242022-03-24T04:00:00-04:002022-03-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-24:/coding-2022-03-24<p class="first last">Okay, I'm ready to wait again.</p>
<p>Okay, I might take a break from this tomorrow, but here's where I am right now:</p>
<p>I wrote a kind of janky helper function for creating static requirement data.
Part of the jankiness is from making it generic, so it currently takes a weird bunch of arguments.</p>
<p><em>Anyway.</em></p>
<p>I really should write tests to see what I'm now missing, and the first thing I realized I was missing is...</p>
<p>A good way to actually <em>import</em> these modules from outside of MOTR.
I don't want to have the tests just reach inside, so that means I need to think about reorganizing these modules a little so they make a bit more sense.</p>
<p>To accomplish this, I need to take some time to trace out the requirements and workflow for implementing parts of the motrfile logic using the new code, and that should help me figure out how to group things.</p>
<p>For the moment, I just want to space out for a bit.</p>
<p>Good night.</p>
Coding 2022-03-232022-03-23T04:00:00-04:002022-03-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-23:/coding-2022-03-23<p class="first last">So close...</p>
<p>Screw waiting for things.</p>
<p>I think I've got nearly everything I need for wrapping command lines, so let's <em>go</em>.</p>
<p>I'm starting with flake8.
For reference, here's the general command again:</p>
<p><tt class="docutils literal">flake8 <span class="pre">--format=html</span> <span class="pre">--htmldir</span> <generated path> <span class="pre">--isort-show-traceback</span> <path to <span class="pre">root>/src</span> <path to <span class="pre">root>/tests</span></tt></p>
<p>And it has requirements like:</p>
<ul class="simple">
<li>flake8</li>
<li>flake8-black</li>
<li>flake8-comprehensions</li>
<li>flake8-docstrings</li>
<li>flake8-html @ <a bunch of nonsense></li>
<li>flake8-isort</li>
<li>flake8-pytest-style</li>
<li>flake8-rst</li>
<li>flake8-rst-docstrings</li>
<li>flake8-type-checking</li>
</ul>
<p>The majority of these plugins don't require anything except to be installed.
If we divide those up, with the ones that need special handling first...</p>
<ul class="simple">
<li>flake8-html</li>
<li>flake8-isort</li>
</ul>
<p>And, everything else:</p>
<ul class="simple">
<li>flake8-black</li>
<li>flake8-comprehensions</li>
<li>flake8-docstrings</li>
<li>flake8-pytest-style</li>
<li>flake8-rst</li>
<li>flake8-rst-docstrings</li>
<li>flake8-type-checking</li>
</ul>
<p>I bet I could convert that one command-line flag for flake8-isort into a bit of flake8 config, which would give me a bunch of things that merely need to be installed.
I don't have a strong sense for what would be better for people who aren't me, but moving stuff from the command line into the config files certainly makes things easier <em>within</em> a repository.</p>
<p>(Source: I couldn't figure out why I was getting weird errors from running mypy directly instead of through MOTR, until I figured out that I could convert some static environment variable stuff I was doing into a config line.)</p>
<p>With that in mind, all I really need to code is handling for flake8-html, and everything else should probably get some kind of generic something.</p>
<p>This does raise the question, is there anything else in the motrfile I can do this to?</p>
<p>So, pytest has output stuff which needs to integrate with the higher-level abstractions, and some stuff that might or might not be needed in the automated case, but definitely isn't needed if you're invoking it manually, so, eh.</p>
<p>Looks like coverage has some stuff in the HTML output that it probably makes more sense to live in config.</p>
<p>Oh no, I just remembered that I think some of the coverage configs need to be generated on a per-command basis.
Hm, that's going to be workable, but also confusing.
Or maybe I can put it all together at once in some way...</p>
<p>In any case, the immediate goal is to figure out how to best collect together this kind of "just install a package" stuff that's so common.
It's getting late, so let's just see about some quick plans:</p>
<ul class="simple">
<li>Create a helper function in <tt class="docutils literal">flake8.py</tt> for now, until I figure out the right way to generalize it.
Unless...
Something like <tt class="docutils literal">Command.install_plugin()</tt>...
Or some kind of nice wrapper around <tt class="docutils literal">Label[Pip]</tt>...</li>
<li>Start working on the tests, focusing on building up the test data first.</li>
<li>Remove unneeded lines from <tt class="docutils literal">flake8.py</tt>.</li>
<li>For the actual tests, focus on validating the registry generated from the test data.</li>
<li>Fill things in until I have full coverage and the ability to handle all of the cases that the current motrfile does, plus some low-effort nice-to-haves.</li>
</ul>
<p>Anyway, I'll have time later to think about this.
For now, I'm getting pretty tired.</p>
<p>Good night.</p>
Weekly Roundup 2022-03-222022-03-22T04:00:00-04:002022-03-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-22:/weekly-roundup-2022-03-22<p class="first last">Getting ready to be extremely distracted</p>
<ul class="simple">
<li>Wednesday: I messed around a bit with writing, and it went well.</li>
<li>Thursday: I messed around a bit more with writing, and it didn't go as well as I would have liked.</li>
<li>Friday: I thought a bit about why I got stuck. I'm not sure I really got anywhere with that.</li>
<li>Saturday: I made some changes to MOTR's code that I now realize were premature.</li>
<li>Sunday: I made some progress towards getting MOTR usable, and also got distracted a bit by writing code to reduce boilerplate, and, um, mypy plugins to make it believe that that code was acceptable. That last bit is... probably not done.</li>
<li>Monday: I got the urge to add more flake8 plugins, so I did.</li>
</ul>
<p>Next week, I ought to get back to one of the various projects I'm "juggling".
(They are all on the floor.)
But, earlier today, I realized that there's some redundancy in my new MOTR code that I can factor out, and I'm itching to get those improvements in.</p>
<p>I'll see if I can get that out of my system until the weekend, after I publish this.</p>
Coding 2022-03-212022-03-21T04:00:00-04:002022-03-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-21:/coding-2022-03-21<p class="first last">Picking a random metric to improve on.</p>
<p>Today, I messed around with the new registry protocol a bit, and then stepped back from that.</p>
<p>Rather than continuing on with the command-line wrappers, I ended up adding some flake8 plugins and doing bits of cleanup.</p>
<p>Well then, next weekend, let's see about finishing up flake8, pytest, the python wrapper, then mypy, pyinstrument, and lastly coverage.</p>
<p>I can't say how long that will all take.</p>
<p>The basic arc I want to take is to get the commands all wrapped, get the motrfile <em>finally</em> simplified, more-or-less freeze the code, get coverage back up to full, and then look into improvements like:</p>
<ul class="simple">
<li>Renaming things</li>
<li>Documenting things</li>
<li>Setting up mypy tests so I'm comfortable subbing in the registry protocol without worrying that it'll crash mypy.</li>
</ul>
<p>Although, I might also just switch to another hobby project for a bit in honor of my multi-month attempt at delayed gratification.</p>
<p>Speaking of delays, this post is late, and I should wrap up ten minutes ago.
In service of that—</p>
<p>Good night.</p>
Coding 2022-03-202022-03-20T04:00:00-04:002022-03-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-20:/coding-2022-03-20<p class="first last">"Here are all of the reasons this doesn't work." "So, those are all of the things I need to change to make it work? :)"</p>
<p>Earlier today I did the minimal required rewrite for the <tt class="docutils literal">FlexOut</tt> class, and just now I wrote the <tt class="docutils literal">inject()</tt> helper for <tt class="docutils literal">Dynamic</tt>s.</p>
<p>In between that, I got distracted trying to make mypy do things that it's not supposed to do.</p>
<p>So, <em>ideally</em>, I "should" be working on building up the CLI wrappers, but I really want to see if I can get the plugin I wrote into a state where the class it operates on can function as a base class for the four classes worth of boilerplate that it's supposed to replace.</p>
<p>I don't feel like resolving to do things one way or the other right now.
Tomorrow, I'll do whatever I feel like.
Maybe some writing as well?</p>
<p>I don't want to think about it too hard, because it's late right now.</p>
<p>Good night.</p>
Coding 2022-03-192022-03-19T04:00:00-04:002022-03-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-19:/coding-2022-03-19<p class="first last">Quick fix</p>
<p>Okay, I didn't give myself much time to code today, but I at least want to plan stuff out.
So, here's planning for supporting module calls.</p>
<p>The existing code determines a path to an executable.
The code I need to add doesn't produce a specific path, not exactly.
All the same, a path seems like the easiest choice, even if it's not precisely correct in all circumstances.</p>
<p>This is going to look messy.</p>
<p>Messier.</p>
<p>Basically, I need to add a scan over the <em>arguments</em> to the resolution logic for the <em>extra_io</em>.</p>
<p>...</p>
<p>Oh, wow, that is messy.
Let's see what MOTR thinks of its code...</p>
<p>Not so happy with it...</p>
<p>I've fixed some of the issues, so I just want to check that I'm narrowing it down.
Okay...
I've made some changes that should cascade out to fix this...</p>
<p>And, bam, that seems to be cleared up, and also the code makes a little more sense at the higher levels of abstraction.
The interface is kind of wonky, but it's... fine?</p>
<p>Anyway, moving on for now, the other thing I need is to figure out how to fix up the <tt class="docutils literal">FlexOut</tt> class.</p>
<p>Okay, not happening in the next five minutes.
I'll try to work things out later.</p>
<p>Good night.</p>
Diary 2022-03-182022-03-18T04:00:00-04:002022-03-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-18:/diary-2022-03-18<p class="first last">I got extremely engrossed with color schemes, and I'm not sure I'm done with that yet.</p>
<p>Hmm.</p>
<p>I didn't make it so far today.
Mostly I got distracted tweaking system settings to try to make things look vaguely more consistent with... something.</p>
<p>When it came down to fleshing out the character arc I was messing with yesterday, I just kind of got stuck on the fact that I don't have strong feelings about how I want it to end.
That's important, because how it ends influences what happens in the middle, and probably how the beginning gets presented.</p>
<p>It seems like I need to have some level of emotional investment before I feel like it's worth going into more detail.
If this is correct, it won't be a problem when it comes to stuff that I want to write for a reason beyond practice.</p>
<p>In any case, I'm not getting any further for the rest of today, so I'll just have to take things easy for now, and tomorrow.</p>
<p>Good night.</p>
Diary 2022-03-172022-03-17T04:00:00-04:002022-03-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-17:/diary-2022-03-17<p class="first last">Not quite as productive experiments</p>
<p>After the luck I had with using randomness in writing yesterday, I tried it in a more structured context, with a list of questions I'd gotten from writing advice, on compelling character arcs.
Unfortunately...</p>
<p>I did fine on coming up with a sketch of a character, but when it came to the last question, which was basically "Why should the audience care about the character's struggles", I choked.
I'm not up for rethinking this in detail right now, but my gut feeling from this is that I need to approach the question differently somehow.</p>
<p>Like, I think I did this well enough with the worldbuilding poem thing.
Maybe the question could be something like "What is at stake that the audience could relate to?"
This isn't a restatement of what the character's trying to accomplish, more, like, how do the conflicts relate to the character's humanity, I guess.</p>
<p>I tried approaching it from another angle, and I didn't have much luck.</p>
<p>...</p>
<p>Actually, by complaining about it here, I gave myself some ideas for how to move forward, and I've got enough now to mess around with.</p>
<p>For the moment, I want to take care of some other things, like getting ready for bed, but I think I'll be able to pick this up tomorrow.</p>
<p>Good night.</p>
Diary 2022-03-162022-03-16T04:00:00-04:002022-03-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-16:/diary-2022-03-16<p class="first last">Productive experiments</p>
<p>Shifted gears again as far as writing goes.
I just did a quick experiment with writing, and using a random word generator whenever I wasn't sure of something.
After messing around so much with AI dungeon, it felt great.
Still got to have some unpredictability, but I only had to write things so I could understand them, and I could plunge ahead without the focus suddenly jerking off in unexpected directions.</p>
<p>This first one, I did without an outline of any kind, so I'm not exactly sure what's going on, but I suspect I could use this to work within or fill in a high-level outline.</p>
<p>Since my issue writing the Fiasco solo was momentum, I suspect this could help me out in some way.
I want to investigate how this works for me a bit more, first.
So, I'd like to try writing and filling in outlines a few different ways, before trying out converting the structure of Fiasco into an outline, and then filling it in more-or-less in order.</p>
<p>For now, though, I'll just be glad that I've got a technique for writing stuff that I can't predict ahead of time, that <em>doesn't</em> unpredictably take over twenty minutes to proceed, or get messed up by obscure techniques like "extremely common metaphors".
Anyway, it's late, so I'll get to bed.</p>
<p>Good night.</p>
Weekly Roundup 2022-03-152022-03-15T04:00:00-04:002022-03-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-15:/weekly-roundup-2022-03-15<p class="first last">A week of important discoveries.</p>
<ul class="simple">
<li>Wednesday: I looked at screen-writing software, and thought of some changes that I'd like to see made. Then I thought about stuff I want to change with other software I'm using.</li>
<li>Thursday: I read about basic screenwriting stuff.</li>
<li>Friday: I read more about screenwriting, and decided that I don't want to use screenwriting formats for the initial draft of my Fiasco stuff, but we'll see what I want to do when, later.</li>
<li>Saturday: I started picking things back up with MOTR.</li>
<li>Sunday: I started trying to put the MOTR code into practice, and encountered a shortcoming in the code, made harder to grasp by <em>just how much</em> the code does.</li>
<li>Monday: I dealt with <em>just how much</em> by reviewing the full stack of code, back from "synthesize the data required to describe actions MOTR can take", and found two major things: a bug that <em>will</em> break my code if I don't fix it, and the plausible location for a fix to that shortcoming I found.</li>
</ul>
<p>Next week, I'm going to try to take things easy or write until the weekend, then get to work on MOTR.
I think once I get another release of MOTR done, I'll reconsider how I'm distributing my work through the week.</p>
Coding 2022-03-142022-03-14T04:00:00-04:002022-03-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-14:/coding-2022-03-14<p class="first last">Start back over with how everything works, and look for the gaps.</p>
<p>It's a little earlier in the day, and I'm having trouble concentrating on what I want to concentrate on, so I'm going to try to lay out what MOTR does and see if I can find a better way, or if it actually does just all work.</p>
<p>(By the way, some of this stuff is slated to be potentially renamed.
I'm going to go with the names currently in the code for now.)</p>
<p>So, let's start near the end.
The end goal of running the motrfile is the creation of an object of type <tt class="docutils literal">motr.core.registry.Registry</tt>.
The registry contains several mappings:</p>
<ul class="simple">
<li>From <tt class="docutils literal">motr.core.runner.RuntimeAction</tt> to <tt class="docutils literal">motr.core.registry._ActionData</tt>, which tracks a set of <tt class="docutils literal">motr.core.target.Target</tt> objects that have to be satisfied according to the parameters of the registry, before the key action can be executed.</li>
<li>From <tt class="docutils literal">motr.core.target.Target</tt> to <tt class="docutils literal">motr.core.runner.RuntimeAction</tt>.
This indicates the action that must be executed to satisfy the target.</li>
<li>From <tt class="docutils literal">motr.core.target_name.TargetName</tt> to a set of <tt class="docutils literal">motr.core.target.Target</tt>.
Every target name is user-selectable at execution time using the <tt class="docutils literal"><span class="pre">-t</span></tt> argument.</li>
<li>And a set of <tt class="docutils literal">motr.core.target_name.TargetName</tt> objects that should <em>not</em> be selected by default.</li>
</ul>
<p>These fields are not modified directly.
Instead, the class defines a <tt class="docutils literal">require()</tt> method that takes an argument that is an instance of one of the types in the <tt class="docutils literal">Requirement</tt> union:</p>
<ul class="simple">
<li><tt class="docutils literal">Action</tt> adds a runtime action to the registry.</li>
<li><tt class="docutils literal">ActionInput</tt> adds a precondition to an action.</li>
<li><tt class="docutils literal">ActionOutput</tt> adds a result to an action.</li>
<li><tt class="docutils literal">TargetName</tt> associates a name to a target.</li>
<li><tt class="docutils literal">SkippedName</tt> marks a name as not selected by default.</li>
</ul>
<p>There are some undocumented requirements about ordering in order to avoid cycles, but one of the really important parts of this is that it should be the case that, if <tt class="docutils literal">new_registry == old_registry.require(requirement)</tt> (without any error), then <tt class="docutils literal">new_registry == new_registry.require(requirement)</tt>.
This allows me to play kind of fast and loose with requirements at the higher layers.</p>
<p>The next type that matters is <tt class="docutils literal">motr._api.requirements.requirements.Requirements</tt>, which is just an alias for <tt class="docutils literal">typing.Generator[motr.core.registry.Registry, None, T_co]</tt>, where <tt class="docutils literal">T_co</tt> is just <tt class="docutils literal"><span class="pre">typing.TypeVar("T_co",</span> covariant=True)</tt>.
This type is used as a return type all over the high levels of code.</p>
<p>The <tt class="docutils literal">motr._api.requirements</tt> package also has some modules that provide helpful wrappers around the <tt class="docutils literal">Requirement</tt> classes, in the form of tiny helper functions that coordinate the creation of instances of those classes.
I'm going to skip over them unless I realize that they're somehow important.</p>
<p>The next level up is the modules under <tt class="docutils literal">motr._api.actions</tt>.
One of these modules, <tt class="docutils literal">io</tt>, defines more of the types used all over the place in the higher levels.
Basically, wrappers around generic values, but marking them to be either an input or output of their associated action.
The other modules are:</p>
<ul class="simple">
<li><tt class="docutils literal">cmd</tt>, which defines a <tt class="docutils literal">Cmd</tt> class that is a runtime action to execute a command, and a <tt class="docutils literal">cmd_</tt> function that handles constructing a <tt class="docutils literal">Cmd</tt> instance and putting out all of its associated requirements.</li>
<li><tt class="docutils literal">mkdir</tt>, which defines a <tt class="docutils literal">Mkdir</tt> class that is a runtime action to create a directory, a <tt class="docutils literal">mkdir()</tt> function to wrap constructing a <tt class="docutils literal">Mkdir</tt> instance and putting out the associated requirements, and a <tt class="docutils literal">make_parent()</tt> function that does the same, but with the <em>parent</em> of whichever path it is passed.</li>
<li><tt class="docutils literal">write_bytes</tt>, which defines a <tt class="docutils literal">WriteBytes</tt> class that is a runtime action to write a sequence of bytes to a path.
The bytes are constant with respect to the registry.
There's also a <tt class="docutils literal">write_bytes()</tt> function that wraps constructing a <tt class="docutils literal">WriteBytes</tt> instance and putting out the associated requirements.</li>
</ul>
<p>Then, there's the <tt class="docutils literal">motr._api.build</tt> module, which just defines a function to convert a <tt class="docutils literal">Requirements</tt> object into a <tt class="docutils literal">Registry</tt>.</p>
<p>I believe this is the point after which I ended up building a whole lot of <em>stuff</em> that isn't actually used yet.</p>
<p>I don't remember what order any of this is in, let's see...</p>
<ul class="simple">
<li><tt class="docutils literal"><span class="pre">cli/*.py</span></tt></li>
<li><tt class="docutils literal"><span class="pre">cli_types/*.py</span></tt></li>
<li><tt class="docutils literal">package.py</tt></li>
</ul>
<p>The next place to look is into <tt class="docutils literal">cli_types</tt>.</p>
<p>The easy ones:</p>
<ul class="simple">
<li><tt class="docutils literal">entry</tt> and <tt class="docutils literal">program</tt>: define marker types for coordinating the combination of command line snippets.</li>
<li><tt class="docutils literal">label</tt>: defines a type that can be used as the key to a mapping, in a way that provides type information about the value to Mypy, depending on the mapping.- <tt class="docutils literal">objects</tt> and <tt class="docutils literal">items</tt>: mappings that use <tt class="docutils literal">Label</tt>s as keys.
<tt class="docutils literal">objects.Objects</tt> maps <tt class="docutils literal">Label[T]</tt> to <tt class="docutils literal">T</tt>, and <tt class="docutils literal">items.Items</tt> maps <tt class="docutils literal">Label[PVector[T]]</tt> to <tt class="docutils literal">T</tt>.
<tt class="docutils literal">items</tt> also defines some helper functions.</li>
<li><tt class="docutils literal">installer</tt> defines a protocol.
Classes that implement this protocol provide a means of combining with other objects of the same class, and of converting a command name to an absolute path to that command, in a dynamically created environment based on the data within the class.</li>
</ul>
<p>Then things start getting a little more elaborate.
I'm gong to try to focus on the stuff that probably won't need to change, if I <em>do</em> need to change something.</p>
<ul class="simple">
<li><tt class="docutils literal">dynamic</tt> defines the <tt class="docutils literal">Dynamic[T_co]</tt> class, which is a wrapper around a <tt class="docutils literal"><span class="pre">typing.Callable[[Objects,</span> Items], Requirements[T_co]]</tt>.
It also defines a bunch of helper functions and classes.
Basically, what all of this is <em>for</em> is to have facilities for combining <tt class="docutils literal">Dynmic</tt> objects, with the end goal being that it matches up with the input type to a function that I haven't mentioned here yet.</li>
</ul>
<p>Here are the remaining modules:</p>
<ul class="simple">
<li><tt class="docutils literal">command</tt> defines a <tt class="docutils literal">Command</tt> class that bundles a command name and the label of an installer, to indicate "this command, in the associated environment".
It also defines a <tt class="docutils literal">CmdMeta</tt> class, that represents a fragment of a command-line invocation, along with the metadata required to properly call the <tt class="docutils literal">cmd_</tt> helper.
<strong>IMPORTANT NOTE:</strong> This module does not handle module-type commands properly.</li>
<li><tt class="docutils literal">arguments</tt> defines <tt class="docutils literal">Command</tt> and <tt class="docutils literal">Option</tt> classes, which are wrappers around <tt class="docutils literal">CmdMeta</tt> objects.
The <tt class="docutils literal">Command</tt> class also adds more of the metadata required by <tt class="docutils literal">cmd_</tt>.</li>
<li><tt class="docutils literal">input_accumulator</tt> defines a pair of related classes: <tt class="docutils literal">InputAccumulator</tt> and <tt class="docutils literal">ValueAdaptor</tt>.
These classes work together to build up a <tt class="docutils literal">Dynamic[Input[motr._api.actions.cmd.PathStr]]</tt>, where <tt class="docutils literal">PathStr</tt> is a helper alias.</li>
<li><tt class="docutils literal">flex</tt> defines a protocol and classes that implement it.
The protocol is concerned with transforming some kind of <tt class="docutils literal">Dynamic</tt> into "the right" form for requiring or providing data.
<strong>IMPORTANT NOTE:</strong> The <tt class="docutils literal">FlexOut</tt> class seems like the likeliest candidate for implementing the behavior I was looking for yesterday.
There may need to be other changes to fully support it; I'll go into my reasoning below.</li>
<li><tt class="docutils literal">invocation</tt> defines the <tt class="docutils literal">Invocation</tt> class and a bunch of helper classes.
The <tt class="docutils literal">Invocation</tt> class is basically the dynamic version of the <tt class="docutils literal">arguments.Command</tt> class.
It's meant to be the, like, ultimate form of all of this in terms of fully generic code.</li>
</ul>
<p>So, what I'm basically looking for to handle the changes is to have a single <tt class="docutils literal">Invocation</tt> object that can have <em>something</em> passed to its <tt class="docutils literal">invoke()</tt> method that results in regular changes to the paths and names of some of the outputs it defines.
I think that looks like...</p>
<p><tt class="docutils literal">invoke</tt> takes an <tt class="docutils literal">Objects</tt> argument that gets somehow injected into the <tt class="docutils literal">Dynamic[_arguments.Command]</tt> that it returns.
(Another possibility is that <tt class="docutils literal">Invocation</tt> objects have an <tt class="docutils literal">Objects</tt> mapping on them...)
Meanwhile, <tt class="docutils literal">FlexOut</tt> should be somehow incorporating the values from the injected <tt class="docutils literal">Objects</tt> into the generated paths and the output names.</p>
<p><tt class="docutils literal">FlexOut</tt> makes sense as a target than the slightly-lower-level modules, because the lower-level modules don't use <tt class="docutils literal">Dynamic</tt>s, and those are the most straightforward candidates for changing the data around like this.</p>
<p>Anyway, I'm going to need some time to consider some of this, so I'm going to wrap up for now, and try to deal with the clocks changing.</p>
<p>Good night.</p>
Coding 2022-03-132022-03-13T05:00:00-04:002022-03-13T05:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-13:/coding-2022-03-13<p class="first last">"Well, this seems like a minor detail. ... OH NO."</p>
<p>I worked on a few things today.
A little bit of Fiasco writing.
I tried getting the first scene done.
I'm not sure if it's any good.
I think I'm really feeling the fact that I have the energy of only one person here.</p>
<p>Anyway, I did some random cleanup on MOTR, and tried to revamp the color schemes on all of the reports.
I'm not sure how well I did, because the flake8-html styling is both elaborate and a little weird.
We'll see what I think when I start working seriously on this again.</p>
<p>To get ready for that, let's consider the basic kinds of interface I want to build for these modules:</p>
<ul class="simple">
<li>Constructing invocations that don't need a module.
For these, it should work to define a function that takes <tt class="docutils literal">Part</tt>s, and may allow passing a different command.
For handling "different commands", my gut reaction is to put the command in a "reified partial", so there's an update method and a normal call.</li>
<li>Constructing invocations that need a module.
These need to pass data <em>into</em> the module constructor.</li>
<li>Module constructors.
These should just need a string argument to handle data paths and target names.</li>
</ul>
<p>I think the cohesive approach to this is a builder object.
And if we can use the <tt class="docutils literal">Invocation</tt> itself...
The main obstacle there is that it doesn't quite fit with the structure of the <tt class="docutils literal">Invocation</tt> object, but I think that might be a problem with the <tt class="docutils literal">Invocation</tt> object.</p>
<p>I'm confusing myself trying to work this out in my head, so I'm going to try to step back for a moment.
For dealing with these modules, I want to accumulate metadata that will properly identify the paths relevant to the specific <tt class="docutils literal">Invocation</tt>.
And this was <em>supposed</em> to be a solved problem.
It's the <tt class="docutils literal">path_segments</tt> field on the <tt class="docutils literal">Pip</tt> object.
So, to work with this, I need to make sure that the <em>outer</em> command has access to the <em>inner</em> command's label.</p>
<p>Side note, I just noticed that the way I'm setting up the pytest wrapper looks wrong.
It needs a <tt class="docutils literal">Command</tt> class that makes the <tt class="docutils literal">Input</tt> an <tt class="docutils literal">extra</tt> and just resolves to a string.</p>
<p>Now, back to the issue of handling <tt class="docutils literal">Label</tt>s and moving them between different wrappers...
I hope I'm missing something, because this is making my head hurt.
The nature of the <tt class="docutils literal">Label</tt>s being used has to be specific to the operation being performed.</p>
<p>I should explain a little about the <tt class="docutils literal">Label</tt>s.
I'm using them for various purposes at this high level, but the purpose in this context is to track information about the different virtual environments in play.
I'm trying to plan for having multiple virtual environments in play because I think that's required to type check Python 2 code with mypy.
But then, we have a situation where an <tt class="docutils literal">Invocation</tt> can have <em>2</em> <tt class="docutils literal">Label</tt>s associated with it.</p>
<p>Okay, here's a thought.
Stop thinking about the <tt class="docutils literal">Label</tt>s, because I just remembered that the <em>parametric</em> aspect of this is handled by the <tt class="docutils literal">Objects</tt> and <tt class="docutils literal">Items</tt> objects, as well as the <tt class="docutils literal">Flex</tt> objects.
If the design of all of this sounds like a horrible rats' nest, that's</p>
<p>probably accurate.</p>
<p>Except I'm not sure if anything is handling the specific case I'm thinking of...
The parameter-ish thing I want to inject is "what is running this module".
I really hope I took care of this somehow.
So, what would "taking care of this" look like?</p>
<p>The current motrfile hardcodes a lot in this area, and I'm starting to think I just genuinely overlooked the issue here.
For now, let's assume I did, and try to lay out a solution.</p>
<p>Well, the motrfile requires a path to be passed to the <tt class="docutils literal">run_pytest</tt> helper.
How far can I get by taking a similar approach?
The direct translation of this would be having a <tt class="docutils literal"><span class="pre">Callable[[str],</span> Invocation</tt>, but the <em>motrfile calls it directly</em>.
This works, but I feel like there should be a more elegant solution.
I think part of such a solution would look something like:</p>
<ul class="simple">
<li>Track some kind of "output context" on <tt class="docutils literal">Invocation</tt>s.</li>
<li>Provide facilities at a lower level to pull this context into the output generation.</li>
<li>Possibly rewrite the <tt class="docutils literal">Flex</tt> interface to route it through there?</li>
</ul>
<p>If I'm routing this data through the <tt class="docutils literal">Flex</tt>es, then the obvious question is if there's some way for the <tt class="docutils literal">FlexOutput</tt> to inject it into other parts of itself.</p>
<p>I've been going in circles, and I'm tiring myself out.
I'm starting to think that my only hope of getting this all to make sense is a comprehensive review of the architecture.
And I'm not up for that right now, so for the moment, I am done.</p>
<p>Good night.</p>
Coding 2022-03-122022-03-12T05:00:00-05:002022-03-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-12:/coding-2022-03-12<p class="first last">Hooray, it mostly worked!</p>
<p>Am I up for working on MOTR right now?
I don't know, but I want to try.
I'll get to writing tomorrow.</p>
<p>Anyway, the first step to updating the existing wrapper modules is to update the types.</p>
<p>But before I do that, I want to try and remember how different Python versions are supposed to work.</p>
<p>So, Python version is set on the <tt class="docutils literal">Pip</tt> class, which implements the <tt class="docutils literal">Installer</tt> protocol.
So, to figure out what's up, I need to search for usages of that protocol.
It's just used in command.py, to...
Handle stuff related to <tt class="docutils literal">CmdMeta.installer_registry</tt>.
So, what's populating that?
python_helpers.py
And, looking at that, I'm not sure whether I'm <em>populating</em> the version field yet, but I can worry about that later, because the important thing is how these functions interact, and I've confirmed that I have the capability to specify the versions the way I want.</p>
<p>Anyway, let's see...</p>
<p>I've got these <tt class="docutils literal">_arguments.Option[]</tt> types that need to be changed around to be wrapped in <tt class="docutils literal">_invocation.Static[]</tt>.
Let's see about that...</p>
<p>Okay, that's done, so the next to look at is turning my sketches from last time into actual code.</p>
<p>And, it worked until it didn't.
Something was weird with the new decorator, but I dealt with it by removing some code paths I didn't need.
I should probably do that with the other decorators, because I really didn't need some of the utility code I wrote.</p>
<p>At this point, there are a few things I can look into, but it's pretty late and I think I'm done for the night.</p>
<p>Good night.</p>
Diary 2022-03-112022-03-11T05:00:00-05:002022-03-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-11:/diary-2022-03-11<p class="first last">Trying to make some decisions, now that I have a slightly better understanding.</p>
<p>I'm taking some preliminary notes on screenplay formatting and getting conventions to fit within the fountain file format.
In general, the combination of fountain's relaxed formatting and the vim plugin I installed, should make it possible for me to write sensible screenplays without excessive effort, if I go that route.</p>
<p>While the formatting won't be a big issue (barring issues converting from fountain to other formats), I think I've decided that, for the Fiasco idea, I don't want to <em>start</em> by drafting in script form.</p>
<p>My initial thought is to draft it in the form of a metaphorical chat log between the characters.
This should allow me to start of preserving the feel of the game mechanics, which I think fits in with my general idea of "Do things in the typical case, then move away as I get a better grasp on things".</p>
<p>Anyway, things are wrapping up over here, so I'm going to get ready for bed now.</p>
<p>Good night.</p>
Diary 2022-03-102022-03-10T05:00:00-05:002022-03-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-10:/diary-2022-03-10<p class="first last">Treading water.</p>
<p>Okay.
Work has felt kind of rough this week, so I'm trying to take things easy right now.
Still reading about screenplays to get some sense of whether that's the format I want for solo Fiasco stuff.
The book I'm reading, I guess I don't have to read it in strict order to get the information I currently want, but for the moment, I'm going to take it as it is.</p>
<p>Actually, I just checked the table of contents, and I'll <em>probably</em> skip ahead soon.</p>
<p>Anyway, for now, I've got to focus on myself, rather than forcing myself to do anything.
I can't think of anything else to add to this entry, so it's done.</p>
<p>Good night.</p>
Diary 2022-03-092022-03-09T05:00:00-05:002022-03-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-09:/diary-2022-03-09<p class="first last">Must... not... shave... yak...</p>
<p>Oh boy.
I kind of poked around at more tech stuff, and ended up proposing—not committing to anything, just proposing!—a pretty major overhaul to a fork of an open-source project, just so I wouldn't have to open a GUI window sometimes.</p>
<p>On balance, I think I'm going to want something along those lines long-term, but I should hold off on doing such work for as long as I can.
I've taken notes on some alternatives for now, and I should definitely make do with them until things get much further along than I currently anticipate them getting.</p>
<p>All that said, I should try to focus on learning more about screenwriting, just for my own edification.</p>
<p>Thinking for a sec about other projects I'd like to work more on...
flake8-html and junit2html, I think.
I don't remember what I concluded the last time I looked into them, but I think it makes more sense to fork their code and mess with it, than to write a style for Stylus like I did for Mypy's coverage output just now.</p>
<p>But really, I should put down the text editors for now.
I should also get ready for bed.</p>
<p>Good night.</p>
Weekly Roundup 2022-03-082022-03-08T05:00:00-05:002022-03-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-08:/weekly-roundup-2022-03-08<p class="first last">Pivoting a bit, then moving back...</p>
<ul class="simple">
<li>Wednesday: I messed around with some other other stuff I can do with programming, until I satisfied most of my curiosity.</li>
<li>Thursday: I realized I'd been doing something wrong, so I went back to playing with graphviz, until I satisfied myself that the diagrams I was trying to build were probably more trouble than they were worth.</li>
<li>Friday: I explained what the motivation for the diagrams was: helper code for tracking a solo game of Fiasco.</li>
<li>Saturday: I took things easy. Watched a movie and played Vampire Survivors.</li>
<li>Sunday: I did some work for MOTR that I'd previously written up.</li>
<li>Monday: I did a little work on MOTR, and sketched stuff out for later.</li>
</ul>
<p>Next week, I'm going to decide how I want to write up the Fiasco stuff.
I'm pretty experienced with prose, but when I was thinking about this, I got the urge to learn about screenplay formatting.
I'm not sure if I want to make "doing it" contingent on "doing it as a screenplay", but I'd like to learn the basics before I decide one way or the other.
I spent today working on getting a plausible-sounding software toolchain together, so I'm going to try to step back from that for now and focus again on the stuff that goes into that pipeline.</p>
Coding 2022-03-072022-03-07T05:00:00-05:002022-03-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-07:/coding-2022-03-07<p class="first last">Rechecking my work, and forging ahead on some basic progress.</p>
<p>Oh boy, it has been a long time since I went over some of this stuff.
This is for MOTR, and I'm starting with the flake8 wrapper.
Going from the top, we have:</p>
<ul class="simple">
<li><tt class="docutils literal">Program</tt> subclass</li>
<li>flake8 <tt class="docutils literal">Label</tt></li>
<li><tt class="docutils literal">Command</tt> and <tt class="docutils literal">Option</tt> aliases</li>
<li>The necessary <tt class="docutils literal">Command</tt> instance</li>
<li><tt class="docutils literal">Option</tt> instance, which <em>should</em> just need to be wrapped in an <tt class="docutils literal">invocation.Static</tt></li>
<li>"<tt class="docutils literal">builder</tt>" functions, which need a little more work</li>
</ul>
<p>Both of the definitions share a <tt class="docutils literal">Label</tt>, which needs to get reworked into a <tt class="docutils literal">ValueAdaptor</tt>.
Let's see if I can sketch that out.</p>
<div class="highlight"><pre><span></span><span class="nd">@adaptor</span><span class="p">(</span><span class="n">PACKAGE_LABEL</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">package</span><span class="p">(</span><span class="n">python_package</span><span class="p">:</span> <span class="n">PythonPackage</span><span class="p">)</span> <span class="o">-></span> <span class="n">PathStr</span><span class="p">:</span>
<span class="k">return</span> <span class="n">python_package</span><span class="o">.</span><span class="n">root</span>
</pre></div>
<p>That is... probably going to come in useful for other modules.</p>
<p>Anyway, to use it <em>here</em>, I'm going to need something like...</p>
<div class="highlight"><pre><span></span><span class="nd">@adaptive_dynamic</span><span class="p">(</span><span class="n">package</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">srcdir</span><span class="p">(</span><span class="n">objects</span><span class="p">:</span> <span class="n">Objects</span><span class="p">,</span> <span class="n">items</span><span class="p">:</span> <span class="n">Items</span><span class="p">)</span> <span class="o">-></span> <span class="n">Requirements</span><span class="p">[</span><span class="n">Option</span><span class="p">]:</span>
<span class="k">yield from</span> <span class="p">()</span>
<span class="n">package</span> <span class="o">=</span> <span class="n">items</span><span class="p">[</span><span class="n">PACKAGE_LABEL</span><span class="p">]</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">package</span><span class="o">.</span><span class="n">src</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
<span class="k">return</span> <span class="n">basic_option</span><span class="p">(</span><span class="n">objects</span><span class="p">[</span><span class="n">ROOT_LABEL</span><span class="p">]</span> <span class="o">/</span> <span class="n">package</span><span class="o">.</span><span class="n">root</span> <span class="o">/</span> <span class="s2">"src"</span><span class="p">)</span>
<span class="nd">@adaptive_dynamic</span><span class="p">(</span><span class="n">package</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">testdir</span><span class="p">(</span><span class="n">objects</span><span class="p">:</span> <span class="n">Objects</span><span class="p">,</span> <span class="n">items</span><span class="p">:</span> <span class="n">Items</span><span class="p">)</span> <span class="o">-></span> <span class="n">Requirements</span><span class="p">[</span><span class="n">Option</span><span class="p">]:</span>
<span class="k">yield from</span> <span class="p">()</span>
<span class="k">return</span> <span class="n">basic_option</span><span class="p">(</span>
<span class="n">objects</span><span class="p">[</span><span class="n">ROOT_LABEL</span><span class="p">]</span> <span class="o">/</span> <span class="n">items</span><span class="p">[</span><span class="n">PACKAGE_LABEL</span><span class="p">]</span><span class="o">.</span><span class="n">root</span> <span class="o">/</span> <span class="s2">"tests"</span>
<span class="p">)</span>
</pre></div>
<p>This works out to no <em>code changes</em> within the functions, I just need to change the decorator on them, and for that, I first need to write the new decorator.</p>
<p>Let me see if I can bang that out quickly.</p>
<p>...</p>
<p>All right, I'm not really sure about "quickly", but it's out.</p>
<p>And I'm tired.</p>
<p>I'm going to get to bed to try to avoid feeling even lousier.
Hopefully, this entry should provide a solid groundwork for when I get back to this.</p>
<p>Good night.</p>
Coding 2022-03-062022-03-06T05:00:00-05:002022-03-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-06:/coding-2022-03-06<p class="first last">Just didn't feel like having a long entry tonight, or even a medium-length one.</p>
<p>Okay, I did a little writing, but I also did a little work on MOTR.
The extra... flexibility... for <tt class="docutils literal">FlexOut</tt> is coded up and typechecks.
The next thing to do is get back on revising the existing command line wrappers, and writing new ones.
It had better work out this time.</p>
<p>Anyway, I'm going to end this quickly tonight, and see what I'm up for after it publishes.
I hope to get into those rewrites tomorrow.</p>
<p>Good night.</p>
Diary 2022-03-052022-03-05T05:00:00-05:002022-03-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-05:/diary-2022-03-05<p class="first last">I said "Dairy Farm" the first time. Like, "Oh boy, the DPS on those Holsteins is no joke"</p>
<p>Okay, I'm wiped out, but it's fine, but I'm not up for much of a post tonight.</p>
<p>We watched the livestream of the new MST3K episode, and that movie was <em>complete nonsense</em>.
At one point I was like "Wait, we're watching Jonah and the bots, watch Santo, watch something else."
It was super Brechtian, is what I'm saying.</p>
<p>Anything else I want to talk about right now?
Hm...</p>
<p>Oh yeah, I can talk about playing Vampire Survivors.
I've got all the normal unlocks as of v0.3.0c, although I haven't bought any curse, because the Dairy Plant is scary enough without curse.
(Like, maybe I could be convinced to up the curse for the previous levels, but in the Dairy Plant it feels like I have to fight to get to the half hour mark.)</p>
<p>I'm still not psyched up to cheese the reaper fight.
I've got the walkthrough all lined up, and it's just, like, it sounds <em>really</em> frustrating.</p>
<p>Anyway, I'm going to publish this and zone out doing Fiasco-related data entry for later.</p>
<p>Good night.</p>
Diary 2022-03-042022-03-04T05:00:00-05:002022-03-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-04:/diary-2022-03-04<p class="first last">Hopefully, the name of the system won't end up being descriptive.</p>
<p>I wasn't really coordinated today, so I'm going to talk a bit about what I'm planning to write while I take a break from worldbuilding.</p>
<p>Basically, I saw more discussion about <a class="reference external" href="https://bullypulpitgames.com/games/fiasco/">Fiasco</a> recently, and saying that it worked better as a writing aid than as a game.
It's been a while since I played it, but that idea basically makes sense to me; the "game mechanics" aspect of it didn't quite gel for me.
Like, I couldn't quite see the right way into the magic circle, or something.</p>
<p>Point is, that discussion got me to revisit it, and put stuff together to try to learn it as a writing tool, as a change of pace.</p>
<p>I'm using the classic rules because I haven't heard anything about the updated version that makes me go "Yes, I need this", and I have heard about some changes that make it less convenient for some of the stuff I want to try than the classic rules, so, there we go.</p>
<p>I'm trying to ease myself into some of the more advanced playsets, so I'm starting with a really basic one and no extra rules.
One double-edged aspect of not having any other players is, I don't need to schedule this around anything, but at the same time, <em>I don't have obligations to anyone else to actually do this on any kind of time frame</em>.
Hopefully, I'll manage to pick up the pace a bit in the next day or so.</p>
<p>Anyway, I spent too long trying to write this, so I'd better get going.</p>
<p>Good night.</p>
Coding 2022-03-032022-03-03T05:00:00-05:002022-03-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-03:/coding-2022-03-03<p class="first last">Backtracking, then backing off.</p>
<p>It turns out graphviz works a lot better for "lay stuff out in a shape" when I switch the engine to "neato".
I'm having trouble getting the lengths to fully work in all of the cases I want to cover, but I can fake it by throwing some random mathematical operations at it.</p>
<p>I'm going to step back from trying to get the shapes "exactly right", and consider what I need to add to get the rendering right.</p>
<p>What I'm basically doing here is creating a polygon, where the graphviz nodes correspond to the vertices, and to the midpoints of the edges.
(And some other nodes that just exist to try to control the layout.)
In my proof-of-concept code, they just have generated names/labels, but want to be dropping in nodes with custom labels that may end up pulling in other nodes connected to them.</p>
<p>Okay, as I think about that, I think I might want to try harder to express the positions of this stuff in absolute terms, and with the aid of piles of trig...</p>
<p>As I see it, the problem of layout boils down to:</p>
<ul class="simple">
<li>Determine the convex hull of each component</li>
<li>Generate a set of points based on the required graph structure</li>
<li>Generate the Voronoi diagram of the point set</li>
<li>Place the anchor point of each component on its corresponding point, and scale the distances between points until the convex hull is entirely within the corresponding region of the Voronoi diagram</li>
</ul>
<p>All right, I think this, like, should work, but I've put enough effort into this that I'm now willing to try simpler solutions that don't have as much pizzazz.</p>
<p>Okay, I started working on that, and I need to put in more effort, but I'll be fine with a barebones representation for now.</p>
<p>It's getting late,so I'll get back to writing tomorrow.</p>
<p>Good night.</p>
Coding 2022-03-022022-03-02T05:00:00-05:002022-03-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-02:/coding-2022-03-02<p class="first last">And now for something completely different.</p>
<p>Instead of working more on MOTR, I'm looking into a few things.
One is messing with messing with DBus, with an eye towards getting global menu support for applications that I might write in the future.
This might end up not being useful directly, depending on the GUI toolkits I favor, but DBus seems powerful enough that I'll probably manage to find <em>something</em> to do with it at some point.</p>
<p>I'm also trying to put together some code to help with some writing exercises I want to try.
Rather than automating the bookkeeping, like with some of my other projects, my goal here is solely to have some way to nicely collect and lay out data as I enter it in.
My first thought was "Oh, I'll do it in graphviz", and my initial experiments suggest that that will not work, so I'm thinking about writing code to lay out SVGs, because the major issue I ran into was that the nodes just kind of go where they feel like, and I couldn't get any sense of how to do something like say "space out these nodes along a circle, and these other nodes along a bigger circle".</p>
<p>Anyway, I spent quite a while messing with those things and making embarrassing mistakes, so it's late now, but I'll get back into it tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2022-03-012022-03-01T05:00:00-05:002022-03-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-03-01:/weekly-roundup-2022-03-01<p class="first last">Wow, that's February gone.</p>
<p>The weekly backup is taking longer than I was hoping, so we'll see what happens if I write and upload this entry while it's going...</p>
<ul class="simple">
<li>Wednesday: I snarked about the way my laptop works, and made a little progress worldbuilding.</li>
<li>Thursday: I amended the previous snark with information that, in my opinion, just made things worse. I decided to cut the current worldbuilding draft short.</li>
<li>Friday: I wrote some utility stuff for MOTR, and made some notes for later, in case I need to make certain fields more powerful.</li>
<li>Saturday: I made some improvements to my design for part of MOTR, and planned what to work on next.</li>
<li>Sunday: I did some cleanup, which I didn't really describe, and some planning, which I did.</li>
<li>Monday: Now that the <tt class="docutils literal">Flex</tt> classes are almost done, I started checking over the code that would use them, to make sure they can handle everything they need to. As it happens, they can't quite, so I've got a small amount of work left to do.</li>
</ul>
<p>Next week, I'm going to shift gears a bit, but I'm not committing to <em>how</em>, yet.</p>
Coding 2022-02-282022-02-28T05:00:00-05:002022-02-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-28:/coding-2022-02-28<p class="first last">It needs a bit of work, but probably not too much.</p>
<p>Earlier today, I tried to make the <tt class="docutils literal">DynamicMeta</tt> class more robust.
We'll see how that works out for me.</p>
<p>Anyway, now I need to refresh my memory about what the command-line wrapper modules do, and what they should do, and figure out how to get between those states.</p>
<p>So, what I think I want is to have a very abstract interface, where the modules are ultimately defining functions that produce <tt class="docutils literal">Dynamic[Command[Script, Any]]</tt> objects.
(They can also have functions that produce intermediate values like <tt class="docutils literal">Invocation[Module, Any]</tt>.)</p>
<p>Basically, given a <tt class="docutils literal">Dynamic[Command[Script, Any]]</tt>, which potentially includes other <tt class="docutils literal">Dynamic[Command[Script, Any]]</tt> objects, that can be fed into a utility function that I should <em>probably</em> move into <tt class="docutils literal">invocation.py</tt>, that should be all we need to set up the argument to <tt class="docutils literal">api.build()</tt>.</p>
<p>Let's take a look at <tt class="docutils literal">flake8.py</tt>.
It has:</p>
<ul class="simple">
<li>A <tt class="docutils literal">Program</tt> subclass</li>
<li>A <tt class="docutils literal">Label[Pip]</tt> for installing and running flake8</li>
<li>A <tt class="docutils literal">Command</tt> alias</li>
<li>An <tt class="docutils literal">Option</tt> alias</li>
<li><tt class="docutils literal">Command</tt> and <tt class="docutils literal">Option</tt> definitions</li>
<li><tt class="docutils literal">Dynamic[Option]</tt> objects</li>
</ul>
<p>Under the <tt class="docutils literal">Invocation</tt> paradigms, those last two need their <tt class="docutils literal">labels</tt> arguments broken out into a <tt class="docutils literal">ValueAdaptor</tt>, and to be converted into <tt class="docutils literal">AdaptiveDynamic</tt> instances.
It requires an interesting collection of <tt class="docutils literal">Part</tt>s to handle the HTML output, so I might need to mess around with that a bit.
Basically, it's a situation where there's an <tt class="docutils literal">Input</tt> <tt class="docutils literal">Arg</tt> that needs to be created, and it'll have a predictable child as an <tt class="docutils literal">Output</tt> <tt class="docutils literal">Extra</tt>.
What this says to me is that I should consider reworking <tt class="docutils literal">FlexOut</tt>.
Currently, when <tt class="docutils literal">FlexOut</tt> has <tt class="docutils literal">make_parent = True</tt>, it adds the parent to <tt class="docutils literal">extra_io</tt>.
So...</p>
<p>Would it work to convert this to some kind of callback that turns the parent input into a <tt class="docutils literal">CmdMeta</tt>?
Since there are some... issues potentially, with creating arbitrary <tt class="docutils literal">CmdMeta</tt> objects, then my feeling is that I want to create some form of union of classes that implement the callbacks.
I'm going to write this down for now, rather than mess with the code more.</p>
<p>There is more to evaluate in the other wrappers, but I'd like to wind down for now, so I'm done for tonight.</p>
<p>Good night.</p>
Coding 2022-02-272022-02-27T05:00:00-05:002022-02-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-27:/coding-2022-02-27<p class="first last">Intensive refactor.</p>
<p>I spent a lot of today cleaning stuff up.
It's... not quite done yet, unfortunately, but I need a bit of a break.
My plan now is:</p>
<ul class="simple">
<li>Finish updating the <tt class="docutils literal">DynamicMetadata</tt> class</li>
<li>Review the existing wrapper code</li>
<li>Update the wrappers</li>
<li>Write new wrappers</li>
<li>Review the overall code base in terms of names and organization</li>
<li>Consider reorganizing the tests, and possibly including <tt class="docutils literal"><span class="pre">limit-coverage</span></tt></li>
<li>Write new tests to get the coverage up to full</li>
</ul>
<p>For now, I'm going to take things easy again, and see what I'm up for working on tomorrow.
For now, I don't know, take things easy one way or another.</p>
<p>Good night.</p>
Coding 2022-02-262022-02-26T05:00:00-05:002022-02-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-26:/coding-2022-02-26<p class="first last">Satisfying, but hard-to-describe, progress.</p>
<p>I didn't put in much time on MOTR tonight, but I made some really nice progress on the <tt class="docutils literal">Flex</tt> classes by reworking the Protocol to expose what was formerly a convenience method, and move the logic specific to the "old" methods into the wrapper classes.
With this, the <tt class="docutils literal">Flex</tt> classes are complete, and my priorities now are:</p>
<ul class="simple">
<li>Remove the <tt class="docutils literal">flex</tt> functions</li>
<li>Update stuff related to the <tt class="docutils literal">DynamicMeta</tt> class</li>
<li>Update some names</li>
<li>Implement functionality required by the motrfile</li>
<li>Maybe I missed something?</li>
</ul>
<p>Anyway, I'm going to get ready for bed now and be glad that I finished this up.</p>
<p>Good night.</p>
Coding 2022-02-252022-02-25T05:00:00-05:002022-02-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-25:/coding-2022-02-25<p class="first last">I need this, okay?</p>
<p>I had a miserable day at work today, all inflicted by technology, so to wind down, I hacked a bit on MOTR, which I can at least reliably <em>understand</em>.</p>
<p>The specific thing I worked on today was a helper class for writing validators for use on <a class="reference external" href="https://www.attrs.org/en/stable/">attrs</a> classes.
This was inspired by noticing that some of the <tt class="docutils literal">flex</tt> functions have validation logic, that I haven't replicated on the <tt class="docutils literal">Flex</tt> classes yet.
Some of the stuff I thought of didn't exist in the code before, but basically makes sense.</p>
<p>One unfortunate thing that occurred to me as I worked on this is that there's some functionality that I'm not quite sure how to support.
In light of that, I'm going to pare it back until I have a need for it.</p>
<p>The feature in question was dynamically naming the output produced by a <tt class="docutils literal">FlexOut</tt>.
Thinking about this, I came up with a plan for supporting this, but it's so fiddly that I'm not going to try without a reason.
Basically, instead of storing the names directly as a <tt class="docutils literal">Dynamic</tt>...</p>
<ul class="simple">
<li>Add a type variable to <tt class="docutils literal">InputAccumulator</tt> and <tt class="docutils literal">ValueAdaptor</tt>, so I can control the type produced by the <tt class="docutils literal">Dynamic</tt></li>
<li>If that works, give <tt class="docutils literal">FlexOut</tt> an <tt class="docutils literal">InputAccumulator[Sequence[str]]</tt>; if that doesn't work out, give it a sequence of <tt class="docutils literal">InputAccumulator</tt></li>
<li>In either case, also give it a sequence of <tt class="docutils literal">ValueAdaptor</tt></li>
<li>When implementing a method from the <tt class="docutils literal">Flex</tt> interface, filter out any <tt class="docutils literal">ValueAdaptor</tt> instances that don't correspond to what was passed in, and <em>then</em> perform the accumulation.</li>
</ul>
<p>This sounds like a solid idea, but I don't really want to try it until I've determined that there's a need.</p>
<p>Anyway, I'm done for tonight, and I'm going to get ready for bed.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2022-02-242022-02-24T05:00:00-05:002022-02-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-24:/worldbuilding-ksa-2022-02-24<p class="first last">Just felt kind of bad and gross today, so I cut things short.</p>
<p>Minor thing I missed yesterday: the fact that I'm using SDDM instead of LightDM was apparently somehow relevant.
I...</p>
<p><em>Why</em>?
<em>Why computers</em>?</p>
<p>Nevertheless...</p>
<p>I thought about this, and I decided that I'm done for now.
I mean, for all that this is not as long as it could be, it's still rather overdetailed already.</p>
<p>Anyway, I'm going to take care of some other stuff, and try to take it easy for a bit.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2022-02-232022-02-23T05:00:00-05:002022-02-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-23:/worldbuilding-ksa-2022-02-23<p class="first last">The point of the "*checks notes*" is to communicate incredulity.</p>
<p>Before I start writing up stuff for worldbuilding, I want to say that my laptop seems to be working fine now, without any of the rough edges introduced by previous workarounds, and I want to thank the <a class="reference external" href="https://github.com/fish-shell/fish-shell/issues/8741#issuecomment-1047820309">fish devs</a> for</p>
<p>*checks notes*</p>
<p>providing a snippet to copy into <tt class="docutils literal">config.fish</tt>, which prevents</p>
<p>*checks notes*</p>
<p>snapd from clobbering</p>
<p>*checks notes*</p>
<p><tt class="docutils literal">$XDG_DATA_DIRS</tt>, which resolves the</p>
<p>*checks notes*</p>
<p>segfault in</p>
<p>*checks notes*</p>
<p>ksplashqml, which prevented</p>
<p>*checks notes*</p>
<p>Plasma from starting up properly.</p>
<p>...</p>
<p>Computers!</p>
<p>Anyway, let's see what I can pick off when it comes to worldbuilding.</p>
<p>I did a little work, so, let's see what's still needed...</p>
<ul class="simple">
<li>Notes on magic;
Started filling stuff in;
Unfortunately, a lot of this was in my head, so I'll need to work out some of the details from scratch.</li>
<li>Notes on how to play the different subspecies
...
I forget what I meant by this.
Oops.</li>
</ul>
<p>When I started working on this draft, I had some ideas about, like an overarching sensible organization.
It looks like I'm going to have to accept that the layout of information is going to be, for now, slapdash and inscrutable.</p>
<p>Anyway, in light of that second bullet, I should be done with the current draft once I flesh out magical techniques a bit more.</p>
<p>It's late, and I'm nearly done.
I'd best take a break now, and leave the rest for the next few days.</p>
<p>Good night.</p>
Weekly Roundup 2022-02-222022-02-22T05:00:00-05:002022-02-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-22:/weekly-roundup-2022-02-22<p class="first last">Speaking as someone who currently has these problems, they sound extremely fake.</p>
<ul class="simple">
<li>Wednesday: I added onto the worldbuilding draft.</li>
<li>Thursday: I continued to add onto the worldbuilding draft.</li>
<li>Friday: I added a bit more onto the worldbuilding draft.</li>
<li>Saturday: I mentioned The Weird Growth On My Arm That We Only Know What It Isn't.</li>
<li>Sunday: My laptop ushered in another important milestone towards the Year of Linux on the Desktop, by having the desktop login code segfault because I was using <a class="reference external" href="https://fishshell.com/">fish</a> as my shell instead of <a class="reference external" href="https://www.gnu.org/software/bash/">bash</a>.</li>
<li>Monday: I figured that out, and got some work done on MOTR.</li>
</ul>
<p>Next week, I'm going to work on whatever.
I probably <em>should</em> take a break from MOTR until the weekend, but I made some good breakthroughs once I got my laptop working again, and it looks like a straight shot to getting this stuff implemented.</p>
Coding 2022-02-212022-02-21T05:00:00-05:002022-02-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-21:/coding-2022-02-21<p class="first last">Laptop situation upgraded from "borderline nonfunctional" to "somewhat uncanny".</p>
<p>My laptop is still broken in weird ways, but it's now mostly working, thanks to some tips on a workaround that I got from Launchpad.
There's supposed to be a bug report, but there's so much going on that I'm kind of not sure how to isolate a single bug out of everything that I'm seeing.</p>
<p>Anyway, I did a little work fixing bugs in unused code paths in MOTR yesterday, but let's see what I can do in terms of filling in the stubs I wrote.</p>
<p>First up is the <tt class="docutils literal">as_arg</tt> method for <tt class="docutils literal">FlexIn</tt>.
This has to convert a <tt class="docutils literal">Dynamic[Input[PathStr]]</tt> into a <tt class="docutils literal">Dynamic[CmdMeta]</tt>.
The outermost layer of this is accomplished with the <tt class="docutils literal">dynamic.reduce</tt> function, which takes a reducer function, a <tt class="docutils literal">Dynamic</tt> object to provide a template for the arguments to the reducer, a set of <tt class="docutils literal">Key</tt> objects to iterate over, and an initial value.
For this method, the values break down as follows:</p>
<ul class="simple">
<li>The initial value is the empty <tt class="docutils literal">CmdMeta</tt>.</li>
<li>The keys are the argument to the method; the types involved may need to change somewhere.</li>
<li>If the prefix value is <tt class="docutils literal">None</tt>, then the template is just the result of mapping the <tt class="docutils literal">FlexIn</tt>'s wrapped value into a <tt class="docutils literal">CmdMeta</tt>, which is easy.
If the prefix is not <tt class="docutils literal">None</tt>, then it's as above, but mapping the prefix and the wrapped value.</li>
<li>The reducer is <tt class="docutils literal">CmdMeta.combine</tt>.</li>
</ul>
<p>Well, let's see what kind of problems this gives me.</p>
<p>Not too bad.
All of the problems were misunderstandings on my end, that I cleared up quickly.</p>
<p>Anyway, there are five more methods to cover...
Next up, in terms of ease versus utility, I can either take a look at the <tt class="docutils literal">as_extra</tt> method for <tt class="docutils literal">FlexIn</tt>, or the <tt class="docutils literal">as_arg</tt> method for <tt class="docutils literal">FlexOut</tt>, then do the other one of those, then <tt class="docutils literal">as_extra</tt> for <tt class="docutils literal">FlexOut</tt>.
After that, I can do the <tt class="docutils literal">as_env_var</tt> methods for completeness, but I don't think I need those right now.</p>
<p>For now, I'm going to take a little break from the code, and take a look at it with fresh eyes later.</p>
<p>Good night.</p>
Diary 2022-02-202022-02-20T05:00:00-05:002022-02-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-20:/diary-2022-02-20<p class="first last">My laptop is full of mysteries, and aargh...</p>
<p>Early entry today because my laptop is freaking out in ways I don't understand, and I'm just glad I've gotten enough working to post this.</p>
<p>Unless I get some kind of epiphany on how to fix this, my weekend is shot.</p>
<p>Good night.</p>
Diary 2022-02-192022-02-19T05:00:00-05:002022-02-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-19:/diary-2022-02-19<p class="first last">The human body is full of mysteries, but I'd rather not deal with this one.</p>
<p>Okay, I tried to take things easy today, since I've been kind of wiped out these last few days.</p>
<p>One thing that's been ongoing for the past few weeks is, I've been keeping tabs on a Mysterious Growth on my arm.
It's been poked and scanned, and it's not totally clear what it is, but it's shrunk considerably since it suddenly showed up, so I'm not really worried, just kind of... annoyed that we only seem to know what it <em>isn't</em>.
The plan is to see if it goes away in a few months, or does something surprising before then.</p>
<p>I waited a bit to see if I'd come up with something else to say, and, I guess not.
I should get to bed.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2022-02-182022-02-18T05:00:00-05:002022-02-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-18:/worldbuilding-ksa-2022-02-18<p class="first last">My rate of progress makes sense in light of the fact that I'm <em>really</em> sleepy.</p>
<p>I did a little work, so, let's see what's still needed...</p>
<ul class="simple">
<li>Notes on magic;
Started filling stuff in;
I put in some general notes on all magic, and now I need to fill in a bunch of specifics.</li>
<li>Notes on technology</li>
<li>Military history stuff</li>
<li>Notes on how to play the different subspecies</li>
</ul>
<p>I recognize that I'm only picking off a few bullets at a time, but, counterpoint, I'm really tired, and I'm glad to get anything done right now.</p>
<p>I guess I'm not going to finish with this this week, unless maybe I do some work on it during the day over the weekend.</p>
<p>Anyway, I want to take things easy now.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2022-02-172022-02-17T05:00:00-05:002022-02-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-17:/worldbuilding-ksa-2022-02-17<p class="first last">Getting the easy bits copied and transcribed.</p>
<p>Okay, let's see about that list.
Got a bit done before I started on this entry, so now what remains is...</p>
<ul class="simple">
<li>Notes on magic;
Added a partial outline</li>
<li>Additional notes on dragons (including legendary figures)</li>
<li>Notes on technology</li>
<li>Military history stuff</li>
<li>Notes on how to play the different subspecies</li>
<li>Some flavor derived from what the dragons in this setting sound like.</li>
</ul>
<p>I'm going to call things here.
It was a quick bit of work, but it's progress, and I was tired all day, so I'm not going to push things.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2022-02-162022-02-16T05:00:00-05:002022-02-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-16:/worldbuilding-ksa-2022-02-16<p class="first last">There are a lot of list items, but most of this stuff is pretty short in the notes, and will end up pretty short in the rough draft.</p>
<p>Let's see what remains in the notes and my head.</p>
<p>In my head, there are some ideas about the usage of the magic system.
Basically, different disciplines that apply to different kinds of magic.
Also, some details about how specific bits of the magic system might "really work".</p>
<p>In the notes, I've got...</p>
<ul class="simple">
<li>Details about some cultures' languages; I'll <em>probably</em> leave these out of the first draft.</li>
<li>Some sections that I'd mixed up where they went to, so I just now fixed that up.</li>
<li>A geographical feature where nobody <em>lives</em>, so it doesn't really fit in with discussing settlements.</li>
<li>Notes on technology.</li>
<li>Military history that might not be valid any more.</li>
<li>Some literary history that I definitely need to fit in.
It's stuff about the dragons in the setting.</li>
<li>A discussion of some of the more mysterious locations.</li>
<li>Notes on which subspecies "make sense" for player characters if using this as an RPG sourcebook.
I'll need to reconsider these on general principle.</li>
<li>Some key notes about subspecies characteristics that people might assume incorrect things about.</li>
<li>A few minor details.</li>
<li>Some flavor derived from what the dragons in this setting sound like.</li>
</ul>
<p>Okay, that's good to work with.
I don't want to think too hard about how to organize all this, but I do want to think <em>some</em>, before I start putting this all together.</p>
<p>Anyway, that feels like a good place to call it.
Tomorrow, I'll work on the geographic stuff first, then, I don't know, outline some stuff by hand.</p>
<p>Good night.</p>
Weekly Roundup 2022-02-152022-02-15T05:00:00-05:002022-02-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-15:/weekly-roundup-2022-02-15<p class="first last">Good forward progress, once again.</p>
<ul class="simple">
<li>Wednesday: I wrote a bit more worldbuilding information, and learned that I'm <em>still</em> not used to rough drafts being... rough.</li>
<li>Thursday: I reminded myself of one of the motivations for the worldbuilding project, which is to come up with stuff that makes me go "that's cool".</li>
<li>Friday: I made more progress transcribing stuff.</li>
<li>Saturday: I finished with the first pass on the worldbuilding draft, and decided to take a break from it for a few days.</li>
<li>Sunday: I started putting my notes on MOTR into practice again.</li>
<li>Monday: I made a few minor tweaks to the code.</li>
</ul>
<p>Next week, I'm going to get back to the worldbuilding stuff during the week, and maybe work on MOTR on the weekend.</p>
Coding 2022-02-142022-02-14T05:00:00-05:002022-02-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-14:/coding-2022-02-14<p class="first last">Tantalizingly close, but I don't want to push myself right now.</p>
<p>Okay, let's see.
I don't know how much more code I'm up for touching tonight, but I made some improvements earlier today by noticing that some layers in the new code were redundant, and stripping them out.</p>
<p>At this point, the API should be mostly done when I reimplement the <tt class="docutils literal">flex</tt> functions as methods on the <tt class="docutils literal">Flex</tt> classes, and then start using the <tt class="docutils literal">Invocation</tt> class to implement specific programs.</p>
<p>I think for now, I'm just going to put in explanatory comments for me to act on later.</p>
<p>For now, I'm going to look for a way to relax, because I'm kind of wound up.</p>
<p>Good night.</p>
Coding 2022-02-132022-02-13T05:00:00-05:002022-02-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-13:/coding-2022-02-13<p class="first last">Kind of a weird <tt class="docutils literal">Flex</tt></p>
<p>All right, I want to get back to work on MOTR, but I'm feeling a little fidgety and jittery.
Here's what I've got...</p>
<p>The <tt class="docutils literal">Part</tt> alias in <tt class="docutils literal">invocation.py</tt> currently uses <tt class="docutils literal">_input_accumulator.InputAccumulator</tt> directly.</p>
<p>This needs to be changed to a <tt class="docutils literal">Union[Argument, EnvVar, Extra]</tt>, where those classes need to be written.
These wrap classes that implement the <tt class="docutils literal">Flex</tt> protocol.</p>
<p>So, let's start by building up the higher-level interfaces...</p>
<p><tt class="docutils literal">Flex</tt> protocol and consumer types, done.
Now to just hook it up at the high level.
And...
Hm.
There are issues.
I think they can be addressed... like... this...
Okay, that partly works...
And I've figured out the rest.</p>
<p>The code is pretty gnarly, so I'm going to have to revisit how I implement this later.</p>
<p>I got on this early, so I'm going to take a break for a bit and get back to this later.
I think the next thing I want to do when I come back, is move some of this code I just added to its own module.</p>
<p>Okay, I'm doing that, and I'm going to call it a night once I get flake8 passing.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2022-02-122022-02-12T05:00:00-05:002022-02-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-12:/worldbuilding-ksa-2022-02-12<p class="first last">Hopefully just another week or so before I finish the current draft.</p>
<p>Well, after a bit more work, I'm basically done with my first pass over my worldbuilding notes.
I'd like to take a bit of a break from this, but I should be able to finish things up pretty quickly once I've taken that break.</p>
<p>I'd like to have something else to say here but... I guess I don't?</p>
<p>Thinking about things I could talk about...
It might make sense to discuss the tools I'm using, to see if they click for anyone else to use in their own projects.</p>
<p>But, I don't have my thoughts in order for that right now, and I'd rather just kick back and take things easy for now.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2022-02-112022-02-11T05:00:00-05:002022-02-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-11:/worldbuilding-ksa-2022-02-11<p class="first last">It happened again.</p>
<p>At this point, I seem to be about halfway through the other notes file.
And I <em>know</em> some of that isn't going into the current draft.
So, the draft should be ready in a few days.</p>
<p>I still don't want to go into detail, but it continues to feel good to revisit the ideas I had and go "Oh yeah! I did all of this because I thought it was cool!"</p>
<p>(Worry not, I'm not going for "It's cool so it doesn't matter that it doesn't make sense".
I'm going for "It's cool <em>because</em> it makes sense, despite being so outlandish".
With, admittedly, a bit of "Well, this part is clearly magic, because it doesn't make physical sense".
The way I see it, I should strive for realism in people's responses to a situation, and in the behavior of the world around them, I should strive for <em>consistency</em>.)</p>
<p>Anyway, I'm going to wrap things up for now.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2022-02-102022-02-10T05:00:00-05:002022-02-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-10:/worldbuilding-ksa-2022-02-10<p class="first last">Another one of those "too much work to write about the work" nights.</p>
<p>Okay, it's super late, so I'm going to make this super short.</p>
<p>I have two main notes files (that I remember...), and I've transcribed most of one of them.
In reading over it, I reminded myself of some of the things that got me excited about this setting in the first place, so that was nice.</p>
<p>Anyway, good progress, more work to be done, best chance of doing it if I get to sleep soon, shouldn't dawdle!</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2022-02-092022-02-09T05:00:00-05:002022-02-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-09:/worldbuilding-ksa-2022-02-09<p class="first last">Just looking at my own brain and going "This isn't fair!"</p>
<p>I got a few more pages drafted, and it appears that <em>every single writing project</em> is going to require me to re-learn to put in my rough draft without worrying about quality.</p>
<p>I'm just going to have to settle for scrawling stuff out and not worrying for now about "Is this in a sensible order?" or "Can anyone else understand this?".</p>
<p>I feel like I should apologize for the fact that, even though I have this blockage everywhere else, I <em>don't</em> have it for Three Dollar Quill.
I don't know.</p>
<p>Anyway, I'll settle for making a bit of progress a day, then getting everything together and trying to wrangle it into shape.</p>
<p>There isn't really much else to say.
I wanted to do the thing some.
I did the thing some.
Objective attained.</p>
<p>I'm going to play Vampire Survivors or something.</p>
<p>Good night.</p>
Weekly Roundup 2022-02-082022-02-08T05:00:00-05:002022-02-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-08:/weekly-roundup-2022-02-08<p class="first last">Hopefully, this all translates into progress.</p>
<ul class="simple">
<li>Wednesday: I took some notes for the math writing that I'm totally working on...</li>
<li>Thursday: I found the worldbuilding notes that I want to rework into the reference document.</li>
<li>Friday: I worked on... stuff... and mostly took things easy.</li>
<li>Saturday: I did some planning for MOTR that's going to be necessary to keep things from grinding to even more of a halt.</li>
<li>Sunday: I did some prototyping based on the planning.</li>
<li>Monday: I iterated on the prototyping.</li>
</ul>
<p>Next week, I'm going to plan for taking it easy.
Some things have come up that make it so I'm even less able to be confident about hitting any kind of pace or goal.</p>
Coding 2022-02-072022-02-07T05:00:00-05:002022-02-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-07:/coding-2022-02-07<p class="first last">Either so close, or so far...</p>
<p>I spent some time tweaking the prototype.
Right now, it's at a point where I can kind of see how it'll come together, but I think I need some time to leave it be, and revisit it to see if it all makes sense later.</p>
<p>I'm not up for thinking or writing about too much else today, so I'm going to have this be a short entry, and wind down early-ish.</p>
<p>Good night.</p>
Coding 2022-02-062022-02-06T05:00:00-05:002022-02-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-06:/coding-2022-02-06<p class="first last">Let's see what I'm missing.</p>
<p>Okay, I've decided that if I want to get anywhere with the <tt class="docutils literal">Flex</tt> concept, I need to do some prototyping.</p>
<p>So, let's see what I've got...</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>
<span class="kn">import</span> <span class="nn">typing</span>
<span class="kn">import</span> <span class="nn">attr</span>
<span class="n">T_co</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T_co"</span><span class="p">,</span> <span class="n">covariant</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">FlexIn</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">Generic</span><span class="p">[</span><span class="n">T_co</span><span class="p">]):</span>
<span class="nb">input</span><span class="p">:</span> <span class="n">Dynamic</span><span class="p">[</span><span class="n">Input</span><span class="p">[</span><span class="n">T_co</span><span class="p">]]</span>
<span class="k">def</span> <span class="nf">as_arg</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">FlexIn</span><span class="p">[</span><span class="n">PathStr</span><span class="p">],</span> <span class="n">keys</span><span class="p">)</span> <span class="o">-></span> <span class="n">Requirements</span><span class="p">[</span><span class="o">...</span><span class="p">]:</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">as_env_var</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">FlexIn</span><span class="p">[</span><span class="n">PathStr</span><span class="p">],</span> <span class="n">keys</span><span class="p">)</span> <span class="o">-></span> <span class="n">Requirements</span><span class="p">[</span><span class="o">...</span><span class="p">]:</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">as_extra</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">FlexIn</span><span class="p">[</span><span class="n">Target</span><span class="p">],</span> <span class="n">keys</span><span class="p">)</span> <span class="o">-></span> <span class="n">Requirements</span><span class="p">[</span><span class="o">...</span><span class="p">]:</span>
<span class="o">...</span>
<span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">FlexOut</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">Generic</span><span class="p">[</span><span class="n">T_co</span><span class="p">]):</span>
<span class="nb">input</span><span class="p">:</span> <span class="n">Dynamic</span><span class="p">[</span><span class="n">Input</span><span class="p">[</span><span class="n">PathStr</span><span class="p">]]</span>
<span class="nb">map</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Callable</span><span class="p">[[</span><span class="n">PathStr</span><span class="p">],</span> <span class="n">T_co</span><span class="p">]</span>
<span class="n">dynamic_output</span><span class="p">:</span> <span class="n">Dynamic</span><span class="p">[</span><span class="n">typing</span><span class="o">.</span><span class="n">Sequence</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span>
<span class="n">target_key</span><span class="p">:</span> <span class="n">Key</span><span class="p">[</span><span class="n">FlexIn</span><span class="p">[</span><span class="n">T_co</span><span class="p">]]</span>
<span class="n">make_parent</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">def</span> <span class="nf">as_arg</span><span class="p">(</span>
<span class="bp">self</span><span class="p">:</span> <span class="n">FlexOut</span><span class="p">[</span><span class="n">PathStr</span><span class="p">],</span>
<span class="n">keys</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">Requirements</span><span class="p">[</span><span class="o">...</span><span class="p">]:</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">as_env_var</span><span class="p">(</span>
<span class="bp">self</span><span class="p">:</span> <span class="n">FlexOut</span><span class="p">[</span><span class="n">PathStr</span><span class="p">],</span>
<span class="n">keys</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">Requirements</span><span class="p">[</span><span class="o">...</span><span class="p">]:</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">as_extra</span><span class="p">(</span>
<span class="bp">self</span><span class="p">:</span> <span class="n">FlexOut</span><span class="p">[</span><span class="n">Target</span><span class="p">],</span>
<span class="n">keys</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">Requirements</span><span class="p">[</span><span class="o">...</span><span class="p">]:</span>
<span class="o">...</span>
<span class="n">FlexType</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">Union</span><span class="p">[</span><span class="n">FlexIn</span><span class="p">[</span><span class="n">T_co</span><span class="p">],</span> <span class="n">FlexOut</span><span class="p">[</span><span class="n">T_co</span><span class="p">]]</span>
<span class="n">Flex</span> <span class="o">=</span> <span class="n">FlexIn</span><span class="p">,</span> <span class="n">FlexOut</span>
</pre></div>
<p>This should be the basic outline of the <tt class="docutils literal">Flex</tt> types, although it does need some work to nail down many of the details.</p>
<p>I did give this a few iterations just now, so this should illustrate most of the issues I need to deal with.</p>
<p>For now, I'm glad to have thought some of this through, and I'll look into putting this together with some of my notes.
If I can nail down the right type for the <tt class="docutils literal">keys</tt> arguments, I should be able to prove out these interfaces by replacing the existing stuff with them.</p>
<p>Right now, I want to rest.</p>
<p>Good night.</p>
Coding 2022-02-052022-02-05T05:00:00-05:002022-02-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-05:/coding-2022-02-05<p class="first last">Trying to get this to make sense...</p>
<p>In some (entirely predictable) circumstances, I'm not up for serious work right now, but some stuff is occurring to me about MOTR.</p>
<p>I was talking earlier about creating <tt class="docutils literal">Flex</tt> types to rearrange the overall flow of the <tt class="docutils literal">Invocation</tt> processing.
Well, here's something from earlier that I just remembered.
While arguments and environment variables can be handled somewhat reasonably, "extra" inputs and outputs are just different enough that I think that I need to parameterize the <tt class="docutils literal">Flex</tt> types.</p>
<p>But, if I go down that road, I'm going to need to be really careful.</p>
<p>Because, let's see...</p>
<p>The whole reason that "extra" inputs and outputs <em>need</em> this additional flexibility is that the coverage flow needs to support deletes.</p>
<p>Now, think this through...</p>
<p>The <tt class="docutils literal">coverage erase</tt> command needs to be invoked together with the <tt class="docutils literal">coverage run</tt> commands so they get the exact same set of flex arguments.
I forget what order I thought things should go in, but this kind of seem like maybe the output-focused <tt class="docutils literal">Flex</tt> objects need an adaptor function to handle their type parameter, while the input versions can just use the parameter directly.</p>
<p>I think that's about as much design work as I can handle for tonight, so I'm going to wrap up and take the rest of the night easy.</p>
<p>Good night.</p>
Diary 2022-02-042022-02-04T05:00:00-05:002022-02-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-04:/diary-2022-02-04<p class="first last">Okay, so I might have played <em>a lot</em> of Vampire Survivors.</p>
<p>I'm still waiting on feedback on the worldbuilding stuff, and I ended up mostly taking today easy, which, frankly, is fine with me.
I did spend some time on a project that I don't remember if I've described, but I wouldn't mind describing it, at some later point when it's more fleshed out.</p>
<p>Tomorrow afternoon, I should have more of a chance to work on stuff like worldbuilding or pinning down MOTR's design.</p>
<p>For now, I really want and need to get to sleep so I can get something like a proper night's rest.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2022-02-032022-02-03T05:00:00-05:002022-02-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-03:/worldbuilding-ksa-2022-02-03<p class="first last">Getting ready for a serious expansion.</p>
<p>I spent most of today doing other stuff, but I did take the time to, like, remind myself where my worldbuilding notes are, so I can start giving them a proper writeup.</p>
<p>Before that, I wanted to make sure that the format I have from a really early draft of the worldbuilding document is, like, good, so I gave it to my wife to have a look.</p>
<p>There's not enough to any of this to show off yet, but I think I'd like to try to get a draft published somewhere by the end of the year.</p>
<p>Instead of thinking about that further, I'm going to wrap things up for now and get to bed.</p>
<p>Good night.</p>
Diary 2022-02-022022-02-02T05:00:00-05:002022-02-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-02:/diary-2022-02-02<p class="first last">Just, so many layers to some of this...</p>
<p>I ended up mostly focusing on notes for Missable Mysteries.
Some of these are not so much "notes" as "venting", but I decided that it's best to get all of my thoughts down, and sort through them later.</p>
<p>I really don't want to talk more about what exactly I'm taking notes <em>on</em>, because I worry that the nature of "the document" would distract from my educational aims.</p>
<p>Anyway, I left things too late to write more, but at least I made some progress on what I was actually working on.
I should wrap up.</p>
<p>Good night.</p>
Weekly Roundup 2022-02-012022-02-01T05:00:00-05:002022-02-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-02-01:/weekly-roundup-2022-02-01<p class="first last">Progress and setbacks</p>
<ul class="simple">
<li>Wednesday: I outlined what I expect the worldbuilding poem to convey.</li>
<li>Thursday: I started revising the rest of the worldbuilding document, and ran into some tooling issues.</li>
<li>Friday: I realized that solving those tooling issues won't be straightforward, and outlined some other tasks to work on later.</li>
<li>Saturday: I fixed the tooling issues with the worldbuilding document, thereby opening the way to <em>so many</em> fun diversions in the future.</li>
<li>Sunday: I got back into MOTR, and began to run into... problems.</li>
<li>Monday: I tried to work out the proper solution to my issues, and I realized it's just not happening without an actual effort at design, because the correct way to accomplish this level of abstraction that I want, has too many moving pieces under the hood to fit in my head right now.</li>
</ul>
<p>Next week, I'm going to work on worldbuilding, and take some notes that will eventually feed into an actual plan for Missable Mysteries.</p>
Coding 2022-01-312022-01-31T05:00:00-05:002022-01-31T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-31:/coding-2022-01-31<p class="first last">Don't worry, I don't understand any of this at this point.</p>
<p>All right.
The flake8-black maintainers stepped up pretty quickly, so everything was working right by sometime this morning.
Thanks for that.</p>
<p>I wrote a basic evolution method, and set it up to be used.
There are a more to go.
I think for now, I'll focus on the ones without tricky issues.</p>
<p>And, that didn't fully work, because the logic for combining <tt class="docutils literal">Dynamic</tt> metadata is annoyingly fiddly.
(A lowlight of this effort was realizing that I'd forgotten that I'd implemented some required logic, because it was in a function with a name that <em>did not indicate</em> that it should be there.)</p>
<p>Before I touch any more of this, I'm going to go over the <tt class="docutils literal">flex</tt> concept, carefully.</p>
<p>The basic idea is that a given invocation will have some values that vary, not based on the base structure of the invocation, but based on values passed into the function that constructs the invocation.
To produce the required variation, the caller needs to provide a mapping from registry values to something that can fit in a path.
Let's call one of these sites of caller-parameterized variation <tt class="docutils literal">Flex</tt> objects.
A given invocation can have many <tt class="docutils literal">Flex</tt> objects, and what they do is take a set of keys and associated functions, and pass that data into each <tt class="docutils literal">Flex</tt> object.</p>
<p>This promises to get even more confusing, because this isn't the order that the current code does things, but maybe it <em>should</em> do them in this order.</p>
<p>Anyway, I've got a scenario I'm trying to work out that's confusing me.
There are two broadly different "modes" of carrying out the <tt class="docutils literal">Flex</tt> operation, based on whether the goal is to produce an "input" or an "output" to the invocation.
At the invocation level, <tt class="docutils literal">Flex</tt>es are introduced in "output" mode, and reused in "input" mode.
The result of this is that there could be a <tt class="docutils literal">Flex</tt> that got several keys associated with it in "output" mode, and then, when it's used in "input" mode, the object it produces must not provide any keys that aren't required by outputs from the invocation.
The only way I see right now to make this vaguely tractable is to require that all outputs are specified using <tt class="docutils literal">Flex</tt> objects, which ought to be fine in this context.</p>
<p>So, what do we know about this situation?
Well, "output" mode <tt class="docutils literal">Dynamic</tt>s require that no associated <tt class="docutils literal">Dynamic</tt>s provide a key that is not known to them, which means that the keys available for <tt class="docutils literal">Flex</tt> operations must be a superset of all keys provided by any part of the invocation.
And <em>that</em> means that when we carry out a <tt class="docutils literal">Flex</tt> in input mode, we want the resulting <tt class="docutils literal">Dynamic</tt> to provide the intersection of its keys and the provided keys.</p>
<p>Stepping away from this code for a bit and then coming back gave me the perspective I needed to properly understand it.
I now properly understand that this code is a confusing monster.</p>
<p>I'm going to try to chip away at this code for a while, but I think I need to accept that, for a while, this could very well end up being something where I put in a lot of effort to get back a little progress.</p>
<p>Anyway, I don't want to drag this out any more, so I'm going to wrap this up and ponder my decisions.</p>
<p>Good night.</p>
Coding 2022-01-302022-01-30T05:00:00-05:002022-01-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-30:/coding-2022-01-30<p class="first last">There was a lint error in every file, but it wasn't my fault.</p>
<p>Okay, let's see what we've got here.
How am I creating these new metadata objects currently?</p>
<ul class="simple">
<li>Given a set of keys the metadata produces, create a metadata with no restrictions on other keys, and no registry data.</li>
<li>Given an existing metadata, do one of the following actions:<ul>
<li>Narrow the keys that it provides</li>
<li>Impose restrictions on which other keys can be present</li>
<li>Add an entry to the registry</li>
<li>Convert the metadata into one which restricts which keys can be present</li>
<li>Combine the characteristics of two metadatas</li>
<li>Provide additional keys</li>
<li>(After I've had a chance to fix things up) Converting a metadata that provides keys into one that requires keys</li>
</ul>
</li>
</ul>
<p>Having thought some about the "restriction" concept, I think it's compatible with keeping the <tt class="docutils literal">maximal</tt> flag, and can be computed as <tt class="docutils literal">None</tt> if the flag is <tt class="docutils literal">False</tt>, and as the union of the requirements and provisions if it's <tt class="docutils literal">True</tt>.
Then, instead of calculating the new restricted values in the case of a union, the only thing to check is whether the calculated sets are equal if they're both non-None.</p>
<p>So, that gives me a few methods to add.
Let's see how that goes...</p>
<p>Okay, the new constructors went through.
I had to pin back the version of Black, because flake8-black can't handle the new version of Black.
That should be cleared up soon.</p>
<p>Anyway, the next step is to write and wire in the evolution methods.
I want to take a bit more time to review the notes I took for them.
I think I'll wrap this up now, and poke at the worldbuilding document a little.</p>
<p>Good night.</p>
Coding 2022-01-292022-01-29T05:00:00-05:002022-01-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-29:/coding-2022-01-29<p class="first last">A nice variety of things done.</p>
<p>Okay, here's where I've gotten so far: after doing a bunch of things that were, with the help of internet searches, relatively obvious, I've managed to get ALE to pass the correct information to rstcheck.
So, I'll be good to use custom directives in the worldbuilding.
I'm glad that's over with.</p>
<p>Anyway, it's the weekend, so let's do a little MOTR work.
It's <em>somewhat</em> late already, so I'm going to set myself a pretty modest goal for tonight: create the new class to hold the metadata for <tt class="docutils literal">Dynamic</tt>, so I can then convert the explicit manipulations of that metadata into method calls.
It's simple to start with: create the class, add the indirection, then fix Mypy errors until it's good to go.</p>
<p>...</p>
<p>Okay, I've made the changes required to get it to pass static checks.
I won't really be able to trust it until I've got full coverage, though.</p>
<p>The next step is to catalog the usage of the new type, and see about writing methods.
I don't think I'm up for that right now.</p>
<p>Good night.</p>
Coding 2022-01-282022-01-28T05:00:00-05:002022-01-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-28:/coding-2022-01-28<p class="first last">I suppose it's a good idea to see just how much I have to work on...</p>
<p>The stuff I was talking about coding for the sake of the worldbuilding book/site yesterday?
It turns out that it's not as easy as I thought, because apparently nothing is allowed to be easy?</p>
<p>Basically, I wanted to improve <a class="reference external" href="https://github.com/dense-analysis/ale">ALE</a>'s support of <a class="reference external" href="https://github.com/myint/rstcheck">rstcheck</a> so I can have rstcheck pick up on the config file and have proper checking of files that use custom directives.
Per a comment on a <a class="reference external" href="https://github.com/dense-analysis/ale/pull/2411">previous PR</a> attempting to add similar functionality, all I need to do is conditionally pass the relevant command-line argument when the version of rstcheck is <a class="reference external" href="https://github.com/myint/rstcheck#next-version">greater than, um...</a></p>
<p><a class="reference external" href="https://github.com/myint/rstcheck/commit/3f92957478422df87bd730abde66f089cc1ee19b">UM...</a></p>
<p>So, this is a problem.</p>
<p>I think the path of least resistance is to fork rstcheck, cut a local release, and point the checkout of ALE that neovim uses to my fork.
I don't want to do that right now, so I'm just going to pause to take stock, and prioritize the various things I can work on.</p>
<ul class="simple">
<li>Work on my draft for Missable Mysteries</li>
<li>Work on my outlines for worldbuilding</li>
<li>Work on my outlines for Missable Mysteries</li>
<li>Rejigger how I'm setting up rstcheck and ALE<ul>
<li>Cut new release of rstcheck<ul>
<li>Support passing <tt class="docutils literal"><span class="pre">--config</span></tt> option from ALE to rstcheck<ul>
<li>Work on my draft for worldbuilding</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Verify my outline of how <tt class="docutils literal">Dynamic</tt> should work in MOTR.<ul>
<li>Make the changes<ul>
<li>Update <tt class="docutils literal">Invocation</tt><ul>
<li>Write user-facing code<ul>
<li>Write tests<ul>
<li>Cut a new version<ul>
<li>Confirm that <tt class="docutils literal">Invocation</tt> actually simplifies writing motrfiles.<ul>
<li>Release a new version, and try it out with my other projects.<ul>
<li>Work on other personal coding projects.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>This is a somewhat intimidating tower of tasks, but just start peeling stuff off the bottom, I guess.
For now, I'm going to take things easy.
I'll see what I'm up for in the next few days.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2022-01-272022-01-27T05:00:00-05:002022-01-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-27:/worldbuilding-ksa-2022-01-27<p class="first last">Moving along.</p>
<p>I'm going to try to take some quick notes on where to take the setting document for <em>Korín, Sorín, and Arín</em> next.
So, the introductory poem provides a very, very brief peek at the kind of stuff that happens in the setting.
I don't have any kind of narrative <em>arc</em> planned out for the sweep of history in the setting, so I'd like to emphasize the roleplaying angle.</p>
<p>...</p>
<p>All right, I updated the draft.
Before I move on into the actual meat of the documentation, I have some tooling updates I need to do.
Don't worry, I <em>think</em> it'll be simple.</p>
<p>I just don't know exactly when I'll be up for it, since I've got some stuff happening right now that's a bit stressful.
Hopefully it'll all be cleared up soon.</p>
<p>For now, I'm going to take things easy.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2022-01-262022-01-26T05:00:00-05:002022-01-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-26:/worldbuilding-ksa-2022-01-26<p class="first last">Getting my bearings.</p>
<p>All right, I took another look at the poem draft, and there certainly are still issues, including a few that I introduced in the last editing pass, but you know what?
I'd rather move on for now.</p>
<p>Move on from the frustration of agonizing over word choices, to the frustration of trying to figure out how to follow up on this.</p>
<p>To start with, let's see what I established in this poem.
I know there are some ideas I have that I didn't convey, and I'm honestly not concerned about conveying in the poem, but I should make sure I have a good sense of what <em>is</em> being conveyed.</p>
<ul class="simple">
<li>The speaker's metaphor of time is based on upwind vs downwind, with upwind in the past.</li>
<li>Some places in the setting have stone castles, which is apparently somewhat distinctive.</li>
<li>The rulers of those castles did something bad, which violated the social expectations placed on them.</li>
<li>But (just?) one of them refrained out of principle.</li>
<li>It is reasonable to speak of magic that is specific to humans, so their must be some other source of magic.</li>
<li>Human magic affects life in some way, healing, hurting, and taking or giving life.</li>
<li>The land had two princes.
The younger prince is the one that refused to engage in this abuse of magic, and the older prince became a vampire, presumably because of said abuses.</li>
<li>The younger prince is not the only resident of the land to rebel against the royal family.
He joins some kind of organization that trains him in terms of magic and combat.</li>
<li>The society is polytheistic.</li>
<li>The different gods have simple descriptive epithets.
(Side note: I avoided naming them in the poem, because I didn't want the rhyme scheme to determine the names.)</li>
<li>The different gods have different priorities.</li>
<li>It is expected that both princes would have prayed to the same gods, and come up with their own justifications for why they should receive those gods' favor.
(I'm assuming here that the narrator of the poem can't "really know" what the older prince was doing for most of the poem, so the older prince's prayers say more about social expectations than what "actually happened".)</li>
<li>The God of the Crown is concerned with the aesthetics of government.
The God of Life and Death is concerned with the cycles of life, and whether a particular killing is "just".
The God of Leadership is concerned with the quality of government.</li>
<li>It's possible to directly invoke the power of the gods, using talismans that can be affixed with pins.
One function of talismans is to disable a vampire.</li>
<li>There is a moon.</li>
<li>Both brothers have some command over the wind.
Perhaps this is related to the distinction between different types of magic.
(I feel like I'm cheating and using setting knowledge with this one, so I tried to hedge a bit.)</li>
<li>Vampires in this setting have stiff joints and super strength.</li>
<li>Vampires in this setting normally cannot access happy memories from before they were turned.</li>
<li>But it is possible to overcome this.</li>
<li>Vampire bodies can move without their heads.</li>
<li>Powerful vampires have some form of mental link with their minions, with varied effects when the link is broken.</li>
<li>There is a town directly outside of the castle walls, so presumably, the castle functions as an administrative center.</li>
<li>There is a sun.</li>
<li>The sky has some form of upper liquid surface.</li>
<li>The sun has something to do with dragons.</li>
<li>(Some) dragons are aligned with the "heavens", and apparently specific gods.</li>
<li>It is customary, at least in some cultures, for most people to avert their eyes from a visiting dragon.</li>
<li>... Though they will peek.</li>
<li>Dragons can be tasked with enforcing the will of the gods.</li>
<li>Dragons speak a language that is comprehensible to mortals.</li>
<li>The younger prince forms the basis of a quasi-mythical group of vigilantes tasked with protecting people from exploitation.</li>
</ul>
<p>I've sent out the draft to a few people, so we'll see what kind of feedback I get on how much of that, beyond the <em>very</em> obvious, was clear.</p>
<p>(I mean, some items on that list, I expect other people not to list because they're obscure, and other things, I expect other people not to list because they're obvious, so the stuff in between is probably the most interesting.)</p>
<p>Anyway, this was a use of my time, and I'm not going to stress myself out about doing significantly more in the next hour.
Hopefully less time than that.
I don't actually want to be on my laptop until midnight.</p>
<p>Good night.</p>
Weekly Roundup 2022-01-252022-01-25T05:00:00-05:002022-01-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-25:/weekly-roundup-2022-01-25<p class="first last">Once again, I would have liked to get a bit more done, but this looks good, overall.</p>
<ul class="simple">
<li>Wednesday: I managed to edit poetry. It wasn't pleasant, but at least the draft is much better now.</li>
<li>Thursday: I made a little progress on my series of math education posts.</li>
<li>Friday: I had a headache, so I couldn't do much of anything.</li>
<li>Saturday: I tried to explain the somewhat disorganized state of the card prototype I mentioned earlier.</li>
<li>Sunday: I started getting myself back up to speed with MOTR.</li>
<li>Monday: I noticed that there were serious issues in the layer of MOTR that I'm trying to build on top of, so I started planning what I'd need to rectify them.</li>
</ul>
<p>Next week, I'm going to try to focus on my writing for a bit, but it's clear that I'm going to need to do some careful planning to salvage my work on MOTR.</p>
Coding 2022-01-242022-01-24T05:00:00-05:002022-01-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-24:/coding-2022-01-24<p class="first last">Oh dear, I have jumped some guns.</p>
<p>Okay, I'm not up for much right now.
I'm just going to sketch stuff out according to what I was thinking about as I worked yesterday.</p>
<p>So, the <tt class="docutils literal">flex</tt> methods conceptually exist in a matrix which I have only partially filled in.
There are three parts of a <tt class="docutils literal">Command</tt> that can accommodate an <tt class="docutils literal">IO</tt> type.
There are arguments, environment variables, and values <em>based</em> on arguments and environment variables, but not explicitly passed.</p>
<p>So, between those two axes, let's see what behaviors need to be considered.</p>
<ul class="simple">
<li>All <tt class="docutils literal">Output</tt> values need to depend on a non-strict superset of the keys required by the rest of the command.
If this condition is violated, then two different commands will contend for the same output.</li>
<li>All <tt class="docutils literal">extra</tt> values need to depend on a non-strict superset of the keys required by the rest of the command.</li>
</ul>
<p>Actually, oh no.
This is some kind of variance thing.
<tt class="docutils literal">extra</tt> values require a flipped treatment from <tt class="docutils literal">arg</tt> values, because adding <tt class="docutils literal">Input</tt> values to a command is problematic, but adding <tt class="docutils literal">Output</tt> values is...
Okay, so, it needs to be a superset, but it shouldn't really break anything except for some mental models in the event that it's a strict superset.
A strict superset should probably generate a warning, however, because I'm pretty sure it violates some convenient simplifications that <em>usually</em> hold.</p>
<p>So, really what has to happen for <tt class="docutils literal">extra</tt> <tt class="docutils literal">Input</tt> values (and this is <em>not</em> implemented yet), is that every associated key must be used by an <tt class="docutils literal">arg</tt> or <tt class="docutils literal">env</tt> value.
Like, <tt class="docutils literal">Dynamic</tt> values have to track two sets of keys, say "provided" and "required".
"Provided" plays the role of the current key set, but what's different is that not all new keys go in there.
The instantiation logic now needs a validation step, that checks whether all "required" keys are "provided".
This should be accomplished via a private variable and a public wrapper, so that combinator logic can bypass the validation.</p>
<p>Thinking about adding all of this metadata, I'm a little tempted to factor out the metadata into its own class and writing methods to implement the field manipulation.
The latter part is definitely a good idea.
I'm not sure about the former.</p>
<p>Anyway, the existing logic is at its best when it comes to the <tt class="docutils literal">arg</tt>s.
Considering the case of environment variables, maybe the thing to do for now is to require that, if they're used, they get passed all of the keys they use.</p>
<p>I think to make this work, I need additional fields or wrappers for <tt class="docutils literal">Invocation</tt>, but I'm not sure what the best implementation is.
Now that I have this new perspective, I'm going to need to take some time to plan things out.</p>
<p>I'm feeling wiped out right now, so I'm not going to draw this out.</p>
<p>Good night.</p>
Coding 2022-01-232022-01-23T05:00:00-05:002022-01-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-23:/coding-2022-01-23<p class="first last">I should not be allowed to cite the principle of least astonishment.</p>
<p>I did mess a little with the card code, but that is in serious need of modularization.
Putting that aside, I finally got back to MOTR, and I, sadly but understandably, didn't get right back up to speed immediately.</p>
<p>I wrote some helper aliases for defining decorators, and they, kind of helped, I guess.</p>
<p>I don't remember <em>exactly</em> what came next, so I'm going with my best guess, which is that I should be filling in these blocks that end in <tt class="docutils literal">raise NotImplementedError</tt>.</p>
<p>These blocks are there to handle two of the possible types that a value of the <tt class="docutils literal">Part</tt> union can take.
I've handled <tt class="docutils literal"><span class="pre">Static[...]</span></tt>, so what remains is <tt class="docutils literal">InputAccumulator</tt> and <tt class="docutils literal">AdaptiveDynamic</tt>.</p>
<p>It's been three weeks, so I kind of don't remember how this stuff, like, <em>works</em>.
Let's see...
<tt class="docutils literal">AdaptiveDynamic</tt> assembles any number of <tt class="docutils literal">ValueAdaptor</tt> instances, which are already loaded into the <tt class="docutils literal">adaptors</tt> accumulator parameter, so I don't need to worry about that bit.
The intended result of each of these blocks is that a value of type <tt class="docutils literal">Dynamic[Option]</tt> is stored in the <tt class="docutils literal">option_dynamic</tt> variable.
All it makes sense to do with the <tt class="docutils literal">AdaptiveDynamic</tt> is to replicate the <tt class="docutils literal">builder</tt> decorator as a method.</p>
<p>Okay, I did all that, and there are <em>no tests</em>, so let's just hope that actually made sense.
Let's see if I can put together something plausible-sounding for the other block.
That's going to be an <tt class="docutils literal">InputAccumulator</tt> that gets built up by the adaptors, and then converted via the <tt class="docutils literal">flex</tt> functions, which... hm.
I forget if I had plans for environment variable handling, but I'm not seeing anything obvious for it, so I think I need to step back and consider whether I'm representing all of the data that needs to be represented.</p>
<p>I've got some other things I want to take care of tonight, so I'm going to call things here, and get a better handle on this code later.</p>
<p>Good night.</p>
Coding 2022-01-222022-01-22T05:00:00-05:002022-01-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-22:/coding-2022-01-22<p class="first last">"Quick"</p>
<p>Okay, I'm feeling better, but I mostly took things easy today.
As such, rather than dive into anything really heavy, I'm going to dash off a quick summary/critique of the card prototype I was working on earlier.</p>
<p>Let's start with the basic goal of what it represents, and what I want to do differently, or additionally.</p>
<p>So, right now, it represents basic playing cards that can be put into a deck, and it handles rank-suit combinations, named cards, duplicates of cards, and duplicates of ranks and suits.</p>
<p>One thing that could be interesting to add is cards that have a name and metadata.
I'd like to evaluate what's in there currently before adding that in.</p>
<p>So, the basic concepts are <tt class="docutils literal">Card</tt>, <tt class="docutils literal">Rank</tt>, and <tt class="docutils literal">Suit</tt>.
They all expose the capability to generate distinct duplicates of themselves, using the <tt class="docutils literal">SuccCard</tt>, <tt class="docutils literal">SuccRank</tt>, and <tt class="docutils literal">SuccSuit</tt> classes, which are created using the <tt class="docutils literal">Succ[T]</tt> mixin.
Currently, this is mostly done with concrete classes.
I tried to come up with a Protocol-based alternative as a thought experiment, but it ended up kind of awkward.
The basic requirement is that the output of the <tt class="docutils literal">succ</tt> method on <tt class="docutils literal">Card</tt>, <tt class="docutils literal">Rank</tt>, and <tt class="docutils literal">Suit</tt> needs to match the type of the class in question.
Since I'm not currently doing <tt class="docutils literal">isinstance</tt> checks using these classes, I could get a less awkward set of static types, in exchange for some much stranger runtime types, by using a <tt class="docutils literal">cast</tt>, but it's better to get a handle on what operations I expect to be able to do on these types first.</p>
<p>Anyway, right now the static behavior of the system is pretty locked-down via some type variables: <tt class="docutils literal">TSucc</tt> is one of the three basic classes, and <tt class="docutils literal">TPart</tt> is just <tt class="docutils literal">Rank</tt> or <tt class="docutils literal">Suit</tt>.
These variables are invariant right now.</p>
<p>Then, there are some types that I haven't really named well.
<tt class="docutils literal">Base[T]</tt> is a mixin that <em>essentially</em> indicates "instances of this type are not a duplicate of another card", and <tt class="docutils literal">Primitive[T]</tt> is an extension of <tt class="docutils literal">Base[T]</tt> that indicates "instances of this type are not defined in terms of other <tt class="docutils literal">Base</tt> types, but use only more primitive types".
These types feel kind of awkward to use and reason about, and I think they need some work to make the code that uses them intuitive, which it really isn't right now.
Right now, the only class that is <tt class="docutils literal">Base[T]</tt> and not <tt class="docutils literal">Primitive[T]</tt> is <tt class="docutils literal">RankSuitCard</tt>, which is a cad defined by its rank and suit.</p>
<p>(Maybe make the base classes abstract and put the method implementations in the mixins, and inherit the marker classes into the mixins.
This makes sense currently, because in leaf classes, <tt class="docutils literal">Named</tt> and <tt class="docutils literal">Primitive</tt> are one-to-one.)</p>
<p>Moving right along, then I've got a helper class, a protocol that provides generic slicing support for a container class, given an implementation of just integer-based indexing.
The first implementation of this, because I decided to do type-based checking for empty sequences, is <tt class="docutils literal">Empty[T]</tt>.
Thinking about this in retrospect, it would simplify the code by <em>a lot</em> if I reworked it to allow most sequences to be empty.
It wouldn't eliminate special cases, but various things would be simplified.
The one concern is the weird number of ways something could be empty.
It might make the most sense to simply remove some of the union types I'm using currently, but I'm not sure.</p>
<p>Anyway, next up are:</p>
<ul class="simple">
<li><tt class="docutils literal">Individual[T]</tt>, which is a length-1 container for a <tt class="docutils literal">Primitive[T]</tt></li>
<li><tt class="docutils literal">Duplicated[TSucc]</tt>, which stores at least 2 "copies" of a <tt class="docutils literal">Base[TSucc]</tt>, according to its <tt class="docutils literal">copies</tt> field.</li>
<li><tt class="docutils literal">Composite[TPart]</tt>, which stores non-composite sequences of <tt class="docutils literal">TPart</tt>.
This is indicated with a union rather than some kind of marker.
I think I'd rather do it via a marker, but I'm not sure how practical it would be.</li>
</ul>
<p>Then things get into specifically sequences of <tt class="docutils literal">Card</tt>s with:</p>
<ul class="simple">
<li><tt class="docutils literal">RankSuitCards</tt>, which combines non-empty sequences of <tt class="docutils literal">Rank</tt>s and <tt class="docutils literal">Card</tt>s into a matrix of <tt class="docutils literal">RankSuitCard</tt>s.</li>
<li><tt class="docutils literal">DuplicateDeck</tt>, which stores at least 2 "copies" of basic sequences of <tt class="docutils literal">Card</tt>s.</li>
<li><tt class="docutils literal">CompositeDeck</tt>, which stores at least 2 simpler decks, although I see that I haven't set up the "at least 2" validator on this class.</li>
</ul>
<p>Finally, there are a bunch of helper functions after this, and I'm going to hold off on summarizing them for two reasons:</p>
<ul class="simple">
<li>It's late</li>
<li>Their names are somehow even worse than the classes</li>
</ul>
<p>Though I will note that many of them probably could, and maybe should, be methods on the classes.</p>
<p>I'm going to cut things off here before I blink and it's ten minutes later, since I know that can happen to me this late.</p>
<p>Good night.</p>
Diary 2022-01-212022-01-21T05:00:00-05:002022-01-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-21:/diary-2022-01-21<p class="first last">Ow.</p>
<p>I didn't get to do much today, because I was really tired, and I ended up with a bad headache.
I'm going to take the rest of the night as easy as I can instead of trying to "push through" this, because I know it's not worth it.</p>
<p>I'm going to publish this and get off my laptop.</p>
<p>Good night.</p>
Diary 2022-01-202022-01-20T05:00:00-05:002022-01-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-20:/diary-2022-01-20<p class="first last">Yay, progress!</p>
<p>Since I'm taking a break from touching the worldbuilding/poetry, I figured I'd get back to drafting my SoME followup post.
Given the amount of editing I needed to make the first post somewhat coherent, I know intellectually that I should just focus on putting together a rough sketch of the post's structure and fill it in, but gosh, it is hard to feel good about going "yeah, I'll just write something that I know is probably bad here, so I can fix it later".</p>
<p>I don't want to go into too much detail on any of it right now.
The most I feel like saying is that I'm trying to take some parts of the post a bit quicker than I did the first one, and we'll see if that holds up in editing.</p>
<p>I was focused on that, so it's now really late and I want to get to bed.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2022-01-192022-01-19T05:00:00-05:002022-01-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-19:/worldbuilding-ksa-2022-01-19<p class="first last">Apparently, sometimes I can't count?</p>
<p>Haha, I did it!
I edited the poem instead of messing with code.</p>
<p>I <em>hate</em> this.</p>
<p>Revising poetry or prose is like, you stare at something for weeks, and then you look at it again, and find major issues that you entirely failed to notice.
Meanwhile, write some tests for code, and the behavior covered by those tests cannot regress unnoticed.</p>
<p>But anyway, I've addressed most of the glaring issues, so now I just need to wait a bit, and do it all.
over.
again.
yay.</p>
<p>Anyway, I'm done for now, so I can get away with not thinking about this any more until some time tomorrow.
I need to do <em>something</em> to take my mind off this, but I'm not sure right now what that "something" could be.</p>
<p>I guess that's the first thing I'll do after I publish this: think of something to take my mind off of it for now.
Nothing more to talk about, so I'm going to publish and get ready for bed.</p>
<p>Good night.</p>
Weekly Roundup 2022-01-182022-01-18T05:00:00-05:002022-01-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-18:/weekly-roundup-2022-01-18<p class="first last">This was some kind of a break, but I need a bit more of a break.</p>
<ul class="simple">
<li>Wednesday: I planned out how to generate actual parses with the Earley parser code I've written.</li>
<li>Thursday: I did some more work on the parser, and frankly I didn't write it up well enough to jog my memory.</li>
<li>Friday: I finally generated a parse, after fixing a bunch of bugs of varying degrees of weirdness.</li>
<li>Saturday: I took it easy for a bit.</li>
<li>Sunday: I got the Earley parser working well enough that I expect to be able to come back to it.</li>
<li>Monday: I worked on some other, less algorithmically-intensive code, and rehashed my motivations for working on MOTR.</li>
</ul>
<p>Next week, I'm going to try to focus on prose or poetry for a bit.</p>
Coding 2022-01-172022-01-17T05:00:00-05:002022-01-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-17:/coding-2022-01-17<p class="first last">I <em>must</em> take a break...</p>
<p>Well, I didn't touch the Earley parser, so, um, "success".
Instead, I pulled up some old prototype code from I don't remember exactly how long ago, and tried to polish it up.
In this case, the code was for representing card decks.
The plan is to incorporate this into one of my other projects, but I haven't done that yet, preferring to go through a few prototype phases.</p>
<p>So, after I posted the last entry, I basically pulled up the most recent prototype, and started retyping and adapting it in Jupyter.
Replacing old questionable decisions with new questionable decisions, that kind of thing.</p>
<p>Earlier today, I was able to set it up to represent a basic 52-card deck, and I also got some hanafuda decks in there, albeit missing lots of details.
I regard this as pretty promising, because it proved out the following features:</p>
<ul class="simple">
<li>Representing a very regular matrix of rank and suit</li>
<li>Representing extra one-off cards</li>
<li>Representing distinct "copies" of a card</li>
<li>Representing "copies" of a rank or suit (the hanafuda kasu are currently represented via duplicates of the kasu rank, rather than duplicates of the combination of rank and suit; assuming this distinction makes sense, I don't know if it's relevant, and if so, whether I should be implementing it this way, or, like, the opposite way; my hope is that details of ordering are more relevant than the precise semantics that I use to handle the duplication)</li>
</ul>
<p>At this point, there are two major things to work on:</p>
<ul class="simple">
<li>Making sure the code is correct</li>
<li>Representing more decks</li>
</ul>
<p>Honestly, as I think about planning this, everything comes back around to MOTR.
I want to do things like:</p>
<ul class="simple">
<li>Cut a new MOTR release</li>
<li>Pick my other Python projects back up using MOTR</li>
<li>Pull this code into it, taking advantage of modules to keep it from being, like, super long</li>
</ul>
<p>Everything comes back to this project, for a simple reason: I see MOTR as my chance to turn my task runner code into a more compact, maintainable format than what I have currently.
I assume tox has changed a bunch since I last tried to write a config file, but my experiences working with other people's parameterized tox files have kind of soured me on that idea.
I much prefer Nox, but I never did figure out how to track dependencies between sessions, and I want to try to take advantage of concurrent execution.</p>
<ul class="simple">
<li>tox has concurrent execution, but its dependency tracking is designed differently from MOTR, and I prefer MOTR's design, obviously, because why would I design something that I don't want?</li>
<li>I don't know if Nox has any kind of inter-session dependencies planned or implemented, but I do remember seeing an issue asking for concurrent execution get bogged down in how to reconcile "execute things in parallel" with "real-time command output"</li>
<li>MOTR discards the latter, at least for now, in exchange for focusing on producing viewable artifacts, principally HTML, so I can look over them afterwards</li>
</ul>
<p>Thinking about working on this, I think the right tack to take is to focus on other stuff like the poetry until next weekend, and then get back into this.
We'll see if I can hold myself to that.
Anyway, it's late.</p>
<p>Good night.</p>
Coding 2022-01-162022-01-16T05:00:00-05:002022-01-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-16:/coding-2022-01-16<p class="first last">Will I finally put this stuff down for more than a day or so? (Hopefully, yes.)</p>
<p>I wasn't really sure to call this "coding", because I just did a little more work on the Earley parser, or "worldbuilding" because I revised the poem earlier today.</p>
<p>So.
I revised the poem a little.
I was just focusing on some meter and scansion issues near the beginning, so I haven't confronted the big issues near the end, where I just kind of gave up on stuff like "sounding good".
Not much more to say there, but I did put in some work.</p>
<p>On the Earley parser, I hacked together nullable infinite loop detection in a way that makes sense to me.
("If a rule's RHS doesn't contain any of the symbols that <em>could</em> participate in an infinite loop, then it definitely doesn't participate in an infinite loop, so it can be removed from the set.
Repeat this process until the set is empty, or the process reaches a fixed point.")
All of this code has no tests, so I'm now going to back-burner it for real, until I...
Until I get MOTR into a workable state.
So, I guess the next thing I'll work on in terms of coding is either...
MOTR again, or something else that I can scribble into a Jupyter lab session.</p>
<p>I'll sleep on that, and call this entry early.</p>
<p>Good night.</p>
Diary 2022-01-152022-01-15T05:00:00-05:002022-01-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-15:/diary-2022-01-15<p class="first last">I need to work on taking it easy.</p>
<p>Okay, I just want to relax.
Not consider trying to devise some kind of metric for limiting parse depths so I can guarantee that every parse matching a pathological grammar is hit at some point.
(It would probably be worth more right now to focus on reworking the parser representation so you can have identical rules with different actions, which would do <em>deeply obnoxious</em> things to the parse generator.)</p>
<p><strong>ANYWAY</strong>, I'm spacing out and not sure what I'm doing, and I don't even have an excuse as such, this time.</p>
<p>Let's think about this weekend.
I want to get back to doing some editing.</p>
<p>Maybe play some games.
Ideally, work on getting more rest.</p>
<p>Actually, I think I'll work on a puzzle thing while this entry publishes, finish things up for now.</p>
<p>Good night.</p>
Coding 2022-01-142022-01-14T05:00:00-05:002022-01-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-14:/coding-2022-01-14<p class="first last">I bet there are still bugs.</p>
<p>The good news is, I managed to construct a successful parse.
The not-as-good news is, I had to fix some bugs before it went through.
The worse news is, while almost all of the bugs made sense in retrospect, I think I'm going to need to do a close reading of the entire tutorial to understand where I went wrong with the final bug.</p>
<p>Easy stuff:</p>
<ul class="simple">
<li>"Oh, I forgot to include the token value when I do a scan."
This is totally my fault, since it's a failure to fulfill a requirement <em>that I came up with</em>.</li>
<li>"I missed the final predict/complete step."
This is a bit more interesting, because it reveals something that I glossed over about Earley parsers: in a successful parse, there will be one more state set than there are tokens, because the state sets border the tokens on either side.</li>
</ul>
<p>And now that I say that, I understand what went wrong with the last bug.
This is a doozy, so let's see whether I can explain it.</p>
<p>All right, so my parse generators rely on several recursive functions.
The function that I broke takes an item and an "end index" to a state set, and, looking in the range between the end index, and the item's "start index", yields all possible sub-divisions of that range into the symbols required by the rule.
This function calls itself recursively for one of two reasons:</p>
<ul class="simple">
<li>If the item has a non-<tt class="docutils literal">None</tt> value as its last node, then that value corresponds to a terminal symbol, so the node is skipped over: the node is discarded, and the end index is decremented so we check the previous state set.</li>
<li>Otherwise, the code checks all items at the end index, to see if it can find a completed item that matches the non-terminal symbol required by the item's rule at this point.
If it does, then we can get the rest of the division by... discarding the node and choosing an appropriate value for the end index.</li>
</ul>
<p>And that last bit is where I tripped up.
I forgot that the state set indices go <em>between</em> tokens, so I tried to "skip over" an index, because the last token used by one symbol is the token before the first token used by the next symbol.
This doesn't work, because "the ending of one symbol" and "the beginning of the next symbol" correspond to <em>the same</em> state set index.
So I tried to "compensate" for something when I should have left well enough alone.</p>
<p>Next up, now that I sort of understand things, I see that I absolutely did not account for empty rules.
(I first verified this experimentally.)
So, before I can properly move on, I'll want to fix that.</p>
<p>Let's see what fixing that looks like.</p>
<p>Well, first off, I need a constructor helper for <tt class="docutils literal">Parser</tt> objects.</p>
<p>...</p>
<p>I got distracted and did the fix.
This basically consisted of implementing the algorithm that Jeffrey Kegler provided for detecting nullable symbols, undoing some premature optimizations I had done that interfered with actually using the data on nullability, fixing a code divergence because apparently that happens nearly immediately after I copy and paste some code less than ten lines down from its origin, and pondering whether I have it right, because the fixed code has <em>more</em> items in its state set than the code from the tutorial.</p>
<p>I <em>think</em> this is okay, because if I'm understanding things correctly, the tutorial is showing an intermediate stage of parsing.
I could be totally wrong, though.</p>
<p>Hm, interesting question that just occurred to me: is my current parse generation code able to properly handle nullable sequences that can go arbitrarily deep?
I'm skeptical, so maybe just don't do that.</p>
<p>I think it might actually act really pathological.
But it's getting late, and I don't want to think about that too hard.</p>
<p>Since I've gotten a successful parse, maybe I should move on for now, and come back to this code later.</p>
<p>Good night.</p>
Coding 2022-01-132022-01-13T05:00:00-05:002022-01-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-13:/coding-2022-01-13<p class="first last">I really appreciate how easy the code is once you understand the concepts behind it. It's too bad this stuff started off so intimidating to me.</p>
<p>I got a late start again today, but I have managed to put together a rough draft of the parser code from the past few days' notes.
I'll test it later.
Testing it requires some decisions about how to represent the AST nodes that I don't want to make so close to midnight.</p>
<p>Once I have a successful run with the tutorial's example parser, I'll put this on the back burner for a bit, then come back to it soon-ish and start working on cleaning up the code.
Maybe make a post just to talk about it.</p>
<p>Anyway, I don't want to risk thinking of "just one more thing" to write for half and hour, so I'm cutting things off here.</p>
<p>Good night.</p>
Coding 2022-01-122022-01-12T05:00:00-05:002022-01-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-12:/coding-2022-01-12<p class="first last">Maybe I should come up with a mascot character, like how Amos has cool bear.</p>
<p>I'm going to try to diversify what I work on and blog about, but not today.</p>
<p>All right, let's plan out some of the stuff I was talking about last time.
Iterating over parses.
Because any found sub-tree is guaranteed to produce at least one valid sub-parse, I think I want to work by iterating over all possible top-level divisions of sub-trees (to look for the values that work), and then take the product of the parses of those sub-trees.</p>
<p>So this looks like:</p>
<ul class="simple">
<li>"I have a generator that yields valid parse trees of the given type, with the given start and end indices"</li>
<li>"What's it look like inside?"</li>
<li>"Well, it iterates over all items where the rule's LHS matches the type..."</li>
<li>"Uh-huh"</li>
<li>"For each matching rule, it passes that item to a generator that finds all valid divisions of the item's range..."</li>
<li>"Uh-huh"</li>
<li>"Then, it takes the product of the parse iterators over the items in the divisions."</li>
<li>"So..."</li>
<li>"So, there's a top-level <tt class="docutils literal">parses</tt> function that iterates over all successful items in the last set.
It then delegates to a <tt class="docutils literal">parses_for_item</tt> function that takes an item and an end index and generates all parses satisfying those constraints.
This function relies on a <tt class="docutils literal">divisions_for_item</tt> function to get the information.
Ultimately, <tt class="docutils literal">parses_for_item</tt> is recursive, because it needs to slot successful parses into the divisions.</li>
</ul>
<p>I'm not sure whether I'd rather accomplish that by making a bunch of these have the same return types, or by confining the recursion to the <tt class="docutils literal">parses_for_item</tt> function.
I was originally thinking the former, but I'd like to try the latter.
Later.</p>
<p>It's late and I'm tired.</p>
<p>Good night.</p>
Weekly Roundup 2022-01-112022-01-11T05:00:00-05:002022-01-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-11:/weekly-roundup-2022-01-11<p class="first last">It's nice to work on something with a slightly more defined end goal.</p>
<ul class="simple">
<li>Wednesday: I started messing with Earley parsers, just trying to get a handle on how they work.</li>
<li>Thursday: I had some ideas about trying to simplify the presentation of the loops involved, but I didn't have the code in a state where I could actually do it at that point. (It may be possible now.)</li>
<li>Friday: I took a step back, wrote up the state of the code at the time, and wrote some helpful functions.</li>
<li>Saturday: I just kind of relaxed.</li>
<li>Sunday: I started to better understand the tutorial's explanation of how everything fit together, and I started cleaning up the code.</li>
<li>Monday: I wrote up my major divergences from the tutorial code, and tried to restate the tutorial so I understood it better, with no expectation that this will make things clearer to anyone else.</li>
</ul>
<p>Next week, I might change focus again.
It'd be nice to get the Earley parser to a state where it can do approximately what the tutorial's parser does by the end.</p>
Coding 2022-01-102022-01-10T05:00:00-05:002022-01-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-10:/coding-2022-01-10<p class="first last">ершы шы аштую</p>
<p>The linux side of things works a little better now.
In this context, "a little better" somehow means "my laptop now has an input mode that has Cyrillic letters and fullwidth spaces".</p>
<p>But anyway.
We handled some stuff today that took up part of the afternoon, and now I want to see if I can get a handle on taking the recognizer and getting it to produce parse trees.</p>
<p>Let's see how that looks.</p>
<p>My initial thought is to have it work like "given an index that defaults to -1, generate all valid trees that end at that index".
(I'm using Python indexing, so that's how that means what I want it to.)
First some context: instead of storing an index for the dot in the items, I'm storing a tuple of <tt class="docutils literal">Optional[Token]</tt>s, which I'm calling nodes.
The <tt class="docutils literal">Forest</tt> objects that I'm writing this for store a reference to the type of the topmost node, so things start out as follows:</p>
<ul class="simple">
<li>In the <em>last</em> index, find all <em>completed</em> items that start at index <em>0</em> and have a rule with a left-hand-side of the <em>root node type</em></li>
<li>This is a degenerate case at the top level, but if the item has no nodes associated with it, then it's an empty rule that matched an empty token stream.
Call the rule's function with no arguments, and yield the result.
At the top level, there is no more work to do.
(Assuming that rules can't be identical except for their associated function, which I'm not trying to enforce, but is... probably reasonable?
This might suggest a tiered mapping structure for storing rules in the parser object.)</li>
<li>If the node corresponding to the symbol before the dot is a token, then the item was generated by a scan, and the thing to look at is the previous index, for that rule, but with the last node discarded.
Technically, we shouldn't really need to <em>look</em>, per se.
There's only one possible value of the predecessor to a scanned item, and we know it exists in the previous set, so we don't actually have to find it.
I'll think through the precise implications of this later.</li>
<li>So, the meat of all of this is dealing with a non-terminal symbol before the dot.
To look for a non-terminal symbol at a given index, you have to look for all <em>completed</em> items <em>in that index</em>, with a left-hand-side matching <em>that symbol</em>, and a start index <em>greater than the parent's start index</em>.
Each such item will produce at least one valid internal parse (unless I'm extremely mistaken), and all such parses will relate identically to the broader parses, if any.
Essentially, it's a product between "recursing the algorithm in smaller bounds" and "the rest", where "the rest" is "whatever item has the sub-parse fitting into it, discard that node and look for the resulting item at the start index of the sub tree".</li>
</ul>
<p>I think this is about what the tutorial was saying, and I've tried to reword it for my own comprehension, but I'm not sure the result is helpful for anyone else.
It's basically notes, a little less refined than a rough draft.
If anyone is following along with this and trying to understand this for themselves, I would highly recommend taking your own notes along these lines, in whatever way and format makes the most sense to you.
Not least because I haven't yet vetted this stuff, so there's a chance some aspect of it is simply wrong.</p>
<p>Anyway, I should get this published and get to bed ASAP.</p>
<p>Good night.</p>
Coding 2022-01-092022-01-09T05:00:00-05:002022-01-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-09:/coding-2022-01-09<p class="first last">Roughing stuff in.</p>
<p>So, I tried a few things today, and they mostly worked.
I don't feel like going into more detail.</p>
<p>Anyway, let's see what I can do as far as making some progress or plans on the Earley parser.</p>
<p>So, in my understanding of things, the initial state should include some states.
To expand on these states:</p>
<ul class="simple">
<li>We perform any possible completions until no more completions are possible</li>
<li>We perform any possible predictions, doing newly-allowed completions as needed, until no new predictions are possible</li>
<li>Once only scans are possible, we scan into the next state</li>
</ul>
<p>A completion looks like:</p>
<ul class="simple">
<li>Given an item that has no symbol after the dot<ul>
<li>Find any items in the set indexed by the item's <tt class="docutils literal">start_index</tt> that have the item's left-hand-side after the dot.</li>
<li>Place the advanced versions of those items in the current set</li>
<li>This may require an optimization to avoid quadratic behavior on some grammars.</li>
</ul>
</li>
</ul>
<p>A prediction looks like:</p>
<ul class="simple">
<li>Given an item that has a non-terminal symbol after the dot<ul>
<li>Add all rules that produce that symbol to the current set</li>
<li>Mark any <em>newly added</em> rules for processing</li>
<li>If the newly added rules are eligible for completion, recursively carry out completions until they're done</li>
</ul>
</li>
</ul>
<p>A scan looks like:</p>
<ul class="simple">
<li>Given an item that has a terminal symbol after the dot<ul>
<li>If the terminal symbol matches the current token</li>
<li>Add the current item to the next set, advanced by one</li>
</ul>
</li>
</ul>
<p>If we maintain multiple stacks/deques/sets/whatever/maybe dicts that we <tt class="docutils literal">popitem</tt> from, and clear them before the scan step, then we can have a uniform setup of "here is a set and sets to process, add it to both, and to the correct set to process if it's new".
If I do it like that, then the full prediction step looks like "predict one, complete again".</p>
<p>I should note at this point that it's very likely that I'll have very different ideas about how this should be done once I've prototyped this, because I only sort of understand the documentation that I'm reading.</p>
<p>For now, I'm going to write the helper for this as a nested function inside the method.</p>
<p>Several rewrites and fill-ins later, I have a prototype that is almost certainly not quite correct, and not enough time in the night to feel like testing.</p>
<p>Basically, the core of the logic looks... fine, but I have some assertions after the outer loop that are only sometimes valid, and can probably be expected to not be valid most of of the time.
From writing this out, I fixed up the assertions, and now I need some new ones to make sure the data is actually usable.</p>
<p>A few more tweaks later, and I'm about done for the night.</p>
<p>I elected to return a frozen version of the state set from the parse method, so that "find the correct parses" is decoupled from "produce the state set".
I'll work on producing the parses next, and come back to optimizing the parse method once I've proved that anything works.</p>
<p>For now, I should wrap up and take the remainder of the night as easy as I can, which is not as easy as last night.</p>
<p>Good night.</p>
Diary 2022-01-082022-01-08T05:00:00-05:002022-01-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-08:/diary-2022-01-08<p class="first last">I can't be up and going all the time, but I hope to be able to move a little faster tomorrow than I am right now.</p>
<p>I'm not really back up to speed from vacation, so this week was a little rough on me.
As such, I'm taking it easy right now.</p>
<p>What's going on in my life...
Um, tomorrow, I'm planning to change up my grooming routine some.
I'll probably write about that after I try it.</p>
<p>Aside from that... I dunno, it's not like I'm doing anything particularly different.
All that's really happening is, with the state of the pandemic, I'm going to need to coop myself up <em>even more</em>, I guess.
That's not going to be pleasant, but when has any of this been pleasant?</p>
<p>I'm going to call this here and stop trying to write.</p>
<p>Good night.</p>
Coding 2022-01-072022-01-07T05:00:00-05:002022-01-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-07:/coding-2022-01-07<p class="first last">I can't get away with just winging it. How many times will I learn this lesson?</p>
<p>All right, my conclusion from thinking about trying to implement Earley parsing differently, is that I really should get a basic working implementation together.
Prototype based on a design, before messing with the design.
So, let's take this closely.
First off, I've got some code that is <em>very</em> loosely based on Spark, so let's take stock of that.</p>
<p>Classes for:</p>
<ul class="simple">
<li>Token matcher</li>
<li>Scanner to produce tokens</li>
<li>First pass at a "Rule" object for the parser, which is really weird from a typing perspective, because it reflects on the annotations of the parser action, which means that it has to be covariant in both the arguments and the return value of the function, which I assume <em>actually supporting</em> would involve writing a Mypy plugin for.
(Also, I think the way I'm setting this up my be a design misstep on my part, but I'd like to see it through and focus on the algorithm, which shouldn't be affected by the bit I'm not sure about.)</li>
<li>Earley item class</li>
<li>The beginning of a Parser class, which currently has the bare minimum of data required, with no optimizations, and just enough code for the <tt class="docutils literal">parse</tt> method to be syntactically invalid because I'm not sure how to write the loops.</li>
</ul>
<p>Anyway, let's take the tutorial slowly.</p>
<ul class="simple">
<li>"A <em>grammar</em> is a set of <em>rules</em>."
Check.</li>
<li>"non-terminal symbols [...] and <em>terminal symbols</em>"
I should write a method to distinguish terminal and non-terminal symbols according to the... somewhat questionable way I'm representing symbols.</li>
<li>Earley items...
There are some obvious convenience methods to add to what I have.</li>
<li>State sets...
I'm going to need to think carefully about what actions to take on state sets, because I want to make sure I can work with them semi-efficiently.
So, I've got "a container of <tt class="docutils literal">Item</tt> objects", and it may be the case that a set would be better than a list, so I'll make that change.
All right, initialization is done, I think.
I have no idea how it relates to the corresponding-ish code in Spark, but whatever.</li>
</ul>
<p>Okay, I think I've written what I need for the outer loop, and some helpful stuff for the inner loop.
Let's compare the effects of prediction, scanning, and completion.</p>
<ul class="simple">
<li>Scanning adds an advanced item to the next set (If a rule's next symbol is terminal)</li>
<li>Prediction adds a new item to the current set (If a rule's next symbol is non-terminal)</li>
<li>Completion adds an advanced item to the current set (If a rule is completed, and therefore has no next symbol)</li>
</ul>
<p>Thinking about how these relate, prediction is the only process which adds a new starting index.
I'm not sure if that is relevant to anything.</p>
<p>My big concern with these is, according to the open letter I linked yesterday, the different types of operation can be strictly sequenced, but I don't understand how that's possible.
Let's set aside scans, since those have much easier behavior: you can just iterate through one set, and perform all scans, into the next set.</p>
<p>So, doing completions and then predictions works if we know that prediction will never add a completed set.
If we allow empty rules, then it <em>currently appears to me</em> that the easiest way to guarantee that prediction doesn't add completed rules would be to essentially run any possible completions "in-line" as part of prediction.</p>
<p>It's getting late, so I'm going to take "I thought about this and wrote some helper functions" as a win, and get ready for bed.</p>
<p>Good night.</p>
Coding 2022-01-062022-01-06T05:00:00-05:002022-01-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-06:/coding-2022-01-06<p class="first last">It's really hard for me to visualize a lot of this. Intuitions about convergence/divergence flipping back and forth like a Necker cube.</p>
<p>I'm going to sketch out some thoughts on implementing an Earley parser.
The tutorial I'm reading is talking in terms of loops, but I'm trying to think about this in terms of reducing a stream of tokens.
I'm <em>pretty sure</em> this will work, and it means I can punt on figuring out the outer loop for a bit.</p>
<p>Here's the basic idea: I have a series of rules, and that's bundled up in an object that defines a method like "given a state and a token, return a new state".
Then I can just generate the initial state, <tt class="docutils literal">functools.reduce</tt>, and bam, done.
... Probably.</p>
<p>So, because this is an Earley parser, the state is going to be something like "a list of state sets", where a state set is "a set of Earley items", where an Earley item is "a rule, the index of when it started in the state, and partial completion data".
For a <em>recogniser</em>, the completion data is just how far you've read, but if you want to parse, I assume it needs to accumulate the previously-parsed items instead.
I should... probably read further in the tutorial, I think.</p>
<p>All right, I read over it, and here's where my understanding is:</p>
<ul class="simple">
<li>Loup is talking, at least at first, about extracting the parse data from the information gathered by the recognizer.</li>
<li>What I had in mind would have been very inefficient, because it would have essentially performed eager evaluations that wouldn't succeed.</li>
</ul>
<p>So, basically, I want to say:</p>
<ul class="simple">
<li>Given a state, can we extract a valid parse tree from it?</li>
<li>Given a parse tree, we can materialize an AST (which would presumably include information like text positions, or anything else helpful), but this means that we can't carry out the actions until we have a parse tree, which means my ideas about discarding the token stream as we process it <em>do not work</em>.</li>
<li>Like, it's possible to write the code to consume a stream, but that's only worth it if it makes the code easier to understand, because it doesn't do anything memory-wise.
I mean, I guess it would allow early termination if the token stream is bad and it results in an empty state set.</li>
</ul>
<p>Ooh, I've got an idea that could be really good or really weird.
Suppose we have some kind of stream-recording data structure, so we can then make our functions operate on streams.
If we organize the generation of items according to <a class="reference external" href="https://github.com/jeffreykegler/kollos/blob/master/notes/misc/leo2.md">Jeffrey Kegler's open letter</a> (scans, completions, predictions), then <em>I think</em> it should be possible to say "okay, we can view a set as consuming one iterable and producing two, by taking an initial iterator from the previous set and expanding on it, and also producing an iterator of scans for the next set".
By interleaving the order of iteration, it "should" be possible to make sure that all possible parses are reached, even if some rules recurse indefinitely (which, why would you do that, but whatever).
(Although, if there's an indefinitely recursive rule and a syntax error, then this idea would presumably keep on trying the same stream of nullable rules in the hope that that will somehow repair the parse downstream...
So it's almost like, indefinitely recursive rules should trigger once-ish for the initial parse pass, and then they can kind of do whatever when it comes time to perform actions on a tree.)</p>
<p>In any case, I'm going to need to do a bunch of sketching of this stuff on paper, because these concepts don't all fit in my head.</p>
<p>And, I've got some other stuff I want to take care of right now, so I'm going to wrap this up here.</p>
<p>Good night.</p>
Coding 2022-01-052022-01-05T05:00:00-05:002022-01-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-05:/coding-2022-01-05<p class="first last">I don't have anything in mind to do with this, but at least it's got a smaller scope than the last project I had like that.</p>
<p>Okay, so.
I'm still coding, but I <em>am</em> taking a break from MOTR.</p>
<p>Basically, I recently read a <a class="reference external" href="https://tratt.net/laurie/blog/entries/text_is_dead_they_say.html">blog post about parsing</a>, and it inspired me to look into Earley parsers some more.</p>
<p>I'm right now trying to roll one on my own, based on <a class="reference external" href="https://loup-vaillant.fr/tutorials/earley-parsing/">a tutorial</a> and some 20-year-old Python code which I am just trying to get the broad strokes of, since it's targeting Python 1.5 and has hand-optimized stuff that... I don't actually know if that optimization is backed up with profiling.</p>
<p>So, I'm trying to get the broad strokes and put together something using modern Python, which is shockingly different from, Python so old I never personally used it.</p>
<p>In any case, it's late and I'm tired, so I'm going to have to wrap things up now.</p>
<p>Good night.</p>
Weekly Roundup 2022-01-042022-01-04T05:00:00-05:002022-01-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-04:/weekly-roundup-2022-01-04<p class="first last">This neither sounds nor felt like much of an accomplishment.</p>
<ul class="simple">
<li>Wednesday: I started re-simplifying the <tt class="docutils literal">Dynamic</tt> class in MOTR.</li>
<li>Thursday: I planned out some of the changes I needed to make to the functions, formerly methods.</li>
<li>Friday: I did some more work, and some more planning.</li>
<li>Saturday: A bit more work...</li>
<li>Sunday: A stub class or two...</li>
<li>Monday: I tried to fill in the classes, and Mypy quasi-accidentally pointed out a bug to me.</li>
</ul>
<p>Next week, I want to take some kind of break from MOTR.
Either as subtle as switching back to planning and writeups instead of writing code, or <em>actually working on something different</em>.</p>
<p>(I just remembered I was thinking of redoing my weekly... schedule is too strong a word... rhythm? This year. Um... eh. I'll see how I feel once I've had some more sleep.)</p>
Coding 2022-01-032022-01-03T05:00:00-05:002022-01-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-03:/coding-2022-01-03<p class="first last">It's nice when the tools don't have a super-obvious bug.</p>
<p>Okay, I'm sort of rested up.
I'm going to try to get code stuff done a little early today.
Let's see...</p>
<p>The obvious place for me to prove out this design is in the method that will convert an <tt class="docutils literal">Invocation</tt> to a <tt class="docutils literal">Dynamic[Command]</tt>.</p>
<p>I'm sketching out the rough details, avoiding the really gnarly parts, but the gnarly parts are coming to me.
I hit a condition that looks extremely like a bug in Mypy to me.
Like, it replaced a concrete type with a type variable.
I don't know why it gave up that information.</p>
<p>Wait, wait, wait, no I just wrote the code wrong.
Let's see, if I fix the code the, yep, there it goes, passes just fine.</p>
<p>It turns out Mypy doesn't run on the code you <em>thought</em> you wrote.</p>
<p>Anyway, looks like one of the next things I want to cover is redoing some of the type signatures for those functions I was rewriting and moving around.</p>
<p>To be honest, I'm not feeling like pushing things late, so I'm just going to take things easy and call it now.</p>
<p>Good night.</p>
Coding 2022-01-022022-01-02T05:00:00-05:002022-01-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-02:/coding-2022-01-02<p class="first last">Incremental progress.</p>
<p>Did some more travel today, so I can take things easy tomorrow.</p>
<p>I got started on this late, so it's going to be another quick set of thoughts today.</p>
<p>The missing alternative for <tt class="docutils literal">Part</tt> needs to be a combination of a <tt class="docutils literal">DynamicFunc[Option[TProgram]]</tt> and a vector of <tt class="docutils literal">ValueAdaptor</tt>s.
It should use some of the code that's currently in the <tt class="docutils literal">builder</tt> decorator, which I'll want to phase out ASAP.</p>
<p>Let's see about writing that class quickly.</p>
<p>Wrote the class, wired it in, no decorators or methods yet...</p>
<p>And, Mypy complained.</p>
<p>Let's fix this quick, and get to bed.
Okay, hopefully fixed...</p>
<p>And, actually fixed.
I'll work on decorator stuff tomorrow, unless I think of something that needs to happen before that.</p>
<p>Good night.</p>
Coding 2022-01-012022-01-01T05:00:00-05:002022-01-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2022-01-01:/coding-2022-01-01<p class="first last">Quick update for the new year.</p>
<p>I was once again messing around with stuff today, so I didn't have much time to touch the code, wasn't really thinking about it clearly.</p>
<p>I started working on the new module, and I didn't get it far enough to work on the next steps.</p>
<p>What I have to start with:</p>
<ul class="simple">
<li>A class for representing constant values.</li>
<li>A union alias, not fully filled in, to represent the things that can be used in the invocations, which is what I'm calling this last abstraction.</li>
<li>The <tt class="docutils literal">Invocation</tt> class, which hopefully will bring together everything I need.</li>
</ul>
<p>It's the new year for me now, so I'll wrap this up.</p>
<p>Good night.</p>
Coding 2021-12-312021-12-31T05:00:00-05:002021-12-31T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-31:/coding-2021-12-31<p class="first last">They're not all horrible weird one-liners, but it's close enough.</p>
<p>Okay, I've managed to squeeze all the enjoyment that I can get out of rewriting this <tt class="docutils literal">Dynamic</tt> code, which I'm sure is more enjoyment than most people could get.
It's not totally the way I'd like it, but it's close enough.
Let's see what I need to do next:</p>
<ul class="simple">
<li>Pull the functions into a new module to avoid import cycles when I update the return types.</li>
<li>Write the code for hopefully the last general abstraction.</li>
<li>Write types to simplify writing decorators, because I have to rewrite an existing decorator <em>anyway</em>, because it should be using the code from the previous step.</li>
<li>Rewrite that decorator.</li>
</ul>
<p>At this point, the typing errors should force everything into using the last abstraction, and I can make sure the ergonomics look reasonable, and then <em>finally write some tests for this stuff</em>.</p>
<p>At the moment, I need to take some time to cool off.</p>
<p>Good night.</p>
Coding 2021-12-302021-12-30T05:00:00-05:002021-12-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-30:/coding-2021-12-30<p class="first last">Video games...</p>
<p>I bashed at the code some more today, and gradually got different parts of it more similar to each other.
At this point, to go with the <tt class="docutils literal">map</tt>-style functions I've written, I need a custom <tt class="docutils literal">reduce</tt>-style function.</p>
<p>Here's what it needs to take:</p>
<ul class="simple">
<li>Reducing callable (in this case, <tt class="docutils literal">Option.with_option</tt>)</li>
<li><tt class="docutils literal">Dynamic</tt> value</li>
<li>Keys to iterate over</li>
<li>Initial value</li>
</ul>
<p>The resulting <tt class="docutils literal">Dynamic</tt> should have an <tt class="docutils literal">instantiate</tt> defined by the function, a <tt class="docutils literal">keys</tt> equal to the argument, and the <tt class="docutils literal">maximal</tt> and <tt class="docutils literal">flexible</tt> values carried over from the <tt class="docutils literal">Dynamic</tt> argument.</p>
<p>Before I do that, I want to figure out some way to cut down on the size of the last big nested function.</p>
<p>I need to take some time to think about this (and play videogames).</p>
<p>Good night.</p>
Coding 2021-12-292021-12-29T05:00:00-05:002021-12-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-29:/coding-2021-12-29<p class="first last">Staring at my code like "Why's it broken <em>now</em>?"</p>
<p>All right.
I was playing video games most of the day, so I didn't touch MOTR, but gosh dang it, I want to, so let's see what I can do about the to-do list I wrote last time.</p>
<p>I was able to convert the methods into functions by dedenting the <tt class="docutils literal">def</tt> line and running <tt class="docutils literal">black</tt>.</p>
<p>Next, I need a helper that acts as a <tt class="docutils literal">DynamicFunc[CmdMeta]</tt>, given a <tt class="docutils literal">Dynamic[T]</tt> and a <tt class="docutils literal"><span class="pre">Callable[[T],</span> CmdMeta]</tt>.
This is the core logic of <tt class="docutils literal">map_1_dynamic</tt>, so I'll factor that out, then factor it out for the <tt class="docutils literal">flex</tt> functions.</p>
<p>I'm working on shrinking down the insides of those functions so they're easier to reason about, but it looks like I added some typos in the latest refactor attempt, so I'm going to just fix those and publish.</p>
<p>I'll try to get a bit further tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2021-12-282021-12-28T05:00:00-05:002021-12-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-28:/weekly-roundup-2021-12-28<p class="first last">Work work work, crash, but not because of working...</p>
<ul class="simple">
<li>Wednesday: I changed <tt class="docutils literal">Builder</tt> to <tt class="docutils literal">Dynamic</tt>, and moved it to a new module.</li>
<li>Thursday: I revisited my notes/plans from last week, and made sure I understood how to proceed with them.</li>
<li>Friday: I started implementing stuff from those plans.</li>
<li>Saturday: I wrote some helper functions, and planned ahead a bit more.</li>
<li>Sunday: I did some more detailed planning.</li>
<li>Monday: I tired myself out, so I didn't really do anything there.</li>
</ul>
<p>Next week, I'm going to try to execute some of the plans I the night before last.
At the same time, earlier today, I got back to work on Missable Mysteries, and I definitely want to continue on with that.
I think I need to start sketching out the diagrams for the post, and then I'll have a better sense of how to proceed with it.
Anyway, I'll worry more about the details tomorrow.</p>
Diary 2021-12-272021-12-27T05:00:00-05:002021-12-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-27:/diary-2021-12-27<p class="first last">I'm too tired right now to think about moving ever again.</p>
<p>Okay.
We were traveling and visiting people for part of today, so I didn't get a chance to mess with code.</p>
<p>I can't think of anything else to write about right now.
We're going to be spending the week recovering from the holidays, I guess.</p>
<p>Something seems a little off about "Oh, we don't have work, let's make sure we're <em>even more</em> exhausted." but whatever.</p>
<p>I'm not wringing any more thoughts out of my brain tonight, so I'm not going to try any more.</p>
<p>Good night.</p>
Coding 2021-12-262021-12-26T05:00:00-05:002021-12-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-26:/coding-2021-12-26<p class="first last">Please, let this be the last abstraction. Oh please oh please oh please.</p>
<p>This was a good Christmas.
But also, I am utterly wiped out.
Let's see what I'm up for.</p>
<p>I was telling my wife about the current state of the project, and I compared it to writing a story in which you're just constantly introducing new shadowy figures which were secretly behind everything all along, including the <em>previous</em> shadowy figures.
There's at least a bit more purpose to these abstractions, but it's tiring all the same.</p>
<p>In any case, regardless of whether this layer is the last one, let's get it over with.</p>
<p>The top-level container starts with a <tt class="docutils literal">Command</tt> (probably in the "installer plus string" sense), is followed by any number of type-coordinated <tt class="docutils literal">Option</tt>-producing objects, and has an optional "module" argument which can contain another instance of the overall value, but with any program type.</p>
<p>There are three or four basic possibilities for "<tt class="docutils literal">Option</tt>-producing objects":</p>
<ul class="simple">
<li>Constant string sequences / environment variables, possibly accompanied by installer requirements.
These must contain no <tt class="docutils literal">IO</tt> objects.</li>
<li>Combinations of <tt class="docutils literal">ValueAdaptor</tt> objects with <tt class="docutils literal">Dynamic</tt> <tt class="docutils literal">Option</tt>s that don't involve <tt class="docutils literal">Output</tt> objects.</li>
<li>Flexible <tt class="docutils literal">Dynamic</tt> objects that create restricted <tt class="docutils literal">Option</tt>s that involve <tt class="docutils literal">Output</tt> objects.</li>
<li>The "or four" comes from, ideally the same flexible <tt class="docutils literal">Dynamic</tt>s that create the restricted options can be used to create the <tt class="docutils literal">ValueAdaptor</tt> + <tt class="docutils literal">Dynamic</tt> things, when they're being used for input.</li>
</ul>
<p>This is going to require a few things.
One is that the <tt class="docutils literal">builder</tt> decorators get completely overhauled to create the <tt class="docutils literal">Output</tt>-less <tt class="docutils literal">Dynamic</tt>s + <tt class="docutils literal">ValueAdaptor</tt> objects.
The other is that the <tt class="docutils literal">flex</tt> methods need to be split up into pairs that have different output types, because now the "<tt class="docutils literal">Output</tt> <tt class="docutils literal">flex</tt>" gets invoked implicitly, but the "<tt class="docutils literal">Input</tt> <tt class="docutils literal">flex</tt>" is invoked more differently and has a different overall purpose.</p>
<p>Here's how I want to lay the groundwork for this:</p>
<ul class="simple">
<li>Pull the <tt class="docutils literal">flex</tt> methods out into functions.</li>
<li>Factor out common logic into helper functions.</li>
<li>See if any of those helper functions should be converted back into methods.</li>
<li>Split out the input and output code paths, so I end up with four public top-level functions.</li>
<li>Consider moving most of these functions to their own module.</li>
</ul>
<p>At this point, I can work on the new types and functions, and updating the existing decorators.
At that point, I may put together the basic type helpers I had in mind for helping with the decorators, since I'm going to be messing with the decorators again, and it would be nice to apply a mild level of Don't-Repeat-Yourself to the type annotations.</p>
<p>Anyway, I'm really tired, as previously established, so I'm going to publish this, reflect on these ideas, and ponder some incredibly cursed programming ideas I've been thinking about.</p>
<p>Good night.</p>
Coding 2021-12-252021-12-25T05:00:00-05:002021-12-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-25:/coding-2021-12-25<p class="first last">Could this actually be the last layer of abstraction?</p>
<p>Earlier today, I wrote some decorators to make it easier to create <tt class="docutils literal">InputAccumulator</tt>s and <tt class="docutils literal">ValueAdaptor</tt>s.
Typing them was a bit obnoxious, and I was tempted to put together some helper types, but I decided against it for now.</p>
<p>Right now, I need to check over how this code could be used, and see if I need more helpers.
I'm feeling a little out of it at this point, unfortunately, so I'm just going to take a few notes.</p>
<ul class="simple">
<li>Currently, I have separate <tt class="docutils literal">Dynamic</tt>s for the <tt class="docutils literal">src</tt> and <tt class="docutils literal">tests</tt> directories for <tt class="docutils literal">flake8</tt>.
For now, I should merge them into one.</li>
<li>I'm missing the class to combine a <tt class="docutils literal">ValueAdaptor</tt> with the <tt class="docutils literal">Dynamic</tt> using the keys...
Actually, since these <tt class="docutils literal">Dynamic</tt>s could <em>theoretically</em> use multiple keys, I guess what I want is to replace the current decorator invocations with something that takes <tt class="docutils literal">ValueAdaptor</tt>s...</li>
</ul>
<p>Note to my future self: this isn't redundant with the <tt class="docutils literal">path_segments</tt> concept, because that controls the virtual environment path, and it's possible to reuse virtual environments for different commands.
Okay?
Okay.
Good.</p>
<p>Anyway, I guess the ultimate form of this is something that looks sort of like the <tt class="docutils literal">Command</tt> interface, but augmented with <tt class="docutils literal">InputAccumulator</tt>s and <tt class="docutils literal">ValueAdaptor</tt>s.
I'm imagining something that takes one <tt class="docutils literal">Command</tt> argument, some number of possibly value-adapting <tt class="docutils literal">Dynamic</tt> <tt class="docutils literal">Option</tt>s of the same <tt class="docutils literal">Program</tt> type, and also possibly some <tt class="docutils literal">InputAccumulator</tt>s, as well as an optional keyword argument to invoke a module with the same general types.
I really hope this is the last level of abstraction I end up layering on top of all of this, but I guess we'll see!</p>
<p>Anyway, I'll try to put this all into practice next week.
Handling:</p>
<ul class="simple">
<li>New argument types</li>
<li>Accumulating off the <tt class="docutils literal">ValueAdaptor</tt> data</li>
<li>Making sure I'm right about the order this all happens in, because I think I can generate the final <tt class="docutils literal">Dynamic</tt> for a command without instantiating it, and thereby extract a flex input to convert to an output from a previous command.</li>
</ul>
<p>(So, setting up coverage looks like "generate command with no deletion dependencies, extract the coverage output, convert it to a deletion input, then pass that output version to the erase and the input version back to the original command to create the true final version".
Eugh.)</p>
<p>Good luck with whatever you're working on.
I'm certainly going to need it to get through this.</p>
<p>Good night.</p>
Coding 2021-12-242021-12-24T05:00:00-05:002021-12-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-24:/coding-2021-12-24<p class="first last">It seems to be all set, but I'm not sure I trust it.</p>
<p>Okay, I've put together a rough draft of the accumulator and adaptor stuff.
It was a bit annoying to get the necessary actions together.
I ended up with nested functions like:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">instantiate</span><span class="p">(</span>
<span class="n">objects</span><span class="p">:</span> <span class="n">_objects</span><span class="o">.</span><span class="n">Objects</span><span class="p">,</span>
<span class="n">items</span><span class="p">:</span> <span class="n">_items</span><span class="o">.</span><span class="n">Items</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">_requirements</span><span class="o">.</span><span class="n">Requirements</span><span class="p">[</span>
<span class="n">_io</span><span class="o">.</span><span class="n">Input</span><span class="p">[</span><span class="n">_cmd</span><span class="o">.</span><span class="n">PathStr</span><span class="p">]</span>
<span class="p">]:</span>
<span class="k">return</span> <span class="p">(</span>
<span class="k">yield from</span> <span class="bp">self</span><span class="o">.</span><span class="n">dynamic</span><span class="o">.</span><span class="n">instantiate</span><span class="p">(</span>
<span class="n">objects</span><span class="p">,</span> <span class="n">items</span>
<span class="p">)</span>
<span class="p">)</span><span class="o">.</span><span class="n">map</span><span class="p">(</span>
<span class="k">lambda</span> <span class="n">path_str</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">accumulator</span><span class="p">(</span>
<span class="n">adaptor</span><span class="o">.</span><span class="n">adaptor</span><span class="p">(</span>
<span class="n">items</span><span class="p">[</span><span class="n">adaptor</span><span class="o">.</span><span class="n">key</span><span class="p">]</span>
<span class="p">),</span>
<span class="n">path_str</span>
<span class="p">)</span>
<span class="p">)</span>
</pre></div>
<p>Except a little less skinny, because I reformatted that to try to fit in the code box.</p>
<p>There is a ridiculous amount of stuff going on there.
The whole function conforms to the <tt class="docutils literal">DynamicFunc[Input[PathStr]]</tt> interface, and relies on the wrapped value being a <tt class="docutils literal">Dynamic[Input[PathStr]]</tt>, so it can produce the actual value, and then use <tt class="docutils literal">Input</tt>'s <tt class="docutils literal">map</tt> method to adapt the <tt class="docutils literal">Input</tt>'s wrapped value with a partial call of the <tt class="docutils literal">accumulator</tt> field function, with the dynamic value corresponding to the adaptor's key, adapted by the adaptor.</p>
<p>This is all to say that this code had better work, after all the trouble I went through writing it.</p>
<p>I'm not going to try to use this code just yet, but I should get on that in the next few days.</p>
<p>I'm going to wrap up now before I stay up too late again.</p>
<p>Good night.</p>
Coding 2021-12-232021-12-23T05:00:00-05:002021-12-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-23:/coding-2021-12-23<p class="first last">I traveled and procrastinated today, but I wanted to get <em>something</em> done.</p>
<p>Just going to sum some things up quickly...
Slightly bad/annoying news on the "wrapper types for dealing with <tt class="docutils literal">Dynamic</tt> <tt class="docutils literal">Output</tt>" front.</p>
<p>I added a new type into the mix, to handle <tt class="docutils literal">Token</tt> targets that are added as <tt class="docutils literal">extra_io</tt>.
(Noting how they're added is mainly relevant because <tt class="docutils literal">Token</tt> instances can't be passed on the command line.)
This is a problem, among other reasons, because <tt class="docutils literal">Token</tt> is one of the few classes that I specifically intend for other libraries to be free to subclass.
That means I'm going to need to nail down exactly what the code needs to be able to do, and define that as an abstract function on the <tt class="docutils literal">Token</tt> class.</p>
<p>So, let's review my previous sketches in light of the new reality.
There may be multiple <tt class="docutils literal">InputAccumulator[T]</tt> classes or there may not, doesn't matter.
The new value of <tt class="docutils literal">T</tt> that needs to be accounted for is <tt class="docutils literal">Token</tt>.
(The only subclass of <tt class="docutils literal">Token</tt> currently is <tt class="docutils literal">Deleted</tt>, which wraps a ... string?
I don't remember why I wanted to use a string instead of <tt class="docutils literal">pathlib.Path</tt>.)
Either way, we need some way to define a function that accumulates information into a <tt class="docutils literal">Token</tt>.
My inclination is to have something similar to <tt class="docutils literal">Input</tt>'s <tt class="docutils literal">map</tt> method.
Make <tt class="docutils literal">Token</tt> parametric on the wrapped type and put the type information in the method signature.</p>
<p>Here's another wrinkle...
In my use case for this, the <tt class="docutils literal">Deleted</tt> instances have to match up one-to-one with some paths generated elsewhere in the function...</p>
<p>So do I want this to go like:</p>
<ul class="simple">
<li>Fully generate the paths, extract the final <tt class="docutils literal">Dynamic</tt> at some point, and map <tt class="docutils literal">deleted</tt> over its contents, and re-flex the result?</li>
<li>OR generate the data twice and keep it in sync with itself?</li>
</ul>
<p>I'd been worried there was some reason I couldn't do the first option, but it looks like I was wrong.
This is nice, because I means I don't actually have to do any of the stuff I was pondering earlier: I can do all of the hard stuff exactly once, then write a tiny trivial map function over <tt class="docutils literal">Dynamic</tt> in order to convert the inner type.</p>
<p>It's getting late, so I can't stretch this out too much further, but I'll try to nail things down more tomorrow.</p>
<p>Good night.</p>
Coding 2021-12-222021-12-22T05:00:00-05:002021-12-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-22:/coding-2021-12-22<p class="first last">Kind of tempted to see if I could code golf this with HKTs, but I'd rather work on adding functionality.</p>
<p>All right, I have a new name for <tt class="docutils literal">Builder</tt>.
I'm going to try calling it <tt class="docutils literal">Dynamic</tt>.</p>
<p>Okay, as I started copying things over, I realized that I'm missing a <tt class="docutils literal">flex</tt>-style method for handling implicit prerequisites and outcomes, stuff that doesn't directly show up on the command line.
I know I need that to make Coverage work properly, so I've got to get that in at some point.
Hopefully, get this big weird convoluted method written right next to the other big weird convoluted method will give me some inspiration to factor out common logic.
One aspect of this that's somewhat unfortunate is, I'm going to have to switch from storing "dynamic flexible" instances in a simple map to another registry-style mapping.
That'll be the fourth one, unless I just...
I think I can safely shove this in an <tt class="docutils literal">Objects</tt>, I just need to parameterize it aggressively.
Wait, no, that doesn't work.
I legitimately need a whole new registry type.
UUUUUUGH.</p>
<p>Well, I did it, and I got everything moved over.
At this point, the <tt class="docutils literal">types</tt> module contains no <tt class="docutils literal">class</tt> statements, which is... interesting.</p>
<p>Anyway, that was a marathon session, it felt like, and I think the new <tt class="docutils literal">dynamic</tt> module is somehow <em>longer</em> than <tt class="docutils literal">types</tt> was yesterday?
I'm not going to dwell on that too much.</p>
<p>I think, in light of the enhancements I made to the <tt class="docutils literal">Dynamic</tt> class, I want to take a break from this refactor, and work on writing the classes I was sketching out last week.</p>
<p>For now, I want to decompress from all of the coding I just did.
Time to take things easy.</p>
<p>Good night.</p>
Weekly Roundup 2021-12-212021-12-21T05:00:00-05:002021-12-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-21:/weekly-roundup-2021-12-21<p class="first last">Having experienced pain, I would not recommend it.</p>
<ul class="simple">
<li>Wednesday: I did some work sketching out the types to generate the flexible builders for MOTR.</li>
<li>Thursday: Oh, the pain.</li>
<li>Friday: I made a plan for breaking up some of the modules in MOTR.</li>
<li>Saturday: I got rid of some weird prototype code, and started splitting things up.</li>
<li>Sunday: I did some more splitting-up, then revisiting the sketch work I did for Wednesday on Tuesday.</li>
<li>Monday: I split out some more code, and fixed some bugs that I feel like mypy let me down a little by not catching.</li>
</ul>
<p>Next week, I'm going to be taking a break from work, and hopefully making some good progress on all of my hobby stuff, like MOTR.</p>
Coding 2021-12-202021-12-20T05:00:00-05:002021-12-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-20:/coding-2021-12-20<p class="first last">I think I need to write tests of my types, which is... a pain, probably.</p>
<p>Hoo boy.
I pulled out the stuff related to <tt class="docutils literal">Command</tt> and <tt class="docutils literal">Fragment</tt> into two modules.
This helped me by getting them into separate files, and I could rename <tt class="docutils literal">Fragment</tt> to also be <tt class="docutils literal">Command</tt>.
This is a bit awkward, but it's all right for now.
At least it's possible, with the classes living in separate modules.</p>
<p>One thing I discovered from investigating the <tt class="docutils literal">CmdMeta</tt> class and related functions, was that I'd gotten some of the method signatures wrong, in a way that I'd have expected mypy to catch, but I guess there were too many <tt class="docutils literal">Any</tt>s in there.
We'll see if this works better once I've actually run some of this code.</p>
<p>If I want more substantial posts from these rewrites, I should probably write them as I work on the code.
As it is, I'm trying to remember what exactly I did, and I'm like "Man, that was like ten hours ago, that's <em>ancient history</em>."</p>
<p>Anyway, I'll be able to work on stuff more intensely in a few days.
I don't know if I actually will, but I'll be <em>able</em> to.</p>
<p>Anyway, I'm not going to push myself any further tonight, so I'm done for now.
In any case, <em>soon</em>.</p>
<p>Good night.</p>
Coding 2021-12-192021-12-19T05:00:00-05:002021-12-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-19:/coding-2021-12-19<p class="first last">I'm not sure how interesting any of this is. Oh well.</p>
<p>Okay.
I did some more work on breaking up MOTR modules.
I don't remember if there was anything of note.</p>
<p>I've got more work to do there, but I should make sure I'm ready to add more required functionality, once that's done.</p>
<p>So, that'd be the pair of types that generate <tt class="docutils literal">Builder[Input[PathStr]]</tt> objects, and invoking its <tt class="docutils literal">flex</tt> method with a specified prefix, all contributed keys, and predetermined output data that includes output names and whether to create the parent directory, as well as the index to store the base Builder on (not yet implemented).</p>
<p>Anyway, that's important when I get to split out <tt class="docutils literal">Builder</tt>.
Before that, I've got to work with the aliases at the beginning of the <tt class="docutils literal">types</tt> module.
There's some duplication of aliases between <tt class="docutils literal">motr._api.cli.types</tt> and <tt class="docutils literal">motr._api.actions.cmd</tt>, and some of them should be defined partially within <tt class="docutils literal">motr._api.actions.io</tt>.
Let's see what I can do there.</p>
<p>Okay, I'm still not seeing much to talk about here, but there's more work to do, so I'm going to publish and then mess around a bit more.</p>
<p>Maybe I'll have something more definite to talk about tomorrow.
Frankly, I'm not going to worry too much.</p>
<p>Good night.</p>
Coding 2021-12-182021-12-18T05:00:00-05:002021-12-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-18:/coding-2021-12-18<p class="first last">Really appreciating having modules that are closer to, like, a screen in size, rather than being $LONG lines long.</p>
<p>Wish me luck, I'm going to try to clean up the code a little.
Basically, since a lot of this code isn't hooked up to anything, I'm safe to mess around with it without having to consider what it'll mean for the project's own motrfile.
I'm switching over to the subclassing-based solution, so let's see what the necessary changes look like.</p>
<p>The system that I'm replacing was using <tt class="docutils literal">Literal</tt> types to represent different programs.
Which is mostly fine, but it has a bunch of minor shortcomings, and it also looks really strange.
The basic point of all of this was to use these literals as marker types.
But repurposing literal types for this was awkward and inflexible.
To my mind, I'm not really running the usual risks of a subclassing-based interface, if the classes only really do anything at the type level, so they never actually get instantiated.</p>
<p>Anyway, that was all pretty simple.
My next issue is splitting up the <tt class="docutils literal">types</tt> module.
The problem there is where to put them.
As long as the <tt class="docutils literal">cli</tt> package is mostly a bundle of related things, I'd rather it not be a bundle of <em>two kinds</em> of things.
For now, and this doesn't seem like an objectively great solution as I type this, but I haven't thought of the better one yet, I'm going to split off these new modules into a <tt class="docutils literal">cli_types</tt> package.
Let's see how that works out for me.</p>
<p>First I'm going to add the package and just make sure the bare package doesn't somehow break anything.
Now, let's see what it takes to split out the <tt class="docutils literal">Key</tt> code into its own module.
While I was working on this, I noticed something that I think I like more as a way to handle some of the functionality, so I made that change at the same time because, like, whatever.</p>
<p>Okay, I went and pulled that functionality out into its own module.
Next up is...
Let's try the Registry classes.</p>
<p>...</p>
<p>I now realize that the distinction between "Objects" and "Items" is... obscure at best.
I'm not totally sure what to do about that.
I'm just going to leave it as-is for now and sleep on it for a bit.
Anyway, let's finish up this migration.</p>
<p>...</p>
<p>I'm not focusing super-well right now, so this is going a little slow.</p>
<p>...</p>
<p>All right, it's late, but I've successfully pulled out two modules.
It turns out they were pretty small, so I didn't really cut down on the main <tt class="docutils literal">types</tt> module yet, but in time...</p>
<p>Anyway, there's no way I'm getting anything else done tonight, so I'm calling it here.</p>
<p>Good night.</p>
Coding 2021-12-172021-12-17T05:00:00-05:002021-12-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-17:/coding-2021-12-17<p class="first last">Preparing to break some modules up.</p>
<p>Okay, I'm still tired, but I'm not <em>in pain</em> any more.
I want to get something code-related done.
One thing that I've been doing with MOTR, is focusing on new functionality to make writing the motrfile easier.
But before I start prototyping that stuff, it might be worth trying to clean up some of the new modules I'm writing.
Most of the code I've written is in the <tt class="docutils literal">motr._api.cli.types</tt> module, which is the largest module in the package by statement count, and over twice as large as the next-largest module.
Let's see if I can find any points of division.</p>
<p>First, let's see what's in there.</p>
<ul class="simple">
<li>Imports.</li>
<li>TypeVar and alias definitions.
Some are completely generic, others are specific to the <tt class="docutils literal">Fragment</tt> API, and have some weird decisions.
Some of this code should maybe be replaced with an API that's based on subclassing.
Which is weird for me to say, but I have good reasons for this very particular case.
Some of these aliases seem like they mainly serve to confuse me, and I should try to cut down on them.</li>
<li>The <tt class="docutils literal">Installer</tt> protocol and supporting types.</li>
<li>The <tt class="docutils literal">Key</tt> class and supporting aliases and functions.</li>
<li>The <tt class="docutils literal">Command</tt> class, which brings together the previous two classes.
And a bunch of aliases that I wonder if there's some more elegant way to deal with.
And helper functions that convert between those aliases as needed.</li>
<li>The Registry Protocols (which are used by the helper functions).
These Protocols are kind of obnoxious, for two reasons.
For one, they're all very similar and it feels like I'd be able to consolidate them with HKTs.
For another, once I add enough methods, <tt class="docutils literal">PMap</tt>s stop satisfying them, but it's weirdly tricky to nail down why.
Like, maybe there are sets of three methods, where I can have any two, but if I add all three, it stops type-checking???
I do not understand what is going on.
Anyway, there's also a helper method for one kind of Registry in particular.</li>
<li>Next we get to <tt class="docutils literal">Fragment</tt> API stuff.
Starting with <tt class="docutils literal">CmdMeta</tt>, which has methods that call some of the helper functions above, and those functions should probably just be inlined into these methods, which could maybe be properties.
Then, we've got the <tt class="docutils literal">Fragment</tt> and <tt class="docutils literal">Option</tt> classes.</li>
<li>Next up the <tt class="docutils literal">Builder</tt> classes.
<tt class="docutils literal">Builder</tt> has some methods that I suspect could be rewritten into some kind of <tt class="docutils literal">map</tt> method, and one that I'm not sure what to do about, the <tt class="docutils literal">flex</tt> method, which is big and complicated, and could probably be simplified <em>somehow</em>.
(Like, maybe I can factor things out so it's got a <tt class="docutils literal">map</tt> style method on one side, and a callable on the other.)</li>
<li>Random helper functions and classes that synthesize the preceding stuff in various manners.
Including one helper that works with nothing but basic registries.</li>
<li>Finally, the helper function that synthesizes stuff from the whole rest of the module into a useful bridge between its high-level representation, and the rest of MOTR's not-quite-as-high-level representation.</li>
</ul>
<p>Thinking over this, here's a division that I'd like to try making:</p>
<ul class="simple">
<li><tt class="docutils literal">Installer</tt> and <tt class="docutils literal">InstallerRegistry</tt> and <tt class="docutils literal">combine</tt></li>
<li><tt class="docutils literal">Key</tt>, <tt class="docutils literal">new_key</tt>, and <tt class="docutils literal">IterableKeys</tt></li>
<li><tt class="docutils literal">Command</tt> and <tt class="docutils literal">CmdMeta</tt> and <tt class="docutils literal">base_cmd</tt></li>
<li><tt class="docutils literal">ObjectRegistry</tt> and <tt class="docutils literal">ItemRegistry</tt> and <tt class="docutils literal">item_registries</tt></li>
<li><tt class="docutils literal">Fragment</tt> and <tt class="docutils literal">Option</tt> and <tt class="docutils literal">static_option</tt></li>
<li><tt class="docutils literal">Builder</tt> and <tt class="docutils literal">Nullary</tt> and <tt class="docutils literal">static_builder</tt> and <tt class="docutils literal">OutputData</tt></li>
<li><tt class="docutils literal">builder</tt></li>
<li><tt class="docutils literal">builder_requirements</tt></li>
</ul>
<p>That should properly divide things up so I'm not constantly spelunking in a 600-line file.
I'll try and look into this later, when I have a bit more energy.
For now, I'll see about getting some energy back.</p>
<p>Good night.</p>
Diary 2021-12-162021-12-16T05:00:00-05:002021-12-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-16:/diary-2021-12-16<p class="first last">The details are too disgusting.</p>
<p>I really wanted to get work done on something tonight, but I <em>also</em> wanted to not be in excruciating pain, so I guess I'm just getting disappointed a lot tonight.</p>
<p>I can't really focus, and I've done all I can for now, so I don't think there's anything for me to do but wait.
I'm not going to try to accomplish anything else now.</p>
<p>Good night.</p>
Coding 2021-12-152021-12-15T05:00:00-05:002021-12-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-15:/coding-2021-12-15<p class="first last">Carefully nailing down responsibility to avoid requiring some of the objects to basically be magic.</p>
<p>Okay, I'm still focused on MOTR, so I might as well think about it carefully.
Right now, I'm concerned with synthesizing <tt class="docutils literal">Builder[Input[PathStr]]</tt> objects.
This can be more-or-less broken into several distinct parts:</p>
<ul class="simple">
<li>An initial <tt class="docutils literal">Builder[Input[T]]</tt>, where the type variable has some reasonable bounds.</li>
<li>A <tt class="docutils literal"><span class="pre">Callable[[U,</span> T], T]</tt> that builds up the wrapped value; <tt class="docutils literal">T</tt> can unify with <tt class="docutils literal">U</tt>, but this isn't required.</li>
<li>For key of type <tt class="docutils literal">Key[PVector[K]]</tt>, a <tt class="docutils literal"><span class="pre">Callable[[K],</span> U]</tt> to convert the values from the <tt class="docutils literal">ItemRegistry</tt> into the proper form.</li>
</ul>
<p>This should coalesce into a few specific objects:</p>
<ul class="simple">
<li><tt class="docutils literal">InputAccumulator[T, U]</tt> wraps a <tt class="docutils literal">Builder[Input[T]]</tt> and a <tt class="docutils literal"><span class="pre">Callable[[U,</span> T], T]</tt>.</li>
<li><tt class="docutils literal">ValueAdaptor[K, U]</tt> wraps a <tt class="docutils literal">Key[PVector[K]]</tt> and a <tt class="docutils literal"><span class="pre">Callable[[K],</span> U]</tt>.</li>
</ul>
<p>The <tt class="docutils literal">InputAccumulator[T, U]</tt> has an evolution method that takes a <tt class="docutils literal">ValueAdaptor[K, U]</tt>.
Once all values are accumulated, the wrapped <tt class="docutils literal">Builder[Input[T]]</tt> can be extracted and converted into a higher-level <tt class="docutils literal">Builder</tt> via its <tt class="docutils literal">flex</tt> method (name subject to change), and then that builder can be concatenated onto the main command.</p>
<p>Now, this doesn't all <em>quite</em> work, because I'm not sure that it makes sense for every <tt class="docutils literal">InputAccumulator[T, U]</tt> in a given context to have the <em>same</em> <tt class="docutils literal">U</tt>, so it's almost like, it should actually be a <tt class="docutils literal">ValueAdaptor[K]</tt> with a <tt class="docutils literal"><span class="pre">Callable[[K,</span> <span class="pre">Type[U]],</span> U]</tt>, and <tt class="docutils literal">InputAccumulator[T]</tt> has a <tt class="docutils literal"><span class="pre">Callable[[ValueAdaptor[Any],</span> T], T]</tt>.</p>
<p>Now, this is all pretty flexible-looking, but I think I want the possible types in play to be pretty heavily restricted.
Like, how far can I get if <tt class="docutils literal">T</tt> and <tt class="docutils literal">U</tt> have to be either <tt class="docutils literal">str</tt> or <tt class="docutils literal">PathLike[str]</tt>?</p>
<p>I'll have to think for a while to see if that would somehow break something, but it seems solid right now.</p>
<p>Now, moving on from that for a moment, to consider how the <tt class="docutils literal">ValueAdaptor[K]</tt>s show up.
Now, the <tt class="docutils literal">InputAccumulator[T]</tt> objects are ultimately used to create an <tt class="docutils literal">Output[T]</tt> object, which sounds pretty bad, but honestly I've got bigger fish to fry for a while.
The point is, accumulating these axes of <em>output</em> variation makes the most sense if there's associated <em>input</em> variation, otherwise it's just duplicating stuff for no reason.
So, the <tt class="docutils literal">ValueAdaptor[K]</tt> object needs to be part of some larger object that creates non-output variation in some way.</p>
<p>Basically, it just needs non-output Fragment or Option Builders.</p>
<p>I think the best course of action at this point is to wait a few days, and see if this all still makes sense.
For now, I want to take things easy.</p>
<p>(Late addition: the <tt class="docutils literal">InputAccumulator[T]</tt>, being meant for output mode, should include some of the arguments to the <tt class="docutils literal">flex</tt> method.)</p>
<p>Good night.</p>
Weekly Roundup 2021-12-142021-12-14T05:00:00-05:002021-12-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-14:/weekly-roundup-2021-12-14<p class="first last">smiley face (unhinged)</p>
<ul class="simple">
<li>Wednesday: I did a quick pass over the names in the MOTR project to see which ones were okay, and started coming up with alternatives for some of the rest.</li>
<li>Thursday: I looked over one of the other modules that needs new names.</li>
<li>Friday: I took a break from coding to think about stuff that I could be coding.</li>
<li>Saturday: I focused on some of the new modules I'm writing for MOTR, and tried to draft out ideas for reducing the boilerplate code in them.</li>
<li>Sunday: I converted the draft code from the previous night into a much slicker class-based interface, and gave the modules much nicer indentation as a result.</li>
<li>Monday: One of the classes I'd written was just kind of weird and I couldn't think of a good name for it, so I deleted it :)</li>
</ul>
<p>Next week, I'm going to have to take it easy somehow, but I kind of don't want to.
We'll see how that tension works itself out.</p>
Coding 2021-12-132021-12-13T05:00:00-05:002021-12-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-13:/coding-2021-12-13<p class="first last">Resolving "I don't know what to name this class" by deleting the class.</p>
<p>All right, I gave this some though, and I think I see the way forward to fixing the functionality of <tt class="docutils literal">MetaBuilder</tt>, if not the name.</p>
<p>Currently, <tt class="docutils literal">MetaBuilder</tt> is kind of split between a <tt class="docutils literal">Protocol</tt> class and a decorator that returns a function that conforms to that <tt class="docutils literal">Protocol</tt>.
I kind of want to get rid of the weird indirection that results from "here is a protocol, and here is the only lexical part of the source code concerned with implementing it", but I'm not sure if that's strictly necessary.
Regardless, the first thing I want to do is, convert the <tt class="docutils literal">Protocol</tt> to a dataclass that wraps a <tt class="docutils literal">Builder[InputPathStr]</tt>, and inline the nested function definition from the decorator into the <tt class="docutils literal">__call__</tt> method.
I probably shouldn't mess with that any further until I have tests for it, except to set up a mapping to hold the <tt class="docutils literal">MetaBuilder</tt> data, and populate that either unconditionally, or only in the <tt class="docutils literal">Output</tt> case.
At that point, I can consider questions like "what should the code that consumes this look like" and "what kind of interface do I need to actually generate the <tt class="docutils literal">MetaBuilder</tt> instances from pytest, coverage, etc?</p>
<p>Hm, one thing that occurs to me as a further step is to convert all of this to a method on <tt class="docutils literal">Builder[Input[PathStr]]</tt>, which removes the need to name a separate class.
This idea feels nicer to me, because now the question is "how do I synthesize a <tt class="docutils literal">Builder[Input[PathStr]]</tt> with the desired properties?" which is somewhat more meaningful than "how do I synthesize a <tt class="docutils literal">MetaBuilder</tt> with the desired properties?"</p>
<p>Let's see how much of a pain it is to do the conversion...</p>
<p>Okay, that wasn't too bad.
I still need to reconsider the inside of the function, which is a terrible mess of nested definitions, but now the broader organization is more sensible.</p>
<p>Important TODO: expose <tt class="docutils literal">self</tt> in some way in the output case.</p>
<p>Now, to think a little about how this all works in the downstream interfaces.
There are basically two kinds of thing that have to be properly combined:</p>
<ul class="simple">
<li>The full range of parameters</li>
<li>The different kinds of output</li>
</ul>
<p>Basically, we need the commands to track all of their relevant keys, and translate them into string values.
The resulting strings then must be fed into a function that produces a <tt class="docutils literal">Builder[Input[PathStr]]</tt> from the key values.</p>
<p>This is going to be awkward, because I <em>know</em> I'll want to pass in stuff like <tt class="docutils literal">PythonPackage</tt>, so it's like I guess I need to pass in a callback or something to handle the conversions.
This sounds like a job for "sleeping before I try to code any of this".</p>
<p>It's a little early now, but I have to get up early tomorrow and deal with a whole bunch of... just... stuff, so it makes sense to try to wrap up now.</p>
<p>Good night.</p>
Coding 2021-12-122021-12-12T05:00:00-05:002021-12-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-12:/coding-2021-12-12<p class="first last">Let's see how this is all going to work. I certainly don't know yet.</p>
<p>Well, after thinking over those ideas from last night, I came up with an even better one.
The invocations are quite compact, but they should be flexible if I need to mess around.</p>
<p>Looking over the <tt class="docutils literal">flake8.py</tt> file, I see that I want a similar helper setup for options.</p>
<p>...</p>
<p>And, done.</p>
<p>Okay, that was, basically speaking, all a fun distraction from the more pressing issue of "how do I hook up the junit output from various commands into junitparser and junit2html?".
From an interface perspective, I think I want a helper function that can be invoked <em>from</em> the program-specific helpers to generate the options.
Except, no, I'm not sure if that works?
Because I can't properly emit the generated requirements until after all of the underlying commands have been built.
So, it's like I need some kind of wrapper around the program-specific command builder that can somehow introspect it to extract the relevant data.</p>
<p>I'm not figuring this out tonight, because this is going to get messy really fast.
I might think something different in the morning, but right now, the way I'm thinking about this is, this is going to look like "integrate the ideas currently known as <tt class="docutils literal">MetaBuilder</tt> more tightly into the <tt class="docutils literal">Builder</tt> interface".
Basically, some kind of Registry-type field that has a <tt class="docutils literal">MetaBuilder</tt> under a field like <tt class="docutils literal">JUNIT_XML</tt>.
(Although, since the types are all the same, I shouldn't need to use the "Registry" stuff that I have currently.)</p>
<p>It might not be necessary to track this on the <tt class="docutils literal">Builder</tt> if I can put together the correct interface for constructing and using this stuff.
I have some notes on this that I don't want to look over right now, but I'm going to need them.</p>
<p>For now, I'd better get to bed.</p>
<p>Good night.</p>
Coding 2021-12-112021-12-11T05:00:00-05:002021-12-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-11:/coding-2021-12-11<p class="first last">The "Will I Understand This Code In The Morning?" Challenge</p>
<p>Okay, I failed at getting more rest last night, so, we'll see what happens tonight.
I'm not feeling super confident, but I'd like to try to get a bit done.
So, let's see what I think about one thing I'd noticed, which is the heavy amount of boilerplate for the base command stuff.
What I want to see is, how much variety is there in the definitions of the base commands?</p>
<p>So, I'm going to try to sketch out what I want from the helper functions for cutting down on the boilerplate.</p>
<div class="highlight"><pre><span></span><span class="c1"># pytest:</span>
<span class="n">BASE</span><span class="p">:</span> <span class="n">Fragment</span> <span class="o">=</span> <span class="n">_types</span><span class="o">.</span><span class="n">Fragment</span><span class="p">(</span>
<span class="n">my_helper_func</span><span class="p">(</span>
<span class="s2">"pytest"</span><span class="p">,</span>
<span class="n">installer_key</span><span class="o">=</span><span class="n">PYTEST_KEY</span><span class="p">,</span>
<span class="n">requirements</span><span class="o">=</span><span class="p">[</span><span class="s2">"pytest"</span><span class="p">],</span>
<span class="n">path_segments</span><span class="o">=</span><span class="p">[</span><span class="s2">"pytest"</span><span class="p">],</span>
<span class="p">),</span>
<span class="n">allowed_codes</span><span class="o">=</span><span class="nb">frozenset</span><span class="p">([</span><span class="mi">1</span><span class="p">]),</span>
<span class="p">)</span>
<span class="c1"># flake8:</span>
<span class="n">BASE</span><span class="p">:</span> <span class="n">Fragment</span> <span class="o">=</span> <span class="n">_types</span><span class="o">.</span><span class="n">Fragment</span><span class="p">(</span>
<span class="n">my_helper_func</span><span class="p">(</span>
<span class="s2">"flake8"</span><span class="p">,</span>
<span class="n">installer_key</span><span class="o">=</span><span class="n">FLAKE8_KEY</span><span class="p">,</span>
<span class="n">requirements</span><span class="o">=</span><span class="p">[</span><span class="s2">"flake8"</span><span class="p">],</span>
<span class="n">path_segments</span><span class="o">=</span><span class="p">[</span><span class="s2">"check"</span><span class="p">],</span>
<span class="p">),</span>
<span class="n">allowed_codes</span><span class="o">=</span><span class="nb">frozenset</span><span class="p">([</span><span class="mi">1</span><span class="p">]),</span>
<span class="p">)</span>
<span class="c1"># Now let's try some I haven't attempted.</span>
<span class="c1"># junit2html:</span>
<span class="n">BASE</span><span class="p">:</span> <span class="n">Fragment</span> <span class="o">=</span> <span class="n">_types</span><span class="o">.</span><span class="n">Fragment</span><span class="p">(</span>
<span class="n">my_helper_func</span><span class="p">(</span>
<span class="s2">"junit2hml"</span><span class="p">,</span>
<span class="n">installer_key</span><span class="o">=</span><span class="n">JUNIT2HTML_KEY</span><span class="p">,</span>
<span class="n">requirements</span><span class="o">=</span><span class="p">[</span><span class="s2">"junit2html"</span><span class="p">],</span>
<span class="n">path_segments</span><span class="o">=</span><span class="p">[</span><span class="s2">"junit2html"</span><span class="p">],</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="c1"># limit_coverage:</span>
<span class="n">BASE</span><span class="p">:</span> <span class="n">Fragment</span> <span class="o">=</span> <span class="n">_types</span><span class="o">.</span><span class="n">Fragment</span><span class="p">(</span>
<span class="n">my_helper_func</span><span class="p">(</span>
<span class="s2">"limit-coverage"</span><span class="p">,</span>
<span class="n">installer_key</span><span class="o">=</span><span class="n">LIMIT_COVERAGE_KEY</span><span class="p">,</span>
<span class="n">requirements</span><span class="o">=</span><span class="p">[</span><span class="s2">"limit-coverage"</span><span class="p">],</span>
<span class="n">path_segments</span><span class="o">=</span><span class="p">[</span><span class="s2">"limit-coverage"</span><span class="p">],</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="c1"># mypy:</span>
<span class="n">BASE</span><span class="p">:</span> <span class="n">Fragment</span> <span class="o">=</span> <span class="n">_types</span><span class="o">.</span><span class="n">Fragment</span><span class="p">(</span>
<span class="n">my_helper_func</span><span class="p">(</span>
<span class="s2">"mypy"</span><span class="p">,</span>
<span class="n">installer_key</span><span class="o">=</span><span class="n">MYPY_KEY</span><span class="p">,</span>
<span class="n">requirements</span><span class="o">=</span><span class="p">[</span><span class="s2">"mypy"</span><span class="p">],</span>
<span class="n">path_segments</span><span class="o">=</span><span class="p">[</span><span class="s2">"mypy"</span><span class="p">],</span>
<span class="p">),</span>
<span class="n">allowed_codes</span><span class="o">=</span><span class="nb">frozenset</span><span class="p">([</span><span class="mi">1</span><span class="p">]),</span>
<span class="p">)</span>
<span class="c1"># pyinstrument:</span>
<span class="n">BASE</span><span class="p">:</span> <span class="n">Fragment</span> <span class="o">=</span> <span class="n">_types</span><span class="o">.</span><span class="n">Fragment</span><span class="p">(</span>
<span class="n">my_helper_func</span><span class="p">(</span>
<span class="s2">"pyinstrument"</span><span class="p">,</span>
<span class="n">installer_key</span><span class="o">=</span><span class="n">PYINSTRUMENT_KEY</span><span class="p">,</span>
<span class="n">requirements</span><span class="o">=</span><span class="p">[</span><span class="s2">"pyinstrument"</span><span class="p">],</span>
<span class="n">path_segments</span><span class="o">=</span><span class="p">[</span><span class="s2">"profile"</span><span class="p">],</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="c1"># junitparser merge:</span>
<span class="n">BASE</span><span class="p">:</span> <span class="n">Fragment</span> <span class="o">=</span> <span class="n">_types</span><span class="o">.</span><span class="n">Fragment</span><span class="p">(</span>
<span class="n">my_helper_func</span><span class="p">(</span>
<span class="s2">"junitparser"</span><span class="p">,</span>
<span class="s2">"merge"</span><span class="p">,</span>
<span class="n">installer_key</span><span class="o">=</span><span class="n">JUNITPARSER_KEY</span><span class="p">,</span>
<span class="n">requirements</span><span class="o">=</span><span class="p">[</span><span class="s2">"junitparser"</span><span class="p">],</span>
<span class="n">path_segments</span><span class="o">=</span><span class="p">[</span><span class="s2">"junitparser"</span><span class="p">],</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="c1"># coverage:</span>
<span class="n">BASE</span><span class="p">:</span> <span class="n">Fragment</span> <span class="o">=</span> <span class="n">_types</span><span class="o">.</span><span class="n">Fragment</span><span class="p">(</span>
<span class="n">my_helper_func</span><span class="p">(</span>
<span class="s2">"coverage"</span><span class="p">,</span>
<span class="s2">"erase"</span><span class="p">,</span>
<span class="n">installer_key</span><span class="o">=</span><span class="n">COVERAGE_KEY</span><span class="p">,</span>
<span class="n">requirements</span><span class="o">=</span><span class="p">[</span><span class="s2">"coverage"</span><span class="p">],</span>
<span class="n">path_segments</span><span class="o">=</span><span class="p">[</span><span class="s2">"coverage"</span><span class="p">,</span> <span class="s2">"base"</span><span class="p">],</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="c1"># ...</span>
<span class="n">BASE</span><span class="p">:</span> <span class="n">Fragment</span> <span class="o">=</span> <span class="n">_types</span><span class="o">.</span><span class="n">Fragment</span><span class="p">(</span>
<span class="n">my_helper_func</span><span class="p">(</span>
<span class="s2">"coverage"</span><span class="p">,</span>
<span class="s2">"html"</span><span class="p">,</span>
<span class="n">installer_key</span><span class="o">=</span><span class="n">COVERAGE_KEY</span><span class="p">,</span>
<span class="n">requirements</span><span class="o">=</span><span class="p">[</span><span class="s2">"coverage"</span><span class="p">],</span>
<span class="n">path_segments</span><span class="o">=</span><span class="p">[</span><span class="s2">"coverage"</span><span class="p">,</span> <span class="s2">"base"</span><span class="p">],</span>
<span class="p">),</span>
<span class="n">allowed_codes</span><span class="o">=</span><span class="nb">frozenset</span><span class="p">([</span><span class="mi">2</span><span class="p">])</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">base</span><span class="p">(</span>
<span class="n">installer_key</span><span class="p">:</span> <span class="n">Key</span><span class="p">[</span><span class="n">Installer</span><span class="p">],</span>
<span class="n">module_fragment</span><span class="p">:</span> <span class="n">Fragment</span><span class="p">[</span><span class="n">Module</span><span class="p">,</span> <span class="n">TProgram</span><span class="p">],</span>
<span class="c1"># Probably something about MetaBuilders?</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">Fragment</span><span class="p">[</span><span class="n">Script</span><span class="p">,</span> <span class="n">TProgram</span><span class="p">]:</span>
<span class="k">return</span> <span class="n">_types</span><span class="o">.</span><span class="n">Fragment</span><span class="p">(</span>
<span class="n">my_helper_func</span><span class="p">(</span>
<span class="s2">"coverage"</span><span class="p">,</span>
<span class="s2">"run"</span><span class="p">,</span>
<span class="n">installer_key</span><span class="o">=</span><span class="n">installer_key</span><span class="p">,</span>
<span class="n">requirements</span><span class="o">=</span><span class="p">[</span><span class="s2">"coverage"</span><span class="p">],</span>
<span class="n">path_segments</span><span class="o">=</span><span class="p">[</span><span class="s2">"coverage"</span><span class="p">],</span>
<span class="p">),</span>
<span class="p">)</span><span class="o">.</span><span class="n">with_module</span><span class="p">(</span><span class="n">module_fragment</span><span class="p">)</span>
</pre></div>
<p>So, there are a few observations here.
One is that the command, the requirement, and the path segment for the environment are <em>usually</em> the same, and most of the remainder of the cases <em>could</em> have them all be the same if I were so inclined.
This all implies to me that I could make the helper just fill in those values and change the arguments to "iterables of additional values".
I'm not confident that I'm using it right for <tt class="docutils literal">coverage run</tt>, but that's the weirdest command out of these, and if I need to do something differently, the underlying code is, like, right there.</p>
<p>So, maybe the helper looks like:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">my_helper_func</span><span class="p">(</span>
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="o">*</span><span class="n">subcommands</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">installer_key</span><span class="p">:</span> <span class="n">Key</span><span class="p">[</span><span class="n">Installer</span><span class="p">],</span>
<span class="n">requirements</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">(),</span>
<span class="n">path_segments</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">(),</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">CmdMeta</span><span class="p">:</span>
<span class="k">return</span> <span class="n">base_cmd</span><span class="p">(</span>
<span class="n">Command</span><span class="p">(</span><span class="n">installer_key</span><span class="p">,</span> <span class="n">name</span><span class="p">),</span>
<span class="o">*</span><span class="n">subcommands</span><span class="p">,</span>
<span class="n">installer_registry</span><span class="o">=</span><span class="n">INSTALLER_REGISTRY</span><span class="o">.</span><span class="n">set</span><span class="p">(</span>
<span class="n">installer_key</span><span class="p">,</span>
<span class="n">Pip</span><span class="p">(</span>
<span class="nb">frozenset</span><span class="p">([</span>
<span class="n">package</span><span class="p">(</span><span class="n">name</span><span class="p">),</span>
<span class="o">*</span><span class="p">(</span>
<span class="n">package</span><span class="p">(</span><span class="n">requirement</span><span class="p">)</span>
<span class="k">for</span> <span class="n">requirement</span>
<span class="ow">in</span> <span class="n">requirements</span>
<span class="p">),</span>
<span class="p">]),</span>
<span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="o">*</span><span class="n">path_segments</span><span class="p">),</span>
<span class="p">),</span>
<span class="p">),</span>
<span class="p">)</span>
</pre></div>
<p>I'll have to sleep on this and see what I think.
Maybe have my original version of the idea, and then this version as a wrapper that <em>just</em> replicates the argument around.</p>
<p>But, I'm pretty tired right now, so I don't want to try to evaluate it at the moment.</p>
<p>Good night.</p>
Diary 2021-12-102021-12-10T05:00:00-05:002021-12-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-10:/diary-2021-12-10<p class="first last">"The overall process really encourages contemplation and —" "Do thing fast!" "But" "Do. Thing. Fast."</p>
<p>Seems like I needed a break today, so I took one.
Ish.</p>
<p>I don't really have a sense of how much effort I put into anything, and I think I've not been getting enough sleep recently, so I'm going to cut myself off a bit early tonight.</p>
<p>That doesn't need to happen quite yet though, so I'm going to mess around a bit.
One thing I've been wanting to investigate for writing is random oracles, and I could use stuff like <a class="reference external" href="https://www.patreon.com/nekoewen/posts">Ewen Cluney's oracles and tables</a> for genre-specific stuff, or I could look into traditional systems and just apply them to fictional characters and situations.
This is partly inspired by playing around with ai-dungeon-type stuff, which has a few issues:</p>
<ul class="simple">
<li>One is that the particular version I'm using is plagued by weird usability issues, and at some point I'm going to have to just read all of the code and reimplement it in a way that supports stuff like "fixing typos earlier in the line without deleting up to that point".
(I'm <em>really curious</em> about how that's broken...)</li>
<li>Another is that I don't always <em>want</em> to give it license to respond every few sentences, but it gets really glitchy if I dump a lot of text into it at once.
I could work around this by splitting things up and using <tt class="docutils literal">/alter</tt>, but that's a ridiculous workflow, not least because I'm having it generate text that I intend to overwrite.</li>
<li>Lastly, there's the swinginess between "Oh, that was a clever response" and "This response demonstrates a willful contempt for knowledge about what I just wrote, human relationships, polite conversation, saliency, grammar, and the locally euclidean nature of space-time", and sometimes it just seems to get <em>stuck</em> in the latter.
I'd like to try <em>committing</em> to interpreting vague results, rather than scrutinizing a result to determine whether it needs reinterpretation, or if it's so bad that it needs to be thrown out and retried.</li>
</ul>
<p>So, I'm going to post this soon, and start messing with programming based divination for extreme efficiency.</p>
<p>Good night.</p>
Coding 2021-12-092021-12-09T05:00:00-05:002021-12-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-09:/coding-2021-12-09<p class="first last">This is mostly more straightforward.</p>
<p>Yesterday I looked at <tt class="docutils literal">core/runner.py</tt>.
The natural next place to look is <tt class="docutils literal">core/registry.py</tt>.
So let's crack that open.</p>
<p>First off, we've got <tt class="docutils literal">Action</tt>, which should be <tt class="docutils literal">Task</tt>.
Next, <tt class="docutils literal">ActionInput</tt>, which should be <tt class="docutils literal">TaskPrerequisite</tt>.
Then, <tt class="docutils literal">ActionOutput</tt>, which should be <tt class="docutils literal">TaskOutcome</tt>.
Then, <tt class="docutils literal">TargetName</tt>, which should be <tt class="docutils literal">OutcomeName</tt>.
Then, <tt class="docutils literal">SkippedName</tt>, which is fine.</p>
<p>Those all get unioned into <tt class="docutils literal">Requirement</tt>.
Let's put a pin in that one.</p>
<p>There's <tt class="docutils literal">_ActionData</tt>, which should be <tt class="docutils literal">_TaskData</tt>.</p>
<p>Finally, there's <tt class="docutils literal">Registry</tt>, which, put a pin in that, but let's look at the methods.</p>
<ul class="simple">
<li><tt class="docutils literal">inputs</tt> -> <tt class="docutils literal">prerequisites</tt> or <tt class="docutils literal">prerequisites_of_action</tt>.</li>
<li><tt class="docutils literal">chosen_targets</tt> -> <tt class="docutils literal">named_outcomes</tt>.
This method takes an iterable of target/outcome names, and resolves them to everything that they refer to.</li>
<li><tt class="docutils literal">parent</tt> -> <tt class="docutils literal">cause_of_outcome</tt> or something.</li>
<li><tt class="docutils literal">default_and_non_default</tt> -> ... um, I'm not sure.
Maybe I can figure a way to not need this method, because it feels kind of arbitrary.</li>
<li><tt class="docutils literal">require</tt> should coordinate with <tt class="docutils literal">Requirement</tt>.
This is a multimethod that coordinates the evolution of the <tt class="docutils literal">Registry</tt>.
Given a <tt class="docutils literal">Registry</tt>, if you pass a <tt class="docutils literal">Requirement</tt> to the <tt class="docutils literal">require</tt> method, you get back a <tt class="docutils literal">Registry</tt> that additionally conforms to that <tt class="docutils literal">Requirement</tt>, or it raises some kind of error if it can't reconcile the <tt class="docutils literal">Requirement</tt>s.</li>
</ul>
<p>I'd like to give this a bit more consideration, but I just stood up and it made me feel awful, so I'm going to have to sleep on this, maybe switch gears for a few days.</p>
<p>Good night.</p>
Coding 2021-12-082021-12-08T05:00:00-05:002021-12-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-08:/coding-2021-12-08<p class="first last">Look, it's not just <em>a</em> hard problem, it's one of <em>the</em> hard problems.</p>
<p>So, after forgetting that I should have been planning to use an interface called <tt class="docutils literal">MetaBuilder</tt>, which barely means anything, I decided that I need to re-evaluate the class and interface names in this project.
I'm going to start more or less at the base, because there are issues all over the place.</p>
<p>First up, a few that I barely care about:</p>
<ul class="simple">
<li>In <tt class="docutils literal">test_helpers.py</tt>, there's an <tt class="docutils literal">App</tt> subclass called <tt class="docutils literal">MOTRTest</tt>.
I honestly forget whether I named it, or the template named it, but it doesn't matter.</li>
<li>In <tt class="docutils literal">core/exc.py</tt>, there are some <tt class="docutils literal">Exception</tt> subclasses.
Probably the biggest problem is that I haven't defined enough of these.</li>
<li>In <tt class="docutils literal">controllers/base.py</tt>, there's a <tt class="docutils literal">Controller</tt> subclass.
It's... whatever.</li>
<li>In <tt class="docutils literal">motr_app.py</tt>, there's the <tt class="docutils literal">MOTR</tt> subclass of <tt class="docutils literal">App</tt>, which makes complete sense.</li>
</ul>
<p>Anyway, the core runtime logic lives in <tt class="docutils literal">core/runner.py</tt>.
This code processes the classes from <tt class="docutils literal">core/registry.py</tt>, but I'm going to cover <tt class="docutils literal">runner.py</tt> first.</p>
<p>In addition to its classes, <tt class="docutils literal">runner.py</tt> also defines a type alias.</p>
<ul class="simple">
<li><tt class="docutils literal">RuntimeAction</tt> defines the basic unit of customization for MOTR.
If you define a class that implements this interface, you can use it in your configuration.</li>
<li><tt class="docutils literal">TaskWrapper</tt> is basically an internal implementation detail.
It takes a nullary awaitable with <tt class="docutils literal">None</tt> return value, and awaits its value exactly once, blocking subsequent calls until the first call returns.
It doesn't really matter what this is called, because it's never used outside of this module.</li>
<li><tt class="docutils literal">Target</tt>, in <em>this</em> module, coordinates access to various common resources.</li>
<li><tt class="docutils literal">Action</tt>, in <em>this</em> module, wraps <tt class="docutils literal">Target</tt> and a specific <tt class="docutils literal">RuntimeAction</tt> to provide the last bits of logic required to correctly dispatch work.</li>
</ul>
<p>Between these three public names, there's a bunch wrong.
The most obvious issue is that <tt class="docutils literal">Target</tt> is a <em>callable</em> that takes as its argument an instance of a <em>different</em> type called <tt class="docutils literal">Target</tt>.
These types are all named after the corresponding-ish concept from <tt class="docutils literal">make</tt>, and I'm not sure how much that really illuminates things.
I suspect that calling the MOTR version of the concept something like "outcome" might make it clearer.</p>
<p>Like "One of this [action]'s <strong>outcomes</strong> is the creation of a junit.xml file".
One thing that would support this idea would be to remove the use of a bare path in the definition of the <em>other</em> <tt class="docutils literal">Target</tt>/<tt class="docutils literal">Outcome</tt> type, and replace it with a <tt class="docutils literal">Created</tt> wrapper.
(Presumably, it would need a bunch of wrapper methods to support some of the things I do with <tt class="docutils literal">Input[Path]</tt> instances currently.)</p>
<p>I also kind of want to rename the concept of <tt class="docutils literal">Action</tt> to <tt class="docutils literal">Task</tt>, because you can <em>do</em> either of them, but unlike an "action", you can "set" a "task" for someone else.</p>
<p>That's sort of beside the point in the context of this module, because these classes mostly shouldn't be using these names the way they are.
For a first approximation, here's what I want:</p>
<ul class="simple">
<li><tt class="docutils literal">RuntimeAction</tt> -> <tt class="docutils literal">Task</tt></li>
<li><tt class="docutils literal">Target</tt> -> <tt class="docutils literal">Coordinator</tt> or <tt class="docutils literal">Solver</tt> or <tt class="docutils literal">Provider</tt> or something.
<tt class="docutils literal">Taskmaster</tt>? I'm not really sure.
<tt class="docutils literal">Runner</tt>?</li>
<li><tt class="docutils literal">Action</tt> can be, like, <tt class="docutils literal">TaskRunner</tt>, maybe?</li>
</ul>
<p>I think part of the confusion her on my part stems from the... somewhat weird signatures some of these callable classes have.
Like, the class-currently-known-as <tt class="docutils literal">Action</tt> has to have a signature of "nullary async" to work with the <tt class="docutils literal">TaskWrapper</tt>.</p>
<p>I think I need to think about this some more.
For now, I want to wrap up early.</p>
<p>Good night.</p>
Weekly Roundup 2021-12-072021-12-07T05:00:00-05:002021-12-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-07:/weekly-roundup-2021-12-07<p class="first last">It's a bad sign when one problem I have is "Well, I forgot what each part did, because none of the names mean anything."</p>
<ul class="simple">
<li>Wednesday: I did some MOTR work. Honestly, it kind of blends together.</li>
<li>Thursday: But I made a list Tuesday (and posted about it for Wednesday), and made some progress against it.</li>
<li>Friday: I ran into typing issues that I probably explained poorly.</li>
<li>Saturday: I figured out the typing issues, and undid a lot of the workarounds I'd put in.</li>
<li>Sunday: I made plans for utilities to support, and started thinking about more PRs to put in.</li>
<li>Monday: I started working on flake8 support, and had some ideas that I later realized didn't make sense.</li>
</ul>
<p>Next week, I'm going to investigate using the <tt class="docutils literal">MetaBuilder</tt>, <em>and not</em> the <tt class="docutils literal">InstallerRegistry</tt>, for passing <tt class="docutils literal">Input</tt> values between <tt class="docutils literal">Builder</tt> objects.
I'm also going to investigate giving this things better names.</p>
Coding 2021-12-062021-12-06T05:00:00-05:002021-12-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-06:/coding-2021-12-06<p class="first last">Discovering entirely new areas of the interface that need to be worked out and locked down.</p>
<p>So, I started working on the flake8 module for MOTR, and a few things jumped out at me:</p>
<ul class="simple">
<li>The base command for both pytest and flake requires <em>a lot</em> of boilerplate to define.
I think I want to address this by adding a helper to the pip module that mostly takes keyword-only arguments.</li>
<li>There's an overlap in problems to be solved for "create virtualenv" and "create report" that implies to me that I should consider reworking the <tt class="docutils literal">Installer</tt> classes and functionality, and creating a <tt class="docutils literal">Report</tt> class as a companion to <tt class="docutils literal">Pip</tt>.</li>
</ul>
<p>I'll have to think about this carefully, because this could be a case of premature abstraction.
This could be a case of needing more prototyping or sketching.</p>
<p>Anyway, it's early, but I'm going to be traveling soon, so I think it's for the best to just cut this short so I know I'm done writing.</p>
<p>Good night.</p>
Coding 2021-12-052021-12-05T05:00:00-05:002021-12-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-05:/coding-2021-12-05<p class="first last">Always nice when I just dash off an improvement to things.</p>
<p>Okay, good progress.
I believe I've got everything required to kick off a pytest run, except for a few utility functions that I'll need to write soon, but I don't need quite yet.
In terms of reusability, I need to port over the rest of the commands over.
I think the order I want to do that in is something like:</p>
<ul class="simple">
<li>flake</li>
<li>the commands for manipulating junitxml files</li>
<li>update pytest to output junitxml</li>
<li>mypy</li>
<li>pyinstrument</li>
<li>coverage</li>
</ul>
<p>Once those are done, coverage will probably be below 80%, so I'll have my work cut out for me in terms of testing.
There are a few other things to look into, though:</p>
<ul class="simple">
<li>Contribute PRs to some of the tools that I've forked</li>
<li>Investigate adding dark modes to the HTML reports that don't already have them.</li>
</ul>
<p>Inspired by those ideas, I just now rewrote my dark mode user style to be a bit less harsh on the eyes.
The links are much easier to read now that it's based off Solarized rather than "I dunno, just make it dark".
Of course, now this makes me want dark mode that much more for flake8-html, mypy, and junit2html.</p>
<p>At some point, I should review the requirements for each of the tools I listed above.
For now, I need to get to sleep.</p>
<p>Good night.</p>
Coding 2021-12-042021-12-04T05:00:00-05:002021-12-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-04:/coding-2021-12-04<p class="first last">Getting closer...</p>
<p>I figured out the type errors.
Basically, because the <tt class="docutils literal">Input</tt> and <tt class="docutils literal">Output</tt> types are simple wrappers around an underlying value, which is immutable, the type should be covariant with respect to its argument, but I didn't do that to start with.</p>
<p>The practical effect of changing from <tt class="docutils literal">Input[T]</tt> to <tt class="docutils literal">Input[T_co]</tt> is that now, <tt class="docutils literal">Input[A]</tt> can be passed for <tt class="docutils literal">Input[Union[A, B]]</tt> (I mean, I'm pretty sure), and also <tt class="docutils literal">Input[Impl]</tt> can be passed for <tt class="docutils literal">Input[Proto]</tt>.</p>
<p>There's some further cleanup and messing-around I want to do as a result of all this, but the thing I think I should focus on right now (after having done some other miscellaneous cleanup) is setting up the infrastructure for building packages.
That's going to take a little consideration to make sure everything fits together.
Basically, I want to start by scanning the repository layout to build a <tt class="docutils literal">Packages</tt> object, that contains some number of <tt class="docutils literal">Package</tt> objects.
Each one has an associated name and path, and the following layout is needed in the <tt class="docutils literal">ObjectRegistry</tt>: one key with the common root information, and one key with all <tt class="docutils literal">Package</tt> data, including name, packed into a <tt class="docutils literal">PVector</tt>.</p>
<p>I think it goes something like:</p>
<ul class="simple">
<li>Find all packages</li>
<li>Synthesize all packages into a common object</li>
<li>Build all packages, and write all necessary information to install them into several text files, one universal and a set of package-specific ones</li>
<li>Pack the information into the <tt class="docutils literal">ObjectRegistry</tt></li>
</ul>
<p>Okay, that's kind of conflating the build-time and run-time actions.
Actually building the packages comes at run-time, but all of the metadata can be calculated ahead of time.
Because the <tt class="docutils literal">ObjectRegistry</tt> entries require the metadata, that means that the build-time logic can't use the <tt class="docutils literal">Builder</tt> functionality.
So, fundamentally, we need a function that takes the <tt class="docutils literal">Packages</tt> data, possibly an initial <tt class="docutils literal">ObjectRegistry</tt>, and returns... probably a <tt class="docutils literal">Requirements[ObjectRegistry]</tt>.
Or maybe it could just return the raw data, and the calling code is responsible for packing them into a registry.</p>
<p>Okay, I think this is enough to start drafting code.</p>
<p>...</p>
<p>And, things are starting to come together.
What I really need to do is to focus on copying and updating code from the motrfile, and making sure everything makes sense.</p>
<p>For now, I'm going to wrap up, because it got late.
It does that.</p>
<p>Good night.</p>
Coding 2021-12-032021-12-03T05:00:00-05:002021-12-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-03:/coding-2021-12-03<p class="first last">Oh no, I have unleashed demons of supreme fiddliness.</p>
<p>Okay, more good progress.
The <tt class="docutils literal">Pip</tt> object has all of the fields that I currently know it'll need, and I wrote the <tt class="docutils literal">combine</tt> method, which was nice and easy relative to the equivalent on <tt class="docutils literal">CmdMeta</tt>, because <tt class="docutils literal">CmdMeta</tt> is still handling the "does not exist on one side" logic, which means I can just assume that the other side exists.</p>
<p>Next up is the <tt class="docutils literal">resolve</tt> method, which I'm going to have to think carefully about.
It goes like:</p>
<ul class="simple">
<li>Locate the environment directory</li>
<li>Create its parent directory</li>
<li>Create the environment</li>
<li>Run the pip command</li>
<li>Return the command path</li>
</ul>
<p>With some "obvious" steps to make sure everything sequences properly.
The part I want to think about is generating the environment directory.
It's basically supposed to be a prefix plus a unique suffix.
I think for now I'll just set the prefix as a module constant.
So, let's give this a shot...</p>
<p>Well, the code for the <tt class="docutils literal">resolve</tt> method looks good, but I'm trying to get the typing right, and, um...
Things are suddenly going <em>very wrong</em> and I'm not sure how to fix them yet.</p>
<p>It looks like I need to redo a bunch of <tt class="docutils literal">Union</tt>s.
I strongly suspect that there's a way to get what I want done, done, elegantly, but for now I'll settle for "working".</p>
<p>After I get all of these typing errors resolved, I'll still need to get the <tt class="docutils literal"><span class="pre">pyproject-build</span></tt> stuff ported, but I think at that point I'll be very close to being ready for a release, code-wise if not test-wise.</p>
<p>Anyway, I'm going to publish this and keep grinding away at those type errors; I don't want to keep this entry any longer.</p>
<p>Good night.</p>
Coding 2021-12-022021-12-02T05:00:00-05:002021-12-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-02:/coding-2021-12-02<p class="first last">It just works.</p>
<p>I got to work on that to-do list I put together yesterday, and it's going pretty well.
Here's what's left:</p>
<ul class="simple">
<li>Add all required fields to the <tt class="docutils literal">Pip</tt> object</li>
<li>Write the <tt class="docutils literal">combine</tt> method</li>
<li>Write the <tt class="docutils literal">resolve</tt> method ASAP</li>
<li>Port over the code from the motrfile that invokes <tt class="docutils literal"><span class="pre">pyproject-build</span></tt></li>
</ul>
<p>I'll try to get the fields added after I publish this, but mostly I'm just, oh man, it's so nice to finally be working on this stuff properly.</p>
<p>Anyway, it ended up being later than I'd like, so I'm just going to wrap things up with no consideration for how awkward it is.</p>
<p>Good night.</p>
Coding 2021-12-012021-12-01T05:00:00-05:002021-12-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-12-01:/coding-2021-12-01<p class="first last">"This is a good idea." *starts implementing it* "What, no it's not."</p>
<p>I ended up getting a bit distracted improving the typing strictness in MOTR, part of which ended up turning into PRs against other libraries.
I... did not do so great with those PRs; I assume they'll get moving in a bit.
(This would all be so much easier if pylint would stop regressing things when it updates...)</p>
<p>Anyway, I have some stub classes for implementing the Pip versions of the <tt class="docutils literal">Protocol</tt>s I need, so let's zoom in on what needs to happen there.</p>
<ul class="simple">
<li>For now, I want the <tt class="docutils literal">Installer</tt> to just build up a command line and not deal with environment variables or extra IO data.</li>
<li>The command line must support <tt class="docutils literal">Input</tt> values.</li>
<li>The root for now is <tt class="docutils literal">pip install</tt>, and I think I can get by with just <tt class="docutils literal"><span class="pre">-c</span> <file></tt>, <tt class="docutils literal"><span class="pre">-r</span> <file></tt>, and string literals for things to concatenate onto it.</li>
<li>The string literals should be validated to not start with <tt class="docutils literal">-</tt>, at minimum.
(I think.)</li>
<li>The other side of the installer is the combination of "data that determines the root" and "key for retrieving Python version".</li>
<li>The <tt class="docutils literal">Installation</tt> class needs the ability to associate <tt class="docutils literal">Output</tt> values with the <tt class="docutils literal">pip install</tt> command.
I can either do this the direct hacky way, or the duplication of effort way.
An alternative possibility would be to turn <tt class="docutils literal">Installation</tt> into a concrete type that simply combines an <tt class="docutils literal">Installer</tt> and some registries, then delegates the underlying functionality to a method on the <tt class="docutils literal">Installer</tt>.
Honestly, I think that makes more sense, so let's see what needs to happen for that...</li>
</ul>
<p>All right, that was pretty painless.
So, let's see what this new <tt class="docutils literal">Pip</tt> class, that I got from not needing to note the kind of class, will need.</p>
<ul class="simple">
<li>Sequence of path segments, and property to convert them into a relative path</li>
<li>Setlike collection of command components, and property to convert them into a command</li>
<li>Python version key</li>
</ul>
<p>It needs to convert all of that into a working environment, and it does so as follows:</p>
<ul class="simple">
<li>Resolve the version key against the registries</li>
<li>Determine the path of the environment root</li>
<li>Create the parent directory</li>
<li>Create the environment with the specified python version</li>
<li>Resolve the command within the environment, convert to <tt class="docutils literal">Input</tt></li>
<li>Convert the <tt class="docutils literal">Input</tt> to an <tt class="docutils literal">Output</tt> in the context of the pip command, and run it.</li>
<li>Return the <tt class="docutils literal">Input</tt></li>
</ul>
<p>I thought I might need something a bit more involved in some cases, but I suspect I was misreading the Mypy documentation.
It would be best to do the following things:</p>
<ul class="simple">
<li>Create a specific data type for <tt class="docutils literal">(Key[Installer], str)</tt> pairs, so I'm not keying off whether something is a tuple.</li>
<li>Prioritize support for PyPy2 once I've got the basics of everything working.</li>
</ul>
<p>I'm also going to need to review how I'm going to fit using <tt class="docutils literal"><span class="pre">pyproject-build</span></tt> into this flow, because that's going to be the code responsible for generating a bunch of the requirements and constraints files, and it's also complex enough that it can't fit into the same ecosystem that it's going to be supporting.</p>
<p>So, things to work on now:</p>
<ul class="simple">
<li>Create the new compound type for getting command paths</li>
<li>Write the helper methods to process it and patch those into the existing code</li>
<li>Write the helper types to support pip command generation</li>
<li>Add all required fields to the <tt class="docutils literal">Pip</tt> object</li>
<li>Write the <tt class="docutils literal">combine</tt> method</li>
<li>Write the <tt class="docutils literal">resolve</tt> method ASAP</li>
<li>Port over the code from the motrfile that invokes <tt class="docutils literal"><span class="pre">pyproject-build</span></tt></li>
</ul>
<p>Actually, it's occurring to me that I should really be able to construct a pip command without needing to rely on the <tt class="docutils literal">Key</tt> stuff directly, by leveraging <tt class="docutils literal">Builder</tt>s.</p>
<p>I made the changes now, and I'll see what I think of all that later.
It <em>might</em> be somewhat unfortunate that I can't be completely consistent about removing late binding, because that's what the <tt class="docutils literal">Command</tt> object <em>must</em> do, but oh well, this should simplify some things, I think/hope.
Or maybe the interface comes out looking virtually identical, but the <tt class="docutils literal">Installer</tt> <tt class="docutils literal">Protocol</tt> is theoretically more flexible.</p>
<p>It's all good.
Anyway, I'm going to wrap up for now, and start working on that list later.</p>
<p>Good night.</p>
Weekly Roundup 2021-11-302021-11-30T05:00:00-05:002021-11-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-30:/weekly-roundup-2021-11-30<p class="first last">Rough week, but I came out of it feeling relatively rejuvenated.</p>
<ul class="simple">
<li>Wednesday: I was tired and unfocused, trying to prepare for the week ahead.</li>
<li>Thursday: I traveled, and didn't do much as a result.</li>
<li>Friday: I fixed some of the problems I'd found with the poem, and then found even more problems.</li>
<li>Saturday: I transferred the list of problems into the poem source so I can have them handy for reference when I'm revising.</li>
<li>Sunday: I tried to nail down exactly what I'd need to implement for the additions I want to MOTR.</li>
<li>Monday: I was late working on stuff because I tried to run a backup and it took <em>forever</em>, but I did get some work done on MOTR.</li>
</ul>
<p>Next week, I'm gong to see how much energy and focus I have to keep working on MOTR.</p>
Coding 2021-11-292021-11-29T05:00:00-05:002021-11-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-29:/coding-2021-11-29<p class="first last">This was a really eventful day, and most of the events were... not pleasant.</p>
<p>I lost some time today because I was trying to do a backup.
(I'll try again after I publish this.)</p>
<p>Anyway, today I did the following:</p>
<ul class="simple">
<li>Renamed the old <tt class="docutils literal">Installer</tt> type so I can work on the new one without too much disruption.</li>
<li>Created the new <tt class="docutils literal">Installer</tt> <tt class="docutils literal">Protocol</tt>.</li>
<li>Created the <tt class="docutils literal">InstallerRegistry</tt> type, and a helper function.</li>
<li>Created the <tt class="docutils literal">Installation</tt> <tt class="docutils literal">Protocol</tt>.</li>
<li>Added an <tt class="docutils literal">InstallerRegistry</tt> field to <tt class="docutils literal">CmdMeta</tt>, preserving the old fields for now.</li>
</ul>
<p>There are a few possible directions to go from here:</p>
<ul class="simple">
<li>Create <tt class="docutils literal">Protocol</tt> instances for pip/virtualenv</li>
<li>Write the helper methods to process the new <tt class="docutils literal">CmdMeta</tt> container types into types that are usable by the lower layers of abstraction</li>
</ul>
<p>Everything else I can think to do requires one of those two to be done, and it's getting late, so I'm going to wrap up and try backing up again.</p>
<p>Good night.</p>
Coding 2021-11-282021-11-28T05:00:00-05:002021-11-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-28:/coding-2021-11-28<p class="first last">This is the quick version.</p>
<p>I really want to make a good guide for myself of the near future work on MOTR, so let's take a look at a use case and see how it illuminates things.</p>
<p>The global information pertinent to running Python-based scripts is contained in an object called the <tt class="docutils literal">ObjectRegistry</tt>.
It maps keys of a parameterized <tt class="docutils literal">Key[T]</tt> type to a value of type <tt class="docutils literal">T</tt>, and has the expected ancillary operations.
(Technically, this type is uninhabited at runtime, and the actual implementation is handled by some <tt class="docutils literal">PMap</tt> objects from <a class="reference external" href="https://pyrsistent.readthedocs.io/">pyrsistent</a>.)</p>
<p>The <tt class="docutils literal">ObjectRegistry</tt> should contain information about which Python interpreters to invoke for a given command, but because this choice depends on the command being run, each command should get its own key.</p>
<p>So, in the case of running <a class="reference external" href="https://docs.pytest.org/">pytest</a> under <a class="reference external" href="https://coverage.readthedocs.io/">coverage</a>, the <tt class="docutils literal">coverage run <span class="pre">-m</span> pytest ...</tt> command should run under every interpreter associated with running tests, while the remainder of the commands should run under a single interpreter.
As such, there should be a <tt class="docutils literal">PYTEST_INTERPRETERS</tt> key of type <tt class="docutils literal">Key[PVector[PythonInterpreter]]</tt>, and a <tt class="docutils literal">COVERAGE_INTERPRETER</tt> key of type <tt class="docutils literal">Key[PythonInterpreter]</tt>, where <tt class="docutils literal">PythonInterpreter</tt> is probably just a <tt class="docutils literal">NewType</tt> wrapper around <tt class="docutils literal">str</tt>.</p>
<p>Now, some quick background:</p>
<p>I'm building up command line arguments using several helper classes.
The relevant class for this discussion is called <tt class="docutils literal">CmdMeta</tt>, and it contains most of the data that the other classes use.
It has a field called <tt class="docutils literal">installer_segments</tt>, because it was originally just meant to contain path segments for locating the installation directory associated with a virtual environment.</p>
<p>My intention is to make <tt class="docutils literal">installer_segments</tt> into something fuller-featured.
Its keys are <tt class="docutils literal">Installer</tt> objects, the current definition of which is unimportant.
Its values should be whatever data is required to generate an installation command, which includes the choice of key to use for retrieving interpreter data.
In the interest of not hardcoding the installation command generation flow into the command concatenation logic, each installer should define a custom type that conforms to a <tt class="docutils literal">Protocol</tt>.</p>
<p>The <tt class="docutils literal">Protocol</tt> should include:</p>
<ul class="simple">
<li>A method for combining two instances of the same class.</li>
<li>A method for generating an installation command, given the <tt class="docutils literal">ObjectRegistry</tt> and <tt class="docutils literal">ItemRegistry</tt> associated with the overall call.
This method should produce a generator that generates lower-level <tt class="docutils literal">Requirement</tt> objects, and returns an object that contains several bits of data:
The last command it generated, and the script path for the generated environment.
This can be bundled up into a class, there shouldn't be any harm in that.
Call it <tt class="docutils literal">Installation</tt>.</li>
</ul>
<p>(An <tt class="docutils literal">ItemRegistry</tt> is similar to an <tt class="docutils literal">ObjectRegistry</tt>, but the keys are of type <tt class="docutils literal">Key[PVector[T]]</tt> while the values are of type <tt class="docutils literal">T</tt>.)</p>
<p>(It makes sense to roll the "requirements" information into this new class, so that other classes can define the data types they want.)</p>
<p>The various containers in the <tt class="docutils literal">CmdMeta</tt> that can contain <tt class="docutils literal">IO</tt> objects need to be modified to also allow <tt class="docutils literal">Tuple[Installer, str]</tt>, or some similar type.
These pairs need to be post-processed out.
This consists of having the <tt class="docutils literal">Installation</tt> returned by a given <tt class="docutils literal">Installer</tt> generating <tt class="docutils literal">Requirement</tt> data in response to the string argument, and returning an <tt class="docutils literal">Input[Path]</tt>.</p>
<p>All of this represents a high-level overview that fits into the generic "core" code I'm working on.
The specific programs I want to cover may end up requiring specialized helper functions, but I should be able to avoid thinking about that right now.</p>
<p>For the moment, I need to review those notes later and come up with answers to some of the stuff I glossed over above, like "where does some of this code <em>go</em>?"</p>
<p>Hopefully, after no more than a few more rounds of this, I'll be ready to touch the code again.</p>
<p>Anyway, it's late and I'm tired.
I'm happy with how this is shaping up.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-11-272021-11-27T05:00:00-05:002021-11-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-27:/worldbuilding-ksa-2021-11-27<p class="first last">Cutting down on the need to cross-reference.</p>
<p>I had a nice relaxed day, but it didn't have much worth blogging about.
I want to take it easy, so I'm going to just convert my current list of gripes into comments in the poem's source code.</p>
<p>...</p>
<p>Okay, I did it.
My feeling on this currently is that it's nice that several of the stanzas don't have comments on them.</p>
<p>I guess there's not much more to say on the matter.
I just want to get ready for bed.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-11-262021-11-26T05:00:00-05:002021-11-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-26:/worldbuilding-ksa-2021-11-26<p class="first last">Somehow, I ended this with more work to do on the poem than when I started.</p>
<p>Busy day today, for reasons that should be obvious when you take into account that I:</p>
<ul class="simple">
<li>Am in the USA.</li>
<li>Date these entries the day after I write them.</li>
</ul>
<p>So, I'm kind of zapped, and trying get this done quick so I can relax more.
I figured I'd try to edit the poem a little.
Let's see what I can fix, and what I'll have to come back to later.</p>
<ul class="simple">
<li>Replaced "lapse" with "collapse"</li>
<li>Removed a "forsake"</li>
<li>"From" in thirteenth stanza</li>
<li>Replaced "almost" with "practically" (er, "practic'ly")</li>
</ul>
<p>Unfortunately, I'm probably not going to get much farther on the list below, because I just tried reading this all out loud, and the second stanza just... doesn't scan, like, at all.
So, I'm going to end up with some new tasks.</p>
<p>Still need to figure out:</p>
<ul class="simple">
<li>Start of second stanza does not scan</li>
<li>Start of fourth stanza isn't great in that respect either</li>
<li>The whole eighth stanza is a wreck</li>
<li>Ninth stanza isn't much better</li>
<li>The tenth stanza just straight up has an extra syllable???</li>
<li>The twelfth stanza is super weird, but I'm not sure that's a problem</li>
<li>Something seems off about the thirteenth stanza, but I can't tell what</li>
<li>The same thing with the eighteenth stanza</li>
<li>Similar, but not as bad in the nineteenth stanza</li>
<li>Something just kills the momentum in the twentieth stanza</li>
<li>Potential clarity issue in the second-last stanza</li>
<li>And another in the last stanza</li>
<li>Replacing "health" with "healing"</li>
<li>The beginning of the speech</li>
<li>"then"/"kin", and for that matter, "home"/"down", and "clashed"/"lash".
Maybe some way to get it to "clash"... "then"/"in", "in"/"mend"</li>
<li>End of eighth stanza</li>
<li>Ninth stanza</li>
<li>Still not sure what the deal is with "storm'd"</li>
<li>Last line of twenty-sixth stanza</li>
<li>"Sore" in twenty-seventh stanza</li>
<li>Too much "struck"/not enough parallelism</li>
<li>General awkwardness in the twenty-ninth through thirty-third stanzas</li>
</ul>
<p>Okay, that's enough work.
I could try to do more, but I don't want to, so I won't.</p>
<p>Good night.</p>
Diary 2021-11-252021-11-25T05:00:00-05:002021-11-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-25:/diary-2021-11-25<p class="first last">Setting my expectations low and clearing them handily.</p>
<p>Travel today.
Did manage to do a bit better with some of the stuff I don't usually blog about.</p>
<p>At the same time, it's now really late and I want to get to sleep soon, so I'm not going to dwell on anything too much now.</p>
<p>Good night.</p>
Diary 2021-11-242021-11-24T05:00:00-05:002021-11-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-24:/diary-2021-11-24<p class="first last">Just kind of flopping around with no energy, somehow still managing to do stuff.</p>
<p>I was super tired today.
And even though I'm trying to pace myself on MOTR development to avoid burnout, I'm really really excited for the potential to finally start cutting down on the current motrfile, so I'm kind of stuck mentally going over planning.</p>
<p>Let's see... I've got some travel to do tomorrow, so that's going to take some time out for sure.</p>
<p>I'll see if I can manage to focus on Korín etc, or get more direction for Missable Mysteries.</p>
<p>In any case, I'd better try to get a good night's sleep, in order to have the best chance at pulling any of that off.</p>
<p>Good night.</p>
Weekly Roundup 2021-11-232021-11-23T05:00:00-05:002021-11-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-23:/weekly-roundup-2021-11-23<p class="first last">A burst of productivity that is almost enough to get things working properly.</p>
<ul class="simple">
<li>Wednesday: I had a weird night and worked on some unimportant Lua code.</li>
<li>Thursday: I shelved the Lua code for now, and started planning changes to MOTR.</li>
<li>Friday: I did some initial work on new stuff for MOTR.</li>
<li>Saturday: I worked through obvious improvements to MOTR.</li>
<li>Sunday: I got a lot of the plans I've made for MOTR properly implemented.</li>
<li>Monday: I started making new plans, and addressing known issues with them.</li>
</ul>
<p>Next week, I'm going to try to take it easy, and step away from code for a bit.
I've got plenty of writing I can focus on.</p>
Coding 2021-11-222021-11-22T05:00:00-05:002021-11-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-22:/coding-2021-11-22<p class="first last">Writing <em>good</em> documentation for all of this is going to be... interesting.</p>
<p>Today, I ended up just trying to do more with MOTR.
It was mainly focused on planning.
I was figuring out what the functionality related to running tests under coverage would look like (there are some weird subtleties), and I think I'm going to need to work things out from the "how are environments created?" perspective.</p>
<p>So, first off, there's some awkward stuff going on that means that things aren't quite right, because I've got this idea that it should be possible to dispatch commands to things besides a Python virtualenv with all of this, but I don't know if it should be possible to run disparate installers for a single command.
The <em>data types</em> support specifying the information, but right now the shape of the code forces a very specific flow that prevents actually using more than one binary directory.
Thinking about this, I think the solution is to create a pair of <tt class="docutils literal">(installer, command)</tt> objects, and allow that type anywhere in a <tt class="docutils literal">CmdMeta</tt>.
Then, after the installers run, the pairs can be processed into <tt class="docutils literal">Input</tt> and <tt class="docutils literal">Output</tt>.
Actually, since the path can be pre-calculated, it would mean less changes to the rest of the stack if the <tt class="docutils literal">Output</tt> data were calculated before the installers run, and injected into their commands.</p>
<p>I think this will help out the structure in general, even if I'm not currently taking advantage of the flexibility this provides.
(It allows my to process the data based on its contents rather than its location, which feels nicer to me.)</p>
<p>Anyway, there are a few related improvements required to get this to work.
The smaller improvement required is for there to be a key for python interpreters (<tt class="docutils literal">NewType</tt> around string with some minor validation, wrapped in an <tt class="docutils literal">Optional</tt>), and then each <tt class="docutils literal">Fragment</tt> type gets an associated key, to allow for stuff like "processing coverage data under one interpreter, but generating coverage data under multiple interpreters".
The bigger improvement, by my estimation, is to set up something like the <tt class="docutils literal">Key</tt> system, but for installer names.</p>
<p>Let's put that aside for a moment and consider what the "run a <tt class="docutils literal">Script</tt> <tt class="docutils literal">Fragment</tt> code" has to look like now.</p>
<ul class="simple">
<li>The <tt class="docutils literal">Fragment</tt> contains a mapping from installers to "segments", which can be processed into a mapping from installers to virtualenv directories.</li>
<li>Somewhere there has to be a mapping from installers to keys; I think I skipped over this... I think this has to live on the <tt class="docutils literal">Fragment</tt> or the <tt class="docutils literal">CmdMeta</tt>.
It shouldn't live in the data type I'm talking about above,
Maybe it should be in the values of the segments mapping.
Let's go with that for now.</li>
<li>So anyway, let's say it retrieves additional argument data for the installer from the segments.
(Combining this data should probably be delegated to a custom class per installer.)</li>
<li>So, that's all the information it needs to <em>run</em> the installer, but before we can run the command, we need to process the <tt class="docutils literal">CmdMeta</tt> to extract the dependencies.</li>
<li>So, we inject the dependencies into the <tt class="docutils literal">cmd_</tt> factory, and probably also do some <tt class="docutils literal">Mkdir</tt> stuff so the directory parents exist.</li>
<li>The installer command is ready to generate, and the <tt class="docutils literal">CmdMeta</tt> is processed, so now we can generate the installer commands, then generate the main command.</li>
</ul>
<p>The big change this needs is to create a "combiner" protocol, and to create another registry-type object to house segments and metadata, complete with a utility function to combine these registries.</p>
<p>Let's see...</p>
<ul class="simple">
<li>Combining metadata protocol</li>
<li>Rework <tt class="docutils literal">Installer</tt> type, fix type errors (including by creating a Pip installer type)</li>
<li>Switch to registry-style type.</li>
<li>Potentially fold <tt class="docutils literal">req_set</tt> and <tt class="docutils literal">installer_segments</tt> together</li>
<li>Rework <tt class="docutils literal">CmdMeta</tt>.
This may involve threading a type parameter through the library that unions onto the data types in the <tt class="docutils literal">CmdMeta</tt>, and it can either be the new type I was describing above, or <tt class="docutils literal"><span class="pre">Union[()]</span></tt>.</li>
</ul>
<p>Around that point, I can step back and reorient.</p>
<p>I think for the next few days, I should take a break from this.</p>
<p>Anyway, I want to get to bed.</p>
<p>Good night.</p>
Coding 2021-11-212021-11-21T05:00:00-05:002021-11-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-21:/coding-2021-11-21<p class="first last">Some of the type inference in mypy feels like it flows in weird directions.</p>
<p>Okay, this was a good day.
I did some work on Missable Mysteries, there might have been something else I did, but the main thrust of it was taking all of my far-enough-along plans for MOTR and getting them to more-or-less work.</p>
<p>The main thing missing right now is to get requirement sets and "segments" properly supported.
That functionality is basically to name and configure the virtualenv, and tweak the command name to be in it.</p>
<p>On the outer side, I need code to create the "registry" data required by this functionality.</p>
<p>The stuff I've been working on is kind of the in-between stuff.
Creating <tt class="docutils literal">Builder</tt>s, and processing them into more complicated forms.
Looking over the diff, the big changes are the reworks of the "registry" types, converting the <tt class="docutils literal">Builder</tt> class to require a requirements generator, fixing a few minor typing issues, writing a bunch more helper methods, and copying code from the motrfile into the core.</p>
<p>I'm going to wind down for now, but, depending on how I prioritize things, I should be good to cut a new version soon-ish.
Basically, I need to get all of the new functionality written or ported, then write tests to exercise the new code; it's possible that, by the time I've written all of the new code I want, it'll have pushed coverage below 90%.
Once I get everything to pass, I'll create a new local version, and start rewriting the motrfile to take advantage of the new features.
I really hope that, once the new release is cut, I'll be prepared to start using MOTR for other projects.
It's a question of having the motrfile be <em>small</em>.</p>
<p>Anyway, if I get it working for my projects, I'll kind of still want to extend it to cope with different layouts, but that's not as high a priority for me as just cutting down on the amount of code in the motrfile.</p>
<p>Cannot stay awake any longer.</p>
<p>Good night.</p>
Coding 2021-11-202021-11-20T05:00:00-05:002021-11-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-20:/coding-2021-11-20<p class="first last">Nice, simple cleanup.</p>
<p>I was tired today, so I picked some easy stuff to work on.
I fixed some mypy errors, some flake8 errors, and got coverage up, but not all the way up.
Then I rewrote the imports to be shorter, and this actually uncovered an issue that had been concealed by the previous format, so I think this has already been a positive change.</p>
<p>Of the remaining thirty lines to have coverage added, some of them need further design work to be able to write the code that produces the data that the functions need to execute properly.</p>
<p>So, for now, I'm going to do something I realized that I could do earlier today, and get rid of one of the actions that I don't need.
It shouldn't seriously change things, but getting rid of it makes things make that much more sense.
Basically, it was an artifact of how I was doing stuff in the noxfile that I derived the motrfile from, that I was doing <tt class="docutils literal">coverage report</tt> after <tt class="docutils literal">coverage html</tt>, and passing the <tt class="docutils literal"><span class="pre">--fail-under</span></tt> argument to the former instead of the latter.
See, because I wanted the report to be at the bottom for when I scrolled up, but that meant it was the last thing to run, so it was the thing that needed to be failing if coverage was too low.
But now that everything happens at once and I don't <em>see</em> the <tt class="docutils literal">coverage report</tt> output ever, it makes more sense to put all of the responsibilities on <tt class="docutils literal">coverage html</tt>.</p>
<p>So, I accomplished some stuff, and now I've got to put in the work to do stuff like enhance the "registry" types, and plan out things like "How do I specify different <tt class="docutils literal">.coverage</tt> files, in the context of stuff like having multiple packages under test, and potentially using <tt class="docutils literal"><span class="pre">limit-coverage</span></tt>?".
That's a good thing to look into for tomorrow, because I'm done for today.</p>
<p>Good night.</p>
Coding 2021-11-192021-11-19T05:00:00-05:002021-11-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-19:/coding-2021-11-19<p class="first last">Why worry? The code type checks. *twitch*</p>
<p>Well.
Hm.
I've started working on that stuff for MOTR, and I've hit a hurdle.
I might be able to just figure it out by describing it.</p>
<p>So, I've got this <tt class="docutils literal">Builder[T]</tt> class that can create instances of <tt class="docutils literal">T</tt>, and I want to write helper functions that perform various simplifications to the interface.
One of these is to have a way to create a <tt class="docutils literal">Builder</tt> that produces <tt class="docutils literal">Output</tt>s, given a <tt class="docutils literal">Builder[Input]</tt>.
The one I'm trying to nail down right now is to create a <tt class="docutils literal">Builder[T]</tt> in which <tt class="docutils literal">T</tt> is not an <tt class="docutils literal">Output</tt>, and it's not a <tt class="docutils literal">Fragment</tt> or an <tt class="docutils literal">Option</tt> that <em>contains</em> an <tt class="docutils literal">Output</tt>.</p>
<p>Laying it out like that gives me an idea that I'm going to try.</p>
<p>Okay, let's see if this typechecks, but the basic idea is to create a validator using <tt class="docutils literal">functools.singledispatch</tt> to put together a really quick recursive setup.
This recurses over <tt class="docutils literal">Fragment</tt>s, <tt class="docutils literal">Option</tt>s, into <tt class="docutils literal">CmdMeta</tt>, and bombs out on <tt class="docutils literal">Output</tt>s, and accepts all other inputs.
This feels kind of hacky, but it looks like it should work.
Anyway, the first decorator I wrote injects a call to the validator.
Unfortunately, it can't do this any earlier than "when it's called to produce output", but this should at least prevent errors from going by unnoticed.
Let's try using the decorator now...</p>
<p>Assuming this works (it just passed typechecking), my concern now is, my previous ideas about structuring imports are definitively super-obnoxious at this point, so I need to remember what, if anything, I was going to replace them with.</p>
<p>It's not great to switch focus in the middle of a big effort like this, but I just typed <em>way</em> too many full paths.
When I have time (not now), I'm going to document any possible collisions, then address them, and cut some painfully long names out of this code.</p>
<p>Anyway, I shouldn't be up any longer.</p>
<p>Good night.</p>
Coding 2021-11-182021-11-18T05:00:00-05:002021-11-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-18:/coding-2021-11-18<p class="first last">Let's do this! ... In a few days.</p>
<p>The Lua code is getting to some design issues that I don't want to work through right now, so I'm going to make some simple changes to MOTR.</p>
<p>Basically, the prototype code for manipulating command-line arguments at a high level is in the following module: <tt class="docutils literal">src/motr/_api/cli.py</tt>.
I want to add in code that uses these prototypes, so I can see if there's anything wrong, but first, I want to figure out where to put everything.</p>
<p>My initial thought is to make a <tt class="docutils literal">cli</tt> package, and have another package under that with modules for each <tt class="docutils literal">Fragment</tt> type and its associated <tt class="docutils literal">Option</tt>s.
The current package would go next to that, but I'm not totally sure what to call it.
I think I'll just call it "types".</p>
<p>Let's see if I can do that.
I'm not going to get too much done today, but I can do that and lay the groundwork for stuff over the weekend.</p>
<p>Okay, that's started.
I could make a sub-package, or I could just have everything next to <tt class="docutils literal">types</tt>.
It's getting late, so I'll stop for now and think about it for later.</p>
<p>Good night.</p>
Diary 2021-11-172021-11-17T05:00:00-05:002021-11-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-17:/diary-2021-11-17<p class="first last">Too much blood outside of bodies.</p>
<p>Well, this wasn't quite a normal day.
Some good things happened, some really unpleasant.</p>
<p>I ended up dinking around with the Lua code I was talking about earlier.
It's a class system, and for now, I'm calling it <tt class="docutils literal">disinherit</tt>.
Unlike my earlier caginess about MOTR, I... kind of don't care if anyone knows the name before I put it up anywhere.
Because of the following related facts:</p>
<ul class="simple">
<li>I'm not planning to put it anywhere</li>
<li>I'm not confident that it will ever be useful</li>
</ul>
<p>It's mainly good for a weird change of pace, since I'm using somewhat out-there (by programming standards) editor settings for the source file.</p>
<p>Anyway, I was once again way slow writing this up, and I can't be up much longer.</p>
<p>Good night.</p>
Weekly Roundup 2021-11-162021-11-16T05:00:00-05:002021-11-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-16:/weekly-roundup-2021-11-16<p class="first last">Important progress, but I would like to hit some kind of milestone...</p>
<ul class="simple">
<li>Wednesday: I got right back into MOTR to take the edge off... I don't remember what, at that point.</li>
<li>Thursday: I took care of the low-hanging fruit with the poem, and wrote up the state of editing it.</li>
<li>Friday: I got a flu shot.</li>
<li>Saturday: I was really tired.</li>
<li>Sunday: I did some prototyping work on MOTR from a "how does it feel to use these abstractions?" perspective.</li>
<li>Monday: I messed around with some Lua code that has no obvious application.</li>
</ul>
<p>Next week, I hope to translate some of my prototyping work into MOTR modules, then verify them against the current contents of the motrfile.
Also, I need to do more with writing, and I might go back to that Lua stuff.
I don't want to rush that, though.</p>
Diary 2021-11-152021-11-15T05:00:00-05:002021-11-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-15:/diary-2021-11-15<p class="first last">I'd like to have some less-weird days.</p>
<p>I didn't get a chance to touch MOTR's code today, so that's just exactly where it was.
I did mess around with some Lua code for the heck of it, but I don't think the result is useful, per se.
The two things I can do with that are:</p>
<ul class="simple">
<li>Get LDoc working the way I want it to.</li>
<li>Find toy problems to throw it at once I nail down the interfaces, which are currently not-quite-right.</li>
</ul>
<p>Anyway, I'm really sleepy and time's getting away from me, so I need to wrap up and get to bed.</p>
<p>Good night.</p>
Coding 2021-11-142021-11-14T05:00:00-05:002021-11-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-14:/coding-2021-11-14<p class="first last">Some interesting "Huh,so <em>that's</em> how that works" moments in here, IMO.</p>
<p>Feeling kind of out of it, but I think making some progress on MOTR will help.
So, the goal right now is to write some prototype code from a usage perspective.</p>
<p>Let's take a look at the simple cases.</p>
<p>The name of a command requires a non-empty sequence, which it only really makes sense to have as strings.
(The <em>first</em> string gets converted to an <tt class="docutils literal">Input</tt> as part of processing.)
The only other <tt class="docutils literal">CmdMeta</tt> field to cover is <tt class="docutils literal">req_set</tt>, which is <em>pretty necessary</em> in every case I can think of.
Beyond that, it needs the ability to customize every other <tt class="docutils literal">Fragment</tt> argument.
With that in mind, I can't think of any sensible shortcut for creating these, since it's just going to need to forward (nearly) all of the arguments.
The stuff that it makes sense to shortcut is the <tt class="docutils literal">CmdMeta</tt>.
Maybe something like:</p>
<div class="highlight"><pre><span></span><span class="c1"># The linewrapping is aggressive</span>
<span class="c1"># because I'm trying to keep the</span>
<span class="c1"># width of the code block boxes in</span>
<span class="c1"># mind.</span>
<span class="k">def</span> <span class="nf">base_cmd</span><span class="p">(</span>
<span class="n">cmd</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="o">*</span><span class="n">sub_cmds</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">req_set</span><span class="p">:</span> <span class="n">RequirementSet</span> <span class="o">=</span> <span class="nb">frozenset</span><span class="p">(),</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">CmdMeta</span><span class="p">:</span>
<span class="k">return</span> <span class="n">CmdMeta</span><span class="p">(</span>
<span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="o">*</span><span class="n">sub_cmds</span><span class="p">),</span>
<span class="n">req_set</span><span class="o">=</span><span class="n">req_set</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">static_option</span><span class="p">(</span>
<span class="o">*</span><span class="n">args</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">Option</span><span class="p">[</span><span class="n">typing</span><span class="o">.</span><span class="n">Any</span><span class="p">]:</span>
<span class="k">return</span> <span class="n">Option</span><span class="p">(</span><span class="n">CmdMeta</span><span class="p">(</span><span class="n">args</span><span class="p">))</span>
<span class="n">Pytest</span> <span class="o">=</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">"pytest"</span><span class="p">]</span>
<span class="n">PYTEST_BASE</span><span class="p">:</span> <span class="n">Fragment</span><span class="p">[</span>
<span class="n">Module</span><span class="p">,</span> <span class="n">Pytest</span>
<span class="p">]</span> <span class="o">=</span> <span class="n">Fragment</span><span class="p">(</span>
<span class="n">base_cmd</span><span class="p">(</span>
<span class="s2">"pytest"</span><span class="p">,</span>
<span class="n">req_set</span><span class="o">=</span><span class="nb">frozenset</span><span class="p">([</span>
<span class="p">(</span><span class="s2">"pip"</span><span class="p">,</span> <span class="s2">"pytest"</span><span class="p">)</span>
<span class="p">])</span>
<span class="p">),</span>
<span class="n">allowed_codes</span><span class="o">=</span><span class="nb">frozenset</span><span class="p">([</span><span class="mi">1</span><span class="p">]),</span>
<span class="p">)</span>
<span class="n">NO_CACHE</span><span class="p">:</span> <span class="n">Option</span><span class="p">[</span>
<span class="n">Pytest</span><span class="p">,</span>
<span class="p">]</span> <span class="o">=</span> <span class="n">static_option</span><span class="p">(</span>
<span class="s2">"-p"</span><span class="p">,</span> <span class="s2">"no:cacheprovider"</span>
<span class="p">)</span>
<span class="n">PYTEST_DEFAULT</span><span class="p">:</span> <span class="n">Fragment</span><span class="p">[</span>
<span class="n">Module</span><span class="p">,</span> <span class="n">Pytest</span>
<span class="p">]</span> <span class="o">=</span> <span class="n">PYTEST_BASE</span><span class="o">.</span><span class="n">with_option</span><span class="p">(</span>
<span class="n">NO_CACHE</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
<p>There are some improvements that could be made to this code from a conciseness perspective.
For example, if the pytest stuff were in it own module, then that module could define local type aliases for <tt class="docutils literal">Fragment</tt> and <tt class="docutils literal">Option</tt> to fill in the type arguments.
Things start to get interesting for the other options.
Also, there should really be a static builder wrapped around that stuff...
So maybe the last bit should be more like</p>
<div class="highlight"><pre><span></span><span class="n">PYTEST_DEFAULT_BUILDER</span><span class="p">:</span> <span class="n">Builder</span><span class="p">[</span>
<span class="n">Fragment</span><span class="p">[</span><span class="n">Module</span><span class="p">,</span> <span class="n">Pytest</span><span class="p">]</span>
<span class="p">]</span> <span class="o">=</span> <span class="n">static_builder</span><span class="p">(</span>
<span class="n">PYTEST_BASE</span><span class="o">.</span><span class="n">with_option</span><span class="p">(</span>
<span class="n">NO_CACHE</span><span class="p">,</span>
<span class="p">)</span>
<span class="p">)</span>
</pre></div>
<p>But the other options have to be embedded in <tt class="docutils literal">Builder</tt>s...</p>
<div class="highlight"><pre><span></span><span class="c1"># Avoid too much flexibility to start with.</span>
<span class="n">TESTDIR_BUILDER</span><span class="p">:</span> <span class="n">Builder</span><span class="p">[</span>
<span class="n">Option</span><span class="p">[</span><span class="n">Pytest</span><span class="p">]</span>
<span class="p">]</span> <span class="o">=</span> <span class="n">Builder</span><span class="p">(</span>
<span class="n">build</span><span class="o">=</span><span class="k">lambda</span> <span class="n">sreg</span><span class="p">,</span> <span class="n">oreg</span><span class="p">:</span>
<span class="n">static_option</span><span class="p">(</span>
<span class="n">oreg</span><span class="p">[</span><span class="s2">"package"</span><span class="p">]</span><span class="o">.</span><span class="n">root</span>
<span class="o">/</span> <span class="s2">"tests"</span>
<span class="p">),</span>
<span class="n">keys</span><span class="o">=</span><span class="nb">frozenset</span><span class="p">([</span><span class="s2">"package"</span><span class="p">])</span>
<span class="p">)</span>
</pre></div>
<p>That would really benefit from a decorator helper, to use instead of the lambda.
I'd also really like to nail down a stricter interface for the registries.
Let's see if I can get anywhere when it comes to the output files.</p>
<p>I'd like to see a single object that can construct either of the following:</p>
<div class="highlight"><pre><span></span><span class="n">XUNIT_OUT_BUILDER</span><span class="p">:</span> <span class="n">Builder</span><span class="p">[</span>
<span class="n">Option</span><span class="p">[</span><span class="n">Pytest</span><span class="p">]</span>
<span class="p">]</span> <span class="o">=</span> <span class="n">Builder</span><span class="p">(</span>
<span class="n">build</span><span class="o">=</span><span class="k">lambda</span> <span class="n">sreg</span><span class="p">,</span> <span class="n">oreg</span><span class="p">:</span> <span class="n">Option</span><span class="p">(</span>
<span class="n">CmdMeta</span><span class="p">(</span>
<span class="n">args</span><span class="o">=</span><span class="p">(</span>
<span class="s2">"--junitxml"</span><span class="p">,</span>
<span class="n">Output</span><span class="p">(</span>
<span class="n">REPORTS</span>
<span class="o">/</span> <span class="n">oreg</span><span class="p">[</span><span class="s2">"segments"</span><span class="p">]</span>
<span class="o">/</span> <span class="n">oreg</span><span class="p">[</span><span class="s2">"package"</span><span class="p">]</span><span class="o">.</span><span class="n">root</span>
<span class="o">/</span> <span class="s2">"junit.xml"</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="p">),</span>
<span class="n">keys</span><span class="o">=</span><span class="nb">frozenset</span><span class="p">([</span>
<span class="s2">"package"</span><span class="p">,</span> <span class="s2">"segments"</span>
<span class="p">]),</span>
<span class="n">maximal</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">XUNIT_IN_BUILDER</span><span class="p">:</span> <span class="n">Builder</span><span class="p">[</span>
<span class="n">Option</span><span class="p">[</span><span class="n">JunitMerge</span><span class="p">]</span>
<span class="p">]</span> <span class="o">=</span> <span class="n">Builder</span><span class="p">(</span>
<span class="n">build</span><span class="o">=</span><span class="k">lambda</span> <span class="n">sreg</span><span class="p">,</span> <span class="n">oreg</span><span class="p">:</span> <span class="n">Option</span><span class="p">(</span>
<span class="n">CmdMeta</span><span class="p">(</span><span class="n">args</span><span class="o">=</span><span class="nb">tuple</span><span class="p">(</span>
<span class="n">Input</span><span class="p">(</span>
<span class="n">REPORTS</span>
<span class="o">/</span> <span class="n">oreg</span><span class="p">[</span><span class="s2">"segments"</span><span class="p">]</span>
<span class="o">/</span> <span class="n">package</span><span class="o">.</span><span class="n">root</span>
<span class="o">/</span> <span class="s2">"junit.xml"</span>
<span class="p">)</span>
<span class="k">for</span> <span class="n">package</span>
<span class="ow">in</span> <span class="n">sreg</span><span class="p">[</span><span class="s2">"package"</span><span class="p">]</span>
<span class="p">))</span>
<span class="p">),</span>
<span class="n">keys</span><span class="o">=</span><span class="nb">frozenset</span><span class="p">([</span><span class="s2">"segments"</span><span class="p">]),</span>
<span class="p">)</span>
</pre></div>
<p>Writing this out is making me really want to have the registries work with typed keys, but I'll put a pin in that.
Now, because the types of these builders have to be different, that implies to me that there must be some kind of callback involved, which is also setting up the prefix.
The types can't really elegantly control the <tt class="docutils literal">Input</tt>/<tt class="docutils literal">Output</tt> distinction or the <tt class="docutils literal">maximal</tt> field, which implies to me that these are two related methods that get passed similar callbacks.
One method generates <tt class="docutils literal">Input</tt>s, the other generates <tt class="docutils literal">Output</tt>s.
Either that, or there's a flag to control what's produced, and the flag defaults to <tt class="docutils literal">Input</tt>.
To handle it correctly in either case, the output case needs a callback to determine the names of the <tt class="docutils literal">Output</tt>, if any.</p>
<p>The other possible way to handle the types is to... actually, I thought of something promising in the middle of this sentence.
Let's give it a shot.</p>
<div class="highlight"><pre><span></span><span class="n">XUNIT_META_BUILDER</span> <span class="o">=</span> <span class="n">Builder</span><span class="p">(</span>
<span class="n">builder</span><span class="o">=</span><span class="k">lambda</span> <span class="n">sreg</span><span class="p">,</span> <span class="n">oreg</span><span class="p">:</span> <span class="n">Input</span><span class="p">(</span>
<span class="n">REPORTS</span>
<span class="o">/</span> <span class="n">oreg</span><span class="p">[</span><span class="s2">"segments"</span><span class="p">]</span>
<span class="o">/</span> <span class="n">oreg</span><span class="p">[</span><span class="s2">"package"</span><span class="p">]</span><span class="o">.</span><span class="n">root</span>
<span class="o">/</span> <span class="s2">"junit.xml"</span>
<span class="p">),</span>
<span class="n">keys</span><span class="o">=</span><span class="nb">frozenset</span><span class="p">([</span><span class="s2">"segments"</span><span class="p">,</span> <span class="s2">"package"</span><span class="p">]),</span>
<span class="p">)</span>
<span class="n">XUNIT_OUT_BUILDER</span> <span class="o">=</span> <span class="n">XUNIT_META_BUILDER</span><span class="o">.</span><span class="n">meta_build</span><span class="p">(</span>
<span class="n">prefix</span><span class="o">=</span><span class="n">PYTEST_JUNITXML</span><span class="p">,</span> <span class="c1"># Option[Pytest]</span>
<span class="n">keys</span><span class="o">=</span><span class="nb">frozenset</span><span class="p">([</span><span class="s2">"package"</span><span class="p">,</span> <span class="s2">"segments"</span><span class="p">]),</span>
<span class="n">output_names</span><span class="o">=</span><span class="p">(),</span>
<span class="p">)</span>
<span class="n">XUNIT_IN_BUILDER</span> <span class="o">=</span> <span class="n">XUNIT_META_BUILDER</span><span class="o">.</span><span class="n">meta_build</span><span class="p">(</span>
<span class="n">prefix</span><span class="o">=</span><span class="n">JUNIT_MERGE_NOOP</span><span class="p">,</span> <span class="c1"># Option[JunitMerge], empty</span>
<span class="n">keys</span><span class="o">=</span><span class="nb">frozenset</span><span class="p">([</span><span class="s2">"segments"</span><span class="p">]),</span>
<span class="p">)</span>
</pre></div>
<p>I'm not sure it'll make sense to use <tt class="docutils literal">Builder[Input]</tt> for this, but the types match up.
(I mean, it's actually <tt class="docutils literal">Builder[Input[T]]</tt> like that, and maybe it can be constrained to <tt class="docutils literal">Builder[Input[PathStr]]</tt>.)</p>
<p>Anyway, this has been pretty enlightening.
Let's see what I need.</p>
<ul class="simple">
<li><tt class="docutils literal">@builder</tt> decorator, possibly multiple versions</li>
<li>A bunch of the utility stuff I wrote up there</li>
<li><tt class="docutils literal">meta_build</tt>, with a better name, and possibly support for automatically invoking <tt class="docutils literal">Mkdir</tt>.</li>
</ul>
<p>So, notes on the proper way to invoke builders:</p>
<p>They should somehow create a bunch of prefix requirements.
My inclination is that they're generators with return values, so those all get composed together, then the top-level return value gets processed into another requirement.
To get this right, I'll need to nail those details down, and possibly add fields to <tt class="docutils literal">Builder</tt>, before I design <tt class="docutils literal">meta_build</tt>.</p>
<p>Anyway, it's late and I extremely need to sleep.</p>
<p>Good night.</p>
Diary 2021-11-132021-11-13T05:00:00-05:002021-11-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-13:/diary-2021-11-13<p class="first last">Tired...</p>
<p>I can't write about much tonight, because I've been tired and spaced out all day, because of various reasons.</p>
<p>And now I'm even less prepared to write stuff, so I'm not going to try.</p>
<p>Good night.</p>
Diary 2021-11-122021-11-12T05:00:00-05:002021-11-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-12:/diary-2021-11-12<p class="first last">Not to get <em>political</em> or anything...</p>
<p>I didn't really work on any of the projects that I blog about today, so this is going to be a short "how am I doing" update.
Well, I'm definitely feeling better than I did yesterday.</p>
<p>I finally got my flu shot today, so that's over with for this year.
I'm a little sore, but nothing crazy so far.</p>
<p>I've got a few other things I want to take care of before I get to bed, so my basic plan is:</p>
<ul class="simple">
<li>Publish this</li>
<li>Brush teeth</li>
<li>Other stuff</li>
</ul>
<p>That should all work out, if I can just finish writing this ASAP.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-11-112021-11-11T04:00:00-05:002021-11-11T04:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-11:/worldbuilding-ksa-2021-11-11<p class="first last">Basic fixes to the poem draft.</p>
<p>I did some poetry editing.
Let's see how that breaks down.</p>
<ul class="simple">
<li>Changed "the land"</li>
<li>Punctuation pass (including fixing the quote marks)</li>
<li>Made a call on the line breaks (including the tenth stanza)</li>
<li>I am using "ere" correctly</li>
</ul>
<p>Still need to figure out:</p>
<ul class="simple">
<li>Replacing "health" with "healing"</li>
<li>The beginning of the speech</li>
<li>"then"/"kin", and for that matter, "home"/"down", and "clashed"/"lash".
Maybe some way to get it to "clash"... "then"/"in", "in"/"mend"</li>
<li>Too much "forsake"</li>
<li>Replacing "lapse" with "collapse"</li>
<li>End of eighth stanza</li>
<li>Ninth stanza</li>
<li>"From" in thirteenth stanza</li>
<li>Still not sure what the deal is with "storm'd"</li>
<li>Replacing "almost" with "practically"</li>
<li>Last line of twenty-sixth stanza</li>
<li>"Sore" in twenty-seventh stanza</li>
<li>Too much "struck"/not enough parallelism</li>
<li>General awkwardness in the twenty-ninth through thirty-third stanzas</li>
</ul>
<p>I'm not sure what to focus on next.</p>
<p>I guess I'll just take things from either the beginning or the end.</p>
<p>For now, I want to take things easy-ish, because I had a rough night.</p>
<p>Good night.</p>
Coding 2021-11-102021-11-10T05:00:00-05:002021-11-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-10:/coding-2021-11-10<p class="first last">I hope this ends up making things simple.</p>
<p>I'm feeling a little rough right now, and I think focusing on MOTR might help, so, early coding post, let's go.</p>
<p>All right, there are two major aspects of the current motrfile that I still have to document.
Here's the <tt class="docutils literal">mypy</tt> command:</p>
<p><tt class="docutils literal">mypy <span class="pre">--html-report</span> <span class="pre">[input-dir]</span> <span class="pre">--junit-xml</span> <span class="pre">[output-xml]</span> <span class="pre">[src-param]</span></tt>, where the input-dir has an associated HTML output.
There are three <tt class="docutils literal">Option</tt>s here, and a base <tt class="docutils literal">Fragment</tt> with an <tt class="docutils literal">allowed_codes</tt> of <tt class="docutils literal">{1}</tt>.
The <tt class="docutils literal">Option</tt>s break down into "specifying output files" and "specifying an input directory, and it all basically makes sense.</p>
<p>The <tt class="docutils literal">pyinstrument</tt> command goes like this:</p>
<p><tt class="docutils literal">pyinstrument <span class="pre">--renderer</span> html <span class="pre">--outfile</span> <span class="pre">[output-html]</span> <span class="pre">-m</span> [module]</tt>.
I'd say <tt class="docutils literal"><span class="pre">--renderer</span> html <span class="pre">--outfile</span> <span class="pre">[output-html]</span></tt> should be all one <tt class="docutils literal">Option</tt> from the user's perspective.
I don't remember whether <tt class="docutils literal">pyinstrument</tt> forwards the return codes from the module, but I know <tt class="docutils literal">pyspy</tt> doesn't, and I sort of remember that being a point of difference between them, so maybe it does?
This is really easy to check, but I don't feeeeeel like it...</p>
<p>That's the details of usage.
A few random thoughts:</p>
<ul class="simple">
<li>The <tt class="docutils literal">extra_io</tt> field is the easiest to overload, because extra <tt class="docutils literal">Input</tt>s and <tt class="docutils literal">Output</tt>s just coexist next to each other.</li>
<li>I think the most sensible way to handle overloading <tt class="docutils literal">args</tt> is to, like I said, have some specifiable prefix (and maybe suffix), and just put the whole thing together before concatenating all the different overlapping versions.</li>
<li>I'm not sure what would make the most sense when it comes to environment variables.
I see "require a different name" and "pack the arguments together in some way" as possibilities, but I'm not sure what I really want.
I can just disallow it until I have a use case.</li>
</ul>
<p>Thinking more about how I want to reuse components (like, ideally, I should be able to construct the pytest module invocation builder <em>once</em>, which means the output xml path needs to have a component that varies per-registry in terms of invocation).
It looks like, given that consideration, I lucked into the correct answer to one of the design questions I was considering earlier.</p>
<p>The question in that case is, when does this per-call variation get introduced?
I think what I'd like to see is some data that somehow gets injected and recombined at the <tt class="docutils literal">Builder</tt> level, because doing it at the <tt class="docutils literal">Fragment</tt>/<tt class="docutils literal">Option</tt> level seems like it's too late.</p>
<p>I could imagine doing some combinatoric stuff will multiple choices, but all I need currently is one per full <tt class="docutils literal">Fragment[Script, <span class="pre">...]</span></tt>.
I'm inclined to say it should be a tuple of strings for now.</p>
<p>... and thinking about this, I realized that I'm sometimes going to want to ensure the directory is created, which means that the ultimate construction needs to be a <tt class="docutils literal">Requirements</tt>, and there needs to be a way to generate <tt class="docutils literal">Mkdir</tt> and probably <tt class="docutils literal">WriteBytes</tt> <tt class="docutils literal">RuntimeAction</tt>s to accompany an <tt class="docutils literal">Option</tt> with an <tt class="docutils literal">Input</tt>...</p>
<p>Well, <em>now</em> I should be prototyping the interface from the motrfile side, because this seems like a big, complicated, something.</p>
<p>Okay, time to wrap up, because that's enough of that for now.</p>
<p>Good night.</p>
Weekly Roundup 2021-11-092021-11-09T05:00:00-05:002021-11-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-09:/weekly-roundup-2021-11-09<p class="first last">Looking over various rough versions of things, and being astonished at the oversights...</p>
<ul class="simple">
<li>Wednesday: I wrote up a bunch of the obvious issues with the rough draft of my worldbuilding poem.</li>
<li>Thursday: I started bringing <tt class="docutils literal">Fragment</tt> code from prototype files into MOTR's main source.</li>
<li>Friday: I took a nap, and that took more out of me than some of the stuff I normally turn into posts.</li>
<li>Saturday: I tried to come up with every piece of information that would need to be associated with a command execution. Several days later, I would realize that I missed at least one.</li>
<li>Sunday: I started trying to design a nice user interface for this stuff.</li>
<li>Monday: I started to review existing command-line invocations from MOTR's motrfile.</li>
</ul>
<p>Next week, I'll hopefully review everything that's going on with <tt class="docutils literal">mypy</tt> and <tt class="docutils literal">pyinstrument</tt>, but I think I should focus on the poem, or maybe finally getting back to Missable Mysteries, first.</p>
Coding 2021-11-082021-11-08T05:00:00-05:002021-11-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-08:/coding-2021-11-08<p class="first last">I promise this all makes sense.</p>
<p>I want to implement the helpers for making <tt class="docutils literal">Fragment</tt>s and <tt class="docutils literal">Option</tt>s and <tt class="docutils literal">Builder</tt>s.
Rather than throwing stuff together all at once, I'm going to take a look at the kind of stuff that the current motrfile uses, since I need to replace most of that functionality.
Looking over the output diagnostics, I see...</p>
<ul class="simple">
<li><tt class="docutils literal">pip install <span class="pre">-U</span> pip</tt>.
This won't be necessary when I switch to full <tt class="docutils literal">virtualenv</tt> instead of <tt class="docutils literal">venv</tt>.</li>
<li><tt class="docutils literal">pip install <span class="pre">-r</span> <span class="pre">requirements/[something].txt</span></tt>.
Part of the point of the <tt class="docutils literal">Fragment</tt> API is to remove this specific structure; in addition, it'll be generating the <tt class="docutils literal">pip install</tt> command implicitly.</li>
<li><tt class="docutils literal">flake8 <span class="pre">--format=html</span> <span class="pre">--htmldir</span> reports/flake8 <span class="pre">--isort-show-traceback</span> src tests</tt> with allowed codes <tt class="docutils literal">{1}</tt>.
Oh no.
I missed the <tt class="docutils literal">allowed_codes</tt> concept.
That's actually really important.<ul>
<li>Anyway, we've got the command, <tt class="docutils literal">flake8</tt> with a python requirement of <tt class="docutils literal">flake8</tt>.
That's a <tt class="docutils literal">Fragment</tt> with <tt class="docutils literal">allowed_codes</tt> of <tt class="docutils literal">{1}</tt>.</li>
<li>Next, there's an <tt class="docutils literal">Option</tt> that is parameterized to produce a value in <tt class="docutils literal"><span class="pre">--format=html</span> <span class="pre">--htmldir</span> [param]</tt> with a python requirement of <tt class="docutils literal"><span class="pre">flake8-html</span></tt>.</li>
<li>There's the <tt class="docutils literal"><span class="pre">--isort-show-traceback</span></tt> <tt class="docutils literal">Option</tt>, which needs <tt class="docutils literal"><span class="pre">flake8-isort</span></tt>, and I'm starting to realize that I'm not sure what some of these requirements are <em>for</em>, per se.
Looks like I'm going to need to audit my requirements files.
Like, what's <tt class="docutils literal">pygments</tt> doing in there?</li>
<li>Anyway, the last <tt class="docutils literal">Option</tt>s are the target directories, which should either be parameterized or dumped all into a single command; I think I'd prefer parameterization, because that's what I'm doing in the relevant <tt class="docutils literal">noxfile</tt>s.</li>
<li>This command also has an <tt class="docutils literal">Output</tt> that needs to be indicated in some way, parameterized.
This <tt class="docutils literal">Output</tt> is via the <tt class="docutils literal">extra_io</tt> field, which can have a simple implementation.</li>
</ul>
</li>
<li>Next command is one of the test runs. Starting with the general test run data...<ul>
<li><tt class="docutils literal">pytest</tt> is a module <tt class="docutils literal">Fragment</tt> with <tt class="docutils literal">allowed_codes</tt> of <tt class="docutils literal">{1}</tt>.
It requires <tt class="docutils literal">pytest</tt>, and the MOTR tests have an additional dependency on <tt class="docutils literal">oschmod</tt>, so there needs to be some nice way to indicate "extra dependencies".</li>
<li>The <tt class="docutils literal"><span class="pre">-p</span> no:cacheprovider</tt> <tt class="docutils literal">Option</tt> should be added by the default invocation of the <tt class="docutils literal">pytest</tt> helper.</li>
<li>There needs to be an <tt class="docutils literal">Option</tt> for the test directory, which should be parameterized.</li>
<li>Lastly, there needs to be an <tt class="docutils literal">Option</tt> with <tt class="docutils literal"><span class="pre">--junitxml</span> [param]</tt>, which suggests to me that the likely helper for parameterized <tt class="docutils literal">Output</tt> arguments should include some form of "prefix" <tt class="docutils literal">Option</tt> data.</li>
<li>It also needs a parameterized pip requirement for getting the proper project installed.</li>
</ul>
</li>
<li>It's wrapping that in <tt class="docutils literal">coverage run</tt>, and how I want to handle that is:<ul>
<li><tt class="docutils literal">coverage run</tt> is a full <tt class="docutils literal">Fragment</tt> from the perspective of the helpers, and it requires <tt class="docutils literal">coverage</tt>.
Its module runner code passes through the allowed codes for the underlying module; this should be the default behavior.</li>
<li>This will need an <tt class="docutils literal">Output</tt> <tt class="docutils literal">Option</tt> with parameterization to locate the coverage file.</li>
</ul>
</li>
<li>There are additional Coverage <tt class="docutils literal">Fragment</tt>s:<ul>
<li><tt class="docutils literal">coverage combine</tt> (needs input files generated from all coverage output files combined) and produces a single <tt class="docutils literal">Output</tt> file.
This indicates something kind of subtle I need to surface from the lower layers.
The <tt class="docutils literal">Input</tt>/<tt class="docutils literal">Output</tt> duality is not quite as clean, because we end up in a situation where each "side" could either be parameterized or not.
Or they could be parameterized <em>differently</em>.
I think the high-level abstraction here is some kind of "parameter set" that combines with a function to create a single parameterized version.
It should take a subset of parameters (not sure whether it should be the Object or Sequence ones; I guess it should be Object since that's what the keys correspond to on the <tt class="docutils literal">Builder</tt>), and default to creating <tt class="docutils literal">Input</tt>s, with an option to create <tt class="docutils literal">Output</tt>s.</li>
<li><tt class="docutils literal">coverage erase</tt> produces a bunch of abstract <tt class="docutils literal">Output</tt>s.</li>
<li><tt class="docutils literal">coverage html</tt> works with the <tt class="docutils literal">Output</tt>s from <tt class="docutils literal">coverage combine</tt> (or <tt class="docutils literal"><span class="pre">limit-coverage</span></tt>, which I haven't set up on this project yet) to produce a corresponding HTML file</li>
<li><tt class="docutils literal">coverage report</tt> works on the same files as <tt class="docutils literal">coverage html</tt>, but only produces abstract <tt class="docutils literal">Output</tt>s.</li>
</ul>
</li>
<li>There are <tt class="docutils literal">junit2html</tt> commands, which need <tt class="docutils literal">junit2html</tt> and map an <tt class="docutils literal">Input</tt> to an <tt class="docutils literal">Output</tt> file.</li>
<li>Some of the <tt class="docutils literal">noxfile</tt>s have <tt class="docutils literal">junitparser merge</tt> lines to combine multiple <tt class="docutils literal">Input</tt> JUnit files into a single <tt class="docutils literal">Output</tt> JUnit file that can be used by <tt class="docutils literal">junit2html</tt>.</li>
</ul>
<p>I'm getting incredibly tired, so I'll just note the stuff I need to document later:</p>
<ul class="simple">
<li><tt class="docutils literal">mypy</tt></li>
<li><tt class="docutils literal">pyinstrument</tt></li>
</ul>
<p>That's not much, but I'm <em>really</em> tired.</p>
<p>Need to get to sleep...</p>
<p>Good night.</p>
Coding 2021-11-072021-11-07T05:00:00-05:002021-11-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-07:/coding-2021-11-07<p class="first last">Writing tests for this is going to be... a whole thing.</p>
<p>I've written a bunch of the foundational code for the <tt class="docutils literal">Fragment</tt> API.
I did some rewrites as I copied things over that caused it to make a lot more sense, but there are still a few things missing:</p>
<ul class="simple">
<li>I haven't ported over the end-user code to actually create any of this.
Part of the reason for that is, I've refined my ideas about what that should look like since I wrote the first prototype.</li>
<li>I haven't written the code to convert all of this into a series of command invocations.
This code is "obvious", which means I should make sure I'm in peak condition before I attempt to write it, because I'm going to run into some problem that'll be completely incomprehensible for over ten minutes if I'm <em>lucky</em>.</li>
</ul>
<p>Here's what the changes I made look like:</p>
<ul class="simple">
<li>The majority of the <tt class="docutils literal">Fragment</tt> and <tt class="docutils literal">Option</tt> classes has been combined into a single implementation class.
The <tt class="docutils literal">Fragment</tt> and <tt class="docutils literal">Option</tt> classes basically exist as wrappers that carry additional type information, and one extra field.</li>
<li>There's now a single <tt class="docutils literal">Builder</tt> class that <em>could</em> wrap anything, but only does anything vaguely useful if it's parameterized with a <tt class="docutils literal">Fragment</tt> or an <tt class="docutils literal">Option</tt> class.
I turned some of the helper functions from the first prototype into methods.</li>
</ul>
<p>Here's everything from the first prototype that's missing in the current prototype:</p>
<ul class="simple">
<li>The <tt class="docutils literal">InstallRunner</tt> class, which I forget what I was trying to do with it, so I'll just wing it until I'm writing the code to go from a <tt class="docutils literal">Fragment[Script, typing.Any]</tt> to a <tt class="docutils literal">Requirements</tt>.</li>
<li>Helpers to convert a non-parameterized bit of <tt class="docutils literal">Fragment</tt>-y or <tt class="docutils literal">Option</tt>-y data into a <tt class="docutils literal">Builder</tt>.</li>
<li>A helper to convert a <tt class="docutils literal">Builder[Fragment[Script, typing.Any]]</tt> into a sequence of <tt class="docutils literal">Fragment[Script, typing.Any]</tt>.</li>
</ul>
<p>Here's what I think I need to be looking into:</p>
<ul class="simple">
<li>Helpers to produce single parameterized <tt class="docutils literal">Output</tt> segments.</li>
<li>Helpers to produce larger parameterized non <tt class="docutils literal">Output</tt> segment sequences.</li>
</ul>
<p>I'm trying to figure out if there's anything else, and I'm not coming up with anything.
We'll see if there's something later that I'm like "Oh, well, of course!", but I'm not going to think too hard about it right now.</p>
<p>(I also did some really obvious work on the poem.)</p>
<p>Anyway, I'd like to wrap up early, so I'm done for now.</p>
<p>Good night.</p>
Coding 2021-11-062021-11-06T04:00:00-04:002021-11-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-06:/coding-2021-11-06<p class="first last">I tried to set up OpenGraph support earlier. Last I checked, I couldn't tell whether it was working.</p>
<p>So, I did a certain amount of the work for the second Fragment API prototype in my head.
A lot of it.
I did a lot of the work in my head.
This is a rough habit I've picked up from trying to do math quickly back in school, and it doesn't scale for complicated stuff, but the interfaces I have in mind are pretty simple, so I'm getting away with it.
Currently.</p>
<p>What I'm going for right now is to divide command arguments into "exclusive" (<tt class="docutils literal">Output</tt>) and "everything else".
I might be missing a field... yes, I think I am.
It was quick enough to add it.</p>
<p>Basically, the <tt class="docutils literal">Fragment</tt> and <tt class="docutils literal">Option</tt> classes track arguments, environment variables, extra IO data, a set of install requirements, additional segments to add to the root directory of the environment installation, and, in the case of <tt class="docutils literal">Fragment</tt>, an optional sequence of additional arguments to invoke another <tt class="docutils literal">Fragment</tt> as a module.</p>
<p>The goal here is to take everything that could need to be associated with a command execution, and have a field for it, so there doesn't need to be special casing for anything in the motrfile itself, and the helpers hopefully properly handle dependencies, because the current system is... not smart.
It just does what you tell it, and I haven't thought of a way to have it provide visibility into whether what you tell it "makes sense".</p>
<p>Anyway, hopefully I'll get more done with this tomorrow.
I don't want to drag this entry out any longer.</p>
<p>Good night.</p>
Diary 2021-11-052021-11-05T04:00:00-04:002021-11-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-05:/diary-2021-11-05<p class="first last">TIRED</p>
<p>Okay, I was extremely tired today, so I didn't really try to accomplish anything.
I mean, there was that nap I took for like an hour that left me extremely disoriented.</p>
<p>I'm thinking of trying to redo my weekly schedule concept in the new year.
Anyway, thinking of nearer-term plans, hopefully I'll be able to translate yesterdays coding post to prototypes in the next few days.</p>
<p>Anyway, I'm going to go wind down.</p>
<p>Good night.</p>
Coding 2021-11-042021-11-04T04:00:00-04:002021-11-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-04:/coding-2021-11-04<p class="first last">A little action and a lot of planning.</p>
<p>I was doing a few things today that I'm not going to blog about, and I decided that I want to start laying the groundwork for putting the <tt class="docutils literal">Fragment</tt> API into MOTR.</p>
<p>I got started pretty late, so in practice, this just meant adding a file to source control that I'm going to transcribe the prototype code into.</p>
<p>Here's the steps to move forward:</p>
<ul class="simple">
<li>Sketch out the desired interface (going to need the ability to create literal stretches, functions that do not generate an <tt class="docutils literal">Output</tt>, and functions that generate exactly an <tt class="docutils literal">Output</tt>; this division will lock in some choices on the interface side, and simplify implementation; also going to need to make sure the composition operators I prototyped are in there)</li>
<li>Get all those interfaces into the file I wrote.
Due to the high level of coupling in the implementations, I'm not going to try to separate things out just yet.</li>
<li>Pull in some of the foundational code I've been prototyping in the motrfile.
I'm not yet sure where it goes.</li>
<li>Create the data required to generate the current content of the configuration file, more or less.</li>
</ul>
<p>One thing I've been punting on is figuring out how to coordinate the naming of the virtualenv.
Because some of the parameters should change the requirements, which means they need a custom environment...
Maybe the environment names need to be formed from segments associated with the requirements sets...
Or something?</p>
<p>Anyway, it's late, and I don't want to dawdle any more.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-11-032021-11-03T04:00:00-04:002021-11-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-03:/worldbuilding-ksa-2021-11-03<p class="first last">I think that's an average of over one problem per stanza. So far.</p>
<p>I let things get kind of late, and there are some other things I want to work on, so I'm going to try taking some quick notes on things I could change in the poem.</p>
<ul class="simple">
<li>Early on, I have "the land". Perhaps it should be "this land" or "these lands".</li>
<li>My punctuation seems kind of inconsistent.</li>
<li>I'm saying "from health to hurt" at one point, and I'd like to get "healing" to work instead.</li>
<li>I think I went back and further on whether to break the lines midway through always at the nine-syllable mark, or at the internal rhyme.
These <em>usually</em> line up.
But, I mean, in the third stanza, they don't.</li>
<li>I don't like "Thanks, all" as the beginning of a speech.</li>
<li>Hm, I'm rhyming "then" and "kin".</li>
<li>Just noticed I used "forsake" twice in three stanzas, and I don't think it's serving any helpful function.</li>
<li>In the fifth stanza, see if I can swipe a syllable from the beginning of the last line, so I can change out "lapse" for "collapse".</li>
<li>Is "ere" a contraction, and also, am I using it correctly?</li>
<li>In the eighth stanza, it would be great if the last line's word order were a bit closer to spoken English somehow.</li>
<li>I forget what's going on with some of the metaphors in the ninth stanza.</li>
<li>Should the stanzas that are part of a speech all start with quotation marks?</li>
<li>In the tenth stanza, am I rhyming the "el" in "elder" with the "hel" in "helping"?
I think that's what's going on, and it's a doozy.
Should I break the words across the lines?</li>
<li>Okay, I've got a period in the middle of a line in the twelfth stanza, so I should probably err on the side of including periods.</li>
<li>In the thirteenth stanza I've got a "from" that I think should be some other word, not sure what.</li>
<li>I forgot to close the quote marks at the end of the thirteenth stanza.</li>
<li>I forget why I spelled "stormed" "storm'd".</li>
<li>Okay, "home" and "down" are, as rhymes go, way too slant for me.</li>
<li>Forgot the closing quote on the eighteenth stanza.</li>
<li>The twentieth stanza rhymes "clashed" and "lash", which isn't quite as slant, but I'd like it to be closer.</li>
<li>"then" and "in". Maybe this is just A Thing with this poem?</li>
<li>In the twenty-fifth stanza, I'd like to find some way to change "almost" to "practically".
Also, "in" and "mend"...</li>
<li>The last line of the twenty-sixth stanza is a bit awkward.</li>
<li>I'd like to find another word than "sore" for the twenty-seventh stanza.</li>
<li>Using "struck" for a rhyme in the twenty-sixth and twenty-eighth stanzas.
Maybe there's potential for parallelism there, but if so, it's not realized yet.</li>
<li>The twenty-ninth stanza feels generally awkward.
As does the thirtieth.
And the thirty-first.</li>
<li>The phrasing is also a bit awkward in the two stanzas after those.</li>
<li>Okay, reading the last stanza, definitely want to use "these lands" in the first.</li>
</ul>
<p>Oof, I'm trying to figure out if this is more or less issues than I was expecting.
Some of the punctuation problems kind of caught me off guard.</p>
<p>Anyway, I should wrap up for now.
This initial pass is enough for now.
Later, I'll write this down to turn it into a checklist.</p>
<p>For now, I've got other things I need to focus on.</p>
<p>Good night.</p>
Weekly Roundup 2021-11-022021-11-02T04:00:00-04:002021-11-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-02:/weekly-roundup-2021-11-02<p class="first last">I feel like I'm starting to spin back up...</p>
<ul class="simple">
<li>Wednesday: I filled in the most obvious deficits in the rough draft of the poem to introduce my worldbuilding.</li>
<li>Thursday: I worked on formatting the draft, so now it renders nicely.</li>
<li>Friday: I circled back around to try to cover all of the issues my current work on MOTR can hit.</li>
<li>Saturday: I sketched out some ideas there, but didn't come to anything really clear.</li>
<li>Sunday: I figured out some stuff that's (probably?) missing from that.</li>
<li>Monday: I focused on stuff that I don't write blog posts for, so... yeah.</li>
</ul>
<p>Next week, I'm going to try to focus on writing for a bit, and then start developing the <tt class="docutils literal">Fragment</tt> API within MOTR's libraries, because I don't think incrementally writing it in the motrfile is worth it, because it doesn't really make sense to switch a script call "halfway" over.
(Although, it might make sense to have some kind of commented block that I can prototype the desired calls in, to firm up the interface ahead-of-time.</p>
Diary 2021-11-012021-11-01T04:00:00-04:002021-11-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-11-01:/diary-2021-11-01<p class="first last">Looks like I took a day off? I didn't realize it.</p>
<p>I seem to have taken things mostly easy today.
I put in some work on projects that I don't want to write up yet/ever.</p>
<p>I thought for some reason I'd end up with more to talk about, but I guess I was wrong.
No reason to drag things out.</p>
<p>Good night.</p>
Coding 2021-10-312021-10-31T04:00:00-04:002021-10-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-31:/coding-2021-10-31<p class="first last">Further and further down some kind of rabbit hole.</p>
<p>Looks like the <tt class="docutils literal">Fragment</tt> API wasn't fully baked before, and it's not quite baked now.</p>
<p>Earlier today, I added stuff onto the prototype, focusing on the Generator classes and helpers.
I got the basics done, though not tested, and I ran across a concept that I need to make sure makes sense.</p>
<p>The motivation is, it should be possible for a <tt class="docutils literal">Fragment</tt> to contain <tt class="docutils literal">Input</tt> and <tt class="docutils literal">Output</tt> values.
<tt class="docutils literal">Input</tt> is fine, but each <tt class="docutils literal">Output</tt> must be unique.
That means that the <tt class="docutils literal">Output</tt> needs to depend on every iteration variable used by the top-level generator helper.
As such, it would help to catch errors sooner if a generator could be marked as needing to depend on every variable.</p>
<p>This could be accomplished with something like a <tt class="docutils literal">maximal</tt> boolean field.
Then the combining helpers could check that if one input is <tt class="docutils literal">maximal</tt>, then the other input's keys are a subset of the <tt class="docutils literal">maximal</tt> input.
And the combined output would have the boolean <tt class="docutils literal">or</tt> of the inputs as its <tt class="docutils literal">maximal</tt> field.
Would probably want warning helpers for invoking things, that can check if an <tt class="docutils literal">Output</tt> is generated from a non <tt class="docutils literal">maximal</tt> root generator, or if a <tt class="docutils literal">maximal</tt> root generator does not generate an <tt class="docutils literal">Output</tt>.</p>
<p>I don't want to keep on writing this until super late, so I'm going to wrap it for now, and think about something else to shift to for a bit.</p>
<p>Good night.</p>
Coding 2021-10-302021-10-30T04:00:00-04:002021-10-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-30:/coding-2021-10-30<p class="first last">I guess this went as well as could be hoped.</p>
<p>I'm not going to touch code for now; I'm just going to try to sketch out that <tt class="docutils literal">FragmentGenerator</tt> idea I thought of last night.</p>
<p>First note, it's not really a good name, and I should come up with something else at some point.
In any case...</p>
<p>The idea I kind of have right now is that there's some kind of registry-ish object (it can just be a dictionary in the prototype) that contains sequences of values associated with different fields.
So, the idea is that the types are like <tt class="docutils literal">def generate(self, registry: Registry) <span class="pre">-></span> Fragment:</tt></p>
<p>Or... I guess the generator has to explicitly expose the fields it's iterating over, because it has to be possible to compose these generators.
That seems to give me an interface where, on the one hand, it passes a registry of sequences, and on the other, it passes a registry of specific values.</p>
<p>But, since we're never going to vary the global registry passed to an overall command, maybe there's some way to move the registry into the construction logic.
Then the top-level fragment generator could set up the proper for-loop, and call the sub-generators just with the for-loop variables required by the sub-generators.
On the other hand, it's not reasonable to duplicate it as an argument to so many constructors...
So, I guess the first idea makes sense.
Pass a registry to the top-level <tt class="docutils literal">FragmentGenerator</tt>, get an iterator of <tt class="docutils literal">Fragment</tt>s.
Within the iterator, convert the registry into a product iterator, and pass all that information into the sub-generators, implicitly, by passing it to a recursive function on the top level.
(I'll want to cache the requirements in each sub-generator, because otherwise there's some level of redundant work, I think...)
Hm, the top-level should be an independent function.</p>
<p>Okay, I'm too tired to go through the rest of this now.
I'll have to make another attempt tomorrow.</p>
<p>Good night.</p>
Coding 2021-10-292021-10-29T04:00:00-04:002021-10-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-29:/coding-2021-10-29<p class="first last">I don't <em>think</em> I'm inflicting problems on myself, but it does slightly feel like it.</p>
<p>I did a little poetry work tonight, but I want to focus on planning for MOTR.
Now, from an implementation perspective, "Shove platform-based string interpolation into a callback" is easier... except that I'm the one who has to implement <em>everything</em>, so I can't pass the buck on this, because it just instantly comes back to me.</p>
<p>So, here's what I know about how the <tt class="docutils literal">Fragment</tt>s will be used:</p>
<ul class="simple">
<li>Some <tt class="docutils literal">Fragment</tt>s will need to run against multiple versions of Python, and each will need to specify distinct output files.</li>
<li>Some <tt class="docutils literal">Fragment</tt>s will need to run against one project per run.</li>
<li>Some <tt class="docutils literal">Fragment</tt>s will need to run against all projects in one run.</li>
</ul>
<p>From that, it seems like there needs to be an interface that takes a multi-project object, and yields some number of concrete <tt class="docutils literal">Fragment</tt>s.
I don't <em>think</em> it makes sense to put this ability on the individual <tt class="docutils literal">Fragment</tt>s.
It would probably be easier to have a general case of "doesn't need individual projects (possibly because it got a multi-project)".</p>
<p>One thing that just occurred to me is that, in the case of stuff like <tt class="docutils literal">coverage erase</tt>, the platforms that it has to <em>parameterize over</em> are different than the platforms it has to <em>run on</em>.
So, these should be separate at the base level, and have some kind of helper to unify them for the common case.</p>
<p>Another possibility is to avoid baking in the different ideas of what to parameterize against, and construct a framework for combining streams of fragments into streams of larger fragments, via <tt class="docutils literal">zip</tt> and <tt class="docutils literal">product</tt>.
That doesn't sound right as an end-user interface, because the choice of whether to <tt class="docutils literal">zip</tt> or <tt class="docutils literal">product</tt> would be based on whether there was an existing parameter of the same type, which would have to be in the same order...
It makes more sense to have something that can generate <tt class="docutils literal">Fragment</tt>s based on external parameters, and then those parameters can simply be looped over once.</p>
<p>So, because the <tt class="docutils literal">Fragment</tt>s don't directly code this, I suppose there needs to be some form of <tt class="docutils literal">FragmentGenerator</tt> protocol...
(One implementation should take a sequence of platforms, and another both a sequence of platforms and a multi-project.
It might make sense to make these explicitly Python-specific.)</p>
<p>I'll try to figure this out later.
For now, I'll be happy that I came to a decision on how to handle this.
And try to wrap up.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-10-282021-10-28T04:00:00-04:002021-10-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-28:/worldbuilding-ksa-2021-10-28<p class="first last">I wasn't expecting to file a bug report from this.</p>
<p>All right, there we go.
I removed the comments from the draft, and formatted the draft based on my initial metrical analysis.
I then added some custom CSS to fix how it rendered in the theme.</p>
<p>The next step from this is to do a few passes of revision on screen, then print it out (it's like 4 pages), and take notes on issues.</p>
<p>The main focus show be on improving the quality of the draft, but I also want to think some about presentation and work on writing up my notes for the rest of the setting document.</p>
<p>All right, I'd better get ready for bed.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-10-272021-10-27T04:00:00-04:002021-10-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-27:/worldbuilding-ksa-2021-10-27<p class="first last">I did a thing.</p>
<p>Today was incredibly tiring, but I did get a single concrete task accomplished: I revised the rough draft enough that it has all of the syllables it needs.</p>
<p>I see no reason to attempt anything else for now.
It's a small task, but now it's done, and I'm closer.</p>
<p>I'm going to get ready for bed now.</p>
<p>Good night.</p>
Weekly Roundup 2021-10-262021-10-26T04:00:00-04:002021-10-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-26:/weekly-roundup-2021-10-26<p class="first last">That was a bit frustrating, but my main priority is sleeping better, which, um, we'll see...</p>
<ul class="simple">
<li>Wednesday: I was really tired.</li>
<li>Thursday: I was even more tired.</li>
<li>Friday: I planned out a quick enhancement to MOTR.</li>
<li>Saturday: I put that plan into action, and then considered the next things to work on afterwards.</li>
<li>Sunday: I couldn't work on much.</li>
<li>Monday: I tried to plan the next changes to MOTR, and I ran into trouble.</li>
</ul>
<p>Next week, I'm going to take things easy tomorrow, try to work on some other things after, and revisit MOTR later.</p>
Coding 2021-10-252021-10-25T04:00:00-04:002021-10-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-25:/coding-2021-10-25<p class="first last">Spinning my wheels a bit.</p>
<p>Okay, my plans for the <tt class="docutils literal">Fragment</tt> API are conflicting with some of my recollections of plans for the <tt class="docutils literal">Project</tt> API, but I'm having trouble tracking down my notes to confirm this.
So, I'm going to need to try to re-derive some of this, and maybe have some new layouts in light of the <tt class="docutils literal">Fragment</tt> API.</p>
<p>One of the key things going on with the <tt class="docutils literal">Fragment</tt> API is that it makes it non-trivial to combine a <tt class="docutils literal">Project</tt> and a <tt class="docutils literal">Platform</tt>.
This is because the choices associated with the <tt class="docutils literal">Project</tt> get baked into the final <tt class="docutils literal">Fragment</tt>, and the <tt class="docutils literal">Platform</tt> does not feed into the contents of the <tt class="docutils literal">Fragment</tt>.
At least, not inherently...
Because each command execution should be creating distinct artifacts, the <tt class="docutils literal">Fragment</tt> API needs to be extended with a system of parameterization or templating in order to have some degree of polymorphism depending on the choice of <tt class="docutils literal">Platform</tt> or other considerations.</p>
<p>My choices for templating systems include the built-in options like <tt class="docutils literal">format()</tt> and <tt class="docutils literal">string.Template</tt>, as well as Jinja, which must be installed, otherwise MOTR is very broken.</p>
<p>Another possibility is to forgo changing the data model significantly, and simply work with <tt class="docutils literal">Callabable</tt>s that use f-string interpolation instead.
Going down that route requires me to remember which order I wanted to pass the objects in.
I <em>believe</em> the idea was that a <tt class="docutils literal">Session</tt>/<tt class="docutils literal">Runner</tt>/<tt class="docutils literal">Whatever</tt> would be first parameterized by all possible <tt class="docutils literal">Platforms</tt>, and secondarily by all possible <tt class="docutils literal">Package</tt>s/<tt class="docutils literal">Project</tt>s/<tt class="docutils literal">Whatever</tt>s.</p>
<p>Although...
Perhaps the runner shouldn't know about the <tt class="docutils literal">Package</tt>s, and should just get a collection of <tt class="docutils literal">Callable</tt>s that take information about the environment...
But at that point, I think something's gone wrong with the abstraction.
Fundamentally, an environment-type object is being constructed to run a single command, which must exist in a single location, so there is always a "main" binary directory, even if, I don't know, I contrive some way to run a command that requires some combination of Node, Python, and Rust packages.</p>
<p>Now, a <tt class="docutils literal">Fragment</tt> contains the data required to construct the environment that can execute it, except for details about the exact <tt class="docutils literal">Platform</tt>s used.
We could suppose that the requirements are encoded as pairs of strings containing a platform alias and a requirement, and the interface for combining a group of <tt class="docutils literal">Platform</tt>s with a <tt class="docutils literal">Fragment</tt> would look something like</p>
<div class="highlight"><pre><span></span><span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Platforms</span><span class="p">:</span>
<span class="n">platforms</span><span class="p">:</span> <span class="n">PMap</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Platform</span><span class="p">]</span>
<span class="n">main</span><span class="p">:</span> <span class="nb">str</span>
</pre></div>
<p>Now, the contents of a <tt class="docutils literal">Fragment</tt> could depend on any <tt class="docutils literal">Platform</tt> in a <tt class="docutils literal">Platforms</tt>, and once the full <tt class="docutils literal">Fragment</tt> is completed, it's then ready to be passed to the main <tt class="docutils literal">Platform</tt> to be converted into an executable call...</p>
<p>Something about this whole setup is striking me as not quite right, but it's in the interaction between "how this must be used" and "the data structures I want".
To settle this, I need to get a firmer understanding of the usage, so I can change the data structures.</p>
<p>I'm not getting that tonight, so I'll wrap up for now.</p>
<p>Good night.</p>
Diary 2021-10-242021-10-24T04:00:00-04:002021-10-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-24:/diary-2021-10-24<p class="first last">Ugh, not again.</p>
<p>Well, I thought I was going to have a chance to work on the <tt class="docutils literal">Fragment</tt> API today, but all of a sudden it's 11:30 and I feel terrible.</p>
<p>I've got to put everything towards feeling less gross, so I'm putting in a super-short entry.</p>
<p>Good night.</p>
Coding 2021-10-232021-10-23T04:00:00-04:002021-10-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-23:/coding-2021-10-23<p class="first last">That was easy. What's next is... probably not.</p>
<p>Okay, I got the <tt class="docutils literal">map</tt> method written and updated the motrfile.
Next up is figuring out the next iteration of the custom actions, and I think that means putting the <tt class="docutils literal">Fragment</tt> prototypes into the motrfile and trying to build from there.</p>
<p>Because of how different the endpoint is from the existing action classes, I think it makes more sense to build it up next to the existing classes, and try to phase out some auxiliary usages, before getting to the meat of it all.</p>
<p>Anyway, I let things go way too late again, and I'm really tired.
I'll wrap up now.</p>
<p>Good night.</p>
Coding 2021-10-222021-10-22T04:00:00-04:002021-10-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-22:/coding-2021-10-22<p class="first last">One of the perks of this project is that I get to decide what to work on.</p>
<p>This is going to be a quick entry.</p>
<p>I looked over the many, many 1.0 blockers that I put in for MOTR, and I picked one that's probably not a big deal, but it should make the code look nicer, so I started working on it.
That issue is "Figure out how to lift operations on the underlying type into the context of the <tt class="docutils literal">Input</tt> wrapper".
And I think the solution is pretty simple: add the following code to the <tt class="docutils literal">Input</tt> class:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">map</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">Input</span><span class="p">[</span><span class="n">T</span><span class="p">],</span> <span class="n">function</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">T</span><span class="p">],</span> <span class="n">U</span><span class="p">])</span> <span class="o">-></span> <span class="n">Input</span><span class="p">[</span><span class="n">U</span><span class="p">]:</span>
<span class="k">return</span> <span class="n">Input</span><span class="p">(</span><span class="n">function</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">path</span><span class="p">))</span>
</pre></div>
<p>This can then be called like <tt class="docutils literal">input_.map(lambda path: path / "child")</tt>, and it's a bit wordy, but it's not a big deal.
In particular, it allows me to get rid of explicit references to the <tt class="docutils literal">path</tt> field, so I can eventually change it to something that makes more sense, given that <tt class="docutils literal">Input</tt> and <tt class="docutils literal">Output</tt> are generic types now.</p>
<p>Working on this issue is one thing that will take references to the field out of the motrfile.
The other is converting some of the custom actions into core actions, which is going to be a much bigger and more complicated undertaking, and maybe I should just be ready to do that one wrong the first time I try.</p>
<p>The central issue with bringing in the custom actions is, I have two custom actions, and I want to get rid of one, and rewrite the other, so I guess I'd rather complete and prove out the rewrite of the latter before I bring it into the core.
Getting the rewrite done is going to require a bunch of other <em>stuff</em>.
(Like the <tt class="docutils literal">Fragment</tt> classes.)</p>
<p>So, low-hanging fruit in the near future, big rewrite project soon after.
Sounds like a plan, and I don't care how good a plan it sounds like.</p>
<p>Good night.</p>
Diary 2021-10-212021-10-21T04:00:00-04:002021-10-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-21:/diary-2021-10-21<p class="first last">So tired... head hurt...</p>
<p>Traveled today.
For hours and hours.</p>
<p>I absolutely should not try to work on anything for the long term tonight.</p>
<p>Maybe I'll poke at stuff after this publishes, maybe I won't.</p>
<p>Good night.</p>
Diary 2021-10-202021-10-20T04:00:00-04:002021-10-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-20:/diary-2021-10-20<p class="first last">I don't remember what I had planned. It's almost as if something is impairing my cognitive functions...</p>
<p>I thought I had something planned for tonight, but I don't remember.
It would really be better to take things easy, rather than think too hard about what it could have been.</p>
<p>Let's see what I can work on in the next few days:</p>
<ul class="simple">
<li>Enhancements to MOTR</li>
<li>Finally revisit Missable Mysteries</li>
<li>Try to work on the poem draft</li>
</ul>
<p>For now, I ought to wrap up and try to get a reasonable amount of sleep.</p>
<p>Good night.</p>
Weekly Roundup 2021-10-192021-10-19T04:00:00-04:002021-10-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-19:/weekly-roundup-2021-10-19<p class="first last">Laying some important groundwork.</p>
<ul class="simple">
<li>Wednesday: I planned out the code required to streamline the release workflow for MOTR.</li>
<li>Thursday: I evaluated bump2version. It should work for my purposes, but it does have one weird interface quirk that I've entered a bug for.</li>
<li>Friday: I looked over my mercurial commands for the simplified workflow, and thought "You know what, that all looks good. It's probably fine."</li>
<li>Saturday: I was extremely tired.</li>
<li>Sunday: I had some... ideas.</li>
<li>Monday: I wrote like 15 bugs against MOTR.</li>
</ul>
<p>Next week, I'm going to try and take things easy, and work on whatever I feel like.</p>
Coding 2021-10-182021-10-18T04:00:00-04:002021-10-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-18:/coding-2021-10-18<p class="first last">A partial list of things I need to change about MOTR.</p>
<p>Checking over the motrfile to see which bugs I should write up...</p>
<ul class="simple">
<li>Move wheel creation code into core.</li>
<li>Move requirements file creation code into core.</li>
<li>Figure out how to lift operations on the underlying type into the context of the <tt class="docutils literal">Input</tt> wrapper.</li>
<li>Move project package code into core.</li>
<li>Move path utility function into core.</li>
<li>Create helpers for generating sets of project packages.</li>
<li>Move <tt class="docutils literal">make_parent</tt> helper into core and evaluate the possibility of using it with <tt class="docutils literal">write_bytes</tt>.</li>
<li>Rewrite virtualenv creation code (including pip calls) to use the <tt class="docutils literal">Fragment</tt> API.</li>
<li>Eliminate usage of <tt class="docutils literal">venv</tt> module.</li>
<li>Eliminate direct references to Flit.</li>
<li>Rework the <tt class="docutils literal">RuntimeAction</tt> interface to take a callback to register output streams.</li>
<li>Rewrite pytest calls to use the <tt class="docutils literal">Fragment</tt> API.</li>
<li>Rewrite flake8 call to use the <tt class="docutils literal">Fragment</tt> API.</li>
<li>Rewrite mypy call to use the <tt class="docutils literal">Fragment</tt> API.</li>
<li>Rewrite coverage calls to use the <tt class="docutils literal">Fragment</tt> API.</li>
<li>Rewrite pyinstrument calls to use the <tt class="docutils literal">Fragment</tt> API.</li>
</ul>
<p>That's going to give me plenty to chew on.
I'll enter that in after I publish this.</p>
<p>I'm not going to try to write any more; I just want to wrap things up quickly.</p>
<p>Good night.</p>
Coding 2021-10-172021-10-17T04:00:00-04:002021-10-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-17:/coding-2021-10-17<p class="first last">"I don't think I have anything else to say." *spontaneously types a bunch of crazy-sounding ideas*</p>
<p>Several corrections later, and I've successfully published a version of MOTR using a script.
Next up, I should make sure it better explains what it's doing.</p>
<p>(The published version has some lines commented out, but it's not like this code needs to work for anyone else.
Moreso than MOTR's whole "most of the code still lives in the configuration file" problem.)</p>
<p>I'm feeling a little iffy tonight, so I guess I'm not going to come up with much more to say.
My big feeling on all of this is that it's nice to do this kind of sketch-then-retype flow.
Lets me do the high-level design first, rough it in, then do a quick full rewrite to sand off any intense awkwardness.</p>
<p>It might be interesting if I could come up with some kind of "pseudo-English" in line with "pseudocode".
If the various analogies hold, that'd make drafting prose, and possibly poetry, easier.</p>
<p>Maybe for prose, I should look into restricting myself to a subset of English and see how that feels.
Or maybe I need to take my drafts, and work on developing some kind of higher-level abstraction of them, that exhibits sensible changes from draft to draft.
Like maybe there's some kind of "higher-level language of prose" that's not satisfying to read if you're in the target audience of the finished product, but that makes it easier to reason about and change the narrative.</p>
<p>Unfortunately, as I say that, I realize that what I'm describing is not analogous to an artifact in a high-level language getting compiled, but an artifact in a formal language getting refined.
I guess I should look more into advanced formal methods.
This sounds crazy enough that I assume it could be mistaken for an attempt at dry humor, but I'm genuinely curious whether this concept could be made to work.</p>
<p>Anyway, I need to wrap up.</p>
<p>Good night.</p>
Diary 2021-10-162021-10-16T04:00:00-04:002021-10-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-16:/diary-2021-10-16<p class="first last">Feeling a bit wrung-out.</p>
<p>I'm going to take things easy for now, and try to get started on the work for MOTR tomorrow.</p>
<p>I'm just really tired is all, and I need to take some rest.</p>
<p>I don't have anything else to say.</p>
<p>Good night.</p>
Coding 2021-10-152021-10-15T04:00:00-04:002021-10-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-15:/coding-2021-10-15<p class="first last">"I don't know which of these assumptions might be wrong, so I guess I'll try running it and see what blows up."</p>
<p>Okay, I'm still not feeling up for serious work, so I'm just going to review the other things I want to verify for the streamlined publishing workflow.</p>
<p>Honestly, all of my hopes/impressions for how mercurial works seem sensible enough that I think I'd rather convert my prototype into a script, comment out the last command, and make sure it handles everything properly.
If that all works, I'll then publish a new version just to make sure that the published version matches whatever I have locally.
(Also, I guess I should avoid letting it publish a major version for now.)</p>
<p>Once that's done, I'll have to get better about handling the issue tracker, and probably using topics.
(Right now, I'm just lumping everything in a topic called <tt class="docutils literal"><span class="pre">self-hosting</span></tt>, which I suppose is reasonable, insofar as I keep moving the goalposts.
MOTR absolutely runs against itself, <em>but</em> it accomplishes this by offloading a heroic quantity of functions and data types onto the configuration file, which means that it's not reasonable to use MOTR for my other projects, let alone expect anyone else to use it.
I should maybe consider renaming the topic to something like <tt class="docutils literal"><span class="pre">other-hosting</span></tt>, I don't really know, and right now, I don't really care.)</p>
<p>Anyway, I've got some other stuff to work on right now, and I want to get this published and over with.</p>
<p>Good night.</p>
Coding 2021-10-142021-10-14T04:00:00-04:002021-10-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-14:/coding-2021-10-14<p class="first last">I think compressing modal qualifiers is supposed to be "acceptable" under some circumstances, maybe, but it's certainly not clear in these circumstances.</p>
<p>All right.
I haven't been doing super great with organization after that migraine, so I didn't have time for much tonight.</p>
<p>I did get <tt class="docutils literal">bump2version</tt> set up and I did some basic tests via the <tt class="docutils literal"><span class="pre">-dry-run</span></tt> option.
The <tt class="docutils literal"><span class="pre">--verbose</span></tt> output from that is <em>a little</em> confusing, because it doesn't distinguish between "not tagging because it's dry-run" (true) and "not tagging because it's disabled in the configuration" (should <em>also</em> be true).</p>
<p>Actually, this output is misleading enough that I'm going to enter an issue for it.</p>
<p>And, that's about all I have time for.
Time to watch some videos about doing horrible things to video games, and I'll try to verify my workflow assumptions later, when I don't need spell-check holding my hand <em>quite</em> so much...</p>
<p>(... "veryify"?)</p>
<p>Good night.</p>
Coding 2021-10-132021-10-13T04:00:00-04:002021-10-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-13:/coding-2021-10-13<p class="first last">I don't gamble with money. I gamble with "Is this remotely the intended way to accomplish this task?" I don't know how to tell if I've won or lost.</p>
<p>Okay, I filled in the prototype of the release streamlining.
Here's what needs to happen:</p>
<ul class="simple">
<li>Set up bump2version, and configure it to update the <tt class="docutils literal">__init__.py</tt> file, and to commit, but <em>not</em> to tag.</li>
<li>Add a check for multiple heads on the current topic.
This appears to be <tt class="docutils literal">hg heads <span class="pre">--rev</span> <span class="pre">topic(topic-of-interest)</span> <span class="pre">--template</span> <span class="pre">"{rev}\n"</span></tt>.</li>
</ul>
<p>Test a bunch of things on a separate repo, including:</p>
<ul class="simple">
<li>Test the above <tt class="docutils literal">hg heads</tt> command.</li>
<li><tt class="docutils literal">hg status</tt> always outputs to <tt class="docutils literal">stdout</tt> if there's <em>something</em> there to talk about.</li>
<li><tt class="docutils literal">hg topics <span class="pre">--current</span></tt> fails if no topic is set, and returns the current topic otherwise.</li>
<li>I've got a reasonable format for generated topic names; I'm currently trying alphanumerics separated by underscores.
This mainly needs to be comprehensible in the context of revsets.</li>
<li>Regardless of repository state, calling <tt class="docutils literal">hg update <span class="pre">--clean</span></tt> with a topic name will at least ensure that there are no changes to commit.</li>
<li>I have the correct logic for reading the <em>second</em> component in a filename that is a period-separated string.</li>
<li><tt class="docutils literal">hg topics target <span class="pre">--rev</span> topic(source)</tt> brings all commits in the <tt class="docutils literal">source</tt> topic into the <tt class="docutils literal">target</tt> topic.
It is acceptable (but maybe not necessary, I don't know?) to assume that the newest commit in the target is the parent of the oldest commit in the target.
I'm also not sure if this is a <em>sensible</em> way to accomplish this.</li>
</ul>
<p>I'm probably missing more things, but <em>hopefully</em> I won't hit too many more edge cases, and when it does, hopefully it'll fail for a weird reason rather than "succeed" in a weird way.</p>
<p>Anyway, it's way too late right now.</p>
<p>Good night.</p>
Weekly Roundup 2021-10-122021-10-12T04:00:00-04:002021-10-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-12:/weekly-roundup-2021-10-12<p class="first last">I feel like I can't trust my eyes not to hurt my brain again.</p>
<ul class="simple">
<li>Wednesday: I finished the rough draft of the poem.</li>
<li>Thursday: Mostly played videogames and did fan region stuff.</li>
<li>Friday: Played videogames.</li>
<li>Saturday: Sick.</li>
<li>Sunday: Sick.</li>
<li>Monday: Not as sick. Played videogames.</li>
</ul>
<p>Next week, I <em>hope</em> to not be as sick.
I've got a few things I can/want to work on, but it's kind of down to what turns out to be possible.</p>
Diary 2021-10-112021-10-11T04:00:00-04:002021-10-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-11:/diary-2021-10-11<p class="first last">Videogames, mostly.</p>
<p>Well, I felt <em>terrible</em> after last night's entry, and now I feel... okay?
Ish?</p>
<p>I still wanted to take things easy today, so there's not much to talk about.</p>
<p>Hopefully I'll get clear of all of this tomorrow.</p>
<p>Good night.</p>
Diary 2021-10-102021-10-10T04:00:00-04:002021-10-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-10:/diary-2021-10-10<p class="first last">Apparently, one of the signs of "migraine is getting better" is "oh wow, my stomach just clenched for no apparent reason".</p>
<p>Migraine update: starting to recover just now, and that hit me hard.
I'm going to do another short post, then space out for a while.</p>
<p>If I feel like it, I might come back and update this post afterwards, but I'm not really planning to.</p>
<p>Good night.</p>
Diary 2021-10-092021-10-09T04:00:00-04:002021-10-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-09:/diary-2021-10-09<p class="first last">It sucks not getting everything done that I want done, but sometimes it's just not possible at the time.</p>
<p>I've had a migraine coming on for a while.
So that sucks.
I'm going to avoid pushing myself any more tonight, and just take it easy.
This post is going to be one of the things I put minimal effort into.</p>
<p>Good night.</p>
Diary 2021-10-082021-10-08T04:00:00-04:002021-10-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-08:/diary-2021-10-08<p class="first last">"I'm a genius! ... Oh no!"</p>
<p>I guess what's really been taking up a bunch of my time lately is playing <a class="reference external" href="http://roguetemple.com/z/hyper/">HyperRogue</a>.
There's a lot for me to see, still; I'd probably see more of it if I could stop getting over-confident or impatient.</p>
<p>I was going to see if I had more to say on the matter, and I guess not.
I should get to bed.</p>
<p>Good night.</p>
Diary 2021-10-072021-10-07T04:00:00-04:002021-10-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-07:/diary-2021-10-07<p class="first last">Apparently, I need to design more water and steel types.</p>
<p>I basically took things easy today.
I'm doing all right focusing on the fan region I mentioned, though I suspect I'll want a break from that soon.</p>
<p>The big effort I put into things today was to put together a spreadsheet of all of my concepts, with metrics.
I think I'm going to want to refine the metrics later; what I have right now is stuff related to type distributions, and it seems to me like stuff like legendaries should maybe be weighted differently in that context.</p>
<p>Anyway, I don't really have anything else to say, and I'll suffer if I don't get to bed, so I'm going to do that.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-10-062021-10-06T04:00:00-04:002021-10-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-06:/worldbuilding-ksa-2021-10-06<p class="first last">Struggling across the finish line, visibly disgusted with my performance.</p>
<p>The rough draft is done.
I feel like the ending falls flat, but it does what it's supposed to, so I'm just going to accept this for now.</p>
<p>I've got other stuff I want to do tonight, so I'm going to rush through finishing this post.</p>
<p>Here's what needs to happen to the draft:</p>
<ul class="simple">
<li>Clean up the outline notes.</li>
<li>Fix up the formatting.</li>
<li>Analyze the scansion and note any serious issues.</li>
<li>Do spot improvements, now that I can edit. (Like I think there are some missing syllables that I just outright gave up on for now, in the name of finishing the draft?)</li>
<li>Print it out and read it and mark it up.</li>
</ul>
<p>For now, I need to work on that other stuff.</p>
<p>Good night.</p>
Weekly Roundup 2021-10-052021-10-05T04:00:00-04:002021-10-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-05:/weekly-roundup-2021-10-05<p class="first last">Would you believe I haven't been holding myself to work on a particular thing on a given day in quite some time? Shocking, I know.</p>
<ul class="simple">
<li>Wednesday: I worked on poetry, and thought I was going to plan Missable Mysteries stuff, which... didn't happen.</li>
<li>Thursday: Same...</li>
<li>Friday: I was distracted from bloggable stuff.</li>
<li>Saturday: I did some prototyping for MOTR.</li>
<li>Sunday: I noticed that MOTR is unusable in an automated context.</li>
<li>Monday: I fixed the most glaring issue there.</li>
</ul>
<p>Next week, I want to get a bit further with poetry, and actually work on Missable Mysteries stuff.</p>
Coding 2021-10-042021-10-04T04:00:00-04:002021-10-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-04:/coding-2021-10-04<p class="first last">Bug fixing speedrun.</p>
<p>Well, I was focused on other stuff today, but I managed to get the exit code stuff handled pretty quickly.</p>
<p>Basically, I added some tests, fixed the tests a few times, discovered that I was missing an exception suppression, added it, got the tests to pass, and then confirmed that the exit code behavior is now correct.</p>
<p>With this, MOTR now has the potential to be useful in an automated context, like what I'm planning to do with the release workflow.</p>
<p>I'll take notes on that workflow later.
For now, I let things go late again, so I need to get to bed.</p>
<p>Good night.</p>
Coding 2021-10-032021-10-03T04:00:00-04:002021-10-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-03:/coding-2021-10-03<p class="first last"><em>OOPS</em></p>
<p>I've got a basic sketch of a streamlined release cutting process, but when I was checking over all of the components, I discovered a show-stopping defect in MOTR that I need to address before I can use it in the process:</p>
<p>MOTR exits with return code 0 if it gets all the way through its tasks <em>even if</em> some of the tasks failed.
That's obviously pretty bad, because it's never going to be able to block a release like that.
Looks like what I want is to set the exit code to 1 after everything is printed, if there are any failed or aborted tasks.</p>
<p>I'll write tests for this tomorrow.
It should be a simple change, but I want to be pretty thorough, which I can't be when I'm tired.</p>
<p>I'll wrap up early and try to get some rest.</p>
<p>Good night.</p>
Coding 2021-10-022021-10-02T04:00:00-04:002021-10-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-02:/coding-2021-10-02<p class="first last">I'm trying to hold off on refactoring the common behaviors until I understand how any of this needs to work.</p>
<p>I managed to give myself kind of a rough day today, so I just focused on exploratory prototyping for MOTR.
Just, like, zoning out a bit, translating notes to code.</p>
<p>Basically... MOTR runs a bunch of commands, and those commands can be decomposed into distinct parts that carry installation requirements in order to work.
So, I've got prototype <tt class="docutils literal">Fragment</tt> and <tt class="docutils literal">Option</tt> classes.
A <tt class="docutils literal">Fragment</tt> is <em>either</em> a complete command (just requiring a bin directory prefix), or an invocation of a Python module.
(This may open up as I look into working with other kinds of command.)
An <tt class="docutils literal">Option</tt> is a sequence of command-line arguments or environment variables, along with associated requirements.
From a runtime perspective, they are nearly the same, except that <tt class="docutils literal">Fragment</tt>s have an optional field that allows them to combine with another <tt class="docutils literal">Fragment</tt>, if the field is not <tt class="docutils literal">None</tt>.
An <tt class="docutils literal">Option</tt> can be added to the end of a <tt class="docutils literal">Fragment</tt> or <tt class="docutils literal">Option</tt>.
In the prototype, this is pretty loosey-goosey, at least at runtime, but I've got a sketch of type-level stuff that should do the right thing, more or less.</p>
<p>Now that I've got something that can be fed into some kind of environment preparation function, I need to design that function.
Focusing on virtualenv for now, here are the axes of variation:</p>
<ul class="simple">
<li>Which Python version gets installed</li>
<li>Which constraints file to use</li>
</ul>
<p>And the different stages:</p>
<ul class="simple">
<li>Creation <em>subsumes</em> the "update" step from the current working version, because virtualenv bundles the latest pip.</li>
<li>Installation is much as the current version, I <em>think</em>.</li>
<li>Running is added; because the command and the requirements are built in parallel, there's no reason to hold off on running the command.</li>
</ul>
<p>As a result, all of the stages should collapse into a single invocation from the perspective of the code at large.</p>
<p>The main thing I need to figure out is how to handle specifying the constraints file.
The design problem arises from the fact that I want to specify environment variables, and I want to build an install command, but the constraints file is the only environment variable that I want to pass to the install command.
I suppose one way around this would be to check if the bug I filed against pip is still open...
<a class="reference external" href="https://github.com/pypa/pip/issues/8439">Yep, there it is</a>.
Looking over Flit's source code, I believe it's currently safe for me to use the command-line options for constraints files.
This is probably the way to go, just punting on addressing the design.
Either I'll come up with a design, or the pip issue will get triaged.
One of those has to happen before 1.0, but I'm not there yet.</p>
<p>Anyway, I think tomorrow I'll put the design on hold, and try to come up with a plan for making releases not have like seven steps or whatever.</p>
<p>Good night.</p>
Diary 2021-10-012021-10-01T04:00:00-04:002021-10-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-10-01:/diary-2021-10-01<p class="first last">I didn't realize I was taking a break and/or switching gears today, but I guess that happened.</p>
<p>I got distracted by stuff I don't want to write up right now, so I guess today is kind of a loss so far.
The process behind the existence of the "stuff" is "I've been watching a bunch of videos about fanmade Pokémon regions lately; why don't I try doing that?"
I don't have any kind of plan right now to make it widely available; maybe I'll want to reconsider making it more public in a few weeks, but I don't think it makes sense to think about the level of polish that would require right now.</p>
<p>I was spinning my wheels a bit seeing if I'd come up with anything else, but I guess not.
I definitely shouldn't push it any further, so I should wrap up.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-09-302021-09-30T04:00:00-04:002021-09-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-30:/worldbuilding-ksa-2021-09-30<p class="first last">I don't have to <em>like</em> it for it to count as progress...</p>
<p>I'm approaching the end of the outline.
The quality of each new stanza feels like it's going down, so, that's not great.</p>
<p>All I can do I push through the last few stanzas, it can't be much more than half a dozen, if that, and then focus on stuff like:</p>
<ul class="simple">
<li>Prototyping more code for MOTR.</li>
<li>Outlining the next for Missable Myteries posts.</li>
<li>Going over the current version of the first post with more scrutiny, now that SoME1 is over and done with, from my perspective.
I would like to see if I can make it less wordy somehow.
I <em>think</em> that's a reasonable thing to attempt.</li>
</ul>
<p>Zoned out, need to wrap up ASAP.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-09-292021-09-29T04:00:00-04:002021-09-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-29:/worldbuilding-ksa-2021-09-29<p class="first last">Not really excited to see how much of this gets junked in revisions, but whatever.</p>
<p>I'm getting into the home stretch on this first draft of the poem.
I didn't get much written tonight, but I got some written, and there's just a handful of story beats left to hit.</p>
<p>I think my plan with this is to finish up the draft, and then let it sit while I finally get back to planning Missable Mysteries content.</p>
<p>For now, I'm going to try to take things easy.
And at the moment, that involves doing some stuff that's a little distracting, so I'm going to wrap this post up before it somehow goes way late.</p>
<p>Good night.</p>
Weekly Roundup 2021-09-282021-09-28T04:00:00-04:002021-09-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-28:/weekly-roundup-2021-09-28<p class="first last">Just putting in a bunch of effort.</p>
<ul class="simple">
<li>Wednesday: I wrote some poetry for my worldbuilding project.</li>
<li>Thursday: I wrote a bit more, and filled space trying to figure out how best to write about writing this stuff.</li>
<li>Friday: I made a bunch of progress with the poetry, and then didn't have the energy to write pretty much any more at all.</li>
<li>Saturday: I made some improvements to MOTR's code.</li>
<li>Sunday: I documented exactly how messed up the process currently is, to publish a new version of MOTR.</li>
<li>Monday: I wrote up hundreds of documentation stubs for MOTR.</li>
</ul>
<p>Next week, I'm going to get back into the poetry stuff for a few days, and work on refining the design for the high-level abstractions I'm designing for MOTR.</p>
Coding 2021-09-272021-09-27T04:00:00-04:002021-09-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-27:/coding-2021-09-27<p class="first last">"This is the Foo class. It is a class that foos."</p>
<p>All right.
Everything that I got flake8 to complain about not being documented, is now documented.
The documentation isn't particularly <em>good</em>, but it's <em>there</em>, and it's ready to be processed by Sphinx.
I'm not ready to hook Sphinx up yet, so now I'm back to making changes to the motrfile.</p>
<p>Right at the moment, I'm cleaning up the requirements files in various ways.
I removed a few unneeded requirements, and some obsolete extras requirements.
I've written a small constraints file based on the few version locks I did.
The steps to change next are:</p>
<ul class="simple">
<li>Wire the constraints file everywhere in the motrfile.
That means using it explicitly in everything that doesn't use the generated constraints file, and using <tt class="docutils literal"><span class="pre">-c</span></tt> to include it in the generated constraints file.</li>
<li>Remove the version locks from the requirements file, and check that the locked versions are still installed.</li>
<li>Create the classes that I've designed to represent parts of command lines.</li>
<li>Allow the existing environment functions to take instances of those classes.
This will take some work updating interfaces, because the new classes bundle together relevant information like "what do you want to do on the command line" and "what do you need to install to do that thing".</li>
</ul>
<p>Looking over the file, I think the proper order for the last two is:</p>
<ul class="simple">
<li>Implement the classes</li>
<li>Create the necessary helpers for flit and pyproject</li>
<li>Update the <em>new</em> environment code to take the new classes</li>
<li>So how that works out for me</li>
</ul>
<p>Once that's done, I can start working on creating helpers for the other commands, and do migrations as I finish them.</p>
<p>I don't really have a lot of focus left for this right now, so I'm going to wrap up early and zone out a bit.</p>
<p>Good night.</p>
Coding 2021-09-262021-09-26T04:00:00-04:002021-09-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-26:/coding-2021-09-26<p class="first last">This is not a one-step process.</p>
<p>I took care of the first bullet point from earlier, and now I want to cut a new release.
This turns out to be harder than it should be, so I'm going to try to document all of the steps in an attempt to get it all to make sense.</p>
<p>So, I need to get a bunch of things done in the right order, which I haven't fully figured out.</p>
<ul class="simple">
<li>The release tag needs to be updated. Right now, I want this to be the last thing I do before I build the release. I appear to have forgotten to do this at least once.</li>
<li>I need to update the version field in the <tt class="docutils literal">__init__.py</tt>.</li>
<li>I need to run <tt class="docutils literal">towncrier build</tt>. I'm having troubles with this giving me the wrong version, so I need to look into how that works.</li>
<li><tt class="docutils literal">flit build</tt> and <tt class="docutils literal">flit publish</tt>. I need to look up how to store my credentials for the publish step.</li>
</ul>
<p>For the flit thing, I just installed <tt class="docutils literal">keyring</tt>, and hopefully that will help.
Now, let's take a look at how <tt class="docutils literal">towncrier</tt> works...
Okay, because I'm running MOTR on itself, I guess the sequence is:</p>
<ul class="simple">
<li>Update the version field.</li>
<li>Install the newest version (because towncrier is doing an import in preference to inspecting the filesystem).</li>
<li>Run <tt class="docutils literal">towncrier</tt>.</li>
<li>Tag the release.</li>
<li>Run <tt class="docutils literal">flit</tt>.</li>
</ul>
<p>Let's try that.
I've already updated, so let's see...</p>
<p><tt class="docutils literal">hg st</tt>...
Clean.</p>
<p><tt class="docutils literal">pip install .</tt>
Worked.</p>
<p><tt class="docutils literal">towncrier build</tt>
Worked as desired.</p>
<p><tt class="docutils literal">hg tag v0.1.4</tt>
Something would have been pretty wrong if that failed.</p>
<p><tt class="docutils literal">flit build</tt>
All set.</p>
<p><tt class="docutils literal">flit publish</tt>
And keyring worked, so that'll be convenient.</p>
<p>Well, then.
That's too many steps.
And I didn't even realize I was supposed to <em>do</em> one of them.
Let's try to fill it all in...</p>
<ul class="simple">
<li><tt class="docutils literal">nvim src/motr/_init__.py</tt> Needs something better</li>
<li><tt class="docutils literal">hg commit</tt></li>
<li><tt class="docutils literal">pip install .</tt></li>
<li><tt class="docutils literal">towncrier build <span class="pre">--yes</span></tt></li>
<li><tt class="docutils literal">hg commit</tt></li>
<li><tt class="docutils literal">hg tag v<tag></tt></li>
<li><tt class="docutils literal">flit build</tt></li>
<li><tt class="docutils literal">flit publish</tt></li>
</ul>
<p>Right now, I'm not sure how I want to consolidate all that together, so I'm going to put that off until tomorrow.
For now, I'm going to install <tt class="docutils literal"><span class="pre">flake8-docstrings</span></tt> and see what kind of carnage that unleashes.
180 violations.
Sounds about right.</p>
<p>I'll publish this post, and then try to fix some of these violations.</p>
<p>Good night.</p>
Coding 2021-09-252021-09-25T04:00:00-04:002021-09-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-25:/coding-2021-09-25<p class="first last">The attribute name doesn't make sense any more, but I can't fix that yet.</p>
<p>I wrote a bit more poetry, then focused on improving MOTR.
Before anything else, I made <tt class="docutils literal">Input</tt> and <tt class="docutils literal">Output</tt> generic, and put some convenience methods for manipulating iterables of them into their module.
I reworked the <tt class="docutils literal">cmd</tt> module to use this new stuff, which is just complex enough that I need to give the type system a little boost to get it going.</p>
<p>The next step is going to be reworking the <tt class="docutils literal">*inputs</tt> argument into something like <tt class="docutils literal">*io</tt>, which is going to be interesting because, once I build and locally install a new version, the motrfile will be broken until I fix it.</p>
<p>Actually, speaking of the motrfile, I just remembered something else that I'm wondering if it works...
Ah, not worth trying right now.
Basically, I'd like to see if <tt class="docutils literal">importlib</tt> can replace the weird dance I'm doing right now to execute the motrfile, and it <em>probably</em> can, I just need to put in a bunch of time to redo the error wrapping, and it's too late at night for that right now.</p>
<p>I'll get back to work on improving the <tt class="docutils literal">cmd</tt> helper, which is a bit harder because it's not a simple refactor.
Hopefully I'll have time to make some of the more interesting changes I have in mind.</p>
<p>Anyway, I should wrap up now.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-09-242021-09-24T04:00:00-04:002021-09-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-24:/worldbuilding-ksa-2021-09-24<p class="first last">"The word 'should've' can have one syllable if I <em>truly believe</em>, right?"</p>
<p>Like eight more stanzas done.
At this point, I'm <em>definitely</em> at least halfway done.
I think.</p>
<p>I'm making progress for sure, but it's still such a slog.</p>
<p>And, once again, I'm too wiped out to write much <em>about</em> what I've written.
I'm really itching to turn my focus to MOTR.
I've got a pretty solid idea of the kinds of challenges I need to deal with to move forward.</p>
<p>Anyway, it's late, and I will regret it <em>a lot</em> if I don't call this post now.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-09-232021-09-23T04:00:00-04:002021-09-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-23:/worldbuilding-ksa-2021-09-23<p class="first last">Three more of these ground out.</p>
<p>I ended last night trying to figure out how to complete a rhyme.
I ended tonight trying to figure out how to complete a rhyme.
The difference is, it's a few stanzas later.</p>
<p>As long as I'm working through the outline, I'm making progress.
It's just... kind of unpleasant, sometimes.
Maybe a lot of the time.</p>
<p>I feel like I've dug myself into a hole somewhat, blog-content-wise.
Because I can't just post the stuff I've been writing.
It's rough-draft quality, which I admit doesn't stop me from putting up most of my posts, but, I don't have a good counter-argument to the point I brought up.
Still not doing it, though.</p>
<p>I think I'm at least halfway through, currently.
I mean, let's see, that's 18 stanzas so far, rounding up.</p>
<p>At least 6 stanzas for the fight, and it would kind of surprise me if the aftermath took even 10...
I could be completely wrong about that, though.</p>
<p>This may end up lacking a certain punchiness next to the outline, but whatever.
If there's material to shave off, that's happening after I finish the draft.</p>
<p>Anyway, I'm going to regret it if I think too much more about the post, so let's wrap it up abruptly.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-09-222021-09-22T04:00:00-04:002021-09-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-22:/worldbuilding-ksa-2021-09-22<p class="first last">Restrictions breed creativity</p>
<p>Got about two stanzas written.
I've just got to fill up the outline, and then that's the draft done.
Just a little bit each day.</p>
<p>I don't remember if I explained what the hook is, so I'm going to do that now.</p>
<p>The first thing I wrote for the setting document for <em>Korín, Sorín, and Arín</em> was a very high-level description of its ridiculous cosmology.
It was very boring.</p>
<p>After some discussion, I decided that the thing to lead with was some in-universe art, that highlighted some of the setting details.
Part of the reason there is that, of all of the things unique to this setting, I think art is the most obviously interesting thing to show other people.
The various implications of the magic system are interesting and all, but a description of them is itself a kind of art, just more dry and technical than I'd personally like to put out.
What's going on there is, to engage with such material, you kind of have to accept some hypotheticals that remove it from your experience.
Thinking about the implications of magic for agriculture doesn't relate in any way to your life, but if you're consuming a song, poem, book, painting, etc, then you are <em>actually consuming that art in your own life</em>.</p>
<p>The fact that this is more engaging, I think, than basically an atlas of a place you can't actually visit, has me hopeful that it'll be a better introduction to the setting.</p>
<p>So, what it actually is, is a song about two brothers.
One of them becomes evil, and the other one has to kill him, for the good of everyone around them.
Lots of dramatic proclamations, and battles, and crying.
And gods, and dragons.</p>
<p>One thing I'm liking about it so far is that the combination of in-universe narrator and metrical constraints basically forbids me from over-explaining things.
So I'm all like "Well, I can write up a detailed explanation of what dragons look like, and do, in this setting, but everyone in the notional audience knows that and it would translate into very quantifiable bloat, as the number of stanzas grows for no good reason."
I don't think I could handle doing anything really longform in verse, but I think it really helps where it makes sense.</p>
<p>Anyway, I spent a good amount of time writing this up, and now I'm tired.</p>
<p>Good night.</p>
Weekly Roundup 2021-09-212021-09-21T04:00:00-04:002021-09-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-21:/weekly-roundup-2021-09-21<p class="first last">I made progress, but I'm not really feeling momentum from it.</p>
<ul class="simple">
<li>Wednesday: I went into more direct detail about the <em>Korín, Sorín, and Arín</em> setting.</li>
<li>Thursday: I had problems working on material for <em>Korín, Sorín, and Arín</em>, which I solved, apparently by complaining about them.</li>
<li>Friday: I made some more progress on the material, and kind of tired myself out before I could write much <em>about</em> my progress.</li>
<li>Saturday: I didn't work on <em>Korín, Sorín, and Arín</em> or MOTR, but I did some thinking <em>about</em> MOTR, and why I'd rather keep on developing it, than switch to what I think of as the major alternatives.</li>
<li>Sunday: I started working on MOTR some more, given a few days worth of notes.</li>
<li>Monday: I realized that the natural way to handle the high-level abstractions for MOTR doesn't match up with the projects I want to use it with; the projects will have to change.</li>
</ul>
<p>Next week, I'm going to try to get back to <em>Korín, Sorín, and Arín</em> for a bit, while taking notes on some high-level concepts I need to nail down for MOTR.</p>
Coding 2021-09-202021-09-20T04:00:00-04:002021-09-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-20:/coding-2021-09-20<p class="first last">Figuring out how to make this more reasonable for other people to use.</p>
<p>Right now, I'm pondering a change in my project structure.
Basically, when I was basically propagating my tooling by mass copy/paste, it more-or-less made sense to encode a bunch of ideas about "here's how to do things" in data files that aren't part of any explicit configuration.</p>
<p>To be more specific:
In a lot of my projects, I have a top-level <tt class="docutils literal">requirements</tt> directory that contains several <tt class="docutils literal">requirements.txt</tt>-type files, meant to be installed in specific circumstances.
But I just checked, and most of them are only like that in some kind of attempt to "streamline" the noxfile, so I can replace "install this and this" with a single filename.</p>
<p>Now, this is a bad fit for the paradigm I'm aiming for with MOTR, because the high-level abstractions I'm writing are connecting an installation task to a script that they expect the task to make available.
In effect, this is asking any consumers to put a file in a specific place, and also put specific things in that file.
In the majority of cases, the onus to do all of this could be entirely removed by just putting the requirement data into the code, and expecting any project-specific fine-tuning to be in a <tt class="docutils literal">constraints.txt</tt> file.
In the remainder of cases, the required work could be somewhat diminished.
These cases are when there are additional plugins that can be installed to augment the functionality of a script.
I mainly have this use case for running <a class="reference external" href="https://flake8.pycqa.org/">flake8</a>, maybe <a class="reference external" href="https://mypy.readthedocs.io/">mypy</a>, and sometimes <a class="reference external" href="https://docs.pytest.org/">pytest</a>.</p>
<p>So, here's what I think I'm leaning towards:</p>
<ul class="simple">
<li>The user can provide a top-level <tt class="docutils literal">constraints.txt</tt> file that covers most details of version/source to install.</li>
<li>The build step generates an additional <tt class="docutils literal">constraints.txt</tt> file that references the user-provided file, if given.</li>
<li>In addition to the package name, the environment creation flow can take a path to a supplementary <tt class="docutils literal">requirements.txt</tt> file, relative to the root. This file <em>does not need</em> to specify the base package name, but doing so shouldn't hurt anything.</li>
</ul>
<p>Now, an additional thing I'll need to work on is plugin code that requires command line arguments.
I can't gloss over that, which means that some of this is going to live in code rather than as requirements files.</p>
<p>Let's see what that looks like:</p>
<ul class="simple">
<li>flake8-isort needs code-level support</li>
<li>as does flake8-html</li>
<li>The <tt class="docutils literal"><span class="pre">--html-report</span></tt> flag for mypy needs code-level support.</li>
</ul>
<p>Thinking over this, here's what I think makes sense:</p>
<ul class="simple">
<li>Make the <tt class="docutils literal">Input</tt> and <tt class="docutils literal">Output</tt> classes more flexible in what they can contain, and allow specifying both in the freeform section of the <tt class="docutils literal">cmd</tt> helper function.</li>
<li>Cut a new release so I can confirm that this simplifies writing the higher-level abstractions.</li>
<li>Remove some hackery from the <tt class="docutils literal">cmd</tt> function.</li>
<li>Cut another new release to confirm that didn't break anything. (I may be able to condense these into one release.)</li>
<li>Write initial documentation of everything, since there's about to be <em>a lot</em> more code in there.</li>
<li>Outline and fill out the new <tt class="docutils literal">constraints.txt</tt> way of doing things.</li>
<li>Migrate the motrfile from the old to the new way, including deleting the old code.</li>
<li>Start pulling code from the motrfile into MOTR.</li>
<li>Figure out how I want to organize the different abstractions in the <tt class="docutils literal">api</tt> module.</li>
</ul>
<p>Good night.</p>
Coding 2021-09-192021-09-19T04:00:00-04:002021-09-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-19:/coding-2021-09-19<p class="first last">Come work on MOTR! We have: inscrutable errors!</p>
<p>I spent a good portion of last week writing up thoughts on how to improve my prototype motrfile, before I start moving more stuff into MOTR proper.</p>
<p>Today, I put some of those notes into practice, which was mainly focused on putting together a wrapper around the <a class="reference external" href="https://virtualenv.pypa.io/">virtualenv</a> package to replace the wrapper around the stdlib <a class="reference external" href="https://docs.python.org/3/library/venv.html">venv</a> module.
This is mainly important because I want to support multi-version testing, and specifically pypy2.
I haven't looked at all into how to attain the speed benefits that are supposed to be possible.</p>
<p>Where I'm at now is, I have a basic implementation of the virtualenv wrapper, more-or-less according to my notes.
Now, I need to kind of iterate on things until I'm using a proper combination of virtualenv and <a class="reference external" href="https://pypa-build.readthedocs.io/">pyproject-build</a>, at which point I should be able to ditch the wrappers for venv and <a class="reference external" href="https://flit.readthedocs.io/">Flit</a>.
Actually getting there will be interesting, because I'm going to want to write actions for generating configuration files for <a class="reference external" href="https://docs.pytest.org/">pytest</a> and <a class="reference external" href="https://coverage.readthedocs.io/">coverage.py</a>.
(And later, <a class="reference external" href="https://mypy.readthedocs.io/">mypy</a>, I think, once I have mutation testing.)</p>
<p>Anyway, I think carrying this out is going to take another high-level look at the code.</p>
<p>Which is going to happen tomorrow, not tonight, because I am <em>exhausted</em>.</p>
<p>Good night.</p>
Diary 2021-09-182021-09-18T04:00:00-04:002021-09-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-18:/diary-2021-09-18<p class="first last">Remember when I worked on stuff besides tooling for the stuff I want to be working on?</p>
<p>I thought I was going to have a chance to work on the hook for Korín, or put the notes I've been taking on MOTR into practice, but I guess I was too busy relaxing and I let time get away from me.</p>
<p>I'm really itching to get MOTR into a good enough state that I feel comfortable using it for other projects, because I feel a bit like I've let, if not the perfect, at least the better*, be the enemy of the good here.
I think a good amount of sustained effort would get me there, but I don't know when I'll have the time to put all that effort in.</p>
<p>*This judgement has to be understood in the context of my motrfile being an evolution of my noxfile template.
I prefer Nox to tox because I prefer Python to INI as a host language, but this loses me the potential for concurrency.
Now, Nox has a barrier to adding concurrency, in that it tries to provide streaming output.
<em>But</em>, my pytest failures have a tendency to generate such monstrous spews of output that there's no point in reading them from the terminal.
So, MOTR sacrifices streaming output in order to obtain concurrency by default, without sacrificing quality of host language.
It also provides means of selecting tasks that make more sense to me than how Nox and tox handle it.</p>
<p>(At some point after I stopped paying attention to tox, it introduced a <tt class="docutils literal">dependency</tt> field, which <em>enforces an ordering of all selected environments</em>, which means you still need to know <em>which environments to select</em>.
Also, I found I prefer to think of dependencies in terms of <em>what a task provides and needs</em> rather than "do this before this because of reasons".)</p>
<p>Time will tell if I end up wanting some more expressive means of specifying targets.
My thinking, or rather hope, is that if just running everything is fast enough, then there's no need to get really fine-grained with the requirements.
Unfortunately, it's kind of hard to tell if there's any way to make the current code much faster, since if I profile the main thread, the vast majority of the runtime is spent polling IO-bound tasks.</p>
<p>I guess I just need to put in the work to make this all work in general.</p>
<p>Anyway, it's later than I though, and I don't want to put off sleeping any longer.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-09-172021-09-17T04:00:00-04:002021-09-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-17:/worldbuilding-ksa-2021-09-17<p class="first last">Me: "Boy, some of these old poets were A Lot." Also me: *rhymes "dedication" and "reconsecration"*</p>
<p>Several stanzas later, and I'm starting to doubt my ability to come up with sentences in English.</p>
<p>I wasn't paying attention to just how much I wrote, but it's both not much in terms of raw words, and decent progress along the outline.
The main thing that makes this kind of bittersweet is, I'm pretty sure I'm going to hate most of this when I finally get to my first editing pass.
Just going to be constantly, like, reading one line, and then covering the page with notes and correction marks.</p>
<p>But yeah, it feels like doing that used up enough of my... writing... juice?... that I can't muster the mental acuity to actually describe what I did in any more detail.</p>
<p>So, instead of a short post because I didn't put any effort towards the stuff I want to write about, it's a short post because I put in <em>a lot</em> of effort (too much?), and I don't have any left.
I guess that's better?</p>
<p>Anyway, my body is telling me to go to bed, and I'm going to listen.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-09-162021-09-16T04:00:00-04:002021-09-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-16:/worldbuilding-ksa-2021-09-16<p class="first last">I manage to psych myself into doing something by writing about how I don't know how to do it. Whatever works, right?</p>
<p>All right, I want to take the hook from outline to actual poem.
And so, I just need to, like, <em>do it</em>, right?
Just need to, make the thing, like, <em>happen</em>.</p>
<p>It's like I'm playing a text parser adventure game, and <em>I don't know the right verb</em>.</p>
<p>I <em>hate</em> this.</p>
<p>I'm going to hope that the problem is with writing poetry in general, and that maybe I can get better at this process by trying to write something less ambitious to start with.
Smaller overall scope.</p>
<p>Okay, actually researching "how do I write poems" helped a bit with the hook.
(I mean, English classes covered this some, but that was over a decade ago.)</p>
<p>I'm, actually not totally sure what I'm doing with this first stanza.
Four lines, nine syllables each, ABAB rhyme scheme, and the stress is <em>mostly</em> dactylic trimeter.
(Or maybe it's dactylic hexameter with internal rhymes?)
Whatever, if I can keep this up, I'm good.</p>
<p>Okay, I've written, like, three and a half-ish stanzas, and I'm ready for a break.</p>
<p>One thing I'm worried about is handling the transitions between scenes.
Maybe I need to jam another stanza in the middle of what I have so far?</p>
<p>I'll have to work on it later, and do some other research.
For now, break.
I'm going to get ready for bed, and see what I can squeeze in around it.</p>
<p>Good night.</p>
Worldbuilding — Korín, Sorín, and Arín 2021-09-152021-09-15T04:00:00-04:002021-09-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-15:/worldbuilding-ksa-2021-09-15<p class="first last">The grand debut of a setting I've, um, already talked about.</p>
<p>All right, I've got enough of a grasp on "things to direct worldbuilding for this setting" that now I'm comfortable with giving it a category.
The setting is called Korín, Sorín, and Arín, and those are the names I'm using for its analogues of the Earth, Moon, and Sun.</p>
<p>To recap, I've been gradually developing the idea for this setting for a while.
The quote-unquote original point of all this was to provide a setting that would allow me to direct and contextualize the development of a conlang.
Which, um, oops, I'm <em>several</em> yaks away from that at this point.
I do want to give that conlang its due at some point, but right now I want to work on the scaffolding of the setting.</p>
<p>And the strategy that I'm taking to develop that scaffolding, is to try to worldbuild just enough for a barebones-feeling roleplaying setting, and then bootstrap it from there by learning to GM and running games in it.
And for that, I need:</p>
<ul class="simple">
<li>A hook that establishes some of the features of the setting, and hints at the kinds of things that a character could do, interact with, or fight with.</li>
<li>A god's-eye view of the setting, establishing the basic details of stuff like "here are the continents you can do stuff on".</li>
<li>For each general category of playable character, a description of what they do, what they can look like.</li>
<li>A <em>limited</em> selection of places to play and general sketch of demographics.</li>
</ul>
<p>This is probably more than I <em>should</em> be planning to do, but I've sunk so much of this cost already.</p>
<p>Here's where I am so far:</p>
<ul class="simple">
<li>The god's-eye view is <em>painfully</em> dull prose right now.
It's too bad I'm not enjoying my own authorial voice there, because I'm the only person I could imagine liking this, and I... don't.</li>
<li>I've outlined the hook, which is going to be my main focus for elaborating on setting details.
If I need it for the hook, it goes in.
If I don't need it for the hook, I'm going to try <em>really hard</em> to put it on the backlog.</li>
<li>I have notes on all of the character design guidelines, which I'll work on putting into a usable form once the hook is firmed up.</li>
<li>I have notes that <em>could</em> feed into the selection of places to play, but it would be best to focus my initial efforts there based on feedback from other people.</li>
</ul>
<p>Anyway, I'm trying to remember if I forgot to do anything today, because I'm doing much better on time than I'm used to doing.
Unless I think of something and go "oh no!" I'm going to take some notes on MOTR after I publish this.</p>
<p>It's a bit early now, as I said, but I'd rather take the win there, than try to wring more out of the next hour or so.</p>
<p>Good night.</p>
Weekly Roundup 2021-09-142021-09-14T04:00:00-04:002021-09-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-14:/weekly-roundup-2021-09-14<p class="first last">I don't want this to get me too far down, but I definitely shouldn't be hard on myself if I go that way...</p>
<ul class="simple">
<li>Wednesday: I cut out functionality from MOTR, to make it easier to extend.</li>
<li>Thursday: I made some improvements to MOTR. I don't think they were anything big.</li>
<li>Friday: I made a little progress on worldbuilding.</li>
<li>Saturday: I tried to figure out what kind of limits I wanted to put on magic in this setting.</li>
<li>Sunday: I ran into deeply weird problems hacking on MOTR.</li>
<li>Monday: I made some proper progress updating the motrfile, but I also took some time to identify a bunch of the problems I'd had with similar code in the past.</li>
</ul>
<p>Next week, I don't know how much I'm really going to get done.
I found out some really heavy family news earlier today, and I don't know how I'm going to process it yet.
I think I'll do better focusing once I've got some plans nailed down, but for now, I'm going to take things easy.</p>
Coding 2021-09-132021-09-13T04:00:00-04:002021-09-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-13:/coding-2021-09-13<p class="first last">Doing code archeology to figure out how obscure the bugs I was hitting were.</p>
<p>Okay, after I posted last night, I got the isolated environment of <tt class="docutils literal"><span class="pre">pyproject-build</span></tt> <em>probably</em> working.
The next step is to allow the pip-related functionality to handle environment variables.
This is because I kind of don't trust the result of passing constraint files on the command line, even though it's <em>probably</em> fine.
It's been a while since doing that bit me, and a lot has changed.
I think the bug I filed is still open, though.</p>
<p>So, I'm passing in an environment, and that's getting processed by the <tt class="docutils literal">cmd</tt> function, which will handle <tt class="docutils literal">Input</tt> instances...
That means I can just hardcode the environment variables in a global dictionary for now.
When I was looking over one of my noxfiles to get environment-related data, I noticed that I'm also setting <tt class="docutils literal">"PIP_NO_CACHE_DIR": "YES"</tt>.
My vague recollection is that this was to deal with local packages sometimes not updating, but it looks like that was maybe an sdist issue?
I certainly haven't encountered it using wheels, so I don't think I need it.
(The "specify it as an environment variable" thing may have <em>also</em> been an artifact of using sdists?)
(Did I only need to use sdists because of some flit-related behavior that has since apparently changed?
<a class="reference external" href="https://flit.readthedocs.io/en/latest/history.html#version-3-0">There we go, yes.</a>
Okay, wait, I think I was using sdists <em>indirectly</em>, because I was pointing pip at a directory rather than at a file?
Well, there are so many reasons not to want to go back to that.)</p>
<p>Anyway, back to what I need to work on now.
I've somewhat solidified the classes I need for this to work, and now it's a question of tracking down the various usages and updating then to work with a <tt class="docutils literal">SinglePythonPackage</tt>, then writing an adaptor that dispatches over a <tt class="docutils literal">MultiPythonPackage</tt>, which is almost, but not quite, just a sequence of <tt class="docutils literal">SinglePythonPackage</tt>s.
I also need to generate the <tt class="docutils literal">MultiPythonPackage</tt> for the MOTR project.
That can be handled for now by just hardcoding a reference to the current directory.</p>
<p>I don't know when I'll be up for working on that.
I kind of don't like working on this during the week, and I'm starting to make some real progress on the setting document.
Anyway, none of that's going to happen right now, because I need to wrap up and get to bed.</p>
<p>Good night.</p>
Coding 2021-09-122021-09-12T04:00:00-04:002021-09-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-12:/coding-2021-09-12<p class="first last">This post was delayed thanks to: <em>something</em> in my Neovim install or environment that jacked up the file recovery process somehow.</p>
<p>All right, I made some improvements and changes to MOTR's motrfile.
<em>Unfortunately</em>, I'm going to have to roll one of the changes back.
I <em>thought</em> "Oh, I can just make MOTR require <tt class="docutils literal"><span class="pre">pyproject-build</span></tt> and not need a venv for that," but <em>no</em>.
It couldn't be that easy.
Somehow that causes the test environments to try to install <em>apparently every version of pytest</em>.
This shouldn't be a problem for end users, but it means I can't run my own tests.</p>
<p>That means I need to reintroduce the path field, and... let's see...
I don't feel like figuring out the right way to do the installation, so I'm just leaving it pretty much as-is for now.</p>
<p>I also fixed up some type errors in the motrfile that weren't really affecting anything, but they made the output kind of obnoxious to read.</p>
<p>The two big things I want to focus on are: putting together the files I need to to handle installing <tt class="docutils literal"><span class="pre">pyproject-build</span></tt> in an isolated environment, because apparently that's something I need to do, and getting the rest of the functions to work with a combination of requirements file and constraints file, instead of just requirements file.
Because I'm working on the <tt class="docutils literal">Package</tt> code in tandem with the <tt class="docutils literal"><span class="pre">pyproject-build</span></tt> update, that'll get the code in the motrfile closer to ready for integration into MOTR.</p>
<p>I'm about done for the night, so I'll get all the thinking for this done tomorrow.
For now, I should get ready for bed.</p>
<p>Good night.</p>
Diary 2021-09-112021-09-11T04:00:00-04:002021-09-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-11:/diary-2021-09-11<p class="first last">"Most people can learn how to kill someone barehanded, but it's not really practical, so this doesn't change much."</p>
<p>Worldbuilding status: I'm trying to figure out how I want really widespread access to magic to have affected the setting.
There are basically a few knobs that I'm adjusting here:</p>
<ul class="simple">
<li>Scope of effect (stuff like conjuring objects is generally out of reach)</li>
<li>Range of effect (anything that's effectively an extension to reach or sensory range is rare or difficult)</li>
<li>Availability of magic (technically, anyone can learn any kind of magic; if I locked this <em>all</em> the way down, it would break some of the setting, so I guess I just took it all the way in the opposite direction)</li>
</ul>
<p>What I basically want to get to is a scenario where the existence of magic has obvious, logical effects, but it's reasonable to apply high-level concepts from our own history to the broad strokes.</p>
<p>I guess the sensible thing to do now is to try to work in the other direction, given a few of the other notes I've taken.</p>
<p>The thing that always gets me worried about my worldbuilding efforts is, what if I come up with some stuff that has a particular logical consequence, but I miss that, and come up with something else that isn't compatible with that logical consequence.</p>
<p>Maybe I just need to lighten up about that.
It's not like anyone can send me to <a class="reference external" href="https://www.youtube.com/watch?v=X7LOoWdbSco">liar's jail</a> over it.</p>
<p>Anyway, I'm hoping to make some real progress on MOTR in the next few days.
See you then.</p>
<p>Good night.</p>
Diary 2021-09-102021-09-10T04:00:00-04:002021-09-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-10:/diary-2021-09-10<p class="first last">I mean, it'd be weird to have Clydesdales without a Clydesdale.</p>
<p>Back to worldbuilding stuff.
I'm focusing on outlining a short, simple narrative that covers a bunch of the basic ideas I've worked out.
Unfortunately, the experience is so like pulling teeth that, after I wrote a paragraph-long outline, I'm now all "Okay, that's enough for now".</p>
<p>I wanted to come up with something else to say about this, but I'm feeling a little on-edge right now as a result of stuff I don't want to put in this entry.</p>
<p>Anyway, besides that, I was considering some other aspects of the worldbuilding.
The setting has kind of a mythic-scale history that means I want to generally ignore anything but the broad strokes of its history beyond a few thousand years before the "present".
I don't really feel value <em>for this setting</em> in coming up with elaborate alternative flora and fauna, especially since humans are already a thing in the setting.
At the same time, I don't want to have very specific forms of animal, plant, (fungus?) showing up.
So, there are horses, but rather than having, say, Clydesdales show up, I want to have breeds based on the needs and aesthetics of regions in the setting.
All that said, I do think it would be worth having some animals and plants show up with no obvious Earth analogue, but <em>in general</em>...</p>
<p>Anyway, that's enough for now.
I'm going to wrap up and get to bed soon.</p>
<p>Good night.</p>
Coding 2021-09-092021-09-09T04:00:00-04:002021-09-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-09:/coding-2021-09-09<p class="first last">It's kind of hard to read the output from the nameless-actions version of MOTR, but, like, oh well.</p>
<p>I just kind of poked at MOTR's code today.
I made some minor fixes to the dead code inside the motrfile, and slightly rearranged the imports in the main package.
I still need to decide how to rewrite those imports, but "divide imports into 'used at runtime' and 'only used in annotations'" feels like a start.</p>
<p>The big thing I should work on is the <tt class="docutils literal"><span class="pre">pyproject-build</span></tt> invocation class, and its support structure.
Once I work out how all of that should work together, I can transition to the <tt class="docutils literal">Package</tt> paradigm, and focus on bringing existing motrfile code into it.
Once that's done, I can move onto <tt class="docutils literal">Platform</tt>.</p>
<p>There's a chance I would have gotten more done with this if the fire alarm hadn't gone off for no good reason and around twenty minutes.</p>
<p>Anyway, I think the thing to do is to take a break from coding for a few days, and really try to write stuff for the worldbuilding doc.</p>
<p>I'm going to wrap up now and play Monster's Expedition for a bit.
That game is complicated, it's great.</p>
<p>Good night.</p>
Coding 2021-09-082021-09-08T04:00:00-04:002021-09-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-08:/coding-2021-09-08<p class="first last">I have no idea what <tt class="docutils literal">flit build</tt> was doing when I had uncommitted work, but I extremely did not like it, and it makes me wonder if I can trust <tt class="docutils literal">flit build</tt> output in general during development. (Maybe it was because I wasn't bothering to pass <tt class="docutils literal"><span class="pre">--wheel</span></tt>, so it was making the wheel from the sdist instead of directly? Eugh.)</p>
<p>Okay.
I've updated MOTR and pushed a version that has some problems, but it works.
This also dragged along some half-finished and broken code in the motrfile, but it's dead code and this is pre-1.0, so I don't care too much about that yet.</p>
<p>Basically, I've cut down on the external logging for now, in order to avoid naming the output files.
This is making the output kind of cluttered, but I can live with that for now, and work on writing pretty-printing code later.</p>
<p>Working on the code like this made realize that there are a few areas I want to focus on:</p>
<ul class="simple">
<li>See if I can eliminate or cut down on imports that are only used in annotations.</li>
<li>Rewrite the remaining imports in some fashion, because I'm finally not liking the whole "import everything by its full path" thing.</li>
<li>Investigate passing <tt class="docutils literal">Output</tt> objects into the <tt class="docutils literal">cmd</tt> function.
This would let me avoid some type system weirdness that I patched in in desperation.</li>
<li>Define exactly what's supposed to be in the sdist.
<tt class="docutils literal">flit build</tt> gets nearly everything, and <tt class="docutils literal"><span class="pre">pyproject-build</span></tt> gets a pretty minimal set.
I think the thing to do is figure out how to build up what <tt class="docutils literal"><span class="pre">pyproject-build</span></tt> gets, and look into switching to it for general usage.
This makes sense since I want to use <tt class="docutils literal"><span class="pre">pyproject-build</span></tt> in the motrfile, so I might as well also use it in the publishing workflow.</li>
</ul>
<p>I <em>should</em> also be focusing more on the <tt class="docutils literal"><span class="pre">pyproject-build</span></tt> <tt class="docutils literal">Action</tt>, and writing code to deal with the <tt class="docutils literal">Package</tt> classes that are currently half-baked at best.
Anyway, I want to wind down now.</p>
<p>Good night.</p>
Weekly Roundup 2021-09-072021-09-07T04:00:00-04:002021-09-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-07:/weekly-roundup-2021-09-07<p class="first last">A little bit slower work than I would have liked, but there was some stuff in there where I needed to be methodical.</p>
<ul class="simple">
<li>Wednesday: I started working out the precise effects of wedging my existing project structure into MOTR's current workflow assumptions.</li>
<li>Thursday: I found out that some of the optimizations I wanted to make, do not actually work, and there are documentation bugs against Python about how it should be more obvious that they don't work.</li>
<li>Friday: I worked on worldbuilding, and by "worked on worldbuilding" I mean "wrestled with the documentation software to get the behavior I want".</li>
<li>Saturday: I worked on worldbuilding, and by "worked on worldbuilding" I mean "took some notes on how to make the presentation more interesting".</li>
<li>Sunday: I walked through my noxfile for another project, and took notes on what the internal logic would look like as a motrfile.</li>
<li>Monday: I started trying to put some of my plans for MOTR into practice, noticed an issue that I'm having with it, and then ran into more issues trying to solve that issue.</li>
</ul>
<p>Next week, I've got a plan for a good-enough approach to all of that, and we'll have to see how it shakes out in practice.
It'll take a bit of work to migrate over to the new system.
I also want to try and force myself to work on the worldbuilding a little, but we'll see how that goes.</p>
Coding 2021-09-062021-09-06T04:00:00-04:002021-09-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-06:/coding-2021-09-06<p class="first last">"I cannot think of any problems with this. [shortly thereafter] I have found a problem."</p>
<p>Doing time.
Wait, no...
Eh.</p>
<p>Anyway, I started adding the basic types that I determined I'll need.
Then I added a utility function that I'll definitely want to put into the MOTR app sooner than later.
But that utility function raised a question for me that I want to look into sooner than later:</p>
<p>Since I'm using attr's dataclasses to define all of my <tt class="docutils literal">Action</tt> implementations, is it worth coming up with a separate name like I am currently?
When it comes to reporting them, can I get by with some form of pretty-printing?</p>
<p>Looking into the first question...</p>
<p>Popping open <tt class="docutils literal">motr.core.registry</tt>...</p>
<p>The main things that would need to change are the <tt class="docutils literal">Action</tt> class in there would stop existing, as well as the <tt class="docutils literal">ActionName</tt> class.
This changes the following attributes and methods on <tt class="docutils literal">Registry</tt>:</p>
<ul class="simple">
<li><tt class="docutils literal">_actions</tt></li>
<li><tt class="docutils literal">_parent_action</tt></li>
<li><tt class="docutils literal">_last_added</tt></li>
<li><tt class="docutils literal">action()</tt></li>
<li><tt class="docutils literal">inputs()</tt></li>
<li><tt class="docutils literal">parent()</tt></li>
<li>Some of the methods used to handle dispatch from <tt class="docutils literal">require()</tt>.</li>
</ul>
<p>I think the thing to do is just to try it, because I'm not seeing all of the consequences, and I've got source control.</p>
<p><tt class="docutils literal">log_dir = self.target.log_dir / self.action_name</tt></p>
<p>Ah.
Right.</p>
<p>I'm going to need to think about the best way to deal with that.
I'll just leave this as-is for tonight, and see if I come up with anything in the next week.
(I mean, I suppose if I'm lazy, I could use the id and just include that in the output, but that's <em>really</em> lazy...)</p>
<p>Anyway, I'm going to wind down now.</p>
<p>Good night.</p>
Coding 2021-09-052021-09-05T04:00:00-04:002021-09-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-05:/coding-2021-09-05<p class="first last">This does involve a bunch more I/O than the noxfile, but I don't think it's a perceptible difference.</p>
<p>Planning time.</p>
<p>All right, let's trace the data flows that the current interface to MOTR would require for some of my other noxfiles.</p>
<p>The first thing it all needs is to gather the package information.
Let's gloss over that.</p>
<p>So...</p>
<ul class="simple">
<li>Given all of the package roots, build the packages, and write a constraint and per-package requirements files.</li>
<li>The noxfile I'm looking at also has constraints on third-party packages, so that needs to factor into the constraints somehow.
Could just read a separate file in, or have handling for any number of constraint files.</li>
<li>Running <tt class="docutils literal">coverage erase</tt> doesn't need any package data.</li>
<li>Running <tt class="docutils literal">flake8</tt> requires the command-line to take into account whether or not there's a src directory, so <strong>the package root data needs to specify whether there is a src directory</strong>.</li>
<li>Running <tt class="docutils literal">mypy</tt> needs the same information.</li>
<li>Running <tt class="docutils literal">pytest</tt> needs to optionally pass additional environment variables based on the package root.</li>
<li>Running <tt class="docutils literal">pytest</tt> <em>under</em> <tt class="docutils literal">coverage</tt> requires a custom configuration file generated from the requirements file.
(The package name has to be processed into an importable module name.)
(Also, the coverage needs to be recorded in a unique data file; I'd say, slugify the package root.)</li>
<li>One thing I need to keep in mind for actually processing the coverage output is not this data flow, but being able to optionally plug in <tt class="docutils literal"><span class="pre">limit-coverage</span></tt>.
The thing <em>about this data flow</em>, which I forgot at first, is that <tt class="docutils literal">coverage combine</tt> is going to need its own coveragerc, deriving paths directives from the package root, whether there is a src directory, and the module name.</li>
<li>The next session is about building an executable with <tt class="docutils literal">shiv</tt>.
I think the only portable way to accomplish this is to extract the entry point data from the wheel, specifically the <tt class="docutils literal">console_scripts</tt> section.
This means that the specific command lines being generated will have to be done at run time instead of graph time.</li>
<li>Running the profiler doesn't need anything extra here...</li>
</ul>
<p>So, we have:
- the package roots
- whether they use src
- the paths to each requirements file
- the requirements file provides access to the package names</p>
<p>(The constraints file is also required to get the path to the wheel file for shiv.)</p>
<p>For some aesthetics purposes, I kind of want to divide the package roots into the common and unique parts.
So the data structure looks something like:</p>
<ul class="simple">
<li>common prefix</li>
<li>unique suffix</li>
<li>src bool</li>
<li>generated path to requirements file, as an <tt class="docutils literal">Input</tt></li>
</ul>
<p>My inclination is to first have the common prefix be empty, and then process all of the instances together at once to get the common prefix as long as possible.
This could also be accomplished by having two distinct data types.</p>
<p>I'll have to work on this tomorrow.
For now, I'm just glad to have worked through this analysis.
From this, I can properly write the functions I need.</p>
<p>But at the moment, I just want to be ready for bed.</p>
<p>Good night.</p>
Diary 2021-09-042021-09-04T04:00:00-04:002021-09-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-04:/diary-2021-09-04<p class="first last">After this entry was mostly written, I began to fail to avoid grappling with technology.</p>
<p>I somehow managed to avoid grappling with technology today.</p>
<p>Instead, I wrote some notes about the direction I want to take the worldbuilding after I discussed it some with my wife last night.</p>
<p>Basically, I want the first thing the reader sees to be a song about the end of a war.</p>
<p>I'm not really in a good shape to explain any of this, so instead I'll just note that I'm really out-of-practice with writing, somehow, after writing that giant post a month ago.
So I need to work on reminding myself how to just write stuff.</p>
<p>Post is late anyway, might as well be late and short.</p>
<p>Good night.</p>
Diary 2021-09-032021-09-03T04:00:00-04:002021-09-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-03:/diary-2021-09-03<p class="first last">It would seem that I have engaged in some pro ... crastination.</p>
<p>I've been working on worldbuilding some more.
Maybe I'll put posts about it somewhere proper on this blog when I've gotten beyond a massively disorganized rough draft.</p>
<p>This is what I've been working on, but I'm not exactly sure what to say about it.
The basic "organization" I have right now is a <a class="reference external" href="https://www.sphinx-doc.org/">Sphinx</a> project that has minimal drafts for a few areas, and a bunch of extensive notes that are extremely disorganized, both internally, and in terms of where they are in my home directory.</p>
<p>I ended up not getting too far, but I did wrestle a bunch with Sphinx's directives.
I <em>think</em> I've got what I need to make night mode work properly with the illustrations I want to add, without requiring a server to be spun up, but it's kind of inconvenient to write.
I suspect there's a less cumbersome way to do what I'm doing, but I'm not sure what it is, and I'd like to focus on content for now.</p>
<p>Anyway.
Late.
Sleepy.
Ending post now.</p>
<p>Good night.</p>
Coding 2021-09-022021-09-02T04:00:00-04:002021-09-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-02:/coding-2021-09-02<p class="first last">A stripped-down, simple core, surrounded by a dozen layers of weird adaptors...</p>
<p>I tried to put the stuff I was talking about yesterday into practice, and it didn't work out.
I think it needs more planning, so I'll once again wait until the weekend.</p>
<p>The main thing I found out is that "passing <tt class="docutils literal">IO</tt> objects into <tt class="docutils literal">subprocess.run</tt>" doesn't work, so it's probably not worth trying to do that up-front.</p>
<p>I started roughing out the pyproject-build and <tt class="docutils literal">Package</tt> stuff, and it ended up as a big mess because I didn't plan it properly.</p>
<p>I'm thinking about the kind of stuff that needs to happen for each phase, and it's pretty confusing.</p>
<p>At the <em>top level</em>, it needs a generator that takes an output directory and some kind of aggregated structure combining paths to use.
The return value needs to be an aggregated data structure that associates to the existing data, objects that can be passed into the pip functions to consume the output files created by the action.</p>
<p>Looking over some of the files I want to put together, I see that it needs the full path as well, but also it needs, say it with me, data that isn't available at graph generation time.
As such, I'm going to end up leaning <em>even more</em> on generating input files for some of this.
This is... probably fine.</p>
<p>I think I'm going to have to set up some kind of shared object that has this information and asynchronous communication stuff set up.
Either that, or defined channels associated with the different actions.
I suppose I could kind of cheat and just read some stuff from the files that I'm writing.
Just be like, okay, we <em>know</em> that this <tt class="docutils literal">requirements.txt</tt> file just contains a single project name, so just, like, interpolate that in.</p>
<p>Eesh, this is going to be so brittle.
I guess I just need really thorough tests.</p>
<p>And some really thorough planning so I know which steps need what information and what they'll have to do with it...</p>
<p>This entry went late, so I'm just cutting it off here.</p>
<p>Good night.</p>
Coding 2021-09-012021-09-01T04:00:00-04:002021-09-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-09-01:/coding-2021-09-01<p class="first last">"That simplifies things in a complicated way."</p>
<p>All right, here's the deal.
I want to work on pulling code from the motrfile into MOTR proper, and part of that is going to be developing two interfaces that the current behavior doesn't need, so this is going to be, a little interesting.
I've talked about these before, but I figure I'll try to just run through them quickly from first-ish principles.</p>
<p>Let's call these interfaces <tt class="docutils literal">Package</tt> and <tt class="docutils literal">Platform</tt>.
A given repository provides one or more packages, which can run on one or more platforms.
A package is a pip-installable library.
A platform is a particular version of Python running on a particular host system.
This can mean different versions of CPython, or PyPy, Brython, Pyodide, maybe Nuitka, etc.</p>
<p>Different steps in the Action graph can target different combinations of platforms, but the overall graph should generally work on a consistent set of packages, so we essentially want some way to combine "two functions that convert a set of packages to a sequence of graph operations" into "one function that converts a set of packages to a sequence of graph operations".</p>
<p>I'd been considering special-casing the "one-package" case, but it's probably less effort to start with to do the following:</p>
<ul class="simple">
<li>Generate a list of package "roots" (at graph creation time).
These "roots" are the directory that contains the pyproject.toml file.</li>
<li>From this, pass each project root into <tt class="docutils literal"><span class="pre">pyproject-build</span></tt>, and from that, extract a path and a package name.</li>
<li>We now have a list of package names, and if I avoid special-casing, then I can just always use that name for the "suffix" purpose.</li>
<li>From the paths, I generate a constraint file.
This is an output, and it's passed as an input to <tt class="docutils literal">pip install</tt> commands, via the constraints <em>environment variable</em>.
It should be accompanied by one of the names from the list of names.
Which means that list needs to be constructed at graph creation time.</li>
</ul>
<p>This is... a little vexing.
I can avoid relying on the actual name by constructing a requirements.txt file associated with the path to the root for each package.
So, fundamentally, at graph time we're <em>always</em> working with a path-to-the-root, and only when the graph is executed do we construct the mapping from those paths to the actual packages.</p>
<p>So, if the <tt class="docutils literal">Package</tt> class is only relevant at graph time, then the only information it <em>can</em> use is path-to-the-root.
That simplifies things in a complicated way.</p>
<p>Taking it from the top:</p>
<ul class="simple">
<li>Generate a list of roots</li>
<li>Have a custom action that takes in the list of roots; its helper should produce a constraints file and a mapping from roots to requirements files</li>
<li>We want to combine these with actions that take multiple roots to create output; to avoid duplicated code, actions should take a single root and requirements file, and there should be a library function to map over these.</li>
</ul>
<p>(It also occurs to me that I'll probably not be able to rely on any of this for RPython projects, that is, projects using PyPy for Python 2.7.)</p>
<p>So, the two ways to take multiple packages are, either to dispatch to a function that takes single packages, or to discard the package information entirely, and dispatch a single call to a function that takes no packages.</p>
<p>Let's see how tasks relate...</p>
<p>I should switch to requirements + constraints ASAP, and hardcode the root list for now.</p>
<p>I should replace the <tt class="docutils literal">Flit</tt> action with a <tt class="docutils literal">PyprojectBuild</tt> action, but maintain the current behavior on the filesystem for the moment.</p>
<p>At some point I need to rewrite the <tt class="docutils literal">Pip</tt> class, but it needs to take an optional root argument, potentially with an associated suffix.</p>
<p>It may make sense to divide the <tt class="docutils literal">Pip</tt> class into a "package" version and a "no-package" version.
That's an open question right now.</p>
<p>(Because every stage of the pip setup needs to at least know the suffix, then the package information is effectively part of the class, and doesn't need to be passed along with the requirements needed for the associated action.)</p>
<p>I'm going to need to take some time to work through all of the implications of this, but not right now.
Right now, I need to get ready for bed, <em>maybe</em> do some writing.</p>
<p>Good night.</p>
Weekly Roundup 2021-08-312021-08-31T04:00:00-04:002021-08-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-31:/weekly-roundup-2021-08-31<p class="first last">This felt vaguely dissatisfying, but I can't really pin down anything to do differently...</p>
<ul class="simple">
<li>Wednesday: I got back to work on MOTR. I come up with some ideas for streamlining the workflows I'm developing.</li>
<li>Thursday: I reached full test coverage for MOTR, and published another version.</li>
<li>Friday: I thought about how I want to handle some issues with a worldbuilding project.</li>
<li>Saturday: I found some improvements I could make to the current workflows I'm prototyping in MOTR, but I didn't try them out yet.</li>
<li>Sunday: I got sidetracked from working on the worldbuilding and ended up working on basically unimportant technical issues. I tried to pivot from those into future work on MOTR, but... eh...</li>
<li>Monday: I complained about how my initial setting document draft was so boring, even I can't get through it.</li>
</ul>
<p>Next week, I'm going to just accept that the beginning of the setting document is a clunker, and try to work on the later parts.
I also need to properly prioritize the stuff I want to work on for MOTR.</p>
Diary 2021-08-302021-08-30T04:00:00-04:002021-08-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-30:/diary-2021-08-30<p class="first last">Being forced to confront the fact that sometimes my creative output is super boring.</p>
<p>I started writing up the setting document for the worldbuilding.
The first thing I worked on was a short explanation of a few basic facts about the world.</p>
<p>You know how, sometimes you're writing something, and you get feedback about needing to cut part of it, and maybe you get kind of offended?
Like, come on, it's not that wordy!
People should be grateful to read my words!</p>
<p>That's not happening here.
It's less than 400 words, and it needs some serious work, because the current version is <em>painfully</em> dry and boring.
And that's not me grudgingly accepting feedback from someone else.
That's me reading over what I wrote, and nearly falling asleep.</p>
<p>It's possible that some illustrations could salvage it.</p>
<p>I'll have to try to come at this from multiple angles to fix it up.</p>
<p>Good night.</p>
Diary 2021-08-292021-08-29T04:00:00-04:002021-08-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-29:/diary-2021-08-29<p class="first last">Time management? What's that?</p>
<p>So, uh, funny story.
I made a <em>little</em> progress on MOTR today, and I may or may not have judged enough SoME1 entries; I'll try to get a few more tomorrow to be sure.
I thought I was going to work on the worldbuilding that I mentioned, for a setting tentatively called Korín, but, um...</p>
<p>"Hey, I write these blog posts in reStructuredText, and it works out pretty well.
Why don't I write up the worldbuilding using Sphinx instead of just haphazardly jammed into a text file?
... Okay, I've got the basics set up, but, oh yeah, sphinx-quickstart generates makefiles.
And my kneejerk reaction to makefiles is to rewrite them in Python.
Just like I did for the blog.
Welp, I guess I'm doing this."</p>
<p>I used <a class="reference external" href="https://www.pyinvoke.org/">Invoke</a> instead of MOTR, because Invoke is pretty much always going to be superior to MOTR for replacing Sphinx's makefiles.
(No concurrency machinery, not <em>required</em> to use dependency specification...)
I mean, unless I created a MOTR builder <em>specifically</em> to replicate the functionality (which... wouldn't be a terrible thing for me to have around), and even then, there'd be some minor differences.
Anyway, bashing it together with Invoke is quicker for now, but, on reflection, putting this functionality into MOTR might be good as a proof-of-concept/evaluation of the idea of writing high-level code into the app library.
(Plus, I'm going to need a more targeted sphinx-build wrapper later <em>anyway</em>...)
(Actually, it wouldn't really work that well, because of the concurrency.
MOTR doesn't print command output to its standard output or standard error streams, so it's not really convenient to get information out of these command-line runs.
I judged this to be an acceptable tradeoff for the case of "running as many things at the same time as my computer allows", but running sphinx-build is... not that.)</p>
<p><em>Anyway</em>, now it's closing in on 11 PM and I'm going "Oh, yeah, I need an outline."</p>
<p>So, um, I guess I'm signing off for now and working on that outline.</p>
<p>Good night.</p>
Coding 2021-08-282021-08-28T04:00:00-04:002021-08-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-28:/coding-2021-08-28<p class="first last">At some point I should come up with a system for archiving or culling old runs, if I'm going to be shoving this much <em>stuff</em> in the folders...</p>
<p>I just tried out <a class="reference external" href="https://pypa-build.readthedocs.io/">build</a> manually, and it looks much better for slotting into the automated workflows for MOTR than <tt class="docutils literal">flit build</tt> is.
Besides the fact that it works with any PEP-517-compatible backend (not just flit), there's also the fact that it supports passing input and output directories.
Neither directory is strictly necessary (and flit more-or-less supports the former, I think), but they are convenient.</p>
<p>I need to figure out how best to do all of this, but I think it would be helpful to isolate the task-runner builds from the "manual" builds.</p>
<p>Unfortunately, I had a bunch of stuff I had to do today, so I'm mostly just setting this aside for tomorrow.</p>
<p>Thinking about this is also giving me a few other ideas for changes, like having the ability to express "a path relative to the current run's log directory" in the definition of an <tt class="docutils literal">Action</tt>.
This would allow me to get better isolation between runs.
And also, would provide, potentially, a nicer setup for reports than what I have currently.</p>
<p>I'll have to sleep on this, and I'll get right on that.</p>
<p>Good night.</p>
Diary 2021-08-272021-08-27T04:00:00-04:002021-08-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-27:/diary-2021-08-27<p class="first last">"But what <em>really</em> happened?" "Well, I started typing..."</p>
<p>Okay, so, I forgot there was a judging period for SoME1, which gives me an excellent excuse/reason to not touch the entries for the next week or so.
It's only fair.</p>
<p>Anyway, while I take a break from coding (but not enough of a break that I haven't been researching stuff; I've decided to try replacing <a class="reference external" href="https://flit.readthedocs.io/">Flit</a> with <a class="reference external" href="https://pypa-build.readthedocs.io/">build</a> to see what happens; if it works, I get every compliant builder "for free"), I'm trying to work on a worldbuilding project.
I forget if I've talked about it in much detail before, but I was all like "here's something I could try doing with a language ... oh no, I have sketched out an entire cosmology and history, albeit in extremely broad strokes, to contextualize this language that I have barely worked on".
I don't <em>begrudge</em> all of that for existing, but I'm sensing one of the failure modes I've noticed before in my world-building attempts: focusing on particular areas out of a sense of "obligation" to "shore up" some other part.</p>
<p>The solution I want to try for dealing with that is to give up control over the focus, by turning what I have now into a very bare-bones RPG setting, and run games in it.
(I'm also trying to find good phonaesthetics for some naming languages, because those should at least take less effort than something fully developed.)
In any case, the next big step I want to take toward that is to put together a setting reference based on the stuff I have currently.
And one of the things I want to have for that is...</p>
<p>Okay, this is going to take a little explanation.
One idea that I've wanted to apply to a bunch of these attempts at fantasy worldbuilding is not in the worldbuilding itself, but in the presentation.
I'm not sure how to articulate my feelings about the concept of "canon", but I want to avoid writing stories that present themselves as "this is what <em>definitely actually happened</em> [in this world that doesn't exist]".
And I want to achieve this by relying on in-setting authors, unreliable narrators, etc.
And I want this to be reflected in the stories that the setting document supports.</p>
<p>In practice, I suppose that works out to, among other things, "Well, the dragons did X, Y, and Z <em>in the game</em>, but that wouldn't happen in 'grounded' stories"</p>
<p>And to support that, I need some way of augmenting the "grounded" presentation with stuff like "the following simplifications are acceptable in such and such circumstances" or "similar technology takes this more fanciful form in more fanciful settings, and is available sooner".
And, similarly, if I get to the point of describing possible personal names (which the initial draft of the document <em>will not do</em>), I'd maybe like to be able to present some spectrum between "just roll on this table to get going", "here are the phonological constraints on names, to varying degrees of detail", and maybe "here are the kinds of things the names can <em>mean</em>, if those sound on the nose, then turn to such-and-such chart to de-Englishify them".</p>
<p>Anyway, I need to really think about all of this, but I figured I'd write down what I want to be thinking <em>about</em>, in order to have a post.
I want to get to bed now.</p>
<p>Good night.</p>
Coding 2021-08-262021-08-26T04:00:00-04:002021-08-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-26:/coding-2021-08-26<p class="first last">So much green...</p>
<p>Hah, yes!
Full test coverage, and a few minor bugfixes thanks to those thorough tests.
I've published version 0.1.2 of MOTR, and it's much nicer in a bunch of little ways that don't really fit into "features" per se.</p>
<p>(I removed an errant newline from the output, and did the previously-mentioned reliability improvements.)</p>
<p>There are two basic directions to go from here:</p>
<ul class="simple">
<li>Refactor and improve the code</li>
<li>Revisit my ideas about organization, with an eye towards using limit-coverage.</li>
</ul>
<p>I'll need both before I'm comfortable releasing 1.0.
The refactorings are probably easier, but getting limit-coverage set up is really appealing to me, because it's needed for the mutation testing paradigm that I want to support.</p>
<p>Here's a thought: maybe if I got the documentation together, I'd have a better idea of how I want to organize the code.
So, I need to do some of the improvements (like exposing the <tt class="docutils literal">Input</tt> type in the <tt class="docutils literal">api</tt> module so that you can <em>actually call a bunch of the functions that the module exposes</em>) so that the code that I'm documenting is closer to how I want the code to end up.</p>
<p>Getting documentation soon is good, but I'd like to first try to move code out of the config file and into the application.
That'll allow me to prototype stuff like a high-level <tt class="docutils literal">Sphinx</tt> action without the motrfile ending up hopelessly cluttered.</p>
<p>So, the best course of action is probably:</p>
<ul class="simple">
<li>Add some of the features that would make the high-level <tt class="docutils literal">Flit</tt> action more straightforward</li>
<li>Add the features that I need for my other project layouts</li>
<li>Adapt the existing high-level code to work with those features</li>
<li>Start pulling stuff into the application, starting with the <tt class="docutils literal">Pip</tt> high-level feature.</li>
</ul>
<p>This should get me into a state where I can start collapsing the configuration file into a few dozen lines.</p>
<p>Something else I ought to look into is supporting other build backends.
I think supporting poetry, enscons, and setuptools in addition to Flit would get me most of the way there.
I kind of need to think about each one separately because I need to know where to look for the wheel that it builds.</p>
<p>Anyway, I think I'll take a bit of a break before getting to work on that.
I'm happy with where I've gotten this so far, but I want to come back to it a little fresher.
For now, I really need to get to bed.</p>
<p>Good night.</p>
Coding 2021-08-252021-08-25T04:00:00-04:002021-08-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-25:/coding-2021-08-25<p class="first last">Some of these tests would have come in handy <em>before</em> I published version 0.1.0.</p>
<p>It's good to be back on this.
I did some work on MOTR after I published the Missable Mysteries, because, while those posts took like a month to write, I wasn't working on them <em>the day of</em>, so I had some free time.
At first, I was focused on iterating on the fixes for replacing <tt class="docutils literal">pip install .</tt> with <tt class="docutils literal">flit build && pip install <SOMETHING></tt>.
That "something" is currently much more straightforward than what I was originally planning, but there are a few changes that can take it further:</p>
<ul class="simple">
<li>Separate the <tt class="docutils literal">Cmd</tt> class into a specialized version that takes byte buffers, and a wrapper around that that exposes the general interface.</li>
<li>With this, I can delegate to the <em>specialized</em> class instead of the <em>general</em> one, which will allow me to get the output from <tt class="docutils literal">flit build</tt> without relying on the knowledge of where the general class writes its output.</li>
</ul>
<p>For now, I'm working on increasing the coverage.
Once I get it all the way up, I'll feel comfortable making more changes to the code, such as:</p>
<ul class="simple">
<li>Factoring some repeated code into functions</li>
<li>Exposing types in the API module that arguably should have been there all along.</li>
</ul>
<p>There's just a few lines left to cover, so I should be able to get on that soon.
I'll publish a new version first, just to have a version with a non-broken config file, then work on those changes, then start working on some of the interfaces I've been wanting to add for a while.</p>
<p>Anyway, it's getting way late again, so I should wrap up.</p>
<p>Good night.</p>
Weekly Roundup 2021-08-242021-08-24T04:00:00-04:002021-08-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-24:/weekly-roundup-2021-08-24<p class="first last">I think part of the problem here was that I was freaking out about the SoME1 deadline. Hopefully I'll be able to handle this better with future installments.</p>
<ul class="simple">
<li>Wednesday: I attempted to tease the secret project (discussed below).</li>
<li>Thursday: I was getting to be <em>done</em> with the week, which is a little awkward given that I write these the day before they're "officially" published, so this was on a Wednesday night.</li>
<li>Friday: I started on a final editing pass for the "secret project", and somehow was so out-of-practice editing that I minorly injured myself.</li>
<li>Saturday: I finished that editing pass, and then did another one, because I apparently noticed a completely different set of issues than I did the night before?</li>
<li>Sunday: I introduced a new series of higher-effort blog posts. These <em>might</em> come out as often as once a month.</li>
<li>Monday: I posted the first proper entry. It may get revised a bit sometime soon, since it was kind of rushed out after a month of work.</li>
</ul>
<p>Next week, I'm going to take a break from thinking <em>too</em> hard about the Missable Mysteries.
Here's what I'm hoping to do:</p>
<ul class="simple">
<li>Improve test coverage on MOTR</li>
<li>Make some tweaks to the code once I have improved coverage</li>
<li>Cut a new release where the main advancement is really just that the motrfile in the source distribution consistently works on more than zero machines</li>
<li>Do some worldbuilding of some nature</li>
<li>Plan the overall trajectory for the Missable Mysteries a little better</li>
</ul>
Missable Mysteries of Mathematics 2021-08-23 (Group Theory Part 1)2021-08-23T04:00:00-04:002021-08-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-23:/missable-mysteries-2021-08-23<p class="first last">I would argue that some of these concepts were not invented, but <em>discovered</em>.</p>
<p>What does adding numbers together have in common with rotating a square piece of paper?
What does rearranging a deck of cards have in common with rotating and flipping a square piece of paper?
These questions are rhetorical; I know the answers, and if you don't already, I hope to help you learn.</p>
<p>Let's start with that square piece of paper.
Suppose we have a square piece of paper, and we mark a dot on it, kind of off-center, like this.</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-01"/>
</svg><p>Now, let's think about moving that piece of paper around, making sure (for now) to keep the dot visible.
We can slide the paper around the table,</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-02"/>
</svg><p>Or we can turn it around as we move it.</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-03"/>
</svg><p>Now, there are many ways to move the paper around, so let's simplify things to make it easier to talk about.
Let's add another rule.
We already had "the dot must be visible".
Let's add "the paper must end up occupying the same area".
We can think about this as follows: we want to talk about motions where the paper ends up where it started, and if you closed your eyes, you wouldn't be able to tell which motion was done, but if you open your eyes, you can see where the dot moved to.</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-04"/>
</svg><p>Let's look more closely at what I'm saying in that last sentence.
Whatever we do to the paper, we currently only care about how it starts out, and how it ends up.
To see why this makes sense, consider the process of rotating the paper a quarter-turn clockwise.
If you stop halfway through, it's got points where it should have sides, and sides where it should have points!</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-05"/>
</svg><p>You could definitely tell something was different if you felt that with your eyes closed!
So, getting to one of the "allowed" positions means passing through "disallowed" positions.</p>
<p>Next, let's compare a half-turn clockwise to a half-turn counter-clockwise.
Looking at them, we can't tell the difference between a square that was turned halfway around clockwise, and a square that was turned halfway around counter-clockwise.
In contrast, consider doing <em>these</em> turns and stopping halfway through the turn.
Each one stops at a quarter-turn.
(A different quarter-turn, no less, but let's come back to that later.)</p>
<p>Let's look over what we can do to a square piece of paper, following these rules:</p>
<ul class="simple">
<li>We've seen that we can turn it a quarter-turn clockwise</li>
<li>We've seen that we can turn it a quarter-turn counter-clockwise</li>
<li>We've seen that we can turn it a half-turn</li>
</ul>
<p>Stopping halfway through the half-turn rotations produced a quarter-turn, which suggests that it's possible to combine these turns into other "things to do to a square piece of paper without flipping it, but making it take up the same space at the end".
Now, "things" sounds a little weird, and "things to do to a square piece of paper without flipping it, but making it take up the same space at the end" is <em>way</em> too long.
Let's call them <strong>elements</strong> instead.</p>
<p>Here is the result of applying each of these three elements to the same square piece of paper.</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-06"/>
</svg><p>Here are some examples of combining these elements:</p>
<ul class="simple">
<li>If we do a quarter-turn clockwise followed by a half-turn, we get a quarter-turn counter-clockwise.</li>
<li>If we do a half turn followed by a quarter-turn counter-clockwise, we get a quarter-turn clockwise.</li>
<li>If we do two half-turns, we get... hm...</li>
</ul>
<p>It looks like that list of three elements was missing an entry.
Let's try to fix that.</p>
<ul class="simple">
<li>We can do nothing to it</li>
<li>We can turn it a quarter-turn clockwise</li>
<li>We can turn it a quarter-turn counter-clockwise</li>
<li>We can turn it a half-turn</li>
</ul>
<p>Now, two half-turns combine into "nothing", and "nothing" and "something" combine into the same "something".
When you consider the individual combination of "nothing" and "something", it doesn't look too impressive (all that work just to get one of the same things you put in?), but it will be useful for more than filling out that list, I promise.
Now, a "do-nothing" element is called an <strong>identity element</strong>, or <strong>identity</strong>, for short.</p>
<p>Speaking of that list, I said there were three elements in it, then I said four!
Is it possible I've missed more elements?</p>
<p>I'll try to convince you that I haven't.</p>
<p>To start with, consider the corner of the square next to the dot.
Let's label that corner <tt class="docutils literal">A</tt>.
Because we're moving the paper around, not somehow moving the dot around on the paper, the dot and <tt class="docutils literal">A</tt> are always the same distance from each other, so by looking at the dot, we can find <tt class="docutils literal">A</tt>.</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-07"/>
</svg><p>Now, let's look at these square pieces of paper with <tt class="docutils literal">A</tt> labeled.
We see that the list of four elements has one element for each corner that <tt class="docutils literal">A</tt> can end up at.
Suppose we label them <tt class="docutils literal">B</tt>, <tt class="docutils literal">C</tt>, and <tt class="docutils literal">D</tt>, clockwise from <tt class="docutils literal">A</tt>.</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-08"/>
</svg><p>We can describe the listed elements as follows:</p>
<ul class="simple">
<li>An element that takes <tt class="docutils literal">A</tt> to <tt class="docutils literal">A</tt>.</li>
<li>An element that takes <tt class="docutils literal">A</tt> to <tt class="docutils literal">B</tt>.</li>
<li>An element that takes <tt class="docutils literal">A</tt> to <tt class="docutils literal">D</tt>.</li>
<li>An element that takes <tt class="docutils literal">A</tt> to <tt class="docutils literal">C</tt>.</li>
</ul>
<p>This shows that we've listed one element for each possible destination corner for <tt class="docutils literal">A</tt>.
Is it possible that there are some more elements that I've missed?
Let's take a closer look at how <tt class="docutils literal">A</tt> and the dot relate to each other, and the other corners.</p>
<p>If we go clockwise from <tt class="docutils literal">A</tt>, we always see the following things in this order:</p>
<ul class="simple">
<li><tt class="docutils literal">A</tt> (to start with)</li>
<li>the dot</li>
<li><tt class="docutils literal">B</tt></li>
<li><tt class="docutils literal">C</tt></li>
<li><tt class="docutils literal">D</tt></li>
<li>back to <tt class="docutils literal">A</tt></li>
</ul>
<p>We can't change the relative positions of the corners and the dot.
Therefore, under the constraints that we put on this system, if we know which point <tt class="docutils literal">A</tt> has gone to, then we know which point each other point has gone to.
<tt class="docutils literal">B</tt> must be the point right after <tt class="docutils literal">A</tt>, and so on.</p>
<p>Now that we know there are just four elements in the list of things to do to this square, let's try figuring out how they combine.</p>
<p>First off, how many combinations are there?</p>
<p>Well, there are four elements.
A combination of elements has a first element, and a second element.
There's no way that picking one element narrows down our choices for the other element, so it must be the case that each of the four choices for the "first element" can combine with each of the four choices for the "second element".
So, there are four groups of four choices.
Four fours.
Four, plus four, plus four, plus four.
You can trust me that that's sixteen, work it out for yourself, or count the little squares in the following diagram.</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-09"/>
</svg><p>In the diagram, I have named each element after the destination of <tt class="docutils literal">A</tt>.
Let the left side represent the first element in the combination, and the top, the second element.
The square that is directly to the right of a label on the left, and directly below a label on top, represents the combination of, first the left label, and then the top.
Let's try to fill in the labels for all of the combinations.
To start with, because each element is named after the destination of <tt class="docutils literal">A</tt>, we know that <tt class="docutils literal">A</tt> is the identity element.
Therefore, if one of the elements in the combination is <tt class="docutils literal">A</tt>, then the combination is just the other element.
This gives us the top row and the left column, which you can count up as seven squares.
We're nearly halfway done!</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-10"/>
</svg><p>Let's look at the second column.
The first column is filled in, and indicates that if we turn the square some amount and then do nothing, that is indistinguishable from just turning it that amount.
To go from the first column to the second column, we just have to turn the square a quarter-turn clockwise.
On a quarter-turn, <tt class="docutils literal">B</tt> goes to <tt class="docutils literal">C</tt>, so moving <tt class="docutils literal">A</tt> to <tt class="docutils literal">B</tt> twice puts <tt class="docutils literal">A</tt> on <tt class="docutils literal">C</tt>.
Furthermore, <tt class="docutils literal">C</tt> goes to <tt class="docutils literal">D</tt>, so moving <tt class="docutils literal">A</tt> to <tt class="docutils literal">C</tt> and then <tt class="docutils literal">A</tt> to <tt class="docutils literal">B</tt> moves <tt class="docutils literal">A</tt> to <tt class="docutils literal">D</tt>.
Finally, <tt class="docutils literal">D</tt> goes to <tt class="docutils literal">A</tt>, so moving <tt class="docutils literal">A</tt> to <tt class="docutils literal">D</tt> and then <tt class="docutils literal">A</tt> to <tt class="docutils literal">B</tt> moves <tt class="docutils literal">A</tt> to <tt class="docutils literal">A</tt>.</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-11"/>
</svg><p>Notice that every element occurs once in the second column.
This isn't surprising for the first row or column, because one of the elements involved was the identity, but it's worth thinking about what it would mean if a column didn't contain every element.</p>
<p>First, because there are the same number of elements as rows, an element would have to be repeated.
Now, what would that imply?</p>
<p>Since we can describe a rotation as taking <tt class="docutils literal">A</tt> to some point, we can also think about what point a rotation brings to <tt class="docutils literal">A</tt>.
And if we take <tt class="docutils literal">A</tt> to a point, and then take that same point to <tt class="docutils literal">A</tt>, then we must have taken <tt class="docutils literal">A</tt> to <tt class="docutils literal">A</tt>, which is the identity element.
So, that means that we could apply the "reverse" element to whatever column has duplicates, and get back to the <tt class="docutils literal">A</tt> column.
But the different elements are just end-points, they don't "remember" how they got there.
Therefore, if a column has duplicate elements, then those same rows must be duplicates in the <tt class="docutils literal">A</tt> column.
But the <tt class="docutils literal">A</tt> column is just the elements, so it can't have duplicates.</p>
<p>So, we know that all of the columns of this table contain each element exactly once.
In other words, once you've applied one element, then there is some element that takes you to any element you want.</p>
<p>Before we finish with the rest of the table, let's look at that idea of "taking a point to <tt class="docutils literal">A</tt>".
It's clear that an element must exist for each of the four points we can choose, because every element ends with some point at <tt class="docutils literal">A</tt>.</p>
<p>So, there is some sense in which every element has an "opposite" element that "undoes" its operation.
We can call this corresponding element the <strong>inverse</strong> of that element.
So, the inverse of the element that takes <tt class="docutils literal">A</tt> to <tt class="docutils literal">B</tt> takes <tt class="docutils literal">B</tt> to <tt class="docutils literal">A</tt> (which is the same thing as taking <tt class="docutils literal">A</tt> to <tt class="docutils literal">D</tt>) and vice-versa.
And, we can see from the chart that taking <tt class="docutils literal">A</tt> to <tt class="docutils literal">A</tt> is its own inverse.
(This is generally true of identity elements: the identity applied to the identity produces the identity, so it must be its own inverse.)
The only remaining element on either side is taking <tt class="docutils literal">A</tt> to <tt class="docutils literal">C</tt>.</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-12"/>
</svg><p>This element is, in fact, its own inverse.</p>
<p>We may as well add this information to the chart.</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-13"/>
</svg><p>We've already shown that the elements in each column must be unique.
It's a little different in terms of order, but a similar argument shows that the elements in each row must be unique.
If a row has non-unique elements, then there are two possible "second elements" that take that row's element to the same final element.
Let's call these "second elements" the <strong>duplicating elements</strong> and the result the <strong>duplicated element</strong>.
Because the columns are different, the duplicating elements must be different from each other.
But suppose we performed the row's inverse element before going through the combination.
So, to start with, we have the combination of <em>first</em> the inverse of the row, and <em>second</em> the combination of the row, and the element that leads to a duplicate entry.
Now, it shouldn't matter precisely how we group the elements in the combinations, because we can think of the overall combination as paths made up of smaller paths.
We could choose to break the above combination into three paths: the inverse of the row, the row, and the duplicating element.</p>
<p>If we set aside the inverse of the row to start with, then we can consider the row and the duplicating element.
Then we can combine them into the duplicated element.
Then, we can bring the inverse of the row element back, and combine it with the duplicated element.
The result should be some element that is independent of the choice of duplicating element.</p>
<p>If, instead, we set aside the duplicating element, then we can consider the inverse of the row, and the row.
Then, we can combine them into the identity.
Then, we can bring back the duplicating element, and combine it with the identity.
The result should be whatever the duplicating element was.</p>
<p>All we did was think in different ways about the path that the piece of paper took.
So, that can't change the end result.</p>
<p>To summarize:</p>
<ul class="simple">
<li><strong>If</strong> a row has non-unique elements</li>
<li>We can choose two columns that have the same entry in the row.</li>
<li>This gives us two distinct duplicating elements that take the row to a single duplicated element.</li>
<li>The row must have an inverse element.</li>
<li>If we combine the inverse of the row, and the row, and a duplicating element, then we can decide <em>mentally</em> whether to combine the first pair or the second pair first, without changing what happens <em>physically</em>.</li>
<li>Grouping the second pair first tells us that, regardless of the choice of duplicating element, we get the same result.</li>
<li>Grouping the first pair first tells us that the overall path is equal to the duplicating element.</li>
<li>So, grouping the first pair first gives us two different results, while grouping the second pair first gives us the same result twice.</li>
<li>But this is purely mental, and can't change what happens physically, so this situation is impossible.</li>
<li>We only got into this situation by assuming that rows can have non-unique elements, so that assumption must be false.</li>
</ul>
<p>Therefore, rows cannot have non-unique elements.</p>
<p>Because every element in a row must be unique, we can look at the rows with three elements and fill in the remaining element in each row...</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-14"/>
</svg><p>And now all that's left is two squares in the bottom row, but now we can use the uniqueness requirement on the columns again, to fill in the rest of the table.</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-15"/>
</svg><p>The argument I made just now relies on another property that these elements have: that we can "group" them in any way without changing the result of applying them.
This is known as the <strong>associative property</strong>.
In the context of rotating this piece of paper, saying "the associative property holds" is equivalent to saying "if we have three rotations, not necessarily distinct, called <tt class="docutils literal">X</tt>, <tt class="docutils literal">Y</tt>, and <tt class="docutils literal">Z</tt>, then the results of 'rotating by the combination of <tt class="docutils literal">X</tt> and <tt class="docutils literal">Y</tt>, then by <tt class="docutils literal">Z</tt>' and 'rotating by <tt class="docutils literal">X</tt>, and then by the combination of <tt class="docutils literal">Y</tt> and <tt class="docutils literal">Z</tt>' should be the same".</p>
<p>So, we have a collection of elements, also called a <strong>set</strong>, and we have an operation that acts on two elements to produce another element, such that:</p>
<ul class="simple">
<li>one element of the set is the identity element with respect to the operation (the result of combining this element with any other, is the other element)</li>
<li>every element has an inverse with respect to the operation (for each element, there is exactly one element that, when combined with it, results in the identity element)</li>
<li>and combining the elements obeys the associative property (we can combine multiple elements, and it doesn't matter whether we combine "left to right" or "right to left")</li>
</ul>
<p>(And these statements are fundamentally <em>observations</em> about how the elements behave, not any kind of outside imposition of properties on them.)</p>
<p>A set and operation with these properties is known as a <strong>group</strong>.
Because of this group's simplicity, it has an additional property that is not part of the definition of a group.
This property can be argued through informally, like I have done for the other properties, but it can also be established by inspecting the table.</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-15"/>
</svg><p>If we imagine flipping the table across this diagonal...</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-16"/>
</svg><p>The values in the cells don't change!
It doesn't matter which order we combine elements, the result is the same.</p>
<p>This is known as the <strong>commutative property</strong>.
A group whose operation obeys the commutative property is called commutative.
(That is, the <em>operation</em> is commutative, so the <em>group</em> is also commutative.)
A group that is commutative is sometimes called a <strong>commutative group</strong>, which is straightforward, and often called an <strong>abelian group</strong>, which is not.</p>
<p>Here's a suggestion of a group that is not commutative, and a teaser for next time.</p>
<svg class="centered">
<use href="https://mwchase.neocities.org/images/group-theory-1.svg#figure1-17"/>
</svg><p>This entry is done for now, due to a combination of working under a deadline and reaching a good stopping point, but there will be more.
If you want to know more before then, I'm going to mention a bunch of helpful terms you can research.</p>
<div class="section" id="further-reading">
<h2>Further reading</h2>
<ul class="simple">
<li>This was an illustration of basic concepts in <strong>group theory</strong>.</li>
<li>The group I was describing is an example of a <strong>cyclic group</strong>, specifically C<sub>4</sub>. Cyclic groups whose <strong>order</strong> (the subscript number) is a <strong>prime number</strong> (a number that has no factors besides 1 and itself) have even more specialized properties than C<sub>4</sub>.</li>
<li>The chart that I spent most of the entry constructing is called a <strong>Cayley table</strong>.</li>
<li>The long argument I used to show that rows cannot have non-unique elements is a <strong>proof by contradiction</strong>.</li>
</ul>
<p>See you then!</p>
</div>
Missable Mysteries of Mathematics 2021-08-22 (Introduction)2021-08-22T04:00:00-04:002021-08-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-22:/missable-mysteries-2021-08-22<p class="first last">The Reveal</p>
<p>This is the secret project I've been... teasing is probably the wrong word; it sort of implies I know what I'm doing with regards to promotion.
Let's go with "admitting exists".
Anyway, welcome to</p>
<div class="section" id="missable-mysteries-of-mathematics">
<h2>Missable Mysteries of Mathematics</h2>
<div class="section" id="or-the-questions-about-mathematics-which-might-not-occur-to-you">
<h3>(Or, The Questions About Mathematics Which Might Not Occur To You)</h3>
<p>Which is a new series of posts I'm working on.
What's new about it?
Well, I intend to have editorial standards rather than just scrawling something at the last minute like a high school student.</p>
<p>The other thing that's new is the subject matter.
Rather than liveblogging whatever I'm working on at the time, this is an educational series, about mathematics.</p>
<p>Mathematical education has had a troubled history, at least in the USA, and I'm building up my plan for posts based on a document in my possession, which illustrates that troubledness, even though it doesn't mean to.
Problems with mathematical education include lack of engagement, and lack of conceptual relevance.
(For example: those of you who have graduated from high school, when was the last time you wrote a two-column proof?)</p>
<p>"The document" reveals a troubled relationship with basic mathematical concepts, and a surface-level knowledge of more advanced ideas.
In an effort to offer some antidote to the conditions that led to that state of mind, I'm writing up the <em>Missable Mysteries</em>.
A <em>Missable Mystery</em> is a mathematical question with a deep or useful answer, that it might not occur to someone to ask.
Additionally, they can be explained without requiring too much up-front knowledge.
(I do, however, plan to use earlier lessons to lay the groundwork for later ones.)</p>
<p>For example, the following questions:</p>
<ul class="simple">
<li>How does basic arithmetic compare and contrast with shuffling a deck of cards? (deep connection between seemingly different things)</li>
<li>How do different physical quantities combine and relate? Given a target measurement and some inputs, what kinds of formulas could plausibly let us get from one to the other? (sanity check for physics calculations at any level of complexity)</li>
</ul>
<p>The first post, which is shorter than I originally planned, because otherwise I would still be writing it, will go up soon.</p>
<p>See you then!</p>
</div>
</div>
Diary 2021-08-212021-08-21T04:00:00-04:002021-08-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-21:/diary-2021-08-21<p class="first last">Looking over what I wrote like "How did I think that was a coherent sentence?"</p>
<p>This isn't under "sneak peek" because, really, what was I even showing off in there?
But anyway, I did the edits I noted last night, and then a bunch more that I realized I needed on a re-read.
I could probably edit this project indefinitely, but I hope I've taken care of all of the really big or definite issues.</p>
<p>Anyway, I'm writing this up early because I had a bit of a rough week (hopefully next week will be a little easier), and I want to do stuff like I did last week, but, with, like, an actual post to go up today.
So, those are my plans for tonight, but what do I want to do over the weekend?</p>
<p>Well, go outside as little as possible on Sunday, to avoid the winds.
But aside from that, I'm going to plan and work on some other projects while I wait for feedback on the latest draft.
In particular, I'm really interested to see whether breaking out flit into its own step will help my MOTR config, and I've got some research and, I guess, experimentation that I want to do for a worldbuilding project that I don't remember whether I've mentioned here.
There's also another project that I'd like to start planning, which is just a silly little thing, but I can probably polish it indefinitely.</p>
<p>Well, that's all I'm going to get written for now.
I'd better wrap up.</p>
<p>Good night.</p>
Diary 2021-08-202021-08-20T04:00:00-04:002021-08-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-20:/diary-2021-08-20<p class="first last">When you don't do something for a few months, just never do it again in case you hurt yourself trying, I guess.</p>
<p>Things are wrapping up a little; there's only so much more to do before the various deadlines.
So that's good.</p>
<p>What's not good is that I managed to injure myself editing a document.
See, it's been a while since I wrote <em>a lot</em> by hand, and apparently taking a few pages of notes on "stuff I did wrong" was enough to mess up my hand a little, possibly giving it a blister.</p>
<p>We always find some way to suffer for our art.</p>
<p>Quick thoughts about what's happening in the coming days:</p>
<ul class="simple">
<li>A few tasks for work</li>
<li>Next draft of ~secret project~</li>
<li>Release the ~secret project~</li>
<li>Get back to work on MOTR</li>
<li>A few ideas that I've had in the last week or so.</li>
</ul>
<p>Anyway, I'll regret it a lot if I don't start wrapping up, so I'll start wrapping up.</p>
<p>Good night.</p>
Diary 2021-08-192021-08-19T04:00:00-04:002021-08-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-19:/diary-2021-08-19<p class="first last">Just holding on at the moment, would like to do better.</p>
<p>Okay, so.
Work is at least changing around a bit, and there <em>probably</em> won't be any more early morning meetings.
Those were so unpleasant.</p>
<p>All of that is none too soon for me, because my nerves are feeling a bit frayed.
I'm going to have to do a good job of relaxing soon, and that probably means planning it some.
I've got some stuff arriving in the mail soon that <em>should</em> help, and plenty of edibles.
Only caveat there is, next time I do that, I want to make sure I write the blog post <em>first</em>, for what I assume are obvious reasons.</p>
<p>And, I guess there isn't anything else I should be working on just now, since I am sleepy and it is getting late.</p>
<p>Good night.</p>
Sneak Peek 2021-08-182021-08-18T04:00:00-04:002021-08-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-18:/sneak-peek-2021-08-18<p class="first last">I'm not sure anything in here is interesting, but it is true, so I guess I stand by it.</p>
<p>I've got a bit more feedback on one of the second drafts.
While I work on figuring out how to act on that feedback, I'm looking over the other second draft, which is at least shorter.
I just sent it over for feedback as well.</p>
<p>The feedback I want is around explaining what this project is, like, for.</p>
<p>Hopefully, I can get this all wrapped up in the next few days.</p>
<p>I had a bit of a rough day.
I just want to get enough rest to finish this up, then get back to working on other things.
(... and also, the next part...)</p>
<p>So, I'll wrap things up here, and take care of a few other things while this publishes.</p>
<p>Good night.</p>
Weekly Roundup 2021-08-172021-08-17T04:00:00-04:002021-08-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-17:/weekly-roundup-2021-08-17<p class="first last">Apparently, my body decided I needed a break and didn't take no for an answer.</p>
<ul class="simple">
<li>Wednesday: I didn't do much because I was tired.</li>
<li>Thursday: I teased, ineffectually, something that should be out in the next week or so.</li>
<li>Friday: I didn't do much because I was tired.</li>
<li>Saturday: I didn't do much because I was high.</li>
<li>Sunday: I started testing out MOTR in earnest. I found some trivial issues in the config file, some major bugs in the actual code, and a vast, screaming maw of insanity in the act of coordinating concurrent file access.</li>
<li>Monday: I started planning how to mitigate those big issues, which break the current configuration, like, every other run, at minimum.</li>
</ul>
<p>Next week, I'm going to get into the home stretch on the secret project in the next few days, hopefully.
After that, I'm going to try to come up with a more reliable MOTR configuration, so I know just what to pull into the application's api library.</p>
Coding 2021-08-162021-08-16T04:00:00-04:002021-08-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-16:/coding-2021-08-16<p class="first last">Representing every interest related to this project is a little confusing, but I think for now I prefer it to the alternatives.</p>
<p>All right, what did I find yesterday?
I found two issues.
One was around installing the package from the current directory.
Something was going really screwy there as a result of other commands running <em>while</em> pip was reading the directory contents.
I still feel like there was no call to try to install a package from a SQLite database, but it is what it is.
The other was that <em>something</em> ended up talking about the paths to <tt class="docutils literal">~ip</tt>, which appears to not be a thing.</p>
<p>I can sort of understand the former, so I'll try to figure out a way around it.</p>
<p>Okay, let's see what makes the most sense...
If I do a <tt class="docutils literal">flit build</tt>, then the build artifacts will be in the <tt class="docutils literal">dist</tt> folder, under a name based on the version, which <a class="reference external" href="https://github.com/takluyver/flit/issues/262">flit currently does not have a command to expose</a>.
If I'm willing to compromise on my vision for MOTR, I can build the artifacts out of band and use stat data to find the newest wheel.
Are there any alternatives?
Well, I may not know the path to the file, but I know the path to the directory.
Can I create an index to add to the install command, with the caveat that this definitely needs to install third-party packages, and that there is a version on PyPI that I don't want to install...
I mean, it looks like <tt class="docutils literal"><span class="pre">--find-links</span></tt> would sort of work with this, except that it would be kind of brittle.
Like, I couldn't run tests against an <em>older</em> version than the current release, and that's not acceptable from a maintenance perspective.
And there are enough sequencing issues even with just using <tt class="docutils literal">dist</tt> that I can't be too comfortable with it.</p>
<p>So, hm, using a direct path or URL to the archive looks like the only way to handle this.
But I think I can still write this in a way that doesn't require determining the version ahead-of-time.
(I want to avoid this because running <tt class="docutils literal">flit build</tt> when I do <tt class="docutils literal">motr <span class="pre">--list-targets</span></tt> seems unexpected.)</p>
<ul class="simple">
<li>Install flit in a venv</li>
<li>Run <tt class="docutils literal">flit build <span class="pre">--format</span> wheel</tt></li>
<li>Inspect <tt class="docutils literal">dist</tt> for the newest file, and write the path as a file url in a <tt class="docutils literal">requirements.txt</tt> type file (This is a custom <tt class="docutils literal">Action</tt>)</li>
<li>Use the path to the requirements file as an <tt class="docutils literal">Input</tt> for the various pip installs, instead of <tt class="docutils literal">.</tt></li>
</ul>
<p>I think that should take care of a bunch of issues, but I still don't know what's with the other error.
The way it's talking about <tt class="docutils literal">__pycache__</tt> directories under <tt class="docutils literal">src</tt> has me hoping that this is somehow also a sequencing issue with running flit through pip, or at least that it has something to do with it.</p>
<p>(Scaling this solution up to my "monorepo-esque" layout would be interesting.
I think the most reasonable way would be to replace the third step with a custom action that essentially handles some of the sequencing itself.
After every install is completed, then the custom action has to retrieve and collate all of the wheel-related data.
It can then store that information in a <em>constraints</em> file.
Properly handling this probably also needs a quick parse of the <tt class="docutils literal">pypyroject.toml</tt> file for each project.
Or maybe the monorepo-esque layout should just expect the project name to match the package name.)</p>
<p>Anyway, good plans for when I'm ready to get back into this.
I've got a few other things I want to take care of tonight, so I'm going to wrap this up now and get to work on those.</p>
<p>Good night.</p>
Coding 2021-08-152021-08-15T04:00:00-04:002021-08-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-15:/coding-2021-08-15<p class="first last">Discovering exciting new problems that I never imagined solving.</p>
<p>Okay, I'm starting on this entry a little earlier than usual, because I couldn't think of a reason not to.
Here's what running MOTR with its repository's prototype file gives me:</p>
<p><tt class="docutils literal">AttributeError: module 'motr.api' has no attribute 'Input'</tt></p>
<p>Let's start dealing with these errors.</p>
<p><tt class="docutils literal"><span class="pre">/api\.Input</span></tt></p>
<p><tt class="docutils literal">[1/14]</tt></p>
<p>Okay...</p>
<p><tt class="docutils literal">AttributeError: module 'motr.api' has no attribute 'add_target'</tt></p>
<p>Uh-huh...</p>
<p><tt class="docutils literal">/add_target</tt></p>
<p><tt class="docutils literal">[1/8]</tt></p>
<p>Cool...</p>
<p><tt class="docutils literal">TypeError: mkdir() missing 1 required positional argument: 'name'</tt></p>
<p>Okay, I'm going to need to refresh my memory on that...</p>
<p>Okay, yeah, I just completely blanked on that part of the API while I was drafting this.</p>
<p><tt class="docutils literal">TypeError: expected str, bytes or os.PathLike object, not Input</tt></p>
<p>Wait, is that... is that a bug?
The error message is kind of vague...</p>
<p><tt class="docutils literal">python <span class="pre">-m</span> pdb <span class="pre">-m</span> motr</tt></p>
<p>That wasn't the right command.</p>
<p><tt class="docutils literal">python <span class="pre">-m</span> pdb (pyenv which motr)</tt></p>
<p><tt class="docutils literal">c</tt></p>
<p>That's better.
Except not much better, because it's not post-mortem-ing when I expect.
So, instead, let's put a breakpoint in the config file (!!!) and run normally...</p>
<p>Okay, let's see... from experimentation, I see that it's only hitting the breakpoint once, so I just need to inspect the first invocation of this function.
I'm not seeing anything too crazy from poking around, it's probably super obvious...
But anyway, let's see how many times we go through the <tt class="docutils literal">cmd</tt> iterator.</p>
<pre class="literal-block">
> /home/maxchase/Documents/synched/motr/motr/motrfile.py(111)run_pytest()
-> api.cmd(
(Pdb) n
> /home/maxchase/Documents/synched/motr/motr/motrfile.py(112)run_pytest()
-> runner + pytest_suffix(junit_file),
(Pdb) n
> /home/maxchase/Documents/synched/motr/motr/motrfile.py(113)run_pytest()
-> f"pytest-{env_name}",
(Pdb) n
> /home/maxchase/Documents/synched/motr/motr/motrfile.py(114)run_pytest()
-> report_dir,
(Pdb) n
> /home/maxchase/Documents/synched/motr/motr/motrfile.py(111)run_pytest()
-> api.cmd(
(Pdb) n
> /home/maxchase/Documents/synched/motr/motr/motrfile.py(115)run_pytest()
-> *test_extra_inputs,
(Pdb) n
> /home/maxchase/Documents/synched/motr/motr/motrfile.py(111)run_pytest()
-> api.cmd(
(Pdb) n
> /home/maxchase/Documents/synched/motr/motr/motrfile.py(116)run_pytest()
-> allowed_codes=[1],
(Pdb) n
> /home/maxchase/Documents/synched/motr/motr/motrfile.py(111)run_pytest()
-> api.cmd(
(Pdb) n
> /home/maxchase/Documents/synched/motr/motr/motrfile.py(110)run_pytest()
-> yield from (
(Pdb) n
TypeError: expected str, bytes or os.PathLike object, not Input
</pre>
<p>All right, let's do that again...</p>
<p>After far too much effort, I have isolated the value that it's choking on: <tt class="docutils literal"><span class="pre">Input(path=PosixPath('reports/pytest'))</span></tt></p>
<p>Which allows me to finally narrow it down to an argument type error in the motrfile.
That could have definitely signalled things to me better.
I think my best bet is to wrap the error in the coercion function.
I should probably also have error checking at the top-level code that users are supposed to invoke.</p>
<p>And, running it again, I got the same error, but from a different line of the config file.</p>
<p>And, fixing that, I find... this looks like an actual bug.
Got all the way through config, and then something acted up in the <tt class="docutils literal">Cmd</tt> class.
Looks like I forgot to make some of the required directories exist.</p>
<p>So, I fixed that bug, and I'll bundle that into the 0.1.1 release.
Next issues: failed to set up dependencies in the motrfile, and then fixing that broke something else...
Or maybe I didn't fix it...
This is confusing.</p>
<p><tt class="docutils literal">: No module named venv</tt></p>
<p>... What.</p>
<p>Okay, let's rewrite the references to <tt class="docutils literal">python</tt> to <tt class="docutils literal">sys.executable</tt>.</p>
<p>All right, that worked.
Ish.</p>
<p>Then, I had to add a message to one of the exceptions I was raising.
I'm not sure what happened in the run after that, I think it might have run into synchronization issues because I never disabled synching on the directory, so, I'll do that in a sec.</p>
<p>And now it... um... after I fixed a frankly embarrassing bug in uncovered code, now it is... sometimes... failing... because paths to <tt class="docutils literal">pip</tt> are sometimes paths to <tt class="docutils literal">~ip</tt>.</p>
<p>I'd love to know which ghost I angered to make <em>that</em> happen.</p>
<p>But anyway, it runs, sometimes.
Unless it does</p>
<p><tt class="docutils literal">ERROR: Could not install packages due to an OSError: <span class="pre">[('/home/maxchase/Documents/synched/motr/motr/.coverage',</span> <span class="pre">'/tmp/pip-req-build-oeiz90rh/.coverage',</span> "[Errno 2] No such file or directory: <span class="pre">'/home/maxchase/Documents/synched/motr/motr/.coverage'")]</span></tt></p>
<p>That.</p>
<p>Why is it trying to install the coverage data file?</p>
<p>Actually, I think I understand, but... really, I don't deserve this synchronization issue.</p>
<p>Anyway, when it... works, it says it runs sub-20 seconds.
Now, I'm sure it can do better performance-wise, but first it needs to do better correctness-wise.</p>
<p>But, I'm not going to figure that out tonight.
However, the code technically <em>can</em> run at this point, at least on my machine, so I pushed out a new version.
Now everyone gets to sort of, sometimes, run this thing's tests against itself.</p>
<p>I don't want to think about this any more tonight.</p>
<p>Good night.</p>
Diary 2021-08-142021-08-14T04:00:00-04:002021-08-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-14:/diary-2021-08-14<p class="first last">I don't know, I'm just really relaxed. It's nice :)</p>
<p>I still don't have much to say about what's going on, but I guess I'm more mellow about it.</p>
<p>Tomorrow, it's either back to MOTR, or hopefully finally getting another round of feedback on the other project.</p>
<p>It'll be nice to focus on my own projects, once I have the time and energy.</p>
<p>Good night.</p>
Diary 2021-08-132021-08-13T04:00:00-04:002021-08-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-13:/diary-2021-08-13<p class="first last">This is a theme.</p>
<p>I'm once again tired and vaguely sore.</p>
<p>I thought for sure I was going to come up with something else to put here, in the time between writing that sentence and this one, but I guess not.</p>
<p>Stuff is definitely going to happen in a week or so, but I've got nothing currently.</p>
<p>Good night.</p>
Sneak Peek 2021-08-122021-08-12T04:00:00-04:002021-08-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-12:/sneak-peek-2021-08-12<p class="first last">Taking it easy until work manages to chill out.</p>
<p>Second draft of the secret project is out for review.
The changes there were around trying to phrase things more clearly, such as by</p>
<ul class="simple">
<li>Using shorter sentences.</li>
<li>Breaking up paragraphs.</li>
<li>Not using unexplained notation.</li>
<li>Spacing out my ideas over more sentences.</li>
</ul>
<p>Hopefully this should bring the overall level of knowledge required to read this much, much lower.</p>
<p>I sat around a bunch to see if I had anything more to say on this, and I guess I don't.
I should wrap up for now.</p>
<p>Good night.</p>
Diary 2021-08-112021-08-11T04:00:00-04:002021-08-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-11:/diary-2021-08-11<p class="first last">Ugh, tired again...</p>
<p>Okay, I am tired right now.
I'm going to have to take things easy for a while.</p>
<p>I'm getting the itch to work on conlanging or worldbuilding again, but I really want to get this other project squared away first.</p>
<p>With luck, this project should be done in a week, and I think work should finally calm down around then as well, though I seem to remember thinking similar things before...</p>
<p>Anyway, I should take things easy for now.</p>
<p>Good night.</p>
Weekly Roundup 2021-08-102021-08-10T04:00:00-04:002021-08-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-10:/weekly-roundup-2021-08-10<p class="first last">Oh yeah, it's all coming together.</p>
<ul class="simple">
<li>Wednesday: I started planning stylesheet updates to the blog, for an upcoming project.</li>
<li>Thursday: I talked about the kind of stuff I'll need for the project.</li>
<li>Friday: I got the first draft of the diagrams done, and planned out the rest of the project.</li>
<li>Saturday: I reworked the diagrams some as a result of actually trying to use them.</li>
<li>Sunday: I updated the stylesheet to add night mode and various facilities for interacting with the diagrams. This all went <em>so well</em> that I updated the stylesheet <em>again</em> the next day.</li>
<li>Monday: I released MOTR, which is not currently... good... but having it out there makes it feel more real.</li>
</ul>
<p>Next week, I'll hopefully get any required polish for the project, so I can get it in like a week early or so.
Once (or during) that's sorted out, I'll iterate some on MOTR.
There's some other coding stuff that I may work on in the genre of "I can do this, and that is the most compelling reason I have to work on it, apparently".</p>
Coding 2021-08-092021-08-09T04:00:00-04:002021-08-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-09:/coding-2021-08-09<p class="first last">Not releasing it because I think it's any good yet, but because I want to try actually using it instead of endlessly polishing it beforehand.</p>
<p>All right, now I'll stop being cagey about the task runner's name.
It is <a class="reference external" href="https://pypi.org/project/motr/">MOTR</a>, short for Max's Obvious Task Runner, though I'll probably flip-flop about whether the O should stand for "Obvious" or "Opinionated".
In any case, the naming is via a slight corruption of the <a class="reference external" href="https://www.boringcactus.com/2021/03/21/coins.html">COINS</a> concept, because I wanted it to be as close to "motor" as possible, and I thought "MOOTR, but pronounce it like it's a German web 2.0 startup" was too far.
And I didn't have any good alternative adjectives in mind.</p>
<p>Now, you'd be forgiven for thinking that, because I released this, I think it has a chance of being useful to anyone in its current state, least of all myself.
My goal here is to get my prototype "motrfile" to a stage where it's capable of running MOTR's own tests and diagnostics.
Then, I'll cut a source release.
At that point, I'll get to work addressing the various issues standing in the way of version 1.0:</p>
<ul class="simple">
<li>Incomplete test coverage.</li>
<li>Non-existent documentation.</li>
<li>Features implemented in motrfile instead of the app.</li>
<li>Features implemented inelegantly.</li>
<li>Some of the code I wrote is kind of disorganized and tangled-up.</li>
</ul>
<p>Anyway, I'm starting this post early.
I'll take a break for now and come back to it tonight.</p>
<p>All right, right off the bat it's failing, and the failure looks, I think, more or less how I want it to at this level.</p>
<div class="highlight"><pre><span></span><span class="x">MOTRError > The MOTRfile at /home/maxchase/Documents/synched/motr/motr/motrfile.py encountered the following exception:</span>
<span class="gt">Traceback (most recent call last):</span>
File <span class="nb">"/home/maxchase/.pyenv/versions/3.9.4/envs/motr-dev/lib/python3.9/site-packages/motr/controllers/base.py"</span>, line <span class="m">127</span>, in <span class="n">_default</span>
<span class="w"> </span><span class="n">exec</span><span class="p">(</span><span class="n">compiled_code</span><span class="p">,</span> <span class="n">motr_globals</span><span class="p">)</span>
File <span class="nb">"/home/maxchase/Documents/synched/motr/motr/motrfile.py"</span>, line <span class="m">252</span>, in <span class="n"><module></span>
<span class="w"> </span><span class="n">MOTR_CONFIG</span> <span class="o">=</span> <span class="n">api</span><span class="o">.</span><span class="n">build</span><span class="p">(</span><span class="n">changes</span><span class="p">())</span>
File <span class="nb">"/home/maxchase/.pyenv/versions/3.9.4/envs/motr-dev/lib/python3.9/site-packages/motr/_api/build.py"</span>, line <span class="m">9</span>, in <span class="n">build</span>
<span class="w"> </span><span class="k">for</span> <span class="n">requirement</span> <span class="ow">in</span> <span class="n">requirements</span><span class="p">:</span>
File <span class="nb">"/home/maxchase/Documents/synched/motr/motr/motrfile.py"</span>, line <span class="m">133</span>, in <span class="n">changes</span>
<span class="w"> </span><span class="n">flake8_report_dir</span> <span class="o">=</span> <span class="n">api</span><span class="o">.</span><span class="n">Input</span><span class="p">(</span><span class="n">reports_dir</span> <span class="o">/</span> <span class="s2">"flake8"</span><span class="p">)</span>
<span class="gr">AttributeError</span>: <span class="n">module 'motr.api' has no attribute 'Input'</span>
</pre></div>
<p>This error is a consequence of the actual application pulling ahead of the prototype motrfile.
I confess I'm not sure whether I should change the motrfile to retrieve the class from the "correct" module, or re-do the export to make <tt class="docutils literal">Input</tt> explicitly part of the api surface.</p>
<p>Thinking about this, I think I want to divide the <tt class="docutils literal">api</tt> module into different "levels".
Like, ideally, you should be able to work with high-level prefab stuff (which... isn't written yet), and have the option to drop down to lower levels of abstraction to write similar but different high-level abstractions.</p>
<p>I don't want to rush into this, so I'm going to sleep on it for now and get back to the other "secret" project.</p>
<p>(Probably the right thing to do to start with is to fit the motrfile to the current interfaces, so I can tell which bits most need to change.)
Anyway, that's enough planning for now.</p>
<p>Good night.</p>
Site Design 2021-08-082021-08-08T04:00:00-04:002021-08-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-08:/site-design-2021-08-08<p class="first last">Planning and research pays off. As well as testing.</p>
<p>Stylesheet is updated, and I made a few tweaks to the templates since I'm re-uploading literally every page anyway.
The most obvious change is that the page now queries for dark mode preference.
There are some extremely minor tweaks to navigation templating on the index pages.
Lastly, every change I think I'll need for the secret project is in there.
If you're really curious, you could try to, like, data mine the CSS or the SCSS files.</p>
<p>I haven't actually checked whether <em>light mode</em> still works because I'm being lazy, but, like, it's probably fine.
(Please contact me via the Mastodon account below if something is, in fact, not fine, or if you have any suggestions.
Or, questions?
I'm not sure what questions I can field beyond "Why the heck did you do such-and-such thing like <em>that</em>?")</p>
<p>Anyway, I'm going to publish this and then see if there are any show-stopping issues preventing the task runner code from releasing as 0.1.0.
I'll get back to this in a few days.</p>
<p>Good night.</p>
Sneak Peek 2021-08-072021-08-07T04:00:00-04:002021-08-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-07:/sneak-peek-2021-08-07<p class="first last">I'm sorry to anyone who downloads the SVG of the figures, and gets slapped in the face with nonsense.</p>
<p>Okay, slight changes of plans.
I figured out how to make inline svg stuff work with the structure of my figures file, <em>mostly</em>.
I did have to reorganize and resize the diagrams, because I'm too lazy to specify viewport information (it's the difference between putting the same few numbers into the document and being done with it, and squinting at the arbitrary weirdness that pops out of positioning these elements by hand), but that wasn't too bad.
Thinking about what comes next, it's probably best for me to get a draft put together now, so I can have something to look at while I iterate over the stylesheet changes.</p>
<p>I'll do that in the morning, because apparently the diagram-rearrangement, while not especially hard, was somewhat time-consuming.</p>
<p>I'm also planning to release the, like, pre-pre-pre-pre-pre-pre-pre-pre-pre-alpha of the task runner tomorrow, so that'll be... interesting.</p>
<p>I'd better get some sleep so I can face the tasks I set for myself.</p>
<p>Good night.</p>
Sneak Peek 2021-08-062021-08-06T04:00:00-04:002021-08-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-06:/sneak-peek-2021-08-06<p class="first last">That was some good zoning-out-in-front-of-Inkscape time.</p>
<p>I believe I have all diagrams basically put together.
They're kind of janky, but it's better to push ahead than to tweak them right now.
If I have time, I'll rework them.
The steps to follow now:</p>
<ul class="simple">
<li>Create files to <tt class="docutils literal"><use/></tt> each diagram. I wanted to believe I could just trivially inline this into the article so I don't need two dozen tiny, nearly-identical files, but I put in the effort testing ways to do that, and I failed, so, again, going to prioritize getting ahead for now.</li>
<li>Update the stylesheets. Timeboxed to two days. Hopefully done in one.</li>
<li>Draft the post, spot check any obvious issues.</li>
<li>Show to my wife for review.</li>
<li>Frantic editing pass.</li>
<li>Lock content, renew polish.</li>
<li>Post intro.</li>
<li>Post first post proper.</li>
</ul>
<p>Okay, I want to be done for tonight, and I'm too tired to decide how to end this, so I'm once again going to just slam headlong into the end of the post.</p>
<p>Good night.</p>
Sneak Peek 2021-08-052021-08-05T04:00:00-04:002021-08-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-05:/sneak-peek-2021-08-05<p class="first last">Hopefully I'll be in a very different place on this in a week or so.</p>
<p>(I'll link into the new category from the last Sneak Peek for it, once I start posting in it.)</p>
<p>So, I put together a few more diagrams for the project that I need to finish in... basically two weeks.
This is going to be interesting.</p>
<p>I wish I'd realized earlier how well Inkscape fits with the kind of visual editing that I've wanted to do.
It's so nice to just drop into the XML and edit it directly, which is probably a sentence that nobody has said before.</p>
<p>Let's take a quick low-spoiler tour of the diagram elements I still need to make:</p>
<ul class="simple">
<li>A square with a dashed outline.</li>
<li>The letters "A", "B", "C", and "D".</li>
<li>An existing diagram element with those letters attached to the points.</li>
<li>A gridded square with two sides labeled by those letters.</li>
<li>A diagonal line</li>
<li>An existing diagram element, mirrored and with part of it colored differently.</li>
</ul>
<p>That all should be pretty manageable if I just take an afternoon to work on it rather than doing it literally the last thing before I go to bed.</p>
<p>Speaking of which...</p>
<p>Good night.</p>
Site Design 2021-08-042021-08-04T04:00:00-04:002021-08-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-04:/site-design-2021-08-04<p class="first last">How do people feel about BEM at this point? Wait, no, I don't think I actually care.</p>
<p>Oh wow, this is all kinds of a blast from the past.
I used to tell you what was in the post before you read it.
What decadence.</p>
<p>Anyway, I'm breaking out this old category because I need to touch my CSS definitions again for a few reasons.</p>
<p>One reason is that I want to support <tt class="docutils literal"><span class="pre">prefers-color-scheme</span></tt> so my wife can look at this site without her night mode extension turning the background a weird brown color.</p>
<p>The follow-on reason is, one of the projects I'm working on is going to need a bunch of diagrams to illustrate its concepts, and if <tt class="docutils literal"><span class="pre">prefers-color-scheme</span></tt> is in place, those diagrams need to handle that.
And I think the easiest (for some value of "easiest") way for me to handle that is to use svg files for the diagrams, and add classes to them so I can style them with the site CSS.</p>
<p>(Get ready for a <tt class="docutils literal">fun</tt> time, Neocities!
My site generator forces cache invalidation of stylesheets by changing the link in the generated pages, so I'm going to need to re-upload <em>my entire blog</em> when I update the style.
As such, I want to make sure I have this <em>right</em> before I push it.)</p>
<p>Here are my notes on this so far:</p>
<ul class="simple">
<li>I've got two placeholders to handle different-colored areas of the screen, <tt class="docutils literal">%light</tt> and <tt class="docutils literal">%dark</tt>. In practice, they aren't accomplishing much, because each one is used just once, and in one case there's a nested modifier style that specifically expects to be under <tt class="docutils literal">%dark</tt>. I think a more correct way to handle this would be to have "main"/"inverse", ""/"emphasized", "text"/"background" variables that are populated by media selectors.</li>
<li>I want to add a new <tt class="docutils literal">figure</tt> block, with <tt class="docutils literal">shape</tt> elements, and modifiers like <tt class="docutils literal">background</tt>, <tt class="docutils literal"><span class="pre">fill-red</span></tt>, <tt class="docutils literal"><span class="pre">stroke-blue</span></tt>, <tt class="docutils literal">emphasized</tt>. I may rework this scheme a bit, we'll see.</li>
</ul>
<p>To be honest, I'll probably table this for now and focus on the content for the posts that will need this, because if I finish the post but not the CSS by the deadline, it'll look a little bad but be readable, but if it's the other way around, then the post won't exist.
I think the one thing I want to work out is the division of elements, because I need to mark up the svg file by hand to have the class data.</p>
<p>I'll think about that for a bit after I publish this.
Which I want to do now, so I don't have an excuse to be up super late.</p>
<p>(PS: Just decided it should be <tt class="docutils literal">line</tt> and <tt class="docutils literal">fill</tt> elements, and <tt class="docutils literal">emphasized</tt> can only apply to <tt class="docutils literal">line</tt> elements.
That doesn't quite nail down everything, but it's a start.)</p>
<p>Good night.</p>
Weekly Roundup 2021-08-032021-08-03T04:00:00-04:002021-08-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-03:/weekly-roundup-2021-08-03<p class="first last">If I don't ship this, it basically doesn't exist, so... I'll get on that this week.</p>
<ul class="simple">
<li>Wednesday: I started trying to work out how to support multiple Python versions, and came up with a solution that I didn't quite like.</li>
<li>Thursday: I took a break from the task runner. Focused on some other projects and code.</li>
<li>Friday: I described some of code I was messing with. I didn't put the code up because I couldn't convince myself it all works properly.</li>
<li>Saturday: I started to refactor the task runner internals so the names make more sense.</li>
<li>Sunday: I finished and explained the refactoring.</li>
<li>Monday: I looked over the way the config prototype handles virtual environments, and found it lacking.</li>
</ul>
<p>Next week, I'm going to keep on focusing on the secret project: creating diagrams and doing editing passes, as well as filling in one last section.
Over the weekend, I'm going to clean up the task runner config prototype, and then publish an 0.1.0 version.
The higher-level interfaces basically don't exist, but I've decided that if I can prove that it's <em>possible</em> to usefully run this code, that's good enough for an initial release.</p>
Coding 2021-08-022021-08-02T04:00:00-04:002021-08-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-02:/coding-2021-08-02<p class="first last">I could imagine years-long-arguments over some of the stuff I'm deliberating over. Software development does things to people.</p>
<p>I mostly took things easy today, did some work just now on one of my secret-ish projects.</p>
<p>Anyway, yesterday I mentioned not being happy with the <tt class="docutils literal">Venv</tt> class in the configuration prototype.
That is because of its public interface.
It has four functions:</p>
<ul class="simple">
<li><tt class="docutils literal">create()</tt></li>
<li><tt class="docutils literal">update()</tt></li>
<li><tt class="docutils literal"><span class="pre">install(*args)</span></tt></li>
<li><tt class="docutils literal">command(cmd)</tt></li>
</ul>
<p>And it only makes sense to call them in that exact order.
(Basically, the filesystem is acting as hidden global state.)
At the same time, there are reasons to want to vary some of these calls.</p>
<p>Here's what I want for each stage, more or less:</p>
<ul class="simple">
<li>Creation: this should have access to a <tt class="docutils literal">root</tt> global, a path value that, in future, should be possible to change for the duration of an app execution; it should have access to a unique name; it should have access to an optional Python version string; these two should be combined into a name that is used for any <tt class="docutils literal">Action</tt>s, and this name should combine with the root to create a path object pointing to a bin dir.</li>
<li>Updating: this needs access to the action name and the bin dir from the previous step; it should produce the path to pip, alongside the action name and bin dir.</li>
<li>Installation: this uses the action name and the pip path; it should produce the bin dir and the name of its <tt class="docutils literal">Action</tt>.</li>
<li>Command registration: this uses the bin dir and the name of the installation action.</li>
</ul>
<p>From this, I can put together a rough sketch of helpful data types:</p>
<ul class="simple">
<li><tt class="docutils literal">CreationResult</tt> with fields for "action name" and "bin dir"</li>
<li><tt class="docutils literal">UpdateResult</tt> with fields for <tt class="docutils literal">CreationResult</tt> and "pip path"</li>
<li><tt class="docutils literal">InstallationResult</tt> with fields for, either "bin dir" and specific action name, or specific action name and <tt class="docutils literal">CreationResult</tt></li>
</ul>
<p>I'm unsure which of those last options makes more sense.
I don't want to move forward on this until I have an answer that I find satisfying.</p>
<p>Anyway, I don't want to let things go any later, I'm pushing myself as is.</p>
<p>Good night.</p>
Coding 2021-08-012021-08-01T04:00:00-04:002021-08-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-08-01:/coding-2021-08-01<p class="first last">And introducing: Me, but using smilies in a somewhat unsettling manner!</p>
<p>I finished the refactoring/rewrite from yesterday, and now I'm not quite sure what I want to work on next.
As such, I think I'll take a bit more of a break, and try to review everything that's in the code with fresh eyes when I get back to it.</p>
<p>Hm, I've got time, I might as well try to describe what I did.</p>
<p>So, the original interface for the <tt class="docutils literal">Registry</tt> objects was a collection of fluent methods that took some set of arguments (with varying aspects of optional and variable arguments).
My goal, which I've stuck to, was to abstract out the <tt class="docutils literal">Registry</tt> object from the act of modifying it.
I defined several helper classes that carry minimal amounts of data, and wrote private handler methods to convert instances of helper methods into a modification of the <tt class="docutils literal">Registry</tt> object.
I then used <tt class="docutils literal">singledispatchmethod</tt> to collapse the private handlers into a single public fluent interface.
However, the existence of this fluent method is an implementation detail, and the intended public interface is to use a <tt class="docutils literal">build</tt> function that accepts an iterable of objects that can be passed to the fluent method, and applies them in order.
The private helpers are on the class, because it's their responsibility to maintain the class invariants.
(For example, there can't be cycles, because I'm pretty sure a cycle would deadlock the application.)</p>
<p>The key thing I changed was to stop talking about the helper classes as <tt class="docutils literal">Change</tt>s, and calling the fluent function <tt class="docutils literal">change</tt>.
Now, they're <tt class="docutils literal">Requirement</tt>s and <tt class="docutils literal">require</tt>.
The main problem with the original names was that, to the extent that they communicated anything, what they communicated was kind of wrong.</p>
<blockquote>
<p>What are they?</p>
<p>They're changes to the registry.</p>
<p>What kind of changes to the registry?</p>
<p>The kinds of changes that can be made to the registry :)</p>
<p>So, if I change the registry with a change, then I get a different registry?</p>
<p>Usually :)</p>
</blockquote>
<p>In other words, they're an unspecified kind of change, that doesn't always change things.
The name <tt class="docutils literal">Requirement</tt> is somewhat more precise, in that most of them describe some form of dependency link between different types of object.
And the name <tt class="docutils literal">require</tt> makes it at least somewhat clear that this is about imposing a requirement, not changing state <em>per se</em>.
If you need eggs and then you need eggs, then you still need eggs, you know?</p>
<p>I also renamed the <tt class="docutils literal">Requirement</tt> classes to basically be a sequence of nouns describing their fields, rather than a verb phrase.
So, <tt class="docutils literal">ActionName</tt> instead of <tt class="docutils literal">AddAction</tt>, <tt class="docutils literal">ActionOutput</tt> instead of <tt class="docutils literal">AddTarget</tt>, <tt class="docutils literal">ActionInput</tt> instead of <tt class="docutils literal">AddInput</tt>, <tt class="docutils literal">TargetName</tt> instead of <tt class="docutils literal">NameTarget</tt>, and <tt class="docutils literal">SkippedName</tt> instead of <tt class="docutils literal">SkipName</tt>.</p>
<p>Honestly, naming things sucks so much that I'm in no way sure if these new names are <em>good</em>, but I'm pretty confident they're <em>better</em>.
There is a bit of weirdness in that, outside of <tt class="docutils literal">ActionName</tt>, <tt class="docutils literal">Action</tt> refers to the <tt class="docutils literal">Name</tt> part of <tt class="docutils literal">ActionName</tt>.
Still, they're better than what I had before; maybe I'll come up with some further improvement; we'll see.</p>
<p>Oh, also, I'm a big fan of the high-level noun and verb being merely morphologically related, rather than just <em>the exact same word</em>.</p>
<p>Anyway, <em>probably</em> the next thing I should work on is the virtual environment creation primitive.
I'm not quite happy with what the prototype has going on, where I tried to make the individual functions limited in scope, but it honestly only makes sense to call them in one order.
Maybe I can work out some form of chained evaluation that makes things a little clearer.</p>
<p>I'll come back to this idea later.
For now, I should get ready for bed.</p>
<p>Good night.</p>
Coding 2021-07-312021-07-31T04:00:00-04:002021-07-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-31:/coding-2021-07-31<p class="first last">At least I'm enjoying myself.</p>
<p>Quick entry today because I got distracted refactoring the task runner internals so the names make more sense.</p>
<p>What did I do?
Well, I... I refactored the task runner internals so the names make more sense.
To be precise, I <em>started</em>.
I'm not done fixing the types, and I'll definitely need to tweak the tests to some degree.</p>
<p>Anyway, I don't want to dawdle, this is already late.</p>
<p>Good night.</p>
Diary 2021-07-302021-07-30T04:00:00-04:002021-07-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-30:/diary-2021-07-30<p class="first last">I don't know if the labels I put on these really mean anything at this point...</p>
<p>Work is a little calmer (<em>for now</em>), so I'm... doing better.
I need to stand up more, lest I mess up my torso muscles.
Or torso something.
Predictable surface-level chest pains, eugh.</p>
<p>Anyway, I spent some time today messing with the code I was talking about earlier.
The basic idea was to try to code the <a class="reference external" href="https://marctenbosch.com/quaternions/">geometric product</a> concept in Python in a way that used very little code.
I ran into a few issues, which I'll lay out after I explain the basic principle.</p>
<p>So, something that becomes clear from reading that article is, once you have the basis (uni?)vectors for a space, then the higher- and lower- dimensional bases will either contain a given basis vector or will not, and this partitions the bases in half as many times as there are basis vectors.
One way to act on this division is to divide them into groups of "does not contain the last basis" and "does contain the last basis".
But this process can be repeated until it's just dividing two numbers from each other, based on whether they're associated with the first basis.</p>
<p>I represented this in code with a class that represents such a basis division, and therefore contains two objects of identical type, the first being "everything that does not contain the relevant basis vector", and the second being "everything that does".
So, the second element is effectively multiplied at the end by a basis that comes after every element it contains, and therefore doesn't need to negate anything.</p>
<p>Getting this object to multiply requires the definition of a function that negates every sub-element associated with an odd number of basis vectors.
I think.
One of the obstacles I hit was that it's kind of hard to reason, first about what this code should even do for even very basic cases, and second, how to scale it up arbitrarily.
It golfed the code to make it negate the vector component at the same level, then <em>subtract</em> the result in the actual multiplication.
(So the more dot-product-y part of the multiplication is a <em>difference</em> of products...)</p>
<p>I imagine that didn't make too much sense.
Part of the problem with all of this is that, currently, I'm not sure I understand the concepts I'm trying to represent well enough to evaluate my representation.
The 3-vector multiplication example from Marc ten Bosch's article does come through properly, which is encouraging.</p>
<p>The final issue I have with all of this is how incredibly sparse the general representation is.
A non-generic representation for 3-vectors requires eight "leaves" for all data, while a specialized representation requires three leaves for vectors and four leaves for rotors.
So, this is acceptable for prototyping, though the possibilities of extending it into higher dimensions are kind of slowed down by the exponential blowup in memory consumption.
(Even if the leaves are mostly memoized, there's still the intermediate nodes to contend with, unless those are also memoized.)</p>
<p>After I said all that, though, I something occurred to me.
It seems to me unreasonable to expect a statically typed, compiled language to specialize a concrete type based on the specific values it contains, but what if the specialized types were user-generated, but delegated their implementations to the generic version?
Then, <em>potentially</em>, inlining and constant propagation could essentially destructure the generic types into data flows at compile time, generating a correct implementation of geometric algebra operations for the specific types, without needing any specifically-written arithmetic.
This sounds like a neat trick, and I'd imagine someone has already tried something along these lines, and maybe gotten it to work.</p>
<p>I'll have to poke around with that more later, but I should wrap up for now.
Eh, it's all set, best get to bed.</p>
<p>Good night.</p>
Diary 2021-07-292021-07-29T04:00:00-04:002021-07-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-29:/diary-2021-07-29<p class="first last">Things continue to suck, but maybe some of these external conditions will turn around?</p>
<p>I've got a definite feeling I should take a break from the task runner stuff.
I don't know where I am in terms of burnout, but some kind of instinct is kicking in, and I'm trying to listen to it.</p>
<p>I don't know, it's this... feeling of a haze?
I guess?
Somehow, these mental states feel like something.
Like a physical sensation.</p>
<p>Anyway, to have something to do, I'm focusing on the secret project, which is writing with somewhat of a deadline.
I'm closing in on the end of the rough draft, after which I'll start working on illustrations and start doing editing passes.
It feels so strange to get back into doing this sort of thing, but I'm interested to see where it goes.</p>
<p>Some of the stuff I was thinking about related to this project inspired me to think about some coding stuff very different from the task runner, so I messed with that a bit, and my initial prototypes completely failed, so that's interesting.
I have some guesses about how I might fix it, but I need to do some working-out on paper before I try anything else.
I'll mess with that after this entry publishes, which I should do ASAP.</p>
<p>This is the end of the blog post.</p>
<p>Good night.</p>
Coding 2021-07-282021-07-28T04:00:00-04:002021-07-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-28:/coding-2021-07-28<p class="first last">Software that might end up being situated just because it turns out nobody else feels like trying to learn it...</p>
<p>As I thought more and more about how to handle multiple Python versions, I realized that I needed a concrete example to really ground things.
So, I'm going to take the previous code, strip the comments out, and try to figure out the "proper" way to extend it for multiple versions.</p>
<div class="highlight"><pre><span></span><span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Flake8HTML</span><span class="p">:</span>
<span class="n">additional_args</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span>
<span class="n">python_versions</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">typing</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span> <span class="o">...</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="kc">None</span><span class="p">,)</span> <span class="c1"># For checking syntax changes across Python versions, I guess.</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">projects</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Project</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s2">""</span><span class="p">:</span> <span class="n">ROOT</span><span class="p">})</span> <span class="o">-></span> <span class="n">ChangeStream</span><span class="p">:</span>
<span class="k">for</span> <span class="n">version</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">python_versions</span><span class="p">:</span>
<span class="n">report_dir</span> <span class="o">=</span> <span class="n">REPORTS</span> <span class="o">/</span> <span class="s2">"flake8"</span>
<span class="k">if</span> <span class="n">version</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">report_dir</span> <span class="o">/=</span> <span class="n">version</span>
<span class="n">flake8</span> <span class="o">=</span> <span class="k">yield from</span> <span class="n">venv_wrapper</span><span class="p">(</span><span class="s2">"check"</span><span class="p">,</span> <span class="s2">"flake8"</span><span class="p">,</span> <span class="s2">"check"</span><span class="p">,</span> <span class="n">python</span><span class="o">=</span><span class="n">version</span><span class="p">)</span>
<span class="k">for</span> <span class="n">project</span> <span class="ow">in</span> <span class="n">projects</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
<span class="n">project_report_dir</span> <span class="o">=</span> <span class="n">project</span><span class="o">.</span><span class="n">suffix</span><span class="p">(</span><span class="n">report_dir</span><span class="p">)</span>
<span class="n">project_report_file</span> <span class="o">=</span> <span class="n">project_report_dir</span><span class="o">.</span><span class="n">path</span> <span class="o">/</span> <span class="s2">"index.html"</span>
<span class="n">action_name</span> <span class="o">=</span> <span class="n">project</span><span class="o">.</span><span class="n">prefix</span><span class="p">(</span><span class="s2">"check"</span><span class="p">)</span>
<span class="k">yield from</span> <span class="n">mkdir</span><span class="p">(</span><span class="n">project_report_dir</span><span class="p">)</span>
<span class="k">yield from</span> <span class="n">cmd</span><span class="p">(</span>
<span class="p">[</span>
<span class="n">flake8</span><span class="p">,</span>
<span class="s2">"--format=html"</span><span class="p">,</span>
<span class="s2">"--htmldir"</span><span class="p">,</span>
<span class="n">project_report_dir</span><span class="p">,</span>
<span class="o">*</span><span class="bp">self</span><span class="o">.</span><span class="n">additional_args</span><span class="p">,</span>
<span class="n">project</span><span class="o">.</span><span class="n">prefix</span><span class="p">(</span><span class="s2">"src"</span><span class="p">),</span>
<span class="n">project</span><span class="o">.</span><span class="n">prefix</span><span class="p">(</span><span class="s2">"tests"</span><span class="p">),</span>
<span class="p">],</span>
<span class="n">action_name</span><span class="p">,</span>
<span class="n">allowed_codes</span><span class="o">=</span><span class="p">{</span><span class="mi">1</span><span class="p">},</span>
<span class="p">)</span>
<span class="k">yield from</span> <span class="n">add_target</span><span class="p">(</span><span class="n">project_report_file</span><span class="p">,</span> <span class="n">action_name</span><span class="p">,</span> <span class="s2">"check"</span><span class="p">)</span>
</pre></div>
<p>Most of the code is the same, but the differences are instructive.
Because I'm generating a separate set of reports for each Python version, I can't do something like dependency-inject the virtual environment creation step, because then a bunch of registry entries collide.
It's a little unfortunate that there's no "generic" way to specify Python versions, but something like a coverage run is going to invoke different environments at different "stages", and it's not clear to me how to separate that out, unless...</p>
<p>I just drew some inspiration from the fact that some of my projects use my <tt class="docutils literal"><span class="pre">limit-coverage</span></tt> tool and some don't.
So, maybe I want to decompose some of these complicated runs into specialized types that nest each other in a carefully chosen way.
If I enforce an idea of one (lexical) environment call per type, then however I specify the Python environment is unambiguous as to what it refers to.
Because the projects should be the same over the course of a call, but each thing handling the call can vary its environments, I think what I want is to standardize on an attribute for everything containing a (lexical) call, or maybe some kind of accessor function?
I'll have to try this out later, when I'm not wiped out from traveling or apprehensive about work.</p>
<p>It's pretty instructive how many of the ideas I had when I was thinking about "supporting multiple Python versions" in abstract terms, proved too unworkable to bother prototyping, when I took a look at actual (-ish) code.</p>
<p>I don't know when I'll be up for working on this again, so I think I should make myself take a break, at least until work calms down a little.</p>
<p>(But wait, if the "correct" implementation at that point is always a big for loop, then it should just be taking a single version, and the for loop should be lifted out to... somewhere.
Or the version should be made part of the call interface, and then there's a wrapper type that composes a list of versions to make it more session-y.
I guess I'm not done thinking about this.)</p>
<p>Good night.</p>
Weekly Roundup 2021-07-272021-07-27T04:00:00-04:002021-07-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-27:/weekly-roundup-2021-07-27<p class="first last">Getting into the useful but sometimes-boring bits of this work...</p>
<ul class="simple">
<li>Wednesday: I made the imports in the task runner code consistent. I'm still not sure if I <em>like</em> the result, but it's consistent. I worked on some further factoring-out to make it easier to rewrite the <tt class="docutils literal">Registry</tt> again if I need to.</li>
<li>Thursday: I did some late night refactoring. I don't actually remember, but I'm pretty sure I regretted it in the morning.</li>
<li>Friday: I figured out how to separate the codebase into layers.</li>
<li>Saturday: I was generally tired after a few hours on the road, and then had to deal with, well, rural internet infrastructure.</li>
<li>Sunday: I didn't get much concrete done, but I did start planning the initial layering.</li>
<li>Monday: I put together a "basic" class prototype for the higher-level constructs. I don't know what anyone else thinks of it.</li>
</ul>
<p>Next week, I'm going to try to push ahead with this, but there are a few other things that might end up being easier for me to work on.
We'll see.</p>
Coding 2021-07-262021-07-26T04:00:00-04:002021-07-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-26:/coding-2021-07-26<p class="first last">Code samples that either cause everything I've been talking about to make much more, or much less, sense.</p>
<p>Okay, let's try to speedrun this post and go back to playing Understand for a bit.
No touching the code; that's a sucker's game on this network, this late at night.</p>
<p>Earlier today, I got my <tt class="docutils literal">cmd</tt> helper to work, through... somewhat blunt methods.</p>
<p>In any case, the next layer to bring in is the virtual environments, and I sense I should try a little harder to plan this stuff out, because I've got use cases that I intend for the future that I won't be battle-testing as I work on the runner itself.</p>
<p>One question I need to answer is whether I want to use the <tt class="docutils literal">virtualenv</tt> package <em>exclusively</em> in the long term, or if I want to provide interfaces to <tt class="docutils literal">venv</tt> as well.
Since I definitely want <tt class="docutils literal">virtualenv</tt> to be usable, I'm not sure if <tt class="docutils literal">venv</tt> offers anything besides "you don't have to install another package".
I mean, this project already has a few transitive dependencies.</p>
<p>I think the way forward is to add the dependency, and adapt my <tt class="docutils literal">Venv</tt> class from the config prototype with an <tt class="docutils literal">Optional[str]</tt> <tt class="docutils literal">python</tt> attribute.
Then start cribbing code from Nox or tox to convert that into a usable path in a cross-platform fashion.</p>
<p>Now, whether a <tt class="docutils literal">Session</tt> needs a <tt class="docutils literal">python</tt> argument (or multiple <tt class="docutils literal">python</tt> arguments) is a function of its semantics, so that shouldn't be a part of the <tt class="docutils literal">Protocol</tt>.</p>
<p>Let's sketch out a <tt class="docutils literal">Flake8HTML</tt> class.</p>
<div class="highlight"><pre><span></span><span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Flake8HTML</span><span class="p">:</span>
<span class="n">additional_args</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span>
<span class="c1"># I'm using a bad default argument because I don't want to bring in the machinery needed for an immutable map.</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">projects</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Project</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s2">""</span><span class="p">:</span> <span class="n">ROOT</span><span class="p">})</span> <span class="o">-></span> <span class="n">ChangeStream</span><span class="p">:</span>
<span class="n">report_dir</span> <span class="o">=</span> <span class="n">REPORTS</span> <span class="o">/</span> <span class="s2">"flake8"</span>
<span class="c1"># This is a higher-level wrapper that is specific to my current preferred project structure.</span>
<span class="c1"># The first argument is the name to use for the various Targets and Actions</span>
<span class="c1"># The second argument is the name of the command to export from the virtualenv</span>
<span class="c1"># The third argument is the name of the requirements file to install</span>
<span class="c1"># I expect this to change by the time all of this code is ready to use, since the concept of</span>
<span class="c1"># "module command plus module runner" better fits a variable number of requirements files</span>
<span class="n">flake8</span> <span class="o">=</span> <span class="k">yield from</span> <span class="n">venv_wrapper</span><span class="p">(</span><span class="s2">"check"</span><span class="p">,</span> <span class="s2">"flake8"</span><span class="p">,</span> <span class="s2">"check"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">project</span> <span class="ow">in</span> <span class="n">projects</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
<span class="n">project_report_dir</span> <span class="o">=</span> <span class="n">project</span><span class="o">.</span><span class="n">suffix</span><span class="p">(</span><span class="n">report_dir</span><span class="p">)</span> <span class="c1"># suffix() probably returns an Input</span>
<span class="c1"># This is a common pattern that I may want a helper function for.</span>
<span class="n">project_report_file</span> <span class="o">=</span> <span class="n">project_report_dir</span><span class="o">.</span><span class="n">path</span> <span class="o">/</span> <span class="s2">"index.html"</span>
<span class="c1"># This might not be the right way to handle this</span>
<span class="c1"># (I'm really not sure)</span>
<span class="c1"># But it's close enough for now</span>
<span class="n">action_name</span> <span class="o">=</span> <span class="n">project</span><span class="o">.</span><span class="n">prefix</span><span class="p">(</span><span class="s2">"check"</span><span class="p">)</span>
<span class="k">yield from</span> <span class="n">mkdir</span><span class="p">(</span><span class="n">project_report_dir</span><span class="p">)</span>
<span class="k">yield from</span> <span class="n">cmd</span><span class="p">(</span>
<span class="p">[</span>
<span class="n">flake8</span><span class="p">,</span>
<span class="s2">"--format=html"</span><span class="p">,</span>
<span class="s2">"--htmldir"</span><span class="p">,</span>
<span class="n">project_report_dir</span><span class="p">,</span>
<span class="o">*</span><span class="bp">self</span><span class="o">.</span><span class="n">additional_args</span><span class="p">,</span>
<span class="n">project</span><span class="o">.</span><span class="n">prefix</span><span class="p">(</span><span class="s2">"src"</span><span class="p">),</span>
<span class="n">project</span><span class="o">.</span><span class="n">prefix</span><span class="p">(</span><span class="s2">"tests"</span><span class="p">),</span>
<span class="p">],</span>
<span class="n">action_name</span><span class="p">,</span>
<span class="n">allowed_codes</span><span class="o">=</span><span class="p">{</span><span class="mi">1</span><span class="p">},</span>
<span class="p">)</span>
<span class="k">yield from</span> <span class="n">add_target</span><span class="p">(</span><span class="n">project_report_file</span><span class="p">,</span> <span class="n">action_name</span><span class="p">,</span> <span class="s2">"check"</span><span class="p">)</span>
</pre></div>
<p>This all basically provides a basic example of how the interfaces involved should probably work, because this is about the least complicated thing you can do while still leveraging the <tt class="docutils literal">Project</tt> interface.
So, whatever I end up with, it should support writing something like this without additional complication.</p>
<p>Handling stuff like different python versions or commands that need the project installed would add those as arguments to the <tt class="docutils literal">venv_wrapper</tt> call and move it into a for loop.</p>
<p>Maybe it would help things to have some kind of an "environment builder" interface that could be passed into the session to handle the environment creation.
That way, people, such as my future self, wouldn't need to lay out all of their projects in the exact same way.</p>
<p>So, if I can nail down that interface, then I'll be getting somewhere.</p>
<p>Anyway, this as supposed to be quick and it... wasn't.
If I don't call this now, I'm pretty much guaranteed to suffer in the morning.
So...</p>
<p>Good night.</p>
Coding 2021-07-252021-07-25T04:00:00-04:002021-07-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-25:/coding-2021-07-25<p class="first last">Smashing my modules into tiny pieces.</p>
<p>Okay.
Lots of stuff today, none of it related to my projects.
I'm not, like, sour or angry about this, but I am <em>exhausted</em>.</p>
<p>Let's see what kind of changes I can make to my code.
I want to create an <tt class="docutils literal">_api.changes</tt> directory for holding the five, I mean four, functions for generating state change streams.
That type should probably go next to the other modules for now.</p>
<p>"But wait, having like one function per module sounds kind of obnoxious."
Until this hits 1.0, I don't think I'm really writing this code for anyone else, and even then, I can't say for sure.
So, my feelings on this are the only ones that matter, and my feelings are "Let's see what happens!"</p>
<p>One thing that happens is that I need to think really hard about what gets imported into the <tt class="docutils literal">api</tt> module, now that it's all re-exports.</p>
<p>Another thing that happens is, I start suspecting that I should be applying this pattern elsewhere, because it's a little obnoxious to make the required imports match up with the defining modules.</p>
<p>It's all kind of a mess right now, and I'll try to get it to make sense tomorrow.
For now, it's late, and this post is going to take forever to publish, so I might as well get started.</p>
<p>Good night.</p>
Diary 2021-07-242021-07-24T04:00:00-04:002021-07-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-24:/diary-2021-07-24<p class="first last">Five hours on the road. Ugh.</p>
<p>Traveled today, which kind of wiped me out for doing anything else.
I want to try messing around with code, but I'll publish this first, because I don't know if I can really trust the internet out here, and I can't supplement it with my phone; its data connection out here is... faster than residential internet <em>used to</em> be.
Like 20+ years ago.</p>
<p>Whatever, I'm not out here for the internet, I'm out here for <strong>family</strong>.
*explosions or something*
(Did I do it right?)</p>
<p>Anyway, I'm going to call this post early because I have a headache and I don't want to push myself.</p>
<p>Good night.</p>
Coding 2021-07-232021-07-23T04:00:00-04:002021-07-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-23:/coding-2021-07-23<p class="first last">Figuring out what the code should be...</p>
<p>Earlier today, I finished up some of the changes I was working on.
So, what can I do next...</p>
<p>Keeping in mind that I am incredibly tired, let's see which files need to be broken up how.</p>
<p>The <tt class="docutils literal">api</tt> module needs to be broken into several layers of abstraction, which must themselves be divided into smaller units of responsibility.
At the lowest level of abstraction in the module, there are five functions that directly interact with the stream-based interface to <tt class="docutils literal">Rgistry</tt> construction.
Two of these functions are somewhat related, but I don't think they're fundamentally more tightly coupled than any other pair.</p>
<p>The next layer of abstraction is made up of three classes and their corresponding helper functions.
Each class represents a specific <tt class="docutils literal">Action</tt>, and the helper function constructs an appropriately detailed change stream around an instance of its corresponding class.
This layer consumes a pair of data classes that represent the production and consumption of <tt class="docutils literal">Target</tt>s.</p>
<p>The next layer on top of that specializes the usage of the above classes into helper classes/functions for setting up isolated execution environments.
Currently, this is just virtual environments via the stdlib <tt class="docutils literal">venv</tt>, but my long-term goals basically require a version of this using the pip-installable <tt class="docutils literal">virtualenv</tt> module.
Also, I could support other programming languages, probably.
(Possibly have a version that uses <tt class="docutils literal">conda</tt> instead of <tt class="docutils literal">pip</tt>.
If I come up with a really compelling reason.)</p>
<p>Above that layer, I have the somewhat-implicit concept of clusters of specific Python packages that provide an executable and may require project code to be installed to work properly.</p>
<p>Very sketchily above that layer, the idea of different wrappers around <tt class="docutils literal">pytest</tt>, to provide different functionality.
It makes sense, I think, to apply a similar structure to other test runners, and ideally the wrappers don't have to care about what code they happen to be wrapping.</p>
<p>Anyway, that covers the <tt class="docutils literal">api</tt> module and the config prototype.
Beyond that, we have...</p>
<p>The base controller, which has some not-terribly-related helper code in it that should be using plugins or extensions instead of what it's currently doing.</p>
<p>While the <tt class="docutils literal">registry</tt> module is pretty big, I think I've pulled out everything that really makes sense.
I may want to create a <tt class="docutils literal">Protocol</tt> for the <tt class="docutils literal">Registry</tt> class, because I <em>think</em> that would let me break some import cycles more elegantly, but that's still not a priority.</p>
<p>The <tt class="docutils literal">runner</tt> module is probably the best place to put that <tt class="docutils literal">Protocol</tt> if/when I do make it.
It's got three main classes that are pretty thoroughly coupled together, but it would probably help make it more obvious what was going on if there were a simple helper method that filled in some of the expected values.
There's also a helper method that could easily go either in its own module, or the base controller, but I'm not sure it matters.</p>
<p>The application defines a single extension module that should probably be split up into two or three.
Some of it deals with conditional formatting, and some of it deals with colored text, and some of it deals with conditionally applying colors to text.</p>
<p>There are various other modules in the application, but the rest of them look pretty well broken down for now.</p>
<p>I'm going to call this post here.
I don't know how much of a chance I'm going to get to work on any of this over the weekend, but I can't handle anything else right now.</p>
<p>Good night.</p>
Coding 2021-07-222021-07-22T04:00:00-04:002021-07-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-22:/coding-2021-07-22<p class="first last">Mistakes were made. Not in the code, but with my time.</p>
<p>I'm having kind of a rough week, so I didn't get much coding done today.
Let's try moving around a type and see if I break everything.</p>
<p>Hm, everything broke, time for plan B.
Plan B worked fine, at least for now.</p>
<p>Several rounds of tinkering later, I realize that it's way late and I need to get to bed, but I really want to break out a few more modules.
Time for some bad decisions.</p>
<p>Good night.</p>
Coding 2021-07-212021-07-21T04:00:00-04:002021-07-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-21:/coding-2021-07-21<p class="first last">Still figuring out which of my past decisions were bad, actually.</p>
<p>I did a bunch of cleanup of the code today.
Mainly, I got all of the imports to be in a consistent format, and I rewrote a bunch of test code that was slightly more complicated than it needed to be, and twice as long.
This should help future rewrites, because I got rid of most <tt class="docutils literal">from ... import</tt> and <tt class="docutils literal">import ... as</tt> statements, so I can't cause a name collision by adding more modules.</p>
<p>Now I can ponder deep mysteries, like "The <em>implementation</em> of the <tt class="docutils literal">Action</tt> type is irrelevant to the module that explicitly depends on its existence, but it's not even named in the module that <em>does</em> care about the implementation".
I'm not sure how to reconcile that with the <a class="reference external" href="https://en.wikipedia.org/wiki/Single-responsibility_principle">single-responsibility principle</a>, unless the solution is to make the classes involved generic and only use one type for their type parameter.
That sounds weird to me.</p>
<p>I guess I could try moving the type definition, having an import cycle, and trying to make sure it's resolvable, but I'd much rather not have the cycle.</p>
<p>Thinking about this more, I think what I want to do is convert the stuff I'm currently doing by reaching into the <tt class="docutils literal">Registry</tt> class into methods on a <tt class="docutils literal">Protocol</tt>, implement those methods on the concrete class, and then rely on the <tt class="docutils literal">Protocol</tt> and make the <tt class="docutils literal">Registry</tt> class attributes private.</p>
<p>At the very least, I want to make the attributes private and have accessor methods on the <tt class="docutils literal">Registry</tt>; that would have made some previous changes easier.
Setting up the <tt class="docutils literal">Protocol</tt> and such is basically a flourish.
(Thinking about it, somehow, having a <tt class="docutils literal">Protocol</tt> with type parameters but the only concrete implementation fills all of them in feels less objectionable than a generic concrete class that only uses one parameter value in practice.)</p>
<p>The methods so far would be:</p>
<ul class="simple">
<li>Given a <tt class="docutils literal">Target</tt>, return the name of its parent <tt class="docutils literal">Action</tt>.</li>
<li>Given the name of an <tt class="docutils literal">Action</tt>, return the <tt class="docutils literal">Target</tt>s that it relies on.</li>
<li>Given the name of an <tt class="docutils literal">Action</tt>, return that action.</li>
<li>Given a list of names of <tt class="docutils literal">Target</tt>s, return all <tt class="docutils literal">Target</tt>s referred to by those names.</li>
</ul>
<p>Anyway, it's super late again, so I need to stop writing this and post it.</p>
<p>Good night.</p>
Weekly Roundup 2021-07-202021-07-20T04:00:00-04:002021-07-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-20:/weekly-roundup-2021-07-20<p class="first last">Looking over my past decisions and going "Wait, that didn't make any sense. I can just...", and then, just.</p>
<ul class="simple">
<li>Wednesday: I was unhappy that the prototype configuration file was so long.</li>
<li>Thursday: I started figuring out why that file was so long, and what I can do about it.</li>
<li>Friday: I started doing things about it. I don't think the file is much shorter yet, but the groundwork is laid.</li>
<li>Saturday: I made more plans about classes to define in order to make the configuration file easier to read.</li>
<li>Sunday: I looked at the <tt class="docutils literal">api</tt> module some, and thought about how to break it up.</li>
<li>Monday: I started splitting out parts of the internal library modules.</li>
</ul>
<p>Next week, I'll keep on poking at this, but entries might be even shorter somehow, because I want to put in some work on a Secret Project that I hope to finish in a month or so.</p>
Coding 2021-07-192021-07-19T04:00:00-04:002021-07-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-19:/coding-2021-07-19<p class="first last">Thinking about having some modules where basically one line of code really does anything. We'll see.</p>
<p>Another light day today, but some progress is better than no progress.</p>
<p>I split out the <tt class="docutils literal">Result</tt> type from the <tt class="docutils literal">registry</tt> module, because the <tt class="docutils literal">registry</tt> module makes no assumptions about the <tt class="docutils literal">Result</tt> type beyond "it exists".
I could (and have) totally rework the implementation of <tt class="docutils literal">Result</tt> without affecting the rest of the <tt class="docutils literal">registry</tt> module in any way.
So, that was an obvious candidate to give it its own little module.</p>
<p>I'm trying to decide what I want to go for next.
I think some of the things I could split out based on that reasoning might end up being very small, and at first I was thinking this could be a <em>reductio ad absurdum</em> kind of situation, but I'm not really sure now.
I think I'm going to have to try it, and see if it really is absurd.</p>
<p>That won't happen right now, but soon.
Sooner, though, I'm going to bed.</p>
<p>Good night.</p>
Coding 2021-07-182021-07-18T04:00:00-04:002021-07-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-18:/coding-2021-07-18<p class="first last">I wonder if there's some way to manually highlight sections of text in vim (like, just change the background color). (Ideally it would also be possible to zoom out for a bird's-eye view.)</p>
<p>Another light day today, just because some stuff happened that's making it hard to focus.
Nothing important long-term, just... urgent.</p>
<p>Not dwelling on that, quick notes on dividing up the <tt class="docutils literal">api</tt> module before I get back to the other stuff.</p>
<ul class="simple">
<li>The module defines a helper type that many functions return. This type can be grouped with the five most basic helper functions, or separately.</li>
<li>There's a high-level helper function that nothing else relies on, so that could in theory stay in the module.</li>
<li>There are three <tt class="docutils literal">Action</tt> implementations, that should each get their own module, along with the helpers that instantiate them.</li>
<li>There is a pair of classes, <tt class="docutils literal">Input</tt> and <tt class="docutils literal">Output</tt>, that the <tt class="docutils literal">Action</tt> implementations use. Only <tt class="docutils literal">Input</tt> needs to be exposed. (Because it has a helper that creates an <tt class="docutils literal">Output</tt>.)</li>
<li>The module re-exports a helper function from inside the library, that it might make sense to move to the <tt class="docutils literal">_api</tt> package, since I don't think any of the non-<tt class="docutils literal">api</tt> code relies on it.</li>
</ul>
<p>While I'm thinking about breaking stuff up, I'd like to do something about the internal <tt class="docutils literal">registry</tt> module, because it's a whole big thing that seems kind of awkward to work with.</p>
<p>I think it's possible to pull out bits here and there as opaque units with a smaller interface, but I think my best bet is to copy this text into a word processor and start marking it up.
That's how I figured out that the config prototype was about 50% support code.</p>
<p>Anyway, super late, wrapping up.</p>
<p>Good night.</p>
Coding 2021-07-172021-07-17T04:00:00-04:002021-07-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-17:/coding-2021-07-17<p class="first last">Doing design work so I don't end up tied into knots.</p>
<p>All right, I didn't touch the code today, so here are some thoughts on what I should be working on after I clean up the <tt class="docutils literal">api</tt> module.</p>
<p>For virtual environments, I'm going to want some way to determine the Python executable to use.
That's going to determine the path it attempts, as well as providing a modification to the virtual environment path <em>and</em> action name.</p>
<p>As I said before, for locating files to process or report, I'm going to want a "project" protocol to modify paths specific to a command.</p>
<p>Thinking about the divisions more, code that needs a <tt class="docutils literal">Project</tt> is going to need <tt class="docutils literal">Python</tt> information for almost the same reason.</p>
<p>I hadn't anticipated that, and that feels like it'll be awkward if I rush into it.</p>
<p>Okay, so, the higher-level abstractions should be constructing their own virtual environments, which means they need an ability to take <tt class="docutils literal">Python</tt> objects, <em>but</em> not all commands should be duplicated by Python version, which means that the interface for getting them in is to set up arbitrary "shapes" of <tt class="docutils literal">Python</tt> containers in the constructor.
So, technically, it's not "required", it's just that you can't actually <em>do</em> anything if you don't somehow have access to one.</p>
<p>Good talk.</p>
<p>Anyway, thinking about the sort-to-medium term plans for this:</p>
<ul class="simple">
<li>Break up the <tt class="docutils literal">api</tt> module.</li>
<li>Create (and test!) abstractions for the two repos I want this working with.</li>
<li>Cut an initial release.</li>
<li>(Possibly lower priority) See if I can get this working with a PyPy 2 repo so I can mess with fancy JIT interpreter stuff later. This would be a good proof of concept for <tt class="docutils literal">Python</tt> objects, because I'm not at all interested in getting the runner to work with Python 2, so all pytest etc invocations <em>need</em> a custom path in this scenario.</li>
<li>Add support for other tools. I have no interest in "mandating" a specific ecosystem for the task runner, so long as the stuff I use works, so I might as well see what is needed to work with, for example, pylint, ward, hammet, mamba, ptr, mutmut, cosmic ray, semgrep, hypothesis...</li>
</ul>
<p>Anyway, I let this go late, so I should wrap up, like, right now right now.</p>
<p>Good night.</p>
Coding 2021-07-162021-07-16T04:00:00-04:002021-07-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-16:/coding-2021-07-16<p class="first last">"This is a 100-line function." "Oh dear." "But you should have seen what I had before that!"</p>
<p>Okay.
I've rewritten the body of the prototype config file so that the business logic is all in a giant generator function.
This is in a temporary state of code smell, in that the generator function is larger than most of the modules that it relies on.
BUT, this rewrite has made it clear how I need to proceed.</p>
<p>In essence, there are several axes of variation that a command can be subject to, with pytest varying the most.
The axes I've seen so far are:</p>
<ul class="simple">
<li>Which subproject the command applies to (this doesn't apply to the task runner repo, at least not currently, but I need it)</li>
<li>What command is getting applied. In the case of pytest, this effectively gets split into:<ul>
<li>What runs pytest</li>
<li>What arguments pytest runs with</li>
</ul>
</li>
</ul>
<p>The interfaces I want to be able to handle all of this properly are:</p>
<ul class="simple">
<li><tt class="docutils literal">Project</tt> This class must provide interfaces to add a prefix to a dirname (which should lead to a path in the repo), or to add a suffix to a dirname (which will be used to generate report directories)</li>
<li><tt class="docutils literal">Session</tt> This interface takes a mapping from <tt class="docutils literal">str</tt> names to <tt class="docutils literal">Project</tt>s, and yields all necessary changes to the registry.</li>
<li><tt class="docutils literal">PytestCommand</tt> and <tt class="docutils literal">PytestRunner</tt>. These combine together to create a <tt class="docutils literal">Session</tt>.</li>
</ul>
<p>While all of this should allow me to crunch down the config file pretty aggressively, my main motivation is to extract out reusable components so that all of my config files can be crunched down like this, and also able to get bugfixes.</p>
<p>I think the next step for me to take is to review the current <tt class="docutils literal">api</tt> module, and to start splitting it up into modules in an <tt class="docutils literal">_api</tt> sub-package.
Once the application code is tidied up so, I can resume pulling stuff out of the config file prototype into it.</p>
<p>I have no idea how long it is until an initial release at this point, but the state of the code is much more satisfying than it was a week ago, so that's nice.</p>
<p>Good night.</p>
Coding 2021-07-152021-07-15T04:00:00-04:002021-07-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-15:/coding-2021-07-15<p class="first last">It was honestly surprising to me just how much of the prototype file was code that was "supposed to be" in a library.</p>
<p>I'm not going to try to do anything about it yet, but I've figured out a few things about the prototype task runner file that I was so annoyed about the length of.
First off, the length is mostly due to the fact that it has helper functions that I really want in a library instead of the config files.</p>
<p>The bigger realization I had is that the interfaces get a lot simpler if I wrap everything in a generator function.
Basically, the template that everything is kind of fitting into is that there are helper functions that return a list of generators and possibly some extra value.
If I relax the idea of "returning multiple generators" (which then get evaluated in sequence), then I can rework these helper functions into generators that expect to be yielded from.</p>
<p>This would allow me to do some... somewhat questionable things.</p>
<p>First, background:</p>
<p>Decomposing the various registry modifications into the smallest units of work made it easier to reason about when they should be idempotent.
By implementing idempotence at the lowest level, I can bubble it up higher without actually doing anything at any intermediate level.
This means, and I have automated tests for this, that playing back the same sequence of modifications, which before was often an error, is now a no-op.
So, this means I don't need to worry about "repeating" modifications, as long as the original modifications are executed in order.
I mean, from a correctness perspective.
From a performance perspective, I am... not quite sure what I'm setting myself up for.</p>
<p>As far as what this allows me to do, this means that, supposing I make a helper class for representing virtual environments, I can turn the helper method to retrieve the path to a binary into a generator that establishes the link to the pip upgrade command that installed the binary.</p>
<p>I'm realizing now that I probably want to have some kind of wrapper around the generator to divert exceptions from the for-loop into the generator, so the traceback can bring together the code that hit the error and the code that caused the error to be hit.
This would probably be a bit squirrelly to call, but I only have to call it once.
Or I could not bother, and say that continuing after an exception is undefined behavior.
That's probably a better use of my time for now.</p>
<p>I don't want to actually touch any of this code for now, but talking through this has given me some good ideas.
And some maybe-good ideas.</p>
<p>I don't think I have anything else to talk about right now, so I'm going to send this.</p>
<p>Good night.</p>
Coding 2021-07-142021-07-14T04:00:00-04:002021-07-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-14:/coding-2021-07-14<p class="first last">It'll be nice when this is in a good enough state that I can at least tell whether it's <em>fast</em>.</p>
<p>I didn't get too much done today.
I started considering how to use the task runner for more complex project structures (structures that I'm already using, so this isn't a YAGNI violation or anything), and that turned out to take more effort than I expected.</p>
<p>The basic issue is that my current prototype task runner config file, even discounting the code in it that has to be moved into the application itself, is... a lot.
It's around twice the length of the noxfile, and I have to believe this is partially due to the fact that it's surfacing the relationships between different actions.</p>
<p>Anyway, the point is, I'm going to need to go over this stuff with a pretty fine-toothed comb to get all of this configuration code into the right state.</p>
<p>I think the right thing to do going forward is to take a break, at least from this, and come back to it when I'm feeling a bit fresher and have more time.
I'd better wrap up for now.</p>
<p>Good night.</p>
Weekly Roundup 2021-07-132021-07-13T04:00:00-04:002021-07-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-13:/weekly-roundup-2021-07-13<p class="first last">I've nearly got the high-level interfaces nailed down.</p>
<ul class="simple">
<li>Wednesday: I designed a fancy system for passing state around while constructing the task runner's registry; I haven't actually used it yet.</li>
<li>Thursday: I started converting the sessions from the noxfile into <tt class="docutils literal">Action</tt>s and <tt class="docutils literal">Target</tt>s for the task runner.</li>
<li>Friday: I made a little more progress there, and tried to figure out which part of the current implementation bothers me the most.</li>
<li>Saturday: I didn't get much done, because I was focusing on making things not hurt.</li>
<li>Sunday: I touched up parts of the API.</li>
<li>Monday: I tried to touch up a bit more of the API.</li>
</ul>
<p>Next week, I'm going to write a task runner file for one of my other projects, and see how I need to fix up the prototype file before I bring more into the codebase.</p>
Coding 2021-07-122021-07-12T04:00:00-04:002021-07-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-12:/coding-2021-07-12<p class="first last">I can't be expected to manage my time! I have a messed-up toe that hurts sometimes!</p>
<p>So, here's what happened today:</p>
<ul class="simple">
<li>Bunch of Minecraft</li>
<li>Travel</li>
<li>Frantic attempts to get code stuff done</li>
</ul>
<p>That last one mainly focused around trying to split up the "virtual environment setup" logic into one function per script invocation.
My hope is that I can build on this work in order to port the rest of the noxfile, and from there make sure all of the functions and classes I want to use end up in source control.</p>
<p>I should probably track the prototype file, as well.</p>
<p>The basic streams of logic that need to be worked out:</p>
<ul class="simple">
<li>Generic logic for running pytest as a suffix of some command</li>
<li>Commands for a few coverage invocations. (Generalize existing coverage environment creation.)</li>
<li>JUnit XML manipulation commands.</li>
</ul>
<p>I'll also want to prototype the task runner file for one of my larger projects, so I can make sure I have functionality for some of the more complicated logic.</p>
<p>Anyway, it's way too late and I should sleep.</p>
<p>Good night.</p>
Coding 2021-07-112021-07-11T04:00:00-04:002021-07-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-11:/coding-2021-07-11<p class="first last">Contorting into weird positions in an attempt to mitigate the soreness from past weird contortions. I foresee no issues with this.</p>
<p>All right, it's way late because I spent most of the day playing Minecraft, but I want to get <em>something</em> done with this API stuff.
I'll make one of the changes I was planning, and see how I feel like from there.</p>
<p>Okay, basically, I made some improvements to the "add command" helper.
I added a class for "paths that a command makes exist", and generally made the "paths that a command needs to exist" class more helpful.
I moved more code from the task file into the "api" file, which at this point <em>really</em> needs to be split up.
I also cleaned up the <tt class="docutils literal">setup_venv</tt> function a little.</p>
<p>I'm going to check over the code for correctness while this publishes, then get to bed a bit late.
And next thing I work on probably has to be splitting the code up.</p>
<p>Good night.</p>
Diary 2021-07-102021-07-10T04:00:00-04:002021-07-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-10:/diary-2021-07-10<p class="first last">Pain continues to be stupid.</p>
<p>My injury isn't <em>currently</em> bothering me, but I don't trust it.</p>
<p>I made some progress thinking about coding, but I didn't actually touch it.
Tomorrow, hopefully.</p>
<p>Anyway, I just feel really thrown off by my various attempts to avoid putting pressure on one foot.
It sucks that messing up one tiny part of my body means I have to contort all of my activities around supporting the healing process, assuming any of what I'm trying is even working.</p>
<p>Nothing else to say, I guess, so I'll wrap up.
This is me wrapping up.</p>
<p>Good night.</p>
Coding 2021-07-092021-07-09T04:00:00-04:002021-07-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-09:/coding-2021-07-09<p class="first last">Helper functions that call helper functions that construct class instances to pass into helper functions that yield helper class instances that trigger dispatch to internal functions that build up a graph representation that gets traversed according to command-line arguments in order to do... stuff. I <em>totally</em> had this realistically scoped to start with...</p>
<p>I've dealt with some of the soreness, so I'm doing a bit better now.</p>
<p>Anyway, back to some of the problems I was having with the code yesterday...</p>
<p>Basically, sometimes the dependencies that <em>should</em> exist are "obvious", but as the author of the code, I know they're not going to be picked up unless I include them explicitly.</p>
<p>I can think of two basic cases: the necessary <tt class="docutils literal">Target</tt> is part of the command, or it isn't.
The latter case is handled adequately by the current interface, and must be handled by a few different commands.</p>
<p>I can imagine a way for this to work, so I guess I'll try it...</p>
<p>Okay, yeah, I like this.
Basically, the boilerplate was so annoying because, on some level, I knew that the required helper functions were trivial.
Just a few lines of code, but it covers all of the stuff that "obviously" should be handled.</p>
<p>Right now, some of the helpers are missing full coverage of the interface that they wrap, but I don't want to get too distracted right now.</p>
<p>Actually, I'm going to need to add that coverage to handle pytest, and that's next to port, so I might as well...</p>
<p>Okay, I'm looking at this code and <em>knowing</em> that it's got all sorts of weird deficiencies, but I don't really want to fix it before I bring it into the codebase proper.</p>
<p>So, here's what I need to consider now:</p>
<ul class="simple">
<li>Am I ever going to use more than one command from a virtual environment? If not, I can simplify my helper functions considerably.</li>
<li>Which of my internal names do I have the most issues with, and how can I fix them? Two big issues... For one, I named a module after one of the major classes in it, so if I instantiate that class in another module, the obvious name for the variable is... the name of the module that I had to import to instantiate the class. For another, some of the casting/coercion/whatever functions use different naming conventions for no good reason. No useful difference between the functions <tt class="docutils literal">to_thing</tt> and <tt class="docutils literal">as_thing</tt>. (To be clear, the functions <em>are</em> different, because "<tt class="docutils literal">thing</tt>" is different. But they both perform the same action relative to their specific value of "<tt class="docutils literal">thing</tt>".)</li>
<li>I need to rewrite some of my helpers to use my other helpers; this will make some future extensions easier.</li>
<li>Think about the organization of the <tt class="docutils literal">api</tt> module. It's getting a little cramped, but, like, what kind of imports should consumers expect to need to do? Maybe I can have, like, an <tt class="docutils literal">_api</tt> package inside, and just re-export a bunch of it in the <tt class="docutils literal">api</tt> file.</li>
</ul>
<p>My general feeling is that I can address a lot of this by breaking things up more, so I'll look into that later.</p>
<p>For now, my take on this is, now that I've gotten through the initial hurdles of "using" this code, it's showing promise, though I need to take some time once I'm done porting my noxfile, to figure out what kind of idioms make sense, since currently it's just kind of a massive stream of top-level statements and global declarations.</p>
<p>I'm getting tired and a little sore, so I'll start wrapping things up.</p>
<p>Good night.</p>
Coding 2021-07-082021-07-08T04:00:00-04:002021-07-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-08:/coding-2021-07-08<p class="first last">It feels a little bit like building a house out of popsicle sticks, but whatever.</p>
<p>I'm kind of sore and cranky right now, but I want to get work done on the task runner, so I'm going to try to do that.</p>
<p>The first thing I remembered that simplifies things is, I currently don't need the file writing stuff for <em>this</em> project.
I will need it, though.
The second thing I remembered is, wait, I have a noxfile.
I should just be rewriting that.</p>
<p>I gave writing a basic command my best shot.
It's... something.</p>
<div class="highlight"><pre><span></span><span class="n">dot_dir</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="s2">".task-runner"</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
<span class="n">requirements_dir</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="s2">"requirements"</span><span class="p">)</span>
<span class="n">reports_dir</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="s2">"reports"</span><span class="p">)</span>
<span class="n">coverage_deleted</span> <span class="o">=</span> <span class="n">api</span><span class="o">.</span><span class="n">deleted</span><span class="p">(</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="s2">".coverage"</span><span class="p">))</span>
<span class="c1"># Move this to api</span>
<span class="c1"># Add a "freeze data dict" helper</span>
<span class="k">def</span> <span class="nf">make_state</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="o">*</span><span class="n">changes</span><span class="p">):</span>
<span class="k">return</span> <span class="n">api</span><span class="o">.</span><span class="n">State</span><span class="p">((</span><span class="n">c</span> <span class="k">for</span> <span class="n">change</span> <span class="ow">in</span> <span class="n">changes</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">change</span><span class="p">),</span> <span class="n">data</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">setup_venv</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">requirements_file</span><span class="p">,</span> <span class="n">commands</span><span class="p">,</span> <span class="n">project</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="n">changes</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">final_targets</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">venv_path</span> <span class="o">=</span> <span class="n">dot_dir</span> <span class="o">/</span> <span class="n">name</span>
<span class="n">cmd</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"python"</span><span class="p">,</span> <span class="s2">"-m"</span><span class="p">,</span> <span class="s2">"venv"</span><span class="p">,</span> <span class="s2">"--clear"</span><span class="p">,</span> <span class="n">venv_path</span><span class="p">)</span>
<span class="n">make_venv</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"make-venv-</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">"</span>
<span class="n">bin_dir</span> <span class="o">=</span> <span class="n">venv_path</span> <span class="o">/</span> <span class="s2">"bin"</span>
<span class="n">changes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">api</span><span class="o">.</span><span class="n">add_action</span><span class="p">(</span><span class="n">api</span><span class="o">.</span><span class="n">Cmd</span><span class="p">(</span><span class="n">cmd</span><span class="p">),</span> <span class="n">make_venv</span><span class="p">))</span>
<span class="n">changes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">api</span><span class="o">.</span><span class="n">add_target</span><span class="p">(</span><span class="n">bin_dir</span><span class="p">,</span> <span class="n">make_venv</span><span class="p">))</span>
<span class="n">cmd</span> <span class="o">=</span> <span class="p">(</span><span class="n">bin_dir</span> <span class="o">/</span> <span class="s2">"pip"</span><span class="p">,</span> <span class="s2">"install"</span><span class="p">,</span> <span class="s2">"-U"</span><span class="p">,</span> <span class="s2">"pip"</span><span class="p">)</span>
<span class="n">update_pip</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"update-pip-</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">"</span>
<span class="n">changes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">api</span><span class="o">.</span><span class="n">add_action</span><span class="p">(</span><span class="n">api</span><span class="o">.</span><span class="n">Cmd</span><span class="p">(</span><span class="n">cmd</span><span class="p">),</span> <span class="n">update_pip</span><span class="p">,</span> <span class="n">bin_dir</span><span class="p">))</span>
<span class="n">changes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">api</span><span class="o">.</span><span class="n">add_target</span><span class="p">(</span><span class="n">update_pip</span><span class="p">,</span> <span class="n">update_pip</span><span class="p">))</span>
<span class="n">cmd</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">bin_dir</span> <span class="o">/</span> <span class="s2">"pip"</span><span class="p">,</span>
<span class="s2">"install"</span><span class="p">,</span>
<span class="s2">"-r"</span><span class="p">,</span>
<span class="n">requirements_dir</span> <span class="o">/</span> <span class="n">requirements_file</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">project</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">cmd</span> <span class="o">+=</span> <span class="p">(</span><span class="n">project</span><span class="p">,)</span>
<span class="n">install_requirements</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"install-requirements-</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">"</span>
<span class="n">changes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
<span class="n">api</span><span class="o">.</span><span class="n">add_action</span><span class="p">(</span><span class="n">api</span><span class="o">.</span><span class="n">Cmd</span><span class="p">(</span><span class="n">cmd</span><span class="p">),</span> <span class="n">install_requirements</span><span class="p">,</span> <span class="n">update_pip</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">for</span> <span class="n">command</span> <span class="ow">in</span> <span class="n">commands</span><span class="p">:</span>
<span class="n">command_path</span> <span class="o">=</span> <span class="n">bin_dir</span> <span class="o">/</span> <span class="n">command</span>
<span class="n">changes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">api</span><span class="o">.</span><span class="n">add_target</span><span class="p">(</span><span class="n">command_path</span><span class="p">,</span> <span class="n">install_requirements</span><span class="p">))</span>
<span class="n">final_targets</span><span class="p">[</span><span class="n">command</span><span class="p">]</span> <span class="o">=</span> <span class="n">command_path</span>
<span class="k">return</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">changes</span><span class="p">),</span> <span class="n">final_targets</span>
<span class="n">CLEAN_CHANGES</span><span class="p">,</span> <span class="n">CLEAN_COMMANDS</span> <span class="o">=</span> <span class="n">setup_venv</span><span class="p">(</span><span class="s2">"clean"</span><span class="p">,</span> <span class="s2">"coverage"</span><span class="p">,</span> <span class="p">[</span><span class="s2">"coverage"</span><span class="p">])</span>
<span class="n">CLEAN_CHANGES</span> <span class="o">+=</span> <span class="p">(</span>
<span class="n">api</span><span class="o">.</span><span class="n">add_action</span><span class="p">(</span>
<span class="n">api</span><span class="o">.</span><span class="n">Cmd</span><span class="p">([</span><span class="n">CLEAN_COMMANDS</span><span class="p">[</span><span class="s2">"coverage"</span><span class="p">]],</span> <span class="s2">"erase"</span><span class="p">),</span>
<span class="s2">"coverage-erase"</span><span class="p">,</span>
<span class="n">CLEAN_COMMANDS</span><span class="p">[</span><span class="s2">"coverage"</span><span class="p">],</span>
<span class="p">),</span>
<span class="n">api</span><span class="o">.</span><span class="n">add_target</span><span class="p">(</span><span class="n">coverage_deleted</span><span class="p">,</span> <span class="s2">"coverage-erase"</span><span class="p">),</span>
<span class="p">)</span>
</pre></div>
<p>Takeaways so far:</p>
<ul class="simple">
<li>I'll probably only need to define the <tt class="docutils literal">setup_venv</tt> function once, and it should probably be a library function of some kind.</li>
<li>Specifying required targets for these <tt class="docutils literal">Cmd</tt> actions doesn't feel good/obvious/natural, but I'm not exactly sure what to do about that.</li>
<li>This code probably has at least one bug in it, but I'm not going to guess where.</li>
<li>Oh wait, found one. The requirements file needs a <tt class="docutils literal">.txt</tt> extension. I'll leave that as-is in the post, and fix it in the prototype.</li>
</ul>
<p>Anyway, I'm theoretically ready to test this, but I don't think I'm emotionally ready for whatever weird error it's probably going to throw at me.</p>
<p>Sudden thought: "skip" is a bad name for what it is in this app, because the meaning doesn't line up.
Suppose I decided I wanted to allow the user to request just erasing the coverage file, but I didn't want that to be considered a default target.
Suppose further that the coverage test runs depend on the coverage erase step, (because they will, when I write them) and their dependent targets are named and not skipped (because they represent data that we want by default).</p>
<p>This all means that the "erase" step is <em>called</em> skipped, but it actually runs by default.
This behavior doesn't bother me, so the problem must be with the name.</p>
<p>At some point I'm going to have to work on strengthening the naming conventions in this project, and making the names make more sense.
Not right now, though.
For now, I'm going to look at the code up there and think about what I've done.</p>
<p>Good night.</p>
Coding 2021-07-072021-07-07T04:00:00-04:002021-07-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-07:/coding-2021-07-07<p class="first last">It's like trying to translate an academic paper into production-ready code, but everyone involved is me.</p>
<p>I'm trying to actually use the code I've spent all of this time on, and I'm coming to the conclusion that it needs a lot of scaffolding built on top of it to be usable.</p>
<p>I took a break from writing this post for a bit, and I think the problem I was having is that my initial attempts were too low-level.
Instead of writing a helper function per-<tt class="docutils literal">Action</tt>, I need, like, one function that:</p>
<ul class="simple">
<li>creates a virtual environment with a given name</li>
<li>updates pip</li>
<li>runs pip with the arguments and environment passed into the function</li>
<li>creates targets for every script that's supposed to be in the virtual environment</li>
<li>returns both the resulting <tt class="docutils literal">State</tt> and a mapping from script names to script paths; the paths should be <tt class="docutils literal">Target</tt>s in the changes on the <tt class="docutils literal">State</tt>.</li>
</ul>
<p>One of the other things I need for my workflow specifically is a way to create a file that a pip command can read.
This might require changes to the execution model, or maybe there's something simpler I can do.</p>
<p>The crux of this is that my idiom for doing this in a noxfile involved using a <tt class="docutils literal">TemporaryDirectory</tt> to store the file, and thinking about this in the context of the task runner implies to me that I'd need to be essentially running one <tt class="docutils literal">Action</tt> "inside" another.</p>
<p>That would take a lot of effort, and I think a better way would be to put the responsibility for constructing a temporary directory on the application.
At that point, creating the file would be a normal <tt class="docutils literal">Action</tt>, and everything could just depend on it straightforwardly.</p>
<p>Hmm.
I can mostly see how to do this, but it would be somewhat annoying, and I could just as well put the generated file next to the virtual environments, and it would be much quicker to implement.
I'll try that for now, and see if <em>not</em> using a temporary directory somehow bites me.</p>
<p>In any case, I'll need an <tt class="docutils literal">Action</tt> for "write some data to a file", and a helper that adds the file path as a <tt class="docutils literal">Target</tt>.</p>
<p>Something else that's becoming clear to me is that the <tt class="docutils literal">State</tt> concept doesn't actually pull its weight until I'm running parameterized commands, so I just shouldn't bother to start with.</p>
<p>Sketching things out, I basically want to create the virtual environment with the virtual environment directory as the target.
I can then have a pip upgrade action that relies on the virtual environment and has, say, the path to pip as the target it exports.
So far, so generic.</p>
<p>But the next action I want to set up has a bunch of moving parts: it needs to rely on the <em>upgraded</em> pip, and export an arbitrary set of targets, and also rely on a target that's passed in as part of the environment to this action's pip command.</p>
<p>That's, like, a lot.</p>
<p>I'll have to think about this a bunch before I write the helper, but I can at least write the <tt class="docutils literal">Action</tt> to write data to a file.</p>
<p>I'll do that, then get to bed.</p>
<p>Good night.</p>
Weekly Roundup 2021-07-062021-07-06T04:00:00-04:002021-07-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-06:/weekly-roundup-2021-07-06<p class="first last">Head down on this, because I want to be ready when the rest of the tooling I want hits 1.0.</p>
<ul class="simple">
<li>Wednesday: I figured out the design for the non-fluent interface for the task runner, and started implementing it.</li>
<li>Thursday: I dealt with some failing tests by deleting them.</li>
<li>Friday: I took the internal error messages from "absent" to "maybe other people can understand this?"</li>
<li>Saturday: I made a major stride in improving coverage, by writing tests that, um, don't do much, but use a lot of code in the process.</li>
<li>Sunday: I put together a class for representing a single command-line execution, and then tried to figure out an ergonomic way to use it.</li>
<li>Monday: I tossed together a class and function for handling <tt class="docutils literal">Action</tt>s and <tt class="docutils literal">Target</tt>s in sequence. It needs me to try to use it, then write tests.</li>
</ul>
<p>Next week, I'm going to either keep on with this, or take a break again.</p>
Coding 2021-07-052021-07-05T04:00:00-04:002021-07-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-05:/coding-2021-07-05<p class="first last">I feel like my Python code might be in a ternary plot with extremes of "pseudo-code", "Pokémon", and "speaking in tongues".</p>
<p>I took things easy again today, so the main progress I made was in realizing that the idiom I'm trying to work with requires using <tt class="docutils literal">Iterator</tt>s instead of providing a function for iteration.
The point of this is to make it so that if I "reuse" a dataclass instance, its <tt class="docutils literal">Action</tt>s and <tt class="docutils literal">Target</tt>s only get added to the <tt class="docutils literal">Registry</tt> once.</p>
<p>I don't know if this is the right approach, but I have a gut feeling that I don't want to lean on the type system for really fine-grained stuff, and instead have a few simple types that relate via operations like "compose" and "fan-in".
So, like, maybe the type would be as simple as the <tt class="docutils literal">Iterator</tt> and a mapping from strings to sets of data.</p>
<p>Something like...</p>
<div class="highlight"><pre><span></span><span class="c1"># It's a little weird that it's frozen with mutable state, but meh.</span>
<span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">State</span><span class="p">:</span>
<span class="n">changes</span><span class="p">:</span> <span class="n">Iterator</span><span class="p">[</span><span class="n">Change</span><span class="p">]</span>
<span class="n">data</span><span class="p">:</span> <span class="n">PMap</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">PSet</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Path</span><span class="p">]]]</span>
<span class="k">def</span> <span class="nf">combine</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">:</span> <span class="n">State</span><span class="p">)</span> <span class="o">-></span> <span class="n">State</span><span class="p">:</span>
<span class="n">changes</span> <span class="o">=</span> <span class="p">(</span><span class="n">c</span> <span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">args</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">arg</span><span class="o">.</span><span class="n">changes</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">args</span><span class="p">:</span>
<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">arg</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">data</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="nb">set</span><span class="p">())</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="k">return</span> <span class="n">State</span><span class="p">(</span><span class="n">changes</span><span class="p">,</span> <span class="n">pmap</span><span class="p">({</span><span class="n">k</span><span class="p">:</span> <span class="n">pset</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">data</span><span class="o">.</span><span class="n">items</span><span class="p">()}))</span>
</pre></div>
<p>And then you just have the new state as the last argument.
This code is totally untested and unpolished, but I think it gets the basic idea across.</p>
<p>I'm doing basic tests on it right now, and I'll try actually using it later, but it's late now and I want to get to bed.</p>
<p>Good night.</p>
Coding 2021-07-042021-07-04T04:00:00-04:002021-07-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-04:/coding-2021-07-04<p class="first last">Unfocused rambling because I more-or-less took things easy today.</p>
<p>Oh boy...</p>
<p>I threw together a <tt class="docutils literal">Cmd</tt> class, but I don't have any tests or attempts to use it yet.
Let's see what I can come up on the spur of the moment.</p>
<p>I'm going to want virtualenv creation, which is going to look like:</p>
<p><tt class="docutils literal">python <span class="pre">-m</span> venv <span class="pre">--clear</span> <path></tt></p>
<p>The generator for that needs to create an action and a target parented to that action, with the target being <path>.</p>
<p>It should somehow make it easy to create <tt class="docutils literal">Cmd</tt>s like</p>
<p><tt class="docutils literal"><span class="pre"><path>/bin/<cmd></span> <args></tt></p>
<p>One thing I want to work out is how to deal with commands that parameterize kind of all over the place.
Like, pytest commands need the particular virtualenv they're running under, the top-level executor, the core of the command, and then the testpaths and related arguments.</p>
<p>I'm thinking maybe something like...</p>
<p><tt class="docutils literal">def cmd(args: typing.Sequence[str], prefix: typing.Optional[str], env: typing.Optional[typing.Dict[str, <span class="pre">str]],</span> allowed_codes: typing.Sequence[int]) <span class="pre">-></span> Cmd:</tt></p>
<p>I think I'm going to need to revisit my sketches of how different commands fit together, and where some of these names should come from.</p>
<p>Trying to run through the organization some in my head.
The two main axes of difference are "which project is being accessed", and "what is being done".
Because whether or not a given task <em>has</em> project-specific behavior depends on the task, the higher-level organization is the different tasks, and those different tasks should be parameterized by the list of projects.
If I try to come up with a class for everything, it looks like my pytest stuff needs some kind of core pytest command and wrapper classes to annotate it with stuff like extra inputs and outputs.
I think this is the way to go, yeah.
The classes are dataclasses, and they define iterators that produce their relevant changes, and also have attributes and properties representing various things they expose according to interfaces.</p>
<p>I'm not sure when I'll have the focus to put this together.
Maybe I'll manage it in the next few days, maybe I'll need to take another break and get to it in a week.
We'll see.
Anyway, it is way too late right now.</p>
<p>Good night.</p>
Coding 2021-07-032021-07-03T04:00:00-04:002021-07-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-03:/coding-2021-07-03<p class="first last">I guess it's a good thing I tried writing some of these tests.</p>
<p>I think it was earlier today that I hammered out the tests and formatting of my failure messages.
They're pretty detailed and fairly consistent.
They could maybe do with numeric codes for lookup later, but that's not needed right now, and kind of needs documentation first.</p>
<p>Anyway, it's time to get some more coverage.
I'm kind of looking at the uncovered lines and thinking "Well, what would happen if I didn't give it any actions to take? That's a valid test."</p>
<p>Let's see what happens.</p>
<p>Well, it worked, but I decided it needed a few behavior changes, so I modified the relevant templates a little.
Things are in a good place now.
There are just a few lines of code left to test, but they're... kind of a doozy.</p>
<p>I'd gotten this far, see, without writing any legitimate <tt class="docutils literal">Action</tt>s.
To finish things up, I need actual <tt class="docutils literal">Actions</tt>s that I can invoke from test code.</p>
<p>Let's see what I've got in mind...</p>
<ul class="simple">
<li>Delete directory tree (cross-platform)</li>
<li>Run command, with optional statuses to <em>not</em> abort on.</li>
<li>Using run command, create a virtual environment</li>
<li>From a virtual environment, running a command <em>within</em> that virtual environment</li>
</ul>
<p>These tasks should bring in the last of the prototype code.
Once I have this functionality exposed via the API module, I can try running this code against its own repo and see if I actually get the kind of speedup I expected.
Either way, I'll hopefully get some more useful profiling data.</p>
<p>For now, I want to wind down.
There'll be plenty of time to get this working later.
Maybe tomorrow, maybe in a few days, maybe in a week.
I'll get there when I get there.</p>
<p>Good night.</p>
Coding 2021-07-022021-07-02T04:00:00-04:002021-07-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-02:/coding-2021-07-02<p class="first last">Trying to make sure that my failure messages are more detailed than "something broke somewhere."</p>
<p>Here's the deal with coverage misses in the task runner code:
I've got lines missing in three files.
One file corresponds to some templating operations.
One file corresponds to the configuration builder.
And one file is the main logic.</p>
<p>I'm going to get that last one last.
Let's add the templating first, because that should be easy.
Okay, one of them was easy I think, the rest of that file, I don't want to care about right now.</p>
<p>For the other, let's see...
There are a bunch of <tt class="docutils literal">raises</tt> context managers in the tests, but they're not covering enough cases, and they're not checking messages, which means right now the errors are pretty cryptic.
Let's see what we can do about that.</p>
<p>Okay, I didn't write tests to exercise the uncovered code, but I did add thorough error messages to everything that looked like it needed one, and added strict checks to the tests that hit those errors.
This will come in handy when I figure out how I want to set up mutation testing.</p>
<p>I'm kind of too relaxed to think through writing tests to hit these lines right now, so I'll leave that for tomorrow.</p>
<p>For now, I'm going to wind down a bit early.</p>
<p>Good night.</p>
Coding 2021-07-012021-07-01T04:00:00-04:002021-07-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-07-01:/coding-2021-07-01<p class="first last">I really hope this ends up being worth it.</p>
<p>Part of the reason I've been tired lately is that I've stepped my exercise routine up to where it should have been originally, to try to shed some of the pandemic weight.</p>
<p>Anyway, moving away from that, let's see what it takes to make a little more progress.</p>
<p>One of the first things I notice is that my naming schemes don't quite feel consistent.
I'll have to look into this later.
First, I want to be assured that I can safely start deleting code, and to do that, it needs to actually be safe to do so.</p>
<p>Before touching test code, I run it, and see that my coverage has gone all the way down to 90%.
(It's too bad it's not a slightly more useful 90%.)</p>
<p>When it came time to fix the tests, I couldn't figure out how to fix some of them, so I just deleted them.
We'll see what the damage is once I've deleted the code that shouldn't be covered any more.
But first, I have to fix the tests, because they're failing as I write this.
Oh. I missed a comma somewhere.
Correction, several commas, all in nearly the same place.
Let's see how it goes now.
Better...</p>
<p>Coverage is still above 90% <em>somehow</em>.
I'm going to start deleting code and just dare this to fail, then see about getting coverage back up.</p>
<p>All pass, 93% coverage.
Yeah okay.</p>
<p>All right, there's work to be done to get the coverage up, but that's going to happen later, because I'm tired now.</p>
<p>Good night.</p>
Coding 2021-06-302021-06-30T04:00:00-04:002021-06-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-30:/coding-2021-06-30<p class="first last">It's probably a little cursed when there's a block that just starts <tt class="docutils literal">if not typing.TYPE_CHECKING:</tt></p>
<p>I've got the design I want for updating the configuration worked out, but I spent a lot of today zoning out, so we'll, like, see how far I get.</p>
<p>Step one: create data classes to represent changes, and create a <tt class="docutils literal">Union</tt> combining them.</p>
<p>Step two: create a function that takes the union and will dispatch to individual implementations.</p>
<p>Step three: create the individual implementations, and forward the existing functions to them, for ease of testing.</p>
<p>Step four: set up the dispatches</p>
<p>Step five: test this intermediate stage</p>
<p>(Secret step five and a half: fix stuff that I broke, and also contemplate filing a bug against Python for some of the stuff I encountered.)</p>
<p>Anyway, I'm not getting anything else done tonight, so I'll put off future steps, such as "write helper functions that produce the new classes", "expose my desired interface through the api module", and "rewrite the tests to use the new interface", along with "actually test the main application logic".</p>
<p>But yeah, currently exhausted.</p>
<p>Good night.</p>
Weekly Roundup 2021-06-292021-06-29T04:00:00-04:002021-06-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-29:/weekly-roundup-2021-06-29<p class="first last">The similarities between the previous two summaries were not planned ahead-of-time, or even during-time.</p>
<ul class="simple">
<li>Wednesday: I started reasoning about the things that I'm doing kind of wrong with the task runner. Some of the changes I had in mind had me worried about the efficiency implications.</li>
<li>Thursday: I made one code change, but it was a good one. I also left myself a note to help with future changes.</li>
<li>Friday: I tried a truly absurd number of things to make my chest stop hurting as a result of sitting... like... one sec. Sorry, I had to stand up, for... some reason.</li>
<li>Saturday: More code simplification. Turned some of the types involved <em>dramatically</em> simpler.</li>
<li>Sunday: I started outlining the configuration API changes that I want.</li>
<li>Monday: I came up with an invariant that should more-or-less leave the algorithms involved at about the same level of complexity, which went a long way towards getting me comfortable with the API changes.</li>
</ul>
<p>Next week, I'm going to try to get the task runner really for real ready for an initial release.
This requires:</p>
<ul class="simple">
<li>Finish redoing the configuration API</li>
<li>Full test coverage</li>
<li>"Self-hosted"</li>
</ul>
<p>I was poking at this some today, and decided to remove some functionality that I don't have a use for, and this made running the tests much more tractable; it remains to be seen how much overhead will be added when I get full test coverage, but I'd be shocked if the "self-hosted" version takes more than five seconds.
Fingers crossed.</p>
Coding 2021-06-282021-06-28T04:00:00-04:002021-06-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-28:/coding-2021-06-28<p class="first last">Past me telling me "It's okay, you've got this." and I'm not sure I believe it.</p>
<p>So, I realized that if I come up with an invariant that enforces similarity to the old workflow, there's a chance that gives similar performance guarantees as well.
I did this by splitting up the functions to add an <tt class="docutils literal">Action</tt> and to define inputs for it, but only allowing adding inputs to the last <tt class="docutils literal">Action</tt> that was added.
This discards some properties of the old system that I don't think I cared about, but it simplifies cycle checking to the case of "does this <tt class="docutils literal">Target</tt> depend on the latest <tt class="docutils literal">Action</tt>?" which is constant-time.
This is because, to get cycles longer than a single <tt class="docutils literal">Action, Target</tt> pair, we need to do something like:</p>
<ul class="simple">
<li>add <tt class="docutils literal">Action</tt> A</li>
<li>add <tt class="docutils literal">Target</tt> 1 as a child of A</li>
<li>add <tt class="docutils literal">Action</tt> B</li>
<li>make B require 1 (allowed)</li>
<li>add <tt class="docutils literal">Target</tt> 2 as a child of B</li>
<li>make A require 2 (not allowed)</li>
</ul>
<p>The last step is not allowed because A is not the most recent <tt class="docutils literal">Action</tt>.
I don't think there's any way to arrange these so that all requirements are added at a valid time.</p>
<p>Anyway, I'll have to see whether I agree with this reasoning later, because I'm kind of sleepy and that took a lot of effort to articulate.</p>
<p>Good night.</p>
Coding 2021-06-272021-06-27T04:00:00-04:002021-06-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-27:/coding-2021-06-27<p class="first last">Getting ready to make problems for future me. What did future me ever do for me, anyway?</p>
<p>Okay, getting a late start again.
Let's see what I want...</p>
<p>The <tt class="docutils literal">Registry</tt> defines four methods for updating its contents, though one is normally called by a convenience hook on another.
I think to handle this, I'd like to completely separate them in the actual classes, and make a helper function that combines them in some kind of stream-based way or something.</p>
<p>Thinking about this, I could put calls to coercion functions into the helper functions, so the objects can contain the coerced strings.</p>
<p>The other thing I'm thinking about is how small I want to make these objects.
In a few cases, making the objects simpler means I need more validation logic, because I can't offload the invariant maintenance onto the object structure.
Like, if I can add new required <tt class="docutils literal">Target</tt>s to an <tt class="docutils literal">Action</tt> whenever, then that means that adding a <tt class="docutils literal">Target</tt> requires a check for cycles.</p>
<p>Maybe there's some way to add additional data to the internal representation to convert non-local invariants to local invariants.
I'll just assume I can do that later and write something simpler for now.
What could possibly go wrong?</p>
<p>I'll probably think about this a bit more before changing the code.</p>
<p>But anyway, I'll regret my decisions that led to this point <em>even more</em> if I don't wrap up ASAP.</p>
<p>Good night.</p>
Coding 2021-06-262021-06-26T04:00:00-04:002021-06-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-26:/coding-2021-06-26<p class="first last">Polishing the code until it... shines is probably a bit much, yet.</p>
<p>Just working on a bit of polish right now.
I made the changes I mentioned at the end of the last coding entry.
Some of it was a bit rough, because I hope I can just punt on some of the design decisions for now.
Currently, the generated paths are... relatively hardcoded.</p>
<p>I'm just going to iterate on that a few more times, because every tweak seems like it's opening up additional simplifications, currently.</p>
<p>Like, I make <tt class="docutils literal">Action</tt>s define their own logging interface, and that simplifies <tt class="docutils literal">Result</tt>s enough that I can replace them with an enum, which means I should be able to eliminate a loop and convert some conditional logic into a dict lookup.</p>
<p>I've got a few fixes to make to a few tests, but nothing major.
I can do it while this entry publishes.</p>
<p>At the same time, it's pretty late.</p>
<p>Good night.</p>
Diary 2021-06-252021-06-25T04:00:00-04:002021-06-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-25:/diary-2021-06-25<p class="first last">Pain is stupid and I hate it.</p>
<p>I messed up my posture like two days in a row, and now I have to stand as straight and tall as I can, or <em>the pain</em> hits.
I hate this.</p>
<p>I am holding a cold pack on my chest to see if it does anything.
I really can't tell, although I am feeling more conscious of what my neck is doing at any given moment.
Status update: still hate this.</p>
<p>Ugh, I wanted to be reviewing the design and design changes for the task runner, but I'm busy trying to make my body stop messing with me so I can get to sleep in a few hours.</p>
<p>I think the only thing I really can do right now is lie down and read for a while, so I guess I'll do that instead of forcing myself to use the computer.</p>
<p>Good night.</p>
Coding 2021-06-242021-06-24T04:00:00-04:002021-06-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-24:/coding-2021-06-24<p class="first last">It's nice to see convoluted messes get replaced with something simpler.</p>
<p>I was doing other stuff today, so I got one thing done: switched <tt class="docutils literal">Action</tt> and <tt class="docutils literal">ActionName</tt>.
This simplified code all over the place, although unfortunately some of the code wasn't covered, so I only have Mypy output to work with.</p>
<p>I guess this was an object lesson in, sometimes you just have to try things, because I don't think I'd have anticipated just how much logic got untangled by slightly changing one data structure.
It's also an illustration of how helpful good type coverage can be, since I would not have felt confident changing the type definition without type coverage; tests can (sometimes) show that there's a problem, but it can be somewhat tricky to discern what the solution is based on a test failure.
When tests failed, I barely looked at the details of what went wrong, and just skipped to looking for API changes that needed to be accounted for.</p>
<p>Anyway, that was all pretty good, but I still want to work on tweaking the configuration interface.
I'll get on that in the next few days.
For now, as usual, I should get ready for bed.</p>
<p>(Quick note, it makes more sense to create an output folder and pass the path to <tt class="docutils literal">Action</tt>s than it does to create specific file handles outside the <tt class="docutils literal">Action</tt>.
That way, a custom <tt class="docutils literal">Action</tt> has complete control over how it logs.)</p>
<p>Good night.</p>
Coding 2021-06-232021-06-23T04:00:00-04:002021-06-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-23:/coding-2021-06-23<p class="first last">Fun fact: switching the <tt class="docutils literal">Action</tt> and <tt class="docutils literal">ActionName</tt> types should be an optimization, but it's not worth checking.</p>
<p>As I was thinking about writing actual files for the task runner, I decided I wanted to make some changes to the API.
Those changes have knock-on effects that need to be carefully reasoned through.</p>
<p>Basically, the current interface uses fluent methods on an immutable <tt class="docutils literal">Registry</tt> object to incrementally build up a configuration.
This is somewhat of a mismatch, because the decision of "what to add" should be independent of "what's in there", so extension packages are burdened by the need to take a <tt class="docutils literal">Registry</tt> as input.
They are further burdened by the fact that the fluency constrains the output type: if a helper function wants to output additional target or action information, then its output needs to be explicitly unpacked, which breaks up the fluent chain.</p>
<p>I believe these issues could be addressed by changing from "here is a method on a <tt class="docutils literal">Registry</tt> object" to "here is an object that describes a change to a <tt class="docutils literal">Registry</tt>".
This means that, instead of a fluent chain, the means of change is a <em>sequence of change objects</em>, which can be manipulated as data.
Instead of chaining methods, just concatenate sequences.</p>
<p>The question this raises for me is, how free should extension packages be to customize the behavior of change objects?
The <em>most general</em> interface is <tt class="docutils literal"><span class="pre">Callable[[Registry],</span> Registry]</tt>, but doing this would discard guarantees like "the output is (loosely speaking) a 'superset' of the input".
That guarantee could be reclaimed by creating some kind of "delta" object that must be merged with the <tt class="docutils literal">Registry</tt>.
This all seems kind of complicated, though.
The easiest sufficient solution is to convert each method to a type, then dispatch from the type to the underlying method.</p>
<p>Thinking about this suggested some invariants that I might want to code explicit invariants for, once I have proper profiling data:</p>
<ul class="simple">
<li><tt class="docutils literal">Target</tt>s and <tt class="docutils literal">Action</tt>s (at least, those reachable from named <tt class="docutils literal">Target</tt>s) form a DAG</li>
<li><tt class="docutils literal">Action</tt> names are unique (for this, I may switch the <tt class="docutils literal">Action</tt> and <tt class="docutils literal">ActionName</tt> types in the definition of <tt class="docutils literal">Registry</tt>.)</li>
<li><tt class="docutils literal">TargetName</tt>s that are skipped by default are all mapped to at least one <tt class="docutils literal">Target</tt>. (I could see downgrading this to a warning.)</li>
</ul>
<p>Thinking about this, the two things to definitely try are to swap <tt class="docutils literal">Action</tt> and <tt class="docutils literal">ActionName</tt>, and to make a simple external type so I can work on deprecating the fluent interface.</p>
<p>I may try moving validator logic out of the update methods, but I don't want to mess with things that have obvious performance implications before I have performance testing that I somewhat trust, and that'll probably be easier to handle once I nail down the interface, so I don't end up needing to rewrite the benchmark.</p>
<p>None of that is happening tonight, however; this is all planning for the next time I start changing around the code.</p>
<p>Good night.</p>
Weekly Roundup 2021-06-222021-06-22T04:00:00-04:002021-06-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-22:/weekly-roundup-2021-06-22<p class="first last">Overall some more good progress.</p>
<ul class="simple">
<li>Wednesday: I got a haircut and thought about tests for the task runner.</li>
<li>Thursday: I thought a little more about the design of the task runner tests that I want.</li>
<li>Friday: I got the sequencing tests written, and thought "Oh, I'll test the command line. That should be simple." It was not simple, and I had to spend some time debugging it.</li>
<li>Saturday: I spent the time to debug the test failures. So many wrong assumptions, so many.</li>
<li>Sunday: I made a small improvement to testability, then started to consider improvements I want to make to the runner unrelated to "run as quickly as several layers of Python code can manage"</li>
<li>Monday: I got home at like ten or ten thirty and wasn't up for writing much.</li>
</ul>
<p>Next week, I'm going to polish and refine the prototype a bit more, before I take a break from it for a bit.</p>
Diary 2021-06-212021-06-21T04:00:00-04:002021-06-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-21:/diary-2021-06-21<p class="first last">I don't remember why I thought I'd get anything done today.</p>
<p>I took things easy today, and then we traveled again, so I didn't have a chance to work on anything.</p>
<p>Right now, I'm just trying to figure out some way to relax and unwind before I go to bed, and I'm not doing a great job currently.</p>
<p>I think I've just got to publish this, shut things down, maybe put on some music, and zone out.</p>
<p>Good night.</p>
Coding 2021-06-202021-06-20T04:00:00-04:002021-06-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-20:/coding-2021-06-20<p class="first last">Not resting on my laurels, which may or may not exist.</p>
<p>All right, there's now control over syntax coloring!
Probably!</p>
<p>While I think the task runner is close enough to tested that I'd be comfortable trying it out against actual codebases, I want to step back for now and kind of subconsciously consider a few things.</p>
<ul class="simple">
<li>Right now, it gathers up stdout and stderr in memory; I want to convert these to files that get streamed to a generated directory. One thing I want to ponder is having a symlink to the latest run's directory; I don't know whether that would present a significant barrier to anyone developing on Windows.</li>
<li>Setting that up would also require changing the signature of the <tt class="docutils literal">Action</tt> callable type, which isn't currently a big deal. It would be to include file objects of some kind. My current thinking is that I should go for "somewhat slower than idealized performance", and say, okay, the interface gets an asynchronous file object, then the consumer can unwrap it if a synchronous object is required. (Note that, it looks like there are various good reasons for the task runner to open these files in binary mode.)</li>
<li>As a further knock-on, I think this gives me a reason to change "<tt class="docutils literal">Action</tt>s given the same name" from a warning to an error, because if all action names are unique, it means that action logs can just use the name directly.</li>
</ul>
<p>I'm not going to think about this specifically, but I'm also going to want, when I come back to this, to figure out the right project layout for exposing the configuration-side APIs at the project root, or possibly in some low-level submodule.
I'm leaning towards the latter because the configuration side of the Python API is supposed to be a temporary thing that gets stripped out before I'm comfortable moving the version to 1.0.</p>
<p>Actually, let's think about the different ways this gets consumed...</p>
<ul class="simple">
<li><em>running</em> the runner invokes an entry point, which (currently) imports the configuration file and processes it</li>
<li><em>writing</em> the configuration file currently involves importing various functions from inside the app</li>
<li>I won't have a handle on <em>extending</em> the app until I try using it</li>
</ul>
<p>Thinking about this, one thing it would be worth doing before I step away is actually writing the configuration file for the app itself, and seeing how that shakes out in practice.
For example, right now the noxfile takes a minute to run, and I believe ten seconds is the realistic lower bound given the current suite, and I want to see which side it's all closer to.</p>
<p>I'll do that tomorrow; for now I want to clean up and get ready for bed.</p>
<p>Good night.</p>
Coding 2021-06-192021-06-19T04:00:00-04:002021-06-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-19:/coding-2021-06-19<p class="first last">Fixing a bunch of trivial errors, to make 100 tests pass.</p>
<p>Summary of the problems I fixed with the task runner:</p>
<ul class="simple">
<li>I misnamed a command-line flag in some of the test variants</li>
<li>Near as I can tell, I wasn't supposed to be using <tt class="docutils literal">resolve()</tt> for what I was using it for</li>
<li>I had a mismatch between the name passed to a template, and the name referenced in a template</li>
<li>Minor issue about gobbling newlines.</li>
</ul>
<p>From looking at some of the test failures before I got this all working, I think an important issue is the fact that I'm not confirming my understanding of the terminal colors.
If I want proper tests in that area, I'll need to create a command-line flag for controlling the coloring behavior, and make some changes to the way coloring is currently handled.</p>
<p>That seems like a good thing to work on later; I'm already tired right now, so once again I'm not going to push myself.</p>
<p>Good night.</p>
Coding 2021-06-182021-06-18T04:00:00-04:002021-06-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-18:/coding-2021-06-18<p class="first last">Catastrophic failure for no obvious reason. Now this is familiar territory.</p>
<p>The sequencing tests were a success, so the core logic looks solid for simple cases.</p>
<p>However, I also wrote tests to exercise the CLI, and some part of the rendering pipeline outright does not work.</p>
<p>Let's go through this slowly.
I've defined a pair of tests; the differences between them are not important.
Thanks to Coverage.py's test integration, I can confirm that both tests are registering and calling some custom hooks on the application object.
These hooks resolve the <tt class="docutils literal">Jinja2TemplateHandler</tt> associated with the app, and inject custom filters into the environment.</p>
<p>At this point, I can see two reasons this could fail:</p>
<ul class="simple">
<li>Repeated invocations of the <tt class="docutils literal">resolve()</tt> method are returning different handler instances. I assume this possibility doesn't make sense.</li>
<li>The handler is used for rendering before the hooks can inject the custom filters. This doesn't make sense to me, and would suck, a lot.</li>
</ul>
<p>I hope there's something else I'm missing, but if there is, I'm not in a state to figure it out.
I just added a bit of exploratory logging, but I'm tired and wasn't thinking clearly and it didn't work.
I think I'm going to need to drop into a debugger to figure this out.
And figuring out the right way to hook that up is probably a whole other thing.</p>
<p>Good night.</p>
Coding 2021-06-172021-06-17T04:00:00-04:002021-06-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-17:/coding-2021-06-17<p class="first last">This entry was somewhat truncated by my eyelashes just jamming themselves all over the inside of my eyelids.</p>
<p>So, I got <em>a little</em> distracted souping up the task runner's noxfile.
It's now got another profiler, the output of which <em>mainly</em> serves to show off how I probably shouldn't be using the test suite to get profiler data.</p>
<p>Anyway, let's see if I can quickly set up more core tests.
The basic topology I want is a single target that transitively depends on everything, and two pairs of "intermediate" actions that can be sequenced into one of six orders, and possibly a baseline action that sets up the dependencies.</p>
<p>So, there are four actions with synchronization between them.
At the cost of "excess" synchronization in some cases, this can be handled by having a <tt class="docutils literal">trio.Event</tt> that's set in one action and waited for in the next.
To avoid having two cases for the initial action, a baseline action can be defined that takes one <tt class="docutils literal">trio.Event</tt> and immediately sets it.
The rest can then two <tt class="docutils literal">trio.Event</tt>s, await one, set the other, and return a dummy result.</p>
<p>Sadly, I'm too sleepy now to execute on this currently, but hopefully that's enough for me to go on a few days from now.</p>
<p>Good night.</p>
Diary 2021-06-162021-06-16T04:00:00-04:002021-06-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-16:/diary-2021-06-16<p class="first last">That's a weight off my shoulders. *finger guns*</p>
<p>I mostly took things easy again today.
We got haircuts, and it feels absolutely amazing to move my head without my hair following through, and feeling stuff on the back of my neck.
Super excited to get my hair quickly washed, dried and combed, rather than just... basically none of those.</p>
<p>Thinking about what I want to do for task runner testing later...
I want more core tests, which should use extra synchronization objects (which probably shouldn't be used for non-test purposes) to force identical task graphs into different orders.
I want to test the exact output of the target list flow, and the end of the output for the execution flow.
(Actually, it occurs to me that I probably need better integration between the progress bar library and the app.
I'll research that after I publish this.)
(Actually, on further reading, I'm not sure whether Cement has the kind of tooling I'm used to from Click.
I'm not currently clear on how I'd do something like capture output.
I guess I have to make sure that I use as few <tt class="docutils literal">render</tt> calls as possible?)</p>
<p>Anyway, I'm really tired again; apparently "spacing out" doesn't count as "sleep", which seems really unfair when you get right down to it.</p>
<p>Good night.</p>
Weekly Roundup 2021-06-152021-06-15T04:00:00-04:002021-06-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-15:/weekly-roundup-2021-06-15<p class="first last">Writing this entry while fighting off a food coma...</p>
<ul class="simple">
<li>Wednesday: I worked on the core scheduling logic for the task runner. Most of it's easy, but I had trouble with the middle layer that basically soaked up all the complexity.</li>
<li>Thursday: I got tests for the whole thing, then started planning what to work on next.</li>
<li>Friday: I decided that, after I published that entry, I would work on designing the output presentation logic, which I did.</li>
<li>Saturday: We went out and did some stuff, and my pyenv installation broke in subtle and mysterious ways.</li>
<li>Sunday: I thought about what "a nice organization" for some of the extension and plugin stuff I want would look like. I probably need to think some more.</li>
<li>Monday: I got the task runner to a point where it's all supposedly more-or-less functional. We'll see.</li>
</ul>
<p>Next week, I'm going to try to polish up the task runner code, and add the one major piece of functionality that's stubbed out: a progress bar.
The main hurdle there is figuring out a clean integration.
I might punt on "clean" and just inject it all into the main flow for now.</p>
Coding 2021-06-142021-06-14T04:00:00-04:002021-06-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-14:/coding-2021-06-14<p class="first last">Getting the easy part done.</p>
<p>All right.
I put together first drafts of the filters I want, injected them in a way that doesn't immediately crash Cement (it wants my functions to be <em>functions</em>? What's up with that? (I joke, but the meaning behind the joke is that it wants at least some of the callables I pass to the API to have <tt class="docutils literal">__name__</tt> attributes, which I wasn't expecting.)), and wrote templates that might be valid; I don't have tests for them yet.</p>
<p>Right now, I'm looking over the main program flow to figure out what I want to tweak next.
Currently, the code errors out "before" it can act on the configuration.
So, that error needs to be moved into a conditional that does a type check, and the next check is for whether to list targets, which, I don't actually have the code for that yet, but that's simple to add.
And, added.
I'm going to try to just muddle my way through all this...</p>
<p>For some of this, I'm just going to transcribe some of my prototype code, which is self-evidently perfect except for all the bits where I didn't run it and it would have blown up if I'd ever tried.</p>
<p>Put that all together and...
Now something is failing most of the tests, and the traceback is formidable.
Let's see what I can work out.</p>
<p>Okay, I just had to let the tests run somewhat to completion.
Turns out I made a bad assumption; I <em>think</em> the default template from Cement led me astray a little.
I think maybe these kinds of templates should have the output commented to show like "here's a good practice to usually follow" versus "here's something silly that you're supposed to change".
That might stop stuff like e-readers shipping with ROT13 or cyclic XOR for DRM.</p>
<p>Anyway, the code is all in, but there are no new tests, and a few static analysis issues.
I'll take care of those after I publish this.
Anyway, this code should be ready for an initial release soon.
All ~0.5 kloc of it.</p>
<p>Well, I should wrap things up for tonight.</p>
<p>Good night.</p>
Coding 2021-06-132021-06-13T04:00:00-04:002021-06-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-13:/coding-2021-06-13<p class="first last">Getting ready to add more features to the application.</p>
<p>I've got plans for implementing stuff for the task runner, using Cement's facilities.
I want to make at least one extension to handle extending the existing Jinja environment to define additional filters.</p>
<p>I was thinking about injecting the <tt class="docutils literal">Terminal</tt> object from <a class="reference external" href="https://github.com/jquast/blessed">blessed</a> into the <tt class="docutils literal">app</tt>, but until I determine that I need to reuse it, I think it's fine to just initialize it in the extension's <tt class="docutils literal">load(app)</tt> function.
I might also want to customize it according to the app's config.
In that case, I might put it in <tt class="docutils literal">pre_setup</tt>, just so I'm sure it's configured before any of the <tt class="docutils literal">post_setup</tt> hooks run.</p>
<p>I didn't want to trying doing all of that before writing up this entry, because I'd like to wrap things up early-ish, and getting this entry in is part of that.
So, after I publish this, I'll mess around a little, then do other stuff to wrap up.</p>
<p>I might have gotten more stuff done today, but eh, we had plans.</p>
<p>Good night.</p>
Diary 2021-06-122021-06-12T04:00:00-04:002021-06-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-12:/diary-2021-06-12<p class="first last">Technology out here keeping me on my toes by inventing entirely new problems that it's possible nobody else has.</p>
<p>Two major things prevented me from having much to write about today.
The bigger problem was that I was unable to get to sleep for a good stretch of last night, so I was in a confused haze all day.</p>
<p>The more recent problem was that something in all the code and scripts related to pyenv is setting my <tt class="docutils literal">PYENV_VERSION</tt> environment variable to <tt class="docutils literal">system</tt> whenever I start a shell, which is really great if you want <tt class="docutils literal">pyenv local</tt> to be useless, and in no other circumstance that I can think of.
I've determined that the problem manifests sometime between the end of <tt class="docutils literal">.profile</tt> and the beginning of <tt class="docutils literal">config.fish</tt>, which... I don't know what goes between those.
This is a clear case of ignorance on my part, and my Mastodon account is right down there if anyone wants to educate me on this.</p>
<p>I mean, I'm working around this by including <tt class="docutils literal">pyenv shell <span class="pre">--unset</span></tt> in my <tt class="docutils literal">config.fish</tt>, but <em>what if I didn't need that line in the first place?</em>
Wouldn't that be nice?</p>
<p>Getting this fixed was a priority because Three Dollar Quill has its own virtualenv for installing stuff like the youtube embedding extension, and I didn't want to manually set the pyenv environment to that every time I entered the directory, <em>like some kind of caveman</em>.</p>
<p>I'm really excited to figure out how to put my design ideas for the task runner into practice, but that's not happening until I get a good night's sleep.
Speaking of which.</p>
<p>Good night.</p>
Coding 2021-06-112021-06-11T04:00:00-04:002021-06-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-11:/coding-2021-06-11<p class="first last">Oops.</p>
<p>Okay, I did some other writing, so rather than take about what I accomplished coding, I'm going to give myself a concrete goal for what to work on after I publish.</p>
<p>So, in my design work for output, I identified a basic unit of presentation that can be applied to the task of output.
There is a list of items to print, separated by newlines.
If there are items in the list, then a specified header is printed, otherwise, nothing is.
The whole thing is wrapped up in terminal formatting codes to change the color.
For each of these sections, the code defines the header and the terminal color, and the input data is the list of items to print.</p>
<p>I need to figure out which parts of this to represent in Jinja, and how.
I believe I already did a lot of the work, I just don't remember it super well.</p>
<p>Anyway, this took way too long and I'm just going to be doing some frantic sketching because it's super late.</p>
<p>Good night.</p>
Coding 2021-06-102021-06-10T04:00:00-04:002021-06-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-10:/coding-2021-06-10<p class="first last">It just worked. That's pretty gratifying.</p>
<p>The code now has full test coverage, and more-or-less makes sense to me.
The tests are... fine.</p>
<p>So, I guess my next step now is to work on designing the various bits of output logic.
After that, get the required code and templates in and tested.
Then, wire it all together.
Finally, get this all "self-hosted" so I can test the code <em>with</em> the code, and pull helper functions out of the configuration file into the library as optional helpers.
Then, just iterate adding more advanced forms of testing and analysis.</p>
<p>I'm going to wrap up now and sketch out output details.</p>
<p>Good night.</p>
Coding 2021-06-092021-06-09T04:00:00-04:002021-06-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-09:/coding-2021-06-09<p class="first last">I should probably rework the code that I haven't tested a little.</p>
<p>I was working on other stuff today (worldbuilding and some other writing), so I just did some quick work on the task runner in the last hour or so.
I added the easy tests, which confirmed that the very core scheduling logic works as expected under simplified conditions, and made me suspect that I should change around the signature for the high-level helper function.
Yeah, I did that.
I can change it back later if it's a problem.</p>
<p>What's left to work on now is the kind of middle layer between them, which seems to have soaked up a lot of complexity that I'm not sure what else to do with.
What's in the middle?
A higher-order function that creates a pair of mutually recursive asynchronous closures over its arguments, some of which are mutable.
The closure that is actually returned is pretty simple, but the workhorse closure starts off with a for-loop inside an asynchronous context manager inside a synchronous context manager, delegate execution to its argument, which has to be a nullary asynchronous function, and then checks whether to raise an exception based on the return value of that.</p>
<p>This is going to be at least another day of work to get tests written for it.
Things to test:</p>
<ul class="simple">
<li>Having stuff in the for-loop or not</li>
<li>Triggering the exception or not</li>
<li>Confirming that raising the exception prevents dependent actions from executing</li>
</ul>
<p>All right, I can see my way to testing that, but I don't want to do it right now.
Soon™.</p>
<p>Time to wrap up.
At the very least, even if I can't go outside yet because the humidity is seesawing between uncomfortable and dangerous, at least I'm getting overall work done at a pace that I like more.</p>
<p>Good night.</p>
Weekly Roundup 2021-06-082021-06-08T04:00:00-04:002021-06-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-08:/weekly-roundup-2021-06-08<p class="first last">I do a bunch of things, and then nature laughs at my unrelated hubris.</p>
<ul class="simple">
<li>Wednesday: I wrote Lexurgy definitions for the vowels I'm going to use, and sketched out a plan for consonants. I described an idea for a high-level workflow that uses Lexurgy to power individual steps within it.</li>
<li>Thursday: I got through consonants, and started thinking about suprasegmentals. I thought some more about the high-level workflow concept.</li>
<li>Friday: I finished up the first draft of my Lexurgy sound definitions, and posted it, because why not. I considered some alternatives to the high-level flow, and decided I probably wanted to go with pretty much the original concept, <em>but</em> I want to prototype it against an existing Lexurgy example.</li>
<li>Saturday: I was kind of out of it, so I talked about the stuff we watched.</li>
<li>Sunday: I switched gears back to coding, starting with critiquing my task runner prototype. This gave me an idea to try for the next prototype version.</li>
<li>Monday: I put that idea into practice, and decided I liked it well enough for now.</li>
</ul>
<p>Next week, I'm going to try to take advantage of our fully-developed immunity.
But it's so humid!
The air is so gross!
I don't want to touch it.</p>
<p>Also, task runner code, fantasy worldbuilding, stuff like that.</p>
Coding 2021-06-072021-06-07T04:00:00-04:002021-06-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-07:/coding-2021-06-07<p class="first last">Just type up the first thing that occurs to me, it's probably fine.</p>
<p>I managed to prototype basically the idea I came up with last night, with a few concessions to mild laziness.
I've confirmed that the code typechecks, and imports fine, but the majority of the logic lives inside closures, because for whatever reason I'm more comfortable sticking a mutable structure into a closure rather than a dataclass-like class.
So, there's a bunch of tests to write, but they shouldn't be particularly hard tests.</p>
<p>Here's what I think is missing:</p>
<ul class="simple">
<li>Target listing (including formatting)</li>
<li>Reading target list from the command line</li>
<li>Calling into the runner code I just wrote</li>
<li>Updating progress bar code from the prototype</li>
<li>Extracting output</li>
<li>Formatting output</li>
<li>Determining desired return code</li>
</ul>
<p>All of that comes down to just hooking up the existing components, some of which I've already researched.
In any case, once I've proved out the core runner code, the hard bit is probably going to be getting the Cement integration right; I may cut a few corners at first.</p>
<p>Anyway, I want to sleep, but I also want to write down some unrelated ideas first, so here we go, wrapping up.</p>
<p>Good night.</p>
Coding 2021-06-062021-06-06T04:00:00-04:002021-06-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-06:/coding-2021-06-06<p class="first last">Coming up with one (1) idea, then getting to sleep, because I got distracted by other things that seemed unreasonably hard.</p>
<p>I got a bit distracted trying to get my computer to be a little more thorough with dark mode.
I was trying all sorts of web searches with the intent to change some of Firefox's color choices with a GTK theme, then I finally gave up and installed Stylish, to redo the coloration only of <tt class="docutils literal"><span class="pre">file://</span></tt> URLs that look like directories.
It's not fully baked yet, but it's a little less blinding.</p>
<p>Anyway, I'm just going to review where I was with the prototype code, and call it a night.</p>
<p>One of the key parts of mutable state in the prototype is a pair of mappings from <tt class="docutils literal">Action</tt>s to <tt class="docutils literal">trio.Event</tt>s.
These are always manipulated together, which implies to me that I should have a wrapper object around two <tt class="docutils literal">trio.Event</tt>s.
I'll have to think this over more later, but it makes intuitive sense to me.
It would mean that I'd potentially need to do some gnarly stuff with higher-order functions.
(Basically, it looks to me like I'd need this new wrapper object to expose a method for handling the high-level dispatch, because part of the prototype logic is based around early returns.
That means that the "core logic", which may or may not run from a given invocation, would need to be passed in as a nullary async function.
(There are other possibilities, but I'm leaning towards nullary.))
Anyway, that's a brand-new idea to me, and I'm going to need to be better-rested to fully evaluate it, so I'd better get to bed.</p>
<p>Good night.</p>
Diary 2021-06-052021-06-05T04:00:00-04:002021-06-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-05:/diary-2021-06-05<p class="first last">Somehow, setting the AC to kick in at a <em>higher</em> temperature than the air outside did something.</p>
<p>Okay, I was kind of out of it today, so I'm not going to push myself to write or do too much.
Just a few more days, and I'll finally be comfortable going outside for reasons besides going to or from the car.</p>
<p>Today, we watched <em>Zero Hour!</em>, which is the movie that more-or-less got remade into <em>Airplane!</em>.
It was kind of weird seeing some of the lines that were used to set up jokes just being said straight and moved on from, but also seeing bits where <em>Airplane!</em> didn't really have to add anything.
All that said, it's a good disaster movie.</p>
<p>Like I said, we'll be done building up immunity soon, and we're trying to think of stuff to go out and do.
I don't really know what's going to be available to go to and do stuff at, because of the pandemic, but we'd like to go out and do <em>something</em>.
Probably get haircuts.
My hair is in pretty sorry shape right now.
Earlier today, I tried to comb it, and it formed into three lobes: one on top, and one on each side.
Not really the look I was going for, but I just have to hold out a little longer.
(It <em>might</em> have been partly down to the high dew point.
It was too humid for me to really even <em>think</em> this morning.)</p>
<p>Anyway, that's everything I can think of to talk about, so I guess I should wrap this up.
I'm now wrapping this up.</p>
<p>Good night.</p>
Conlanging 2021-06-042021-06-04T04:00:00-04:002021-06-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-04:/conlanging-2021-06-04<p class="first last">The first draft is done, time to reflect, and also try to properly learn linguistics.</p>
<p>My Lexurgy definitions are now syntactically valid, though I'm not sure if they all do what I want.
I'm going to drop the current version at the end of the post, and try to wrap things up quickly.
My plan right now is to take some time to think about how to handle affixation.
One possibility that occurs to me is to do all of the pre-processing ahead-of-time, so there's a metadata-annotated lexicon that gets converted into a wordlist that consists of <em>phrases</em> that correspond to single words in the modern language.
My gut reaction to that idea is that it's limited in terms of interpolation and extrapolation.
Deriving intermediate or future lexicons requires generating an entirely new wordlist, because the wordlist is only valid for a single chronolect.</p>
<p>As such, I want to try my initial idea, but not on this conlang.
If this concept works on anything, it should work on the Tpaalha sample in the Lexurgy app.</p>
<p>One thing that occurs to me about having rules for affixation, is that I'd want to have tests to establish that affixation doesn't happen with words that I'm not expecting it to.
That'll be a neat trick, probably.</p>
<p>Anyway, here's my current draft.
It has problems, some of which I'm even aware of!</p>
<p>"Prelude":</p>
<pre class="literal-block">
# Length distinctions apply to both vowels and consonants
Feature +long
# These are the major distinctions that can apply to consonants
Feature +aspirated, +prenasalized, voiced
Feature place(labial, dental, palatal, velar, glottal)
Feature manner(stop, fricative, nasal, approximant)
Feature +sibilant
Feature +lateral
# Only for Sj-sound
Feature +labialized
# These features distinguish vowels
Feature openness(open, openmid, closemid, nearclose, close)
Feature front, raised, retracted
Feature round
# Okay, let's work on stress now...
Feature stress(primary, secondary)
Feature +peak
Diacritic ˈ (floating) (before) [primary]
Diacritic ˌ (floating) (before) [secondary]
Diacritic ⁿ (before) [+prenasalized]
Diacritic ʰ [+aspirated]
Diacritic ̂ [+peak]
Diacritic ː [+long]
Symbol i [close +front -raised -retracted -round]
Symbol y [close +front -raised -retracted +round]
Symbol u [close -front +raised -retracted +round]
Symbol ɪ [nearclose +front -raised -retracted -round]
Symbol ʏ [nearclose +front -raised -retracted +round]
Symbol ʊ [nearclose -front +raised -retracted +round]
Symbol e [closemid +front -raised -retracted -round]
Symbol ø [closemid +front -raised -retracted +round]
Symbol o [closemid -front +raised -retracted +round]
Symbol ɛ [openmid +front -raised -retracted -round]
Symbol œ [openmid +front -raised -retracted +round]
Symbol ɔ [openmid -front -raised +retracted +round]
Symbol a [open +front -raised -retracted -round]
Symbol ɑ [open -front -raised +retracted +round]
# Okay, let's work on the consonants
Symbol m [labial nasal +voiced]
Symbol n [dental nasal +voiced]
Symbol ɲ [palatal nasal +voiced]
Symbol ŋ [velar nasal +voiced]
Symbol p [labial stop -voiced]
Symbol b [labial stop +voiced]
Symbol t [dental stop -voiced]
Symbol d [dental stop +voiced]
Symbol c [palatal stop -voiced]
# This *probably* won't appear in the modern version.
Symbol ɟ [palatal stop +voiced]
Symbol k [velar stop -voiced]
Symbol ɡ [velar stop +voiced]
# This *may* appear so some intermediate thing
Symbol ʔ [glottal stop -voiced] # I *guess* it's -voiced? Either that, or absent.
Symbol s [dental fricative +sibilant -voiced]
Symbol z [dental fricative +sibilant +voiced]
# This should appear in the final result
Symbol ɕ [palatal fricative +sibilant -voiced]
# This should not
Symbol ʑ [palatal fricative +sibilant +voiced]
Symbol f [labial fricative -voiced]
Symbol v [labial fricative +voiced]
Symbol θ [dental fricative -voiced]
Symbol ð [dental fricative +voiced]
# This shouldn't appear in the final result
Symbol ç [palatal fricative -voiced]
# This should
Symbol ʝ [palatal fricative +voiced]
# This should always be labialized in the final result; that's *a* way to handle Sj
Symbol x [velar fricative -voiced]
Symbol ɣ [velar fricative +voiced]
# I don't really want to have the voiced version in here
Symbol h [glottal fricative -voiced]
Symbol r [dental approximant +voiced]
Symbol l [+lateral dental approximant +voiced]
Symbol ʎ [+lateral palatal approximant +voiced]
</pre>
<p>Good night.</p>
Conlanging 2021-06-032021-06-03T04:00:00-04:002021-06-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-03:/conlanging-2021-06-03<p class="first last">It's annoying that this comes down to dozens of subjective judgement calls at the lowest level, but I guess it shouldn't be <em>surprising</em>.</p>
<p>Okay, I've <em>maybe</em> got every consonant I'll need, and a few I'm not sure about, entered into my sound change file, with just a bit of IPA fudging.</p>
<p>It wasn't hard to add support for stress on top of that, and now my big issue is, if I want to have "pitch accent" show up in the modern version of the language, then how do I represent that?
Swedish pitch accent appears to be a distinction that reliably stays with words (mostly) regardless of dialect, but the details of the <em>realization</em> vary by dialect.
The thing that's confusing me in terms of representation, is that the pitch contours for the accents pass through more tones than there are syllables in the words.
So, I can't just cram diacritics onto the syllables.
Can I?
I think what would make the most sense to me would be to have a "peak" diacritic that attaches to the syllable.
That would basically leave the details of the timing to "how many peaks are there?"</p>
<p>(I should probably also add secondary stress, but I'm going to hope that's not too hard.)</p>
<p>My plan now is to sleep on this, make sure it all makes sense, then add in "peak" diacritics and secondary stress markers.
From there, the next step is to validate my feature definitions to make sure I didn't use characters that I shouldn't have.
After that, I'll look into specifying the kinds of things I want to validate in the wordlists, and work on a validator for the end state.
At that point, I'll have to make the call on whether to make this some kind of multi-stage thing.
Unless I've missed something, I don't see a way to add and drop lines purely within Lexurgy, so I <em>think</em> I need to rope in some other form of text processing.
That's something to look into more carefully later, now that I've probably got all but two symbols defined.</p>
<p>The other "fun" thing is going to be discovering what should have been binary, what should have been univalent, and which contentious and academically-recent debates I managed to accidentally pick a side on, and how that's going to mess with my sound change rules.</p>
<p>Thinking ahead...
I've got a bunch of simple changes planned, but what I should probably be thinking about more is stress-dependence.</p>
<p>Anyway, <em>right now</em> I should be thinking about bed.</p>
<p>Good night.</p>
Conlanging 2021-06-022021-06-02T04:00:00-04:002021-06-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-02:/conlanging-2021-06-02<p class="first last">Not committing to setting up a complicated workflow, but not committing <em>not</em> to.</p>
<p>All right, I got into planning to use Lexurgy, and getting started.
Basically, I have a plan now which <em>may</em> be too complicated, so I'm not committing to it, and I'm currently working on things that I know I'll need: feature definitions, diacritic definitions, and symbol definitions.</p>
<p>Currently, I've got enough to define every vowel sound that I currently know to be relevant (there are like 14), and I'm starting on being able to define consonant sounds.
It's basically going to go: simple consonants, slightly less simple consonants, weird consonants, really weird consonants, stress, pitch.</p>
<p>The possibly-too-complicated plan is to try to invoke Lexurgy from a task runner/build system that will handle stuff like creating affixes, by taking Cartesian products of word list files.
I don't really have a sense for how people are using Lexurgy, so I don't know if that idea is reasonable or not, so, as I said, I'm focusing on the stuff that I can't not need, basically.</p>
<p>Anyway, I'm not sure how to end this, but I don't want to draw things out.
Hopefully I'll get done with this definitional stuff in the next few days.</p>
<p>Good night.</p>
Weekly Roundup 2021-06-012021-06-01T04:00:00-04:002021-06-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-06-01:/weekly-roundup-2021-06-01<p class="first last">What's not reflected here is all the time I put into replaying Hero Core, which probably explains some things.</p>
<ul class="simple">
<li>Wednesday: I went over the first prototype, writing it up and trying to figure out how to relate it to the current prototype.</li>
<li>Thursday: I made a few decisions about typing in the current prototype.</li>
<li>Friday: I wrote a lot of the type-level code in the current prototype.</li>
<li>Saturday: I added a helper function, and then had... technical difficulties.</li>
<li>Sunday: I improved my test coverage, and added some comments.</li>
<li>Monday: I got the code coverage up to full, and started thinking about where this project is going.</li>
</ul>
<p>Next week, I'm going to either make more progress on the current prototype, or try to learn Lexurgy.</p>
Coding 2021-05-312021-05-31T04:00:00-04:002021-05-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-31:/coding-2021-05-31<p class="first last">More rushed, late-night work. I think I'll do better soon, but we'll see.</p>
<p>Didn't do much coding or writing today, since we spent the afternoon visiting family to celebrate <em>almost</em> being done with immunity.</p>
<p>Anyway, I was able to get my new code up to full coverage.
That means the next thing to work on is setting up the runner and list-targets flows.
Then, I just need to make sure that this all more-or-less works, which, given the quality of my current tests in some respects, would actually kind of surprise me.</p>
<p>Taking care of that is just going to involve looking over a few lines of code in the prototype, and figuring out how to adapt some of the hackier bits to Cement.</p>
<p>The basic timeline once I have this seemingly working is going to go:</p>
<ul class="simple">
<li>Test this on itself</li>
<li>Release prototype on PyPI</li>
<li>Host the source code... somewhere. I have some ideas, but I need to make some more decisions about my workflow first.</li>
</ul>
<p>I can't think of too much more that this code needs.
You know, other than the core logic that will drive the task scheduling.</p>
<p>Anyway, I'm going to quickly look over the prototype code while this publishes, then get ready for bed.</p>
<p>Good night.</p>
Coding 2021-05-302021-05-30T04:00:00-04:002021-05-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-30:/coding-2021-05-30<p class="first last">Dealing with cryptic, untested code.</p>
<p>All right, rebooting fixed my keyboard, so that's good.
This is totally the year of Linux on the desktop, just you wait!</p>
<p>Anyway, the code I added last night, and tweaked earlier today, outstripped my test code, so now I've got to work on getting my code coverage back up, and making sure that the error cases all make sense.
Speaking as the author of the code, and someone who is pretty careless about commenting my hobby code, I am looking at this code and kind of going "okay, so that means that, so when <strong>this</strong> condition is true, that means..." and it's just not worth it.</p>
<p>I hope I'll get my energy up further in a few weeks, when I'll feel comfortable walking around town again.
Anyway, I'm going to wrap this up now so I can do whatever, maybe write those comments.</p>
<p>Good night.</p>
Coding 2021-05-292021-05-29T04:00:00-04:002021-05-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-29:/coding-2021-05-29<p class="first last">Going to back up my system overnight in case this persists through reboot.</p>
<p>All right, this is a late start, and I'm not feeling terribly energetic.
Let's see...
Helper functions.</p>
<p>Just added a simple one.
I think the rest are going to be a little more involved.
Let's take a look at the prototype...</p>
<p>Okay, I added some methods from the prototype, and then my keyboard freaked out hard.
I'm typing this on a bluetooth keyboard, and I think I want to be done for now.</p>
<p>Good night.</p>
Coding 2021-05-282021-05-28T04:00:00-04:002021-05-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-28:/coding-2021-05-28<p class="first last">Big shoutout to attrs for writing the vast majority of <tt class="docutils literal">__init__</tt> methods in my hobby projects.</p>
<p>I'm still not feeling particularly energetic, so I didn't work much today, then rushed through working on some of the stuff I was talking about yesterday.
Basically, I've defined a whole bunch of classes and type aliases to be able to reason about Actions and Targets, and now I need to get to work on copying, writing, and testing the various utility functions that the user will have access to.</p>
<p>I don't think there's much to say about what I've got currently.
The code makes sense, but doesn't currently "do" much, but all of the tests and checks pass, so I'm ready to move onto the helper functions.
In the coming days, because it's late right now.</p>
<p>Good night.</p>
Coding 2021-05-272021-05-27T04:00:00-04:002021-05-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-27:/coding-2021-05-27<p class="first last">Gradually remembering the parts of the prototype I didn't want to think too hard about.</p>
<p>I vegged out a bunch today, so I'm just going to sketch out some quick thoughts for the whole action/target thing:</p>
<ul class="simple">
<li>It's probably easier to reason about Targets if they have a more restricted type, even if it is convenient to be able to pass in Paths. As such, they should be normalized internally using <tt class="docutils literal">os.fspath()</tt> or similar.</li>
<li>The actual name should just be strings; I think I want to use NewTypes in the definition of the data structures, just to make sure I don't have a type error in my own code, but the API should just use strings.</li>
<li>Some of the types in the current prototype are going to be simpler than the original, because I'm planning to do more to leverage some, uh, inevitable global state.</li>
<li>The big uncertainty I remember having in the first prototype revolved around mutable state. I'm generally not a fan, but some of this stuff needed to happen <em>somehow</em>. Also, some of this stuff is making me realize the appeal of aspect-oriented programming. Maybe this is a sign I should look into how Cement does hooks, and try to fit my desired code into that system.</li>
</ul>
<p>I'll research that last one quickly while this posts, but I should really wrap up.</p>
<p>Good night.</p>
Coding 2021-05-262021-05-26T04:00:00-04:002021-05-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-26:/coding-2021-05-26<p class="first last">Looking at my code from a few weeks ago and going "Hm, that's not documented well."</p>
<p>I feel like I wasn't really focused today, so instead of trying to write code, I'm going to go over the prototype in more detail, and relate it to the current work-in-progress.
So, the current current work-in-progress is capable of locating a configuration file through various means, and executing it.
The basic details of that are:</p>
<ul class="simple">
<li>In writing tests, I have come to suspect that my design for the location logic is flawed, and tries to do too much, but I'll hold off on messing with it for now. I'll put in an issue for myself to revisit it, though.</li>
<li>Currently, the configuration file is executed as Python code, and relies on API calls that don't exist yet. My long-term plan is to see what capabilities I require, and switch to a more restricted configuration language that satisfies my requirements.</li>
</ul>
<p>Anyway, it can figure out which directory the configuration file is in, and I'm currently planning to have it change to that directory once it finds it.</p>
<p>That said, once the configuration is loaded, there are two basic things to be done: either print out various helpful bits of information, or, by default, execute the desired tasks.</p>
<p>To handle this, the prototype uses a "registry" object that contains various mappings and sets.
These use strings (for several different purposes), and types called "Actions" and "Targets".
Basically, Actions can have names (for diagnostic purposes) and Targets can have names (for selection/deselection purposes).
Every Target has an associated Action, and an Action can be associated with any number of Targets.
An Action is a Callable with a particular signature, and Target is somewhat less defined.</p>
<p>Basically, as inspired by various build systems (and to be clear, I do not consider this project a build system), a Target will <em>usually</em> correspond to a filesystem path, though this is a matter of convenience and convention only.
It does not normalize Targets, or do any kind of filesystem inspection.
Now, a few of the Targets I'll want correspond instead to <em>removing</em> a file.
I don't need or want much sophistication around handling, so I don't plan to represent "delete this file" in a way the code can explicitly reason about, but I do think it'd be helpful to natively support <tt class="docutils literal">pathlib</tt> objects, so I'd maybe like some kind of wrapper.
Might be as simple as "here's a trivial wrapper class around paths, go wild".</p>
<p>I don't know if that's enough to start with; maybe I need to think about this some more, but I should be ready to firm up the design soon.</p>
<p>It somehow got really late while I was writing this, so I should wrap things up.</p>
<p>Good night.</p>
Weekly Roundup 2021-05-252021-05-25T04:00:00-04:002021-05-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-25:/weekly-roundup-2021-05-25<p class="first last">I was in a lot of pain today. Good thing I cleared my schedule.</p>
<ul class="simple">
<li>Wednesday: I wrote the post while the NAS that the blog is mirrored to was updating itself, which is... precarious. So, I took precautions, which fortunately were not needed.</li>
<li>Thursday: I reworked some of the foundations of my conlang until I liked them better.</li>
<li>Friday: I concluded that it was time to look into Lexurgy. I haven't tried setting it up yet, but the time is ripe.</li>
<li>Saturday: I complained about how my body reacts to stress, and did some conlang work.</li>
<li>Sunday: I complained about the heat, and touched up the task runner code base.</li>
<li>Monday: I carefully planned out the test implementation for opening files with an informative wrapper. I elected for a somewhat "quick-and-dirty" implementation, because I do not know how, or even if, I'm going to rework the actual implementation's requirements in the future.</li>
</ul>
<p>Next week, I'm hopefully going to recover from the vaccine side effects, and make more progress on the task runner and conlang stuff.</p>
Coding 2021-05-242021-05-24T04:00:00-04:002021-05-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-24:/coding-2021-05-24<p class="first last">Taking time to carefully plan the minor detail that I want to get right.</p>
<p>I was busy getting vaccinated today, and then trying to take it easy.
So, I haven't touched code, but there is something I'm trying to work out.</p>
<p>I have a helper function that wraps errors, both expected and unexpected, from the <tt class="docutils literal">open</tt> function in custom exceptions specific to the application.
I want to be sure to test the branches for "I don't know how this happened, but I should account for it".
But I can't test those by making the <tt class="docutils literal">open</tt> function do stuff, because if I knew how to encounter those errors, then I'd need to write more specific error messages, and then inducing those errors wouldn't trigger the branches I want to test.</p>
<p>So, if I can't rely on the built-in function to trigger the branches I want to test, then I need to be able to substitute in a different function.
I've thought of a few possible ways:</p>
<ul class="simple">
<li>Parameterize over the function to use. This would require me to figure out a "good-enough" signature for <tt class="docutils literal">open</tt>, and I kind of don't want to bother.</li>
<li>Put the exception handling in a context manager. This completely decouples the business logic from the diagnostic messages, and for all that "decoupling" and "weakly coupled" are popular buzzwords, I don't think that makes sense.</li>
<li>Mock the <tt class="docutils literal">open</tt> function. I'm leaning towards this, because it lets me defer refactorings, and I don't really have a refactoring that I want to do here.</li>
</ul>
<p>I basically came to that conclusion while I was writing this post in my head, but I figured that was no reason not to write the post on my computer as well.</p>
<p>Anyway, once I take care of this idea, I should be on-track to properly integrate the prototype code and see how it treats me.
Hopefully, I'll have that done in a week or two.</p>
<p>Good night.</p>
Coding 2021-05-232021-05-23T04:00:00-04:002021-05-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-23:/coding-2021-05-23<p class="first last">Slowly baking in the heat and soaking in the humidity, I focus on code quality.</p>
<p>They brought someone to look at our heating system a few weeks ago, and it was working as intended.
So I'm sure it was <em>supposed</em> to heat up when we tried turning on the AC earlier.</p>
<p>That's part of why I didn't get too much done today:</p>
<ul class="simple">
<li>I fixed up some mistakes I'd made with the con-script, and added some consonants I'd forgotten.</li>
<li>I just now added another test and bit of functionality to the task runner code. To get much further, I'll need to properly plan out the various types involved.</li>
<li>I also have the option of trying to improve the file opening handling. I'll feel better about the code I have if it can handle all likely error conditions as exceptions, instead of checking for them proactively. Looks like OSError is the way to handle that.</li>
</ul>
<p>I'll probably mess with that after I publish this, then work on other stuff as a palate cleanser.</p>
<p>Here's hoping things are a bit more pleasant tomorrow, and... vaguely bearable afterwards, since I'm getting my second dose, and my first dose messed me up a little.</p>
<p>Good night.</p>
Diary 2021-05-222021-05-22T04:00:00-04:002021-05-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-22:/diary-2021-05-22<p class="first last">Betrayed... by my own body... again...</p>
<p>I stressed out too much about work, and it is causing me so much pain now, even as I try to think about anything else.
Why is the human body like this?
"Well, I'm worried about doing a good job, so clearly the helpful thing is to violently dehydrate myself and become physically incapable of looking at bright lights, <em>which is basically my job</em>."</p>
<p>It didn't hit me quite that bad this time, <em>no thanks to my autonomic nervous system</em>.
Writing that rant did remind me to rehydrate, so, self-care, yay.</p>
<p>I did some work on a con-script for the conlang I'm working on, but I somehow miscounted the acceptable values in one of the parameters.
("It's a featural script!" *Booooo* "But <em>only in the protolang</em>." *Oooooo*)
Anyway, miscounted, need to rethink this a bit.</p>
<p>And, I took a break from writing between that sentence and this one, and I think I've got some ideas now.
I'll try them out.</p>
<p>I've tried out the ideas.
So far, they seem interesting and solid in isolation, but I'm missing a few key components still, so I can't put it all together yet.
(I'd "put it all together" into transcribing English to start with, because I don't have any words in the conlang to work with, and the phonology I'm trying to put an orthography to is, in spite of some oddness, mostly a subset of English phonology.
The hopefully interesting stuff come from the differences, and also the phonotactics.)</p>
<p>With just a bit more time, I've got a full first draft laid out.
I'll see what I think of it later, because right now I just want to read.</p>
<p>Good night.</p>
Conlanging 2021-05-212021-05-21T04:00:00-04:002021-05-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-21:/conlanging-2021-05-21<p class="first last">Getting to the point where I need real structure to make progress.</p>
<p>I did a little more sketching of sound change dependencies and desired ordering.
I think what I'm missing is an example of how to document them.
I think now it's time for me to look at <a class="reference external" href="https://www.meamoria.com/lexurgy/app/sc">Lexurgy</a>.</p>
<p>Reading over the documentation, I think Lexurgy has most of the stuff I want, I just have to put in the effort to understand it, and get everything to line up with my current ideas.</p>
<p>I'll be doing that later, because I didn't get enough sleep last night, and I was tired all day, and I'm tired now.
I'll have to try to fix that over the next few days.</p>
<p>Good night.</p>
Conlanging 2021-05-202021-05-20T04:00:00-04:002021-05-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-20:/conlanging-2021-05-20<p class="first last">Closing in on a sketch of protolanguage phonology and development.</p>
<p>I spent some time trying out different ways to achieve palatalization.
Here's basically what I was thinking:</p>
<p>"It looks like the development of palatalization was pretty straightforward in Greek, but if I change the phonology to be closer to Swedish, then that changes the available sounds produced by palatalization.
I think that motivates some limited changes in voicing for certain consonants. ...
Okay, it's a little tricky to come up with a satisfying derivation for this that fits with everything else."</p>
<p>I've come up with two basic ways to try to resolve this.
The first felt excessively fine-tuned, but I like the second.
I can't guarantee that I won't come up with a third that I like more.
Anyway, I'll stick with this second idea for now, and try to firm things up.</p>
<p>Here's what's missing from my plans: lots of things relating to stress, such as vowel length.
Beyond that, I basically know how I want stuff to fit together from a phonological perspective.
The biggest unknown is that I'm pretty sure I want some kind of vowel sound to be present in the protolang and get dropped, and I'm still deciding what kind of sound, and when this happens in relation to determining stress.</p>
<p>Anyway, I'm going to publish this, and then try to do some prep work for something else that probably won't have a blog post associated.</p>
<p>Good night.</p>
Diary 2021-05-192021-05-19T04:00:00-04:002021-05-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-19:/diary-2021-05-19<p class="first last">Not getting problems from the outside world, so making problems for myself.</p>
<p>I am upgrading some of the software on my home network.
I did not realize I was going to be upgrading some of the software on my home network.
The files I am modifying by writing this post are currently in a somewhat precarious position, so it's a bit difficult to focus on writing the blog.
I am making multiple manual backups in case of corruption.</p>
<p>All in all, I'm not comfortable working on any projects until the migration is complete.
So, what else is going on?
Well, my allergies left me alone today, even though I forgot to take antihistamines.
I'm not sure how that works, since the tree pollen levels were apparently terrifying.
At some point, I really should work out exactly what I'm allergic to, because all I know at this point is, it's seasonal.
For now, though, I'm not going to poke my head outside and be all "Where's the suffering? I was promised suffering!"
That's only for tabletop games.</p>
<p>Anyway, that's all I'm up for writing right now.</p>
<p>Good night.</p>
Weekly Roundup 2021-05-182021-05-18T04:00:00-04:002021-05-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-18:/weekly-roundup-2021-05-18<p class="first last">It's hard to write much about this stuff, but it feels good, so I like that.</p>
<ul class="simple">
<li>Wednesday: I continued working on allowable onsets for the conlang.</li>
<li>Thursday: I finished up the first version of the onset chart.</li>
<li>Friday: I planned out some tests for the task runner.</li>
<li>Saturday: I was tired, so I just did some planning, and asked for suggestions for Python tooling to introduce. We'll see where that goes.</li>
<li>Sunday: I evaluated the consonant cluster chart, and started writing new tests for the task runner.</li>
<li>Monday: I got code written to make the tests pass, and did some conlang planning.</li>
</ul>
<p>Next week, I'm going to keep up the mix of projects, probably leaning more on conlanging until the weekend.</p>
Coding 2021-05-172021-05-17T04:00:00-04:002021-05-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-17:/coding-2021-05-17<p class="first last">How many ways can I come up with for the code to refuse to do anything? A lot.</p>
<p>Okay.
I've written up a bunch of tests for error cases, and soon I'll probably want to factor out the really repetitive stuff, because wow this test code is repetitive, and I messed it up at least once.
A few more iterations, and I'll be forced to come up with actual interfaces to the task runner library.
Right now, it's still just "oh, can't run tasks because of X reason".</p>
<p>Not really much to say on that for now, I guess.
It's late, so I'll work on the refactorings later.</p>
<p>The other thing I want to cover is for the conlang, and it is deriving sound change rules from my initial consonant cluster work to try to derive a protolang phonology and phonotactics.
It's probably going to be a pain, but I expect it to be less bad than the kind of stuff I've tried to do before.</p>
<p>Good night.</p>
Coding 2021-05-162021-05-16T04:00:00-04:002021-05-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-16:/coding-2021-05-16<p class="first last">"This is probably impossible, so in a way, it's like I'm already done."</p>
<p>Okay, a few things today:</p>
<p>In non-coding stuff, I went over the initial consonant clusters for the conlang, and cleaned up the chart and made a few changes.
Going over it made me realize that I'd somehow misinterpreted part of Swedish phonology, but I think I'll stick with my initial interpretation, as a way to make this <em>slightly</em> more like its own thing.</p>
<p>In coding, I wrote a bunch of basic tests for handling configuration, focusing for now on some very basic error cases.
Most of the work went into writing test fixtures; I may end up reconsidering these fixtures and cursing my past self later, but for now, I'm just really liking how simple the interfaces and tests are.</p>
<p>I feel like this initial push has me doing things in a more test-driven-development kind of way; I guess I don't want to overthink things when it comes to the code as I write it.
And to get that, I basically have to be writing a test, then figuring out the lowest-effort way to get it to pass.
Speaking of which, I'll try to make all those failing tests I wrote actually pass.</p>
<p>(Actually, thinking about the test changes and additions I did, I'm not sure test-driven development can be formalized to the level of strictness required by one of the projects I have back-burnered, so I... maybe won't revisit that project.)</p>
<p>Anyway, time to do minor rewrites and try to figure out the different between <tt class="docutils literal">app.args</tt> and <tt class="docutils literal">app.pargs</tt> in Cement.</p>
<p>Good night.</p>
Diary 2021-05-152021-05-15T04:00:00-04:002021-05-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-15:/diary-2021-05-15<p class="first last">Crowdsourcing my tooling ideas.</p>
<p>I more-or-less took things easy today, because I woke up tired and that never really turned around.
I intend to rewrite the tests for the task runner tomorrow, and also go over some details of conlang phonotactics.
Neither of those will look like much from the perspective of the blog; oh well.</p>
<p>I don't have anything else to write about right now, I'm just really tired.
Here's an idea: in a few weeks, I should have my task runner in good enough shape to run against its own repository, and that'll give me the freedom to add all kinds of crazy opt-in testing and analysis.</p>
<p>What I have currently:</p>
<ul class="simple">
<li>Normal tests, code coverage, and profiling</li>
<li>A variety of lints, including vanilla flake8 and isort (I haven't added black, and I would like to)</li>
<li>Type checking</li>
<li>Barebones HTML report generation from xunit results</li>
</ul>
<p>What I'm planning to add:</p>
<ul class="simple">
<li>Property-based testing using Hypothesis</li>
<li>Mutation testing using <em>something</em>, I haven't thought too hard about it</li>
<li>Documentation-related lints</li>
</ul>
<p>What I might add:</p>
<ul class="simple">
<li>Pylint</li>
<li>Something like pytest-bdd? I dunno.</li>
<li>There's something called semgrep? It might help? With something?</li>
</ul>
<p>What I'm interested in suggestions for:</p>
<ul class="simple">
<li>Literature on developing better workflows for profiling</li>
<li>Linters besides anything listed above, and also besides wemake-python-styleguide</li>
<li>Other things that plug into flake8</li>
<li>Other static or semantic analysis</li>
<li>Other things that evaluate the code by running it</li>
<li>Fancier xunit -> html conversion</li>
</ul>
<p>Basically, I'm going to want stuff that runs non-interactively from the command line, and can be convinced to output all relevant feedback in a form that, one way or another, ends up as a webpage.
It should also be configurable in terms of what files it writes to, if any, such that I can run multiple processes in parallel in the same directory.</p>
<p>Anyway, if anyone has any suggestions there, my Mastodon account is right down there, so have at it.
For now, I desperately need more sleep.</p>
<p>Good night.</p>
Coding 2021-05-142021-05-14T04:00:00-04:002021-05-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-14:/coding-2021-05-14<p class="first last">Most of this post is devoted to figuring out how to test a single command-line argument.</p>
<p>Okay, let's see what's the minimal configuration I can get set up and tested.
I believe that would be "locate a config file".
Here's what I have in mind:</p>
<ul class="simple">
<li>If no configuration file is provided, the program recurses up into parent directories until it locates it, with a default name.</li>
<li>If an argument is provided, the program will not recurse upward; it will check the exact path given.</li>
<li>If the path is a directory, it will look for the default name in that directory.</li>
<li>If the path is a file, it will look for that exact file path.</li>
</ul>
<p>(Since paths don't inherently have "directory-nature", I guess this means it needs to check whether the path exists before doing any specific logic to it.)</p>
<p>Test cases when the path is not given:</p>
<ul class="simple">
<li>Find the file in the directory</li>
<li>Find the file in a parent directory</li>
<li>Handle file not existing</li>
</ul>
<p>Test cases when the path is given:</p>
<ul class="simple">
<li>Absolute/relative</li>
<li>Current/child/parent/cousin</li>
<li>File/directory</li>
<li>File exists/does not exist</li>
<li>(For the specific case of absolute+cousin, have a test for not cd-ing to a tmpdir first, as well as doing so)</li>
</ul>
<p>To check when the file exists: that the current directory is the directory that contains the file.
(This is fine to check even with the error case, because it's being set in-process, and will be cleaned up by the test finalizer.)</p>
<p>Error cases to handle when the file does exist:</p>
<ul class="simple">
<li>File is not syntactically valid</li>
<li>File raises a runtime exception</li>
<li>File does not produce configuration object</li>
<li>Configuration object is not valid</li>
</ul>
<p>I don't want to get as far as actually consuming the configuration object; that's an entire set of extra dimensions to deal with.
And that up there is already plenty to mess around with.</p>
<p>I think I basically want execution to happen in phases:</p>
<ul class="simple">
<li>Parse command line (handled by Cement); <em>do not</em> inspect the filesystem at this point</li>
<li>Resolve the configuration file</li>
<li>Evaluate the configuration file</li>
<li>(Update defaults from the configuration file. Not quite a thing to do, because I haven't yet planned config that would do anything)</li>
<li>Check whether to list targets from configuration, exit early if so</li>
<li>Determine which targets to include (this has no bearing on the target listing, so can be done after)</li>
<li>Queue all targets via the runner
- Runner updates progress bar or something</li>
<li>Report successes, failures, and errors.</li>
</ul>
<p>I'm trying to figure out the best order to work on this.
In the first prototype, I focused on the core runner logic, and left the fine details of input and output to the wayside.
I guess the first question I should ask is, does Cement have any opinions germane to this kind of structure?
Let's see...</p>
<p>Not seeing anything from a kind of superficial look.</p>
<p>The last thing I want to work out tonight is how to only test the outer layers.
I was imagining some fancy stuff, but as I think about it, I realize the answer is to just stub out the low-level logic with functions that always succeed.
Anyway, when it comes time to test those, I want to either make the tests really fast, or restrict the scope of config file location shenanigans.</p>
<p>So, that's the kind of stuff that I'll want to test with the external interface.
Good rubber-duck session.
Not sure when I'll be good to start implementing these tests, but at least I have a solid foundation to start from.</p>
<p>Good night.</p>
Conlanging 2021-05-132021-05-13T04:00:00-04:002021-05-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-13:/conlanging-2021-05-13<p class="first last">Some of the clusters I found were surprising. Sometimes, that was because they were in loan words.</p>
<p>All right, I've got my preliminary version of the consonant clusters for <em>onset</em> put together.
I'll wait a few days, and then see what I think.
It's possible that I've "missed" some consonant clusters that I'd like to have, but my intuition is that I should be trying to keep things lean.
I think I'd like to evaluate the onsets before I start thinking about what can go in the codas, which is going to be a whole thing, given the current restrictions I want to put on word shape.</p>
<p>After I publish this entry, I'm going to take things easy, and <em>maybe</em> get back to work on the task runner prototyping.</p>
<p>Good night.</p>
Conlanging 2021-05-122021-05-12T04:00:00-04:002021-05-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-12:/conlanging-2021-05-12<p class="first last">Figuring out all the sounds this language can't make, and the surprising ones it can.</p>
<p>Still working on defining allowable consonant clusters.
I'd have made better time if my body hadn't <em>freaked out and betrayed me</em> two days ago, but oh well.
I'm currently working on onsets, mostly.
I think I've got preliminary rules for all stops, and I'm liking the system I have so far.
(That is, the system for figuring out which combinations to allow.
I haven't gone over the current candidates out loud yet.)
It probably won't work as well for codas, unfortunately, but that's not a pressing concern yet.</p>
<p>Today, I also updated dependencies in some of my projects, and good thing, too, because I'd somehow missed properly recording some changes that I'm <em>sure</em> I did the proper legwork for.</p>
<p>I'm going to wrap up now and try and get some time away from my screens.</p>
<p>Good night.</p>
Weekly Roundup 2021-05-112021-05-11T04:00:00-04:002021-05-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-11:/weekly-roundup-2021-05-11<p class="first last">Some progress, a little less than I'd have liked, interrupted by minor but unpleasant medical issues.</p>
<ul class="simple">
<li>Wednesday: I started getting really frustrated with the whole quarantine... situation.</li>
<li>Thursday: I revived the conlanging category with the language I've been messing with recently.</li>
<li>Friday: I described the language's inspirations, and some of the trouble I was having researching them.</li>
<li>Saturday: I did a little better digging up sources, and drew up a list of stuff to work on with the conlang, which I haven't really gotten past the first item yet.</li>
<li>Sunday: Traveling messed up my body.</li>
<li>Monday: Pollen messed up my body.</li>
</ul>
<p>Next week, I'll try to make some more progress on the conlang front, and I might start touching code again.
I understand some of the projects I'm relying on are just a few days out from a major release, so that'll be nice.</p>
Diary 2021-05-102021-05-10T04:00:00-04:002021-05-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-10:/diary-2021-05-10<p class="first last">I want to get off Mr. Pollen's wild ride.</p>
<p>Not so much luck doing stuff today, because my allergies kicked into overdrive, which was an entirely different issue to what I was dealing with yesterday, but really, I don't like any of these situations.</p>
<p>I did manage to clean up the conlanging stuff in a way that made a bit more sense to me, but there's still quite a bit of work to be done.
I'm going to make some further improvements after I publish this, but the main thing I'm going to do is lie around and wait for my face to stop leaking.</p>
<p>Good night.</p>
Diary 2021-05-092021-05-09T04:00:00-04:002021-05-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-09:/diary-2021-05-09<p class="first last">Getting really tired of the predictable, if not fully comprehensible, things my body does.</p>
<p>I did a little setup work for conlanging, but not enough to merit putting it in the category.
Bit of a rough day today, so I was mostly just trying to take things easy.
Tomorrow will probably be the same, then it's the work week, then maybe next weekend will go easier on me.
The weekend after that, I'll potentially have difficulty breathing, in preparation for breathing easier two weeks after that.</p>
<p>For now, though, I want to wrap up and take care of myself.</p>
<p>Good night.</p>
Conlanging 2021-05-082021-05-08T04:00:00-04:002021-05-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-08:/conlanging-2021-05-08<p class="first last">Seems to me like there's way more stuff available for ancient Greek than modern Greek, but I specifically want modern Greek. Oh well.</p>
<p>I looked into asking for help, and I concluded that there are a few resources I didn't properly search for; I now have candidates for those, and I can use those to be better-informed when I do ask for help.
One thing I'll need to keep in mind, I suppose, is that I'm not <em>obligated</em> to get the phonotactics to be super-close to any existing language; I just feel like it would help aesthetically.</p>
<p>Maybe the right approach is to see how far I can get, based on what I've found so far.</p>
<p>I'll work on that over the weekend, I hope, but what I want to figure out right at this moment, is how much I need to have worked out before I'll show off something.</p>
<p>So, I'll try to put together a list here, and then post this.</p>
<ul class="simple">
<li>Allowable consonant clusters, and repair strategies</li>
<li>Details of phonological realization</li>
<li>Inventory of function words</li>
<li>Set of basic content words</li>
<li>Sample text</li>
</ul>
<p>Probably more things in between those items.
Anyway, it's late, I'd like to wrap up sooner than I have been.</p>
<p>Good night.</p>
Conlanging 2021-05-072021-05-07T04:00:00-04:002021-05-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-07:/conlanging-2021-05-07<p class="first last">I felt like I was constantly tripping over weird statements when reading up on this in Wikipedia.</p>
<p>I took a start at describing the intended phonotactics of my current conlang project.
It's probably going to go through a lot of revision still.
I'm going to need to either seek out some seemingly-obscure papers, do actual linguistic legwork, or just wing it, when it comes to basing syllable structure off of the inspirations for this language, though.</p>
<p>I should probably go through my creative process thus far:</p>
<ul class="simple">
<li>Stative verbs are cool.</li>
<li>What if I made negation into an aspect marked on a stative verb?</li>
<li>(months pass)</li>
<li>I want to pursue this language seriously, and come up with an entire elaborate conworld for it to live in.</li>
</ul>
<p>At some point in all of this, jan Misali releases their <a class="reference external" href="https://www.youtube.com/watch?v=JICvHFl7W6o">video on Quenya</a>, and notes that Quenya did not copy Finnish vowel harmony, I agree that this seems like a shame, and decide to be the change.</p>
<p>I kind of see this language as having goals at different levels.</p>
<ul class="simple">
<li>Technical level: prove out my ideas about using stative verbs</li>
<li>Aesthetic level: get some vowel harmony in there, and also draw from languages thematically connected to the speakers in the conworld; this connection is somewhat loose, but I feel like there's some aesthetic potential in trying to draw together the sounds of Greek and Swedish, so I'm sticking with that.</li>
</ul>
<p>In the past, I've tried to put together phonologies in an a-priori kind of way, and that was really unpleasant for me.
At least for now, I prefer the experience of taking natlang phonologies, looking for the distinctive elements, and trying to harmonize them together.
It's possible that, with enough experience, I'll get a sense of which parts can be properly considered as components that can be combined, but I don't want to jump the gun.</p>
<p>I feel like the main obstacle I'm hitting currently is, I can find some information on Greek and Swedish phonotactics, but it's not quite as much or as clear as I would like.
There are either glaring gaps in the literate I've found, or stuff that I "should be" filling in because it's "obvious" and I don't quite have a sense of it.</p>
<p>I think at this point, I should be asking people for help rather than shouting into the void like usual.
I'll get on that in the next few days.
For now, it's super late and I should sleep.</p>
<p>Good night.</p>
Conlanging 2021-05-062021-05-06T04:00:00-04:002021-05-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-06:/conlanging-2021-05-06<p class="first last">I'm going to need to get over my aversion to specifics in talking about this. It's a pretty transparent attempt to deflect potential criticism via obscurity.</p>
<p>I can't tell if I'm feeling any better or not.
Anyway, since I did a decent amount of worldbuilding (nowhere near done, though), I decided to focus on actually getting the language that inspired literally all of this into a decent state.
Right now, I'm trying to shore up the basics of it, figure out stuff I missed.
Here's what I'm seeing so far:</p>
<ul class="simple">
<li>I have a list of most phonemes, but it's missing some phones that arise from interaction between phonemes.</li>
<li>The relevant interactions aren't fully documented, because I essentially slammed the phonologies of two (technically three) languages together, in a way that turns out to create possibly-novel interactions.</li>
<li>I haven't properly documented which combinations of sounds are disallowed, and what repair strategies they'll get.</li>
</ul>
<p>I'm going to have to get really good about writing this down.
I don't think any of the rules I need to formalize are complicated on their own, but there are a lot of them.</p>
<p>Anyway, I'm not going to get that done now, so I'm going to need to remember to do that later.</p>
<p>Good night.</p>
Diary 2021-05-052021-05-05T04:00:00-04:002021-05-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-05:/diary-2021-05-05<p class="first last">I am in a relatively cushy and secure position and this still <em>sucks</em>.</p>
<p>So, I did some worldbuilding work this morning, went to work in the exact same place that I do everything else, took a nap because I was losing my edge by the end of all that, and then did my usual afternoon stuff.
I didn't get much more done afterwards.</p>
<p>I'm feeling a bit frustrated from that, and I don't think it's a case of "I wanted to do more with my projects", though having more done is always nice.
The fact is, I just did not like how I felt today, and that's that.
In a few weeks, I'll hopefully be confident enough to go outside on the regular, but until then, not only am I waiting for my body to properly dial up its immune responses, but the trees are out there giving me immune responses that I <em>don't</em> want.</p>
<p>Oh well, better try to sleep some of this off.</p>
<p>Good night.</p>
Weekly Roundup 2021-05-042021-05-04T04:00:00-04:002021-05-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-04:/weekly-roundup-2021-05-04<p class="first last">Being tired is no joke.</p>
<ul class="simple">
<li>Wednesday: I worked on understanding how the generated Cement app fits together.</li>
<li>Thursday: I was extremely tired, so I had to write a short post about how I had to write a short post because I was extremely tired.</li>
<li>Friday: I did the easy parts of splitting up the entry point module for the cement app.</li>
<li>Saturday: I did the slightly less easy part of splitting up the code, and started working on the coverage.</li>
<li>Sunday: I got coverage up as high as I care to for now, and started planning tests for the new code that's going in soon.</li>
<li>Monday: I was sleepy again, so I did more detailed planning.</li>
</ul>
<p>Next week, I'm going to take a break from coding and work on conlang/conworld/conculture stuff.
Maybe touch the code again over the weekend.</p>
Coding 2021-05-032021-05-03T04:00:00-04:002021-05-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-03:/coding-2021-05-03<p class="first last">I would like to offer more constructive criticism of the tests that I'm not sure about, but I don't have the energy right now.</p>
<p>Okay, so, something about today hit me hard and I'm pretty low on energy, so I'm just going to write up the current state of the task runner's tests, and figure out if there's anything to salvage, or if I should just write now tests and delete these.</p>
<p>So far as the generator-provided tests go, theres:</p>
<ul class="simple">
<li>With nothing special done, the CLI exits with status code 0. This does not correspond to the behavior I want; the task runner will <em>require</em> a configuration file, so it should search for one and error out. This gives us two tests: expect an error with no configuration file, and expect minimal output and success given a minimal configuration file.</li>
<li>The base command accepts a <tt class="docutils literal"><span class="pre">--debug</span></tt> flag. I haven't decided whether that fits into the design or not. I'll either drop it, or make it parameter to the test above.</li>
<li>The final generated test runs the subcommand with various arguments and makes assertions about the resulting render calls. While I want tests against the subcommand, I'm not sure how I feel about the specific things that these tests look for.</li>
</ul>
<p>I think my plan is to sketch out the code that I want to try to test first, see if there are any dependencies I should work on first, then write tests based on the sketches and work on getting the tests to pass.</p>
<p>Since I'm kind of out of it right now, I think the smart course of action is to take a break for a few days and work on other things in the meantime.
For now, I'm going to wind down a little earlier than usual, because I'm tired and I might have a rough day ahead of me.</p>
<p>Good night.</p>
Coding 2021-05-022021-05-02T04:00:00-04:002021-05-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-02:/coding-2021-05-02<p class="first last">Setting stuff up, and preparing to knock it down and set up something different and more complex.</p>
<p>All right, source coverage at 100%, missed function in my conftest that came from the template; I don't want to delete it until I understand what the purpose of it was.
Once that was done, I started figuring out what it would take to port the first prototype code into the second prototype.
This is going to take a lot of work to define the relevant tests, since suddenly the code is going to care significantly about the filesystem in a way it doesn't currently.</p>
<p>I think I want a function-scoped fixture that sets up and tears down a temporary directory, and allows writing files under that directory.
Then, it's just a matter of performing various iterations of, "point the code or the arguments at the directory, and make sure everything resolves as expected".
Also going to need to make sure that the current directory gets reset at the end of every test, if pytest doesn't handle that already.
Let's see, I guess that could be done by using the monkeypatch fixture and patching its <tt class="docutils literal">chdir</tt> method over the <tt class="docutils literal">os.chdir</tt> visible to part of the program logic.
Bundle that up in a fixture itself, because I'm going to want to do that a lot, but I don't want to write it a lot.</p>
<p>Once all of this is written, or at least better planned, I'll need to go over the existing tests and figure out how to fix them, because this logic is probably going to apply to them.</p>
<p>Kind of pondering making the fixture auto-use and making it consume marks do do stuff like "add a default configuration file".
This is all interesting and slightly complicated and something I shouldn't work on at this time of night.</p>
<p>Good night.</p>
Coding 2021-05-012021-05-01T04:00:00-04:002021-05-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-05-01:/coding-2021-05-01<p class="first last">Number go up!</p>
<p>Okay, I got the main function into a more testable state, in a low-effort way that I can confirm didn't break the script endpoint.
My plan is to get application code to full coverage, then start translating my plans for interfaces into test updates.
Hopefully, this will all translate to a second prototype within a few weeks.</p>
<p>Other stuff that's happening...
Well, Pijul's infrastructure is apparently shored up enough now, because it's under active development, as of, like a few days ago, up through a few hours ago.
I've got some interface changes I want to try out, but I think it makes sense to wait for a release; there is all kinds of stuff going on in there.</p>
<p>Anything else?
Mostly, I need rest, so I'll try to wrap up now.</p>
<p>Good night.</p>
Coding 2021-04-302021-04-30T04:00:00-04:002021-04-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-30:/coding-2021-04-30<p class="first last">I accidentally reduced my coverage because the tests now have fewer transitive imports.</p>
<p>All right, I'm working on splitting stuff up right now.
I'm pretty tired, so I probably won't get too far tonight, but I have split things up a little.
Right now, I'm trying to decide what to call the module for the test app class.</p>
<p>This is one of the classes generated by the default Cement template.
It's a modification of the core app class via mixin inheritance, that's more convenient for testing in ways that I haven't really looked into.
The point is, the current tests use this, and I could see an argument for packages that extend the task runner's functionality using it for integration tests.
Will there be such packages?
Well, I intend to put most of the code specific to my use cases into one, in order to keep the core package small.
Point is, even though the definition of the test app class is trivial (in that it is less than ten lines, and anyone who's worked with Cement could write those lines <em>without looking at any part of my code except the app class name</em>), I'd rather have it defined once than make every downstream package that wants it reimplement it.
I'm leaning towards <tt class="docutils literal">test_helpers</tt>.
The only thing I'd need to be sure of there is to make sure to name the fixture I associate with the module a little differently, because last time I tried that kind of naming, I discovered a... behavior that I did not like, in one of Coverage.py's features.
I'll do it, and make sure it all still works.</p>
<p>And, got it.
It's getting late, and the rest of the changes are somewhat more involved, so I'll leave things here and get back to it over the weekend.</p>
<p>Good night.</p>
Diary 2021-04-292021-04-29T04:00:00-04:002021-04-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-29:/diary-2021-04-29<p class="first last">Bad habits, bad post.</p>
<p>I wanted to get stuff done today, but I've been slightly wrecking my sleep schedule and now I'm really tired, so I guess I don't get that.</p>
<p>Honestly, it's really annoying me that I feel like I don't have the focus to even write about anything else for this.</p>
<p>I'm going to try wrapping up and getting off my laptop, because I don't see any kind of <em>specific</em> goal that I can "power through" towards, or whatever.</p>
<p>Good night.</p>
Coding 2021-04-282021-04-28T04:00:00-04:002021-04-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-28:/coding-2021-04-28<p class="first last">Reading up before making a bunch of sweeping changes</p>
<p>I think I need to try to explain what Cement is doing, to decide if I want to do it any differently.
So, inside the package, we have:</p>
<ul class="simple">
<li><tt class="docutils literal">main.py</tt> defines the basic App class, a "testable" version of that class, and a harness for running the app. The separation here seems to be that the app's <tt class="docutils literal">run</tt> method handles the very high-level happy-path behavior, and the harness handles a few aspects of cleanup that can't really be ignored. Due to the way it's structured, I think the bulk of the <tt class="docutils literal">main()</tt> function could be rewritten as a context manager and thereby made testable. I don't know if I want this all in the same module. I have some ideas there that I haven't fully fleshed out.</li>
<li><tt class="docutils literal">templates</tt> contains a sample template for presenting output. I hadn't thought of using Jinja in a command-line application, but I like the idea. (I mean, I was thinking of using it in the virtual tabletop thing that this is all supposed to make easier to develop, but that was at a higher level of abstraction, and I haven't <em>done it</em> yet.) I'm looking at the Jinja extension to get some understanding of how this all works. (One thing that occurs to me, is that it would be helpful to define <tt class="docutils literal">extras_require</tt> in the setup command so that users can do like <tt class="docutils literal">pip install <span class="pre">cement[name-of-optional-plugin]</span></tt> and get exactly the packages required for a plugin, even if the precise details may change.) Anyway, the big thing I'd like to figure out how to do with the Jinja extension is to define custom filters. I think I do that by resolving the app's jinja template handler and messing with its <tt class="docutils literal">env</tt> attribute. That has to be done <em>before</em> rendering anything.</li>
<li><tt class="docutils literal">plugins</tt> and <tt class="docutils literal">ext</tt> are empty, and <tt class="docutils literal">core</tt> just defines a custom exception type.</li>
<li>The main business logic lives in <tt class="docutils literal">controllers</tt>, which has a <tt class="docutils literal">base.py</tt> module that defines the command-line interface. What I want in here is a default handler that launches the tasks and takes an argument for specifying "targets", and a handler for listing available targets (default and non-default)</li>
</ul>
<p>Testing the core logic will require something akin to pytest's helpers that create and populate temporary directories.</p>
<p>Anyway, here are the tickets I need to put in for myself:</p>
<ul class="simple">
<li>Specify and rework controllers</li>
<li>Convert the exception handler into a context manager, or just a higher-order function, or setting the app class as a default argument</li>
<li>Split out the <tt class="docutils literal">main</tt> module into modules defining classes, and try having minimal logic in <tt class="docutils literal">main</tt></li>
<li>Write a hook for injecting filters into the template environment</li>
</ul>
<p>I'll get those in, then publish, then get to bed.</p>
<p>Good night.</p>
Weekly Roundup 2021-04-272021-04-27T04:00:00-04:002021-04-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-27:/weekly-roundup-2021-04-27<p class="first last">So many things are SOON.</p>
<p>Whew, I'm over the hump of initial vaccine symptoms.
That was something.
Just one month until I have to do it again, yaaay.</p>
<ul class="simple">
<li>Wednesday: I mostly tweaked my Mercurial configuration.</li>
<li>Thursday: I went overboard with topics, and decided the result was basically fine.</li>
<li>Friday: I did some basic repository maintenance and tried out towncrier against my repo.</li>
<li>Saturday: I got vaccinated.</li>
<li>Sunday: I took it easy because I got vaccinated the day before.</li>
<li>Monday: I got to work on automated analysis and testing of the task runner, which doesn't yet have any task runner code in it.</li>
</ul>
<p>Next week, I'm going to document some improvements that I made to some of my other noxfiles, and try to regularize and further improve them.
I'm going to work on some of the stuff I mentioned yesterday after I publish this.</p>
Coding 2021-04-262021-04-26T04:00:00-04:002021-04-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-26:/coding-2021-04-26<p class="first last">I'm starting to see the potential here, but I'm still not sold on the entire package.</p>
<p>I've got my noxfile put together, and now the issue I have left to fix is test coverage.
Fixing test coverage kind of gets into a question of organization (because I prefer to have per-source-module test modules), and I'm not super enthusiastic about the default organization that the Cement generator gave me.
It's hard for me to get a handle on the code, and I still, after quite a bit of investigation, don't understand how some of the values it needs at runtime are getting populated, so I can't be comfortable changing some of the layout.</p>
<p>I'm going to have to take some time later to get the exact set of behaviors I want for the runner worked out, and figure out how to translate that into Cement concepts.
For now, I need to rest.</p>
<p>I felt some aches today that I haven't felt in, I think, over a year.
I wasn't missing them.
I think the current round of soreness and pain is ebbing; we'll have to see if my body comes up with a new and unexpected immune response that it hasn't thought of yet.</p>
<p>Good night.</p>
Diary 2021-04-252021-04-25T04:00:00-04:002021-04-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-25:/diary-2021-04-25<p class="first last">Just got to... hold on until June...</p>
<p>I didn't get much done today.
I think I'm approximately the normal level of tired for me lately, but it feels like I shoulder-checked a wall.</p>
<p>I did a little bit of conlang work, and started playing Portal Reloaded.
Those are some weird puzzles, I recommend it.</p>
<p>I understand there's a new Pijul version coming soon really for real now.
If that's landed by tomorrow I'll do template work, and try to put together a repo for conworld info, and if not, I'll get back to my task runner work.</p>
<p>I read up a bit more on Cement in anticipation of that.
The most interesting thing I hadn't realized before is that the original recommendation that got me looking at Cement was <em>sort of</em> a non-sequitur, in that its interface to command-line parsing is just an <em>extremely</em> minimal wrapper over argparse, so, unlike many command-line parsers for Python, it doesn't really have a new or specific thing.
I would describe the idea not as "using Cement for command-line parsing" but "using argparse <em>via Cement</em> for command-line parsing".</p>
<p>That diversion aside, once I have a noxfile set up, I'll be ready to really evaluate Cement.</p>
<p>For now, I'm feeling extremely tired.</p>
<p>Good night.</p>
Diary 2021-04-242021-04-24T04:00:00-04:002021-04-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-24:/diary-2021-04-24<p class="first last">My organization and planning game for today was... iffy, but it turned out not to matter.</p>
<p>Well, that took a while.
Now I just have to wait.
And wait.
And wait.</p>
<p>It'll be a while, but now I get how this stuff works, and I just need to hang tight for a month, and then, soon.</p>
<p>I wish I were a little more articulate about this whole vaccination thing, but it was kind of a stressful thing.
Among other things, I'm not sure I saw that many people, overall, in the year before today.</p>
<p>I'm going to read up on other stuff for a bit, and try to get back into things tomorrow, assuming I don't get any major systemic symptoms from the first dose.</p>
<p>Good night.</p>
Coding 2021-04-232021-04-23T04:00:00-04:002021-04-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-23:/coding-2021-04-23<p class="first last">I didn't actually release anything, because I haven't changed any of the business logic yet.</p>
<p>I did two major things today: converted the generated .gitignore to .hgignore, because I kind of thought Mercurial had code to handle .gitignore files, but I guess whatever I thought was going to happen, didn't happen; and, tried to configure towncrier.</p>
<p>I found the towncrier documentation a little confusing from the perspective of "someone who wants to get this in a working state ASAP without thinking too hard", so the current configuration is probably a bit of a gamble.
I think I'm going to have to just try doing this, and that means cutting release v0.1.0.</p>
<p>Okay, that <em>seems</em> to have worked.
I'll need to make more advanced changes to check, and the first step there is to replace the Makefile with something that I <em>haven't</em> deleted most of the files it expects to be there.
Anyway, I got distracted thinking about features and implementation, so now I need to go to bed.
It's kind of a tossup how much I'll get done tomorrow, but hopefully, on the weekend, I'll get somewhere significant.</p>
<p>Good night.</p>
Coding 2021-04-222021-04-22T04:00:00-04:002021-04-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-22:/coding-2021-04-22<p class="first last">Can't stop won't stop making guitar hero commit graphs.</p>
<p>"Hm, let's see how using topics works out.
How much should I try using them?"</p>
<div class="highlight"><pre><span></span>@<span class="w"> </span>changeset:<span class="w"> </span>25:0c6d5e14d382
|<span class="w"> </span>tag:<span class="w"> </span>tip
|<span class="w"> </span>topic:<span class="w"> </span>flit
|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>22:21:26<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>summary:<span class="w"> </span>Close<span class="w"> </span>#13
|
o<span class="w"> </span>changeset:<span class="w"> </span>24:f77f3b21774c
|<span class="w"> </span>topic:<span class="w"> </span>flit
|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>22:14:32<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>summary:<span class="w"> </span>Add<span class="w"> </span>docstring
|
o<span class="w"> </span>changeset:<span class="w"> </span>23:df820d3835e9
|<span class="w"> </span>topic:<span class="w"> </span>flit
|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>22:13:42<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>summary:<span class="w"> </span>Oops.
|
o<span class="w"> </span>changeset:<span class="w"> </span>22:63472dd89bcf
|<span class="w"> </span>topic:<span class="w"> </span>flit
|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>22:12:45<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>summary:<span class="w"> </span>Remove<span class="w"> </span>setuptools/distutils/whatever<span class="w"> </span>code
|
o<span class="w"> </span>changeset:<span class="w"> </span>21:1b8c7b2d54c9
|<span class="w"> </span>topic:<span class="w"> </span>flit
|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>22:11:34<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>summary:<span class="w"> </span>Copy<span class="w"> </span>script<span class="w"> </span>endpoint<span class="w"> </span>to<span class="w"> </span>pyproject.toml
|
o<span class="w"> </span>changeset:<span class="w"> </span>20:6914376c18e6
|<span class="w"> </span>topic:<span class="w"> </span>flit
|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>22:08:53<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>summary:<span class="w"> </span>Move<span class="w"> </span>requirements<span class="w"> </span>into<span class="w"> </span>pyproject<span class="w"> </span>file
|
o<span class="w"> </span>changeset:<span class="w"> </span>19:8416b066961b
|<span class="w"> </span>topic:<span class="w"> </span>flit
|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>21:59:56<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>summary:<span class="w"> </span>Remove<span class="w"> </span>obsolete<span class="w"> </span>sections.<span class="w"> </span>This<span class="w"> </span>will<span class="w"> </span>need<span class="w"> </span>quite<span class="w"> </span>some<span class="w"> </span>building-up,<span class="w"> </span>later.
|
o<span class="w"> </span>changeset:<span class="w"> </span>18:3966cd21fc9d
|\<span class="w"> </span>topic:<span class="w"> </span>flit
|<span class="w"> </span>|<span class="w"> </span>parent:<span class="w"> </span>17:10098a6f259e
|<span class="w"> </span>|<span class="w"> </span>parent:<span class="w"> </span>7:6637ac94e33e
|<span class="w"> </span>|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>21:49:31<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>|<span class="w"> </span>summary:<span class="w"> </span>Merge<span class="w"> </span>newsfile
|<span class="w"> </span>|
|<span class="w"> </span>o<span class="w"> </span>changeset:<span class="w"> </span>17:10098a6f259e
|<span class="w"> </span>|\<span class="w"> </span>topic:<span class="w"> </span>flit
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>parent:<span class="w"> </span>16:d61630e48c1c
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>parent:<span class="w"> </span>6:cf3dcc39255e
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>21:48:35<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>summary:<span class="w"> </span>Merge<span class="w"> </span>track-version
|<span class="w"> </span>|<span class="w"> </span>|
|<span class="w"> </span>|<span class="w"> </span>o<span class="w"> </span>changeset:<span class="w"> </span>16:d61630e48c1c
|<span class="w"> </span>|<span class="w"> </span>|\<span class="w"> </span>topic:<span class="w"> </span>flit
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>parent:<span class="w"> </span>15:437adcfca631
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>parent:<span class="w"> </span>10:46f39cc09e70
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>21:47:36<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>summary:<span class="w"> </span>Merge<span class="w"> </span>dockerfile
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>o<span class="w"> </span>changeset:<span class="w"> </span>15:437adcfca631
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|\<span class="w"> </span>topic:<span class="w"> </span>flit
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>parent:<span class="w"> </span>14:f4d28742c686
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>parent:<span class="w"> </span>12:07de2c1ad195
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>21:47:02<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>summary:<span class="w"> </span>Merge<span class="w"> </span>setup_cfg
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>o<span class="w"> </span>changeset:<span class="w"> </span>14:f4d28742c686
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|\<span class="w"> </span>topic:<span class="w"> </span>flit
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>parent:<span class="w"> </span>13:66391bb2b27c
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>parent:<span class="w"> </span>8:85369dd3de76
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>21:46:20<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>summary:<span class="w"> </span>Merge<span class="w"> </span>src
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>o<span class="w"> </span>changeset:<span class="w"> </span>13:66391bb2b27c
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>topic:<span class="w"> </span>flit
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>parent:<span class="w"> </span>4:de3dfd17b396
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>21:45:10<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>summary:<span class="w"> </span>Run<span class="w"> </span>flit
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>o---+<span class="w"> </span>changeset:<span class="w"> </span>12:07de2c1ad195
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>topic:<span class="w"> </span>setup_cfg
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>/<span class="w"> </span>/<span class="w"> </span>parent:<span class="w"> </span>4:de3dfd17b396
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>21:38:15<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>summary:<span class="w"> </span>For<span class="w"> </span>now,<span class="w"> </span>this<span class="w"> </span>file<span class="w"> </span>is<span class="w"> </span>not<span class="w"> </span>needed
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>o<span class="w"> </span>changeset:<span class="w"> </span>11:94562533859a
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|/<span class="w"> </span>topic:<span class="w"> </span>sphinx
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>parent:<span class="w"> </span>4:de3dfd17b396
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>21:30:03<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>summary:<span class="w"> </span>Close<span class="w"> </span>#1
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|
|<span class="w"> </span>|<span class="w"> </span>o---+<span class="w"> </span>changeset:<span class="w"> </span>10:46f39cc09e70
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>topic:<span class="w"> </span>dockerfile
|<span class="w"> </span>|<span class="w"> </span>/<span class="w"> </span>/<span class="w"> </span>parent:<span class="w"> </span>4:de3dfd17b396
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>21:35:27<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>summary:<span class="w"> </span>Close<span class="w"> </span>#9
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>|
|<span class="w"> </span>|<span class="w"> </span>o<span class="w"> </span>|<span class="w"> </span>changeset:<span class="w"> </span>8:85369dd3de76
|<span class="w"> </span>|<span class="w"> </span>|/<span class="w"> </span>topic:<span class="w"> </span>src
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>parent:<span class="w"> </span>4:de3dfd17b396
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>21:15:30<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>summary:<span class="w"> </span>Close<span class="w"> </span>#2
|<span class="w"> </span>|<span class="w"> </span>|
o<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>changeset:<span class="w"> </span>7:6637ac94e33e
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>topic:<span class="w"> </span>newsfile
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>parent:<span class="w"> </span>5:84a31d17722f
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>21:10:31<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>|<span class="w"> </span>|<span class="w"> </span>summary:<span class="w"> </span>I<span class="w"> </span>guess<span class="w"> </span>I<span class="w"> </span>didn't<span class="w"> </span>actually<span class="w"> </span>need<span class="w"> </span>to<span class="w"> </span>update<span class="w"> </span>it,<span class="w"> </span>since<span class="w"> </span>towncrier<span class="w"> </span>will<span class="w"> </span>just<span class="w"> </span>handle<span class="w"> </span>it.<span class="w"> </span>Whoops.
|<span class="w"> </span>|<span class="w"> </span>|
|<span class="w"> </span>o<span class="w"> </span>|<span class="w"> </span>changeset:<span class="w"> </span>6:cf3dcc39255e
|/<span class="w"> </span>/<span class="w"> </span>topic:<span class="w"> </span>track-version
|<span class="w"> </span>|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>21:03:10<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>|<span class="w"> </span>summary:<span class="w"> </span>Close<span class="w"> </span>#3
|<span class="w"> </span>|
o<span class="w"> </span>|<span class="w"> </span>changeset:<span class="w"> </span>5:84a31d17722f
|/<span class="w"> </span>topic:<span class="w"> </span>semver
|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>date:<span class="w"> </span>Wed<span class="w"> </span>Apr<span class="w"> </span>21<span class="w"> </span>20:55:31<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>summary:<span class="w"> </span>Close<span class="w"> </span>#4
|
o<span class="w"> </span>changeset:<span class="w"> </span>4:de3dfd17b396
|<span class="w"> </span>topic:<span class="w"> </span>towncrier
|<span class="w"> </span>parent:<span class="w"> </span>0:738930154b75
|<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
|<span class="w"> </span>date:<span class="w"> </span>Mon<span class="w"> </span>Apr<span class="w"> </span>19<span class="w"> </span>21:35:11<span class="w"> </span>2021<span class="w"> </span>-0400
|<span class="w"> </span>summary:<span class="w"> </span>Close<span class="w"> </span>#8
|
o<span class="w"> </span>changeset:<span class="w"> </span>0:738930154b75
<span class="w"> </span>user:<span class="w"> </span>Max<span class="w"> </span>Chase<span class="w"> </span><max.chase@gmail.com>
<span class="w"> </span>date:<span class="w"> </span>Fri<span class="w"> </span>Apr<span class="w"> </span>16<span class="w"> </span>22:59:07<span class="w"> </span>2021<span class="w"> </span>-0400
<span class="w"> </span>summary:<span class="w"> </span>[REDACTED]
</pre></div>
<p>"YES"</p>
<p>My reasoning for going HAM on this was pretty simple: if there are pain points using topics, using them as much as possible should quickly reveal them.</p>
<p>I did run into two annoyances, but I don't know how serious they really are:</p>
<ul class="simple">
<li>I'd like a quick way to see "every topic that is not an ancestor of the current topic". There's probably already some way to do this, and I'm just not reading the documentation closely enough.</li>
<li>I couldn't get it to merge from a topic that was technically a descendant of the current topic. I think this might call for rebase instead, but for now I just got around it by making a commit. ("Shouldn't you use rebase in general?" Eh, don't wanna...)</li>
</ul>
<p>Anyway, I've successfully built the template application using Flit.
Once I have towncrier set all the way up, and sphinx merged in, I'll work on replacing the Makefile, and then the tickets I'm closing will get really interesting.
To me.</p>
<p>I didn't get too much else done today, but this was fun, in a grinding-out-dailies-in-an-MMO kind of way.
I should wrap up now.</p>
<p>Good night.</p>
Coding 2021-04-212021-04-21T04:00:00-04:002021-04-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-21:/coding-2021-04-21<p class="first last">Don't reward developers by lines of code written.</p>
<p>Today, I just focused on getting both old and shiny new Mercurial stuff configured in a way that makes sense to me.
Basically, I'm trying out the Evolve extension, and moving any projects using Mercurial to requiring topic commits.
(With an exemption for this blog, because the blog workflow is very boring, and I'm mainly using Mercurial so I don't have to learn something else.)
We'll see how that treats me as I get back into things.</p>
<p>I also tweaked the color schemes a bunch, in response to an article or blog post that I read years ago and cannot figure out how to search for.
The basic thesis of the article was that the tendency of most tools that deal with diffs to color code additions as green and deletions as red brings in associations that don't necessarily make sense for software development.
In various domains, including status reporting, green is "good" and red is "bad", but that doesn't match up with the fact that the big problem with code is often <em>too much of it</em>.
So, it recommends choosing more neutral colors for representing addition and deletion, to avoid biasing the judgement of whether given aspects of the change are "good" or "bad".
We'll see how that works out for me.</p>
<p>All that, and I didn't touch the code.
Tomorrow night.
For now, I'm going to wrap up early, and try to tweak my color schemes a little bit more.</p>
<p>Good night.</p>
Weekly Roundup 2021-04-202021-04-20T04:00:00-04:002021-04-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-20:/weekly-roundup-2021-04-20<p class="first last">I need to find a more constructive way to express my feelings about well-meaning but flawed tutorials.</p>
<ul class="simple">
<li>Wednesday: I started getting serious about another conlang.</li>
<li>Thursday: I thought about romanization systems for the conlang, and talked myself into continuing with my initial impulses there.</li>
<li>Friday: I did some work on one of my tiny utility packages, to extend it with functionality that helps in a build-system-like environment.</li>
<li>Saturday: I decided to stop using "Pijul has alpha version weirdness" as an excuse to not commit code, and started working on my build-system-but-not-really concept, using Mercurial. (Mercurial has changed, like, a <em>lot</em> in the however-many-years it's been since I used it professionally, but backwards compatibility guarantees mean those differences are mostly hidden. I'm going to have to really familiarize myself with it sometime.) I'm also trying out Cement, to see how it compares to other command-line frameworks and libraries in Python.</li>
<li>Sunday: I put a bow on top of my pip PR. The code is going into the next release, I think. I also did more tooling work, because not only does towncrier call out to Git, but the allowed values for one of the command line arguments are exactly the Git branches in the current repository. This makes things... interesting, if you're like me and don't want to use Git. I haven't tested the functionality yet, because by my standards, the default Cement template is kind of a mess, and until I clean it up, towncrier can't work against the repository.</li>
<li>Monday: I decided to set up a ticketing system so I can name my news fragments the way towncrier expects.</li>
</ul>
<p>Next week, I'm going to be doing a lot of cleanup, now that I have a local trac instance set up.
Probably conlang stuff, and definitely learning about towncrier and the last 5+ years of Mercurial features.</p>
Coding 2021-04-192021-04-19T04:00:00-04:002021-04-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-19:/coding-2021-04-19<p class="first last">I was all set to shave the yak, before I reconsidered whether the thing several layers up would actually provide value.</p>
<p>Okay, here's the deal: I've listed all of the immediate changes I want to make to the initial repo state that Cement generated.
But, I want to track those changes in towncrier.
But, towncrier assumes the existence of some kind of ticketing system.
Since I'm currently developing locally, I'm a little tempted to do something in the vein of the various other issue tracking projects that integrate into the repository.</p>
<p>Writing that sentence down, though, has convinced me that I probably wouldn't get enough from integrating the issue tracker into the repository to justify the tooling effort (which wouldn't be much, just non-zero).
So, I'll look into better-supported options later; I've got one in mind, but we'll see.</p>
<p>Anyway, once I can covert my notes into tickets, and start closing out tickets, I'll do that.
Need to finish this entry ASAP because of other things I put off today, that it doesn't make sense to put off any longer.</p>
<p>Good night.</p>
Coding 2021-04-182021-04-18T04:00:00-04:002021-04-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-18:/coding-2021-04-18<p class="first last">At least it was a quick diversion. Hopefully it'll stay that way.</p>
<p>Today was a little bit all over the place.
I made the last change I can imagine the Pip PR needing.</p>
<p>I looked into using towncrier, and realized that, in a few places (such as the default argument to one of the commands), it <em>really</em> assumes you're using Git, so now I have a fork of towncrier that's supposed to handle both Git and Mercurial repositories.
I have not tried this out, or indeed tested it.</p>
<p>There's a few other things I did, but I'm not sure how best to write them up, so eh.
It'll be interesting when I get into updating the task runner's repository, because, no matter how much I tried to act like it was otherwise, those changes are going to be <em>a lot</em>.
Anyway, it's late, and I'm tired of pushing things when it comes to late night stuff.
Haha, tired...</p>
<p>Good night.</p>
Coding 2021-04-172021-04-17T04:00:00-04:002021-04-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-17:/coding-2021-04-17<p class="first last">My feelings on Git are still about the same: capable of using it, incapable of enjoying it.</p>
<p>All right, here's where things are on the task runner:</p>
<ul class="simple">
<li>I decided that my hangups around the latest Pijul release acting weird were basically procrastination, so I've started the project regardless, but for now it's in a more traditional VCS with a more established user base and maintenance. I am referring, of course, to Mercurial.</li>
<li>Because I've got all or nearly all of the core logic sketched out in the prototype, I figured I'd experiment a bit with <a class="reference external" href="https://builtoncement.com/">Cement</a>, since my complaint from the last time I looked into it ("They're telling me how to start a project, but I already <em>have</em> a project!") doesn't apply.</li>
<li>I started the quickstart, and just filled in my info for the values instead of the todo-list stuff, and committed the results.</li>
</ul>
<p>It's... probably fine.
There's just a few things I would change...</p>
<ul class="simple">
<li>It's using setup.py and all that entails, including MANIFEST.in. I'd rather use <a class="reference external" href="https://flit.readthedocs.io/">Flit</a>.</li>
<li>The runtime requirements don't appear to be specified in the setup.py file, so I don't think this can be packaged <em>and expected to work</em>.</li>
<li>I don't know what version scheme "0.0.1" is, but it's neither <a class="reference external" href="https://semver.org/">SemVer</a> nor <a class="reference external" href="https://calver.org/">CalVer</a>.</li>
<li>No <a class="reference external" href="https://hynek.me/articles/testing-packaging/#src">src directory</a>.</li>
<li>Why do all of these files start with a newline? I don't have any coherent objection to this, because I just don't understand.</li>
</ul>
<p>And, in stuff that's less certain/defensible...</p>
<ul class="simple">
<li>I had a lot better time using <a class="reference external" href="https://github.com/twisted/towncrier">towncrier</a> with Pip than I ever did editing CHANGELOG files.</li>
<li>I'd generally rather use reStructuredText than Markdown. Not because of anything about the syntax, but because I understand <a class="reference external" href="https://www.sphinx-doc.org/">Sphinx</a> just well enough by now.</li>
<li>Speaking of which, there's a docs directory, but I don't think anything interacts with it? What's up with that?</li>
<li>Until my task runner is off the ground, I'm going to replace the Makefile with a noxfile, and probably redo the layout of the repository so I can have a separate package for basic extensions.</li>
</ul>
<p>So, you know, there are a few tiny changes I'm going to make before I get back to following along with the tutorial.
I'll see about getting on those tomorrow.</p>
<p>Good night.</p>
Coding 2021-04-162021-04-16T04:00:00-04:002021-04-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-16:/coding-2021-04-16<p class="first last">Progress and annoyances.</p>
<p>Okay, I got different filename functionality integrated into limit-coverage, and proved it out by testing it against actual code because it has literally no useful tests.
I wasn't able to build pijul myself, oh well.
The more I tinker with prototyping my task runner in Jupyter, the more its editing interface reminds me of the various stumbling blocks that I experienced with Sublime Text.
It's not that I think that there's necessarily such a thing as an editor that manages to follow a simple algorithm that always does what I want, but I think I would be happier with Jupyter if it didn't ever auto-insert tabs, or auto-close delimiters when there's no text selection.</p>
<p>I think what contributes to this is that I'm writing dataclass-style classes, so I'm <em>maybe</em> using variable annotations more than most people who use Jupyter?
And on the delimiter side, Jupyter just has the exact same janky behavior as Sublime where, if you delete from the middle of a run of similar end-delimiters, it will delete "too much" and you will end up with missing closing delimiters.
(I'm not sure that's the precise behavior that triggers this condition, but it's something like it.)
Maybe I should put in bugs later.</p>
<p>Good night.</p>
Diary 2021-04-152021-04-15T04:00:00-04:002021-04-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-15:/diary-2021-04-15<p class="first last">Preserving my thought process for, like, some reason.</p>
<p>I have come to the following conclusion on the conlang romanization stuff I was thinking about yesterday:
I have an idea that feels solid to me for my own use, but if I end up wanting to put text in this language in front of other people, romanized, I think I'll want to come up with something that doesn't look like "brē 'klàtró" or whatever, which I'm not totally sure is on the level in terms of phonotactics, but I don't yet understand some of the stuff I want to include well enough to be sure or to explain what I'm doing.
The point is, I guess I'm self-conscious about producing something that looks like stereotypical fantasy names...</p>
<p>But now that I think about it, do I want to care about people making that kind of aesthetic judgment?
Like, I'm not going to be just sprinkling the diacritics and apostrophes on randomly, and they'll <em>probably</em> be less frequent because they only go on stressed syllables.</p>
<p>Anyway, I'm tinkering with that, and code, and feeling good about things.
I think I'll try to focus more properly on coding in the coming days, as follows:</p>
<ul class="simple">
<li>my task-runner design <em>would really like</em> limit-coverage to have the ability to specify input and output files</li>
<li>I feel reluctant to pester open-source maintainers, so I'm going to try doing a source build of pijul and see if that fixes the problems I was seeing</li>
</ul>
<p>Anyway, it is painfully late, so I'm going to wrap up now.</p>
<p>Good night.</p>
Diary 2021-04-142021-04-14T04:00:00-04:002021-04-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-14:/diary-2021-04-14<p class="first last">Maybe I could use diacritics <em>and</em> apostrophes. Yaaaay...</p>
<p>I did some work today on conlanging stuff.
This is a different language from one that I was working on a bunch before.
I don't want to go into too much detail yet, because there are a lot of things that I could see myself changing or abandoning.
Suffice it to say that I'm in the vicinity of halfway through working on phonotactics, and I'm noticing that what I have currently will take some careful effort to get a good romanization for it.</p>
<p>See, this is one of the things you don't have to worry about with a five vowel system.
There are five vowels.
And here I am going "okay, there are two fundamental axes of variation, so they can't <em>both</em> be diacritics" (can they?)</p>
<p>Anyway, I should ponder these questions later, because it is basically midnight.</p>
<p>Good night.</p>
Weekly Roundup 2021-04-132021-04-13T04:00:00-04:002021-04-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-13:/weekly-roundup-2021-04-13<p class="first last">"At last, I can—OH LOOK A DISTRACTION!"</p>
<ul class="simple">
<li>Wednesday: I got back into the hobby project that originally prompted me to write the pip PR, and planned some short-term improvements.</li>
<li>Thursday: I got a refactor partway done by the time I published, and I <em>think</em> I finished it later that night.</li>
<li>Friday: I decided that "my laptop is stupid beefy, my code evaluation tasks are somewhat embarrassingly parallel, and the task runner I'm currently using has no concurrency" was a bottleneck for iteration. I wrote up the feature set that I wanted, and listed a bunch of tools that <em>didn't</em> satisfy it. I haven't heard back any suggestions, so shortly afterwards, I decided to try rolling my own, even as I suspected that doing so would open me up to all sorts of weird complications. Truly tragic.</li>
<li>Saturday: I did various bits of housekeeping, of varying levels of consequence.</li>
<li>Sunday: I prototyped the "fine, I'll do it myself" task runner, and researched the few bits of my current task definitions that were potentially contending for file access.</li>
<li>Monday: I started getting a little more serious about the task runner, and trying to nail down what it's behavior should be.</li>
</ul>
<p>Next week, I don't quite want to touch code for any of my projects, so I'm going to keep up with planning and prototyping the runner, and doing stuff not related to code.</p>
Coding 2021-04-122021-04-12T04:00:00-04:002021-04-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-12:/coding-2021-04-12<p class="first last">Just working on whatever.</p>
<p>I got a bit further in prototyping things for my task runner, to the point where the current design <em>sort of</em> exists and makes sense.
I think to get any further, I need to look over how other task runners are set up and work on a similar interface.
At this point, I think I've got a small set of options that need to hook into some already-written core logic, but I'm probably missing something.
(Actually, looking over Nox's command-line options, let's see... My runner has a concept of "targets" which should be specifiable, by command line or environment variable, with some degree of fuzzy matching; I can see the utility of backend overrides, but it's not a natural fit to how I'm writing it; I won't be allowing virtualenv reuse, or extra pythons, or customizing fail/abort behavior, or disallowing external programs. A lot of the functionality in Nox won't be core to my runner, so some of this functionality, if I change my mind, might end up being a tad awkward to add, but, eh. Anyway, configuration file. By command line argument or environment variable, path to file or to directory. There's a few more, but the core customization boils down to "where to load the file from, and which targets to try to reach". I'm thinking I'll work on the command-line first, and think about having a config object like Nox later.)</p>
<p>While I was messing around, I added a progress bar that, if I got everything coded up the way I think I do, will jump around a bunch and then make a bunch of questionable estimates.</p>
<p>I also updated the virtual tabletop stuff so the commands that manipulated cache files are now properly reconfigured.</p>
<p>Anyway, I've got some planning work to do here, but I don't want to try to convert this to code just yet.
Fortunately, I have other stuff to work on afterwards.
Anyway, I let this go way late again, so I should stop now.</p>
<p>Good night.</p>
Coding 2021-04-112021-04-11T04:00:00-04:002021-04-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-11:/coding-2021-04-11<p class="first last">Not yet seeing how this'll spiral out of control, but I don't trust it not to.</p>
<p>I did some work prototyping my task runner concept.
The core logic <em>seems</em> solid.
What remains now is to write the harness for interpreting command-line input and formatting command-line output, fleshing out some of the auxiliary data types, and writing a bunch of helper methods to properly define the tasks.</p>
<p>I was able to get the core logic in an apparently-good state just by typing and editing it a bunch, but I think I'm going to need to do some more detailed planning to figure out what the reporting should look like.
I'll also need to make the modifications to the current commands I run, to feel like I can trust the commands to work as expected when run concurrently.
For Mypy, this means targeting the caches to a project-specific directory.
For pytest, this means disabling the cache behavior completely, since I didn't ever use it.</p>
<p>I'll probably wait to implement this after I've planned it, because I really want a new pijul version first, so I'll go back into working on improving the project I want to use this for.</p>
<p>Anyway, it's gotten way later than I meant it to, so I'll stop writing now.</p>
<p>Good night.</p>
Diary 2021-04-102021-04-10T04:00:00-04:002021-04-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-10:/diary-2021-04-10<p class="first last">That's all the really onerous adulting out of the way.</p>
<p>I took care of a bunch of obligations today.
Woohoo.
I'm not feeling great physically, but I can see my way to feeling better emotionally.</p>
<p>On another note, I think I missed updating some timestamps, so this is going to be an interesting publish cycle.
I'll call this here, fix up the timestamps, and try to have something more interesting in the next few days, when I can focus more on the stuff I want to do.</p>
<p>Good night.</p>
Coding 2021-04-092021-04-09T04:00:00-04:002021-04-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-09:/coding-2021-04-09<p class="first last">This is such a bad idea, even <em>if</em> it turns out to work.</p>
<p>Today, I mostly investigated and tweaked the tasks in my noxfile to make them easier to reason about in the context of parallel execution.
There are just a few tweaks left before I'd be comfortable running all of this code in parallel.
The main thing missing... is a runner.</p>
<p>I wrote up a short summary of what I want and what I've looked at <a class="reference external" href="https://dev.to/mwchase/looking-beyond-nox-1h5g">elsewhere</a>, earlier today, but the shorter summary is that it seems like what I want to do falls just outside the intended usage of every tool I've looked at.
Writing up the specific things I want kind of got me thinking, like, "Hey, these aren't <em>complicated</em> features! I could make this!"
(I am conveniently eliding the basic plumbing of a task runner, like "finding and loading the configuration file".)</p>
<p>In any case, if nobody suggests something that works for me, I will probably roll my own, and suffer in some way that I am completely failing to anticipate.
Anyway, I won't do that right now, because it's getting late.</p>
<p>Good night.</p>
Coding 2021-04-082021-04-08T04:00:00-04:002021-04-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-08:/coding-2021-04-08<p class="first last">Learning valuable things about my tools, and generating so many metrics. Some of them might even be useful.</p>
<p>Today, I managed to put in some time refactoring the punq fork.
It's not perfect yet—there are still some type issues—but, um, huh.
One other issue that seems like it shouldn't have any connection to what I just did.
And, I've just discovered that the HTML report out of mypy is apparently totally orthogonal to its error reporting.
That's... not what I expected, and I hope I can change that.
Aha, looks like I want the --junit-xml option.
I'll keep the other HTML report, as well.</p>
<p>Anyway, I'll test that out while this publishes.
I'm pushing things late already, I should get to bed as soon as I can.</p>
<p>Good night.</p>
Coding 2021-04-072021-04-07T04:00:00-04:002021-04-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-07:/coding-2021-04-07<p class="first last">Hello, you glorious backlog of hobby work!</p>
<p>I'm still fighting off a variable-grade migraine, but I really want to <em>do stuff</em>, so I've been trying.
And wearing sunglasses.
Indoors.
With the lights off.</p>
<p>Anyway, I'm making some progress on the writing-related front, but I don't want to talk about that yet.
So, anyway anyway, I realized earlier that, with the pip PR out of my hands, and no new version of Pijul yet for committing cookiecutters to, that means there's currently nothing that I can work on <em>instead of</em> the virtual tabletop stuff, based on the idea that working on the other thing will help virtual tabletop development later.
In other words, I can't shave the yak, so there's no stress from working on the actual project.</p>
<p>I thought I was going to hop in and make various changes to the punq fork that makes most of the code go, but I decided to pick off some low-hanging fruit in missed coverage first.
Thinking about getting coverage improvements right, though, I have come to the following order of priorities:</p>
<ul class="simple">
<li>Reorganize the punq fork's tests so I can re-enable <a class="reference external" href="https://github.com/mwchase/limit-coverage">limit-coverage</a></li>
<li>Improve my coverage metrics</li>
<li>Convert the punq fork to operate on immutable data structures</li>
<li>Migrate utility code into the punq fork package</li>
<li>Specify the punq fork's behavior</li>
<li>Extend the specification to cover generics</li>
<li>Improve the algorithmic properties of the punq fork's canonicalization algorithm. (This is low in the list because I think getting it right is really hard, and the current cache-based solution is probably good enough, despite the fact that I feel like it's inelegant.)</li>
</ul>
<p>Probably the first thing to do is move the canonicalization code into its own module; that code is nearly half the package!
So, that's going to be some stuff I need to learn to do that kind of big refactor in vim instead of Sublime Text or TextWrangler.
(Honestly, it's mainly going to be getting used to cut and paste through vim's buffers. The "resolve all of the errors afterwards" step shouldn't be different in any way that matters.)</p>
<p>Anyway, I'm going to go back to the writing stuff while this posts.</p>
<p>Good night.</p>
Weekly Roundup 2021-04-062021-04-06T04:00:00-04:002021-04-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-06:/weekly-roundup-2021-04-06<p class="first last">I'm okay, except for when I'm really not.</p>
<ul class="simple">
<li>Wednesday: I made the last adjustments to my pip PR. I think my side of things is actually done now.</li>
<li>Thursday: I started porting μKanren to Python, because *shrug*.</li>
<li>Friday: I got a bit further along, and wrote a unifier that works on JSON-like data.</li>
<li>Saturday: I had a migraine.</li>
<li>Sunday: I watched a very silly miniseries.</li>
<li>Monday: I was out of town for part of the day, so eh.</li>
</ul>
<p>Next week, I'm going to try and do more work on writing.
I've reworked how I'm doing Zettelkasten stuff (I now have a card called "just using TiddlyWiki"), and I want to get used to that and try to get in the habit of using it, so I can enter in actionable stuff from the many, many programming blog posts I read.
But for now, working on writing/worldbuilding.</p>
Diary 2021-04-052021-04-05T04:00:00-04:002021-04-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-05:/diary-2021-04-05<p class="first last">I've got some really grueling whims in my back pocket I hope I don't end up reaching for.</p>
<p>We visited family today, so things are lean as far as the kind of stuff I usually write about.
I'm going to try to get some work in on one of my neglected projects while this posts.
See, right now, a lot of the software stuff that I'm hoping to make use of seems to be in a holding pattern, from my perspective, so I'm going to try doing some writing-related stuff.</p>
<p>(I mean, I suppose there's the whole "I ought to make vim flashcards for myself sometime" thing, but I guess "sometime" doesn't feel like it should be "now".)</p>
<p>Let's see, anything else...
Well, I made some progress on the Kanren stuff after the last post.
It's mostly useful as a "teach myself how logic programming works under the covers" kind of thing, and I suppose the next thing I'm curious about is constraint logic programming.</p>
<p>Anyway, I'll go wherever my whims take me, and right now my whim is to wrap up this post.</p>
<p>Good night.</p>
Diary 2021-04-042021-04-04T04:00:00-04:002021-04-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-04:/diary-2021-04-04<p class="first last">Ironic that a movie with a theme of worrying about wasting time would pad itself so aggressively.</p>
<p>I spent most of today recovering from the migraine and catching up on stuff that I didn't do earlier, because of the migraine.</p>
<p>I might have done more after dinner, but we ended up watching all of The Langoliers.
I'd been thinking I'd be up for half of it tonight, but it was so ridiculous we had to see it through to the end.
Extremely silly, and much better without an internet shoutyman edited over it.</p>
<p>There was some other stuff I did today, but I'd like to give it some more time and see if it pans out.
For now, I'm going to wrap up.</p>
<p>Good night.</p>
Diary 2021-04-032021-04-03T04:00:00-04:002021-04-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-03:/diary-2021-04-03<p class="first last">Really not a fan of my body deciding "Nope nope nope, that's too much light."</p>
<p>I had a migraine coming on as I wrapped up that last entry, and I've spent today cowering from the light and napping.
Like, I'm mostly not <em>still</em> feeling it, but I've got extremely obvious limits on how much I can do stuff like, look at a screen.</p>
<p>It looks like there's some movement on some stuff I've worked on; we'll see.</p>
<p>I'm still thinking about the μKanren stuff.
I've concluded one thing I want for my implementation, as an auxiliary function, is something to convert a variable in the context of a state into a fully realized value.
I've got some ideas for this, but I haven't been able to focus for long enough to put them all together.</p>
<p>I'm going to try to sketch stuff out for that after I post this, regardless, but I won't try too hard.
I've still got to take things easy.</p>
<p>Good night.</p>
Coding 2021-04-022021-04-02T04:00:00-04:002021-04-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-02:/coding-2021-04-02<p class="first last">Extremely hard to tell if this code is working, not up for thinking about it right now.</p>
<p>I messed around a bit more with the microKanren thing I started working on yesterday.
I wasn't really sure how it should handle unification, so I abstracted out the unification logic and made it pluggable.
Right now there's just json-inspired unification, but it wouldn't be hard to add other models.</p>
<p>I tried out a very basic usage of that unifier, and it's a little hard to tell how much it, like, works.
The thing that I can tell is that I don't like the variable introduction function, which is a very close port of the Scheme version.
Requiring a function definition or a lambda for every new variable seems painful to me.
Maybe it won't be as bad if I come up with a use case that justifies having this.
I'm trying to remember, I feel like I was doing something recently-ish that seemed like it would have handled better with unification and backtracking, but I can't remember the details.</p>
<p>Anyway, I'm feeling really lousy, so I'm not going to worry about it any more, and try and get some rest.</p>
<p>Good night.</p>
Coding 2021-04-012021-04-01T04:00:00-04:002021-04-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-04-01:/coding-2021-04-01<p class="first last">"Anyway, I didn't have a specific reason for doing any of this."</p>
<p>I got distracted from everything else I was doing, and put together a prototype <a class="reference external" href="http://webyrd.net/scheme-2013/papers/HemannMuKanren2013.pdf">μKanren</a> library in Python.
The main functionality I'm missing is the core of the <tt class="docutils literal">unify</tt> function, because I haven't decided which data types I want it to be able to handle.
Thinking about that reminded me of the probably-not-well-explained logic at the heart of <a class="reference external" href="https://github.com/mwchase/python-structured-data">Structured Data</a>'s matching system, which I'd like to point at more specifically, but it is <em>extremely</em> decoupled.</p>
<p>The other thing I'm worried about is the implementation of the <tt class="docutils literal">bind</tt> function.
In most parts of the prototype, I was able to rewrite recursion into iteration, but I did not work that out for <tt class="docutils literal">bind</tt> yet, due to it's usage of <tt class="docutils literal">mplus</tt>, which I'm not totally happy with my implementation of either.
Now that I write this, I have some ideas.</p>
<p>Well, after thinking about those ideas, the code is different now.
I don't know about better or worse, but it's different.
It's still got some open questions that need to be answered in order to finish the implementation.</p>
<p>Anyway, I didn't have a specific reason for doing any of this.</p>
<p>Good night.</p>
Pip 2021-03-312021-03-31T04:00:00-04:002021-03-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-31:/pip-2021-03-31<p class="first last">I just need to keep on coming back to this with a fresh perspective.</p>
<p>I figured I'd try to trim down the tests in my pip PR a bit, and I managed to combine two pairs into two parametrized tests.
I don't have a good sense of whether it makes sense to collapse things more aggressively.
I think if I went much further, I'd end up with tests that have completely opposite assertions depending on a flag, which is a little scary to me.
A little variation is... fine... but I don't know about "If this test flag is set, the installation should succeed, otherwise it should fail".</p>
<p>I guess I don't have anything else to say here.
I think there's more work to do, but it's not happening now.</p>
<p>Good night.</p>
Weekly Roundup 2021-03-302021-03-30T04:00:00-04:002021-03-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-30:/weekly-roundup-2021-03-30<p class="first last">New old code.</p>
<ul class="simple">
<li>Wednesday: I did some of the easy work remaining on the pip PR.</li>
<li>Thursday: I had a tough day.</li>
<li>Friday: I did some of the slightly-less-easy work remaining on the pip PR.</li>
<li>Saturday: I dug up some old code and evaluated it as a way to teach myself some new libraries I'm interested in. Python development tooling has come a long way in the past nine years.</li>
<li>Sunday: I got sidetracked a bit. I started with "let's prototype the updated code" and ended on "There's a bug in pijul, I think."</li>
<li>Monday: I pushed on with prototyping. My prototypes didn't scale much in terms of maintainability, so now that I've established "this works, and this works, and this works", I want to work in a text editor instead of Jupyter.</li>
</ul>
<p>Next week, I think I'll look back over the pip PR and see what else I can consolidate or rewrite to be clearer.</p>
Coding 2021-03-292021-03-29T04:00:00-04:002021-03-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-29:/coding-2021-03-29<p class="first last">Sometimes hitting mystery issues...</p>
<p>I've done enough prototyping for the solvers to basically understand how to use Numba in a way that at least doesn't raise errors.
I'm not totally happy with how I've written the prototype code.
It feels like there ought to be a clearer way to express the core algorithms, and I say that even though this code is a relatively straightforward port of the previous version.
It was never particularly well-explained, and that's only going to get worse as I get together the stuff I need for more numerically sophisticated algorithms.
I've currently prototyped the <a class="reference external" href="https://en.wikipedia.org/wiki/Euler_method">Euler method</a>, <a class="reference external" href="https://en.wikipedia.org/wiki/Heun%27s_method">Heun's method</a> <em>I think</em>, and <a class="reference external" href="https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods">classic Runge-Kutta</a>.
I've only really tested the Euler prototype because effort, but I'm planning some more things to implement.</p>
<p>I think at this point, I either have to commit to using the cruft clone in <em>some</em> capacity, or just manually set up the repo again.</p>
<p>Things I have in mind once I have a repo together:</p>
<ul class="simple">
<li>A variety of helper functions to un-clutter the current prototype definitions.</li>
<li>Simple harmonic motion system.</li>
<li>Basic invariant checks for the harmonic system.</li>
<li>Port over more complicated code, like the variable-step methods, and some other things that I <em>did not</em> document well. Also, other systems and their associated checks.</li>
<li>Other methods.</li>
</ul>
<p>Anyway, I'm going to try to prototype some of those helper functions while this posts.</p>
<p>Good night.</p>
Coding 2021-03-282021-03-28T04:00:00-04:002021-03-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-28:/coding-2021-03-28<p class="first last">What does it look like I'm doing‽</p>
<p>"Well, I did some planning for the update, it'd be nice to have a solid foundation for experimenting with code."</p>
<p>...</p>
<p>"I'd like to base this off of my current preferred repository layout, and ideally I'd use the cruft clone, but the cruft clone doesn't exist yet. Well, I can at least start making the cookiecutters."</p>
<p>...</p>
<p>"Okay, let's see what kind of response the bug report I just filed against Pijul gets."</p>
<p>...</p>
<p>So, I'm a few layers deep here.
To try to get around all of this, I'm going to set up a quick prototype in Jupyter.
Then, later, I can transfer it to regular python files.</p>
<p>I just tossed together the basic requirements for messing around with Numba, and I'll try that out later.
I don't want to draw this out too much, so I'll just drop this context for the summary.</p>
<div class="youtube youtube-16x9"><iframe src="https://www.youtube.com/embed/_UZFI-8D5uA" allowfullscreen seamless frameBorder="0"></iframe></div><p>Good night.</p>
Coding 2021-03-272021-03-27T04:00:00-04:002021-03-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-27:/coding-2021-03-27<p class="first last">Finding some code I wrote in college, and getting it into a shape where I can tell it "Welcome... to the <strong>future</strong>! *jazz hands*"</p>
<p>Today, I followed a whim, and dug up some of my academic code from nearly a decade ago.
It's meant to evaluate differential equation solvers in a way that I assume other people have thought of, but I haven't looked very hard.
Basically, if you're modeling a physical system, then that system will have associated invariants that you know about, but it is unlikely that the differential equation solver specifically optimizes for them.
So, given a system and an invariant, you can compare different solvers by their error metrics with that invariant.</p>
<p>I don't have any particular usage in mind for this, I just think it's neat.</p>
<p>Today, I just took some basic notes on the modules I wrote about nine years ago.
I can't use them directly because of... reasons.</p>
<p>Closer to nine years ago, I wrote the initial implementation in pure Python, no support from libraries like <a class="reference external" href="https://numpy.org/">NumPy</a>.
Performance was... painful.
For a project in another course, I rewrote the code to use NumPy, which took things all the way to "sort of reasonable", but was still a lot of Python code firing per simulation step, with some truly questionable attempts at optimization.</p>
<p>Now, that wrapped up in the summer of 2012.
Back then, Python packaging was a serious chore, so I kind of... didn't do it for this.
No real tests either.
(I'm sure some people are still unhappy with the state of Python packaging today, and to them I say "MANIFEST.in". Whatever you think of it now, now I'm using <a class="reference external" href="https://flit.readthedocs.io/">Flit</a>, and it's just a completely different experience from back then. Huh, this code also appears to just barely predate the first public release of the <a class="reference external" href="https://github.com/pypa/wheel">wheel</a> package. Sounds about right.)
And it was in Python 2, because Python 3.3 wasn't out yet, and I'm pretty sure the narrative didn't start shifting on Python 3 until Python 3.4.</p>
<p>So, what do I want now?
Well, I'm curious about <a class="reference external" href="https://numba.pydata.org/">Numba</a>, and I think this code is the best candidate I have, in terms of code I've written, for "let's rewrite this to use Numba and see how it works".
I'll have to be pretty careful about this effort, because this is not a simple rewrite.
Among other things, it appears that I was in the middle of a rewrite effort eight years ago that left the codebase in a slightly nonsensical state.
So, I have to work to figure out the spirit of the code, rather than the letter, as it were.
Plus, I'm not writing the same style of code I was nine years ago, so I've got some choices to unravel that I <em>would not</em>, and <em>will not</em>, make the same way today.</p>
<p>All of that is for tomorrow.
Today, I took inventory of the modules, and next, I need to plan how the different bits of data and functions relate to each other.
It's going to be a whole thing, and the best thing to do for now to handle it right, is to get some sleep.</p>
<p>Good night.</p>
Pip 2021-03-262021-03-26T04:00:00-04:002021-03-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-26:/pip-2021-03-26<p class="first last">Better than it was...</p>
<p>I started consolidating the rest of the tests tonight.
I got the really obvious, low-hanging fruit.
There's probably more to be done, but I'm not going to strain too hard to see it just yet.</p>
<p>It's kind of a pain how long the tests take to run, and how sometimes I missed something that turned my changes from rewrite into breakage, but I should be one or two cycles away from wrapping up for the night.</p>
<p>Okay, I see I fixed one test, but not the other.
Time to debug... in a few minutes...</p>
<p>And after one more cycle, it's done for now.
I pushed what I have, even though I think I need to do more.
I just felt like updating the public view of my fork.
(And checking that I didn't manage to break an earlier version of Python.)</p>
<p>Anyway, I'll get back to this whenever.
Work has calmed down a bit, but that's not an excuse to immediately use up all the slack on something else.
So, I should get to bed soon.</p>
<p>Good night.</p>
Diary 2021-03-252021-03-25T04:00:00-04:002021-03-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-25:/diary-2021-03-25<p class="first last">So many things happening <em>to</em> me mean not many things happening <em>from</em> me.</p>
<p>Work has been rough lately, and because of that, today I took a nap and played video games.
No work on pip, and some minimal work on other projects.</p>
<p>I knew this week was going to be rough, but I was not prepared for the specific ways that it was rough.</p>
<p>I cannot think of anything to add.
I should get things wrapped up asap, so I will.</p>
<p>Good night.</p>
Pip 2021-03-242021-03-24T04:00:00-04:002021-03-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-24:/pip-2021-03-24<p class="first last">Way out on the asymptote...</p>
<p>Started working on enhancing and cleaning up tests for the pip PR.
Tonight, I'm doing the easy bit: adding marks and another version of a test.
The rest of the tests though...</p>
<p>The reason I'm putting those tests off is, there are a number of inconsistencies in the tests that I wrote, and also tests that should almost certainly be collapsed together via the parametrize decorator.
Those tests constitute the majority of the work I have to do currently to refine the PR.</p>
<p>For the rest of the night, though, I want to focus on other stuff, so I'll be tinkering with enhancing the reporting from my other projects.</p>
<p>In a few days, I should be ready to update the PR; I don't see the point in doing so now, when I know what more work there is to be done.
Anyway, I want to wrap this up.</p>
<p>Good night.</p>
Weekly Roundup 2021-03-232021-03-23T04:00:00-04:002021-03-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-23:/weekly-roundup-2021-03-23<p class="first last">Much prefer just being responsible to myself. Eesh.</p>
<ul class="simple">
<li>Wednesday: I found more work to do on pip.</li>
<li>Thursday: I finished with the PR for the time being (but see below), and hoped to work on other stuff to unwind.</li>
<li>Friday: I was tired.</li>
<li>Saturday: I rang in spring by complaining about how the winter had been.</li>
<li>Sunday: I did sudoku.</li>
<li>Monday: I redid some of the diagnostic reporting for the CI on my hobby projects, which will be handy when I write some cookiecutters. I did have to fork one of the plugins I installed to make it work properly with one of the <em>other</em> plugins. Will I open a PR to that project? ... I will <em>think</em> about it, eventually.</li>
</ul>
<p>Next week, I've got more work to do on the pip PR, this time around tests.</p>
Coding 2021-03-222021-03-22T04:00:00-04:002021-03-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-22:/coding-2021-03-22<p class="first last">At least it's a minor fork.</p>
<p>Quick entry:</p>
<p>I've made some progress moving the reporting from one of my projects from the command line to generated HTML.
This should reduce the amount that I have to scroll back to deal with failures.
I can push this further, but I only got so far tonight, in part because I ended up forking one of the libraries I added, in order to tweak the output formatting to my taste.
I guess I can think about opening a PR to see what other people think, but I should probably try to get some more real-world usage out of my fork.
Anyway, I'll work more on such things later.
For now, I need to wrap up and get to bed.</p>
<p>Good night.</p>
Diary 2021-03-212021-03-21T04:00:00-04:002021-03-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-21:/diary-2021-03-21<p class="first last">Extremely difficult youtube videos.</p>
<p>Today, I basically tried to get through a backlog of youtube videos. ...
Put that way, it sounds kind of ridiculous, but, come on, it's Cracking the Cryptic.
I may have solved some of the hunts, but some of the puzzles from the last few weeks have been vicious, but even so, I don't want to give up without feeling like I gave it a fair shot.</p>
<p>I can't think of anything else to really note.
Super excited for the weather to stop being like it has been, and to get more daylight.</p>
<p>Good night.</p>
Diary 2021-03-202021-03-20T04:00:00-04:002021-03-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-20:/diary-2021-03-20<p class="first last">I'm ready to be done with so many things...</p>
<p>Work is still kind of obnoxious.
I've been trying to pick hobby stuff back up in the past week, and it's a little eh.
At some point, I'm going to have to look into paying for lessons for some of this stuff.</p>
<p>I'll try to ramp stuff up a bit more tomorrow, but honestly, what I'm most looking forward to is mild weather.
This winter hit me pretty hard, and I'm glad to see it go.</p>
<p>I can't think of anything else to say, and things won't work out well if I try hard to come up with more, so, I'm wrapping up.</p>
<p>Good night.</p>
Diary 2021-03-192021-03-19T04:00:00-04:002021-03-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-19:/diary-2021-03-19<p class="first last">Well, I'm tired. Again.</p>
<p>I'm feeling pretty beat right now, and I think that means I should be taking things easier.</p>
<p>Things might just be like this until it calms down at work, which might be a while.</p>
<p>I'd be much happier if it felt like I had the time to do all the things I want to do, but it doesn't feel like that.
Oh well.</p>
<p>Good night.</p>
Pip 2021-03-182021-03-18T04:00:00-04:002021-03-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-18:/pip-2021-03-18<p class="first last">I revised the code for the PR while on a treadmill. <em>Probably</em> not a good idea...</p>
<p>I've gotten the tests against the pip PR passing again.
There's still some discussion to be had, I think, but currently things are looking good.</p>
<p>I'm hoping I can switch to diary stuff for a bit, to take a break, and then get back into the various bits of software I want to work on.
(Part of getting back into things is probably going to be getting through a massive backlog of CtC videos...)</p>
<p>Anyway, I don't have much more to say right now, so I'm not going to.</p>
<p>Good night.</p>
Pip 2021-03-172021-03-17T04:00:00-04:002021-03-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-17:/pip-2021-03-17<p class="first last">Closing in... again...</p>
<p>The pip PR has been in review long enough that <em>I've</em> started noticing more problems with it.
Hopefully, I can get those taken care of eventually, probably with help.</p>
<p>Okay, several test iterations later, I've determined that the code was doing what it should, and my initial test was wrong.
So, there's no more work to be done around the missing test coverage, because now it's not missing, and it passes.</p>
<p>Anyway, that's enough messing with pip for tonight.</p>
<p>In the future, I'm going to have to work out a better way to structure my time, because I feel like I <em>could</em> have done more, but for now, the best thing to do, is sleep.</p>
<p>Good night.</p>
Weekly Roundup 2021-03-162021-03-16T04:00:00-04:002021-03-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-16:/weekly-roundup-2021-03-16<p class="first last">Not sure if this is forward momentum...</p>
<ul class="simple">
<li>Wednesday: I sketched out enough concerns with my initial plan for the complicated clone of cruft, that I realized the basic premise was flawed, and what I had to do to fix it.</li>
<li>Thursday: I started relating those ideas to Jinja's design, and settled on a new plan.</li>
<li>Friday: I stepped back momentarily, to think about the ends that this kind of tooling is supposed to be a means to.</li>
<li>Saturday: It turns out I'm not quite done with pip.</li>
<li>Sunday: I figured out <em>a</em> way to deal with the pip issue, but I don't like it. Either I'll change my mind, or I'll find something better.</li>
<li>Monday: I didn't do much, but I did mention my latest plan to get myself organized. We'll see how that plans out; I plan to work on it some after I publish the roundup.</li>
</ul>
<p>Next week, I don't know.
Pip?
Organization?
Publishing a Python package that's an extremely divergent fork of an existing package?
I haven't thought about it too hard.</p>
Diary 2021-03-152021-03-15T04:00:00-04:002021-03-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-15:/diary-2021-03-15<p class="first last">This would have gone slightly better if I'd made a decision beforehand and committed to it.</p>
<p>I mostly took today off.
I can't tell if that was the "right" decision, but I'm hoping taking things easy helps in the long run.</p>
<p>Here's what's most important to get back to:</p>
<ul class="simple">
<li>I still need to fix up my pip PR, but I'm also still not sure what the best way to do that is.</li>
<li>I'm trying out <a class="reference external" href="https://en.wikipedia.org/wiki/Zettelkasten">Zettelkasten</a>. It's just gotten started, but I assume it'll get much more momentum once I start documenting my projects in it. My hope is that it'll give me a centralized place to reason about my projects, and not turn into a one-person instance of <a class="reference external" href="https://xkcd.com/927/">this xkcd</a>.</li>
</ul>
<p>The clock change is doing all sorts of stuff to my body, so for some reason I'm sleepy when it's objectively earlier, but rather than question this situation, I'm going to wrap up ASAP and stop staring at a screen.</p>
<p>Good night.</p>
Pip 2021-03-142021-03-14T05:00:00-04:002021-03-14T05:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-14:/pip-2021-03-14<p class="first last">Not yet ready to do the easy thing if it seems like it's not the right thing.</p>
<p>Figuring out what was going on with pip took a little longer than I would have liked, because I wrote the test wrong.
Once I figured out the correct test, I was able to put together an extremely simple fix that I don't like because it seems to me like it breaks reasonable assumptions about how the code works.
The alternatives I looked into, I either couldn't figure out how to do, or they simply didn't work.
All the same, I'm not yet comfortable committing to the way I've found that does work.</p>
<p>Hopefully, I'll decide on something in the next few days.
I won't focus completely on that; I've got some other projects that I want to see how they shake out.
I've got some other other stuff I want to take care of soon, so I'll call this entry here.</p>
<p>Good night.</p>
Pip 2021-03-132021-03-13T05:00:00-05:002021-03-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-13:/pip-2021-03-13<p class="first last">Not quite done...</p>
<p>One of the reviews on my pip PR pointed out that it doesn't properly set up the distribution, at least under some circumstances.
That's bad, because it breaks <tt class="docutils literal">pip freeze</tt> output, which is both bad in general, and also works against one of the specific use cases of the feature.
So, someone needs to figure out how to fix that.
I'm trying, but it's slow going.
The current assumption is that somewhere, an attribute isn't being set, which sounds to me like a case of more missing code.
Either there's some call not happening that should be, or an existing call is missing a necessary argument.</p>
<p>So, right now I'm trying to get more information experimentally, because I managed to basically ignore this part of the code in my initial implementation.</p>
<p>For the rest of tonight and however long, I'll be iterating on that and trying to get it to make sense to me, but I also want to get in some stuff that I was considering for the projects I want to pick up soon.
Small quality improvements, nothing earthshaking.
I'll get on that now, while I rerun pip's tests, unless those finish as I type this sentence...</p>
<p>Good night.</p>
Diary 2021-03-122021-03-12T05:00:00-05:002021-03-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-12:/diary-2021-03-12<p class="first last">It's hard for me to get excited about the tooling I want, when I focus on it completely and don't work on the projects it's supposed to be for.</p>
<p>Not much coding work today.
I think tomorrow has some potential.</p>
<p>Thinking about the different things I want to work on, I think I need to work on prioritizing the different projects.</p>
<ul class="simple">
<li>For the Cruft clone, I basically know what I need to do, but I don't know how long it'll take me, besides "probably a while".</li>
<li>Related to the Cruft clone, I need a pair of cookiecutters and some helper scripts to generate my preferred repo structure.</li>
<li>But to figure out what goes in those cookiecutters, I need to work on the tooling for what were my active projects, before I decided to Be The Change with pip.</li>
</ul>
<p>I'm not really sure how to translate that into development priorities.
I guess I need to take stock of my active projects.
Then, it probably makes sense to focus on them instead of the Cruft clone, and work on deriving requirements for the clone and the cookiecutters from my experiences.</p>
<p>Anyway, it's later than I planned to let it be, so I'm going to wrap things up now, and hopefully make some progress on <em>something</em> tomorrow.</p>
<p>Good night.</p>
Coding 2021-03-112021-03-11T05:00:00-05:002021-03-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-11:/coding-2021-03-11<p class="first last">Working on a plan for this whole "translating diffs between formats" thing.</p>
<p>I now know more about how Jinja works.
It's not helping with the implementation yet.
Basically, Jinja templates are converted to Python source code and compiled to functions.
This means that I can't do some kind of side-channel tagging, because any metadata will be discarded by the time it does the compilation.
So, if I want to have subsequence metadata, I have to make it explicit.
And I probably want to include the actual data to make sure I don't lose it.
At the very least, this is necessary for tagging expressions.
But I want to make sure that the generated text can't masquerade as metadata.
So there needs to be some unambiguous way of distinguishing them.
Escaping, or perhaps length-prefixing the data.
I'm a little worried about stuff like call blocks, insofar as I don't want the template expansion machinery to see the metadata.</p>
<p>But all of this does suggest a way forward to me:
Define a macro that takes a "tag" argument.
Wrap calls to the macro around each identifiable output text in each version, tagging the calls with a "sequence id".
In the macro itself, output metadata and data.
In applying the macro, do not go inside expressions or other call statements.
This does mean that some precision will be lost.
This will be the biggest problem when dealing with call blocks that take large blocks of text and pass them back verbatim, because that represents a loss of data that can be reasoned about.</p>
<p>My inclination currently is to wonder how much this case will be hit.
Searching github reveals that two cookiecutter repos use call blocks, over a total of 18 files.
This is few enough results that there's a chance the numbers are being swamped by miscounting, but I'm just trying to get a ballpark figure.
So, 18 cookiecutter files with call blocks, vs ~140,000 cookiecutter files.
(I dropped 10,000 files from consideration because some of them are config files for cookiecutter itself, I think.)
Anyway, at 0.01% of all cookiecutter files, I am fine with considering emitting a warning, but not actually bothering.</p>
<p>So, now I've got a plan for coordinating the metadata, and the next big step is to figure out how to inject it into the templates.
Next step after that, derive the metadata from diff information.
This is feeling good.
I'll probably get serious about planning this stuff over the weekend.
For now, I should wrap up.</p>
<p>Good night.</p>
Coding 2021-03-102021-03-10T05:00:00-05:002021-03-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-10:/coding-2021-03-10<p class="first last">If I weren't blogging about how I'm not sure what I'm doing, I <em>really</em> wouldn't know.</p>
<p>I haven't thought too hard about this cruft-related project, but there's something bothering me about my first iteration on the design.
Basically, if there are changes that overlap in just the right way, the current design will lose information by taking the changes as a whole, rather than by applying them one by one.</p>
<p>For a simple example, consider an if block:</p>
<div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">if</span> <span class="nv">condition_a</span> <span class="cp">%}</span>
<span class="x"> Non-trivial content</span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
</pre></div>
<p>And imagine changing it to:</p>
<div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">if</span> <span class="nv">condition_b</span> <span class="cp">%}</span>
<span class="x"> Content with a non-trivial diff</span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
</pre></div>
<p>Now, there's nothing stopping the source from being more elaborate in the conditions, but this is less distracting and was less effort to type.
The situation here is that there's a non-trivial diff between the contents of the if blocks, and we'd like that diff to be preserved if <em>both</em> condition_a and condition_b are true.
The more branches either version has, the more complicated this can potentially be.</p>
<p>The current design would see the diff inside the condition expression, and just put each version completely separately, but that loses information about the diff when the condition bodies overlap.</p>
<p>This might seem like a bit of an edge case, but I cannot trust edge cases to not become critical functionality.
So, I'm trying to figure out how to represent this.</p>
<p>One way I could think about this would be to try to bring the correspondences of the diffs into the higher-level representations.
Do it with lexing, and you've got a token stream that sometimes bifurcates and rejoins.
Do it with the AST, and I guess the result is some kind of double-tree.
I've got this vague idea that maybe I could ignore how Jinja implements... everything, and try to do something with Huffman coding, but, like, not for compression.
It's not a well-developed idea currently.</p>
<p>Taking another swing at this...
The structure I care about involves the sequences that are <em>the same</em> in each version of the template.
In that sense, looking at what changed is kind of the complement to what I want to accomplish.
To figure out my priorities and what the implementation should do, I need a concept of "the same" that handles stuff like for loops.</p>
<p>It's kind of daunting to imagine carrying this out for everything that a template <em>could</em> do.
Ideally, I'd like to annotate specific sequences within the source and see where they end up.
If it were possible to get that data from running Jinja more-or-less as normal, then I could apply established diff algorithms to handle any alignment issues that get introduced (somehow...), and then the diff would be basically ready.
I don't know if it's possible to fake out Jinja's internals that extensively, but I'll look into it tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2021-03-092021-03-09T05:00:00-05:002021-03-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-09:/weekly-roundup-2021-03-09<p class="first last">It's done! (On my end.)</p>
<ul class="simple">
<li>Wednesday: I mostly worked on the latest sudoku hunt from Cracking the Cryptic.</li>
<li>Thursday: I tried and failed to replicate the Windows failures of my new tests. It turns out I had all the information I needed to figure out what was wrong; I just wasn't putting it together. (Basically, Windows doesn't really handle command-line parsing like any other OS I know of, so pip's test script runner can't escape things as scrupulously. So, some version specifiers can't be cleanly specified on the command line.)</li>
<li>Friday: I put the recommended fixes to the tests into practice, then took things easy.</li>
<li>Saturday: With my changes to pip <em>mostly</em> ready, I started planning other things. Such as a pijul-based clone of Cruft that has a more complicated (I think) implementation, but hopefully that delivers enhanced functionality. Hopefully.</li>
<li>Sunday: I did a bit more work on that. Didn't say much.</li>
<li>Monday: I did a bit more work on the pip PR.</li>
</ul>
<p>Next week, so far as I know, the pip PR is good enough that it's out of my hands now, which is a really liberating experience.
I don't know what kind of timeframe for implementation anyone else was expecting, but that was a few months that I suspect other people could have gotten through quicker, if they'd had the time.
Which is a weird counterfactual.</p>
<p>Anyway, it's time for me to take things easy, and work on things beholden only to me.</p>
Pip 2021-03-082021-03-08T05:00:00-05:002021-03-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-08:/pip-2021-03-08<p class="first last">Closing in...</p>
<p>Took some feedback on pip to clear stuff up.
There's a little more work for me or someone else to do, and probably some other changes to be made, but hopefully I made some improvements to it today.</p>
<p>I did some other stuff today that hit me kind of heavy.
Not any kind of problem, but I'm a bit winded.</p>
<p>I'm going to wind down for now and sketch stuff on paper.</p>
<p>Good night.</p>
Coding 2021-03-072021-03-07T05:00:00-05:002021-03-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-07:/coding-2021-03-07<p class="first last">Cycling through half a dozen different design concepts.</p>
<p>I did some planning and prototyping for my cruft-alike.
I think I understand enough of Jinja's structure to handle the whole "diff of template into template of diff" concept, though testing it will be... interesting.</p>
<p>I think I'm going to need to put more work into this before it's in a state for me to say more about it.
For now, I really should wrap up.</p>
<p>Good night.</p>
Diary 2021-03-062021-03-06T05:00:00-05:002021-03-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-06:/diary-2021-03-06<p class="first last">Laying out a rather ambitious scope of implementation for a relatively humble scope of functionality. I'd say "go big or go home", but I have been home for nearly a year now.</p>
<p>Okay, I kind of took it easy today, mostly because I was pretty tired.
Not much to show off, but I figured I'd work through what I want to accomplish with a project that I'm not sure when I'll be able to get it to a working state.</p>
<p>The basic idea is similar to <a class="reference external" href="https://github.com/cruft/cruft">Cruft</a>, but trying to leverage Pijul instead of Git.
One thing that's different is, <em>if I'm understanding the documentatation correctly</em>, Cruft is most meant to overwrite and add files that don't get edited during the course of development.
What I want from my tool is, a few things:</p>
<ul class="simple">
<li>Handling changes of the template</li>
<li>Handling changes of the values</li>
<li>Expanding a template anywhere in a repository; in particular, having a root templated directory, with arbitrarily many templated directories directly underneath it.</li>
<li>Automatically running commands after all templated directories are updated. (It might be possible to bootstrap this from post-generate hooks)</li>
</ul>
<p>These requirements suggest a few things:</p>
<ul class="simple">
<li>I need a flexible in-memory representation of a diff between strings. In particular, it must be possible to grow and shrink the diff sections by moving unchanged characters across the boundary.</li>
<li>I need custom Jinja filters for rendering diff data. (Alternatively, maybe it's possible to pass template data incrementally, and assign the output directly into an in-memory diff, but I don't know if Jinja would let me do that.)</li>
<li>I need to be able to introspect Jinja syntax enough to convert a diff of a template into a template of a diff, by growing the diff the minimum amount needed.</li>
<li>I need to be able to write Pijul diffs. I believe the format isn't fully documented, but I'm not sure.</li>
<li>Tool-specific data about a templated directory should be stored relative to the repository, not relative to the templated directory.</li>
<li>Maybe something vaguely make-like.</li>
</ul>
<p>I'm not sure if Pijul is ready to have this tool targeting it, but I'm a ways off from implementing all the parts that don't depend on Pijul, so it basically evens out.
I'll be researching some of the Jinja stuff while I publish this.</p>
<p>Good night.</p>
Pip 2021-03-052021-03-05T05:00:00-05:002021-03-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-05:/pip-2021-03-05<p class="first last">It's nearly over.</p>
<p>All right, the Windows issues are addressed, and I'm taking feedback now.
Pip work is in good shape, then, and I'm going to focus on other things as I can.</p>
<p>I don't see too much interesting here to talk about, and I was kind of sleepy today, so I'll wrap up early again.</p>
<p>Good night.</p>
Pip 2021-03-042021-03-04T05:00:00-05:002021-03-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-04:/pip-2021-03-04<p class="first last">I now have genuine questions that I cannot ask without sounding horribly elitist.</p>
<p>I <em>tried</em> to replicate the PR's Windows failures.
I really did.
But I barely got <em>anything</em> working when I tried.
If anyone out there knows about running tox on Windows and wants to help me out with this, then please take a look at <a class="reference external" href="https://github.com/pypa/pip/pull/9673">my PR</a>.</p>
<p>For now, I'm going to stop thinking about this, because it just makes me confused and angry.</p>
<p>In happier news, I finished the puzzle hunt earlier today.
I'm going to finish this entry, because it's actually bothering me to look at my own account of trying to replicate the failures.</p>
<p>EDIT: The problem with my tests was obvious in retrospect, given my Windows knowledge, and is now fixed.
Now to act on the various bits of feedback, in a few hours.</p>
<p>Good night.</p>
Diary 2021-03-032021-03-03T05:00:00-05:002021-03-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-03:/diary-2021-03-03<p class="first last">Just decompressing for a while.</p>
<p>I decided to keep focusing on sudoku hunt stuff today.
I'm getting close to finishing, but I'm going to need to ask for help, since I don't think I've done a puzzle like Petra before, and I'm not sure where to start.
Also, I'm curious what the intended solution path was for Machu Picchu, because what I did worked, and was not bifurcation, but it still felt icky.</p>
<p>Other stuff that's happening...
The linting plugin I'm using seems to handle deleting text in normal mode really weirdly/poorly.
Stuff persists way longer than it should.</p>
<p>Anyway, I'm going to take it easy: random other stuff after I publish this, and focus on Petra and finishing the hunt tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2021-03-022021-03-02T05:00:00-05:002021-03-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-02:/weekly-roundup-2021-03-02<p class="first last">So close to being finished!</p>
<ul class="simple">
<li>Wednesday: Took a break from pip stuff, did puzzles.</li>
<li>Thursday: Worked on the details of logic related to the pip PR.</li>
<li>Friday: Following those discussions, and some thought, I simplified my design for the pip changes some.</li>
<li>Saturday: I got the pip code ready to merge so far as the Python package itself, but it still needed documentation updates.</li>
<li>Sunday: I took a break from pip, and worked on stuff for vim.</li>
<li>Monday: I put in the PR, at last, and it immediately failed in the Windows pipelines, so that's a bummer.</li>
</ul>
<p>Next week, I'm going to work on running those tests locally, and hopefully figure out why they can fail.
Besides that, more casual stuff.
I'm also working on the Cracking the Cryptic puzzle hunt for March.
I think I'm making good time on it.
Feels like I'll be done in a few days at most, even if I did hit a rough patch in the middle of Machu Picchu.</p>
Diary 2021-03-012021-03-01T05:00:00-05:002021-03-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-03-01:/diary-2021-03-01<p class="first last">Bit of a rough day that I wouldn't want to relate to anyone online who <em>wants</em> to know.</p>
<p>I published my pip PR today, and... it failed on Windows.
The error doesn't make any sense to me, but I guess this means I need to run the tests locally on Windows.
I'll do that in a few days; I just want to relax for a bit, and wait for feedback first.</p>
<p>(For that, I'll need git and (want) pyenv-win or similar, probably through Chocolatey.
I'm not really familiar with Windows packaging, but I think I've indirectly used Chocolatey via <a class="reference external" href="https://github.com/ionelmc/cookiecutter-pylibrary">cookiecutter-pylibrary</a> and its AppVeyor integrations.)</p>
<p>I think I'll look for something inconsequential to work on while I psych myself up for spinning up a Windows environment for Pip development.
I might get a post out of that when I get to it; I should probably try to.</p>
<p>I think I'll work on some silly stuff I've had in mind for a while, right now.</p>
<p>Good night.</p>
Diary 2021-02-282021-02-28T05:00:00-05:002021-02-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-28:/diary-2021-02-28<p class="first last">I blame my keyboard.</p>
<p>I took a break from pip today, and just focused on improving my editor setup.
I've finally got somewhat reliable spellcheck, which should cut down on instances of editing posts a few days later, or worse, not doing so.</p>
<p>I feel like I'd like to say more, but I guess I was just reading stuff when I wasn't tinkering with vim.
I'll need to devote more time to a thorough look at vim sometime.
Right now, I'm scratching the surface, I think.
pyenv-fallback really proved itself with some of the stuff I was setting up.
I should look into publishing it sometime.</p>
<p>For now, though, I should wrap up again.</p>
<p>Good night.</p>
Pip 2021-02-272021-02-27T05:00:00-05:002021-02-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-27:/pip-2021-02-27<p class="first last">Trying to figure out the correct level of editorializing.</p>
<p>I was kind of tired today, so I didn't get much done.
I retested after rebasing, and there was some breakage, around more detailed error messages, and some stuff that I'm sure used to work with pip, but was never supposed to, now not working.
It was all test-side, though, which is nice.</p>
<p>I also started working on the news fragment for the change.
It looks like that doesn't have to be too extravagant, so I'll focus on the documentation now.</p>
<p>I am... not sure how best to add this in.
The solidest reasoning for this feature is constraining to <tt class="docutils literal">pip freeze</tt> output, but that isn't made <em>easy</em> in all cases by this change, just <em>possible</em> in some instances where it currently isn't.</p>
<p>I'm going to need to think about this some.
At least overnight.</p>
<p>Good night.</p>
Pip 2021-02-262021-02-26T05:00:00-05:002021-02-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-26:/pip-2021-02-26<p class="first last">Don't hold onto something just because you put effort into it.</p>
<p>Scaling back some of the future-proofing I attempted, because I don't seem to need it, and it's going to make the stuff that people are asking for harder.
So, it goes:</p>
<ul class="simple">
<li>Remove complicated logic we don't want.</li>
<li>Update tests that that broke.</li>
<li>Move simplified utility function to the proper place.</li>
<li>Note the future-proofing that I undid, and the probable work required when the future comes.</li>
<li>Wire the utility function into the existing code to avoid duplicate logic drifting.</li>
</ul>
<p>That'll be a bit of effort, but I should be able to get through that part tonight.
Of course, the tests do take a while, and I'm not ready to switch gears to something else while it goes.</p>
<p>Earlier today, I was planning out some of the stuff I want to work on after this is done.
My initial ideas seem kind of out-there, but I'm willing to do whatever to make this work.</p>
<p>All right, it's taken some time, but that part is all together.
Now, I'll wind down for the night, because it would be a bad idea to commit to anything for the next fifteen minutes.</p>
<p>Things to work on later: update my fork again, rebase my branches, update documentation, write news.
Things are looking good for this.</p>
<p>Good night.</p>
Pip 2021-02-252021-02-25T05:00:00-05:002021-02-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-25:/pip-2021-02-25<p class="first last">The day was taken up with other stuff, so the progress, while definite, makes for a short post.</p>
<p>Had some discussion of how URL constraints should compare links.
The word is "they should act the same as URL requirements, but with an eye towards changing both behaviors in the same way later".
That's going to take some thought, because part of what I'm trying to do, is have comparisons between two different data types.
I believe this is necessary for future-proofing, but I could be convinced otherwise.</p>
<p>Anyway, I'm going to be dividing my time between implementing these updates to my draft, and planning projects I want to work on.
For now, it's late, I should wrap up.</p>
<p>Good night.</p>
Diary 2021-02-242021-02-24T05:00:00-05:002021-02-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-24:/diary-2021-02-24<p class="first last">Taking a break, dealing with stress</p>
<p>I've got stuff to do for pip, but for today, I took care of some more urgent things, and then just took it easy for a bit.
I'm working on the latest puzzle hunt from Cracking the Cryptic.
I'm kind of wondering what the proper way to solve the first part was, because I honestly ended up guessing and checking.</p>
<p>In any case, I'm going to have to step things up to finish by the end of the month.
The other parts seem pretty tricky.</p>
<p>Going to call things here because I don't think I can spin anything I did today into a longer entry, and it doesn't make sense to try.</p>
<p>Good night.</p>
Weekly Roundup 2021-02-232021-02-23T05:00:00-05:002021-02-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-23:/weekly-roundup-2021-02-23<p class="first last">Oops, all pip!</p>
<ul class="simple">
<li>Wednesday: I fixed some brokenness in the link comparison logic. (Some of pip's internal classes don't implement <tt class="docutils literal">__eq__</tt>.)</li>
<li>Thursday: I changed up the link comparison logic. I may change it again.</li>
<li>Friday: I discovered that I'd forgotten to code the wheel tag logic, so I implemented part of it.</li>
<li>Saturday: I made progress getting rid of invalid tests.</li>
<li>Sunday: I tried to figure out why the final test was failing, and ended up mostly confused.</li>
<li>Monday: I figured out what was going wrong with the last test, and implemented the rest of the wheel tag logic.</li>
</ul>
<p>Next week, I want to take a short break, then work on getting my changes ready for review.</p>
Pip 2021-02-222021-02-22T05:00:00-05:002021-02-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-22:/pip-2021-02-22<p class="first last">No weird magic, just some code I forgot to write.</p>
<p>Success!</p>
<p>The problem with my code was that it was missing a bit that I'd previously realized I'd need, but that I'd forgotten about.
It's a pretty subtle omission.</p>
<p>So, where am I now?</p>
<p>Well, every valid test that I have thought of is passing.
For all I know, I'm missing some edge case functionality still.
There are some implementation decisions that I've punted on, and I want to circle back to them now.
Specifically, what fields of a URL should be considered, when it comes to determining equality?
I think it would be a bad idea to just pick an answer here myself and just go ahead, because it's much easier to change this feature now, than it will be after it's merged.</p>
<p>Anyway, I've also got to, let's see...
NEWS entry, update documentation, what are other PRs like...
Not seeing anything else that it looks like I should add, but I do still need to work on those.</p>
<p>Now that it feels like I'm over the hump, in terms of implementation, I'm going to touch base in the issue.
In the coming days, I'm going to work on improving the code organization and style; what I have now is kind of just "the minimum required to make the things I've thought of work", and the result is some unprincipled additions to the codebase.
For now, though, I want to cool off a bit.</p>
<p>Good night.</p>
Pip 2021-02-212021-02-21T05:00:00-05:002021-02-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-21:/pip-2021-02-21<p class="first last">I wouldn't say my use of italics is <em>excessive</em>...</p>
<p>I haven't made any dramatic breakthroughs on the last test I have.
I'm just going to try to lay out what I know.</p>
<p>I am creating a wheel at... wait.
I have a suspicion about what's going wrong.
If I'm failing to properly replace the wheel tags...</p>
<p>Okay, I've done something less brittle.
Wish me luck!
Or don't, the test will run <em>well</em> before I need to publish this.</p>
<p>Hm, didn't work, let's see what happened...</p>
<p>It's still hard to figure out what's going wrong.
It looks clear that it's possible for the URL constraint code I added to <em>just not fire</em>.
Which is troubling.
The way that this would happen that makes the <em>most</em> sense to me is that the constraint isn't being added.
Why could that be...</p>
<p>Okay, there's a bunch of code that I added, and all of the <em>other</em> tests pass, so the problem is either specific to what the test is asserting, or how the test is written.
I'm going to go over the test in excruciating detail.</p>
<ul class="simple">
<li>I create a wheel for "dep" at version 0.1.0.</li>
<li>I attempt to change the wheel tags. I'm not sure that I'm doing this correctly, but I'm not seeing the expected failure from doing this wrong. Nevertheless, I should work on doing it right.</li>
<li>I create a constraint file that points to the changed(?) wheel.</li>
<li>I create a subfolder for use as the find-links target, because I'm unsure of the behavior of find-links, and I can work around that uncertainty like this.</li>
<li>In that sub-folder, I create wheels for "dep" at 0.2.0, and "base" (I know these names aren't good) at 0.1.0 and 0.2.0. 0.2.0 of "base" depends on "dep".</li>
<li>I attempt to install "base" using the constraints file.</li>
</ul>
<p>The buggy behavior that results is kind of special, because instead of just "what I expected" and "what happened", there's:</p>
<ul class="simple">
<li>What I expected: version 0.1.0 of "base" is installed, and "dep" is not installed</li>
<li>How I expected it to break: 0.2.0 of "base" and 0.1.0 of "dep" are installed</li>
<li>How it actually breaks: 0.2.0 of "base" and "dep" are installed</li>
</ul>
<p>So, the first version corresponds to "knew about the constraint, generated no candidates because it didn't match the installation platform, backtracked to lower version of base".
The second version corresponds to "knew about the constraint, generated a candidate because I didn't set the wheel tags properly, installed latest base".
The third version, I can't be as sure of, because it happened outside my head, but it looks like either the constraint didn't get populated, or the constraint <em>failed to reject a completely different path</em>.</p>
<p>The latter option, I'll try to check, because I wrote the rejection code and it's not <em>completely</em> trivial.
...
It is pretty close to trivial, though, and it sure <em>looks</em> like it should be capable of distinguishing the paths at issue.</p>
<p>All the same, the only way I can see to pin this outside my code is to suppose some form of filtering step that's stopping the constraint from populating, and that doesn't seem to exist.</p>
<p>At the same time, I have tests passing that <em>require</em> the constraint logic to fire under some conditions.</p>
<p>So, I'm going to want to fix my wheel generation just because it's <em>really</em> doubtful that what I'm doing currently works.
However, once I'm satisfied with that, I'm going to have to ask for help, because I don't think that's going to fix it, and <em>something</em> is really wrong.
I'll try to work on the first part while this publishes.</p>
<p>Good night.</p>
Pip 2021-02-202021-02-20T05:00:00-05:002021-02-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-20:/pip-2021-02-20<p class="first last">Don't have to fix the test if it's testing a behavior that doesn't actually exist.</p>
<p>I've been polishing the tests, and now I'm down to four failures:</p>
<ul class="simple">
<li>One that looks like I either have no idea how to use pip, or I've messed up the implementation. I'll take either, frankly, but the implementation <em>looks</em> reasonable.</li>
<li>Three that look about the same, all having to do with <tt class="docutils literal">_DistInfoDistribution__dep_map</tt>. The bulk of the traceback makes it look a lot like a test issue, so I'm going to take another look. Hm, yes, I think these are invalid. I'll get rid of them.</li>
</ul>
<p>So, that's one troublesome test left.
I'll try to take care of it tomorrow, and then, at last, I can work on stuff aside from code for this.
I'm just going to make super sure that I have just the one failure left, and then post this and wrap up for the night.
Okay, cool, it's as good as I can manage for now.</p>
<p>Good night.</p>
Pip 2021-02-192021-02-19T05:00:00-05:002021-02-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-19:/pip-2021-02-19<p class="first last">I may take a break at some point to write some of the most ridiculous code I can manage, for fun.</p>
<p>Haha, I'm nowhere close to done implementing this stuff.
It turns out I just straight-up <em>forgot</em> about the wheel tag checks, so it's an <em>extremely</em> good thing I wrote all these tests to fail when it installs incompatible wheels.</p>
<p>A bunch of my other tests were pretty half-baked, so I'm finishing them up.
Better now than never.</p>
<p>Anyway, I'm feeling kind of tired already, so I'm going to call this here and go over the compatibility checks, figure out how best to add them.</p>
<p>Good night.</p>
Pip 2021-02-182021-02-18T05:00:00-05:002021-02-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-18:/pip-2021-02-18<p class="first last">Somewhat slow progress, but I think it was faster than when I was just constantly planning and rehearsing.</p>
<p>There are a few fronts on the pip development.
One is that there's an easily-correctable bug in my test changes.
(Probably understating it; really, it's just the latest thing I've found.)
The other is, we're running into "exactly what parts of the Link object should be compared when testing for equality?"</p>
<p>My initial "don't think too hard" implementation compared the entire link, but the legacy resolver ignores at least some of the fields on the link.
The wheel cache only considers particular fields, and ignores every field that I <em>know</em> the legacy resolver ignores.
At the same time, the new resolver apparently considers the whole Link.
(For the purposes of requirements, I think.)</p>
<p>My take on this is, there needs to be a decision, and I shouldn't make it unilaterally, so I'm going to fix the tests I know I can fix, then, kind of... sit on this.
Maybe work on the documentation and changelog.
We'll have to see how fast things move.</p>
<p>Hm, I tried to fix that test, and it failed with the same error.
I suspect the answer may be to delete the test, but I'm not sure.
Okay, got it.
Should be a simple edit, we'll see.
I'm actually not totally sure it's possible to hit the code path I've added.
Weird.</p>
<p>Okay, I still don't understand what's happening, because there are clearly tests that hit this, but it's seemingly weirdly difficult for me to get <em>one particular</em> test to hit it.</p>
<p>Okay, let's review.
I want to have a <em>named</em>, <em>editable</em> install requirement.
Okay, I think I got it.</p>
<p>I'm going to publish this entry <em>probably</em> before the test I'm interested in for now actually runs, but it was relatively simple to see what was happening, once I just looked at the source code.
I think there's more for me to try to do before getting into discussions about how stuff <em>should</em> work.</p>
<p>Anyway, I'm going to wrap up while the tests go.</p>
<p>Good night.</p>
Pip 2021-02-172021-02-17T05:00:00-05:002021-02-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-17:/pip-2021-02-17<p class="first last">I've got a good feeling about this, but that's not new.</p>
<p>Following some question and answers on the pip issue, I've got a first pass at improved link comparison logic for constraints.
The organization seems kind of bad, but I'm hoping that'll get hammered out in the PR process, since I'm still not really familiar with the code.
In any case, I like what these changes do to the code.
It makes the interpretation of the link data much more consistent, so I think this code would be less buggy even if it hadn't originally had a show-stopper bug.
I anticipate that this will fix several test failures, but I let this all go late, so I don't want to run the tests tonight.</p>
<p>I'll get to them sometime tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2021-02-162021-02-16T05:00:00-05:002021-02-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-16:/weekly-roundup-2021-02-16<p class="first last">Will it be done soon?</p>
<ul class="simple">
<li>Wednesday: I talked about the changes I made to my environment, and complained a little about some software I tried to use just because.</li>
<li>Thursday: I tweaked said software a little more, and then started working on a pyenv plugin. It's not yak shaving if there's no top-level goal.</li>
<li>Friday: I figured out what I can and can't do with a pyenv plugin, and got my desired plugin written well enough. I did a somewht bad job of showing off the functionality.</li>
<li>Saturday: I wrote a short entry because I'm trying to get to bed sooner, and I have to start sometime.</li>
<li>Sunday: At long last, I started trying to implement my desired changes to pip. I got the initial draft partway done.</li>
<li>Monday: I got the rest of the way through the initial draft, and started testing it. The tests failed for many reasons some of which I've addressed, and some which I still need to.</li>
</ul>
<p>Next week, I'd like to see if I can keep up this pip momentum and get things over with.</p>
Pip 2021-02-152021-02-15T05:00:00-05:002021-02-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-15:/pip-2021-02-15<p class="first last">Looks like it wasn't quite as easy as I was hoping.</p>
<p>I got pip's code updated to my own satisfaction.
And, the tests failed.
Some of these were due to existing tests that I hadn't updated, so I started on those because they're easy, and test failures are <em>extremely</em> noisy.</p>
<p>Anyway, those are running, and here's how I see things:
Either I fixed all of the tests I tried to fix, or I didn't.
(Note from slightly in the future: there are still failures outside of the modules I added tests to, so, probably didn't?)
Regardless, there's a bunch of tests I didn't go over that need work, and I don't want t give up sleep for that, so I'll take the progress I made today, for today, and do the rest of this stuff later, maybe tomorrow, maybe not.</p>
<p>The tests are still running, let's hope I don't get any more failures.
I really wouldn't like that.</p>
<p>And, no more failures, but I don't fully understand the ones I got.
Oh well, that's a problem for another day.</p>
<p>Good night.</p>
Pip 2021-02-142021-02-14T05:00:00-05:002021-02-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-14:/pip-2021-02-14<p class="first last">Finally yelled at myself to just do the thing.</p>
<p>All right, I took it easy for a bit, but now I want to see if I can just get things over with, at least enough that I feel comfortable getting feedback.
So, I did a bunch of waffling on whether I understood things well enough, and at this point, I'm just going to try.</p>
<p>So, step one is to add a field to the constraint object...</p>
<p>Okay, I didn't really delineate that well, but I added a field, updated the methods, added a helper function, and changed one of the helper functions for install requirements.
Next up is going over the find_candidates method in the Factory class.</p>
<p>Honestly, I think that's another day's work, so I'm going to call this now and try to get wrapped up at a reasonable time.</p>
<p>Good night.</p>
Diary 2021-02-132021-02-13T05:00:00-05:002021-02-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-13:/diary-2021-02-13<p class="first last">Not the shortest entry I've put out, but down there. Oh well.</p>
<p>Trying to get today's entry out of the way early, because I feel like I should be cutting down my screen time at night.
This is inspired by my ongoing state of being <em>extremely tired</em> and having trouble focusing, so I'm shaking things up in various ways.
For example, this entry is being written standing up.
Anyway, I'm calling it now.</p>
<p>I'll try to work on pip stuff during the day tomorrow.</p>
<p>Good night.</p>
Coding 2021-02-122021-02-12T05:00:00-05:002021-02-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-12:/coding-2021-02-12<p class="first last">The bad news is, some of the things I wanted were impossible. The good news is, I didn't have to do them.</p>
<p>I've got my pyenv plugin working about as well as it can.
I wasn't able to do everything I wanted, because it turns out pyenv runs the relevant hook code <em>after</em> it performs some of the logic I wanted to mess with.
So, that's unfortunate, but on the bright side, I was able to delete a bunch of code from my plugin because it wasn't doing anything.</p>
<p>The integration between pyenv and its plugins is really nice.
Aside from my self-inflicted bash bugs, working on this was so enjoyable, it's kind of a shame I can't think of any other reason to write a pyenv plugin.</p>
<p>Oh yes, and it does work.
Take a look:</p>
<div class="highlight"><pre><span></span>↪ pyenv fallback
3.9.1
3.8.7
3.7.9
3.6.12
pypy3.7-7.3.3
↪ pypy
Python 3.7.9 <span class="o">(</span>7e6e2bb30ac5, Nov <span class="m">18</span> 2020, 10:55:52<span class="o">)</span>
</pre></div>
<p>Not the best example, I know, but I don't want to fiddle with my fallbacks now that I've got them working, aside from the fact that 3.8.7 is shadowed by the system Python.
It'll probably be more impressive if I end up thinking of things that I want pyenv-implicit-style behavior for.
Like, here's something that I want to install in a virtualenv, but run wherever.
I've kind of moved away from that kind of thing for now, but now I have the option to move back.</p>
<p>And slightly more concretely, now I have the ability to write standalone scripts or shivs against Python versions besides 3.8, without hardcoding my home directory into the shebang.</p>
<p>Just to reiterate, this is different from pyenv-implicit because I control which environments it looks at.
So, earlier versions don't shadow newer ones unless I want them to, and virtualenvs don't get considered unless I want them to be.
I think it's worse, in terms of time complexity, but I don't <em>think</em> the difference is perceptible.</p>
<p>Anyway, I guess I'm working on something else next, because this is all set, near as I can tell.</p>
<p>Good night.</p>
Coding 2021-02-112021-02-11T05:00:00-05:002021-02-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-11:/coding-2021-02-11<p class="first last">Honestly, I don't even know what it looks like I'm trying to do, at this point.</p>
<p>Minor hiccup yesterday, because I forgot to add 1 to the date when dating the entry.
It's fixed now.</p>
<p>Anyway, today I put together one of the utility things that helps me, but I don't know how generally useful it is.
It's a wrapper around <tt class="docutils literal">zip <span class="pre">-sf</span></tt> that looks for a shebang line and prints it first, if it finds it.
This way, I can look at the shiv files I'm writing, see my pyenv root in the shebang, go "<em>That's</em> probably not portable.", and, honestly, I'm not sure what the next step is.
Don't give those shiv files to anyone else, because they literally only work on my machine?</p>
<p>Maybe I can put every version of python I care about in pyenv global and change the shebang to, like <tt class="docutils literal">/usr/bin/env <span class="pre">python3.<version-I-want></span></tt>.
That's probably the cleanest option.
And, it doesn't really work.
What I want is something like pyenv-implicit, but with some additional tweaks to the logic.</p>
<p>It's surprisingly comfy out in the weeds, all right?</p>
<p>Anyway, I'm going to research how to accomplish what I want.</p>
<p>Hm...
You know, I could try to do a bunch of weird special casing and elaborate sequence manipulations, or I could just figure out how to implement what I <em>wanted</em> setting "global" to do.
It honestly doesn't look too hard.
I'll try to remember to do it tomorrow.
It'd be a bad idea right now, because I'm not focusing the greatest.
That zip wrapper I mentioned earlier, it took me a while to get it right because I was making a basic mistake, and I was so sure the code was right, I couldn't actually see it.
So, I should probably wrap up, in any case.</p>
<p>Good night.</p>
Diary 2021-02-102021-02-10T05:00:00-05:002021-02-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-10:/diary-2021-02-10<p class="first last">"It's just a quick entry." ha ha ha ha</p>
<p>I didn't do much worth writing about today, but I've got a few minutes...
I think I mentioned before that I was messing around with my environment.
At this point, I'm running <a class="reference external" href="https://fishshell.com/">fish</a> under <a class="reference external" href="https://sw.kovidgoyal.net/kitty/">kitty</a>.
I've pretty well replaced Sublime Text with <a class="reference external" href="https://neovim.io/">neovim</a>, with the two caveats that I'll probably go back to Sublime Text for the purpose of working on pip, and I don't have a good workflow yet for replacing my old somewhat dysfunctional pattern of "just stuff in an unsaved Sublime Text window and leave it there for months".</p>
<p>Let me see if I can throw together a replacement quickly.
Well, having another dedicated folder for saving these things is... something.
It's probably more useful and sustainable than having such data who-knows-where inside Sublime Text's appdata.</p>
<p>Anyway, after getting all of that working, and getting past a few weird hurdles (I know I had to change my neovim color scheme to get the background to go from "unusably bright" to "noticeably brighter than under any other circumstance, but it's fine". I don't remember if there was anything else in particular.), I'm now seeing about taking advantage of some of the features this setup gives me.
Shell-based visual filebrowsers seem like an interesting novelty, so I've been messing with them in particular.
I don't want to go into too many specifics, because my general experience was that they didn't quite work the way I wanted, but it was hard for me to figure out why.
The main sticking point is image previews, which is really a nice-to-have, but, I mean, it <em>would</em> be nice...
I've seen the following behaviors:</p>
<ul class="simple">
<li>"In terminal emulators besides kitty, the preview is low-res, but in kitty, it's full-resolution" -> In kitty, the low-res preview is rendered with pixels instead of cells, resulting in what could generously be called a postage stamp.</li>
<li>"If you do all of these extra steps, a full-size preview renders" -> I never get it to work.</li>
<li>"Supports kitty's graphics protocol" -> Doesn't actually render previews, just runs a loading animation.</li>
<li>"Scales the image down if needed" -> Does not scale the image down, resulting in the screen doing all kinds of bizarre nonsense.</li>
</ul>
<p>In the end, I took the one that I liked the most (due to other aspects <em>almost</em> working excellently by default), and went through the tweaks required to make it work for me.
I think there's a bit more customization to be done, but it's definitely in "conform the tools to my preferences" territory at this point.</p>
<p>Anyway, that's quite enough writing.
This went on way longer than I meant it to, but at least I fixed up some of the tools.
In the future, I should try to get this all done sooner, if I'm not going to get useful work done until I start writing about it.</p>
<p>EDIT: At least three of the issues above were due to a bug in fish that is fixed in the latest release.
I think this vindicates my decision not to name the tools I was having trouble with.
Because it wasn't their fault.</p>
<p>Good night.</p>
Weekly Roundup 2021-02-092021-02-09T05:00:00-05:002021-02-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-09:/weekly-roundup-2021-02-09<p class="first last">Things seemed to be going well, and then the weekend just totally wrecked me for some reason.</p>
<ul class="simple">
<li>Wednesday: I started messing with algorithmic composition. First day: some helper code, some of which turned out not to work.</li>
<li>Thursday: I started figuring out what I'd been doing wrong, and making plans to move forward.</li>
<li>Friday: I started executing on those plans, and it went great.</li>
<li>Saturday: I took a quick entry to figure out that some of the high-level ideas I had didn't make sense, and I should move in a somewhat different direction.</li>
<li>Sunday: Not the most productive start to a weekend. [Standard spiel about how the way I name the days on the blog in general, and in these posts in particular, is sometimes unintuitive.] Oh well.</li>
<li>Monday: Even less productive. Wrote this entry as fast as I could, just to have <em>something</em>. So, there's nothing else to say about it, and this summary is about as long as everything I wrote for that post now. Maybe longer.</li>
</ul>
<p>Next week, I'm not sure what I'll be writing about.
I'm feeling like taking a break from coding, and continuing to tweak my environment.
At some point, I'm going to have to put together a vim cheatsheet, just so I remember things more clearly.
Maybe I could make a deck for Anki.</p>
Diary 2021-02-082021-02-08T05:00:00-05:002021-02-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-08:/diary-2021-02-08<p class="first last">Typing too much here would be a mistake.</p>
<p>Took things really easy today.
I want to get to bed as soon as possible, so this entry is really only this long.</p>
<p>Good night.</p>
Diary 2021-02-072021-02-07T05:00:00-05:002021-02-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-07:/diary-2021-02-07<p class="first last">I feel like my efforts to get more sleep might be getting sabotaged by the fact that I've gotten more sleep.</p>
<p>Didn't really touch code today.
The ideas I had for music stuff are going to be pretty intimidating to put together.
(I should probably try sequencing a song entirely manually first, then iterate on abstracting stuff out.)
Anyway, I'm going to try taking things easy for a bit, then getting back into pip so I can hopefully get it over with.</p>
<p>Anyway, I got distracted and let this go late, so I'm going to have to cut this off here.
We'll see if I have more to write tomorrow, but I'm not going to push myself.</p>
<p>Good night.</p>
Coding 2021-02-062021-02-06T05:00:00-05:002021-02-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-06:/coding-2021-02-06<p class="first last">Also, I updated my blog publishing pipeline, and had to work around some dumb bugs, but that's all not very interesting.</p>
<p>Okay, work went a bit late and I watched some long videos, so it's too late already.</p>
<p>As such, I'm going to just jot down some thoughts on representing chords.
There are a few different things that "a chord" can mean, and a few different ways that those realizations could reasonably be represented in MIDI.</p>
<p>Classically speaking, if I remember my lessons from ten years ago correctly, the important aspects of a chord are the root, the third, and the tone that the bass is playing/singing.
Considering a cord in isolation, it can either be several tones that start and end simultaneously, relatively stable in the lower voices but more elaborate in the upper voices, or stable in the middle voices but elaborate in the outer voices.
This stability can last across multiple chords.
What this means is... "how should I represent a bunch of notes in complete lockstep" is probably not a question I should try to answer, because there usually isn't a reason to do that <em>a lot</em>.
(Unless I decide to bring back Theory by Exhaustion or whatever it was called. (Wait, did I make that post, or just think about it? I'm not seeing it when I search...))</p>
<p>So, the "right thing", I think, is to figure out how to represent a framework of timing events, and then have my code subscribe to that framework.
I could then do stuff like coordinate tempo changes through that framework, and have a bunch of things "just work".</p>
<p>Thought on how to do that, relatively unpolished: awaiting a synchronization object produces a new object representing the "final time", and that provides an async method that takes a note length.
It should also be possible to wait for events like "the next bar after this time point" or "a named section".</p>
<p>The way to tell whether that's workable or painful: transcribe music into that framework, and see what I think.</p>
<p>Anyway, I've taken way too much time on this.</p>
<p>Good night.</p>
Coding 2021-02-052021-02-05T05:00:00-05:002021-02-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-05:/coding-2021-02-05<p class="first last">It's also nice when you think doing something will immediately improve things, <em>and it does</em>.</p>
<p>I ended up not working on the music stuff much today, because I reworked a bit of my environment for the heck of it.
As far as I know, only like one thing is broken currently, and it's not a big deal for now.
(Update from the end of the post: the issue is... fixed... I guess...)</p>
<p>So, to get something done fast, I did the note wrapper class, and rewrote my current example to use it.
It's a good abstraction so far.
A bit of obvious boilerplate confined to a single class, and then everything using it becomes shorter and easier to understand.</p>
<p>It's way too late right now, so I'm cutting myself off now.</p>
<p>Good night.</p>
Coding 2021-02-042021-02-04T05:00:00-05:002021-02-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-04:/coding-2021-02-04<p class="first last">Nice to be working with something that's more intuitive and tractable.</p>
<p>All right, I did some basic stuff with the code I wrote around Mido.
Basically, just proved things out, and got some hands-on experience with the code.
From there, I've got a few quick conclusions.</p>
<p>First off, the stuff that I thought through and completely understood worked well.
On the other hand, there are some areas where I'm going to need to add abstractions.
Currently, the "play a note" function expects a note-on message object, which it derives a note-off message from, somewhat haphazardly.
I believe I should write a higher-level class that constructs the relevant messages as needed.</p>
<p>This class should probably be pretty minimal, to start with, because I don't know what capabilities I'll want.
But it only makes sense that the types should be what is expected, and the note and channel values should match.</p>
<p>My basic proof-of-concept tested out the play-note function with a simple scale.
Here's where I want to go next:</p>
<ul class="simple">
<li>Higher-level "Note" object</li>
<li>Recreate current poc with Trio primitives</li>
<li>Play a chord</li>
<li>Figure out what I want to change next</li>
<li>Then start transcribing various songs to code, and refactor the code.</li>
</ul>
<p>One thing I'll probably want in there is to put together something I've thought about: a port-like object that transcribes messages to a MIDI file.
There are a few steps and procedures I'd need to get right for that, but it's the logical thing for me to want to add, now that I can do real-time playback.</p>
<p>Anyway, it's pretty late, I should wrap up.</p>
<p>Good night.</p>
Coding 2021-02-032021-02-03T05:00:00-05:002021-02-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-03:/coding-2021-02-03<p class="first last">Pleasantly surprised to have gotten anything done here.</p>
<p>I wanted to get some stuff done tonight, but I let things go too late, and I'm liking this whole "get to bed earlier" thing I've been doing.
So, I'll describe what I'm planning to work on.</p>
<p>Basically, I want to try using <a class="reference external" href="https://trio.readthedocs.io/">Trio</a>, <a class="reference external" href="https://mido.readthedocs.io/">Mido</a>, and <a class="reference external" href="https://tytel.org/helm/">Helm</a> together.
I've proven to myself that Mido and Helm seem to work together pretty much automatically, at least on my laptop.
To start with, I want to focus on the compositional side of things, and not tweak Helm's settings much.
Where does Trio come in?
Well, in western music tradition, you've got the concept of a note that has a specific duration, and that is a higher-level concept than MIDI works at.
I need to be sending events to start and stop the notes playing, and I want to be interleaving those somehow.
Now, I could try to manually sequence this stuff, <em>or</em> I could lean on an existing concurrency framework.
Threading is also an option, but I'd much rather use almost anything else, at least in Python.</p>
<p>I'll just sum up what I already have written, since there's no way I'm getting anything further in the next ten minutes.
I've got some Protocol classes that are basically a typed wrapper around Mido classes.
I should probably write stubs for Mido and re-evaluate the usefulness of the wrappers.
I've got one more class, and it implements the concept of "playing a note" as a context manager.
Most urgent question about this code: should that class continue to be a class, or should I rewrite it (pretty trivially) into a top-level context manager with just the play-a-note functionality?
Right now, I think that would make sense.
My gut feeling is that there isn't enough of a reason for this to be a class.
It doesn't offer any potential for polymorphism, and it's not aggregating multiple data structures.
I'll make the change while this post publishes, then get ready for bed.</p>
<p>Good night.</p>
Weekly Roundup 2021-02-022021-02-02T05:00:00-05:002021-02-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-02:/weekly-roundup-2021-02-02<p class="first last">In which I do a bad job of relaxing.</p>
<ul class="simple">
<li>Wednesday: I started making plans for changes to pip's code.</li>
<li>Thursday: I tried to find potential gotchas with my approach.</li>
<li>Friday: I started taking a break from pip, and filed a bug against another project (since fixed).</li>
<li>Saturday: I was tired.</li>
<li>Sunday: I was still tired.</li>
<li>Monday: I was <em>still</em> tired, but I was able to plan ahead a bit.</li>
</ul>
<p>Next week, I'm going to keep on with non-pip stuff for a bit.
I want to spend some time with stuff that I can more-or-less fit in my head and make my way around.
When I write PRs against open-source projects, I spend a lot of time just trying to figure out what the different parts <em>do</em>, and it's a little exhausting.</p>
Diary 2021-02-012021-02-01T05:00:00-05:002021-02-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-02-01:/diary-2021-02-01<p class="first last">Ugh, so <em>tired</em>.</p>
<p>In terms of what happened today, things are about the same.
I've decided to try and turn some things around, which is mostly going to be stuff I do in the coming days, but I did also get some stuff that I've been procrastinating on ordering, and it should all help.</p>
<p>Still not ready to get back to pip.
I might try to get back up to speed by messing around more with non-pip stuff.</p>
<p>I don't have anything else to talk about for now, so I'm going to wrap up ASAP.</p>
<p>Good night.</p>
Diary 2021-01-312021-01-31T05:00:00-05:002021-01-31T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-31:/diary-2021-01-31<p class="first last">About the same.</p>
<p>Still tired, still late.
I knew this was going to go down more or less like this, so I'm just resigned to it.
I'll try to scrape things together in the coming week.</p>
<p>Good night.</p>
Diary 2021-01-302021-01-30T05:00:00-05:002021-01-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-30:/diary-2021-01-30<p class="first last">Get sleep. Don't let whatever the hell this is happen to you.</p>
<p>I am extremely tired right now.
I messed around some with writing, but I 100% recognize that I'm in no condition to make serious progress right now, and in a few minutes, I'm going to sleep for what will probably be an alarmingly long time.
This is the future I made for myself.</p>
<p>Good night.</p>
Coding 2021-01-292021-01-29T05:00:00-05:002021-01-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-29:/coding-2021-01-29<p class="first last">Writing code to accomplish even weirder things than usual.</p>
<p>I'm letting pip stuff just kind of stew in the back of my mind, so it feels less like I'm going in circles for a bit.</p>
<p>I did a few things that I'll want for the virtual tabletop stuff, like putting in a bug against another Python implementation, basically asking "Here is a thing that does not work like in CPython, is this desired/acceptable?"
I also put together a tiny cursèd shim that should make trio compatible with Python 3.7+ implementations besides CPython and PyPy.
It's <em>extremely</em> sketchy.</p>
<p>Anyway, I'm still looking for a balance between "I'm having trouble focusing on stuff" and "I just want to get this done".
I'm not going to come up with answers to that, or anything else to talk about, in the next few minutes, so time to wrap up.</p>
<p>Good night.</p>
Pip 2021-01-282021-01-28T05:00:00-05:002021-01-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-28:/pip-2021-01-28<p class="first last">Just one guy going "Does not!" "Does too!" over and over.</p>
<p>The multiple-pip invocation tests I wrote appear to be currently valid, but I honestly didn't remember.</p>
<p>Anyway, time to pin down my concerns with AlreadyInstalledCandidates.</p>
<p>There are five leaf classes of Candidate.</p>
<ul class="simple">
<li>LinkCandidate and EditableCandidate are basically the same for my purposes, and I think I know how I'm going to work with them.</li>
<li>If I understand their use cases correctly, the correct course of action when any code I touch encounters an ExtrasCandidate or a RequiresPythonCandidate is to do whatever it does <em>currently</em>.</li>
<li>An AlreadyInstalledCandidate can come from a few sources, and in any case, I need to be able to tell where it was installed from, in a way that's compatible with the Link field I'm adding to Constraints.</li>
</ul>
<p>(It has to be a Link, because it's required to <em>generate</em> the corresponding candidate.)</p>
<p>So, what I need to move forward on this is a generic way to determine where a Candidate is/will be installed from, keeping in mind that it's not possible to generate a sensible answer for some candidates.</p>
<p>Now, one factor common to the Candidates that I care about is the Distribution.
And it's possible for a Distribution to allow for the generation of a DirectUrl object, but this appears to only be possible, from some quick inspection of one of my projects, if the local candidate was in fact installed from a URL.
Let's see if I can track down the issue I'm worried about complicating.</p>
<p>Thinking about this, it's probably sensible to treat "a resolved package that was installed from an index" differently from "a package that was installed via direct link into an index, for some reason".</p>
<p>So, I think I know what needs to be done.
I'm not going to rush into it.
I want to confirm my ideas here with the maintainers, and I'll be taking things easy for unrelated reasons this weekend, so it could be a little while before I actually touch the code.</p>
<p>Actually, I'll wait to confirm, because something about the flow here still confuses me.
I'm going to have to study this, and perhaps experiment...</p>
<p>Hm, looking at this, I wouldn't be surprised if it turns out I was wrong about ExtrasCandidate, since it certainly exposes enough information currently to get checked by a constraint.
This is so confusing, but I guess I've given myself plenty of time to figure it out.</p>
<p>Good night.</p>
Pip 2021-01-272021-01-27T05:00:00-05:002021-01-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-27:/pip-2021-01-27<p class="first last">Feeling a little overwhelmed from nothing worth talking about here...</p>
<p>Okay, I want to go over my test code to make sure the tests with multiple pip invocations make sense (they probably don't), but I believe I now know which areas of the code need to change.</p>
<ul class="simple">
<li>Factory.find_candidates needs to attempt to construct a candidate from the constraint, and add it to explicit_candidates. (For this, it will use the first Link, if it exists, and the first ireq, if it exists.)</li>
<li>It also needs to pass the url constraint info to Factory._iter_found_candidates.</li>
<li>The Constraint class needs to track and handle Link data.</li>
<li>check_invalid_constraint_type needs to allow Link data, but specifically disallow the editable flag. The error message should probably be updated, and it'd be nice if I could update the issue number, but I don't think I can...</li>
</ul>
<p>One major hurdle is handling AlreadyInstalledCandidates.
I'll need to investigate that specific area more.</p>
<p>I'll dig into that a bit while this entry publishes.</p>
<p>Good night.</p>
Weekly Roundup 2021-01-262021-01-26T05:00:00-05:002021-01-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-26:/weekly-roundup-2021-01-26<p class="first last">Feeling a bit rough. I want to make some tangible progress on pip, then take a break.</p>
<ul class="simple">
<li>Wednesday: I took a closer look at what needs to be done to get the changes I want to make to pip done.</li>
<li>Thursday: I updated my clone, and complained about what I perceive as a mismatch between git's behavior and documentation.</li>
<li>Friday: I took it easy, apparently.</li>
<li>Saturday: I took it easy again, but it didn't quite take.</li>
<li>Sunday: I took a first look at another part of pip's codebase, and things didn't look good.</li>
<li>Monday: On my second look, things look much better, and I've got a plan that might work, I just need to evaluate it to make sure it really makes sense. At a quick glance just now, I'm definitely more confident in all of this.</li>
</ul>
<p>Next week, I'll get back to pip at some point.
One thing I'll have to do is add marks to some of my tests that rely on features that I assumed were implemented, but are not yet.</p>
Pip 2021-01-252021-01-25T05:00:00-05:002021-01-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-25:/pip-2021-01-25<p class="first last">Still not sure how some of this works.</p>
<p>On closer inspection of stuff I probably should have noticed in the first place, I've concluded that some of the stuff I want to do with pip is probably easier than I thought.</p>
<p>Here's the deal.
find_candidates constructs a set of Candidates and a list of InstallRequirements.
I'm trying to figure out if I can rely on those always having <em>some</em> value when I want them to.
The kinds of requirements that need to be processed are:</p>
<ul class="simple">
<li>ExplicitRequirement. I'll come back to this. (provides candidate)</li>
<li>SpecifierRequirement. I think this is the kind of requirement I'll most want to have working. (provides ireq)</li>
<li>RequiresPythonRequirement. I don't... think this should ever be relevant? (never provides ireq)</li>
<li>UnsatisfiableRequirement. I can hardly improve on this situation.</li>
</ul>
<p>Okay, so, the Factory makes ExplicitRequirements that contain candidates with a link, but either the link matches, in which case there's no work to do, or the link doesn't match, in which case it's unsatisfiable and I don't need to do anything.
The other source of ExplicitRequirements is ExtrasCandidates.</p>
<p>I've got a hypothesis about how this works, but I'm not confident:
ExtrasCandidates wrap specific existing Candidates (because otherwise how could you determine the extras requirements), so ExtrasCandidates shouldn't come into play when generating candidates in the first place.
Let's keep that in mind as something that might go wrong.</p>
<p>So, for the normal case of taking a SpecifierRequirement and creating a candidate from a Link, we have the following flow:</p>
<ul class="simple">
<li>If there isn't an ireq, skip the rest of these steps and continue with _iter_found_candidates, which may need to be changed some.</li>
<li>If there aren't URL constraints, skip the rest of these steps, as above.</li>
<li>If the first URL constraint points to an incompatible wheel, skip as above.</li>
<li>Use the first of each (in the case of ireqs, for consistency, in the case of links, because multiple links break it anyway) with _make_candidate_from_link, doing the full due diligence to populate all of the arguments correctly.</li>
<li>Add the candidate to explicit_candidates.</li>
</ul>
<p>I'll need to re-evaluate whether _iter_found_candidates needs to change any.
Also, I'm not sure whether to pass extras to _make_candidate_from_link.
On the one hand, "project with extras" is a different node from "project", so their candidates are not interchangeable.
On the other hand, if not there, then where?</p>
<p>I think I'm misunderstanding something, but I'm not sure what.
I think I need to review the documentation for how pip's resolver works.</p>
<p>Wait, if the loop lives in the vendored resolvelib, that would mean that the extras could be built up across multiple invocations.
I'll have to see if that works out, and if that actually helps.</p>
<p>Thinking about this more, I'm slightly more confident.</p>
<p>I'm also tired.
I'm going to wrap up now, because there's no point in drawing this out.</p>
<p>Good night.</p>
Diary 2021-01-242021-01-24T05:00:00-05:002021-01-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-24:/diary-2021-01-24<p class="first last">Too tired to decide whether I have the category right.</p>
<p>Turns out I'm taking more of a break than I expected.</p>
<p>The basic issue I'm having with adding functionality to pip, is that it <em>looks like</em> I need to have enough information in the Constraint values to generate a Candidate later, but it also <em>looks like</em> the Candidate should be patterned off of an InstallRequirement, and it also <em>looks like</em> that InstallReqirement should come from the non-constraint side of things, to be able to include stuff like the editable flag, and extras.</p>
<p>Thinking about it like that, it's like I need a function that translates existing Candidates to have the desired URL.</p>
<p>Okay, talking about this has pointed me at some functions that might be useful here.
I'll look into this more tomorrow, or next week.
Whenever.</p>
<p>Good night.</p>
Diary 2021-01-232021-01-23T05:00:00-05:002021-01-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-23:/diary-2021-01-23<p class="first last">Second verse, same as the first.</p>
<p>I tried to take it easy again today.
I'm a little keyed up currently, so that didn't work out well for whatever reason.</p>
<p>Need to sleep now.</p>
<p>Good night.</p>
Diary 2021-01-222021-01-22T05:00:00-05:002021-01-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-22:/diary-2021-01-22<p class="first last">Another light day, I guess.</p>
<p>I poked a little at the pip PR stuff today, but I didn't really make any changes.
I've got some extremely useful information for when I get back to it, though.</p>
<p>Aside from that, I can't really remember what I did today.
Read, I guess.</p>
<p>I should wrap up; I've been getting to bed too late.</p>
<p>Good night.</p>
Pip 2021-01-212021-01-21T05:00:00-05:002021-01-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-21:/pip-2021-01-21<p class="first last">I refuse to accept this situation with grace.</p>
<p>I updated my checkout of pip, because it should be a lot easier to work with now, on account of the lack of Python 2 compatibility requirement.
Yes, I forked it that long ago, and just studied it for months.</p>
<p>Anyway, I'm going to complain about git for a sec.</p>
<p>I had some unstaged changes on top of the commit that introduces the tests I wrote.
I wanted those out of the way while I rebased, so I used <tt class="docutils literal">git stash</tt>, and got everything updated.
Far and away not the worst rebase I've done.
Anyway, the documentation of <tt class="docutils literal">git stash pop</tt> states "do the inverse operation of <tt class="docutils literal">git stash push</tt>".
<tt class="docutils literal">git stash push</tt> is the interpretation of <tt class="docutils literal">git stash</tt> on its own.
So, I pop my stash of <em>unstaged modifications</em>, and it stages them‽
What kind of inverse is that?
The documentation goes and builds up a small mental model that <em>immediately</em> breaks down when confronted by reality.</p>
<p>I haven't used Mercurial's Shelve extension, but I feel confident in stating that it <em>can't</em> be confusing in that particular way, because staging changes isn't a thing in Mercurial.</p>
<p>Anyway, I'm thinking again about how to compare Candidates against Link data.
I think I was wrong yesterday about constructing the ExplicitRequirements, because the Constraint object lacks the context required to do that.
The more I think about this, the more I think it needs to be a new method added to the Candidate interface.</p>
<p>Here's how I think this should work:</p>
<ul class="simple">
<li>A RequiresPythonCandidate does not match any Link.</li>
<li>An ExtrasCandidate must defer to its BaseCandidate.</li>
<li>The remaining questions are, how to deal with the other types.</li>
<li>It seems to me that the constraint level shouldn't be mandating editable or not, so it should be possible to just define the implementation in the base class, so the only question that remains is:</li>
<li>How to test this for an AlreadyInstalledCandidate, which doesn't have a link field, and has source_link as None by design. It does have a Distribution value, which has a location field, which appears to be a URL. It might not be the URL I want; I'm not sure, and I'll need to investigate.</li>
</ul>
<p>I'll get on that within the next few days.
For now, it's too late at night, again.</p>
<p>Good night.</p>
Pip 2021-01-202021-01-20T05:00:00-05:002021-01-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-20:/pip-2021-01-20<p class="first last">Finding all of the stuff I glossed over in earlier planning.</p>
<p>I started trying to nail down exactly what needs to be done to implement URL constraints.
Some of it's straightforward (add this field, here's how to handle it in various circumstances), and some of it is not (how do I check whether a candidate matches a URL constraint? I'm almost tempted to translate the link field into an ExplicitRequirement, which... might actually make the most sene. That's not a judgment call I feel comfortable making at midnight.)</p>
<p>I wrote another test as future-proofing, because I noticed a potential issue, given planned changes to the code.</p>
<p>Speaking of changes to the code, I probably should have pulled and rebased before I started making changes, even if those changes are just taking notes on what needs to happen.
Oh well, I'll try to remember to do it tomorrow.
I can muddle my way into a good state one way or another.</p>
<p>Anyway, I have to wrap up several minutes ago.</p>
<p>Good night.</p>
Weekly Roundup 2021-01-192021-01-19T05:00:00-05:002021-01-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-19:/weekly-roundup-2021-01-19<p class="first last">Racking up distractions in the background.</p>
<ul class="simple">
<li>Wednesday: I tried to untangle which bits of code are relevant to compatibility tags, and figured out the implementation, more or less.</li>
<li>Thursday: I found some of pip's features that I absolutely need for writing those tests.</li>
<li>Friday: I took a break and poked at midi libraries for Python.</li>
<li>Saturday: I started figuring out what I can and can't have from vim.</li>
<li>Sunday: I planned the compatibility tag tests.</li>
<li>Monday: I wrote the compatibility tag tests, and I thought I was totally done, but I just realized they need linting, so I'm doing that now.</li>
</ul>
<p>Next week, I'm going to get some more work done on pip.
There's a chance I'll leave that for the weekend and mess with other stuff until then.</p>
Pip 2021-01-182021-01-18T05:00:00-05:002021-01-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-18:/pip-2021-01-18<p class="first last">Wrote three more tests, now I'm ready to do the rest of the damn PR.</p>
<p>The last of the tests should be good to go.
I'm running them now to make sure there aren't any howlers of problems with them.
While I wait, let's check...</p>
<p>"This branch is 134 commits behind pypa:master."</p>
<p>Yeah, sounds about right.</p>
<p>For now, I'm just going to commit the changes and take it easy for the rest of tonight.
I'll do pulls and rebases and such later.</p>
<p>For now, the best thing for me to do, as usual at the end of these entries (no matter how long/short) is to relax.</p>
<p>Good night.</p>
Pip 2021-01-172021-01-17T05:00:00-05:002021-01-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-17:/pip-2021-01-17<p class="first last">Easy does it...</p>
<p>All right, I had way too much fun(?) today configuring vim and filing bugs against plugins.
Let's see about pip.</p>
<p>I basically have three tests in mind.
All of them relate to what happens when a constraint URL points at a wheel with compatibility tags.
The first two tests are simple; they just relate to making sure that compatibility tags are respected for an attempted install.
The third test is more elaborate.</p>
<ul class="simple">
<li>There is a "dependency" package. It has two wheels, one of which has compatibility tags incompatible with a specified platform. That wheel has a known URL, the other is just in the index.</li>
<li>There is a "base" package. Version 0.1.0 does not rely on "dependency". Version 0.2.0 does rely on "dependency", but uses no specifiers.</li>
<li>The test is that, given a URL constraint to the incompatible wheel, version 0.1.0 of "base" should be installed.</li>
</ul>
<p>I will put these tests with the other new non-hash tests.</p>
<p>I sketched out the tests, but thanks to the fun(?) I had taking up most of the day, I'm not going to fill them in for now.
I'll try to do that tomorrow.
Then, commit, pull, rebase, whatever I have to do to get stuff up-to-date before I start on the rest of the work.
For now, I'm going to wind down.
(And maybe tinker with vim some more.)</p>
<p>Good night.</p>
Diary 2021-01-162021-01-16T05:00:00-05:002021-01-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-16:/diary-2021-01-16<p class="first last">Relaxed a little too hard.</p>
<p>So, this entry is a little late.
I took things easy today, and started messing more with vim.
It's not going to be a drop-in replacement for Sublime Text in the ways I care about, especially not after the effort I put into customizing the syntax files.
From initial looks over this stuff, I'm not at all sure it'll be possible to port over all of the stuff I want to have.
For example, in my custom color scheme for Sublime Text, the <em>contents</em> of a string are slightly emphasized, but the <em>delimiters</em> are not.
(Modulo various bits of special-casing, like that interpolated expressions are not emphasized, and neither are Python docstrings, which instead are internally highlighted as ReStructuredText.)</p>
<p>I tried getting hashed syntax highlighting working, and that was a disaster.
I have some complaints for myself about how I configured it in Sublime Text, but the plugin I found for vim just has so much it does wrong, and I couldn't figure out how to mitigate it.</p>
<p>On reflection, I'm not extremely attached to the hashed syntax highlighting (I mostly don't mind either its presence or its absence, which implies to me that it would be a net good if I can fix some of the bad color choices I made), but the lack of emphasis stuff makes me mildly anxious.
(I mean, I suppose I'm not using that on my work computer either, but...)</p>
<p>I should probably get more experience with this stuff before I toss myself onto VimScript, or translating VimScript tutorials to use Lua instead.</p>
<p>Anyway, it is way too late, I need to end this post half an hour ago.</p>
<p>Good night.</p>
Diary 2021-01-152021-01-15T05:00:00-05:002021-01-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-15:/diary-2021-01-15<p class="first last">Trying to relax.</p>
<p>I took things easy today, like I said.
I mostly focused on dealing with a backlog of Cracking the Cryptic videos/puzzles.</p>
<p>I also recently started messing with midi software.
Instead of piano-roll/sheet music composition, I'm going to try writing stuff in Python.
I've got what I need to handle real-time midi output, at a very primitive level, though ideally I'd like to have a little better idea of how to transcribe the midi, given the system that I have in mind currently.
I think I've figured out something that can work, but I'll need to sketch things out a bit more.</p>
<p>Anyway, if I don't wrap things up promptly, that'll cancel out the relaxation, so...</p>
<p>Good night.</p>
Pip 2021-01-142021-01-14T05:00:00-05:002021-01-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-14:/pip-2021-01-14<p class="first last">I found the tests I need to pattern off of, so things are going great.</p>
<p>Earlier today, I stumbled across the <tt class="docutils literal"><span class="pre">--platform</span></tt> option to <tt class="docutils literal">pip install</tt>.
I believe that's the major missing piece of the puzzle for me.
Now, I know how to structure tests so as to be guaranteed to be able to install, or not able to install, a test wheel file.</p>
<p>It's going to be a bit more effort to make use of this, because I need to either wrap the low-level wheel-creation code that doesn't actually write a file, or I need to rename the output of the higher-level helpers.
I hope the latter works, because that sounds like way less effort.
(It... looks like it should?
I'll need to test this some.)</p>
<p>Anyway, I don't want to work on this during the week any more, so I'm going to take things easy for the next two days, then start writing the tests.</p>
<p>I'm going to start on that break now, and try to relax before getting to bed.</p>
<p>Good night.</p>
Pip 2021-01-132021-01-13T05:00:00-05:002021-01-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-13:/pip-2021-01-13<p class="first last">Pip's codebase still feels really big.</p>
<p>Woohoo, I got a shoutout from Cracking the Cryptic.</p>
<p>Anyway, I'm looking over pip's internals again, and I'm going to need to take notes.
This is kind of starting in the middle, but <tt class="docutils literal">collector:LinkCollector.collect_links</tt> seems promising.
I'll put a pin in that, and see if I can hit it the other way by passing a URL <em>requirement</em> to the new resolver.
Or maybe I should be looking at <tt class="docutils literal">package_finder:PackageFinder.find_all_candidates</tt>.</p>
<p>Okay, looking from the middle isn't working for me.
Let's trace this from the start.
First, let's see what kind of errors I can get by forcing incompatible requirements.</p>
<p>Okay, a requirement leads to an error from <tt class="docutils literal">factory:Factory.make_requirement_from_install_req</tt>, which was called from <tt class="docutils literal">resolver:Resolver.resolve</tt>.
Now, a <em>valid</em> URL requirement is propagated by adding it to the requirements list.
Constraints are added to the constraints dict, which is fed into the <tt class="docutils literal">PipProvider</tt>.
The lower-effort option at this level would be to somehow change the <tt class="docutils literal">PipProvider</tt> behavior, but first I should look at the resolve method being used here...
Okay, I've gotten to, <tt class="docutils literal">provider:PipProvider.find_matches</tt> looks like it should be relevant, and its behavior depends on <tt class="docutils literal">factory:Factory.find_candidates</tt>, which takes a constraint!
We know that the constraint is activated if it gets this far, so what it needs to do is convert the link/url/whatever information from the constraint, into a <tt class="docutils literal">Candidate</tt>.</p>
<p>Now, that part is just the implementation of the feature.
The requirement that I need to satisfy, is that installation should fail if the candidate generated points to an incompatible wheel.
So far, I see two basic ways to accomplish that.
One is to avoid generating the candidate, and waiting for resolution to fail.
The other is to error out immediately.
I was going to say that erroring out made more sense because there's no way to recover, but then I realized that there is: look for a version that doesn't rely on the dependency!
So, the correct answer has to be to avoid generating the candidate, and that gives us some test cases.</p>
<p>We want to make sure that wheel tags are properly matched, that an install attempt that requires an incompatible wheel will fail (as opposed to, say, nonterminating), and that, if a constraint points to an incompatible wheel, the selected versions do not depend on that package.</p>
<p>To implement this, I need a helper that converts the data that will be stored on constraints into a <tt class="docutils literal">Candidate</tt>.
It should check what the URL points to, and, if it's a wheel, whether it's compatible.
My initial inclination is to implement this as a generator that takes the constraint argument and iterates over the field, producing valid candidates.
(This would end up deferring obviously broken situations, but we're delegating to the resolver, because it can backtrack.)</p>
<p>I'm still not sure how to test this, but at least I have test cases.
I also might need to adjust some of my ideas about what gets stored on the constraint, if it's getting converted into a <tt class="docutils literal">Candidate</tt>, but we'll see.</p>
<p>Okay, that was a productive hour or two, time to wrap up.</p>
<p>Good night.</p>
Weekly Roundup 2021-01-122021-01-12T05:00:00-05:002021-01-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-12:/weekly-roundup-2021-01-12<p class="first last">Closing in on getting a PR ready.</p>
<ul class="simple">
<li>Wednesday: I refreshed my memory on how hash tests should work for URL constraints.</li>
<li>Thursday: I wrote a few tests, and said a tiny bit about the insurrection.</li>
<li>Friday: I checked over my test code to make sure that it wasn't too broken. (It was still pretty broken at the time, in ways I didn't grasp.)</li>
<li>Saturday: I took a nap. Then, right after publishing that post, I slept for twelve hours.</li>
<li>Sunday: I finished up the obvious tests, and started really putting them through their paces.</li>
<li>Monday: I started contemplating the wheel compatibility logic, and convinced myself that my earlier reasons for thinking it would "just work" probably weren't valid.</li>
</ul>
<p>Next week, I'm going to get back to figuring out what wheel compatibility code/tests should look like.
If I don't get this worked out quickly, I'll have to take another break, but it's fine.</p>
Pip 2021-01-112021-01-11T05:00:00-05:002021-01-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-11:/pip-2021-01-11<p class="first last">I thought this would "just work". Now, I'm not so sure.</p>
<p>I was kind of taking it easy today, so I haven't started on pip, so I'm not going to do much.
For now, I just want to figure out what tests of wheel compatibility tags would look like.</p>
<p>I'm not seeing an example of an end-to-end test I could copy and rewrite for this, so let's head back into the code to see if there's a smaller section of code I can isolate.</p>
<p>Okay, I'm going to need to start over at understanding the code, because I've gotten myself confused again.</p>
<p>Like, okay, adding a URL constraint makes a new wheel available to download, but if the platform doesn't match, the wheel shouldn't be considered as a candidate, I think.</p>
<p>I think I need to be looking in <tt class="docutils literal">factory:Factory.find_candidates</tt>.
That delegates to some other functions that hopefully filter stuff out...</p>
<p>Okay, there's a <tt class="docutils literal">make_requirement_from_install_req</tt> function that freaks out if it's given a link requirement that links to an unsupported wheel, but I don't think it makes sense to go down that path unless the constrained package is required.</p>
<p>I'm going to have to try again to undertand this later.</p>
<p>Good night.</p>
Pip 2021-01-102021-01-10T05:00:00-05:002021-01-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-10:/pip-2021-01-10<p class="first last">Shockingly close to done, even though I've only touched test code so far.</p>
<p>Well, I slept for twelve hours after the last post, and now I'm fine(?).</p>
<p>I've finished roughing out the tests that I know how to do.
I should maybe try to figure out how to write tests for wheel compatibility tags, but I'd rather get the tests I have to be valid.
Looking over the utility function definitions, it's... probably fine to copy and paste between files.</p>
<p>I did that, and filled in the details.
I've got an hour, let's goooooo.
Okay, it took a quarter of an hour, and all of the tests failed as expected.
Let's remove the xfail marks and see if any of them are failing for bad reasons.</p>
<p>And some of them are.
Let's see about patching this up.
I'll rerun them tomorrow.</p>
<p>I think the next thing I need to fix up is to add some expect_errors to a bunch of the calls.
That should make some of the twenty tests I've added pass, but that's fine.</p>
<p>Anyway, I'm drifting off, so I should wrap up.</p>
<p>Good night.</p>
Diary 2021-01-092021-01-09T05:00:00-05:002021-01-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-09:/diary-2021-01-09<p class="first last">Done napping, time to go to bed.</p>
<p>zzzz</p>
<p>No progress, only naps.</p>
<p>Good night.</p>
Pip 2021-01-082021-01-08T05:00:00-05:002021-01-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-08:/pip-2021-01-08<p class="first last">Kind of tired today, <em>for some reason</em>.</p>
<p>I didn't do too much with pip today, because I was doing other stuff, like sleeping.</p>
<p>I did quickly look over the tests I put in earlier, because I was worried they might be somewhat broken.
On closer inspection, they're not broken for the reason I thought they might be, but I can't be sure they don't have many other problems.</p>
<p>I'll see if I'm up for writing the next tests tomorrow, but I'm going to assume it'll be the weekend.</p>
<p>It's late, I should wrap up.</p>
<p>Good night.</p>
Pip 2021-01-072021-01-07T05:00:00-05:002021-01-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-07:/pip-2021-01-07<p class="first last">I hope nobody was thinking of me as "apolitical", especially not like it was a good thing.</p>
<p>I got a few basic hash+url constraint tests mostly written.
I need to figure out the best way to assert about what pip actually did.
I think the easy way is to just copy some utility functions between test files.</p>
<p>Anyway, it's a little hard to concentrate on this right now, for reasons that I trust are obvious.
I want to keep on making progress on this, that's heartening, but what's happening in Washington DC right now...</p>
<p>I don't often talk about political issues that affect me, and I do not think I have a principled reason for that.
I sometimes find myself fixating on the worst possible outcome of an event or action.
(On reflection, a lot of really bad outcomes have come as a surprise to me at the time, so it's not like I can even call myself a "realist" here.)
But, if I can say something here that reaches someone, anyone, from this little blog, then I think the good that does will outweigh any negative consequences that my brain can imagine.</p>
<p>Today, in the Capitol, there were innocent bystanders who didn't deserve what happened to them.
There were heroes.
There were, and are, reprehensible people who are likely to face far less consequences than their words and deeds merit.
I do not intend to forget this day, the violence, the lies, the distaste for democracy.
Everyone who was in the Capitol today deserves to have their actions memorialized, <em>especially</em> those who will, soon enough, be trying to deny and minimize them.</p>
<p>I want to believe the worst is over, but I cannot bring myself to relax just yet.
I hope we make it through the next two weeks, and that we can finally start getting the leadership we needed a year ago.</p>
<p>Fuck Trump.</p>
<p>Good night.</p>
Pip 2021-01-062021-01-06T05:00:00-05:002021-01-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-06:/pip-2021-01-06<p class="first last">It's good to be back on this.</p>
<p>I'm reminding myself what I want for the hash tests.</p>
<p>Basic tests:</p>
<ul class="simple">
<li>Hash requirement plus constraint to matching URL succeeds</li>
<li>Hash requirement plus constraint to differing URL fails</li>
</ul>
<p>More advanced:</p>
<ul class="simple">
<li>Hash requirement in dependency plus matching URL constraint succeeds</li>
<li>Hash requirement in dependency plus differing URL fails</li>
<li>Two versions of dependent, with dependencies on different hashes, always select the version compatible with the URL constraint. In particular, if the constraint matches the hash requested by the lesser version of the dependent, those versions are what get installed.</li>
</ul>
<p>Probably want to try these with extra hashes or overlapping sets to look for something really tricky.</p>
<p>I'll try to get on that tomorrow.
I've decided to try to be okay with taking things a little at a time.</p>
<p>Oof, I just realized that I hadn't twigged that hashes are supported in constraints.
That's going to mildly increase the number of test cases, but it should be fine.</p>
<p>Good night.</p>
Weekly Roundup 2021-01-052021-01-05T05:00:00-05:002021-01-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-05:/weekly-roundup-2021-01-05<p class="first last">I did not have a good time last week. I seem to be doing a little better now that it's over.</p>
<ul class="simple">
<li>Wednesday: I felt gross and decided to take a break from the then-current projects.</li>
<li>Thursday: I started trying to solve old Advent of Code puzzles using a programming language that did't exist at the time.</li>
<li>Friday: I focused on learning more about the language itself.</li>
<li>Saturday: I started to get more proficient with the language, BQN, but I'm not totally used to it yet.</li>
<li>Sunday: I made some improvements to my Advent of Code solution.</li>
<li>Monday: I made more headway, and realized I was getting frustrated with a whole bunch of things.</li>
</ul>
<p>Next week, I'm going to try to make some progress on the pip PR, and then, if there's time left in the week, try to switch over to using Vim or some other open-source text editor.</p>
Coding 2021-01-042021-01-04T05:00:00-05:002021-01-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-04:/coding-2021-01-04<p class="first last">Getting quicker at putting this stuff together.</p>
<p>BQN program for part one of the second day complete, and it shouldn't be too hard to do part two, I just don't want to right now.</p>
<p>I'm starting to get really bothered by the fact that it's not convenient to type the symbols.
Since I'm still using Sublime Text, my inclination would be to add nice syntax highlighting and snippets through that mechanism.</p>
<p>(I'm not currently considering switching text editors, but it's starting to seem like something that would make sense.
I mean, I could go outside whenever I felt like it without freaking out around the time the last updates dropped...
Since all I'm doing currently really is plain text, ReStructuredText, Python, TOML, todo.txt sometimes and now BQN...)</p>
<p>(Well, I wasn't considering switching, but now I am.
I'll look into it more after I get back to work on the pip PR.
Which, maybe I'll get back to next week, since now I feel way more relaxed now than I have in weeks.)</p>
<p>Good night.</p>
Coding 2021-01-032021-01-03T05:00:00-05:002021-01-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-03:/coding-2021-01-03<p class="first last">I need to get better at internalizing the vocabulary that points to the relevant concepts.</p>
<p>And with a bit of investigation and fiddling, I managed to write a BQN program for both parts of the first AoC challenge, and the result looks somewhat idiomatic.
I don't think I would have managed it without having looked at the interpreter source code first, though.
Hopefully, I won't hit any huge barriers.
BQN has a small set of primitives, so the challenge is always going to be figuring out how to combine them in a useful fashion.</p>
<p>Having to type all of the fancy symbols does kind of make me ponder some kind of <a class="reference external" href="https://web.eecs.umich.edu/~imarkov/Perligata.html">Perligata</a>-esque asciification, but that's probably a bad idea, if only because taking cues from an esolang should be a red flag.</p>
<p>Anyway, I was doing... other stuff, so I just now put together this short entry, late, and I don't want to draw things out any more.</p>
<p>Good night.</p>
Coding 2021-01-022021-01-02T05:00:00-05:002021-01-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-02:/coding-2021-01-02<p class="first last">This stuff is still pretty weird.</p>
<p>I think I've got all I need from the JavaScript BQN interpreter (not the compiler).
So, once I'm ready to mess around with stuff again, it's time to get serious about learning BQN.
First thing I did: aggressively bump up the magnification on the web site so I can reliably tell the difference between, say, <tt class="docutils literal">⊐</tt> and <tt class="docutils literal">⊒</tt>.</p>
<p>Thinking about the problem I want to use this for... I think I need <tt class="docutils literal"><span class="pre">⊐⟜(-1)</span> something</tt> to start with.</p>
<p>With that, and some searching on <a class="reference external" href="https://mlochbaum.github.io/bqncrate/">BQNCrate</a>, I've made some improvements to my solution, and it's closer to supporting part two.
At least, I think they're improvements?
I really need a better sense of idiomatic style for APL-like languages.</p>
<p>Anyway, I spent enough time trying to figure out array manipulation, better wrap up for now.</p>
<p>Good night.</p>
Coding 2021-01-012021-01-01T05:00:00-05:002021-01-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2021-01-01:/coding-2021-01-01<p class="first last">No links in this post because I'm tiiiired.</p>
<p>Did a little work on a Python interpreter for BQN.
My basic plan is to work from the JavaScript interpreter, then get bugfixes by looking at the JavaScript <em>compiler</em>, work on feature parity with the JavaScript version, then see if I can get feature parity with the Java version.
This will all be in Python 3 to start with.
Once I have feature parity with the Java version, I want to see about benchmarks.
For kicks, I'll then see about backporting to the latest PyPy2 release and generally structuring it more like an RPython-based interpreter.
(Somewhat curious if getting a successful nojit compilation would allow me to use emscripten to make a JavaScript version that has feature parity with the Java version.
Also note that "feature parity with the Java version" might be asking some stuff of the self-hosted compiler that it can't actually do, so there's a chance this last part isn't possible currently; I'm not sure.)</p>
<p>However, what I want to do is, finish up the initial JavaScript interpreter work, then get back into teaching myself the language.</p>
<p>This entry was a few minutes late because I was focusing on the port, and other stuff.
I'd like to be done with it now.</p>
<p>Good night.</p>
Coding 2020-12-312020-12-31T05:00:00-05:002020-12-31T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-31:/coding-2020-12-31<p class="first last">Area nerd still cannot do anything remotely the easy way.</p>
<p>So, what do I do for a change of pace?
Try to learn a seven-month-old programming language in a paradigm that I sort of know about, by looking over some language-agnostic coding challenges.
I don't know, either.</p>
<p>So, here's some background.
<a class="reference external" href="https://en.wikipedia.org/wiki/APL_(programming_language)">APL</a> was a programming language focused on manipulating arrays and having incredibly terse syntax.
While it has influenced several programming languages that I have experience with (of... varying quality), I haven't really tried to use any language with its combination of terseness and power before.
APL inspired several other languages to that degree, such as <a class="reference external" href="https://en.wikipedia.org/wiki/J_(programming_language)">J</a>, which I <em>believe</em> is the APL-like that I first saw actual syntax of, on <a class="reference external" href="https://hillelwayne.com/tags/j/">Hillel Wayne's blog</a>.
(That category should get a new entry that functions as a gentler introduction to J at some point.)</p>
<p>I am not trying to learn J.</p>
<p>Now, I don't even remember how I heard of the language I am trying to learn, whether Hillel mentioned it on his twitter or if I saw it somewhere else or what, but I've vaguely had my eye on a language called <a class="reference external" href="https://mlochbaum.github.io/BQN/index.html">BQN</a>, which is like APL, but with some fundamental differences, that, to the degree I understand them, seem to address some of the minor niggles I encountered with NumPy.
The documentation, tutorials, and interpreters are by now at the point where, through trial and a lot of error, I can bash out a solution to basic coding challenges, sometimes.</p>
<p>Here's a solution to the first <a class="reference external" href="https://adventofcode.com/">Advent of Code</a> puzzle: <tt class="docutils literal">•Out <span class="pre">-´</span> ⥊ <span class="pre">=⌜⟜"()"</span> •FChars "day_1.txt"</tt>.
To be clear, that's the first <em>ever</em>, near as I can tell.
Also to be clear, I don't know if that's the idiomatic way to do that.
And I'm going to have to rewrite it some to be able to handle the second part of the challenge.</p>
<p>Anyway, I'm also looking at the BQN VM implementations, and vaguely wondering how well an <a class="reference external" href="https://rpython.readthedocs.io/en/latest/">RPython</a> VM would work.
The BQN VM is not <em>the most</em> minimal non-esolang that I've considered porting to RPython, but the interpreter version looks pretty small, so I'd be interested in taking some time to get a Python port, then finesse it into RPython, then give the compiler a few hours to chew on it.</p>
<p>Anyway, this took way longer to write than I intended, so it has to be done now.</p>
<p>Good night.</p>
Diary 2020-12-302020-12-30T05:00:00-05:002020-12-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-30:/diary-2020-12-30<p class="first last">Uuuuugh.</p>
<p>"once I feel a little better"
Well, that's not right now, that's for sure.
I was fine all day, and now I feel gross and tired.</p>
<p>I think I might actually deliberately take a break for a bit and work on some other stuff.</p>
<p>For now, though, I'm just going to lie down and keep feeling gross until my body decides to stop doing that.</p>
<p>Good night.</p>
Weekly Roundup 2020-12-292020-12-29T05:00:00-05:002020-12-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-29:/weekly-roundup-2020-12-29<p class="first last">Open source work OR My body continues to let me down</p>
<ul class="simple">
<li>Wednesday: I started writing tests for pip.</li>
<li>Thursday: I wrote a bunch more tests.</li>
<li>Friday: I focused on other things, but got a few tests written.</li>
<li>Saturday: I started planning the tests for interacting with other features.</li>
<li>Sunday: I remembered and wrote a few other tests.</li>
<li>Monday: I focused mostly on puzzle stuff and didn't touch pip.</li>
</ul>
<p>Next week, the fifth TtC puzzle looks too daunting.
I think I'll just wait for the next hunt or monthly puzzle.
In the meantime, I'll try to get back to working on pip, once I feel a little better.
(I've got some kind of illness again.
I'm not having a good time with this.)</p>
Diary 2020-12-282020-12-28T05:00:00-05:002020-12-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-28:/diary-2020-12-28<p class="first last">Hoping to get in only a few days after one of my classmates from highschool.</p>
<p>Took things easy-ish again today.</p>
<p>I'm trying to finish up Tracking the Cryptid.
It turns out I'd badly misunderstood the fourth puzzle.
I at least understand the fifth puzzle, but it's hard to keep a handle on the rules, and I think I might have already messed up and need to start over.</p>
<p>Anyway, I guess I don't have more to say.</p>
<p>Good night.</p>
Pip 2020-12-272020-12-27T05:00:00-05:002020-12-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-27:/pip-2020-12-27<p class="first last">Soon...</p>
<p>I actually remembered a few other tests that I wanted, so I added them.</p>
<p>I was doing other stuff for most of the day, again, so I don't have anything else to say.</p>
<p>I'll try to put the hash tests together tomorrow.</p>
<p>Good night.</p>
Pip 2020-12-262020-12-26T05:00:00-05:002020-12-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-26:/pip-2020-12-26<p class="first last">Almost ready...</p>
<p>All right, next tests to write: hash checking, and then wheel compatibility tags.</p>
<p>Tonight, I'm just going to figure out what's required for these tests.</p>
<p>So, the hash tests consist of the interactions between an explicit requirement that includes a hash specification, and a constraint that points to a URL.
The candidate from the URL should be checked against the hash list.</p>
<p>The compatibility tags tests... I'm not sure.
It looks like the desired behavior (fail if wheel is incompatible with system) should just happen if everything is wired up properly, but I'm not sure how to test it.
I might just be failing to see tests around that area.</p>
<p>Anyway, once the small tests are out of the way, I think it would be good to have a "lifecycle" kind of test that explicitly runs through one of the use cases for the URL constraints feature:</p>
<ul class="simple">
<li>Starting from a requirements file, set up a consistent environment</li>
<li>Write the output of <tt class="docutils literal">pip freeze</tt> to a constraint file</li>
<li>Pare down the requirements file, and install in a fresh environment (or first uninstall everything) using the new requirements file constrained against the <tt class="docutils literal">pip freeze</tt> output.</li>
</ul>
<p>My plan is to spec these out in more detail, write the tests, then remove the xfail marks to make sure the tests are all failing for the right reasons.
For now, I'm going to wrap up.</p>
<p>Good night.</p>
Pip 2020-12-252020-12-25T05:00:00-05:002020-12-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-25:/pip-2020-12-25<p class="first last">Not much to say, because I was focusing on other things again.</p>
<p>Well, I let things go too late.
Let's see...
I want to write a test that confirms that URL constraints apply to packages required as dependencies.</p>
<p>Okay, did that.
I think some of the more elaborate tests I had in mind might have been overkill.
I'm going to figure out the hash tests later.</p>
<p>For now, I'm going to plug my laptop back in and get ready for bed.
Okay, yeah, the new test looks good so far.</p>
<p>Good night.</p>
Pip 2020-12-242020-12-24T05:00:00-05:002020-12-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-24:/pip-2020-12-24<p class="first last">Moving much faster now that I've moved at all.</p>
<p>I think I've got most of the basic tests I want written, and I'm going through them now.
Some of them might pass because the default behavior is to always fail, so I think I'll want to tweak some of them, and—Nope, nevermind, they're all good.</p>
<p>Anyway, in the coming days, I'm going to work on more advanced tests that have more complex packages.</p>
<p>For now, I'm going to let these tests run, and try working on some other stuff while I wind down.</p>
<p>Good night.</p>
Pip 2020-12-232020-12-23T05:00:00-05:002020-12-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-23:/pip-2020-12-23<p class="first last">Hooray, definite progress!</p>
<p>I just wrote two basic tests for URL constraints.
I'll run them later, since it's late, but it's nice to have gotten started, and gotten a little hands-on experience with test writing.
I'm marking these as strict xfail, under the assumption that I'd really like to know if these already pass somehow.</p>
<p>Not much to say on this, since I spent most of today trying to get through <a class="reference external" href="https://www.patreon.com/posts/december-reward-44546753">Tracking the Cryptid</a>.
I made a few mistakes at first on the first three puzzles, but the fourth puzzle...
I think I understand the rules, but I don't know how to convert that into a solve.</p>
<p>Hopefully I make more progress on various things in the coming days.</p>
<p>Good night.</p>
Weekly Roundup 2020-12-222020-12-22T05:00:00-05:002020-12-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-22:/weekly-roundup-2020-12-22<p class="first last">The Kingdom Hearts 3 model of software development.</p>
<ul class="simple">
<li>Wednesday: I started laying out what packages will be necessary for testing URL constraints.</li>
<li>Thursday: I made that slightly more concrete.</li>
<li>Friday: I tried to figure out what was already covered by the existing test index folders.</li>
<li>Saturday: I wrote up the stuff I'd been doing on the side, the "coding abominations". Just so we're clear, I'm laying the "abomination" part squarely at my feet. Anyway, even though the post was pretty long as posts have been here lately, I feel like it was pretty high-level and abstract, so I might want to work my way up to revisiting this at some point.</li>
<li>Sunday: I cleared up some misunderstandings on my part about the test code, and started planning out tests to add.</li>
<li>Monday: I noticed that there's a workflow I should be going through for PRs, so I get to work on following it.</li>
</ul>
<p>Next week, I'm hopefully going to start writing tests.
As well, I've got a few other things I want to do, and <em>maybe</em> write about.</p>
Pip 2020-12-212020-12-21T05:00:00-05:002020-12-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-21:/pip-2020-12-21<p class="first last">Asymptotically approaching starting...</p>
<p>So, I'm about ready in terms of knowing what to write for tests.
Now, I need to make sure that I get my changes in right, to avoid wasting effort.</p>
<p>Folowing along with the documentation, I've got to:</p>
<ul class="simple">
<li>Fork the pypa/pip repository</li>
<li>Clone it</li>
<li>Create a branch called something like "url-constraints"</li>
<li>Add tests</li>
<li>Update code</li>
<li>Update documentation</li>
<li>Add a 8253.feature.rst news fragment? I'm not really familiar with towncrier</li>
</ul>
<p>I think that's it.</p>
<p>I just now got up through the third bullet.
I'll try to get stuff done in earnest tomorrow.</p>
<p>Good night.</p>
Pip 2020-12-202020-12-20T05:00:00-05:002020-12-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-20:/pip-2020-12-20<p class="first last">Refining test descriptions. Soon, they should be as far along as pseudocode.</p>
<p>I do want to do a bit of pip work today.
It's going to be pretty minor.</p>
<p>Thing to note: generated packages don't have hashes (I think), which means...
Actually, looking into this, I'm now kind of confused.
The <tt class="docutils literal">create_basic_wheel_for_package</tt> helper function contains the following comment: <tt class="docutils literal"># Have an empty RECORD because we don't want to be checking hashes.</tt>.
But the <tt class="docutils literal">test_new_resolver_hashes</tt> module defines a <tt class="docutils literal">_create_find_links</tt> helper that calls these other helpers and associates hashes with the result...</p>
<p>OH.
I was confused.
The comment was talking about checking hashes of individual files in a package, while the hashes that matter to testing constraints are of the package as a whole.
So, we're good.</p>
<p>So, I'm going to try to sketch out what the basic tests should be doing:</p>
<ul class="simple">
<li>Create a scratch package</li>
<li>Generate a <a class="reference external" href="file://">file://</a> URL to the package</li>
<li>Constrain installation of that package to that URL, while installing an unrelated package (either another scratch package, or a data index package)</li>
<li>Assert that the installation succeeded, and the first package was not installed.</li>
</ul>
<p>Have another test for having an unused constraint to example.com, though I'm not sure what that should do.</p>
<p>Another test:</p>
<ul class="simple">
<li>Create a scratch package</li>
<li>Generate a <a class="reference external" href="file://">file://</a> URL to the package</li>
<li>Constrain installation, and install the package</li>
<li>The constrained URL should have been used.</li>
</ul>
<p>Another:</p>
<ul class="simple">
<li>Create a scratch package with the same name as a package in the data index, but an intermediate version.</li>
<li>Generate a <a class="reference external" href="file://">file://</a> URL to the package</li>
<li>Constrain installation of that package to that URL, and install the package, while using the data index.</li>
<li>The constrained URL should have been used.</li>
</ul>
<p>As above, but either the constraint or the installation includes a version range incompatible with the scratch package; expect failure.</p>
<ul class="simple">
<li>Create two scratch packages with the same name and different versions</li>
<li>Generate <a class="reference external" href="file://">file://</a> URLs to each</li>
<li>Constrain installation to both</li>
<li>If installing an unrelated package, installation should succeed</li>
<li>If installing the scratch package, installation should fail</li>
</ul>
<p>As the second case above, but with a constraint and a requirement, instead of two constraints.</p>
<ul class="simple">
<li>Create a scratch package</li>
<li>Generate a <a class="reference external" href="file://">file://</a> URL to the package</li>
<li>Constrain the installation to the URL</li>
<li>Require the package by URL along with the constraint</li>
<li>Installation should succeed</li>
</ul>
<p>There's more to outline, but I'm getting tired.</p>
<p>Good night.</p>
Coding 2020-12-192020-12-19T05:00:00-05:002020-12-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-19:/coding-2020-12-19<p class="first last">Links are supposed to have helpful, descriptive names. Supposed to.</p>
<p>I didn't touch pip today, and I don't want to force myself through it, so I think I'll finally start talking about the side project I was putting in some time on.</p>
<p>I found out about <a class="reference external" href="https://clojure.org/reference/transducers">transducers</a> a few months ago from <a class="reference external" href="https://buttondown.email/hillelwayne/archive/d93e4e7e-2334-45a9-aaf3-3909fa6df775">Hillel Wayne's newsletter</a> and twitter.
I found it extremely hard to reconstruct some aspects of the Discourse™ several years down the line (in particular, I don't think I've tracked down any specific examples of Rich Hickey calling something "not transducers"), but the basic concept seems pretty intuitive to me by now.
Consider a section of code that operates on discrete pieces of data one at a time.
We can reify the operation into a function that takes a value representing a state or "accumulator", and one item to operate on, and returns a new value for the accumulator, that can then be passed back in.
Such a function is called a "reducing function".
"Transducers" is the new name for "reducing function transformers", functions that take a reducing function, and return a new one that does some additional operation to the input before passing it to the wrapped function.
The contracts of transducers in Clojure are somewhat more complex, to handle early termination and resource cleanup.</p>
<p>(People who know Haskell better than I do: apparently this is a special or "perverse" case of something called a "<a class="reference external" href="https://www.reddit.com/r/haskell/comments/2cv6l4/clojures_transducers_are_perverse_lenses/">lens</a>".)</p>
<p>I'm going to talk now about why anyone went to all of this trouble, and to do that, I'm going to switch programming languages, since my Lisp is <em>extremely</em> rusty.
(Nothing to do with any of <a class="reference external" href="https://github.com/murarth/ketos">the</a> <a class="reference external" href="https://github.com/swgillespie/rust-lisp">three</a> <a class="reference external" href="https://stopa.io/post/222">projects</a> I just found trying to combine Rust and Lisp.)</p>
<p>When functions like <tt class="docutils literal">map</tt> were added to Python, they took lists, and returned lists.
Since Python is eagerly evaluated, compared to languages like Haskell, this meant that both the input and the output lists had to exist in memory simultaneously, but <em>so did any intermediate lists</em>.
These operations would build up each intermediate list in memory, then discard it.
As such the memory consumed by such an operation would be several times that of the only lists that the user specifically cared about: the input and the output.</p>
<p>Various additions and reforms were made to the standard library to combat this.
The builtin functions were given the ability to accept iterable values, which could produce values one-at-a-time, but they could not change their output type until the Python 3 compatibility break.
Until then, Python 2.3 and onward had the itertools library, which provided versions of builtin functions that return iterable values, and still provides additional functions for working with iterables, that did not make it into the builtins module.</p>
<p>Until Python 3, we see this kind of tabular relation, where one axis is <em>what we're doing to the data</em>, and the other axis is <em>how we're passing data in and out</em>.
<tt class="docutils literal">map</tt> corresponds to <tt class="docutils literal">imap</tt>, <tt class="docutils literal">filter</tt> corresponds to <tt class="docutils literal">ifilter</tt>, and so on.
With Python 3, the standard library took the general approach of using iterables where possible; if the old behavior was desired, the output could be wrapped in a call to <tt class="docutils literal">list</tt>.
So, the duplication of effort was resolved.
Except.
Several years later, the <tt class="docutils literal">async</tt> and <tt class="docutils literal">await</tt> keywords were added to Python 3.5.
In particular, the <tt class="docutils literal">async for</tt> statement was added, which operates over <em>asynchronous</em> iterables.
There have been <a class="reference external" href="https://pypi.org/project/aitertools/">efforts to make async versions of itertools functions</a>, and I can't say for sure that the builtin functions won't somehow adapt to support both kinds of iterable, but any such efforts are not guaranteed to extend cleanly to third-party libraries, and the more of these functions we care about, the more effort it is to get every version of them up to the same level of functionality, the more raw code there is, and thefore the greater risk of bugs.
With functions written like <tt class="docutils literal">map</tt> and <tt class="docutils literal">filter</tt>, we're stuck with the tabular relation between <em>what we're doing to the data</em> and <em>how we're passing data in and out</em>.</p>
<p>What if we could abstract those concerns apart, so that, if we have m stream operations, and n stream sources, we have m + n functions, rather than m * n?
That's the motivation for rewriting these functions as reducing functions!
That way, we can have "a reducing function that maps" and "a function that calls a reducing function in a for loop" and recover Python 3's <tt class="docutils literal">map</tt>.
More interestingly, if the interfaces involved are solid enough, two different projects can define these functions independently, and another project could put them together, and have it just work.</p>
<p>Now, that motivation is for reducing functions.
It doesn't touch on transducers.
The idea of transducers is to make it easier to write a desired reducing function, by applying a sequence of transformations to the input data.
That way, the function to drive the reducer only needs to be called once, and the data doesn't have to constantly round-trip through different formats.
It's the difference between <tt class="docutils literal">the_same_driver_every_time(reducer_1, the_same_driver_every_time(reducer_2, source))</tt> and <tt class="docutils literal"><span class="pre">the_same_driver_every_time(transducer_1(transducer_2(base_reducer)),</span> source)</tt>.
The difference can add up as you add more operations.</p>
<p>So, transducers seem pretty cool to me.
On their own, they haven't yet convinced me to pick up Clojure, so I've been looking into transducers implementations for Python.
There's <a class="reference external" href="https://github.com/sixty-north/python-transducers">an existing project</a>, but it hasn't been updated in years, and the code style is... not what I would write.</p>
<p>("Oh boy, here we go again.")</p>
<p>There are many decisions I could disagree with, but the biggest issue for me is the lack of type annotations.
I've had trouble in the past articulating why I think people should use type analysis tools for Python, because the gains in documentation quality and confidence were just so, so obvious to me once I tried it.
Now, <a class="reference external" href="https://rakhim.org/summary-of-transducers-a-talk-by-rich-hickey/#transducer-types">typed transducers</a> (ignoring the Haskellers going "They're lenses!") is apparently a contentious topic.
For my part, I find the argument of "the type of the accumulator can change between steps, so you can't assign it a static type" unpersuasive.
Just use a union.
("Sum!" "Enum!")
It's true that using unions obscures runtime relations between input and output types, but I don't know where the implicit requirement that the static types have such detailed knowledge of the runtime relations <em>comes from</em>.
What would the type system even do with that information?
Unless the length of the input is known statically (which seems like a dubious assumption when potentially infinite streams are involved), the final value has to collapse into a union anyway, and if it <em>is</em> known statically, then we're getting into <a class="reference external" href="https://en.wikipedia.org/wiki/Dependent_type">dependent types</a>.</p>
<p>To put it another way, this sounds to me like rejecting typing systems in general, because there exist typing systems that cannot handle function definitions like <tt class="docutils literal">double: Int <span class="pre">-></span> EvenInt</tt> and <tt class="docutils literal">increment: EvenInt <span class="pre">-></span> OddInt; increment: OddInt <span class="pre">-></span> EvenInt</tt>.</p>
<p>All this is to say that I'm not going to let Rich Hickey's opinions stop me from trying to add type annotations to the python-transducers package.
I <em>will</em> let the code itself stop me, though.
In my efforts, I ran across code that I couldn't properly annotate because, considering what it actually does, I couldn't convince myself it was correct.
As a result of this, I attempted a from-scratch rewrite with types from the beginning, rather than forced in afterwards.
This effort failed, because I hadn't looked at the provided reducing functions, some of which do things that surprised me, and which defeated my first attempt at typing.</p>
<p>After I had some time to think, I began my second rewrite, in which I used my intuitions about types to guide changes to the interfaces.
As such, even though the code I have fulfills the same goals as transducers, as I understand them, I actually wouldn't mind if anyone looked at them and said "those aren't transducers!"
There are obvious differences, that exist for possibly-subtle reasons.
This is entirely hypothetical, for now, because I'm not currently in the habit of shoving out half-finished projects that aren't even used anywhere.
(Do I want to do anything about my current slate of half-finished, unused projects?
Eeehhh, effort.)</p>
<p>Maybe later I'll go into more detail about the code I actually wrote, but first I'd like to confirm that it's usable, and that, um, has kind of a stumbling block, because my rewrites are in the genre of "writing a bunch of code because the structure of the code provides an intellectual challenge".
I'm not writing a standard library, or any generally-useful extensions.
I don't have any projects where I see myself explicitly being generic in how a reducing function is to be called.
I've done a bunch of these kinds of solutions-in-search-of-problems over the years, and they're probably educational, but they eventually stop being <em>satisfying</em>, which is why I'm leaning towards putting this rewrite on the back burner.</p>
<p>Anyway, it's late, and I want to be done with this.</p>
<p>Good night.</p>
Pip 2020-12-182020-12-18T05:00:00-05:002020-12-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-18:/pip-2020-12-18<p class="first last">Still in a holding pattern while I try to gather my strength.</p>
<p>I've gotten to a point with the abomination code where I need to just, consider what I'll do with it, if anything.
I'd like a proper project to mess with it in if I go any further, which means this all comes back to the pip stuff.</p>
<p>For now, I'm going to try to add some context to what I was saying yesterday, because as far as I'm concerned, I'm missing it.</p>
<p>One thing I need is a package that doesn't depend on anything I care about.
That way, I can install it along with a constraint, to make sure that the constraint is correctly ignored.
For the bulk of the tests, I need packages I can refer to via a URL constraint, which means packages somewhere in the data directory.
The most complicated thing I want is URL-referable packages that refer to a requirement by URL.
For that, I basically want to throw together various combinations of URL requirement and constraint, and confirm they behave as expected.
For that, I need to somehow generate those packages...</p>
<p>So, the first two have plenty of packages in the test index already that look perfect for that.</p>
<p>So, I just need to figure out how to generate a package (check) and refer to it by file URL rather than by name (I'll get back to you).
Ah, got it, I just need to <em>not</em> use the scratch path as an index, and instead generate file URLs to its contents.
With this, I can also more cleanly create packages that aren't in the index being used.
This system is... still a little magic, to be honest, but not quite as magic as I thought.</p>
<p>I think I understand it well enough now to actually write tests, once I collect my thoughts.</p>
<p>Anyway, I'm going to wrap up now and take it easy for a bit.
Easy-easy, not "borderline incomprehensible higher-level functions" easy.</p>
<p>Good night.</p>
Pip 2020-12-172020-12-17T05:00:00-05:002020-12-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-17:/pip-2020-12-17<p class="first last">Incremental progress.</p>
<p>I spent a bunch of today playing Nova Drift (new high score on my current profile), and refining my code abominations.</p>
<p>Let's see if I can't do some quick planning, though.</p>
<p>I need packages something like:</p>
<ul class="simple">
<li>"standalone", say version 1.0.0</li>
<li>"forked", version 1.0.0, with URL versions 2.0.0 and 3.0.0</li>
<li>"forked_again", with URL versions 1.0.0 and 2.0.0 (relate to "forked")</li>
</ul>
<p>It occurs to me that I may want tests involving packages where the fork has an identical version.
It should be sufficient to have this as a variant of the second bullet, but with no relation to the third bullet.</p>
<p>I'll try to work on these over the weekend.
For now, I just want to focus on relaxing.
Which is something that I'll have to accept I might have a strange definition of.</p>
<p>Good night.</p>
Pip 2020-12-162020-12-16T05:00:00-05:002020-12-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-16:/pip-2020-12-16<p class="first last">I don't need much, but I do need to figure out how much I need.</p>
<p>Okay, let's see about an inventory of the packages I'll need.</p>
<ul class="simple">
<li>A package that can be referred to by URL. It should be well-formed, and I need to be able to check whether it is installed.</li>
<li>A package with multiple versions, which can be referred to by URLs.</li>
<li>A package with a version in the index, and a different version that can be referred to by URL.</li>
</ul>
<p>That covers most of the tests, and can be accomplished with a single package that has one indexed version and two URL versions.</p>
<p>In case I want more elaborate tests, I could have stuff like, a package that depends explicitly on one of the URL packages.
Then, constraining to the other version should fail.</p>
<p>And, for something more elaborate, having two versions of a package that each depend on different URLs.
That raises a few questions that probably apply more generally.
Suppose the latest version of the dependent is installed (no constraints), and either the dependent, or an unrelated package, is installed unqualified, but constraining the URL dependency.</p>
<p>So, the minimal kind of set for that is:</p>
<ul class="simple">
<li>Package with no relations</li>
<li>Package with one version in index, and two versions that need URLs to locate</li>
<li>Package with one version in index (depends on one URL version), and one version in another index (depends on the other URL version)</li>
</ul>
<p>As long as usable hashes can be generated for any of these packages, I think that should be enough for a start.</p>
<p>Okay, that's some solid planning.
I'm going to unwind by coding some abominations.</p>
<p>Good night.</p>
Weekly Roundup 2020-12-152020-12-15T05:00:00-05:002020-12-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-15:/weekly-roundup-2020-12-15<p class="first last">Drawn to software projects with no clear purpose like a moth to a flame.</p>
<ul class="simple">
<li>Wednesday: I worked on getting pip's tests to pass. In part, this involved reworking my vcs setup.</li>
<li>Thursday: I started sketching out tests for the new functionality.</li>
<li>Friday: I mostly did other stuff, but also started familiarizing myself with pip's test layout. And sketched out a few more tests.</li>
<li>Saturday: I worked on understanding the existing tests little better.</li>
<li>Sunday: I messed with some other coding stuff that didn't really work out. I <em>might</em> be able to wring something out of it.</li>
<li>Monday: I played Nova Drift, and did a little more investigation and thinking about how to test URL constraints with pip.</li>
</ul>
<p>Next week, I might take another crack at the side project I gave up on, but I definitely want to start writing tests for pip.</p>
Pip 2020-12-142020-12-14T05:00:00-05:002020-12-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-14:/pip-2020-12-14<p class="first last">I think I've figured out where everything I need is.</p>
<p>I mean, for most of today, I was playing Nova Drift.
But I did just now make some key progress on planning tests for pip.</p>
<p>Since the feature I'm adding is all about installing packages from URLs, I'll need URLs of packages, and I'd rather not rely on external resources for new tests, so that means leveraging the test data directory.
There are plenty of packages in there; I just have to figure out which ones make sense to install, since some of them are deliberately broken for the sake of particular tests.</p>
<p>I'm thinking I should probably add and document new packages for it, so there aren't conflicting requirements or concerns for packages.</p>
<p>I think that was the last piece of the puzzle, for me.
With that, I can convert my brief sketches of tests to a more detailed description, then convert those to tests.</p>
<p>Anyway, I should wrap up.</p>
<p>Good night.</p>
Diary 2020-12-132020-12-13T05:00:00-05:002020-12-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-13:/diary-2020-12-13<p class="first last">Sort of a frustrating day, in retrospect. Oh well.</p>
<p>I didn't touch pip today.
I messed some more with the coding stuff I was trying to do on the side.
I'm not writing that up yet because I need to either find a language that's a better fit for it than Python, or psych myself up to do a postmortem.
Either that, or really go in on changing how it works...
This wasn't really <em>for</em> anything, so I think it's best to just drop it.</p>
<p>It would have been nice if I'd had the the focus left over to work on new tests for pip, but oh well.</p>
<p>I think maybe I need to commit myself to relaxing a bit, then get back into this.</p>
<p>Anyway, no point in trying to grind out a longer post now.</p>
<p>Good night.</p>
Pip 2020-12-122020-12-12T05:00:00-05:002020-12-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-12:/pip-2020-12-12<p class="first last">Trying to balance recovering my focus with wanting to do stuff...</p>
<p>So, I have to <em>understand</em> the tests of the new resolver before I can write new ones.</p>
<p>Looks like there are various helpers.
There's the <tt class="docutils literal">script</tt> fixture, which is a <tt class="docutils literal">PipTestEnvironment</tt>.
That's going to be what ends up executing the various pip commands.
It looks to me like the kind of tests I want are a pretty straightforward translation into the existing idioms.</p>
<p>I don't know when I'll be up for actually doing the translation, but I'll try to get started in the next few days.</p>
<p>I'll also need to get rid of some of the existing tests, but that shouldn't be too difficult.</p>
<p>I'm going to try to wrap up, and by try to wrap up, I mean put in some more work on the other thing I've been messng with.</p>
<p>(Also, since I took a break from the virtual tabletop stuff, I've had some time to think, and concluded that I've pushed nox too far, so I'm looking into alternatives that would give me stuff like, parallel execution, and dependencies between stages. I've got some plans sketched out, and the migration should be an interesting couple of days, week, month...)</p>
<p>Good night.</p>
Pip 2020-12-112020-12-11T05:00:00-05:002020-12-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-11:/pip-2020-12-11<p class="first last">I might write up the other thing later.</p>
<p>I more-or-less took today off so far as working on pip goes, but what I mostly did would require a really extensive explanation, so I'm going to do like ten minutes of work now and write up that instead.</p>
<p>Looks like the "functional" test directory is a good place to start, since it has two files that mention the new resolver, and constraints.
One of them is specifically for tests involving hashes, which is something I forgot about when I was writing up tests yesterday.</p>
<p>The basic test cases I think I need to cover are:</p>
<ul class="simple">
<li>URL in constraints, hash in requirements</li>
<li>URL and hash in constraints (I think hashes in constraints are supported)</li>
</ul>
<p>In both cases, resolution should succeed (absent other conflicts) if the hash matches the URL payload (I <em>think</em> that's the proper interpretation), and always fail if they don't match and the package is required.
I think the behavior should basically match what happens if it's all in requirements, so that's a good reference point.</p>
<p>Anyway, that's some good stuff to have in mind when I get my focus back.</p>
<p>Good night.</p>
Pip 2020-12-102020-12-10T05:00:00-05:002020-12-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-10:/pip-2020-12-10<p class="first last">I probably missed something.</p>
<p>Status of getting pip's tests running on tox: it turns out that some of the remaining failures are because those test sessions are running in a virtualenv, which... I don't know what to do about that for local development, so I'll just push it off onto PyPA's CI.</p>
<p>So, now I need to start working on tests for a few different cases:</p>
<ul class="simple">
<li>Specifying a URL constraint but not requiring the package <em>does not</em> install the package.</li>
<li>Specifying a URL constraint and installing the package installs the package</li>
<li>Specifying multiple URL constraints causes resolution to fail</li>
<li>Specifying one URL constraint and requiring the same URL installs the package</li>
<li>Specifying one URL constraint and requiring a different URL causes resolution to fail</li>
<li>Specifying a URL constraint and constraining/requiring a compatible version range installs the package (in the case of constraining, assuming there's a requirement)</li>
<li>Specifying a URL constraint and constraining/requiring an incompatible version range causes resolution to fail (in the case of constraining, assuming there's a requirement)</li>
<li>Should probably test that constraints properly do and don't apply when python_version is constrained, but that should Just Work.</li>
<li>Specifying a URL constraint that is satisfied by an existing installation succeeds</li>
<li>Specifying a URL constraint that is not satisfied by an existing installation attempts to satisfy the constraint by updating</li>
<li>Test different URL protocols</li>
<li>Confirm that <tt class="docutils literal">pip freeze</tt> output can be used as a constraint file.</li>
</ul>
<p>I spaced out and did other stuff, so compiling the list will have to do for now.
I'll look over the existing tests later to see where these fit and what they'd look like.</p>
<p>Good night.</p>
Pip 2020-12-092020-12-09T05:00:00-05:002020-12-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-09:/pip-2020-12-09<p class="first last">Too old, too new, the important thing is that people can call me a hipster.</p>
<p>The first step in getting tests to pass was to fix up the Mercurial-related tests.
It appears those were broken for me because I was doing something at least somewhat peculiar to have Mercurial available everywhere, but I realized, I don't really use it except for publishing this blog.
(So, the fact that you're reading this means I got everything working well enough.)
Now, Mercurial <em>itself</em> is not trapped on Python 2, but the latest PyPI release of the extension that is the <em>other</em> reason I ever use Mercurial nowadays <em>is</em>, so I undid the global-ish install.
(To an extent.)
I have to stop clinging obnoxiously to the past...</p>
<p>And start clinging obnoxiously to the future!
The new Pijul alpha is super confusing after versions 0.12 and 0.11, but I don't care!
You hear that, world‽
You can make me use git, but you can't make me like it, and I will gladly use experimental software for my own stuff!</p>
<p>Anyway, making it so the tests don't hit the wrong Mercurial script fixed some of the tests, but it looks like some tests failed for other reasons.
Those other reasons include "I'm hitting the rate limits that broke pip's CI a few months ago. But this isn't CI. This is a laptop. Oh well."</p>
<p>If I can just use the same workaround, I'm happy.</p>
<p>So, I'm rerunning the tests with the "CI" logic activated, and we'll see how that does.
The next step is getting it to run on every version of Python that isn't EOL.</p>
<p>Looks like all that is enough to get some of the Pythons to pass.
I'm going to take it easy for the rest of the night while that runs.</p>
<p>Good night.</p>
Weekly Roundup 2020-12-082020-12-08T05:00:00-05:002020-12-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-08:/weekly-roundup-2020-12-08<p class="first last">Trying to imagine how badly this would have gone if I'd just jumped in and started changing code. It would not have been pretty.</p>
<ul class="simple">
<li>Wednesday: I laid out what I knew about pip's new resolver, and what I want to change. (This is in line with an existing issue.)</li>
<li>Thursday: I did a little research on pip, while sick with... something.</li>
<li>Friday: I started sketching out what needs to happen for the feature I want to add to pip.</li>
<li>Saturday: I went into more detail, and asked and answered some new (to me) questions.</li>
<li>Sunday: I didn't write up much, just posted on the GitHub issue.</li>
<li>Monday: I got a response on GitHub, which has given me a full initial plan for the changes I want to make to pip.</li>
</ul>
<p>Next week, I'm going to work on asking as many questions up-front as I can think of, and converting them to tests before doing work on pip itself.</p>
<p>Before that, I should probably figure out how to get all of the tests to pass in the first place.
That'll be... interesting.
Good thing I don't have to do that right now!</p>
Pip 2020-12-072020-12-07T05:00:00-05:002020-12-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-07:/pip-2020-12-07<p class="first last">Still not sure what form some of the data should be stored in.</p>
<p>Okay, here's what I want to have a plan for currently.
Right now, I can expect that the <tt class="docutils literal">Candidate</tt> generated from a URL <tt class="docutils literal">InstallRequirement</tt> will have a usable <tt class="docutils literal">source_link</tt> field, but I believe I should not rely on that, and be able to generate relevant information from one with that field set to <tt class="docutils literal">None</tt>, such as an <tt class="docutils literal">AlreadyInstalledCandidate</tt>.</p>
<p>Per discussion on GitHub, I should get the equivalent information from <tt class="docutils literal">direct_url_helpers.dist_get_direct_url()</tt>.
That function takes a <tt class="docutils literal">Distribution</tt> and returns an <tt class="docutils literal">Optional[DirectUrl]</tt>.
If need be, I can convert a <tt class="docutils literal">Link</tt> to a <tt class="docutils literal">DirectUrl</tt> using an adjacent function, so that part should be workable.
My next issue is generating a <tt class="docutils literal">Distribution</tt> from an <tt class="docutils literal">AlreadyInstalledCandidate</tt>.
That's just the <tt class="docutils literal">dist</tt> field.
Glad that part was easy.
That field is part of the <tt class="docutils literal">Candidate</tt> interface, so it's possible it'd be more stable to always use it.</p>
<p>Not sure what the preferred way to compare <tt class="docutils literal">DirectUrl</tt> instances is, since there's no comparison methods defined on the class.
I'm pretty sure converting them to a <tt class="docutils literal">dict</tt> would work, since the tests do something similar.</p>
<p>Since I've now got a plan for implementing this stuff, I think next I should be putting together tests so I can have some confidence in all of this when I start putting it together.</p>
<p>Good night.</p>
Pip 2020-12-062020-12-06T05:00:00-05:002020-12-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-06:/pip-2020-12-06<p class="first last">Some minor concerns, nothing too worrying.</p>
<p>Not much done with pip, a little research into potential issues.
I got distracted by that and spaced out, so I'm going to post this, post an update in the GitHub issue, and wrap up.</p>
<p>Good night.</p>
Pip 2020-12-052020-12-05T05:00:00-05:002020-12-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-05:/pip-2020-12-05<p class="first last">Doing a lot of work to figure out how much extra work I need to do, and it turns out it's "none".</p>
<p>I just did some cursory research on usage of URL constraints, and didn't find anything new.</p>
<p>Here's what I'm thinking so far.</p>
<p>Per pfmoore's thoughts on the behavior, each URL constraint should apply to all candidates, which means that, in practice, two URL constraints together should always fail, though the logic shouldn't be frontloaded.
So, the Constraint object can build up a set of Link objects; the empty constraint has an empty set, and the <tt class="docutils literal">__bool__</tt> and <tt class="docutils literal">__and__</tt> methods behave accordingly.
To check whether a Candidate satisfies the Link objects, every Link must be compared against the Candidate's <tt class="docutils literal">source_link</tt>, and they all have to match.</p>
<p>As I was typing this up, some questions occurred to me:</p>
<ul class="simple">
<li>It looks like python_version constraints are not rejected by the same code that rejects URL constraints. Are they possible, and, if so, how do they act on their own? How do they act in conjunction with any given implementation of URL constraints?</li>
<li>What happens when the requirement is already installed? Is it guaranteed that a LinkCandidate will be generated? What behavior does the AlreadyInstalledCandidate have? Are there any inconsistencies between this and requiring the URL directly? (I think I've noticed that URL requirements always reinstall, while requiring the bare name just succeeds, so the behavior I think it'll have should be acceptable.)</li>
</ul>
<p>Okay, looking into the first, this looks a little gnarly.
<tt class="docutils literal">requires_python</tt> is evidently a <em>Link</em> field, which means it'll definitely be associated with Links, but it seems to me that the only sensible interpretation of it is to consider the Link to match all candidates if the Python version <em>doesn't</em> line up.
The other option I see is to evaluate Links as they come in, which I'm really not sure how to do.</p>
<p>I'll need to figure out what the current implementation does for non-URL constraints/requirements, because it looks like it does treat them as I expected.
I'm not sure if I need to do anything then...
Okay, got it.
There's logic that runs for constraints, which I'm not sure how it filters out non-satisfying Python version constraints, but experimentally, it does.
That means only relevant constraints will be added, and I don't have to do any extra legwork on them once they show up.</p>
<p>Random bit of advice for anyone taking the same approach as me to figuring out how pip works: the attrs package has a bunch of versions, and no dependencies.
I haven't touched dependencies-of-dependencies, or anything like that, yet.
That's going to be a whole thing.</p>
<p>Okay, so setting up the initial prototype for this should be relatively straightforward.
We shall see.
Later.</p>
<p>Good night.</p>
Pip 2020-12-042020-12-04T05:00:00-05:002020-12-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-04:/pip-2020-12-04<p class="first last">"I don't get it I don't get it I don't get it I... sort of get it."</p>
<p>I searched through pip's source code enough that I've worked out approximately what needs to change.
I'll probably run up against something horrible, but we'll see.</p>
<p>Anyway, I should make sure I know about the use cases so I can make sure that things work:</p>
<ul class="simple">
<li>Redirect installation of a package to a fork hosted on a website. (Useful for projects with common overrides, but many environments that may not need everything installed.)</li>
<li>Redirect installation of a package to a local file (I'm not sure if people besides me do this)</li>
<li>Run <tt class="docutils literal">pip freeze</tt> against an environment. Use the result as a constraint file when recreating it. This means that the packages installed in the recreated environment will be a subset of the original environment (provided the project didn't add requirements), but if the project has dropped some requirements, it will be a smaller subset. This workflow requires URL constraints because <tt class="docutils literal">pip freeze</tt> will output URL requirements, if applicable. (In any case, this works out to controlling the evolution of a project over time.)</li>
</ul>
<p>To be honest, my use case is probably the weakest, since it works out to "basically a devpi index with less steps".
But I think all of these use cases require the same basic functionality, so it works out.</p>
<p>Anyway, I should probably do a broader survey of use cases before moving on, just to make sure I'm not missing something.</p>
<p>Good night.</p>
Pip 2020-12-032020-12-03T05:00:00-05:002020-12-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-03:/pip-2020-12-03<p class="first last">Bit of a slow day. It happens.</p>
<p>I was distracted today, and now I feel a little sick.
(If my sense of smell goes away, I'll mention it.
Right now, it's extremely present.)</p>
<p>Point is, I got just a little work done researching how pip works.
What I concluded is, there doesn't seem to be much documentation (at least, on what I want to know) anywhere obvious, so to make progress, I'm going to have to formulate a bunch of basic questions, then work on answering them, and possibly write stuff up to flesh out the documentation.</p>
<p>I'll hopefully make progress there by the end of the week.
Right now, I just want to work on not feeling gross.</p>
<p>Good night.</p>
Pip 2020-12-022020-12-02T05:00:00-05:002020-12-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-02:/pip-2020-12-02<p class="first last">Getting ready to put in a lot of effort, to avoid... probably less effort, but eeeeh.</p>
<p>What I know about pip's new resolver:</p>
<ul class="simple">
<li>People wrote stuff about how pip isn't a proper package manager, and I think the new resolver is supposed to address that.</li>
<li>Supposed to make it harder to end up in an inconsistent state. In my own code, I mostly work with small virtualenvs, but at work, we addressed our various packaging woes by pinning every single package version, which <em>sort of</em> worked.</li>
<li>Everything I've read about the new resolver makes it sound like it's a pretty pervasive rewrite.</li>
<li>In particular, some functionality that was <em>officially</em> never supported was removed.</li>
<li>That last sentence is salty because I got the idea for using said functionality from the documentation introducing one component of it; that documentation has been unchanged since the feature was introduced, so I'd <em>sure as heck</em> like to know what the original intention was supposed to be.</li>
</ul>
<p>Okay, here's the deal.</p>
<ul class="simple">
<li>I'm developing groups of related packages in concert, and for testing and packaging purposes, I need to be able to install these packages, which depend on each other, through pip (or some other PEP 517 frontend, which I don't think really exists yet).</li>
<li>I want to install my copy of a package, even if it's also available on PyPI, and I don't want to have to think about whether it is.</li>
<li>I've attempted various ways to accomplish this, but the easiest way I found to do it with the old resolver is to dynamically define constraints files that use absolute file URLs to point to the project paths. (I could potentially make this faster by building wheels, but I'm not feeling bottlenecked by pip currently.) (I also added normal constraints on the third-party packages so I don't have to duplicate those in all of the pyproject files, but those constraints could live in a separate static file.)</li>
<li>Currently, this doesn't work with the new resolver, because constraints "were never supposed to work like that".</li>
<li>But there's enough demand for the feature that there's a design sketched out, and it'll happen when...</li>
<li>When they get a PR.</li>
</ul>
<p>Now, if I try to write that PR, that's a lot of effort on my part, and it could be pretty complicated.
But consider: my alternative is something like devpi, which I would have to commit to setting up on every machine I do personal projects on.
If I can manage to implement this (or help someone else do it; I just want it done), then I don't have to change my workflow, and it'll continue to just work, with only the bare minimum required setup.
(Like, this current project's code is just... not going to work without Python 3.8 or later.)</p>
<p>So, what do I think I know about what has to change?</p>
<p>Well, old-style constraints are basically old-style requirements in a funny hat, and new-style constraints are their own specific thing.
I <em>believe</em> that getting URL constraints to work requires the creation of a new kind of constraint, so the first thing I want to look at is how new-style constraints are defined, and used.</p>
<p>So, let's get into it.</p>
<p>Okay, some of the logic lives in pip itself, and some of it lives in resolvelib.
Or is resolvelib vendored? Not sure the modules match up.
Okay, looks like any changes I make need to be in resolvelib (or packaging? Looks more likely to be packaging) first, then the vendored copies need to be updated.</p>
<p>Okay, I confused myself several times looking into that.
Here's what I've got currently:</p>
<ul class="simple">
<li>Some of the logic that is relevant to this lives outside the vendored packages, so doing this will involve some non-trivial changes to pip's code.</li>
<li>I don't know how flexible the vendored packages are, so they might need some changes.</li>
</ul>
<p>To get started, I decided to just follow along with the development documentation.
I've got pip cloned, and tox is running tests.
There are a few failures so far; I'll have to see later if those are expected, or something I need to fix in my environment.
It's also probably going to yell at me about missing Python versions, since I didn't try to reach parity with what pip supports.</p>
<p>I don't know how much more I'm going to get done tonight; I want to just see the baseline state of the fresh clone.
I should probably also mention this in the GitHub issue, make sure to communicate, like, basic things.</p>
<p>Update from running tox: it is, in fact, complaining to me about missing pythons.
Including some that I see installed under pyenv.
Oh dear, this could get messy.</p>
<p>Well, I'll work things out tomorrow.
For now, I'd like to wrap up.</p>
<p>Good night.</p>
Weekly Roundup 2020-12-012020-12-01T05:00:00-05:002020-12-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-12-01:/weekly-roundup-2020-12-01<p class="first last">I am on <em>many</em> cutting edges.</p>
<ul class="simple">
<li>Wednesday: I investigated browser-based Python stuff a little more, and found more bugs. (I found even more today; we'll see what comes of them.) I also did some work on the punq fork.</li>
<li>Thursday: I rewrote my AST visitor code to use eval instead.</li>
<li>Friday: I got the eval code working. The resulting code is significantly slower under test, I think because of the greater amount of work required by this approach. I think it'll be worth it, though.</li>
<li>Saturday: I set up profiling for all of the test suites, and determined that I can mitigate the slowdown using an LRU cache, so I'm doing that. I started pondering refinements and changes to the rough interface that I... "designed" is the wrong word.</li>
<li>Sunday: I made some progress on the Mythic CLI, and found other things that I'd like to do differently.</li>
<li>Monday: I wasn't up for much, so I just got the test suite to basically pass again.</li>
</ul>
<p>Next week, I'm working on actually planning this stuff, both in terms of what to refactor, and what I'm going to implement.
I've got a big list of stuff that I'm going to flesh out with more and more information, including my plans for localization, and what I want to implement, from each of the seven systems.</p>
<p>One other thing that I apparently have to work out if I ever want to upgrade pip again for these projects, is how to replicate my old constraints-based flow, which is <em>totally</em> not <a class="reference external" href="https://github.com/pypa/pip/pull/2857/files#diff-4b46e99840eeda55b0a1d8078707997092936e42dcc8804f25f165b6abe2a90f">how constraints files were meant to be used</a>.
The cleanest way is probably devpi, but... effort.
The quickstart tells me to set up supervisord, and the first time I tried that, it didn't feel quick <em>at all</em>.
I'll try again later, I guess.
Or, I can try reimplementing URL constraints myself.
PRs welcome, and all.</p>
Coding 2020-11-302020-11-30T05:00:00-05:002020-11-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-30:/coding-2020-11-30<p class="first last">Short post because I don't feel like trying to write a lot.</p>
<p>I made some tweaks to the Mythic CLI so the tests pass, even though I'm pretty sure at least some of the code just doesn't work.</p>
<p>I've got two broad categories of thing I want to work on: improvements to existing code, along various axes, and planning out the large amount of code that remains to be added.</p>
<p>I'm feeling about done for tonight, so I'll leave this post there and think about what I want to work on next.</p>
<p>Good night.</p>
Coding 2020-11-292020-11-29T05:00:00-05:002020-11-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-29:/coding-2020-11-29<p class="first last">Thinking of tinkering with some other unrelated bits of this project.</p>
<p>The big things missing currently from my prototype Mythic CLI (besides rolls <em>not</em> based on the Fate Chart), are working converters to generate the types required by the endpoints.</p>
<p>Other things I noticed:</p>
<ul class="simple">
<li>I ended up writing a small amount of formatting logic that I'd rather push off on a localization system, which raises the question for me of how I want to handle localization. Like, okay, each library is going to have a set of messages that it generates, and will presumably provide localizations for them, so I guess I need to have my libraries define functions that'll load a set of locale roots into a set, and recurse into other libraries to make sure they're covered? Maybe?</li>
<li>I messed around with the roll implementation some more, and it is so disorganized in there. So disorganized. I think I need to take a break from this code for a bit, then come back to it later with an eye on simplifying things a lot.</li>
</ul>
<p>I spaced out a bit writing that up and researching localization, so I guess I'm done for now.</p>
<p>Good night.</p>
Coding 2020-11-282020-11-28T05:00:00-05:002020-11-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-28:/coding-2020-11-28<p class="first last">Discovering some pretty severe tech debt.</p>
<p>I've got nearly all the components of Mythic's fate roll put together.
The sheer volume of code I've written for this makes me kind of question my approach here, but I'm hoping this is just kind of a reflection of the underying complexity of the full rules.</p>
<p>I'm kind of reeling from all of that.</p>
<p>Anyway, I also put together <a class="reference external" href="https://github.com/joerick/pyinstrument">Pyinstrument</a> profiling for all of the packages.
Right now, it only works on the test suites, so it's not really representative, although it does confirm that my very newest code in the punq fork takes up a huge portion of execution time.
I'm not up for much more tonight, but I will try slapping an LRU cache on the top-level function and see if that does anything.
Okay, that makes the tests up to ten times faster, which is helpful.
It's unlikely that the shiv will benefit as much, since the cache gets thrown away at the end, but this will probably be extemely helpful once I start putting together larger apps using this same code.</p>
<p>One thing I realized from putting together the Mythic stuff, and I'll have to do something about this later, is that I picked the wrong signature for prompting the user for input.
When using Tk, this is going to be, like, a modal popup with generated widgets.
Currently, the interface is "give user string, receive string from user", which can't work with that generically, unless I write a parser to parse out the string that I <em>just</em> generated, which I'm not going to do.
I'm going to need to make the interface something like "provide a <tt class="docutils literal">Question[T]</tt>, receive a <tt class="docutils literal">T</tt>", where the <tt class="docutils literal">Question</tt> type does not exist yet.
To figure out what kind of range it needs to allow, I'm going to have to review all of the systems I want to port.</p>
<p>None of that is going to happen today, because it is almost midnight now.</p>
<p>Good night.</p>
Coding 2020-11-272020-11-27T05:00:00-05:002020-11-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-27:/coding-2020-11-27<p class="first last">I'm skilled enough to answer my own questions that are such that, if I put them on StackOverflow, everyone would say "You shouldn't do that".</p>
<p>I wired in the eval logic.
It required some minor changes to the supporting types.
Basically, I needed a custom str-stype function that renders <tt class="docutils literal">Ellipsis</tt> as <tt class="docutils literal">...</tt>.</p>
<p>With that in place, and a few iterations on the updated code, I've got the new version up and running.
It's... somewhat easier to understand than the old code, I think.
It might be slower—I didn't actually measure it, since I'm more concerned about getting the code working and correct, than I am about blazing performance.
Subjectively, the Risus shiv has fine performance.</p>
<p>There are still some minor coverage holes, but I think tomorrow I'll switch back to Mythic.
My current design for (parts of) Mythic will stress the punq fork a little harder, but honestly not much so.</p>
<p>So, stuff to look into:</p>
<ul class="simple">
<li>Cleaning up my scattered prototype code for Mythic.</li>
<li>Creating a toy build setup for Brython; not sure what kind of metadata I'd need to add to get this to, like, work, from my end.</li>
<li>Setting up profiling so I know where the hot code paths are.</li>
<li>Not really relevant to this yet, but I wonder if Trio's scheduler can be used to implement causal profiling. That might come in handy when I have a lot of code hooked into GUI libraries.</li>
</ul>
<p>Anyway, it's late, so I guess I'm done.</p>
<p>Good night.</p>
Coding 2020-11-262020-11-26T05:00:00-05:002020-11-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-26:/coding-2020-11-26<p class="first last">I'm not sure metaprogramming in Python is ever chill. It's always some horrible hack or some 2kewl trick. Kind of a shame.</p>
<p>I've attempted a rewrite from AST parse-and-process stuff to a version based on doing horrible things with the <tt class="docutils literal">eval</tt> builtin.
Fortunately, if I'm understanding my own code correctly, most of the logic lives outside the code I'm replacing, which essentially acts as glue code for moving around a bunch of data types.</p>
<p>If this doesn't work out, and maybe even if it does, I think I should try to be a little more rigorous in my requirements, because the way I'm doing this now, basically creating a weird sandbox interpreter that sort of operates solely on the outermost representation of the program data, it's, um, weird and uncomfortable.</p>
<p>As per usual, I'm getting this highly complicated code put together pretty late at night, so my plan is to publish this entry, set up the code paths, run the tests, and call it a night.</p>
<p>And I'm just about ready to do that.
Wrapping up now...</p>
<p>Good night.</p>
Coding 2020-11-252020-11-25T05:00:00-05:002020-11-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-25:/coding-2020-11-25<p class="first last">Multi-yak shaving</p>
<p>It looks like Pyodide has some level of incompatibility with Trio, which will go away, or I can roll a weird messed-up shim library to paper over it, and either way, I'll see what's broken next.
I want to get Trio working under Pyodide in the event that I try to port to it, because I went all in on async, and I'm fairly sure Trio's guest mode can act as an adaptor between async and Pyodide's promises API.
The other possibility is trying to build some sort of minimal wrapper to do the translation.</p>
<p><em>Anyway</em>, what I actually did today was work on improving the punq fork coverage.
It's not fully covered, but it's much better.
I'm just now adding a test for one bit of functionality that I'm not sure it's implemented.
Once I've got that passing, I'm honestly tempted to just do the rewrite to get rid of the <tt class="docutils literal">ast</tt> module.
And the test passed.
Slightly freaky, given that I don't remember what I did to make it pass, but I'll take it.</p>
<p>Anyway, the rewrite is desirable to me because it should actually make it more obvious what's happening, because my first plan should be expressible in terms of documented runtime behavior, rather than solely in terms of syntax properties, so it should also be more stable, and more obvious if I miss something.</p>
<p>Okay, that's enough spacing out before hitting "publish".</p>
<p>Good night.</p>
Weekly Roundup 2020-11-242020-11-24T05:00:00-05:002020-11-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-24:/weekly-roundup-2020-11-24<p class="first last">Final evaluation of whatever the heck I had/still kind of have: not covid, not as bad as covid; I'm not a fan of the various things it did to my face. I only worked as hard as I did last week, because one of the effects of being sick was <em>not realizing how sick I was</em>.</p>
<ul class="simple">
<li>Wednesday: I started working on the Gilded Rose Kata and trying out Ward.</li>
<li>Thursday: I made good progress on the kata, and worked to understand Ward better.</li>
<li>Friday: I started noticing how sick I was all week, and worked on refactoring the kata code.</li>
<li>Saturday: I got tired of the kata, so I got some stuff "done enough" for it, and changed gears. I started thinking about bits of tooling I'll need for my other projects.</li>
<li>Sunday: I got shiv working with the virtual tabletop stuff, which means now I get automated building of command-line utilities. The one I have so far is about 700 kB.</li>
<li>Monday: I approached things from a few angles. I evaluated various ways I could run this code in the browser, mostly out of curiosity. I determined that Pyodide would work, but require a somewhat involved build process, and Brython should work, if I rewrite some of my code to be more portable. I thought a little bit about those changes. I also tried to make some progress porting Mythic over, and developed a plan, which I was too tired to execute on last night, and I'm too tired now.</li>
</ul>
<p>Next week, I'm going to try to clean up the Mythic code, which got really disorganized because I wasn't sure what I was doing, add test coverage to the punq fork, and then try rewriting the punq fork's type alias canonicalization code to avoid using the <tt class="docutils literal">ast</tt> module.
My plan for this is cursed, yet it should be portable.</p>
Coding 2020-11-232020-11-23T05:00:00-05:002020-11-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-23:/coding-2020-11-23<p class="first last">Developing plans to, among other things, replace horrifying metaprogramming nonsense with more portable metaprogramming nonsense.</p>
<p>Status of thinking about getting this working in the browser: my two big constraints are from my punq fork, which uses Python 3.8 syntax and the stdlib <tt class="docutils literal">ast</tt> module.
The syntax constraint narrows the choices I have, out of everything I know about, to <a class="reference external" href="https://brython.info/">Brython</a> and <a class="reference external" href="https://pyodide.readthedocs.io/en/latest/">Pyodide</a>.
(Python 3.8 eliminates for now, I think, <a class="reference external" href="https://www.transcrypt.org/">transcrypt</a>, <a class="reference external" href="https://github.com/beeware/batavia">Batavia</a>, <a class="reference external" href="http://pyjs.org/">pyjs</a>, <a class="reference external" href="https://skulpt.org/">Skulpt</a>, and <a class="reference external" href="https://pypyjs.org/">PyPy.js</a>)
Using either one would take some work from where I am now:</p>
<ul class="simple">
<li>Brython doesn't provide the <tt class="docutils literal">ast</tt> module, which the fork currently uses to parse and partially evaluate type annotations. I believe there are several ways I could attempt to work around this.</li>
<li>Because I'd be bundling several un-published packages with Pyodide, I'd need to install the wheels from a URL, which means it won't do dependency resolution, and I need to calculate the installation order at build time with some kind of topological sort.</li>
</ul>
<p>Either of these could be worth working on, but I think I'm ready to get back to Mythic for now.</p>
<p>I'll catch up on that, and later work on finally getting the coverage up, as well as patching some holes I noticed.</p>
<p>Okay, there are various difficulties with implementing the Fate roll from base Mythic.
One is the choice of focus table.
There's just one focus table in base Mythic, but Variations does a bunch of stuff, and The Adventure Crafter has a different way of handling focus tables as well.
Separating out concerns...
The different parts of a Fate roll are as follows:</p>
<ul class="simple">
<li>Determine the <tt class="docutils literal">target</tt></li>
<li>Roll d100, to produce the <tt class="docutils literal">result</tt></li>
<li>If the <tt class="docutils literal">result</tt> is divisible by 11, MAYBE produce a random event, given the focus table and chaos factor. (The choice of whether to generate one is influenced by the dominant theme, which may not be the theme whose focus table to being rolled against.) (Since I'm trying to make each package standalone to start with, this implies to me that I should drop some of the logic and classes I have currently.)</li>
<li>Given the <tt class="docutils literal">target</tt> and <tt class="docutils literal">result</tt>, produce a set of <tt class="docutils literal">outcomes</tt> accessible by spending up to 25 favor points</li>
<li>Present the <tt class="docutils literal">outcomes</tt>, and wait for input to determine if a different outcome was taken</li>
<li><em>Deduct spent favor points</em></li>
<li>The previous three bullets assume that there is an available pool of favor points. The answer to that should be consistent, or at least possible to determine ahead of time. So... write a factory that determines it, maybe? Still need to be able to line up the types, though. If I want to be a stickler, I could just have two high-level functions that package up the different flows. The question then, is what to return from the version that prompts to spend favor points.</li>
</ul>
<p>Thinking about this has made me decide that these functions should make as few decisions about the context they're used in as possible, so I should avoid making them rely on sheets.
That means the favor point version has to take a favor point count, and return a new total, along with everything else.</p>
<p>...</p>
<p>And the classes are ballooning out of control.
I'm going to try to sketch out exactly what the sequence of events is supposed to be:</p>
<ul class="simple">
<li>Determine the target number (this relies on varying factors and should be abstracted away; just expect a target)</li>
<li>Roll against the target number</li>
<li>Determine the outcome</li>
<li>Optionally apply favor points to shift the outcome</li>
<li>Use the roll result, among other inputs, to determine whether a random event occurred.</li>
</ul>
<p>I'm kind of tempted to try using punq for this, at kind of a higher level.
Just, like, pass in stuff from the broader container, as well as volatile arguments.</p>
<p>Okay, I've sketched some stuff out on paper, and I think I have a solid plan for this.
However, I'm tired, and I don't want to mess with the code any more while I'm tired.</p>
<p>Good night.</p>
Coding 2020-11-222020-11-22T05:00:00-05:002020-11-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-22:/coding-2020-11-22<p class="first last">I guess if I try to support Brython, I'll need to, like, port my mypy and test sessions to Brython. Try to figure out how to get coverage data out of a headless Selenium session where Coverage can't use the C extension, among other things...</p>
<p>I ended up deciding that devpi was too heavy-weight for me to set up currently.
I kind of wonder what it would take to spin up a temporary index that just does what I want.
(I mean, it would basically just have to take a mapping from package names to file urls, and forward all other requests to another index.)
The main imposition from doing such a thing is that there'd need to be an explicit build step which... might make things faster?</p>
<p>Anyway, I got shiv working, after some confusing stuff that was not its fault.
Here's how my noxfile looks currently:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span>
<span class="normal">102</span>
<span class="normal">103</span>
<span class="normal">104</span>
<span class="normal">105</span>
<span class="normal">106</span>
<span class="normal">107</span>
<span class="normal">108</span>
<span class="normal">109</span>
<span class="normal">110</span>
<span class="normal">111</span>
<span class="normal">112</span>
<span class="normal">113</span>
<span class="normal">114</span>
<span class="normal">115</span>
<span class="normal">116</span>
<span class="normal">117</span>
<span class="normal">118</span>
<span class="normal">119</span>
<span class="normal">120</span>
<span class="normal">121</span>
<span class="normal">122</span>
<span class="normal">123</span>
<span class="normal">124</span>
<span class="normal">125</span>
<span class="normal">126</span>
<span class="normal">127</span>
<span class="normal">128</span>
<span class="normal">129</span>
<span class="normal">130</span>
<span class="normal">131</span>
<span class="normal">132</span>
<span class="normal">133</span>
<span class="normal">134</span>
<span class="normal">135</span>
<span class="normal">136</span>
<span class="normal">137</span>
<span class="normal">138</span></pre></div></td><td class="code"><div><pre><span></span><span class="kn">import</span> <span class="nn">contextlib</span>
<span class="kn">import</span> <span class="nn">os.path</span>
<span class="kn">import</span> <span class="nn">pathlib</span>
<span class="kn">import</span> <span class="nn">tempfile</span>
<span class="kn">import</span> <span class="nn">toml</span>
<span class="kn">import</span> <span class="nn">nox</span>
<span class="n">PROJECTS</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">directory</span>
<span class="k">for</span> <span class="n">directory</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">()</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isdir</span><span class="p">(</span><span class="n">directory</span><span class="p">)</span>
<span class="ow">and</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">directory</span><span class="p">,</span> <span class="s2">"pyproject.toml"</span><span class="p">))</span>
<span class="p">]</span>
<span class="n">CONSTRAINTS</span> <span class="o">=</span> <span class="p">(</span>
<span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
<span class="p">[</span>
<span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">project</span><span class="si">}</span><span class="s2"> @ </span><span class="si">{</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">project</span><span class="p">))</span><span class="o">.</span><span class="n">as_uri</span><span class="p">()</span><span class="si">}</span><span class="s2">"</span>
<span class="k">for</span> <span class="n">project</span> <span class="ow">in</span> <span class="n">PROJECTS</span>
<span class="p">]</span>
<span class="p">)</span>
<span class="o">+</span> <span class="s2">"""</span>
<span class="s2">attrs ~=19.3</span>
<span class="s2">camel ~=0.1.2</span>
<span class="s2">click ~=7.1.2</span>
<span class="s2"># punq ~=0.4.1</span>
<span class="s2"># trio"""</span>
<span class="p">)</span>
<span class="nd">@contextlib</span><span class="o">.</span><span class="n">contextmanager</span>
<span class="k">def</span> <span class="nf">constraints_env</span><span class="p">():</span>
<span class="k">with</span> <span class="n">tempfile</span><span class="o">.</span><span class="n">TemporaryDirectory</span><span class="p">()</span> <span class="k">as</span> <span class="n">tmpdir</span><span class="p">:</span>
<span class="n">constraints</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">tmpdir</span><span class="p">,</span> <span class="s2">"constraints.txt"</span><span class="p">)</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">constraints</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s2">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">fh</span><span class="p">:</span>
<span class="n">fh</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">CONSTRAINTS</span><span class="p">)</span>
<span class="k">yield</span> <span class="p">{</span><span class="s2">"PIP_CONSTRAINT"</span><span class="p">:</span> <span class="n">constraints</span><span class="p">,</span> <span class="s2">"PIP_NO_CACHE_DIR"</span><span class="p">:</span> <span class="s2">"YES"</span><span class="p">}</span>
<span class="k">def</span> <span class="nf">install_from_repo</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="o">*</span><span class="n">projects</span><span class="p">):</span>
<span class="k">with</span> <span class="n">constraints_env</span><span class="p">()</span> <span class="k">as</span> <span class="n">env</span><span class="p">:</span>
<span class="n">session</span><span class="o">.</span><span class="n">install</span><span class="p">(</span><span class="o">*</span><span class="n">projects</span><span class="p">,</span> <span class="n">env</span><span class="o">=</span><span class="n">env</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">install_from_requirements</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span>
<span class="n">session</span><span class="o">.</span><span class="n">install</span><span class="p">(</span><span class="s2">"-r"</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"requirements/</span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="s2">.txt"</span><span class="p">)</span>
<span class="nd">@nox</span><span class="o">.</span><span class="n">session</span>
<span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="n">session</span><span class="p">):</span>
<span class="n">install_from_requirements</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="s2">"coverage"</span><span class="p">)</span>
<span class="n">session</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="s2">"coverage"</span><span class="p">,</span> <span class="s2">"erase"</span><span class="p">)</span>
<span class="nd">@nox</span><span class="o">.</span><span class="n">session</span>
<span class="nd">@nox</span><span class="o">.</span><span class="n">parametrize</span><span class="p">(</span><span class="s2">"project"</span><span class="p">,</span> <span class="n">PROJECTS</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">check</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">project</span><span class="p">):</span>
<span class="n">install_from_requirements</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="s2">"check"</span><span class="p">)</span>
<span class="n">session</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
<span class="s2">"isort"</span><span class="p">,</span> <span class="s2">"--check-only"</span><span class="p">,</span> <span class="s2">"--diff"</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">project</span><span class="si">}</span><span class="s2">/src"</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">project</span><span class="si">}</span><span class="s2">/tests"</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">session</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="s2">"flake8"</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">project</span><span class="si">}</span><span class="s2">/src"</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">project</span><span class="si">}</span><span class="s2">/tests"</span><span class="p">)</span>
<span class="nd">@nox</span><span class="o">.</span><span class="n">session</span>
<span class="nd">@nox</span><span class="o">.</span><span class="n">parametrize</span><span class="p">(</span><span class="s2">"project"</span><span class="p">,</span> <span class="n">PROJECTS</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">mypy</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">project</span><span class="p">):</span>
<span class="n">install_from_repo</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">project</span><span class="p">)</span>
<span class="n">install_from_requirements</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="s2">"mypy"</span><span class="p">)</span>
<span class="n">session</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="s2">"mypy"</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">project</span><span class="si">}</span><span class="s2">/src"</span><span class="p">,</span> <span class="n">env</span><span class="o">=</span><span class="p">{</span><span class="s2">"MYPYPATH"</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="s2">"stubs"</span><span class="p">)})</span>
<span class="nd">@nox</span><span class="o">.</span><span class="n">session</span>
<span class="nd">@nox</span><span class="o">.</span><span class="n">parametrize</span><span class="p">(</span><span class="s2">"project"</span><span class="p">,</span> <span class="n">PROJECTS</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">nocov</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">project</span><span class="p">):</span>
<span class="n">install_from_repo</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">project</span><span class="p">)</span>
<span class="n">install_from_requirements</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="s2">"pytest"</span><span class="p">)</span>
<span class="n">session</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
<span class="s2">"python"</span><span class="p">,</span> <span class="s2">"-m"</span><span class="p">,</span> <span class="s2">"pytest"</span><span class="p">,</span> <span class="n">project</span><span class="p">,</span> <span class="n">env</span><span class="o">=</span><span class="p">{</span><span class="s2">"PYTHONPATH"</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">project</span><span class="p">)}</span>
<span class="p">)</span>
<span class="nd">@nox</span><span class="o">.</span><span class="n">session</span>
<span class="nd">@nox</span><span class="o">.</span><span class="n">parametrize</span><span class="p">(</span><span class="s2">"project"</span><span class="p">,</span> <span class="n">PROJECTS</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">cover</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">project</span><span class="p">):</span>
<span class="n">install_from_repo</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">project</span><span class="p">)</span>
<span class="n">install_from_requirements</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="s2">"cover"</span><span class="p">)</span>
<span class="n">session</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
<span class="s2">"coverage"</span><span class="p">,</span>
<span class="s2">"run"</span><span class="p">,</span>
<span class="s2">"-m"</span><span class="p">,</span>
<span class="s2">"pytest"</span><span class="p">,</span>
<span class="n">project</span><span class="p">,</span>
<span class="n">env</span><span class="o">=</span><span class="p">{</span><span class="s2">"PYTHONPATH"</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">project</span><span class="p">)},</span>
<span class="p">)</span>
<span class="nd">@nox</span><span class="o">.</span><span class="n">session</span>
<span class="k">def</span> <span class="nf">report</span><span class="p">(</span><span class="n">session</span><span class="p">):</span>
<span class="n">install_from_requirements</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="s2">"report"</span><span class="p">)</span>
<span class="n">session</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="s2">"coverage"</span><span class="p">,</span> <span class="s2">"combine"</span><span class="p">)</span>
<span class="c1"># Disable while the punq fork is the main focus of development.</span>
<span class="c1"># session.run("limit-coverage")</span>
<span class="n">session</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="s2">"coverage"</span><span class="p">,</span> <span class="s2">"html"</span><span class="p">,</span> <span class="s2">"--show-contexts"</span><span class="p">)</span>
<span class="n">session</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
<span class="s2">"coverage"</span><span class="p">,</span> <span class="s2">"report"</span><span class="p">,</span> <span class="s2">"--skip-covered"</span><span class="p">,</span> <span class="s2">"-m"</span><span class="p">,</span> <span class="s2">"--fail-under=100"</span><span class="p">,</span>
<span class="p">)</span>
<span class="nd">@nox</span><span class="o">.</span><span class="n">session</span>
<span class="k">def</span> <span class="nf">shiv</span><span class="p">(</span><span class="n">session</span><span class="p">):</span>
<span class="n">install_from_requirements</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="s2">"shiv"</span><span class="p">)</span>
<span class="n">shiv_build</span> <span class="o">=</span> <span class="s2">"build/shiv"</span>
<span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">shiv_build</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">artifacts</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">project</span> <span class="ow">in</span> <span class="n">PROJECTS</span><span class="p">:</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">project</span><span class="p">,</span> <span class="s2">"pyproject.toml"</span><span class="p">))</span> <span class="k">as</span> <span class="n">toml_data</span><span class="p">:</span>
<span class="k">for</span> <span class="n">script</span><span class="p">,</span> <span class="n">endpoint</span> <span class="ow">in</span> <span class="p">(</span>
<span class="n">toml</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">toml_data</span><span class="p">)</span>
<span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"tool"</span><span class="p">,</span> <span class="p">{})</span>
<span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"flit"</span><span class="p">,</span> <span class="p">{})</span>
<span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"scripts"</span><span class="p">,</span> <span class="p">{})</span>
<span class="o">.</span><span class="n">items</span><span class="p">()</span>
<span class="p">):</span>
<span class="n">artifacts</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">project</span><span class="p">,</span> <span class="n">script</span><span class="p">,</span> <span class="n">endpoint</span><span class="p">))</span>
<span class="k">with</span> <span class="n">constraints_env</span><span class="p">()</span> <span class="k">as</span> <span class="n">env</span><span class="p">:</span>
<span class="k">for</span> <span class="n">project</span><span class="p">,</span> <span class="n">script</span><span class="p">,</span> <span class="n">endpoint</span> <span class="ow">in</span> <span class="n">artifacts</span><span class="p">:</span>
<span class="n">session</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
<span class="s2">"shiv"</span><span class="p">,</span>
<span class="s2">"-e"</span><span class="p">,</span>
<span class="n">endpoint</span><span class="p">,</span>
<span class="s2">"-o"</span><span class="p">,</span>
<span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">shiv_build</span><span class="p">,</span> <span class="n">script</span><span class="p">),</span>
<span class="n">project</span><span class="p">,</span>
<span class="n">env</span><span class="o">=</span><span class="n">env</span><span class="p">,</span>
<span class="p">)</span>
</pre></div></td></tr></table></div>
<p>First, it detects all PEP 517 projects one level down, and uses them to generate constraint files.
I also added the only lines that I consider project-specific, to make sure that the various third-party packages are constrained consistently.
punq is commented out because my fork is one of the subprojects, and trio is commented out because I haven't tried to constrain it yet.</p>
<p>Next up, helpers for actually using the constraints files.
The context manager puts the constraint data somewhere pip can see it, and creates environment variables to make pip, and nested pips, act properly.
I think this is because I'm not bothering to bump versions, but everything breaks if I let pip use a cache directory.
Anyway, the context manager was spun out from the following function, which handles installing one of the subprojects.
It was spun out so it could be used with shiv, because shiv uses pip under the covers.</p>
<p>The next helper installs the requirements for a particular session, which are stored in the <tt class="docutils literal">requirements</tt> directory, and are built up by including each other as needed.</p>
<p>Getting to the sessions, we've got <tt class="docutils literal">clean</tt>, which makes sure that coverage data doesn't leak between runs, and would do other cleanup if it were needed.
The <tt class="docutils literal">check</tt> session does basic linting against the codebases, that does not require installation.
I could maybe turn that into a for-loop and remove the parametrization.
The <tt class="docutils literal">mypy</tt> session typechecks each project in isolation, with the help of some stubfiles I had to write for some of the dependencies.
The <tt class="docutils literal">nocov</tt> and <tt class="docutils literal">cover</tt> sessions run pytest against each project, with the invocations as similar as possible, except that <tt class="docutils literal">cover</tt> runs under coverage.
The environment manipulation is required to get punq's doctests to pass when invoking pytest from another directory; I don't know if the way they're being invoked and supported is idiomatic, because I don't use doctests much.
The <tt class="docutils literal">report</tt> session is not quite how I usually like it, because the <tt class="docutils literal"><span class="pre">limit-coverage</span></tt> command has extremely specific expectations about test layout that are intuitive to me, and I don't know about anyone else.
Point is, unless I rearrange all of punq's tests (which I might as well do, at some point), running <tt class="docutils literal"><span class="pre">limit-coverage</span></tt> would make it impossible to get sensible data, so I'm not going to run it.
Anyway, it generates a nice HTML report and yells at me if I have uncovered statements, which is reasonable, in my experience.</p>
<p>Lastly, the new session, <tt class="docutils literal">shiv</tt>, scrapes all of my pyproject files for script declarations, and converts them into shiv commands.
Thinking over what it does, I'm actually going to rewrite it a little, but it's nothing too significant.
The code is a little rough and kind of suggests some refactorings, but I don't think they'd be well-motivated yet, so I'm going to hold off.
The directory structure for the build artifacts is a little nested, because I want to leave my options open for creating other kinds of artifacts.</p>
<p>(By the way, <em>apropos of nothing</em>, I wonder what the etiquette is for something like... a PR that I haven't looked at in over a year, because I stopped using the project it's against...)</p>
<p>Anyway, that file is more-or-less how I like to handle automated tasks related to Python development these days.</p>
<p>It's late now, so I should wind down.</p>
<p>Good night.</p>
Coding 2020-11-212020-11-21T05:00:00-05:002020-11-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-21:/coding-2020-11-21<p class="first last">"Is this sufficiently done? 'Yes.'"</p>
<p>I ended up not having the patience to write out all of the end-to-end cases that the requirements changes in the Gilded Rose kata... require, so I just wrote tests for the basic case, and assumed it should compose as expected with all of the other cases.
I'm going to say this is "learning to finish", and get on with my life.</p>
<p>Anyway, I've been investigating the upcoming changes to pip and how they will, at least temporarily, potentially break my workflow, and the more I've thought about it, the more I think it would make more sense to implement my desired workflow as a policy against a local PyPI mirror.
This sidesteps the question of "how should pip interpret URL constraints", by taking the question more-or-less out of pip's hands.
Looks like I'd like to try <a class="reference external" href="https://docs.devpi.net/">devpi</a> for that.</p>
<p>The other thing that thinking about that made me realize is, I don't have a plan for getting the libraries I'm writing into a usable state for me, like having an executable.
For that, I'd either need to maintain a cache and a venv and make sure the venv pip always points to the cache, or... I could try out something like <a class="reference external" href="https://shiv.readthedocs.io/en/latest/">shiv</a>, and make the executables be explicit artifacts that get built.
In a similar vein, I'm kind of curious what happens if I try shoving some of these into something like <a class="reference external" href="https://brython.info/">Brython</a>.
I'm... not sure if Brython is compatible with trio's guest mode, but if I make sure the business logic doesn't refer to specific async libraries, and move that out to whatever executes them, I should be okay.
If I go this route, I'll want to break up my modules <em>even more</em>, so I end up with, like, risus, and risus-cli, and I can hopefully be confident that I'm not mixing event loops in an unprincipled fashion.</p>
<p>So, there's a plan for the future:</p>
<ul class="simple">
<li>devpi</li>
<li>shiv</li>
<li><em>maybe</em> Brython</li>
</ul>
<p>I'm trying to get a jump on understanding how best to configure devpi; it looks like I might want to try using <a class="reference external" href="https://pypi.org/project/devpi-constrained/">devpi-constrained</a> to have an intermediate index that filters out all of the packages I'm installing myself.
Maybe.
I'll figure this out later.
For now, I'll wind down.</p>
<p>Good night.</p>
Coding 2020-11-202020-11-20T05:00:00-05:002020-11-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-20:/coding-2020-11-20<p class="first last">Current solution is somewhat lacking in elegance, but at least it's clear what's going on.</p>
<p>I spent a big chunk of today trying to recover from whatever is going on with me, so I didn't have much time to work on the kata.
I did have time to change some of the callbacks I added, so they're now callable objects.
The plan there is to try to convert some of the extant conditionals/switches into operations I can call on the callbacks, so I can move some of the business logic back into the core function, rather than having opaque "do the thing" top-level functions.</p>
<p>Okay, I did that, and now the groundwork is mostly laid to add processing for conjured items.
But doing that means adding tests, and it's too late at night for me to be up for that.
I'll work on updating the tables and the tests tomorrow or over the weekend.</p>
<p>Good night.</p>
Coding 2020-11-192020-11-19T05:00:00-05:002020-11-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-19:/coding-2020-11-19<p class="first last">Nothing went wrong, so I didn't have much to write about.</p>
<p>I wrote up some simple decision tables for the kata, and used them to write a thorough set of tests.
From there, I was able to rewrite the kata code with a much flatter control flow.
Passed all tests once the types lined up properly.</p>
<p>It's late now, so I'll work on the next part tomorrow.</p>
<p>Ward was mostly easy to use, although I initially expected parameterization to work a little more like in pytest, which it doesn't quite.
Basically, Ward's parameters cannot vary independently.
This required me to split up some tests a little more thoroughly, which is probably fine.</p>
<p>I guess I don't have much to say, since putting together the tables then translating them to tests was pretty straightforward and quick.
No real complaints; I'd definitely recommend at least trying it for any given project.</p>
<p>Good night.</p>
Coding 2020-11-182020-11-18T05:00:00-05:002020-11-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-18:/coding-2020-11-18<p class="first last">I'm sure the documentation said I could do this, but I'm going to trust the deprecation warning more...</p>
<p>I'm going to try to keep this brief because I'm not in the best of shape right now.
To take a break from the punq stuff, I'm going to try using some somewhat new tools with a small challenge I haven't tried before.</p>
<p>All of this is inspired by <a class="reference external" href="https://twitter.com/mengwong/status/1328334995623006210">this twitter thread</a>.
The quick summary of the thread is that people aren't using <a class="reference external" href="https://www.hillelwayne.com/decision-tables/">decision</a> <a class="reference external" href="https://www.hillelwayne.com/post/decision-table-patterns/">tables</a> with the <a class="reference external" href="https://github.com/emilybache/GildedRose-Refactoring-Kata">Gilded Rose kata</a>, and they should be.
I've used decision tables some in the past.
Though I didn't use them on the punq fork, I imagine they wouldn't have gone amiss there.</p>
<p>The other thing I want to look into is using <a class="reference external" href="https://wardpy.com/">Ward</a> instead of <a class="reference external" href="https://pytest.org/">pytest</a>.
I heard of Ward recently, and given how little I mess with pytest's configuration in my hobby projects, I'm not feeling particularly tethered to pytest, so I'm curious what it's like currently.
The only thing I might need to do is name things somewhat un-idiomatically by Ward standards, to get <a class="reference external" href="https://coverage.readthedocs.io/">Coverage.py</a> to assign contexts properly.
(Although, that's not necessary for the kata, since it only has one source file.)</p>
<p>Anyway, my plan is to copy over things from the virtual tabletop repo, since that has the most recent version of my project scaffolding, copy in the Gilded Rose stuff, make sure I've got everything working with pytest, then switch it to Ward.
After that, I'll work on documenting the current behavior with decision tables, translate the results into tests.
Refactor the code to be less of a tangle of if statements.
Then, extend the decision tables in accordance with the kata, and add the new tests required by the new rows.</p>
<p>Let's see how far I can get with all that for now.</p>
<p>Some time later, I'm nearly at the end of the first sentence.</p>
<p>Ten minutes more and I am at the end.</p>
<p>I'll get to work on the decision tables tomorrow.</p>
<p>Stuff I learned from trying this:</p>
<ul class="simple">
<li>I missed the boat to comment on <a class="reference external" href="https://github.com/pypa/pip/issues/8210">pip#8210</a>. That issue seems to mean I need to adapt my current workarounds to the new resolver, because they won't work. I'm looking into the related issues now.</li>
<li>Coverage.py's dynamic contexts don't play well with Ward. I believe the problem is on the coverage side, and fixing it probably requires setting some configuration options that may or may not exist yet.</li>
</ul>
<p>Then I spaced out for about half an hour trying to figure out which pip issue fits my use case.
So, I guess I'm done for now.</p>
<p>Good night.</p>
Weekly Roundup 2020-11-172020-11-17T05:00:00-05:002020-11-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-17:/weekly-roundup-2020-11-17<p class="first last">I made good progress, but it stopped <em>feeling</em> good.</p>
<ul class="simple">
<li>Wednesday: I planned a bunch of changes to my punq fork.</li>
<li>Thursday: I realized that "evaluate type aliases only up to the name of the alias" is actually a pretty involved ask.</li>
<li>Friday: I fixed the majority of test failures that came from the previous changes, and realized that what I'm doing is probably not going to get merged back.</li>
<li>Saturday: I wrote some extremely questionable-looking code to handle an edge case that only arose in doctests. (The code would later be removed, along with the features it supported.)</li>
<li>Sunday: I understood punq's original implementation better, and tried to "fix" aspects of it.</li>
<li>Monday: Looking over my attempted fixes, I decided instead to remove a bunch of features that I haven't used yet, and don't expect to.</li>
</ul>
<p>Next week, I'm going to try to change pace somehow.
Something to get me out of the current cycle I feel like I'm in.
I've got some ideas, but I don't want to commit to anything.
If I can muster the will to get back to coding game rule logic, that's fine, but I don't know if I can, yet.</p>
Coding 2020-11-162020-11-16T05:00:00-05:002020-11-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-16:/coding-2020-11-16<p class="first last">Ditributing the fork later like, "What does it have going for it?" "Less features!"</p>
<p>I made the judgment call that, since my punq fork is purely for my own stuff currently, I'm removing the functionality I don't use.
This got rid of some of the weird hacky stuff I put in, but it didn't change much.
The existing code just seems a lot leaner than the stuff I added, I guess.</p>
<p>Anyway, making another judgment call: I've been spinning my wheels on this a bit, so next week, I'm going to find something else to work on for a bit.</p>
<p>I don't know what, and I'm feeling a little under the weather right now, so I'm not going to try too hard.</p>
<p>Good night.</p>
Coding 2020-11-152020-11-15T05:00:00-05:002020-11-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-15:/coding-2020-11-15<p class="first last">Tinkering on this codebase like it's a project car.</p>
<p>Today, I improved my coverage metrics by deciding that some of the code I added didn't make sense, so I deleted a bunch of it.</p>
<p>Looking for other low-hanging fruit, I noticed some code I added that should have been running, but wasn't, because I didn't update the rest of the code to properly invoke it.
That improved things a little further.
Now I'm just missing "what about subclasses that don't define an <tt class="docutils literal">__init__</tt>, but a superclass does?", and various invocations of annotations and alias helpers.
I should just put aside some time to work through those, but I don't feel like it right now.</p>
<p>My longer-term plans, once this has full coverage:</p>
<ul class="simple">
<li>Make sure that these changes I made to punq <em>actually enable</em> the use cases that motivated the fundamental changes here in the first place. The place to look for this is in the Risus CLI functions.</li>
<li>Remember what I was planning to do with Mythic. I <em>think</em> my intention was to make the sheet a resolution-time argument, which I now realize I didn't need to make all these changes to enable, but I only realize that because of what I learned making the changes, so I guess it <em>sort of</em> works out.</li>
<li>Get this into a state where I can make it a proper fork, since I really don't think it'd make sense to merge up all of the changes I've made, but I'm willing to offer up some of them. Especially since some of the more drastic ones turned out to be unnecessary.</li>
<li>Actually understand some of the core logic that I barely touched. I mean, clearly I didn't break it for simple cases, but for more complicated stuff...</li>
</ul>
<p>Actually, looking over some of that code, I'm kind of skeptical of bits of it, and I'm going to try changing more of the base logic and see what happens.
Eh, need more planning.
And it's not hurting anything, currently.
I'm thinking that the cache value format for ResolutionContexts should be changed so it has fields like <tt class="docutils literal">first: T; rest: Optional[Tuple[T, <span class="pre">...]]</span></tt>.
That's a tomorrow question, though.</p>
<p>Good night.</p>
Coding 2020-11-142020-11-14T05:00:00-05:002020-11-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-14:/coding-2020-11-14<p class="first last">Here's one for the books everyone: I used a regular expression and ended up with less problems.</p>
<p>After much agonizing over the way to make my new code work with doctests, I got something together that works for the existing tests without compromising normal functionality.
It's... only a little cursed.</p>
<div class="highlight"><pre><span></span><span class="n">DESTRUCTURE_ALIAS</span> <span class="o">=</span> <span class="sa">r</span><span class="s2">"^([^[]*)(\[.*\])?$"</span>
<span class="n">LIST_ALIASES</span> <span class="o">=</span> <span class="nb">frozenset</span><span class="p">([</span><span class="n">canonical_alias</span><span class="p">(</span><span class="nb">list</span><span class="p">),</span> <span class="n">canonical_alias</span><span class="p">(</span><span class="n">List</span><span class="p">)])</span>
<span class="k">def</span> <span class="nf">get_all</span><span class="p">(</span><span class="n">alias</span><span class="p">:</span> <span class="n">Alias</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
<span class="n">match</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">DESTRUCTURE_ALIAS</span><span class="p">,</span> <span class="n">alias</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">match</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">if</span> <span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">LIST_ALIASES</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">return</span> <span class="kc">True</span>
</pre></div>
<p><em>It's fine.</em></p>
<p>Basically... doctests don't create bindings at module scope, so I had to avoid the code paths that queried for classes defined in the doctest, because those are <em>local</em> variables, I think.
To figure out what I'm good to do, I had to define the <tt class="docutils literal">Alias</tt> newtype to track whether a string was a canonical alias.
While it's safe to call <tt class="docutils literal">canonical_alias</tt> repeatedly on normal aliases, it really expects to get references to module globals, and so barfs on these kinds of edge cases.</p>
<p>Anyway, with this, and some minor test fixes, I'm back to all tests passing, and can now focus on patching up the coverage holes introduced by my additions.
My new code takes the coverage from 100% to 87%, and I know the error handling in the new sections is shaky at best, except where it was covered by existing tests.</p>
<p>While implementing the ideas that I came up with was... an ordeal, it was nice to be rewriting code primarily to change the functionality, rather than because I didn't like the design.
It was also nice to have tests that worked right off the bat.</p>
<p>Anyway, better wrap up for now.</p>
<p>Good night.</p>
Coding 2020-11-132020-11-13T05:00:00-05:002020-11-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-13:/coding-2020-11-13<p class="first last">Haha whoops I forgot the summary at first. Um... it's going well, but not easily.</p>
<p>I've got the failures down to just a few in punq's suite, which, I did rework nearly everything, so, fair.</p>
<p>Where I'm at now in addressing these is, I now understand the arguments to the <tt class="docutils literal">resolve</tt> function better, and now I realize I was accidentally changing the semantics.
I'm trying reverting my changes and seeing if the result just works.
It actually seems plausible.
And, it looks like it's working.
Just some minor tweaks after I finish testing, and then I can move on to fixing other stuff.</p>
<p>Anyway, getting punq to do what I want was far harder and less pleasant than anyone could have politely predicted, and it's not quite done.
Current problem: I <em>somehow</em> broke the logic that I didn't understand in the first place, what a shock.
It's passing too many arguments under some circumstances, so I've got to figure out why it's doing that and how to make it stop.</p>
<p>Tomorrow.
I'll do that tomorrow.</p>
<p>Anyway, I've sort of alluded to the potential of porting my changes back to the official version of punq, and that now seems very unlikely to me.
My fork is <em>a</em> future of punq, in that it was directly developed from it, but I highly doubt it's <em>the</em> future, due to the sheer scale of the breaking changes to it, and my introduction of syntax from Python 3.8.
When it's ready for public consumption, which it definitely isn't currently, I'll have to discuss and think about it some more, to figure out what I want to do.</p>
<p>Anyway, I let this entry go too late for everything I want to get done, so I should wrap up.</p>
<p>Good night.</p>
Coding 2020-11-122020-11-12T05:00:00-05:002020-11-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-12:/coding-2020-11-12<p class="first last">It's just a couple hundred lines of new code. It's probably fine.</p>
<p>It turns out I didn't give "convert the annotations to a canonical form while preserving aliases" enough credit for how fiddly it seems like it's going to be.</p>
<p>Let's see.
A top-level alias might be a Subscript, which can contain Tuples, Lists, Ellipsis/Constant, and must eventually bottom out in a top-level alias which must be interpreted in the context of the uppermost alias...
The fundamental constituents are Names and Attributes.</p>
<p>After some effort, I put together several node visitor classes in a somewhat questionable fashion.
There is obvious room for improvement, but first I need to make sure it works.
And for that, I think I should take a break and get some sleep first.</p>
<p>Although, actually, thinking about this, I noticed some big misses, so I guess it's not ready yet.
...
Just bashed something together for it.</p>
<p>Okay, I'm too curious, I have to know how this breaks.</p>
<p>... Oh wow, that's brutal.
Thousands of failures.
I can't even read the full output.</p>
<p>And it looks like some of them are down to the fact that I haven't used, or written, the helper functions I knew I'd need.</p>
<p>So, I scribbled out some helpers, and now I'd like to put this aside for now and work on some other things for a bit.</p>
<p>Good night.</p>
Coding 2020-11-112020-11-11T05:00:00-05:002020-11-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-11:/coding-2020-11-11<p class="first last">Trying to plan ahead rather than work stuff out in my head and change it on the fly. Baby steps.</p>
<p>I've got some major changes that I want to make in my punq fork, and I decided I want to write them out here as a dry run before doing them.
That way there's a chance I'll notice if I get in over my head.</p>
<ul class="simple">
<li>For aesthetic reasons, I want to try replacing the <tt class="docutils literal">instance</tt> keyword argument with an <tt class="docutils literal">Instance</tt> or <tt class="docutils literal">Singleton</tt> class that acts as an argument to the <tt class="docutils literal">factory</tt> keyword, but with special-casing. This represents a breaking change, but there are plenty more where that came from, so it's fine-ish.</li>
<li>The <tt class="docutils literal">builder</tt> type annotation is too restrictive.</li>
<li>I don't know <em>what's</em> going on with <tt class="docutils literal">args</tt>. I'll have to come back to that, though a cursory look makes it look like it should be a <tt class="docutils literal">Dict[str, Any]</tt>.</li>
<li><tt class="docutils literal">_registrations</tt> should be a <tt class="docutils literal">DefaultDict[str, List[Registration]]</tt>, and <tt class="docutils literal">_localns</tt> should be gone. (Maybe it should be with <tt class="docutils literal">Tuple[Registration, <span class="pre">...]</span></tt>)</li>
<li>As should the specific implementation of <tt class="docutils literal">_get_needs_for_ctor</tt>. Instead, it should crawl the mro for a class that defines <tt class="docutils literal">__init__</tt> in its <tt class="docutils literal">__dict__</tt>, then look up that class's <tt class="docutils literal">__module__</tt> in <tt class="docutils literal">sys.modules</tt>, and from there get the global module scope. Then, it should call <tt class="docutils literal">get_type_hints(init, module_globals)</tt>, and probably pop <tt class="docutils literal">"return"</tt> from the result. No error wrapping.</li>
<li>Various parts of the library will have to perform type-to-string conversion, and that should be pushed to as high a level as possible.</li>
<li>I don't know if I want to change it, but I'm not sure I understand why concrete impls can't be registered with keyword arguments. My inclination is to get as much code as possible shared between the various paths.</li>
<li><tt class="docutils literal">build_context</tt> looks fine, though the usage of explicit <tt class="docutils literal">__getitem__</tt> confuses me.</li>
<li><tt class="docutils literal">_update_localns</tt> is gone.</li>
<li>The signature of <tt class="docutils literal">Registry.register</tt> should end up something like <tt class="docutils literal">service: Union[str, type], factory: Optional[Callable], scope: Scope, /, **kwargs: Any</tt>. This allows passing any kwargs, and requires an explicit factory to be provided when setting the scope. This is a (minor, I think) expressiveness hit in terms of what's required to register a concrete impl as a singleton, but I think the tradeoff is worth it. If it turns out problematic, my first attempt will be to change things <em>more</em>, by replacing the <tt class="docutils literal">scope</tt> argument with more wrapper classes.</li>
<li><tt class="docutils literal">ResolutionTarget</tt> looks okay with <tt class="docutils literal">str</tt> and <tt class="docutils literal">List[Registration]</tt>, but the <tt class="docutils literal">generic_parameter</tt> property freaks me out a little. It does, however, show that one thing that should be done when interpreting annotations and resolve arguments is, if the top node is an index operation, and the lhs is <tt class="docutils literal">typing.List</tt>, in some way or other, then the argument should be all attribute access, and that's what gets resolved.</li>
<li>I think <tt class="docutils literal">ResolutionContext</tt> is about fine, I'll figure out the annotations later.</li>
<li><tt class="docutils literal">Container</tt> is probably the most relevant part, but most of it follows from the previous notes.</li>
</ul>
<p>I'll write up the supporting functions on paper later.
I think I basically have everything I need, between today and yesterday.</p>
<p>I want to wind down now.</p>
<p>Good night.</p>
Weekly Roundup 2020-11-102020-11-10T05:00:00-05:002020-11-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-10:/weekly-roundup-2020-11-10<p class="first last">I think it's possible to define aliases in more complicated contexts, but I don't really want to handle the cases that come to mind.</p>
<ul class="simple">
<li>Wednesday: I was mildly freaked out about the election. I also talked about the Fate Roll.</li>
<li>Thursday: I wasn't up for much, so I rewrote the code and disabled a bunch of tests.</li>
<li>Friday: I explained the changes, and decided they were a net positive.</li>
<li>Saturday: I made an update suggested by my previous changes.</li>
<li>Sunday: I fixed up the tests I disabled.</li>
<li>Monday: I decided to revisit my effort ten and a half months ago, to update or fork or do <em>something</em> to punq.</li>
</ul>
<p>Next week, I'm going to have to figure out how best to continue with the punq fork I'm developing.
Adding typing to the current state of it is... not happening.
I guess I should be working on tests, or maybe just...
I don't need to keep using limit-coverage for now.
So, let's comment that out of the noxfile and see what kind of raw coverage numbers we get...
All right, I can confirm that, in spite of what punq's coverage badge says, it gets full coverage.</p>
<p>All right, remembering one of the directions I wanted to go all that time ago, I kind of wanted to make it canonicalize on string representations of types, but being aware of aliases.</p>
<p>Let me see if I remember the logic.</p>
<p>From the annotation side, given a string annotation in the context of a module, I want to <em>assume</em> that the name before the final dot evaluates to a module, and that module contains the remainder of the name, and that if the <tt class="docutils literal">__name__</tt> attribute of the class matches the name, then the canonical name is the <tt class="docutils literal">__qualname__</tt> of the class, and that otherwise, the canonical name is the <tt class="docutils literal">__name__</tt> of the module and the original RHS.</p>
<p>From the registration side, passing a class is shorthand for passing its <tt class="docutils literal">__qualname__</tt> (and probably similarly for resolution).
I want to avoid going too far with stack introspection, so I'll probably just want a helper function that basically takes <tt class="docutils literal">(module, alias)</tt> to <tt class="docutils literal"><span class="pre">f"{module.__name__}.{alias}"</span></tt> and is more compact.</p>
<p>I think I can work from here.
I've got a few more ideas that are a bit less fleshed out, but also less fundamental, so I'm okay leaving them sketchy for now.</p>
<p>Quick notes for my future self:</p>
<ul class="simple">
<li>Rely on the <tt class="docutils literal">ast</tt> module to figure out where to look for the module path.</li>
<li>I'm not sure how to handle subscripts, but I'm pretty sure the overall stuff that I can conceivably care about matching is like <tt class="docutils literal">(<module <span class="pre">name>\.)*<class</span> <span class="pre">name>(\[<args>])?</span></tt>. In other words, if it's an index, then <em>probably</em> discard the subscript, expect either a bare identifier, or an attribute access, in which the right hand side is a bare identifier, and the left-hand side is evaluated in the context of the current module to change the current module for the purposes of evaluating and analyzing the right-hand side.</li>
<li>Allow some minor "inconsistencies" in the interpretation of the "just the class" registration shortcut.</li>
<li>Walk the mro to figure out which module to resolve the <tt class="docutils literal">__init__</tt> annotations from the context of. First class in the mro where the <tt class="docutils literal">__init__</tt> shows up in the <tt class="docutils literal">__dict__</tt> is the place to look for the context.</li>
</ul>
<p>Okay, that's enough poking at the code and design.
Done for now.</p>
Coding 2020-11-092020-11-09T05:00:00-05:002020-11-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-09:/coding-2020-11-09<p class="first last">Excited to see the potential of "just vendor whatever, it's all namespaced".</p>
<p>I forget exactly what I did today.
I think it was some coverage improvements and fixes, as well as the minor changes I was talking about yesterday.</p>
<p>Still pondering the way to handle the roll stuff for Mythic.
What I'm leaning towards is, a given roll needs to be in the context of a particular player/sheet.
It also needs associated global information.
So, if there's a way to inject a SheetProxy...</p>
<p>Ugh, dammit.
If I try to do this in the way that I think of as simple and obvious, I'm going to run into a limitation in <a class="reference external" href="https://punq.readthedocs.io/en/latest/">punq</a> that confused me so hard when I first ran into it.</p>
<p>Here's the deal:</p>
<p>punq is a library for performing dependency injection, and it can be used to <a class="reference external" href="https://sobolevn.me/2019/03/enforcing-srp">make functions have flexible behavior without cluttering their interfaces</a>.
Basically, by inspecting the annotations associated with a callable object, it figures out which other callables it needs to use to get the required arguments.
It also has the ability to specify associated values at resolution time, but such values are passed as keyword arguments, so they effectively must be string keys.
There are facilities for translating between string and type in some direction or other, but I do not trust them.
I try to avoid them, but to some extent, it's not possible.
This is because using string and type annotations that are equivalent from a typing analysis perspective leads to <em>different behavior</em> when punq analyzes them.</p>
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">attr</span>
<span class="kn">import</span> <span class="nn">punq</span>
<span class="k">class</span> <span class="nc">Target</span><span class="p">:</span>
<span class="k">pass</span>
<span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span>
<span class="k">class</span> <span class="nc">WithType</span><span class="p">:</span>
<span class="n">field</span><span class="p">:</span> <span class="n">Target</span>
<span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span>
<span class="k">class</span> <span class="nc">WithStr</span><span class="p">:</span>
<span class="n">field</span><span class="p">:</span> <span class="s2">"Target"</span>
<span class="n">punq</span><span class="o">.</span><span class="n">Container</span><span class="p">()</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">WithType</span><span class="p">)</span> <span class="c1"># Works</span>
<span class="n">punq</span><span class="o">.</span><span class="n">Container</span><span class="p">()</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">WithStr</span><span class="p">)</span> <span class="c1"># Raises exception from within punq</span>
</pre></div>
<p>It seems to me like "define a string type annotation that gets filled in at runtime" would be a really useful pattern, but I'm not sure how to, like, do it.</p>
<p>Unless... I've got an attempt at a fork that rectifies some of my complaints with punq.
I can just take that, and any changes to punq since, and make a local copy within the repo.
Thanks to my workarounds to the pip issues I was hitting earlier, that should just work, and give me some real-world proving-out of this stuff.</p>
<p>... I opened the PR against punq <em>earlier this year</em>‽
That's it, time is <em>definitely</em> fake.
Fortunately, this means there's only a minor update required.
I'll get to work on this tomorrow.</p>
<p>I think the correct order to do things is:</p>
<ul class="simple">
<li>Copy code from the main punq repo. Get everything set up as I want, but leave the code itself be.</li>
<li>Make sure it properly shadows everything, and still works.</li>
<li>Archive the repo at that point, because I'm not super conversant with non-trivial pijul usage.</li>
<li>Run black over the codebase.</li>
<li>Address any coverage holes. (punq's coverage badge is broken, so I don't know what to expect; also it's almost certainly not compatible with limit-coverage, which will be... a barrier to merging back.)</li>
<li>Look over the changes from my PR, and either redo them, or do something different.</li>
<li>See how well or poorly my fork works when used in anger.</li>
<li>Consider propagating the changes back to my own upstream, and committing to either a merge or a fork.</li>
</ul>
<p>Those are big plans, and it's late.</p>
<p>Good night.</p>
Coding 2020-11-082020-11-08T05:00:00-05:002020-11-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-08:/coding-2020-11-08<p class="first last">Really satisfying to replace all my weird coroutine hacks with simple async library calls.</p>
<p>I got all of the tests I disabled updated and enabled, so now coverage is in a much better place.
I just want to make some minor organizational changes, and then I'll be ready to start hacking on the Mythic rules and work on designing the last major callback I need to define.</p>
<p>Basically, some of Mythic's rolls cause changes to the numbers I want the virtual tabletop to track, which means I'm going to have to figure out how to express and return changes to the state.</p>
<p>I don't think I'll get anywhere with that tonight, so I'm going to wrap up for now.</p>
<p>Good night.</p>
Coding 2020-11-072020-11-07T05:00:00-05:002020-11-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-07:/coding-2020-11-07<p class="first last">Want. Implement. Procrastinate on testing.</p>
<p>I was doing other stuff today, like napping, so let's see about blogging code work as I do it.</p>
<p>First thing I want to do is separate out my click-trio "adaptor" class into its own package.
Let's see about that...</p>
<p>Okay, that's done, no proper tests though.</p>
<p>I would have liked to get more done, but I guess I just wasn't up for it.
I should get to bed ASAP.</p>
<p>Good night.</p>
Coding 2020-11-062020-11-06T05:00:00-05:002020-11-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-06:/coding-2020-11-06<p class="first last">Today would have gone a lot worse if it hadn't turned out that the code all basically works.</p>
<p>I started playing around with my rewritten code, and the behavior seems solid.
It still desperately needs tests, but I want to couple any testing with more of a rewrite.</p>
<p>Basically, the change I've been doing recently was to rework how my roller functions send messages to the host application.
Formerly, when I knew I didn't need input, I was able, and I think this was the right call within that context, to structure the output as a generator, using yields and yield froms to compose different components.
The basic concept, which I haven't yet written a host application to take proper advantage of, was to be able to incrementally display new messages as the calculations are completed.
I <em>think</em> all of this is a kind of manual, restricted version of how async is implemented in Python.</p>
<p>Now, Mythic will require the ability to prompt the user for input, and process the result.
A much earlier form of this code worked by just using the <tt class="docutils literal">input</tt> function directly, but I wanted something that would be more abstract from the standpoint of the business logic.
From reading about async, I thought it would be a better fit in terms of idiomatically expressing the behavior of input and output.</p>
<p>When I actually tried it, I liked the result, especially because it allowed me to rewrite some context-manager type code as an actual context manager, rather than a higher-order function.
Marginal effort, marginal gain, good prospects for future changes.</p>
<p>One thing that happened as a result of the rewrite was that I wrote an adaptor class that bridges Click and Trio.
I want to move that to its own package in the monorepo.
I'll do that first.</p>
<p>And now, I sleep.</p>
<p>Good night.</p>
Coding 2020-11-052020-11-05T05:00:00-05:002020-11-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-05:/coding-2020-11-05<p class="first last">Test-*excessive mumbling*-development</p>
<p>Things are looking generally up-ish from here.
I wa still kind of jittery, so rather than doing any kind of careful, considered work on my hobby code, I just switched everything over to using async, and disabled every test that looked at the resulting code funny.</p>
<p>I'm going to have a heck of a time restoring coverage, but once I get coverage back up, I should be good to make enough progress on porting Mythic.
Where "enough progress" means "I'll write some code, then get a proper use case for a much less destructive change that I'll need to make".</p>
<p>I'm not really done with the original rewrite, it's just at a good stopping point.</p>
<p>Anyway, I'm not up for focusing any more tonight, so I guess I'm done.</p>
<p>Good night.</p>
Coding 2020-11-042020-11-04T05:00:00-05:002020-11-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-04:/coding-2020-11-04<p class="first last">I really want things to be better later.</p>
<p>So, these posts are dated at the start of the day after they're about.
So this Wednesday post was written after a day of, well, I'm in the USA, so you can probably guess how it's been.
And probably going to be for a while.</p>
<p>Regardless of those jitters, I got enough stuff together for Mythic to start thinking about how I'm going to put it all together.
It's not exactly clear to me from the perspective of just dashing off code, due to a few factors:</p>
<ul class="simple">
<li>The chaos factor is consistent over the course of a single roll, and would be nice to avoid passing around overmuch, but it changes at defined points.</li>
<li>The original fate roll will require user input according to additional factors that are not relevant to the rest of the roll calculation.</li>
<li>The fate roll may result in additional outcomes <em>after</em> the roll is resolved.</li>
<li>There's a rules question here that I never asked about, and kind of don't want to; I'd rather just stand by my decision earlier.</li>
</ul>
<p>I've got some ideas for how to deal with this; in a few cases, several possible solutions to one problem.
I'd like to ponder this stuff away from my screen.
It's late enough already.</p>
<p>Good night.</p>
Weekly Roundup 2020-11-032020-11-03T05:00:00-05:002020-11-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-03:/weekly-roundup-2020-11-03<p class="first last">Kind of a rough week that I don't fully remember.</p>
<ul class="simple">
<li>Wednesday: I messed with trio and tkinter, and decided that I wanted to focus on the code that I understood better, to start with.</li>
<li>Thursday: I made my tkinter/trio bridge better, but still not good enough that I'd want to show it off. On the virtual tabletop side, I implemented some stuff for Risus.</li>
<li>Friday: I laid ut all of the systems that I want to implement stuff for to start with, and their approximate order of implementation.</li>
<li>Saturday: I went through all of the details of Mythic's bundled lightweight system.</li>
<li>Sunday: I started working on stuff for fate rolls in Mythic.</li>
<li>Monday: I got more data structures for Mythic written. No real tests yet; I should probably get on that.</li>
</ul>
<p>Next week, I'll try to keep on all that, but I've got a few other things I could look into.
One is taking advantage of my design's sensibilities to port over more complex systems.
And another is taking another crack at songwriting for an idea that I don't feel like laying out here and now.</p>
Coding 2020-11-022020-11-02T05:00:00-05:002020-11-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-02:/coding-2020-11-02<p class="first last">Can't tell if it's because of how late it was while I was coding things, but now that I better understand the default system in Mythic, I <em>really</em> don't like it. Good thing I won't be using it.</p>
<p>I've got the bedrock details of original Mythic added.
What's mostly missing now is stuff that I've already coded up, so I'll be looking through that later.</p>
<p>Going off daylight saving time is messing me up at this actually-extremely-late hour, so I'm not up for describing or explaining anything.
I should figure out when I will be, since I'm not sure when I'll have much to say on this before I get everything together and start trying to actually use it.</p>
<p>Anyway, I'll stop forcing myself to stay up.</p>
<p>Good night.</p>
Coding 2020-11-012020-11-01T04:00:00-05:002020-11-01T04:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-11-01:/coding-2020-11-01<p class="first last">I <em>think</em> I have to change the timestamps tomorrow?</p>
<p>Manifold Garden Manifold Garden Manifold Garden.</p>
<p>Anyway, I didn't get those plans from yesterday implemented earlier today, for <em>some reason</em>, so let's see what I can do now.</p>
<p>So, I didn't get too much done:</p>
<ul class="simple">
<li>The classes required for odds and ranks, missing some of the helper bits I put in other versions</li>
<li>The fate chart is entered as a resource file.</li>
</ul>
<p>If I manage to get things together on this for more than a few hours tomorrow, I should be able to sort things out.</p>
<p>Anyway, it'll probably be tomorrow when I post this, so I'm done for now.</p>
<p>Good night.</p>
Coding 2020-10-312020-10-31T04:00:00-04:002020-10-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-31:/coding-2020-10-31<p class="first last">I know it has two "i"s in the book, but I'm willing to be a prescriptivist at myself.</p>
<p>I was tired all day, so, planning rather than wild prototyping.
With the Mythic stuff, I have four systems.
I'm leaning toward giving each of them their own package, but I don't know if that'll lead to problems.</p>
<p>Putting that aside, covering the question of Rank.
Rank is used in various parts of Mythic, and my inclination is to turn it into a union of three types.
"Raw Rank" ranges from Minuscule to Superhuman.
There is also Superhuman Plus, and Minuscule Plus.
Characters can have Ranks that are Raw, or Superhuman Plus.
Rank shifts can adjust the ranks to anywhere in the full range.
The Plus ranks have an associated number, which, to be consistent with the Fate Chart, has a minimum value of 2.
The Plus ranks calculate an adjustment factor from their number; for the Raw ranks, this number is just 0.
The overall adjustment is the acting rank adjustment minus the difficulty adjustment.
Odds and Chaos Factor map to a Raw Rank, and those are then used as input to the fate function.</p>
<p>Back to the character sheet, there are seven default attributes, as well as allowances for customization.
There are also abilities, which are more freeform.
Attributes and abilities are given a rank of at least minuscule.
Strengths and weaknesses consist of a name, rank shift (number from -3 to 3) and description (when it applies, and what it applies to).
Rank shifts must be applied at user discretion, from the point of view of the code.
There are also notes (this should be a module provided by the base package), and favor points (this should be a distinct module).
There's also "summary", which I'll stick on the main Mythic module for now, but it might move to its own thing.</p>
<p>Besides that, I don't need much I haven't already implemented in some form.
I need to be able to track the chaos factor, and I <em>think</em> for that, I'll implement an idea of "party" that the player sheets can point to, and that'll hold the chaos factor.</p>
<p>I've worked out a bunch of stuff to sink my teeth into.
I should get on this tomorrow afternoon.
For now, sleep.</p>
<p>Good night.</p>
Coding 2020-10-302020-10-30T04:00:00-04:002020-10-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-30:/coding-2020-10-30<p class="first last">For some reason, not totally willing to commit to "this is entirely a personal tool".</p>
<p>Looking over the systems I'm going to try to implement:</p>
<ul class="simple">
<li>Risus (moving on for now)</li>
<li>Mythic</li>
<li>Mythic Variations</li>
<li>Mythic Variations 2</li>
<li>Some homebrew for Mythic Variations 2</li>
<li>The Adventure Crafter</li>
<li>(<em>Maybe</em> other Word Mill stuff, but I'm not planning on it)</li>
<li>The Universal NPC Emulator</li>
</ul>
<p>I intend to add support for everything, even the stuff I'm not planning to use, but I'm ready to jettison that.</p>
<p>Here's the basic idea: The Adventure Crafter provides the large-scale arc of events, and hooks into the genre tables from Mythic Variations; the homebrew allows using the V2 fate check, which is much more compact; V2 also provides most of the other moment-to-moment questions, except for combat and task resolution, which are on Risus, and the behavior check, which is on the UNE.</p>
<p>This "just the way I like it" setup leaves out a shocking amount of the original Mythic, but everything else will need to be most of the way implemented.</p>
<p>Mythic will be interesting because it will require references to the modules in some of the roll flows, and the ability to update some of those modules because the original fate check allows you to spend resources to influence the outcome.</p>
<p>Other things that will be required: those same resources will need to be able to listen for events in the game, or to ask for a judgment call at specific junctures.</p>
<p>I won't be using the specific mechanics I have in mind there, but I think that at least planning them will help inform the architecture.</p>
<p>I don't know if I'll make much progress on this tomorrow; the weekend seems like a better bet.
Anyway, I should wrap up, it's late again.</p>
<p>Good night.</p>
Coding 2020-10-292020-10-29T04:00:00-04:002020-10-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-29:/coding-2020-10-29<p class="first last">The spellcheck dictionary here is weirdly limited for a code-centric editor. Seriously trying to tell me that "validator" isn't a word?</p>
<p>Still not handling my time well.
I did some hacking on the tkinter/Trio bridge, a mix of improving the correctness and just kind of golfing things down.
I'm not using what I have, and it's got some inflexibility that means I'd be reluctant to give it to anyone else until it's been proved out on non-toy code.</p>
<p>So far as the virtual tabletop stuff, I just kind of did a few of the things I've been thinking about: removing the specific requirement for a serializer registry on the classes, implementing common modules, and implementing stuff for Risus.
I don't feel like writing tests for validators for the stuff I have now, so I'll probably just add some TODOs and start switching between systems to implement.</p>
<p>I'm slightly more tired than I thought I'd be now, so I should wrap up.</p>
<p>Good night.</p>
Coding 2020-10-282020-10-28T04:00:00-04:002020-10-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-28:/coding-2020-10-28<p class="first last">Not sure what the proportion is here between "not having enough prototyped to make an informed decision" and "wanting to stay in my comfort zone", with a side bit of "taking on a bunch of new concepts and wondering if I'm over-complicating things".</p>
<p>Okay, here's what I did today.
I tested communicating with trio from the tkinter side of the event loop, and it seemed to work.
Aside from that, napping, and, like, work and eating, I guess.</p>
<p>Anyway, I'm hoping that I can use trio to handle computationally intensive or elaborate tasks.
I'm not sure how much sense it makes to go for it right off, so I'm now going to focus on wrapping or adapting my existing code to stream event information to a basic tkinter app.
I think I'd like to make things general enough that the same core logic can drive the command line or a GUI, but I'm not sure that makes sense.</p>
<p>There's kind of a bunch of things I want to do, but they've got weird interdependencies and I'm not sure what I want to do first:</p>
<ul class="simple">
<li>Factor out the requirement (not at all validated) that Modules define serializers, and put together some kind of policy-checking-something.</li>
<li>Implement workflows that require user input, so I have something concrete to check against.</li>
<li>Evaluate whether async adds value to those workflows.</li>
<li>Figure out the general GUI design I want.</li>
<li>Determine how to handle widget design for specific components.</li>
</ul>
<p>Thinking about this, I think what I want to do is punt on GUI code and actually using the serializers, and work on getting data structures and workflows for the symptoms I want, so I can have something concrete to point to when sketching out the systems I want.</p>
<p>I'll write as much stuff as I can for each system.
(The serializers for Modules should be simple, and will let me know what validation actually needs, for example.
Also, I don't think I'm ready to put together a whole GUI, but I can definitely put together experimental widgets and see where the rough bits are.)</p>
<p>I've been in rough shape myself lately, so I'm going to try to wrap up, like, thirty whole minutes earlier than usual.</p>
<p>Good night.</p>
Weekly Roundup 2020-10-272020-10-27T04:00:00-04:002020-10-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-27:/weekly-roundup-2020-10-27<p class="first last">Guess I'm learning new things. Wasn't quite planning on that.</p>
<ul class="simple">
<li>Wednesday: I laid out my design concept for serializer methods, and thereby realized that I didn't want to use that concept.</li>
<li>Thursday: I started working on type stubs for a third-party serialization library</li>
<li>Friday: I sketched out what functionality I want from serializer validation. (That is, validation of the serializer, not validation performed by the serializer.)</li>
<li>Saturday: I sketched out requirements for what exactly the serializer validation should look for.</li>
<li>Sunday: I pondered how the new module that has all of this stuff feels too big already.</li>
<li>Monday: I let things go until after minight and rushed out a post.</li>
</ul>
<p>Next week, I'm going to experiment with what I can do with tkinter.
One thing I'm pretty sure I can do is integrate it with Trio, which should give me the ability to avoid explicitly breaking up big functions: just write helper functions that kick stuff off, then use a channel or an event or something.
(It looks like other people have looked into the general idea of Trio + tkinter, and run into <a class="reference external" href="https://github.com/python-trio/trio/issues/1578#issuecomment-689785694">caveats</a>.)
I need to get more experienced with tkinter first, and see how far I can push it to work with my existing message passing stuff.</p>
Coding 2020-10-262020-10-26T04:00:00-04:002020-10-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-26:/coding-2020-10-26<p class="first last">Oh no, not procrastination. Again. Who could have predicted this?</p>
<p>I let things go late again.
Here's the extremely fast summary of what I worked on today.</p>
<p>I laid out the responsibilities of each module in my main virtual tabletop thing.
For the old modules, this is easy.
For the new module, it's kind of not.
I pondered trying to give this a GUI, and decided I'd like to make some decisions on that ahead of time so my design choices can be informed by an actual framework.</p>
<p>I then started researching some of my options for GUI toolkits.</p>
<p>And that brings us up to now.
I need to wrap up ASAP, so.</p>
<p>Good night.</p>
Coding 2020-10-252020-10-25T04:00:00-04:002020-10-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-25:/coding-2020-10-25<p class="first last">I don't know if "carve" sounds weird, but it <em>feels</em> right.</p>
<p>I know what the code needs to do for runtime serializer validation, but I'm not totally sure how to actually wedge the functionality in there.</p>
<p>Part of the problem is that the module for managing modules/sheets/tables is starting to feel bloated to me.
I think I need to set aside some time to pin down what I'm trying to accomplish, and how each part fits into that.
Let's see what I can do towards that right now, in the next fifteen minutes or so.</p>
<p>Basically, I want to play tabletop games that aren't <em>not</em> meant for solo play, and I've got a few issues:</p>
<ul class="simple">
<li>Even with my heavily tricked-out rules binder (so many flags sticking out of everywhere), it's sometimes a pain tracking down the relevant rules, and I've got new rules I want to try out.</li>
<li>We don't have many dice.</li>
<li>I don't want to have to keep track of physical character sheets, especially if I decide I want to do something like, I don't know, Danger Patrol but it's Retrocausality.</li>
</ul>
<p>The second bullet point is an extremely solved problem by now.
I have iterated on code to handle this a whole bunch, and it's fine.
The first bullet point requires work to be done per-system, and also needs the third bullet.
The third bullet is what I've been focusing on recently.</p>
<p>Putting them out like this suggests some avenues of improvement.
The second-bullet code is spread across seven modules, while the third bullet point is crammed into one.</p>
<p>That's the first order of business: figuring out all of the responsibilities in this module so I can carve it up.</p>
<p>Anyway, it's been more than fifteen minutes and I'm about to fall asleep.</p>
<p>Good night.</p>
Coding 2020-10-242020-10-24T04:00:00-04:002020-10-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-24:/coding-2020-10-24<p class="first last">I'm still a little bitter about PEP 416 getting rejected.</p>
<p>Okay, I sort of took today easy, so this is going to just be a quick sketch of what I'm going to try to accomplish.</p>
<p>This is all based off the <a class="reference external" href="https://github.com/eevee/camel">camel</a> library.
My minimum requirements are:</p>
<ul class="simple">
<li>No multi-dumpers.</li>
<li>Always use the highest version. This is <tt class="docutils literal">None</tt> if <tt class="docutils literal">None</tt> is present in the dumper dict, and the maximum value otherwise.</li>
<li>Warn if the parameter annotations don't match the type.</li>
<li>Expect a container type as the output</li>
<li>If a list, add its parameter</li>
<li>If a union, add each parameter</li>
<li>If a typeddict (the normal case), add the type of each field</li>
<li>Keep track of which types were seen; the values should form some kind of DAG, but the type system doesn't have to enforce that (even if it usually will)</li>
</ul>
<p>Basically, most types should just be recursed on immediately, but we need special casing for lists, unions (and probably optionals), dicts, and typed dicts.
Basically, we need typed dict special casing because that's what most of the data will use for serialization, and we need special casing for all supported generics because we need to consider each runtime type separately.</p>
<p>Another requirement that I'm not yet sure how to accomplish: no two registries should implement loaders or dumpers for the same type.
(If one registry implements a dumper for a type that isn't needed by the types that bring in that registry, then that dumper won't be checked, unless I just declare that every dumper in a every registry gets checked.)</p>
<p>I'm tired and I don't think I can make this make much more sense for now, so I'm calling it here.</p>
<p>Good night.</p>
Coding 2020-10-232020-10-23T04:00:00-04:002020-10-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-23:/coding-2020-10-23<p class="first last">List of caveats inspired by reading a bunch of Hillel Wayne, I think.</p>
<p>I seem to have gotten the type stubs I wrote working, so that's exciting.
After I publish this, I'm going to try updating the tests to be properly type-compatible before I start tossing in runtime validation using the new fields I expect to have.</p>
<p>The basic idea there is to write visitors for different kinds of generic aliases, so I can confirm at import time that, if the data in a module instance conforms to its type annotations, the instance should be able to attempt <em>something</em> when serialized.
There are a few things this idea doesn't test:</p>
<ul class="simple">
<li>Whether the type annotations are actually accurate.</li>
<li>Whether the serializer functions provided by the libraries will succeed.</li>
<li>Whether loaders exist for the serialized data (this wouldn't be hard to add, but I don't know if it'd be worth it)</li>
<li>Whether the serializers and deserializers properly round-trip data (this would be the domain of property-based testing)</li>
</ul>
<p>I think what I want to do is get the basic runtime infrastructure together for the basic serializer checks, then work on property-based tests.
The idea there is to make sure that, if I use this code, it'll end up writing <em>something</em> to disk.
The property-based testing is to develop confidence that what's written to disk is valid.
As long as I don't totally cheap out on the serializers, then it's <em>probably</em> not a problem if something is wrong with a loader, since I can just debug the loader and then pick things back up.</p>
<p>Anyway, cutting things close on time, better wrap up.</p>
<p>Good night.</p>
Coding 2020-10-222020-10-22T04:00:00-04:002020-10-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-22:/coding-2020-10-22<p class="first last">This entry brought to you by both poor judgment, and poor time management.</p>
<p>Quick post.</p>
<p>Got distracted by various things, the last of which was writing type stubs for a third-party library that only sort of fits my idea of a PEP-484 compliant library.
It's tricky, but I'm making headway.</p>
<p>For a different value of it, it's midnight, so I should wrap up for now.</p>
<p>Good night.</p>
Coding 2020-10-212020-10-21T04:00:00-04:002020-10-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-21:/coding-2020-10-21<p class="first last">It's nice to talk through my original design and figure out how much of it is unneeded or counterproductive.</p>
<p>For the past few days, I thought about how I want to set up serialization so that there's some assurance that the classes I care about can handle it.</p>
<p>Here's what I'm currently thinking of.
It's pretty elaborate, but it should provide the bare minimum of verification.</p>
<p>Right now, my module modules look like this:</p>
<div class="highlight"><pre><span></span><span class="o">...</span>
<span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">FooModule</span><span class="p">:</span>
<span class="n">field</span><span class="p">:</span> <span class="nb">int</span>
<span class="c1"># ModuleProxy populates a global registry,</span>
<span class="c1"># such that each module only has one proxy.</span>
<span class="k">class</span> <span class="nc">FooProxy</span><span class="p">(</span><span class="n">ModuleProxy</span><span class="p">[</span><span class="n">FooModule</span><span class="p">],</span> <span class="n">FooModule</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Put extra validation or functionality in</span>
<span class="sd"> here, not relevant to the example."""</span>
</pre></div>
<p>I want to make them look something like this:</p>
<div class="highlight"><pre><span></span><span class="o">...</span>
<span class="k">class</span> <span class="nc">FooSerialized</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="n">field</span><span class="p">:</span> <span class="nb">int</span>
<span class="k">class</span> <span class="nc">FooBarSerializer</span><span class="p">(</span><span class="n">Serializer</span><span class="p">):</span>
<span class="nd">@dumper</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"foo"</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">__dump_foo_v1</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">FooModule</span><span class="p">)</span> <span class="o">-></span> <span class="n">FooSerialized</span><span class="p">:</span> <span class="c1"># type: ignore[misc]</span>
<span class="k">return</span> <span class="p">{</span><span class="s2">"field"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">field</span><span class="p">}</span>
<span class="c1"># I haven't thought too hard about this bit.</span>
<span class="c1"># Maybe it'd be like this, maybe I'll go crazier with subclassing.</span>
<span class="c1"># Maybe I could go the other way and make everything a staticmethod.</span>
<span class="nd">@loader</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"foo"</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="nf">__load_foo_v1</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="n">FooSerialized</span><span class="p">,</span> <span class="n">version</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="n">FooModule</span><span class="p">:</span>
<span class="k">return</span> <span class="n">FooModule</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s2">"field"</span><span class="p">])</span>
<span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">FooModule</span><span class="p">(</span><span class="n">FooBarSerializer</span><span class="p">):</span>
<span class="n">field</span><span class="p">:</span> <span class="nb">int</span>
<span class="c1"># Add the typing checks here,</span>
<span class="c1"># because that's the latest that still has teeth.</span>
<span class="k">class</span> <span class="nc">FooProxy</span><span class="p">(</span><span class="n">ModuleProxy</span><span class="p">[</span><span class="n">FooModule</span><span class="p">],</span> <span class="n">FooModule</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Same as last time."""</span>
</pre></div>
<p>The verification step would basically be to make sure that, for every user-defined class that the module is defined in terms of, that class has a dumper defined in the module's base class.</p>
<p>Thinking about it like that, I'm inclined to go the "everything is a staticmethod" route.</p>
<p>Thinking over this from the top, I could make the serializer class a required class attribute rather than a subclass, which would make things cleaner.</p>
<p>From there, I could remove the "dumb container" class, and just work with serializer registries directly.</p>
<p>With a little minor fiddling, then, it shouldn't be as big of a change as I was thinking it might be.</p>
<p>It's late, done for now.</p>
<p>Good night.</p>
Weekly Roundup 2020-10-202020-10-20T04:00:00-04:002020-10-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-20:/weekly-roundup-2020-10-20<p class="first last">If I keep on getting sidetracked like this, I'll end up trying to work on Shine Whave again or something.</p>
<ul class="simple">
<li>Wednesday: I looked for natlangs to base my writeup off of.</li>
<li>Thursday: I got sidetracked trying to figure out how L works in English. It's very subtle, and I can feel distinctions that I can't consistently hear.</li>
<li>Friday: I decided it was time to look at the natlang grammars, and so I ended up...</li>
<li>Saturday: Coding up auto-roller stuff.</li>
<li>Sunday: I got sidetracked again via Minecraft, but I did get some design work done.</li>
<li>Monday: I implemented the design, but not the tests. I thought about future directions.</li>
</ul>
<p>Next week, I'd like to start looking at some of the natlang grammars, and figuring out how I want to handle serialization for the virtual tabletop stuff.
I know I want <em>something</em>, because I don't want to do this all within a single Python session.</p>
Coding 2020-10-192020-10-19T04:00:00-04:002020-10-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-19:/coding-2020-10-19<p class="first last">Today's discovery: apparently, now my laptop needs a full restart after every software update, whether it says so or not.</p>
<p>I've got the classes for modeling the broader relationships between player characters hopefully completed.
There are a few directions to go from this:</p>
<ul class="simple">
<li>Adding tests so I have some assurance that this stuff actually works.</li>
<li>Adding common modules.</li>
<li>Writing a module for Risus.</li>
<li>Adding serialization support.</li>
<li>Working on the six other systems I want to use.</li>
</ul>
<p>I <em>think</em> that's about the right order to work on this stuff in.
Maybe do serialization somewhat sooner.</p>
<p>In any case, things are shaping up.
I just hope it doesn't all go horribly wrong when I try to actually use the new stuff.
If it does, it should at least be fixable.</p>
<p>Anyway, it's getting late.
I'd like to wrap things up before I zone out too much more.</p>
<p>(At some point, I should see about replacing some of my third-party software repositories with new versions, but that point is <em>super</em> not now.)</p>
<p>Good night.</p>
Coding 2020-10-182020-10-18T04:00:00-04:002020-10-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-18:/coding-2020-10-18<p class="first last">Maybe these entries would be longer if I got enough sleep, and also didn't play I-don't-know-how-much Minecraft.</p>
<p>Minecraft Minecraft Minecraft.</p>
<p>Anyway, I thought about how to handle Risus stuff, and then realized that my baseline classes aren't expressive enough to handle everything about the parts of Risus I want to represent, so I'm workig on designing the additional stuff.
I want to say that this will be enough detail to support anything else (basically, an individual module needs to have an interface it can use to inspect the entire table), but I can't feel confident about that.</p>
<p>I haven't started coding this yet, but I'd like to get the ball rolling for tomorrow, so I'll start adding stub classes after I publish this.</p>
<p>Good night.</p>
Coding 2020-10-172020-10-17T04:00:00-04:002020-10-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-17:/coding-2020-10-17<p class="first last">This code is easy to test, but sometimes I have trouble testing it <em>meaningfully</em>.</p>
<p>I've been coding on and off all week.
I've stashed away the Ironsworn stuff, and I'm working on a system for Risus.
My basic plan is to get the dice rolls solid (since that's what I personally care most about automating), and then see about working outward to handle stuff like character sheets (relatively simple) and the combat rules.</p>
<p>I should probably do some planning or design once I'm done adding test coverage, since I'm not sure how to represent stuff like teams at a character sheet level.
It might need another redesign.</p>
<p>Anyway, I got distracted playing Minecraft, so this entry is quick and short.</p>
<p>Good night.</p>
Conlanging 2020-10-162020-10-16T04:00:00-04:002020-10-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-16:/conlanging-2020-10-16<p class="first last">Maybe these entries would end up less sparse if I brought back the "specific things on specific days" structure.</p>
<p>A bit more Novegradian.
I'm liking the historical aspects, but I know that for my own conlang, I'd like the details to be much sketchier, so I should probably be looking at some of the natlang grammars soon, since those shuld give me an idea of what kind of things get said about extinct languages that we don't know much about.</p>
<p>Spaced out for a bit, and once again I don't have much to add to what I've already said.
Wrapping up for now.</p>
<p>Good night.</p>
Conlanging 2020-10-152020-10-15T04:00:00-04:002020-10-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-15:/conlanging-2020-10-15<p class="first last">Real tongue hours.</p>
<p>Reading up on Novegradian, I see that my confusion about the lateral consonants was due to unfamiliarty with IPA, and it's a contrast between clear L and dark L.
Both exist in English, except not quite, because English has alveolar L, and Novegradian (and apparently also Russian; I am learning so much Russian phonology, and getting progressively more annoyed with how evidently inadequate Duolingo is on its own) has dental L.</p>
<p>Okay, I say all that, because that's what Wikipedia says, but I can't tell the difference audibly, and also, I'm pretty sure I actually use both in English?
Like, alveolar for word-final L, and dental otherwise.
(Except that's not quite right, because "lull" is all alveolar, "lily" is all dental, and the second L in "little" remains alveolar even if I add a suffix.
I <em>think</em> compound words count as "not word-final".
"Small" is alveolar, and I think "small-minded" is dental.)
Is that a thing?</p>
<p>Well, my wife got similar results, and neither of us can tell what's going on by listening.
I should stop messing with this for now, because now my tongue is a little sore.</p>
<p>Anyway, yeah, a bit more progress reading about Novegradian, and a bunch of learning about natlangs.</p>
<p>Good night.</p>
Conlanging 2020-10-142020-10-14T04:00:00-04:002020-10-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-14:/conlanging-2020-10-14<p class="first last">So much of problem solving is restating things you know until you notice an obvious follow-up question.</p>
<p>I started reading the grammar for Novegradian.
It looks extremely promising as a reference point for what I plan with my current project, so I'll definitely keep on with it, even if it is a bit... lengthy.
I don't have much to comment about it specifically yet; I think I'm still in the introduction.</p>
<p>One thing I'm trying to figure out is how much (invented) history I want to present in the grammar that I write.
I do have a basic historical trajectory sketched, but I kind of want to present this language as an isolate, even if I do have an explanation for where it came from.
Although, if I commit to an in-universe perspective, I suppose that means I'd have to mark some fraction of the language as a reconstruction, as it's supposed to be an exinct language.</p>
<p>I suppose I should do the thing that I now realize is obvious, and look up resources on languages that went extinct in the past few centuries.</p>
<p>Okay, a few skims of Wikipedia later, and I've got a promising cross-section of languages to investigate.</p>
<p>All right, I can't think of anything else to say here, so I'll wind down.</p>
<p>Good night.</p>
Weekly Roundup 2020-10-132020-10-13T04:00:00-04:002020-10-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-13:/weekly-roundup-2020-10-13<p class="first last">Everything feels at least slightly different...</p>
<ul class="simple">
<li>Wednesday: I grabbed some reference grammars, and forgot that definition of "grammar".</li>
<li>Thursday: I remembered the definition, and reconsidered my approach to reading the grammars.</li>
<li>Friday: I put together a wishlist for things I want to see in a grammar, beyond the established checklists.</li>
<li>Saturday: I took a detour from conlang stuff to work on some hobby code.</li>
<li>Sunday: I explained at length some of the subtleties of one specific corner of Python's packaging ecosystem.</li>
<li>Monday: I upgraded my laptop, and fixed all of the issues that I currently know about.</li>
</ul>
<p>Next week, I'm going to skim over some of the other grammars, then start working in earnest on planning my own.
Probably tweak the hobby code some more, but I'd like that to be in the background.</p>
Coding 2020-10-122020-10-12T04:00:00-04:002020-10-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-12:/coding-2020-10-12<p class="first last">A collaboration between laziness and prudence.</p>
<p>Earlier today, I upgraded my laptop, and this post could very well have ended up brought to you by my phone's USB tethering mode, but I've fixed all of the upgrade issues.
That I know about.</p>
<p>I did some coverage improvements for the auto-roller, as well as some fixes.
The testing I did convinced me to drop the pytest verbosity for that project, since it's a real pain to find a few failures buried in over a thousand successes.</p>
<p>It'll also be kind of a pain to put together enough stuff to handle properly testing the Ironsworn stuff, which I'm not currently planning to actually use, but... hm.
Maybe I should see about putting this off in a branch or something.</p>
<p>I should wrap this post up now so I have plenty of time to troubleshoot if something else is broken.</p>
<p>Good night.</p>
Coding 2020-10-112020-10-11T04:00:00-04:002020-10-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-11:/coding-2020-10-11<p class="first last">There are two kinds of bulleted list items.</p>
<p>More tweaks:</p>
<ul class="simple">
<li>I undid some of my changes from yesterday, on the grounds that they weren't necessary, and made it harder to do type inference.</li>
<li>I realized that setting the <tt class="docutils literal">PIP_CONSTRAINT</tt> environment variable made more sense than passing the <tt class="docutils literal"><span class="pre">--find-links</span></tt> argument to pip. I'm not sure if it's clear what use case could be somewhat covered by both of these. Basically, using constraint files was always the right answer for my use case, which is to have a bunch of packages in a repo that depend on each other, and I don't care about what's published. Passing <tt class="docutils literal"><span class="pre">--constraint</span></tt> to pip didn't work here when the packages use flit, because currently pip generates further pip commands that don't respect the constraint files. (This might be less of an issue now, since flit tries to avoid installing so much any more, I think.) BUT, the environment variables get passed through, so <tt class="docutils literal">PIP_CONSTRAINT</tt> handles it. Before I realized this, I was pre-building the wheel files and storing them in a known location, so I could add that location as an index via <tt class="docutils literal"><span class="pre">--find-links</span></tt>. The problem with that approach is that pip wouldn't actually prefer one index to another in any way that mattered to me, and I didn't want to cut off PyPI entirely. The way to require a local version of a package is constraint files, which didn't work for me, until I figured out this workaround, and also flit changed to not require the workaround, but, eh, the workaround makes it cleaner. (And it'll come in handy if I ever roll my own PEP 517 backend for some, presumably terrible, reason.)</li>
</ul>
<p>Anyway, next I want to switch focus to some systems that won't need such incredibly complicated formats for representing the relevant data, and work on factoring some things out.
(For example, most RPG characters have names.)</p>
<p>And, I spaced out and it's late again, so I guess this post is done.</p>
<p>Good night.</p>
Coding 2020-10-102020-10-10T04:00:00-04:002020-10-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-10:/coding-2020-10-10<p class="first last">"my fancy metaprogramming was wrong, [so I] replaced it with different fancy metaprogramming"</p>
<p>I ended up not looking at conlang stuff today, so instead I'll talk about the coding stuff I was doing this week.
I've mentioed this before; the basic idea is that it's software for automatically following rolling rules for tabletop games, and hopefully tracking game state as well.
I'm not sure whether I'll ever be comfortable releasing the various "game" packages, but I might release the core at some point, maybe.</p>
<p>This week, I put together a skeleton of an Ironsworn sheet to test the limits of the sheet logic, then realized that my fancy metaprogramming was wrong, and replaced it with different fancy metaprogramming that is slightly more amenable to typechecking.</p>
<p>There are a few enhancements I want to make, some cleanup of the sheet, and then once I've wired stuff together and proven the basic functionality, I'll switch to the various systems that I'm interested in using currently, which should be simpler overall.</p>
<p>Also, I should write serialization logic for all of this, which is going to be... a bit of a chore.</p>
<p>I've been spacing out a bit tonight, so now it's late, so I guess I'm done for now.</p>
<p>Good night.</p>
Conlanging 2020-10-092020-10-09T04:00:00-04:002020-10-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-09:/conlanging-2020-10-09<p class="first last">I should try and translate this into goals, and get to work soon.</p>
<p>Thoughts on what I'd like to look at first in a reference grammar:</p>
<ul class="simple">
<li>Phonology</li>
<li>The orthography used in the grammar</li>
<li>Phonotactics, focusing at first on pronunciation changes that are implicit in the orthography</li>
<li>Basic sentences and glosses</li>
<li>Sentences and glosses embedded in a narrative context; basically, I want glosses where there's a motivation to say a sentence like "The girl brings a book to the elder." or whatever.</li>
<li>My idea here is "quickly get a sense of how it sounds"</li>
</ul>
<p>Some of this might not live in a grammar.
I'm not sure.</p>
<p>Anyway, there's a lot more to cover, and stuff that needs to be worked out to get these, like morphology.</p>
<p>I think these give me a good baseline to work towards.</p>
<p>I'm tired and I divided my attention, so it's once again a quick entry.
Oh well.</p>
<p>Good night.</p>
Conlanging 2020-10-082020-10-08T04:00:00-04:002020-10-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-08:/conlanging-2020-10-08<p class="first last">The heart wants what the heart wants, and what the heart wants is apparently hand-rolling code to handle character sheets.</p>
<p>I made a little more headway on the Kahtsaai grammar (<em>There's</em> the word I was looking for yesterday!), but I got a bit distracted with some projects that are relevant to stuff that I'm not writing about.</p>
<p>Thinking about my experience so far, now I'm trying to remember if there's any advice I've read on reading conlang grammars (or grammars in general), because trying to just read stuff in order is... a lot. (I read <a class="reference external" href="http://www.nzdl.org/gsdlmod?e=d-00000-00---off-0hdl--00-0----0-10-0---0---0direct-10---4-------0-0l--11-en-50---20-about---00-0-1-00-0--4----0-0-11-10-0utfZz-8-00&cl=CL2.7.11&d=HASHf4c763bbedf2771100d30b.9.6.2&gt=1">this</a>, and, hm, yes.)</p>
<p>It wouldn't do for a reference grammar to present things like a textbook, but I wonder if there's some way to compile both in a way that reduces duplication of effort.</p>
<p>Anyway, I should work on reading these grammars more actively, or I'll have a bad time.</p>
<p><em>Much like</em> if I don't get to bed soon.
(Boom, nailed the segue.)</p>
<p>Good night.</p>
Conlanging 2020-10-072020-10-07T04:00:00-04:002020-10-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-07:/conlanging-2020-10-07<p class="first last">Don't want to be the Garth Marenghi of conlangs.</p>
<p>Rather than jumping back into this, I'm trying to read through other people's writeups of their conlangs.
There's so much to it that it doesn't make sense, at this point in time, to remake from first principles, so I'm trying to get an idea of what I should be doing, presentation-wise.
(Also, it wouldn't make any sense for me to expect other people to look at my stuff without looking at other people's stuff.)</p>
<p>It might take me a while to get through it, but it also doesn't make sense to try to write something I'd have trouble reading.
And reading this kind of specialized writing is a skill.</p>
<p>I've downloaded a few PDF writeups, and right now I'm looking over the one for <a class="reference external" href="https://lingweenie.org/conlang/kahtsaai.pdf">Kahtsaai</a>.
I'm just a few pages in, so so far I just have surface-level reactions, such as:</p>
<ul class="simple">
<li>I am not confident in my ability to pronounce contrastive length or tone.</li>
<li>I hadn't had a reason to use the voiceless alveolar lateral fricative before. (I'm hoping I read the consonant chart correctly.) Anyway, I really like it. I might see if I can use it somewhere in the history of my current project.</li>
</ul>
<p>This will probably take a while, and I don't have anything else to say right now, so I'm calling the post here.</p>
<p>Good night.</p>
Weekly Roundup 2020-10-062020-10-06T04:00:00-04:002020-10-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-06:/weekly-roundup-2020-10-06<p class="first last">I don't know how many people don't read these, and thereby get confused when I refer to them later.</p>
<ul class="simple">
<li>Wednesday: I griped more about trying to use Sphinx with Cryptopals.</li>
<li>Thursday: I figured out a way around the latest issue.</li>
<li>Friday: I tried out some code metrics, and gave up on them.</li>
<li>Saturday: I documented "why" a bunch of my documentation is weird and non-standard in its behavior or layout.</li>
<li>Sunday: I made a little more progress on documentation, then decided I need a break.</li>
<li>Monday: For my break, I picked conlanging back up.</li>
</ul>
<p>Next week, I might also mess with the virtual tabletop stuff.
This is in contrast to my guess yesterday that I'd go for Dennis next.
Well, we'll see.</p>
Conlanging 2020-10-052020-10-05T04:00:00-04:002020-10-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-05:/conlanging-2020-10-05<p class="first last">I think the next project I'm going to return to X months after the last entry is Dennis.</p>
<p>I decided to take a break from Cryptopals, and dust off my conlanging stuff.
I basically remember what I was doing a few months ago, so I hopefully shouldn't end up totally lost.</p>
<p>I tried to put together a few things inspired by this video, among them a list of goals.</p>
<div class="youtube youtube-16x9"><iframe src="https://www.youtube.com/embed/bSaKIkWoR94" allowfullscreen seamless frameBorder="0"></iframe></div><p>I've got some basic goals written up, but I think I need to go over them some more.
It feels like I'm kind of mingling "what I want to accomplish" and "possible ways to accomplish what I want to accomplish".
Which, I don't think it's bad to note the latter, but it needs to be called out that that's what it is.</p>
<p>The other thing I want to figure out is guidelines for "Is this ready to show off?".
I don't want to be too quick or too slow to ask for feedback, though right now I'm sure it's not ready.
I think I need to just look at what other people are doing to get some idea of what standard to hold myself to.</p>
<p>Anyway, I'm super tired, so, I should go deal with that.</p>
<p>Good night.</p>
Coding 2020-10-042020-10-04T04:00:00-04:002020-10-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-04:/coding-2020-10-04<p class="first last">I should, like, keep track of how often I start feeling burnt out on stuff. Probably won't.</p>
<p>I ground away a bit at the AES documentation today.
It's pretty straightforward, but I'm not feeling focused on it.
I think I might need a change of pace.</p>
<p>I'll think about it tomorrow.
There are some things I've been meaning to get back to.
I just need to work out a good way to be sure I'll get back to this.
I've just tried one way, I might think of others.</p>
<p>And, I seem to be done for the night.</p>
<p>Good night.</p>
Coding 2020-10-032020-10-03T04:00:00-04:002020-10-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-03:/coding-2020-10-03<p class="first last">Feeling really good at finding all of the things a tool can't easily do.</p>
<p>I forget if I documented any more code today.
I did decide to document my grievances with Sphinx next to the weird syntax I put in to work around them, to explain why the weird syntax is there.
By working through this, I was able to devise some workarounds that lead to output that I deem acceptable, and are accepted by the linting pass, so they're <em>probably</em> fine.</p>
<p>I'll try to power through documenting the AES wrappers tomorrow.</p>
<p>What else am I doing...</p>
<p>I'm working on some articles that I plan to actually edit, post elsewhere, and link to them here.
Those will probably take some time, but oh well.</p>
<p>I am blanking out on whether I did anything else worth posting, which I assume means I should wind down now.</p>
<p>Good night.</p>
Coding 2020-10-022020-10-02T04:00:00-04:002020-10-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-02:/coding-2020-10-02<p class="first last">I should dial back the salt towards open-source projects. It's <em>meant</em> to be directed at people recommending them when, IMO, they're not ready.</p>
<p>I spent today doing various things:</p>
<ul class="simple">
<li>Coming to grips with the <tt class="docutils literal">bitstreams</tt> module, including:</li>
<li>Turning some top-level functions into methods.</li>
<li>Figuring out what I actually want to include in the documentation.</li>
<li>And improving the names of classes and variables.</li>
<li>Adding, and then removing, a nox session for running metrics against the code. Like, what's the point of metrics if the tool's Halstead metrics *cough* don't work, and the McCabe metrics are just a bunch of 1s and 2s, a few 3s, and a 7? Maybe there are better metrics, but the only other one I've seen people talking about is cognitive complexity, which incentivized some... interesting... code in Structured Data. I hope there's better stuff out there I haven't heard of, but if there is, I... haven't heard of it.</li>
</ul>
<p>What got me in a good place with the code was writing comments on how visible I want each thing to be in the documentation.
From there, I was able to use those notes to get a handle on the big picture.
It's possible I'll end up wanting to rewrite some of this, but I'll document everything first and see what I think.</p>
<p>Things are going well, and I should wrap up for now.</p>
<p>Good night.</p>
Coding 2020-10-012020-10-01T04:00:00-04:002020-10-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-10-01:/coding-2020-10-01<p class="first last">Quality issues? The code is <em>totally</em> fine and intuitive. *shoves <tt class="docutils literal">self = yield from self._emit()</tt> under the rug*</p>
<p>Putting "I win" as a commit message seems to have glitched up either pijul or my terminal a little, but the point is, specifying the aliases I want documented as autodata rather than letting them be collected as "genericalias" seems to basically do what I wanted done, at the slight cost of kicking those documentation entries out of order.
The moral of the story is, if you can't do a thing, do something else.</p>
<p>Anyway, I added some documentation and switched configuration files into pyproject.toml, in part thanks to FlakeHell, which I am <em>extremely</em> underutilizing, but at least it does what I initially wanted it to.
I'll see later what else I'd like to do with it.</p>
<p>After that, I started documenting probably the most complicated module in the project, which just barely justifies its existence versus how complicated it is.
Basically, and this whole thing will probably provoke multiple "well, there's your problem" reactions, I rolled my own classes for converting streams to/from bytes and base64 and hex encodings.
At first, I was hand-coding the control flow inside the iterators, but that's kind of a pain, since you have to do various fiddly bits of bookkeeping in the base64 case.
By making the logic generic, I was able to undo the hand-rolling iteration synchronization I'd done, and offload the question of "which bits go where" onto the runtime.</p>
<p>Where the <em>problem</em> comes in, from my perspective, is that this "generic bitstream iterator" concept predates the rewrite to make all iteration repeatable.
This meant that I had to convert some of my boilerplate code for interacting with this, into a wrapper class.
So, there's <em>a bunch</em> of code in there, (over 100 lines, with no documentation), and I'm looking at it and thinking "Before I even get to documentation, how much of this code should actually <em>exist</em> in the current form?"
It's possible that "Before" is a bad assumption, and I should be trying to document stuff to get insight on what needs to change, but I'm not sure.</p>
<p>I had kind of a rough night in other regards, for some reason, so I'm not going to push myself, but tomorrow I'd like to figure out what I'm going to do with this module.</p>
<p>Good night.</p>
<p>(PS If my coworkers are reading this, there's a chance that they're boggling at my getting freaked out by "only" 100 lines.
Well, this is small hobby code, and if I tried singlehandedly imposing my standards on our codebases, I would not have time for anything else.
That's not hyperbole.</p>
<p>Also, there are some longer files in this project, but they have a much higher ratio of API surface to LoC, and some of them are documented.)</p>
Coding 2020-09-302020-09-30T04:00:00-04:002020-09-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-30:/coding-2020-09-30<p class="first last">So, Sphinx totally has stuff for handling <tt class="docutils literal">typing</tt> in there, it just... does a bunch of things that I don't want it to? And possibly does things that I'd be fine with, if I noticed.</p>
<p>I added some more documentation, and found a new gripe about Sphinx.
One of the things Sphinx does for "data" members by default is to include their value in the generated documentation.
I knew this, from elsewhere that I disabled it.
The automodule directive, as near as I can tell, and I would like to be wrong, invokes the other directives as needed, <em>with no way to control what options it passes</em>.</p>
<p>This means that, when I document my stream types, I end up with gunk at the end of the entry like "alias of Union[cryptopals.sized_iterable.ExactSizedIterable[NewType.<locals>.new_type], cryptopals.sized_iterable.ApproximateSizedIterable[NewType.<locals>.new_type]]".
No hyperlinks, no nothing.
In the current documentation, this comes right after some stuff I wrote manually that presents as the proper types, with links.</p>
<p>I want to be wrong about this as well, but I believe having explicit entries for these definitions, to suppress the annotation, would cause the definitions to be grouped independently from the rest of the module, so if I want to avoid that, I need to document every member in order.</p>
<p>After inspecting Sphinx's sourcecode, I have news!
Is it good news?
Bad news?
It's news!</p>
<p>If I'm reading this right, I was incorrect in assuming that the <tt class="docutils literal">:annotation:</tt> directive would suppress the generated documentation of the value.
So the good news is that I don't have to try to do this, because the bad news is that I apparently can't!
News!</p>
<p>It's midnight and I'm not taking this well, possibly because I strained my shoulder earlier learning how to do creative stuff that doesn't involve typing.</p>
<p>I'm going to leave this as is and come back to it tomorrow, because I may want to sleep, but I <em>don't</em> want to admit defeat.</p>
<p>Good night.</p>
Weekly Roundup 2020-09-292020-09-29T04:00:00-04:002020-09-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-29:/weekly-roundup-2020-09-29<p class="first last">I think I might have low standards for "mystery".</p>
<ul class="simple">
<li>Wednesday: I complained about Sphinx, and devised workarounds for my complaints.</li>
<li>Thursday: I thought about potential changes I could make to my Cryptopas code, that wouldn't currently be worth it.</li>
<li>Friday: I sketched out my plans for Challenge 11, and justified them, because I felt they needed justification.</li>
<li>Saturday: I gloated a bit about the quality of my old low-comment code, from the perspective of maintaining/rewriting it years later.</li>
<li>Sunday: I ran into a problem with my Challenge 12 code. I assumed it was slow.</li>
<li>Monday: <a class="reference external" href="https://www.metalevel.at/prolog/nontermination">It was nonterminating</a>.</li>
</ul>
<p>Next week, I'm going to focus on tooling, documentation layout, general quality improvements.
I may try to figure out a mystery I discovered: under coverage, the Challenge 12 test runs significantly slower as a hypothesis test than a parametrized test, and the overall time does correlate with the number of examples, but the correlation should be linear, and 100 examples is nowhere near 100 times as long as 1 example, which implies to me some kind of massive constant term, <em>but</em> I'm not getting the same slowdown from a strictly more complex test signature that runs at an acceptable speed.
So it's not the test body, because the constant term is dominating.
But it shouldn't be hypothesis, because other tests aren't hitting this slowdown.
It's like every section of the test lifecycle is pointing accusatory fingers at every other section.</p>
Coding 2020-09-282020-09-28T04:00:00-04:002020-09-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-28:/coding-2020-09-28<p class="first last">That's not what "never is often better than <em>right</em> now." means...</p>
<p>... It would not have passed in a finite amount of time.
Turns out I messed up writing a helper function.
After giving that a few passes with breakpoints and assertions, I ran the code to discover...
That it's still slow by Hypothesis standards without Coverage.py, and it's quite slow under coverage.
To the point where I've elected to cut down on the number of explicit examples to a point where it's not really doing PBT, but I'm prioritizing development speed here.</p>
<p>Ugh, I really wish I knew why that test takes like six minutes under coverage.
Anyway, time to work on code quality.</p>
<p>Some code split out, and documentation improved.
I fixed up some minor loose ends from a few days ago.
I'm a little split between feeling like I ought to get more documentation in, and wanting to find checkers and metrics to mess with and perturb the code.</p>
<p>Regardless, it's late enough that I'm done for tonight.
I'm going to publish this and let the test suite run one last time.</p>
<p>Good night.</p>
Coding 2020-09-272020-09-27T04:00:00-04:002020-09-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-27:/coding-2020-09-27<p class="first last">This was... not as straightforward as I was expecting.</p>
<p>I'm not afraid to admit when I make mistakes.
One of them was passing 100 explicit examples of keys to my challenge 12 test.
I brushed my teeth after it hit that test, and it's still going as I write this.
I'll keep you posted.
I'll have to crank down the number of examples used in a normal test run, because this is, um, silly.</p>
<p>Now, some of this could be down to language runtime slowness, or inefficiency in my underlying code, but I think the two things I should really be looking into, in reverse order of importance, are:</p>
<ul class="simple">
<li>Investigating the algorithmic complexity of my attacker function.</li>
<li>Not running the code a hundred dang times, sheesh.</li>
</ul>
<p>Anyway, while the code (hopefully) came over relatively fine, it could have done with more comments.
There is a comment in there, that was very nice and helpful (though I need to think over its assumptions some), but the rest of the code I lightly updated is, um, dire.</p>
<p>And technically, I still don't know if it really worked, since it's still going, and the most I can say without results is that it's probably on the happy path, but the happy path could be coiled around on itself really nastily.</p>
<p>The test conked out after like an hour.
So, something is wrong.
I'll definitely reduce the number of examples and see what I get.</p>
<p>Hm.
One example is not exactly zippy, but, you know, I <em>can't</em> go lower.
I'm going to need to do some serious investigation of this stuff later, because this is too intimidating for me when I'm this sleepy.</p>
<p>Fingers crossed this passes in a finite amount of time.</p>
<p>Good night.</p>
Coding 2020-09-262020-09-26T04:00:00-04:002020-09-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-26:/coding-2020-09-26<p class="first last">I've got to say, this has <em>not</em> been an object lesson in the importance of commenting code. The old code with a few lines of comments actually <em>is</em> that obvious to me, years down the line.</p>
<p>I followed yesterday's plan, and everything worked perfectly.
I should savor this while it lasts, since it looks like the twelfth challenge is the last one I have a past version to crib from.
Quick notes on what to do next:</p>
<ul class="simple">
<li>I wrote an <tt class="docutils literal">Encryptor</tt> class to handle the eleventh challenge, and it can handle the twelfth challenge with no changes.</li>
<li>The only required parameter there is the key.</li>
<li>The <tt class="docutils literal">Encryptor</tt> class should be moved to an <tt class="docutils literal">oracle</tt> module.</li>
<li>I should have a module for my custom hypothesis strategies.</li>
<li>I should use <tt class="docutils literal">random</tt> with a constant seed to generate the key examples for the twelfth challenge.</li>
<li>Once I solve the twelfth challenge again, I should take a break from challenges and work really hard on quality and tooling.</li>
</ul>
<p>(Tooling and quality notes:</p>
<ul class="simple">
<li>I want to look into eliminating config files outside of <tt class="docutils literal">pyproject.toml</tt>. It looks like <a class="reference external" href="https://github.com/life4/flakehell">FlakeHell</a> will help with that.</li>
<li>I should finally see about getting coverage on the modules that underly all of this.</li>
<li>Document and reorganize before working on coverage, or I'll be sad.</li>
</ul>
<p>)</p>
<p>I wish I had something more substantial to say, but it really did work right out of the box.
So well, that I temporarily bumped up the verbosity and disabled output capturing to check that it was, in fact, running 432 explicit examples.
It turns out that telling a computer to do a bunch of relatively simple things, even in a high-level language, is fast.</p>
<p>Anyway, I'm confident I'll handle the twelfth challenge easily after a night of sleep, and then things will get interesting.</p>
<p>Good night.</p>
Coding 2020-09-252020-09-25T04:00:00-04:002020-09-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-25:/coding-2020-09-25<p class="first last">Weeks of coding could have saved me hours of planning!</p>
<p>Today, I didn't really touch the Cryptopals code, but I did make plans.
I'll quote them here in the hopes that they illuminate why I always end up putting special effort in challenge 11.</p>
<blockquote>
<p>Ingredients for random encryption:
short prefix
short suffix
key
cbc or ecb
if cbc, iv</p>
<p>Usage:
The library must define an ecb detection oracle
(posit: cannot conclude cbc if ecb not detected, could be other obfuscation)
oracle takes a Callable[[bytes], bytes], returns True if ECB, False otherwise</p>
<p>Construct the encryptor thus:</p>
<p>prefix: bytes (len in [5, 10])
suffix: bytes (len in [5, 10])
key: bytes (len = 16)
iv: Optional[bytes] (len = 16)</p>
<p>Constructing the plaintext stream requires a Chain SizedIterable</p>
<p>Can create a single class that bundles up all relevant data and assembles them when called, with minor polymorphism</p>
<p>Rationale for determinism:
I believe that the spirit of the challenge is in unpredictability and lack of influence, not the application of randomness at specific junctures per se.
If I write tests in terms of a range of input parameters, then it's still the case that the oracle must make judgments about code that it can only control the behavior of so far as feeding it input text.</p>
<p>If it does in fact become necessary to generate random ciphertext, then I can write a trivial wrapper around this class.</p>
</blockquote>
<p>As we can see, I'm trying to not follow the letter of the challenge, because that would involve writing automated tests that explicitly inject randomness, and honestly random tests that are implicitly random are bad enough.
I may look into an idea I had quite some time ago for some other code, to write tests as hypothesis tests that default to pre-specified deterministic behavior, but have the option to run a broader set of strategies.
It would be a little awkward, but I think the best way to handle that would be to opt into it by setting an environment variable to a truthy value and just bomb out of the "full hypothesis" session if it's falsy.</p>
<p>Good plan.
I'll see about getting to at least some of it by the weekend.
For now, I'd like to give myself a bit more time to wind down.</p>
<p>Good night.</p>
Coding 2020-09-242020-09-24T04:00:00-04:002020-09-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-24:/coding-2020-09-24<p class="first last">I should get back on social media or something to find someone to look over this stuff.</p>
<p>It feels like I'm getting into a nice rhythm of alternating between improving my Cryptopals codebase, and extending it to deal with new challenges.
After I got basic documentation done for some of the code, I started splitting out code from one of the more bloated modules.
After I was satisfied with that, I got through the tenth challenge.</p>
<p>For the eleventh challenge, I'm going to consider things carefully, because I feel like every time I've done the eleventh challenge, the details of plumbing things together and having deterministic tests are more involved than the challenge description makes them sound.</p>
<p>One thing the description is making me ponder, and I'll hold off on this until I see where the challenges are going, is rewriting things to go from creating streams based on other streams, to picking a "main" stream where applicable, and expressing the current stream types as a bunch of composable stream transformers.
The question of whether this makes sense to do for this project comes down to how many of the functions I'm going to have to write are going to look like "take a plaintext and produce a ciphertext with no other input".
Also, how efficiently I can actually apply those transformations to a concrete stream.</p>
<p>I believe that, if I don't peek ahead, the correct course of action is "build that function signature out of existing components".
And peeking ahead would probably just confuse me.</p>
<p>So, that's my plan for tomorrow.
And my plan for now: try to sleep.</p>
<p>Good night.</p>
Coding 2020-09-232020-09-23T04:00:00-04:002020-09-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-23:/coding-2020-09-23<p class="first last">Some elaborate-ass Karening to start with.</p>
<p>Sphinx gripes so far:</p>
<ul class="simple">
<li>Generic classes get their constructor signature given as <tt class="docutils literal">(*args, **kwargs)</tt>.</li>
<li>Type aliases (like other values) get expanded to their underyling value, even if that value is super gnarly.</li>
<li>No dedicated support for documenting type parameters, a feature that has been in the language for—I'm sorry, but not sorry enough not to say this—five years now. See also the first item.</li>
</ul>
<p>As you can imagine, these conspired to make documenting a group of generic classes that rely on a generic union referred to via type alias, somewhat unpleasant.
I had to approach this from several angles:</p>
<p>From <tt class="docutils literal">docs/conf.py</tt>:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">suppress_all_signatures</span><span class="p">(</span>
<span class="n">app</span><span class="p">,</span> <span class="n">what</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">signature</span><span class="p">,</span> <span class="n">return_annotation</span>
<span class="p">):</span>
<span class="k">return</span> <span class="p">(</span><span class="s2">""</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">setup</span><span class="p">(</span><span class="n">app</span><span class="p">):</span>
<span class="n">app</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s2">"autodoc-process-signature"</span><span class="p">,</span> <span class="n">suppress_all_signatures</span><span class="p">)</span>
</pre></div>
<p>From the first module I'm trying to type:</p>
<div class="highlight"><pre><span></span><span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">slots</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Repeat</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T_co</span><span class="p">]):</span>
<span class="w"> </span><span class="sd">"""Convert a (presumably finite) stream to a cycle.</span>
<span class="sd"> Parameters</span>
<span class="sd"> ----------</span>
<span class="sd"> [T_co] : TypeVar</span>
<span class="sd"> The yield type of the source iterable, and the instance.</span>
<span class="sd"> internal : :data:`SizedIterable`\\[T_co]</span>
<span class="sd"> The underlying Iterable that will be repeated.</span>
<span class="sd"> """</span>
</pre></div>
<p>The first code block just suppresses all signatures, because most of them run into at least one of the above issues.
To replace the (bad) generated signatures, I use parameter documentation in the class docstring.
(The docstring is in NumPy format, but I just did that to see what I thought of it.)
Before the parameters that actually get passed, I include the type parameters, in square brackets.
For now, they get explicitly called out as TypeVars; for working with type variables interesting enough to require documentation, I'll probably need a link to the TypeVar instance documentation in the type section.
(Putting the link in the variable name breaks things in a way that implied to me that I should stop pushing my luck.
I think I managed to make Napoleon generate invalid ReST.)
This isn't all-the-way-baked, since I'm working with a small sample of apparently rather eccentric code.</p>
<p>(Mostly unrelated, but I managed to invalidate some of the tutorials I found, by not having any <tt class="docutils literal">__init__</tt> methods in the codebase.
attrs is just that good.
In any case, you can't put documentation into what isn't there.)</p>
<p>Anyway, I should wrap things up, and get back into documenting this stuff tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2020-09-222020-09-22T04:00:00-04:002020-09-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-22:/weekly-roundup-2020-09-22<p class="first last">Let's not do that again.</p>
<ul class="simple">
<li>Wednesday: We ran out of internet.</li>
<li>Thursday: I messed around with a formerly-patented data structure.</li>
<li>Friday: Getting the internet back <em>totally</em> didn't go to my head.</li>
<li>Saturday: I switched back to the "Coding" category, because I got really into revisiting Cryptopals.</li>
<li>Sunday: I resolved to ry to improve the quality of my Cryptopals code.</li>
<li>Monday: I tried out my ideas, and liked them in practice, which was a relief.</li>
</ul>
<p>Next week, I'm going to try to put together basic commenting and documentation, possibly look into actually building docs.
I also want to experiment with some possible tooling improvements.
(Not tooling I write, but third-party tools.)</p>
Coding 2020-09-212020-09-21T04:00:00-04:002020-09-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-21:/coding-2020-09-21<p class="first last">Still needs comments and documentation.</p>
<p>My ideas turned out to be less of a boilerplate increase, and more of a boilerplate consolidation.
Specifically, the boilerplate got consolidated into the underlying libraries that other stuff is based on, so it's... basically fine.
The changes I made were focused around picking an interface for the streams I'm manipulating and sticking to it.</p>
<p>Previously, I was trying to pass around iterators, which is kind of fragile, because they can only be used once, and kind of silly, because currently everything is ultimately backed by one of Python's string types, which are reusable.
So, the new interface is based around iterables instead.
Now, every iterator is an interable in Python, but not vice-versa, so if that were all, I'd have only gained a little.
<em>But also</em>, I added the requirement that the iterables make a best effort to estimate their own size.
The details of this are a little involved, but thankfully not in a way that most code has to care about.
(It's basically a union of two custom protocols.)</p>
<p>The big cost of this approach is that it means I need to reimplement basic primitives like <tt class="docutils literal">map()</tt>, because stdlib map doesn't bother to estimate its own length, according to basic manual testing I did.</p>
<p>The thing I really like about the outcome is that it makes it really obvious where logic and flow control should go, to satisfy these constraints.
Because any fresh implementation of a stream transformation would require an implementation of the corresponding length estimation, it's "obviously better" to satisfy the requirements by breaking down complicated functions into simpler primitives with simpler reasoning.
Then, I can replace the implementation of generator functions with something that just glues together the corresponding primitives.</p>
<p>(This does have the slight possible disadvantage that tracebacks are going to mostly ignore these helper functions, so that the relationship between frames is a little magic.
But, I mean, it's not as bad as the time I figured out how to make tail-call elimination work with context managers.
Which, now that I bring it up, I think could have improved ergonomics.)</p>
<p>Anyway, I made a little more basic progress, which meant bringing in some third-party libraries.
I'm a little tempted to believe that I can implement the cryptographic primitives needed for this using my stream primitives, but that's not a good use of my time.
I'll just try and get caught up to my second attempt.
(My third attempt is just the vaporwave shitpost version of my second attempt.)</p>
<p>Good night.</p>
Coding 2020-09-202020-09-20T04:00:00-04:002020-09-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-20:/coding-2020-09-20<p class="first last">Getting seriously bitten by some of my typing choices, among other things.</p>
<p>I got through the sixth challenge in Cryptopals again, but the code quality is really slipping.
I'm going to have to step back tomorrow and work out how I want this to work.
I've got some ideas that I think are interesting, but they'd definitely increase the boilerplate.</p>
<p>I let this go late, so I'll have to stop here.</p>
<p>Good night.</p>
Coding 2020-09-192020-09-19T04:00:00-04:002020-09-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-19:/coding-2020-09-19<p class="first last">I should <em>really</em> comment this code...</p>
<p>Re: last entry: it was fine.</p>
<p>Anyway, switching back to this category for the Cryptopals stuff.
I'm organizing things in a way that makes more sense to me than some of my previous attempts.
Specifically, I'm putting the helpful functions front and center, while the higher-level code that consumes them to solve the challenges is further from the root.
This is in contrast to what I had with previous attempts, in which the top level was a (high-on-boilerplate) collection of challenge answers, plus a subpackage for "all of the lower-level stuff".
I think this way maks more sense, and it makes the imports less of a pain.</p>
<p>One thing I have been taking from previous attempts is snippets of code.
At some point, I'm going to have to review all of the code I have, and make sure I actually understand what I'm doing with it.
I'm right now at the point where things ramp up in the first set, so I should make sure I'm well-rested before I try to get that working with my current libraries.</p>
<p>Maybe once I do these in Python, I should try learning Julia and giving them a shot in that.
I also recently heard of a newish language called BQN that it might be interesting to try it with.
The programs from that would certainly probably be, like, shorter.</p>
<p>Good night.</p>
Diary 2020-09-182020-09-18T04:00:00-04:002020-09-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-18:/diary-2020-09-18<p class="first last">AHH! After ten thousand years, I'M FREE! It's time to CONQUER EARTH!</p>
<p>Late entry because I'm adjusting to going from virtually no internet, to rather a lot of internet.</p>
<p>I thought about my various projects, and decided that what I need to be satisfied right now, is a project that gets concrete results quickly.
To that end, I'm revisiting <a class="reference external" href="https://cryptopals.com/">Cryptopals</a>, starting from scratch and hoping to apply my knowledge of Python libraries a little better.</p>
<p>I did end up going a little wild on generality, writing the functions for the first challenge in terms of stream manipulation, with some... somewhat questionable levels of math, to cut down on special casing, hopefully.
This code is going to need some fiddly tests, that's for sure.</p>
<p>Anyway, I'll probably stick with this in the coming days.
We'll see.</p>
<p>Good night.</p>
Diary 2020-09-172020-09-17T04:00:00-04:002020-09-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-17:/diary-2020-09-17<p class="first last">"Apparently no longer patented" is a heck of a phrase, especially in the context of software.</p>
<p>This should be the last day.
In less than twelve hours, we should be all set.</p>
<p>Anyway, I spent some time today working on the data structure I mentioned yesterday, the zzStructure (which is apparently no longer patented).
I didn't get much implemented relative to my plans, but there's a little more in there than there was before.</p>
<p>After that, I returned to the game dev stuff from... a few months ago, apparently, and worked on test coverage.
I forget exactly what I was doing, but test coverage is generally helpful and I was up for, so I did it.
It took some slight effort to exercise enough patience, since the current network throttles mean that I can't use the internet for <em>anything else</em> while it's updating its caches.</p>
<p>We'll see what I'm up for later; I've got to wrap things up now.</p>
<p>Good night.</p>
Diary 2020-09-162020-09-16T04:00:00-04:002020-09-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-16:/diary-2020-09-16<p class="first last">I anticipated this would happen, and referred to it then as "maximum underdrive".</p>
<p>The data plan has run dry, and switched to "technically enough internet to do things".
It's... weird, seeing images load interlaced.
Attempting to stream audio is pointless, and I haven't even tried to stream video.
Fortunately, this is a temporary condition, we almost have internet back.</p>
<p>I should wrap this entry up quickly, because it will take several minutes to post.</p>
<p>Anyway, I spent some time today going over trying to design an emulator for some of <a class="reference external" href="https://en.wikipedia.org/wiki/Ted_Nelson">Ted Nelson</a>'s ideas, because hands-on experience is way more valuable for such different models, than just reading over documentation.
I'm thinking that's what I'll mess with this week, at least in the short term.</p>
<p>And, I am cutting this quite close.</p>
<p>Good night.</p>
Weekly Roundup 2020-09-152020-09-15T04:00:00-04:002020-09-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-15:/weekly-roundup-2020-09-15<p class="first last">Not as much progress as I'd like, but whatever.</p>
<ul class="simple">
<li>Wednesday: I resolved to try not to change everything around when trying to convert Coverage to output Daikon traces.</li>
<li>Thursday: I tried copying things over piecemeal.</li>
<li>Friday: No entry to speak of, because I felt really sick.</li>
<li>Saturday: I concluded that trying to pick and choose which bits of functionality to copy over was too many decisions with not enough information, even if I probably don't need most of it.</li>
<li>Sunday: So, I copied everything over.</li>
<li>Monday: I started taking notes on the code, and how it relates to execution and tracing.</li>
</ul>
<p>Next week, I'm going to look for a change of pace for a bit.
We're almost through rationing our internet, and I'm getting antsy.</p>
Daikon Tracer 2020-09-142020-09-14T04:00:00-04:002020-09-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-14:/daikon-tracer-2020-09-14<p class="first last">Exactly like Coverage.py except for all the ways it shouldn't be.</p>
<p>Just hung out today and did other stuff, but I took a few notes on how Coverage.py works, for adapting it into the tracer.
This is probably going to require a more methodical approach.
I think I'll want to change gears for a bit before coming back to this.</p>
<p>I don't think I have much more to say, again, so I'm not going to force the matter with myself.</p>
<p>Good night.</p>
Daikon Tracer 2020-09-132020-09-13T04:00:00-04:002020-09-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-13:/daikon-tracer-2020-09-13<p class="first last">Just take the whole thing, and incrementally change it. That probably makes more sense?</p>
<p>We went shopping today, so I didn't think too much about the Daikon tracer, but I did think about it a little, and I concluded that copying stuff over piecemeal doesn't really make sense.
So, I've copied over the entire codebase, done light find-and-replace changes to it (very light), and my plan now is to informally follow the execution paths and figure out what changes need to be made.</p>
<p>Not much more to say on that, and I want to work on other stuff for now.</p>
<p>Good night.</p>
Daikon Tracer 2020-09-122020-09-12T04:00:00-04:002020-09-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-12:/daikon-tracer-2020-09-12<p class="first last">"Copy, paste, and make minor changes" has gotten over-extended.</p>
<p>I didn't work on the tracer yesterday, for what I assume are obvious reasons.
Looking over it now, I see that I'd gotten up to the point in the <tt class="docutils literal">do_run</tt> function where it's validating the arguments in the context of using multiprocessing.
I was thinking about this some yesterday, and now I'm remembering some trains of thought that didn't get too far.</p>
<p>Basically, it comes down to whether the options for controlling the covered files are relevant.
At first, I didn't think so, but now I think that's wrong.
If the intent of trace analysis is to detect invariants in code that the user controls, then it makes sense to restrict the scope of measurement to files specified by the user.</p>
<p>I'm still taking things somewhat easy, but I believe what I should do next, is sketch out high-level descriptions of what Coverage.py does, so I can figure out where the tracer needs to diverge.</p>
<p>One design decision I was considering, is to kind of duplicate the way Coverage.py creates, updates, and processes a database as an intermediate format.
A Daikon tracer doesn't have the same diversity of output formats, but if I'm reading the documentation correctly, the list of list types has to come quite early on, and I'd like to populate that dynamically according to the execution data.
There's also the question of how actually to handle concurrency, and I assume "give each copy of the tracer its own output file, and aggregate them in a post-processing step" makes sense.</p>
<p>I'll think about it some tomorrow.
Or take it easy.
Either is good.</p>
<p>Good night.</p>
Diary 2020-09-112020-09-11T04:00:00-04:002020-09-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-11:/diary-2020-09-11<p class="first last">Ugh.</p>
<p>Can't write an entry.</p>
<p>Feel awful.</p>
<p>Trying not to throw up.</p>
<p>Good night.</p>
Daikon Tracer 2020-09-102020-09-10T04:00:00-04:002020-09-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-10:/daikon-tracer-2020-09-10<p class="first last">I really hope I don't end up needing the setup.py layout.</p>
<p>Nothing really interesting to report yet.
Still just copying stuff over from Coverage.py.
In a few more days, I should have enough scaffolding copied over to start thinking about the trace function, but I want to make an effort to consider as few things as possible at one time.</p>
<p>Also, it just occurred to me that my whole "Well, optparse says not to use it so I don't want to use it" thing doesn't quite make sense, insofar as I like Click, and last I checked, Click is based on optparse.
I read, but do not remember, the whole explanation for why they use optparse and not argparse.</p>
<p>Anyway, that doesn't terribly matter to the tracer, because I want to have the same level of external dependencies as Coverage.py.</p>
<p>I'm getting tired and I'd like to wrap things up.</p>
<p>Good night.</p>
Daikon Tracer 2020-09-092020-09-09T04:00:00-04:002020-09-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-09:/daikon-tracer-2020-09-09<p class="first last">For once I've got to be humble about whether changing everything is a good idea. <em>For once</em>.</p>
<p>I've looked into Daikon's documentation, and Python tracer code, and concluded that I want to write a tracer for Daikon with a minimal/useless feature set, and refine it to gather more data.
So, to start with, I just want something that properly sets up a tracer function, and runs code.
I've concluded that the best way to accomplish that is to just copy the execfile module from Coverage.py, and probably much of the rest of Coverage.py.</p>
<p>Looking over the source code, I see that my next task is to psych myself up to use optparse in spite of its deprecation.
I'm tempted to try and port things to argparse, but I'd need a better understanding of both modules to be able to accomplish it.
I can at least recognize the danger here: that there is some subtlety of behavior that is different between the libraries, that would produce mysterious bugs.</p>
<p>I've started working on porting stuff over, but I don't have a good sense of the right order to work on this in, so I just kind of started copying over from the top down.
This might be wrong, we'll see.</p>
<p>In any case, in the coming days, I'll work on getting things together enough to set up a stub trace function.
For now, I should wrap up.</p>
<p>Good night.</p>
Weekly Roundup 2020-09-082020-09-08T04:00:00-04:002020-09-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-08:/weekly-roundup-2020-09-08<p class="first last">Week one of "Oh dang, I suddenly can't use the internet much."</p>
<ul class="simple">
<li>Wednesday: I got my phone's hotspot to work, and thought more about literate programming.</li>
<li>Thursday: I took another look at Exercism and Leo.</li>
<li>Friday: I figured out what I'd like to use Leo for, and started using it a bunch.</li>
<li>Saturday: I thought of other stuff Leo would be good for, while noticing (what I perceive to be) some of its limitations, mainly that I have no idea how to figure out how to do anything I don't already know.</li>
<li>Sunday: We mooched off of the in-laws' internet and I downloaded a bunch of ebooks and websites.</li>
<li>Monday: I kept on taking it easy, except I wondered if there was any way to make Zoom throttle its data. Initial investigation indicates: probably not.</li>
</ul>
<p>Next week, I have, among other things, offline copies of the documentation for Daikon and Python, and a financial incentive to be online as little as possible.
I had better make something out of all of the stuff I've stockpiled.</p>
Diary 2020-09-072020-09-07T04:00:00-04:002020-09-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-07:/diary-2020-09-07<p class="first last">In the "looming specter" phase of vacation.</p>
<p>Another day of taking it easy.
Things are going to get much more hectic for me in a few days, so I'm absolutely going to take this.</p>
<p>I'm still really dreading starting work with the wifi hotspot, because the daily Zoom calls are likely to eat up this month's bandwidth nigh-instantly, unless I figure out ahead of time how to turn down every setting I can.
Ideally I'd have no video whatsoever except for screen-sharing.</p>
<p>I suppose there's nothing more for me to do right now.
I just need to remember to look into that when I get the chance.</p>
<p>I don't know, I run the numbers, and it looks like this should be totally doable, but just one bad day could wipe everything out.
It sucks.
It sucks much less than a lot of things, but it still sucks.</p>
<p>I'll try to wait one more day before worrying too hard about it, though.</p>
<p>Good night.</p>
Diary 2020-09-062020-09-06T04:00:00-04:002020-09-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-06:/diary-2020-09-06<p class="first last">Absolutely flush with ebooks.</p>
<p>I'm just taking things easy for now.
We've got internet to mooch off of right now, so I'm working on stockpiling PDFs and website mirrors for offline reading later.
I've got a pretty good haul lined up, so I'm also working on stuff in Leo.</p>
<p>I want to have more to say, but I don't have more to say.
I've just get to take this time to recharge before a rough bit-over-a-week.</p>
<p>Good night.</p>
Diary 2020-09-052020-09-05T04:00:00-04:002020-09-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-05:/diary-2020-09-05<p class="first last">Still adjusting to the current situation...</p>
<p>I'm getting more and more ideas for stuff that works well with Leo.
It continues to be great for the Scrivener project I adapted, and I think it has some promise for restarting Drawabox, but I don't see myself using it for any programming projects, at least not directly.
It might work as a replacement for my use of <a class="reference external" href="http://todotxt.org/">todo.txt</a> in some projects, I'm not sure.</p>
<p>It's a combination of, it's really great at representing multiple views of how a concept or task is relevant, a little iffy at manipulating those representations, and when I read the documentation for anything relating to code, I get hopelessly confused until I try it myself, which means I first need to figure out what to try and how to try it.
It kind of feels like Leo is pushing a bunch of paradigms in implementation that I'm unfamiliar with, so I can't really judge their worth.</p>
<p>I still think it would be nice to get Leo to a point where it could substitute for my current usage of Sublime Text, or more of my former usage of Scrivener, but I don't know yet all the things that would need to change, and which of those are configuration changes, and which are code changes.</p>
<p>(For example, how do I make it change autocompletion behavior based on the active language?
I don't want python completions in HTML text.)</p>
<p>Anyway, I'll be looking into that as I feel like it, but it's at least proving useful for now.</p>
<p>Good night.</p>
Diary 2020-09-042020-09-04T04:00:00-04:002020-09-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-04:/diary-2020-09-04<p class="first last">No, I won't go into any more detail on the project.</p>
<p>The connection metering checkbox is feeling like a bit of a placebo right now, so I'm typing this up offline.</p>
<p>I found a use case that is getting me through the basics with Leo: converting my old Scrivener projects into Leo projects.
I had to do this by reading the XML and translating it into Leo's layout, because the export I did months ago didn't quite work, and also discarded important information.</p>
<p>I don't know how replicable this will be with any other project, since this is a case where I specifically wasn't using any rich text formatting.
However, this is the project I was most interested in picking back up, so, I've got an in on using Leo, and I'll see if it seems applicable to anything else.</p>
<p>I wonder how much effort it would take to port my syntax highlighting and color schemes from Sublime Text.
I'll look into that while this publishes.</p>
<p>Good night.</p>
Diary 2020-09-032020-09-03T04:00:00-04:002020-09-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-03:/diary-2020-09-03<p class="first last">Nice heart-stopping moment earlier before I figured out how to meter my laptop's connection.</p>
<p>Still unpacking, but making progress.</p>
<p>Recently, I decided to look back into <a class="reference external" href="https://exercism.io/">Exercism</a>, which I've previously gotten a very short way into on the Erlang and Elm tracks.
I basically reviewed everything I did on the Erlang track, and updated a few of my solutions, then went a little further with some of the side exercises.
(I also joined <em>a bunch</em> of tracks, some of which I'm going to wait until I've upgraded my laptop to look into.)</p>
<p>Not much to say about that, besides that I'm pretty skeptical about the quality of some of my solutions.
I ought to review the community solutions later.</p>
<p>I also looked into separating my repository metadata project into distinct functional areas, and sketching out possible data types for it.
I think I'm going to need to find someone to discuss this project with, because there are a lot of things I want to accomplish, and I'm not sure I've totally nailed down the objectives.</p>
<p>After I publish this, I'm going to mess with <a class="reference external" href="https://leoeditor.com/leo_toc.html">Leo</a> some more.
I've bounced off it a few times because I wasn't sure where to start, but the testimonials seem really interesting.
(Plus it'd be pretty cool to be using a Python-scriptable text editor with a free license.)</p>
<p>I'll get on that now, for maybe the next hour or so.</p>
<p>Good night.</p>
Diary 2020-09-022020-09-02T04:00:00-04:002020-09-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-02:/diary-2020-09-02<p class="first last">That could have gone better.</p>
<p>We moved.
This post is brought to you in part by, my phone, which had a seriously glitchy hotspot at first, but now it's fine, I think.</p>
<p>We're just barely unpacked right now, since I spent the whole day crashing until my wife crashed, at which point we switched, and then I got about as keyed up as I could, under the circumstances.</p>
<p>Anyway, I ended up thinking some more about that minimal literate programming code I wrote/rewrote, and what I want my style to be.
It turns out one thing that bothers me is when the origin of variables is concealed by the weave.
I rewrote a block of code as a function, moved the chunk to the top level, and replaced the original substitution with a function invocation.
I much prefer the result, because it allows for more local reasoning.</p>
<p>Trying to apply this principle in other ways suggests some possible features.
In particular, "run a chunk through a filter, such as lexically sorting and deduplication".</p>
<p>And I just realized that the practical effect of how I want to use that feature is to define a bunch of little modules in a file, specifically to tangle them into a single file.
This has given me feature envy for Lua's <tt class="docutils literal">require</tt> system all over again.</p>
<p>Although, if I set the file up to tangle into <em>different</em> files, then I wouldn't need the deduplication feature because I could use small modules.</p>
<p>It just occurred to me that I'm having all of these thoughts in the context of a sub-100-line script.
It would behoove me to look into using this with one of the large codebases I have lying around.</p>
<p>Not happening right now, though.
We are both exhausted.</p>
<p>Good night.</p>
Weekly Roundup 2020-09-012020-09-01T04:00:00-04:002020-09-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-09-01:/weekly-roundup-2020-09-01<p class="first last">Wish us luck...</p>
<ul class="simple">
<li>Wednesday: I listed a bunch of things I'd like to look into when I'm less stressed. When exactly that is, remains to be seen, see subsequent entries.</li>
<li>Thursday: With the weather nicer, I wrote up some notes on cell.</li>
<li>Friday: I realized that the bundle of functionality I've been calling "cell" might initially work better if the different parts are developed in isolation.</li>
<li>Saturday: I was all burnt out and tired, so I ported a small Python 2 script to Python 3, with the caveat that the script is generated by running itself on a source file. Simpler than it sounds, I was basically able to go through it on autopilot.</li>
<li>Sunday: I had resolved to have less screentime. And failed.</li>
<li>Monday: I came to the realization, that so far as transferring internet service in a timely fashion, I messed up, hard. We're going to be rationing the mobile data plan for the next 2+ weeks.</li>
</ul>
<p>Next week, I will try to avoid going feral from the reduced internet.</p>
Diary 2020-08-312020-08-31T04:00:00-04:002020-08-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-31:/diary-2020-08-31<p class="first last">This is going to be a rough two weeks. At least we'll have a thermostat that does something.</p>
<p>Did not do a great job cutting down on screentime.
But whatever.</p>
<p>I'm currently in the "bargaining" phase of getting my internet transferred.
Hopefully that all works out in a way that's satisfactory.
NOPE.</p>
<p>So, things are going to be pretty boring for a few weeks.
Maybe deeply distrusting my backup plans' ability to stream video will get me to cut down on screen time.
One way or another, we'll make do.
Something something this wasn't a thing my parents had to worry about when I was young, ouch my hip, something something.</p>
<p>Yeah, not happy with this situation, but I'm planning the best I can to deal with it, so I guess I have to accept whatever happens, because I can't change things any further.</p>
<p>Good night.</p>
Diary 2020-08-302020-08-30T04:00:00-04:002020-08-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-30:/diary-2020-08-30<p class="first last">Need to be squinting at a screen <em>less</em>.</p>
<p>More moving prep today.
I should probably figure I won't get much else done until we're moved into the new place and I've had time to get settled.
I should also work on cutting down on screen time.</p>
<p>I'm too tired to think of anything else, so, wrapping up now.</p>
<p>Good night.</p>
Diary 2020-08-292020-08-29T04:00:00-04:002020-08-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-29:/diary-2020-08-29<p class="first last">Fun thing I learned/realized: apparently ">" truncates a file <em>before</em> any commands on the same line have a chance to read it.</p>
<p>I've been pushing myself too hard at work recently, so I'm burnt out and tired.
I should be able to somewhat recover from that over the next week, but for now, I just zoned out porting a small python script for literate programming from Python 2 to Python 3, and gave it a few other improvements while I was at it.</p>
<p>I think this might end up being useful for my repo metadata and state analysis stuff, because making the analysis tools understand the literate programming syntax and properly determine whether to classify a diff as touching "test" or "source" is the hardest version of that problem I can imagine, since it seems totally valid to me to have a literate programming source file that interleaves test and implementation of functionality.</p>
<p>I think those were all the words I had in me after the rest of today.</p>
<p>Good night.</p>
Diary 2020-08-282020-08-28T04:00:00-04:002020-08-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-28:/diary-2020-08-28<p class="first last">Going to need to make a kanban board for this stuff, or something.</p>
<p>I'm revisiting some of my design assumptions for cell.
I think I've got a baseline for a better design, but I haven't fully nailed down how it's going to work.
Because of this vagueness, I've decided to put some of cell's functionality on the back burner (basically, see if I can separate out the template concept from the rest and do the rest first).
For now, I'm working on listing all of the functionality that the various utilities need from a top-down perspective, and I think I've got everything except the testing aspect of cell.
I'm going to need to either find or reconstruct those flowcharts.</p>
<p>I'm also watching over some backup stuff.
I'm trying to switch providers, and the initial backup to the new one is super slow.
Hopefully it won't end up taking the full time until I <em>have</em> to switch, but right now I'm not confident.</p>
<p>Anyway, I'm tired and I want to wrap up.</p>
<p>Good night.</p>
Diary 2020-08-272020-08-27T04:00:00-04:002020-08-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-27:/diary-2020-08-27<p class="first last">At least I'm not stewing in my own sweat now.</p>
<p>The weather is now tolerable.
And I did other moving prep and got a headache.
So mostly, what I managed was to write down some of my ideas for cell.
I think to figure this out, I'm going to need to take some time, probably after the move, to run through some hypothetical workflows and figure out what would be really hard to implement, and hopefully find a good alternative.</p>
<p>I'm pretty tired, so I don't have anything else to articulate.</p>
<p>Good night.</p>
Diary 2020-08-262020-08-26T04:00:00-04:002020-08-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-26:/diary-2020-08-26<p class="first last">Doing things called on account of soggy heat.</p>
<p>So, everything is warm and gross right now.
Rather than trying to focus on anything that really demands my concentration, I'm going to try to list the tutorials I've been looking into.</p>
<ul class="simple">
<li>I started following the <a class="reference external" href="https://www.ponylang.io/">Pony</a> tutorial, but when I went to compile it, I found that <tt class="docutils literal">ponyc</tt> is too cutting-edge for my laptop currently, and I'm going to need to do an OS upgrade. It's probably fine, I just want to get the move totally squared away before I risk putting my main machine for interacting with landlords temporarily out-of-commission.</li>
<li>I started messing with <a class="reference external" href="https://www.pixelvision8.com/">Scratch</a>, because maybe it would be nice to do game dev where I'm not counterproductively challenging myself to reinvent foundational concepts, and also to have tutorials that are both soothing, and respectful of my time. I'm stepping away from this for now because I want to do a little more design work up front than what I have now.</li>
<li>I briefly looked at the tutorial for the <a class="reference external" href="https://www.pixelvision8.com/">Pixel Vision 8</a>. No real reason for it to be brief, aside from the fact that I've been ping-ponging around between things.</li>
</ul>
<p>Speaking of which, I've got <a class="reference external" href="https://processing.org/">Processing</a> installed now, and no concrete plan for doing anything wth it.</p>
<p>I also thought some more about my experimentation with <a class="reference external" href="https://lmms.io/">LMMS</a>, and given the extremely constrained nature of the first thing I tried to do with it, I think the best thing I can do with that is try to adapt it into a chord loop.
Also, learn to write with chord loops.</p>
<p>I'm trying to remember if there was anything else.</p>
<p>Oh yeah, also pondering whether it would be worth it to try getting into niche card games.
If I'm looking at it like that, probably not, but we'll see.</p>
<p>Oh yeah, I was also taking another look at <a class="reference external" href="https://builtoncement.com/">Cement</a>.
Another look that nearly immediately left me feeling the same as last time.
What that inspired me to do, and I haven't done this yet, just be inspired, is to design Cell to have templates for different kinds of projects, in line with the monorepo concept, so I can be like "okay, here's what's in here: a utility library, and, say, flask and cement apps that use it".
Hypothetically speaking something like that.</p>
<p>Also also, I've got <a class="reference external" href="http://leoeditor.com/">Leo</a> installed as well.
I'm probably physically incapable of looking into all of these things in depth in the next few weeks, but I'm feeling up for giving a new text editor a try.</p>
<p>(Also also also, we watched the Rankin/Bass Hobbit movie, and the backstory made me want to try again to learn to play <a class="reference external" href="http://www.bay12games.com/dwarves/">Dwarf Fortress</a>.
"Why, <em>I</em> could manage a dwarven palace until its dramatic and untimely demise!")</p>
<p>Well, this post is a disorganized mess.
So, it's an honest reflection of how I feel in this dang heat.
So excited for the heat to break in the next few hours or so.</p>
<p>(I'll hopefully come back to this later and maybe actually do a thing.)</p>
<p>Good night.</p>
Weekly Roundup 2020-08-252020-08-25T04:00:00-04:002020-08-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-25:/weekly-roundup-2020-08-25<p class="first last">Someone just dump silica gel packets all over my prone body, please.</p>
<ul class="simple">
<li>Wednesday: I did drastic refactorings, because full test coverage baybee~</li>
<li>Thursday: I planned a garbage collector.</li>
<li>Friday: I got the garbage collector working.</li>
<li>Saturday: I proved that the garbage collector worked. I should note that I got this done in three days worth of spare time because I didn't try too hard to make this "something I would be comfortable expecting someone to use for a serious purpose." And also I had full test coverage so I don't have to think about regressions, I can know.</li>
<li>Sunday: I hurt.</li>
<li>Monday: I thought more about the repo metadata thing, and continued to try to give away a couch. That's still available as of this writing. EDIT: Not any more.</li>
</ul>
<p>Next week, I won't do much tomorrow because the sun is a deadly laser.
Anyway, I want to work on specifying the repo metadata stuff.
I've also got tutorials for a whole bunch of things that I want to try out.</p>
Diary 2020-08-242020-08-24T04:00:00-04:002020-08-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-24:/diary-2020-08-24<p class="first last">The couch is fine, we just want to get rid of it before we move to a place without space for it.</p>
<p>Feeling better today, though the pizza we split for dinner is trying to have something to say about that.</p>
<p>I was doing stuff today that meant I couldn't get super into my super-project that tries to combine my various projects for dinking around with data from other tools based on repository layout.
Less than half an hour ago, I started trying to turn my notes from after last post into something resembling a specification.
One problem I'm having at this early stage is separating and naming the different parts.
Like, I need a structure that maps relative paths within the repository to subproject metadata, but how do I want to handle different kinds of project?
I guess I'll have to sketch out a hypothetical hybrid monorepo.
One thing that's annoying about considering this is that implementing the basic cell predicates for a Rust project seems much fiddlier than for a Python project.
Like I guess the code has to somehow determine whether the changed lines for a file are entirely inside a test block or not?
I'm going to hope there's a crate for that, at least.</p>
<p>I'll have to consider this stuff when I'm better rested.
Failing that, in a few days.</p>
<p>Good night.</p>
Diary 2020-08-232020-08-23T04:00:00-04:002020-08-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-23:/diary-2020-08-23<p class="first last">This post took a while to publish because I was mustering the energy required to put the computer down.</p>
<p>Current status: tired, in pain, sick, and I didn't do the specification work, in part due to taking a bunch of time to adult.</p>
<p>I want to wrap this post up ASAP and try to do the stuff I was talking about doing yesterday.</p>
<p>Good night.</p>
Crafting Interpreters 2020-08-222020-08-22T04:00:00-04:002020-08-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-22:/crafting-interpreters-2020-08-22<p class="first last">I'm thinking of trying to rename them with a mad-science theme.</p>
<p>I've added some instrumentation and confirmed that the garbage collector can accomplish <em>something</em>.
Thinking over this, I concluded that I want some native functions to interact with the garbage collector, and represent assertions in Lox code.</p>
<p>I don't want to work on that now, so I worked out some comparisons between the features of cell, limit-coverage, and mutmut-runner (which I think needs a rename).
There are many underlying tasks that they all or most need to do, and some that would probably be helpful where not strictly necessary.
(For example, I think I'd much rather run mutation tests in a temporary clone of a repository.)
I was trying to plan this, and went too general, so I think what I should do is lay out exactly what these tools currently do, and work on converging their underlying operations.</p>
<p>I'll get on that tomorrow, when I'm hopefully less tired from helping move furniture.</p>
<p>Good night.</p>
Crafting Interpreters 2020-08-212020-08-21T04:00:00-04:002020-08-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-21:/crafting-interpreters-2020-08-21<p class="first last">"It did too much, so it was broken. Now it's not broken, and I can't tell if it's doing anything."</p>
<p>I tentatively believe the garbage collector is working, having hit one minor hiccup along the way.</p>
<p>I'm tentative about it because I haven't properly instrumented the code to make sure it's accomplishing anything.
It's certainly getting called, and doing stuff, and I want to believe there's no reason it should fail, but I want certainty for this.</p>
<p>The minor hiccup I hit was due to the fact that, until like half an hour ago, the interpreter code didn't have a proper stack, and instead relied on Python locals to store some of the frame references.
Which meant that those scopes were invisible to the marker.
I put a stack on my State struct, wrote a property to expose the same value as the old "index" field, removed the methods that manipulated that field directly, and rewrote the consumers, in a way that I think makes more sense, so that's nice.
All of the tests pass with the same level of coverage as before, so if I broke anything, it's really subtle.</p>
<p>The breakage in that last paragraph manifested as a failure in garbage collection, due to an earlier garbage collection pass that occurred inside a function call.
Because the dynamically enclosing scope was only referred to in Python locals, it didn't survive collection, and after the function returned, it had an invalid scope reference.
I don't want to think about what would have happened if I were trying to do this in C.</p>
<p>This is all very educational, but most people, myself included, probably shouldn't be hand-rolling garbage collectors for any serious purpose.
I can't say anything about anybody else in particular, but this feels to me like code that should be left to a library when possible.</p>
<p>Anyway, I'll try to develop some kind of strategy for garbage collection that's better than "as often as I think it's possible", and tests for it, and then I want to work on tooling, like I've been talking about.</p>
<p>Anyway, I want to wrap up now; my head kind of hurts.</p>
<p>Good night.</p>
Crafting Interpreters 2020-08-202020-08-20T04:00:00-04:002020-08-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-20:/crafting-interpreters-2020-08-20<p class="first last">Pretty sure "remake the universe without the garbage" was the stated goal of several Pokémon antagonists.</p>
<p>I've sketched out a plan for implementing garbage collection in my Lox interpreter.
I skipped ahead to the garbage collection chapter in Crafting Interpreters, for inspiration.
I can't draw directly from it, due to the following points of difference:</p>
<ul class="simple">
<li>Implementation language</li>
<li>Memory representation of values</li>
<li>Update strategies</li>
<li>Degree of implementation completeness</li>
</ul>
<p>However, it did still help, because of general inspiration, and the considerations of "when and how often do we want to run the GC?" are equally relevant.</p>
<p>My initial plan for this, and this is trying to work with the rest of my design, is to, instead of recreating the state variables but with one less entry each time, I would just traverse the state variable data to populate mutable versions of the state variables, then convert those to an immutable form, and replace them in.
By planning for this approach, I was able to remove some lines I'd added due to anticipating using a different approach.</p>
<p>Looking over the structure of all of this, I think the way I want to implement this is with mutators around the top-level containers, because none of the items in the container get mutated.
I'm going to need to sketch out some of the details by hand, but my current thinking is that I can write helper functions that modify the mutators, and iterate over the referenced items using some methods and helpers I need to write, but <em>only</em> if the item was not already in the mutator.</p>
<p>I think that'll work, but we won't know for sure until I flesh out the design and actually try to implement it.</p>
<p>My basic plan right now is to get this stuff implemented, write any tests I need to get coverage back up, and then change gears to tooling.
It seems to me that limit-coverage and my mutation testing helper should be able to share config logic.
And possibly cell as well.
I'll be really excited if it ends up going that way.</p>
<p>Good night.</p>
Crafting Interpreters 2020-08-192020-08-19T04:00:00-04:002020-08-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-19:/crafting-interpreters-2020-08-19<p class="first last">*Try to follow composition tutorial* "Ugh" *Bend my music theory knowledge in ways it was not meant to be bent* "Ooo"</p>
<p>There is one line uncovered, and I do not care about it.
I made several hundred changes to the code base as part of refactorings today, and it's so, so satisfying.
I think the next thing I want to look into is designing a garbage collector for this implementation.
That'll be quite a lot of work.</p>
<p>Anyway, I also took some time to mess with LMMS without a tutorial.
I experimented with applying a bunch of YouTube videos and vague memories of high school senior year to sketching a little chord progression.
It sounds good to me, which kind of implies that the natural analysis of it is <em>not</em> what I used to come up with it.</p>
<p>And it is past midnight, this is late, let's turn it in.</p>
<p>Good night.</p>
Weekly Roundup 2020-08-182020-08-18T04:00:00-04:002020-08-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-18:/weekly-roundup-2020-08-18<p class="first last">Massive increase in coverage, probably some redundant tests.</p>
<ul class="simple">
<li>Wednesday: I wrote tests, and they didn't pass. I made them pass.</li>
<li>Thursday: Ditto.</li>
<li>Friday: It continued. I also looked into some tooling I might try to use for... something.</li>
<li>Saturday: I took a break from writing tests to try to learn to use LMMS.</li>
<li>Sunday: I managed to add coverage without finding embarrassing bugs.</li>
<li>Monday: I got coverage on every line I care about.</li>
</ul>
<p>Next week, I'm going to work on refactoring, and maybe cut down on cyclic dependencies?
I consider the various indented imports I have to be a code smell.</p>
Crafting Interpreters 2020-08-172020-08-17T04:00:00-04:002020-08-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-17:/crafting-interpreters-2020-08-17<p class="first last">Coming up on the end of the current push with the interpreter.</p>
<p>Limited coverage is over 98.7%.
23 lines are uncovered, and they should be of no consequence.
I'll work on eliminating them during the refactor.</p>
<p>I got wiped out by some stuff we did today after I got coverage up, so I'll just leave it at that.
I'm thinking I'll take a break tomorrow and get back into this the next day.</p>
<p>Good night.</p>
Crafting Interpreters 2020-08-162020-08-16T04:00:00-04:002020-08-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-16:/crafting-interpreters-2020-08-16<p class="first last">Sure is boring./This quality is what all true programmers strive for.</p>
<p>Limited coverage is up around 97%.
I'm done for tonight, but this is good progress.
Another few days, and I can do some refactoring.</p>
<p>Nothing really exciting to report.
I didn't hit any bugs this time.
The biggest stumbling block I'm hitting is the fact that some of the code paths I'm not covering are uninteresting and require tests that bypass the external interfaces.
For a sec I thought I had a way around that, but on further reflection I currently don't.
I'll just have to see if I come up with a nice rewrite during the refactors.</p>
<p>For now, I'd like to wrap things up.</p>
<p>Good night.</p>
Diary 2020-08-152020-08-15T04:00:00-04:002020-08-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-15:/diary-2020-08-15<p class="first last">I continue to be not to be trusted to follow directions.</p>
<p>I wasn't really up for increasing the test coverage on my Lox interpreter today, because the next natural section to work on covering is the various ways that a C-style for-loop can be written, and I'm a snob when it comes to for-loops, apparently.
I'll hopefully be up for it tomorrow, but we'll see.</p>
<p>In any case, I guess what I actually did do today was mess around with a <a class="reference external" href="https://lmms.io/">LMMS</a> tutorial.
I have gotten to a slightly rocky bit as a result of not following the tutorial completely; I diverged from the tutorial either because:</p>
<ul class="simple">
<li>Other resources explicitly recommended taking the opposite choice to the tutorial I'm mostly following;</li>
<li>I have a <em>problem</em>;</li>
</ul>
<p>Anyway, I'm not really in love with the sound of what I've got so far.
I assume this isn't due to the tutorial, but some combination of personal musical taste, lack of experience choosing samples, and leaving the Beat + Bassline Editor playing on loop while I entered all of the percussion.
I'll come back to that later as well, sometime when I'm better rested, and able to relate what the tutorial says to what I've got in front of me.</p>
<p>Good night.</p>
Crafting Interpreters 2020-08-142020-08-14T04:00:00-04:002020-08-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-14:/crafting-interpreters-2020-08-14<p class="first last">Recommendations for test coverage: "100% coverage is unealistic." My uncovered statements: "NoThInG iS fOrBiDdEn AnD eVeRyThInG iS pErMiTtEd."</p>
<p>I've hit eighty-something percent limited coverage, and the new lines of coverage <em>continue</em> to turn up embarrassing bugs.
A few more days of this, and I should be ready to do some refactoring that will cut down on verbosity in exchange for some somewhat eccentric syntax, and then take coverage all the way to 100%, and work on mutation testing.</p>
<p>I've also been looking into Daikon, and I'm significantly less enamored of my original idea tha the first thing I'd try would be to write a front-end myself so I could use it with code that interests me.
The documentation on how front-ends work seems to mix together descriptions of ideal implementations, descriptions of good-enough implementations, explanations of how those implementations can be good enough, descriptions of formats as they are or were, and of formats as they are no longer or might yet be.
For an example of that last one, currently <a class="reference external" href="http://plse.cs.washington.edu/daikon/download/doc/developer.html#Dataflow-hierarchy">Dataflow hierarchy</a> mentions an <tt class="docutils literal">EXCEPTION</tt> program point type that is mentioned nowhere else on the page.
Looking at the implementations some, it <em>looks</em> like it's just supposed to always be an <tt class="docutils literal">EXIT</tt>, which, sort of makes sense.
Regardless, I'd rather throw it at some LLVM output or something.
(It also sounds like a custom build of Python would work, but that's a custom build of Python.
Redoing the work for every interpreter version I care about.
A Python library defining a cusstom tracer function could get potentially every version I care about, and probably almost work on versions I don't know about yet.)</p>
<p>Anyway, I'm just about gone.
I should wrap up.</p>
<p>Good night.</p>
Crafting Interpreters 2020-08-132020-08-13T04:00:00-04:002020-08-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-13:/crafting-interpreters-2020-08-13<p class="first last">limit-coverage is sort of like New Game Plus for coverage metrics</p>
<p>I worked through a few more modules.
Still really enjoying the degree of focus I get from knowing that each test module is only responsible for one source module.
I've had fix a few howlers of bugs as a result of, just, it turns out I never tried running most of the new code.
As such, I've had to make code changes, with varying degrees of gracefulness.</p>
<p>I've got it up to about 60% coverage now, and I'm clearly hitting code that was never exercised before.
The tests I have written at this point are probably sufficient to get extremely high coverage just by pasting them around indiscriminately, but I'd prefer to paste them around discriminately.</p>
<p>I am spacing out on anything else to add, so I guess I should stop.</p>
<p>Good night.</p>
Crafting Interpreters 2020-08-122020-08-12T04:00:00-04:002020-08-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-12:/crafting-interpreters-2020-08-12<p class="first last">Less than two weeks later, and I have determined that this isn't a working Lox interpreter.</p>
<p>Now that I'm motivated to add tests to specific test modules (it's how I prefer to work, apparently), I spent some time increasing coverage, one module at a time.
I got through a few modules, and then I got to the expression module, which includes stuff like dot notation, including with superclass access.
Now, I guess I didn't actually write tests for this before, because when I did here, I ran into numerous issues, and the last issue I hit tonight</p>
<blockquote>
as I wrote the code for the book, I ran into a couple of subtle bugs where the resolver and interpreter code were slightly out of sync. Tracking those down was difficult.</blockquote>
<p>... Yep.
That certainly seems to be the case here, where the number of levels of parent environment is not matching.</p>
<p>Wow, that was arguably not actually the problem.
I thought for sure I was mis-directing the layers of environments related to "this" and "super", but it turns out my implementation of method binding was, roughly speaking, dynamic instead of lexical.
Which I don't know what that works out to, semantically, but it's not good.</p>
<p>Anyway, I'm happy I got the tests passing, but there's much more work to do.
Hopefully it won't involve quite as many instances of totally untested code being howlingly wrong.
I'll see about that tomorrow.
For now, I should wrap up.</p>
<p>Good night.</p>
Weekly Roundup 2020-08-112020-08-11T04:00:00-04:002020-08-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-11:/weekly-roundup-2020-08-11<p class="first last">Area man disturbed both by the unpredictable experience and the predictable effects of the passage of time.</p>
<ul class="simple">
<li>Wednesday: I freaked out about how disjointed the passage of time has felt for the last *checks notes* five months, apparently.</li>
<li>Thursday: I thought some more about programming language design.</li>
<li>Friday: I messed up a random muscle that I apparently use for virtually everything.</li>
<li>Saturday: The muscle was still messed up.</li>
<li>Sunday: I finally updated limit-coverage.</li>
<li>Monday: I started using limit-coverage with most of my recently-developed repos.</li>
</ul>
<p>Next week, I'm going to work on improving the Lox interpreter coverage, since limit-coverage (as intended and expected) dropped it by about 40 percentage points.</p>
Coding 2020-08-102020-08-10T04:00:00-04:002020-08-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-10:/coding-2020-08-10<p class="first last">"This is probably fine."</p>
<p>I mostly took it easy today, and then quickly set up limit-coverage on a bunch of my projects.
It turns out they weren't <em>all</em> set to use it out-of-the-box, since it was arbitrarily limited to Python 3.7 and later, and the Lox interpreter is written against Python 3.6 (so it can use PyPy).
One patch release later, and it's arbitrarily limited to Python 3.6 and later.
Python 3.5 is scheduled to end-of-life in a month or so, so this is probably fine.</p>
<p>Anyway, enabling it on the virtual tabletop project, I'm not sure if that actually did anything, I can't remember if those few lines were missing or not before.
Enabling it on the Lox interpreter cut coverage in half, so I'll just have to see about refactoring the tests to get it back up.
When that's done, I'll feel good about the various rewrites that I have in mind.
When I want mutation testing, I should probably look over the changes I made to limit-coverage and see if any of them apply to my weird, over-engineered runner script.
(Which I should probably rewrite in Python, and convert to an installable library.)</p>
<p>One other thing I was considering was, inspired by <a class="reference external" href="https://jeanstack.substack.com/p/how-to-use-ais-to-find-bugs">JeanStack</a>, writing a Python front-end for <a class="reference external" href="https://plse.cs.washington.edu/daikon/">Daikon</a>.
I need to read over the documentation some more to get a better idea of how much of a pain that would be, but I <em>think</em> that <a class="reference external" href="https://coverage.readthedocs.io/">Coverage.py</a> indicates that a trace function could more-or-less handle extracting the relevant information.
For now, I'll focus on stuff I have a little more experience with.
And, for now for now, I should wrap up.</p>
<p>Good night.</p>
Coding 2020-08-092020-08-09T04:00:00-04:002020-08-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-09:/coding-2020-08-09<p class="first last">Most representative commit message of today goes to "Fix a nonsense"</p>
<p>I mentioned yesterday that I wanted to make <a class="reference external" href="https://pypi.org/project/limit-coverage/">limit-coverage</a> work with the repository layout that I've used for a few projects now.
I put in the effort to update it, and I got it basically working, but I did end up regressing with respect to one of my repository layouts in a somewhat weird way.
I decided to just accept the reduction in functionality and <em>slightly</em> reorganize the repository.
The only ongoing problem I'm having there is that I'm having the same nox session for that repo pass locally, and fail every time in Travis.
I'm going to have to remember to check again in the morning and see if it does any better, because no matter how many times I try, Travis doesn't act like my machine.</p>
<p>While I was in limit-coverage, adding documentation and doing a bunch of manual tests, I kind of had to reflect on my habit of having really poor automation around testing and verifying the tools I write to help test and verify everything else.
I think one of the factors there is that these tools tend to work with the implementation or internal format of other tools.
This is certainly the case with limit-coverage, and its more horrifyingly-invasive predecessor, divide-and-cover.
(limit-coverage programmatically deletes some rows from a sqlite database and supports every version of <a class="reference external" href="https://coverage.readthedocs.io/">Coverage.py</a> starting from 5.0a6. divide-and-cover was basically every "here's why subclassing to add functionality is bad" example rolled into one, and needed updates to avoid regressing functionality added in Coverage 4.5, which was just one minor version later than it was originally written against.)</p>
<p>I'm going to have to think about how to address this.
I mean, the answer is "write more tests", but I look at the tests that I'd have to write and feel really discouraged.
Tests against this functionality basically need fake source code repositories and coverage data to work with.
I suppose I could just write a bunch of toy repos that each exercise a little bit of functionality...</p>
<p>Amyway, the other thing I can do to find issues is use this more widely, which now I can do, since it should work on every repo I've done active development against recently.
I'll get to work on that tomorrow, unless I decide to focus on something else.</p>
<p>Good night.</p>
Diary 2020-08-082020-08-08T04:00:00-04:002020-08-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-08:/diary-2020-08-08<p class="first last">Too tired to explain how tired I am...</p>
<p>Okay, I'm clearly not dealing well with the muscle stuff.
I was tired all day, and I didn't really do anything about it.
I'll see what I can do over the weekend; hopefully "nap a lot" helps.</p>
<p>Thinking about what would help with projects, and I think adapting <a class="reference external" href="https://pypi.org/project/limit-coverage/">limit-coverage</a> to the repository layout I'm starting to use would help a lot.
...
Documentation and tests wouldn't go amiss, as well.</p>
<p>I'm going to wrap up for tonight because I am <em>so tired</em>.</p>
<p>Good night.</p>
Diary 2020-08-072020-08-07T04:00:00-04:002020-08-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-07:/diary-2020-08-07<p class="first last">oww, oof, my [MUSCLES]</p>
<p>I sat badly for a lot of today, and now my chest is messed up.
It's hard for me to focus on writing, so I'm just going to take it easy.</p>
<p>I messed around with Portal 2's level creator a bit, and managed to make a level that's not really bad, but I did find it kind of uninspiring.
That's progress, so I'll take it.</p>
<p>Ugh, I want to write more, but it's so hard to focus like this.
I'm just going to wrap up for tonight and hope that lying down normally will fix my muscles.</p>
<p>Good night.</p>
Programming Language Design 2020-08-062020-08-06T04:00:00-04:002020-08-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-06:/programming-language-design-2020-08-06<p class="first last">Something tells me I need to write <em>a lot</em> of pseudocode and then, through parsing, cause it to retroactively become code.</p>
<p>I'm still trying to get a handle on access control in this language.
I think I've figured out one hurdle, which is that all types need an access control specification.
So, in addition to "a shared vector of shared" and "an exclusive vector of exclusive", there can be "a shared vector of exclusive" and "an exclusive vector of shared".
The ones where the access controls match are pretty easy to reason about, as is "exclusive vector of shared".
That last just means that the individual entries can't be edited, but they can be added or removed from the vector.
Shared vector of exclusive is more troublesome.
It sort of makes sense to have as one possible way to implement "tweak every element of the vector, but don't touch the vector itself", but a shared reference can be cloned, which means that if we naively do what I think makes sense, we can have multiple consumers trying to get exclusive locks on the same reference.
I'm leaning towards "it shouldn't be possible to get multiple references doing that", since a synchronization-based approach would still be fundamentally unpredictable.</p>
<p>I think this means that I can't have trivial auto-derives for copy/clone, which is fine, and some kind of "derive" macro wouldn't work for container types that are specifically designed to expose more access to their items.</p>
<p>Thinking about this has revealed some kind of asymmetry in my mental model, where I'm assuming that a shared reference to a type with exclusive access to a field casts to a shared reference to that field, while a shared reference to a container with exclusive access to its items results in exclusive access to the items.
I think this is useful for the degree of semantic range it permits, but actually implementing this requires some means of opting out of the standard logic.
I think this is the kind of thing that <tt class="docutils literal">unsafe</tt> is for in Rust, but I don't know if there's any direct equivalent to what I'm describing, for Rust Vectors.</p>
<p>Anyway, one thing I'm trying to figure out about access controls, is how much non-determinism I want to allow.
Like, I could imagine a primitive that's just "release the exclusive lock so some other thread of execution can have it", but if you do a release and a reacquire, what can you expect to have happened during the time it was released?
I suppose there could be some signalling layer indicating work to do and work done, but some kind of standard notification system that directly ties into the ownership system seems much more robust, and I think equally expressive.
Like, I could imagine just passing the reference into some kind of worker or scheduler, and waiting for it to complete.
If there's concurrent work to be done, this does imply some kind of spawning or multi-scheduling system.</p>
<p>I think the things I need to review for this are <a class="reference external" href="https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/">Notes on structured concurrency</a>, and <a class="reference external" href="https://without.boats/blog/notes-on-a-smaller-rust/">Notes on a smaller Rust</a>.
I'll definitely be considering "structured concurrency", but it's worth emphasizing that my current vision for Toad drops enough expressive power relative to Rust that it cannot be the "smaller Rust" that Saoirse describes.
That post is of interest because most of the ideas that apply to "smaller Rust" also apply to Toad.
I would describe my thinking for Toad thus: "Many high-level languages have some form of 'box' for their high-level types, that simplifies access control and includes metadata relevant to, for example, garbage collection. I want to experiment with tweaking the capabilities of the 'box'. For situations where Python is 'fast enough', can I design a language with similar expressive power, but that makes it harder to write bugs around concurrent data access?"
Realistically speaking, if I'm working on my own, the answer is probably "no", but I'm curious to see what I can accomplish.</p>
<p>Good night.</p>
Diary 2020-08-052020-08-05T04:00:00-04:002020-08-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-05:/diary-2020-08-05<p class="first last">I have lost the ability to get the hang of any day whatsoever.</p>
<p>I ended up taking it easy today.
I don't remember what I actually <em>did</em>, but I assume it was taking it easy.
I can't believe it's only Tuesday.</p>
<p>And when it's Friday, I'm shocked.
It's like every day, I have the strongest impression of what it was like a week ago, so Tuesday is like it came after a string of Tuesdays, and Fridays feel like the six days between pass really quickly.</p>
<p>Really could have done with a competent federal response to the pandemic, like, several months ago.</p>
<p>I don't know, some of the stuff I've been sinking my time into lately, I wrapped up the really focus-intensive parts today, so maybe I'll have more focus for other stuff.
Maybe.</p>
<p>Anyway, the time I'm using to write this post is passing really quickly, so I should wrap up ASAP.</p>
<p>Good night.</p>
Weekly Roundup 2020-08-042020-08-04T04:00:00-04:002020-08-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-04:/weekly-roundup-2020-08-04<p class="first last">Kind of curious to see how much will have to change for me to be satisfied with my Lox code base.</p>
<ul class="simple">
<li>Wednesday: I got a rough version of the resolver working.</li>
<li>Thursday: I finished the resolver except for classes, so I started working on classes.</li>
<li>Friday: I finished the first chapter on classes.</li>
<li>Saturday: I finished the second chapter on classes.</li>
<li>Sunday: I poked at the code base, added some tests. Mostly I focused on, what do I want out of a new language? And started sketching stuff for a new project.</li>
<li>Monday: I got some "actual code" written for the new language. Quote marks included because the syntax is in <em>a lot</em> of flux.</li>
</ul>
<p>Next week, I'm going to try to nail stuff down for the new language, and work out both where I think I want the language to end up, and a minimal proof of concept I can build on.
I probably won't try implementing anything until I've cleaned up the Lox interpreter code base, and pulled out parts of it for reuse.</p>
Programming Language Design 2020-08-032020-08-03T04:00:00-04:002020-08-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-03:/programming-language-design-2020-08-03<p class="first last">Currently, I'm calling it "Toad", for reasons that I'll leave mysterious for now.</p>
<p>I realized that, rather than Rosetta Code, <a class="reference external" href="https://projecteuler.net/">Project Euler</a> would probably be a better starting point, because it offers challenges in a specific order, and there are multiple ways to approach them.
I messed around with the first challenge, and this got me inspired enough to draft a bunch of rough ideas for standard library-y stuff.
However, there was one thing that I punted on that I want to try to work out in this post.</p>
<p>I kind of punted on mutability.
When I write code, I'm very in favor of immutability, but I feel like this project could do with mutability; I'm not sure why.
Rust-style static lifetimes are cool, but I'm not ready to try to implement them.
As I see it, that means my choices are "dynamic ownership", "Python-style mix", or "everything mutable".
Speaking as someone who writes Python like <tt class="docutils literal">attr.evolve(obj, field=obj.field + <span class="pre">(new,))</span></tt> (or <tt class="docutils literal">attr.evolve(obj, field=obj.field.append(new))</tt>), I don't want a Python-style mix.
I think some kind of ability to "lock" data strctures would be helpful for correctness, though it might turn out kind of fiddly in practice; we'll see.</p>
<p>Here's what I sort of imagine, and this might be totally off...
Let's swipe some ideas from Rust.
We could think about the default version of a type as "owned".
Given a value of a type, there must be exactly one reference to that value by that type.
From an owned value, we can take "shared" and "exclusive" references.
Now as I say this, in a dynamic ownership kind of situation, it's pretty annoying to be constantly destructuring your compound data, so accessing fields or parts of a container should somehow default to shared references, with an option to get out an exclusive reference instead.
I'm not quite sure what an explicit destructuring would look like, but these ideas kind of imply it has to exist.</p>
<p>Now, accesses and iteration and such might need to be defined in terms of reference types, so that iterating over an exclusive reference produces exclusive references, and shared produces shared.
It'd be cool to have this kind of correspondence "for free", but I don't know if that's actually possible.
One thing that I kind of decided here is that there isn't "destructuring iteration".
I think I'm fine with that.</p>
<p>I'll have to adapt the code I have so far to reflect these ideas, and see if it still makes sense.
I think it might be possible to get <em>some</em> correspondences for free.
Basically, and I'm not totally confient in this idea, but I'm not sure what could go wrong, associate trait definitions with types of reference, so that there could be separate "index" implementations for shared and exclusive references.
As I think about this, I realize that I'm wanting implementations for shared references to act as fallbacks for exclusive references.
That seems a little iffy.
According to my intuition, it shouldn't hit a situation where, given several choices, it somehow picks "the wrong one", but weird, gnarly edge cases can pop up seemingly anywhere.
I'll need to consider this while being better-rested.</p>
<p>Good night.</p>
Programming Language Design 2020-08-022020-08-02T04:00:00-04:002020-08-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-02:/programming-language-design-2020-08-02<p class="first last">Just staring at some code I copied from Programming in Lua and going "Hm. Hmm. Hmmmmmmmmmm."</p>
<p>Today, I worked a little on improving test coverage for my Lox implementation.
I made a little progress.</p>
<p>Besides that, I sketched out ideas I might try for applying what I learned to creating a language of my own.
I'm pretty good at implementing these kinds of small language specifications (especially if I'm not actively working against the design of the reference implementation), but actually writing a specification is much more work.
For now, I tried sketching out some ideas.</p>
<p>These ideas include:</p>
<ul class="simple">
<li>Lua-style linear syntax. The fact that Lua doesn't really need semicolons or line breaks to divide statements seems pretty neat to me.</li>
<li>Rust-style lifetimes. I gave up on this when I tried sketching an iterator implementation, and realized that I'd need both "unsafe" and an equivalent of Rust's "Copy" trait to make it even vaguely ergonomic. On reflection, maybe I would have had more luck with a Python-style generator than a Lua-style iterator, but I don't want to go that way right now.</li>
<li>Separating the different kinds of inheritance. I didn't get too far sketching this out, but I think this is what I want to focus on.</li>
</ul>
<p>Thinking about how to sketch out these ideas, I wasn't really sure before, but it just occurred to me that I might be able to get inspiration from <a class="reference external" href="http://rosettacode.org/wiki/Rosetta_Code">Rosetta Code</a>.</p>
<p>I'll have to look into that later.
For now, I want to wrap things up.</p>
<p>Good night.</p>
Crafting Interpreters 2020-08-012020-08-01T04:00:00-04:002020-08-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-08-01:/crafting-interpreters-2020-08-01<p class="first last">Whoo. Two weeks later, and I have, probably, a working Lox interpreter.</p>
<p>Crafting Interpreters has two chapters on classes.
I've gotten through the second chapter.
Test coverage is still not great, only 85%.</p>
<p>I forget when I planned to take a break.
Maybe it would help to lay out the changes I want to make:</p>
<ul class="simple">
<li>100% test coverage</li>
<li>Good mutation coverage</li>
<li><dl class="first docutils">
<dt>Various ergonomics improvements:</dt>
<dd><ul class="first last">
<li>Convert tokens to <tt class="docutils literal">enum.IntFlag</tt>, then convert the helper functions that process them to use bitwise operators instead of sometimes sets, sometimes not.</li>
<li>Convert the Visitor protocol to a fluent interface</li>
<li>Generally convert tuple returns to fluent returns or iterators</li>
<li>Audit some of my weirder divergences from JLox, such as various one-off methods</li>
<li>Reorganize the modules to make importing less fraught</li>
<li>Implement garbage collection for the arenas. ("Wait, you wrote this in Python and it doesn't have garbage collection?" I wrote it using immutable data structures, because once you have those worked out, it's much easier to reason about the code. As a side effect, every value in the interpreter lives until it gets overwritten, and there's no such thing as a delete.)</li>
</ul>
</dd>
</dl>
</li>
</ul>
<p>I don't think there's any urgent need for me to either work on this, or deliberately not work on it, so I'll see what I feel like doing tomorrow, but I should probably try focusing on other things first.</p>
<p>One thing that it would be nice to have before the mutation testing is a version of my <a class="reference external" href="https://pypi.org/project/limit-coverage/">limit-coverage</a> tool that works with the whole "monorepo" layout that I seem to be going with for a bunch of projects now.</p>
<p>(... "I have several mono[repo]s.")</p>
<p>Riffs aside, that would be nice because one of the things that made mutation testing against <a class="reference external" href="https://pypi.org/project/structured-data/">Structured Data</a> bearable was that each module had an associated test module, so when there was a mutation, that meant that I could declare that catching the mutation with a non-associated test module didn't "count", and therefore skip running all of them.</p>
<p>Maybe I should do the "module reorganization" step before "mutation testing".
Anyway, that's a question for another day.</p>
<p>Good night.</p>
Crafting Interpreters 2020-07-312020-07-31T04:00:00-04:002020-07-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-31:/crafting-interpreters-2020-07-31<p class="first last">With being implemented that quickly, it can't be <em>that</em> classy...</p>
<p>Crafting Interpreters has two chapters on classes.
I've gotten through the first chapter, although I haven't done a great job of keeping up with test coverage.
I should be able to finish up the other chapter in a few days, and then I can work on stuff like increasing coverage and improving ergonomics.</p>
<p>I anticipate that it'll be somewhat of a bumpy ride, since I haven't exercised the new code yet.
It can't be totally wrong, since it does typecheck, but there are probably a bunch of weird edge cases I haven't noticed yet.</p>
<p>It's midnight and I have nothing else to say, so, there we go.</p>
<p>Good night.</p>
Crafting Interpreters 2020-07-302020-07-30T04:00:00-04:002020-07-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-30:/crafting-interpreters-2020-07-30<p class="first last">It's so much easier to write when something goes horribly wrong...</p>
<p>The resolver code seems to be all set, so now I'm working on implementing classes.
This might take a while.</p>
<p>I wish I could come up with more to say for these entries, but my day has been taken up by various technical issues that I don't want to write about, and I'm getting a consistent handle on adapting between the intended code and my code.</p>
<p>So, there aren't really any interesting puzzle-y things to write up for now.</p>
<p>One thing that occurred to me to check was how many statements the codebase has, according to coverage measurements.
Looks like 1295, though that can be massaged and altered in various ways, probably by as much as a hundred statements if I really dedicated myself to golfing it.
I should not.</p>
<p>Anyway, it's too late already.</p>
<p>Good night.</p>
Crafting Interpreters 2020-07-292020-07-29T04:00:00-04:002020-07-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-29:/crafting-interpreters-2020-07-29<p class="first last">Thanks to Mypy for catching some absolute nonsense.</p>
<p>I've got the basic parts of the resolver seemingly working.
One concern I have to keep in mind is that I'm not sure how I want the resolution to work in the repl.
I'm thinking the simplest solution is to just have some kind of incrementing thing that gets put in the tokens to disambiguate them.</p>
<p>Anyway, I'll work on that later.
Trying to think if there's anything else I want to mention...
There are some simplifications to my changes that I want to make, but I'm so close to getting through the basic funtionality, and I'd rather push through with it and clean stuff up later.</p>
<p>I'll try out the repl support stuff while this posts.</p>
<p>Good night.</p>
Weekly Roundup 2020-07-282020-07-28T04:00:00-04:002020-07-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-28:/weekly-roundup-2020-07-28<p class="first last">Early posting because I'm trying to do a backup, and the external drive is <em>really</em> finicky.</p>
<ul class="simple">
<li>Wednesday: I found a bug when I was trying to add coverage, so that's nice.</li>
<li>Thursday: I thought about the stuff that I'll have to add to my Lox implementation.</li>
<li>Friday: I finished implementing function calls. (I'll have to revisit them later.)</li>
<li>Saturday: I made some progress on getting ready to move.</li>
<li>Sunday: I came up with a plan for implementing the resolver.</li>
<li>Monday: I started implementing the resolver.</li>
</ul>
<p>Next week, I'll try to wrap up my Lox implementation.</p>
Crafting Interpreters 2020-07-272020-07-27T04:00:00-04:002020-07-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-27:/crafting-interpreters-2020-07-27<p class="first last">I'd been thinking for a bit "This doesn't make sense." Turns out it doesn't, and the reason is that I misread a function definition.</p>
<p>Yesterday, I worked out a general plan for getting the resolver written, and today I started working on it.
I didn't get too far on the actual resolver bit, because I got somewhat hung up on some jank in the typing system while laying the groundwork for it, and then I got just a few visitor methods implemented before I realized that I'd implemented function calls slightly wrong, and I'll either need to fix them, or replicate the breakage in the resolver.
I figured I'd rather fix the implementation, because the wrongness is basically a case of unintentionally diverging from JLox, as opposed to all of the intentional divergences.</p>
<p>One area where I'm not diverging, for now, is in maintaining the shadowing behavior.
The behavior is justified with "Shadowing is rare and often an error so initializing a shadowing variable based on the value of the shadowed one seems unlikely to be deliberate."
That rings a little false to me, but maybe that's just because I've read so many Rust tutorials.
In any case, I'm keeping the behavior of "error on shadow" for now, because the name of a local cannot be visible to consumers, which means that allowing shadowing doesn't open up expressiveness, so I'll stick with what the book says, for once.
(Although, this post indicates that I'm going for at least twice, but whatever.)</p>
<p>I'll probably take a different tack with the language concept sketches that I'll hopefully be working on next week, but that's then and this is now.
And now is late.</p>
<p>Good night.</p>
Crafting Interpreters 2020-07-262020-07-26T04:00:00-04:002020-07-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-26:/crafting-interpreters-2020-07-26<p class="first last">"I wonder if it's a sign that, whenever I attempt something like this, the scope of the changes spirals wildly out of control. ... Naaaah."</p>
<p>I spent a little time today figuring out the plan for implementing the resolver for Lox.
(To be real, I spent more of the day watching Portal-related speedruns.)
Now, one thing that I notice happening with my "bad-at-following-directions" take on tutorials, is that I eventually pile on so many changes and quick hacks, that it becomes impractical to follow the precise details of the tutorial so closely while keeping my reworks, and I have to refactor it to either accord with the tutorial, or what appeals to me aesthetically.
I don't recall ever taking the former option, but it's there.</p>
<p>Anyway, the "reckoning" for the Lox tutorial wasn't too bad, at least I don't think it was.
The basic point of friction is that I'm tracking state very differently from the tutorial, and that means that, while the JLox resolver works by injecting state onto an Interpreter instance, my codebase has all of the mutable state essentially concentrated into a single new class, which updates via <tt class="docutils literal">attr.evolve</tt> rather than mutation.
So, to implement the resolver, I have to have it take a state, and put data on the state.</p>
<p>There are a bunch of improvements I want to make first, that are slightly more complicated than the corresponding improvements to JLox.
Once I make those improvements, I should be ready to implement the resolver and move on.
For now, I want to wind down and cool off.</p>
<p>Good night.</p>
Diary 2020-07-252020-07-25T04:00:00-04:002020-07-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-25:/diary-2020-07-25<p class="first last">I've earned some rest.</p>
<p>Things are looking in good shape now.
I was kind of tired today, so I didn't end up doing anything that I want to write about.
I think we've got plans set for all of the big stuff, so now I'm free to work on prioritizing the stuff that I enjoy doing.</p>
<p>I thought maybe I'd come up with something else to put in this post, but I didn't.</p>
<p>Good night.</p>
Crafting Interpreters 2020-07-242020-07-24T04:00:00-04:002020-07-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-24:/crafting-interpreters-2020-07-24<p class="first last">Not sure if I'm actually reading the chapters at this point.</p>
<p>I've gotten up through implementing function calls for Lox.
Next up is the resolver, then classes and inheritance, then I'm going to take a break, and when I come back to it, work on improving coverage and testing, and figuring out profiling.
Looks like I want to look into <a class="reference external" href="https://vmprof.readthedocs.org/">vmprof</a> for that when the time comes.</p>
<p>I hope I have more to say about doing this on-the-fly port when I come back to it later.
The most I've got right now is, it's kind of shocking how well things map between the different versions.
I'm converting mutation-based Java code to Python code using persistent data structures, and somehow, even when I jump ahead, I end up with code that's bug-for-bug compatible with the code at the time that the book is explaining the bugfix.</p>
<p>Anyway, one thing I want to mess with while taking a break is designing a toy language that I find more interesting.
Maybe try mixing linear syntax, like Lua's, with built-in inheritance and affordances for static analysis.</p>
<p>Good night.</p>
Crafting Interpreters 2020-07-232020-07-23T04:00:00-04:002020-07-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-23:/crafting-interpreters-2020-07-23<p class="first last">I don't think I'll be able to keep up this pace after I catch up to where I was, but eh.</p>
<p>I've got environments mostly done.
There are some loose ends related to the fact that my on-the-fly redesign (of course I have an on-the-fly redesign) in some sense "wants" garbage collection, and is somewhat set up to support it, but does not currently have it.
Currently, namespaces just always exist, and all the changes is the index into an arena.
Ideally, there should be some kind of ref-counting happening, but I think it would be prudent to wait to get to closures before messing with that.</p>
<p>Along with environments, I've got support for most kinds of statement currently in the grammar, and I also fixed up the support for some of the stuff that I added in response to the challenges.</p>
<p>I also also made some improvements to testing coverage.
There'll be some un-fixable shortcomings until I get through the next few chapters, but the coverage is still much better.
Anyway, it's late and hot.</p>
<p>Good night.</p>
Crafting Interpreters 2020-07-222020-07-22T04:00:00-04:002020-07-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-22:/crafting-interpreters-2020-07-22<p class="first last">"Debugging is like being the detective in a crime movie where you are also the murderer." "... and the victim"</p>
<p>I'm approaching parity with the Lua version of the Crafting Interpreters stuff, which means that I'm going to have to slow down soon.
First, though, I have to get moving; I'm working on adding coverage, and I'm seeing some behavior that makes no sense to me at all.
Until I can figure it all out, I'm kind of stuck, because I want to at least understand where the weird behavior is coming from.</p>
<p>I found it.
I'd failed to decorate one of my classes with attrs stuff, so the code that consumed it was crashing because the attributes it was looking for didn't exist.
(And this wasn't bubbling out in a meaningful way becase the test was already expecting failure.)
I can't imagine how much grief that would have caused me if I hadn't worked it out now.</p>
<p>The way is clear to work on Environments, but I think it would be a bad idea to do that now.
I'll work on it tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2020-07-212020-07-21T04:00:00-04:002020-07-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-21:/weekly-roundup-2020-07-21<p class="first last">Again, my response to programming tutorials is nothing if not consistent.</p>
<ul class="simple">
<li>Wednesday: I complained about my back and my posting schedule, then thoughts about the projects I could pick back up.</li>
<li>Thursday: I got more stuf cleaned up for the move.</li>
<li>Friday: I picked Crafting Interpreters back up, this time with a strategy of "Let's write this in typed Python, an see how far I can push that, first."</li>
<li>Saturday: I wrote tests for my Crafting Interpreters code, finally.</li>
<li>Sunday: I jumped the gun a bit, and ported code from my previous attempt. It's probably fine.</li>
<li>Monday: I considered a minor implementation issue, which I have since addressed.</li>
</ul>
<p>Next week, I'm going to probably mess with Crafting Interpreters stuff some more, and maybe work on planning a new posting schedule.</p>
Crafting Interpreters 2020-07-202020-07-20T04:00:00-04:002020-07-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-20:/crafting-interpreters-2020-07-20<p class="first last">I need a rubber duck with a label that says "Internet" on it.</p>
<p>Today, I hid from the heat, and did some more work porting Lox interpreter stuff to Python.
I decided to move on in the book, to the actual interpreter logic, and getting it ported to Python is a little tricky.
The problem isn't strictly expressing the logic of the Lua or Java version, it's expressing the logic in a way that's visible to static analysis.</p>
<p>Fortunately, just complaining about the problem in general terms turned out to provide all the insight I needed to deal with the problem.
However, I do see that there's trouble on the horizon I'll need to deal with later:
The Lua version manages to define the expression <a class="reference external" href="https://en.wikipedia.org/wiki/Visitor_pattern">visitor</a> so that it passes through additional arguments.
I'm not sure how to express that with function signatures in Python.
When I was first thinking about this, I kind of punted it like "Oh, well, it an act like it's just operating on the first argument, but actually it's allowed to return a callable, so the signature can be something like ExprVisitor[Callable[[Environment], Tuple[Environment, LoxObject]]]" and maybe these callables are, like partial applications of private methods?
I don't know, I shouldn't rush into implementing this stuff, so I'm going to sleep on it, and also flee this terrible warmth.</p>
<p>Good night.</p>
Crafting Interpreters 2020-07-192020-07-19T04:00:00-04:002020-07-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-19:/crafting-interpreters-2020-07-19<p class="first last">"This is going slow. I'll just crib from my past self's extensive yet cryptic notes."</p>
<p>Heck of a day today; I'm more wiped out than I usually am around this time.
I did have some time to work on the Crafting Interpreters stuff.</p>
<p>I... ended up getting a little impatient, and porting logic from my Lua version, rather than following the book.
This means that there's random advanced and optional functionality stuck in here, relative to what the book is telling me to do.
This would be pretty bad for a concrete deliverable that is supposed to directly accomplish specific tasks, but I choose to approach this as an opportunity for additional learning.</p>
<p>I think I'll call it a night.
I'm pretty tired now, and I got <em>plenty</em> done today.</p>
<p>Good night.</p>
Crafting Interpreters 2020-07-182020-07-18T04:00:00-04:002020-07-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-18:/crafting-interpreters-2020-07-18<p class="first last">At some point I should try to fix my syntax highlighter for ReST. It has some weird gaps that I'm pretty sure it inherited from its previous version.</p>
<p>I got up through the end of chapter for of Crafting Interpreters with my Python version.
It too a little finagling, and the result is kind of awkward (as a result of how I wrote the code), but it works, at least according to the tests I wrote.
It's nice having tests; I never got experienced with any testing libraries in Lua like I did with <a class="reference external" href="https://docs.pytest.org/">pytest</a> and <a class="reference external" href="https://coverage.readthedocs.io/">coverage.py</a>.</p>
<p>Anyway, I guess I don't have much more to say.
It's late, and the basic lexer for Lox isn't too impressive.</p>
<p>Good night.</p>
Crafting Interpreters 2020-07-172020-07-17T04:00:00-04:002020-07-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-17:/crafting-interpreters-2020-07-17<p class="first last">A fresh start</p>
<p>(Wow, I totally forgot how I laid out my posts two years ago.
Maybe I should bring some of that back, if I settle on a topic schedule.)</p>
<p>Anyway, while I was poking around programming blogs and thinking about stuff to work on, I stumbled back over <a class="reference external" href="http://craftinginterpreters.com/">Crafting Interpreters</a>.
Nearly two years ago, I had looked at the instructions for writing an interpreter in Java, and thought "Eh, I'll try it in Lua."
That decision was both broadly consistent with my reaction to seemingly every coding tutorial, and led to a bunch of work that I foolishly did not comment.</p>
<p>I see that my last post on the topic had me speculating about targeting <a class="reference external" href="https://rpython.readthedocs.io/">RPython</a> for a JIT interpreter.
I've thought about such things in the past few years, and I think I'd specifically like to try prototyping in PyPy3, then potentially porting it back to PyPy2, then restricting it to RPython.
Each step of that entails giving up developer convenience and writing more code in the hope of increasing execution speed.
Either I write simple code now, and gradually replace it with more complicated code, or I try to write the more complicated code all at once, up front.
As such, the cost of using Python 3 to start with is, at worst, the up-front cost of the code that will have to be rewritten into a more complicated version later, which is really low, because <a class="reference external" href="https://www.attrs.org/">attrs</a> and enum are great.</p>
<p>I've just basically gotten started with my Python version of Lox, and it's not too impressive yet.
I don't know if I'll keep on with this, but switching gears seems to have helped with my stress a bit.
Anyway, it's way late now, so I should wrap up.</p>
<p>Good night.</p>
Diary 2020-07-162020-07-16T04:00:00-04:002020-07-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-16:/diary-2020-07-16<p class="first last">I'm a little less sore.</p>
<p>I did more moving stuff today. We're not totally ready, but I feel like we've got enough detritus sorted through that it won't be too onerous to get packed.
Much as it would be nice to get back to the projects I have, I'm still a bit keyed up and it's late.
So, I can't get into them <em>right now</em>.
I'll try to put aside some time for planning and considering over the next few days, and hopefully I'll come to a decision by next week.</p>
<p>Anyway, I don't think I have anything else to say right now, so let's wrap this up.</p>
<p>Good night.</p>
Diary 2020-07-152020-07-15T04:00:00-04:002020-07-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-15:/diary-2020-07-15<p class="first last">Hanging out all day with a messed-up back.</p>
<p>I mostly took it easy today.
One of the quirks of how I date these posts is, I put them up for the day <em>after</em> I wrote them.
(Or mostly wrote them.)
So, this post was written on my birthday, unlike the one with my birthday date on it.
Every once in a while the discrepancy here seems a bit confusing to me, but generally it makes just enough sense that I'm not interested in coming up with alternatives.</p>
<p>Anyway, I did spend some time putting together a list of projects I've been working on or thinking about lately.
There are actually quite a few, and I'm not sure how I want to organize things, but it should be possible for me to work out some kind of schedule.
I don't know when I'll feel comfortable trying to commit to a schedule, since things are kind of in flux right now.
I'm still reading stuff, but I don't have much to say on the stuff I'm reading.</p>
<p>I should wrap things up soon, or I'll regret it.</p>
<p>Good night.</p>
Weekly Roundup 2020-07-142020-07-14T04:00:00-04:002020-07-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-14:/weekly-roundup-2020-07-14<p class="first last">Happy birthday to me...</p>
<ul class="simple">
<li>Wednesday: I took the ECS stuff in a different direction.</li>
<li>Thursday: I tweaked the interface some, and discovered a Mypy limitation.</li>
<li>Friday: It was hot. Instead of trying to code, I tried to learn about generating functions.</li>
<li>Saturday: I had to rearrange the ECS stuff kind of heavily to avoid import cycles.</li>
<li>Sunday: I made a little more progress on the ECS stuff.</li>
<li>Monday: I didn't do anything that I felt like going into detail on.</li>
</ul>
<p>Next week, I'm going to work on cleaning this place out.
Hopefully, I'll have time and energy for other stuff, but no promises.</p>
Diary 2020-07-132020-07-13T04:00:00-04:002020-07-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-13:/diary-2020-07-13<p class="first last">Just kind of tried to take it easy and zone out.</p>
<p>I once again don't remember if I got much done with coding today.
I'm guessing things are going to shift into "preparing to move" mode, and hopefully I'll be able to get back up to speed after that's done, which will probably take a few weeks.</p>
<p>I'm mostly focused on collecting reading materials for some of the projects I want to get back to.
My plan, once I get back up to speed, is to work out something like the weekly schedule of topic days I used to have.
Anyway, it's getting late, and the weather sucks out here.</p>
<p>Good night.</p>
Coding 2020-07-122020-07-12T04:00:00-04:002020-07-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-12:/coding-2020-07-12<p class="first last">Why's it so hot... Ugh...</p>
<p>Slow going on the ECS stuff again today.
Oh well.
I made some progress, though.</p>
<p>I did some more work on other stuff, that I'll maybe talk about later.
Not feeling the motivation right now, so...</p>
<p>Good night.</p>
Coding 2020-07-112020-07-11T04:00:00-04:002020-07-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-11:/coding-2020-07-11<p class="first last">Complications that were unforeseen, mainly because I didn't want to foresee them.</p>
<p>It turns out that even though I put in a lot of work on tests just now, I didn't make much numerical progress.
Basically, I had the type definitions for the ECS package spread out among the various modules, which turns out to not work well when they have all sorts of interdependencies.
When I tried to actually import and test some of the new modules, it crashed repeatedly, and in weirder ways as I tried to work around it.</p>
<p>So, after I added some basic tests, I moved the type definitions to a single module, and tried to get them to mostly build on each other linearly.</p>
<p>That seems to have done the trick, so I'll try to polish off the rest later.
Hopefully there'll be no weird hurdles waiting for me in the morning.</p>
<p>Good night.</p>
Diary 2020-07-102020-07-10T04:00:00-04:002020-07-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-10:/diary-2020-07-10<p class="first last">Summer...</p>
<p>I don't remember if I got much done with coding today.
Certainly no tests.
The basic problem was that it was just stupidly hot today, so I couldn't really focus.
I basically spent all of my mental energy doing exercises from a math textbook I loaded into my e-reader, because squinting at the somewhat-small text is easier than staring at a bright screen that needs to be taken into the hot to recharge every few hours.</p>
<p>If conditions are favorable tomorrow, I'll wrap up the ECS stuff.
If not, I probably won't.
I need to wrap up now; it's really gross out here.</p>
<p>Good night.</p>
Coding 2020-07-092020-07-09T04:00:00-04:002020-07-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-09:/coding-2020-07-09<p class="first last">I would get rumbled so hard by a problem that starts with a bear walking south, and doesn't involve the curvature of the Earth.</p>
<p>I did not get tests done today.
Instead, I iterated on the interface some more.
The way things are going is making me question whether I want to use more specialized data structures for some of this, but the interface to what I have is fine, so this is pretty much a "performance" question, so I'm not currently equipped to answer it.</p>
<p>I think the interface I'm going with currently is solid.
Again, have to try it out, which means I need to get it ready to be tried out.
I'll try to get the tests done tomorrow.</p>
<p>One unfortunate thing I found is that Mypy apparently doesn't really even <em>see</em> class decorators, so I'm possibly going to have to reconsider all of the class decorators I used.
Or maybe just say "You know what, this isn't ready for release, but it's good enough for me right now."</p>
<p>I also tried out some of the problem solving stuff today, first with some of the example problems.
(I had to skip to the end, becase my mental monologue reading the early ones went something like "'A bear walks one mile south'—the north pole! no, white!")
Anyway, that seemed to work out, so I tried applying the principles to something outside the area of math/lateral thinking.
I didn't get as far, because the problem was much more open-ended, but I'm happy with my progress so far.</p>
<p>Good night.</p>
Coding 2020-07-082020-07-08T04:00:00-04:002020-07-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-08:/coding-2020-07-08<p class="first last">Me from a few years ago is super jazzed about trying out this design.</p>
<p>I went through a few iterations with the attempt to convert Dennis's ECS design to entirely immutable data structures.
I concluded that a straight port was impossible, <em>but</em> I've got a draft implementation of a more elegant design.
Once I have it tested (I think I'll finally bring back mutation testing for this), I'm going to try to port Dennis to it, to make sure I properly understand the ramifications.</p>
<p>The big difference is, Dennis's ECS implementation did not actually have the "system" from "entity component system".
It basically got by with a concept I called "Views", which were a way to interact with the "World" structure that contained everything else in a type-safe way.
The key difference between "Views" and anything in the new system is that Views were explicitly coupled into the "World".
In the new system, they're replaced by "Bundles", which are like "Views" that don't do anything, and "Systems", which couple a "Bundle" to a single action that is restricted in what it can actually do.
Basically, the "System" operates on a snapshot of the "World" when the system is started, and it ultimately does two things: return either a new bundle to replace the current entity's bundle, or remove the bundle completely, and return any number of bundles to add to the world.
These modifications are not visible to the other runs of the system, so there can be no dependence on order.
(Or, there can, but it would have to be a deliberate attempt to work around the library.)</p>
<p>It's possible that I'll want more sophisticated interfaces once I try actually using this, but I think this is expressive enough to handle anything I might want to do, <em>somehow</em>.
It should just be a question of convenience.</p>
<p>Anyway, I should get those tests done tomorrow.
For now, I sleep.</p>
<p>Good night.</p>
Weekly Roundup 2020-07-072020-07-07T04:00:00-04:002020-07-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-07:/weekly-roundup-2020-07-07<p class="first last">I think I prefer the books on technique or motivation that don't sound like the the author has the urge to found a cult.</p>
<ul class="simple">
<li>Wednesday: I tried to follow a programming tutorial, and got impatient and started trying to rewrite it on the fly. Sensing a pattern here...</li>
<li>Thursday: The rewrites got too tricky.</li>
<li>Friday: I had a headache and tried to do tricky math problems. Not recommended.</li>
<li>Saturday: I got way too into video games and had an adrenaline crash. Not recommended.</li>
<li>Sunday: I tried to apply more rigorous principles to some of my creative processes. So far, all I can say for sure is that it's a refreshing change in perspective. It feels good. I don't know if it works good.</li>
<li>Monday: I made an effort to explain a lot of things around my programming projects.</li>
</ul>
<p>Next week, I'm going to work on refining processes, but try to put them into practice as soon as I can,</p>
Coding 2020-07-062020-07-06T04:00:00-04:002020-07-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-06:/coding-2020-07-06<p class="first last">I don't think I ever explained that reference before.</p>
<p>I started trying to rewrite Dennis's ECS implementation using <a class="reference external" href="https://www.attrs.org/">attrs</a> and <a class="reference external" href="https://pyrsistent.readthedocs.io/">pyrsistent</a> in a new monorepo.</p>
<p>I feel like it might be helpful to explain what all that means and why I'm doing it.</p>
<p>Dennis is what I called my project to rework the implementation of the roguelike from <a class="reference external" href="http://rogueliketutorials.com/tutorials/tcod/">TStand90's roguelike tutorials</a> in line with my own preferences.
It leans a lot on some features of <a class="reference external" href="http://coconut-lang.org/">Coconut</a>, which I'll <em>probably</em> end up replacing with attrs somehow.
It's called Dennis because it's an <a class="reference external" href="http://www.hrwiki.org/wiki/Thy_Dungeonman">adventure game</a>, kind of, and the implementation is in Coconut, which is a reference to <a class="reference external" href="https://www.youtube.com/watch?v=eKIyVnoZDdQ">Monty Python and the Holy Grail</a>.</p>
<p>Part of the rework involved redoing the implementation of the ECS, or entity component system.
The idea of an entity component system is that, instead of creating a distinct class for each "kind of thing" (something like <tt class="docutils literal">PositionedFactionBasedSizedMonsterWithAI</tt>), there's just one "kind of thing" called an entity, which can have "components" associated with it (which, in the example given, would be something like "Position", "Faction", "Size", "Statblock", "AI").
Dennis represents entities as a simple opaque identifier (using a system that can be simplified in the current rewrite), and component instances are stored in mappings from those identifiers.</p>
<p>In Dennis, the master data structure for the ECS is mutable, and the implementation makes heavy use of Coconut's "data" classes.
In the current rewrite, the data structures are all immutable thanks to pyrsistent, and the "frozen" feature from attrs.</p>
<p>The rewrite is taking place in a new version control repository that will contain the source for multiple Python packages, which will be developed in tandem.
The basic idea is that, where Dennis had a single ECS module, I'm now trying to put that into an ECS package, which should hopefully be easier to reuse in other applications.
Just add a package to the monorepo that defines an entry point for execution, and I can have it pick and choose from the packages in the monorepo.
Part of what I plan to do is rewrite Dennis into the monorepo, so I can better reuse the work I already did.</p>
<p>Anyway, that's a bunch of explaining I just did.
I should get to bed ASAP, again.</p>
<p>Good night.</p>
Diary 2020-07-052020-07-05T04:00:00-04:002020-07-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-05:/diary-2020-07-05<p class="first last">Part of the problem: "It's the same exact game, but now I'm better at it in a way that makes it boring."</p>
<p>I did some reading on problem-solving techniques (which is something that I feel I haven't really been taght in the way that I've just been reading about), and promptly concluded "If these are general techniques, I should be able to apply them to any problem domain, like, say, high-level game design."</p>
<p>I do feel like the attempt led to various better understandings on my part, but I think I should take a break from that and try applying these principles to the kinds of problems they were originally meant for: math problems.</p>
<p>Anyway, I'm going to wrap up, and maybe read other things.</p>
<p>Good night.</p>
Diary 2020-07-042020-07-04T04:00:00-04:002020-07-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-04:/diary-2020-07-04<p class="first last">It turns out I'm apparently a background character in Yu-Gi-Oh.</p>
<p>I looked over the code I mentioned yesterday, and a bit of tinkering and simplification was all I needed to accept that there's probably no point in trying to get it workable in production.
Instead, I decided to pull in some existing libraries, and see about building the system I want on top of them.
I got a fair bit sketched out before deciding that I need to plan and think more about this.</p>
<p>Anyway, other stuff I did today...
I almost beat Slay the Spire with the fourth character, and then spent the next hour or so crashing from the adrenaline rush, because apparently I get excited about card games with virtual monsters attached to them.</p>
<p>I'm gradually accumulating more books I want to read.
I think I should do more of that so my eyes get a little less blasted by backlighting.</p>
<p>I'll get that set up while this publishes, and wrap up for today ASAP.</p>
<p>Good night.</p>
Diary 2020-07-032020-07-03T04:00:00-04:002020-07-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-03:/diary-2020-07-03<p class="first last">Like my brain is trying to balance good and bad ideas for some reason.</p>
<p>I got too much afternoon sunlight today, so I mostly just suffered a little for a while.
I'll try to remember not to do that tomorrow.</p>
<p>So far as what I accomplished, I messed with some recreational math; I've taken a really hard problem, and derived a simplified form of it that I still don't know how to solve, but maybe I can come at it from another angle, unlike the original problem.</p>
<p>I also thought about the game development tutorials that I've tried to follow, and decided that this might be another case for putting together monorepo, like I did for the virtual tabletop stuff, so when I find myself needing to solve similar problems, I can just reach for the code, without copy-paste or a formal repo.</p>
<p>Somewhat unfortunately, the first thing I feel like I want to try putting in there is some experimental code I wrote a few years ago that was just, really bad.
And I have some ideas for improving it, but I don't know of anything that would address the core issue, which is that it was just really not performant at all.
I think I'm being led astray by a gut feeling that I can make it more efficient.
Maybe this time I can figure out why I'm wrong about it.</p>
<p>Anyway, my head still hurts, and maybe if I wrap up now, I can do something about that.</p>
<p>Good night.</p>
Coding 2020-07-022020-07-02T04:00:00-04:002020-07-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-02:/coding-2020-07-02<p class="first last">Where are the Python game dev tutorials from the "composition over inheritance" people?</p>
<p>I got a little further with the <a class="reference external" href="https://pyglet.readthedocs.io/">pyglet</a> tutorial today, before hitting a point where my reflexive refactors got a lot more involved.
So right now, I'm in a little bit of a standoff with myself, over whether to just do this next part as the tutorial says, or to do things right, for some value of "right".</p>
<p>Updates might be even more sketchy in the coming weeks.
We have to move, which seems a little reckless to me, but neither of us is calling the shots here.</p>
<p>I'm trying to think if there's anything else I want to talk about in this entry, and I guess not really?
I focused some on apartment hunting today, which I have no desire to blog about.
I'm going to try to get to bed at a healthier time than I have been lately.</p>
<p>Good night.</p>
Coding 2020-07-012020-07-01T04:00:00-04:002020-07-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-07-01:/coding-2020-07-01<p class="first last">Poor Dennis. I really should look over the build tasks sometime and see if I can simplify and update things.</p>
<p>After I messed around with <a class="reference external" href="https://pyglet.readthedocs.io/">pyglet</a> earlier, I decided to follow along with their tutorial for a simple game.
Now, judging by how I handled the first part, and how Dennis came about, I'm apparently constitutionally incapable of following a game-dev tutorial for Python without throwing in countless refactoring attempts.</p>
<p>I've refrained from using the event dispatcher I wrote earlier, but I'm definitely going to be keeping an eye out as the tutorial gets more sophisticated, seeing if it makes sense to use it anywhere.</p>
<p>Still kind of psyching myself up to try fixing the Ink bug I was looking into.
My intuition says that the changes to behavior should be relatively straightforward, and that level of optimism regarding parts of the codebase I haven't really looked at puts my other intuition on edge.</p>
<p>I'll hopefully have made an attempt by the weekend.
For now, I should wind down.</p>
<p>Good night.</p>
Weekly Roundup 2020-06-302020-06-30T04:00:00-04:002020-06-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-30:/weekly-roundup-2020-06-30<p class="first last">It's kind of not nice to call pyglet-trio "a solution in search of a problem", but, yeah...</p>
<ul class="simple">
<li>Wednesday: I prototyped more of the character sheet stuff for the virtual tabletop.</li>
<li>Thursday: I wrote some utility functions for the character sheet.</li>
<li>Friday: I took a break from coding to mess with World Maker</li>
<li>Saturday: I kept on with World Maker, and didn't have much to say about it.</li>
<li>Sunday: I played Slay the Spire, and poked at other coding stuff.</li>
<li>Monday: I decided to wire together two Python frameworks, got it working on the first try, and realized I didn't have anything I wanted to <em>do</em> with them yet.</li>
</ul>
<p>Next week, I might try to fix a bug I found in Ink earlier this month.
Also, I wouldn't mind adding "use a more general-purpose game library" to Dennis's todo list.</p>
Coding 2020-06-292020-06-29T04:00:00-04:002020-06-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-29:/coding-2020-06-29<p class="first last">"I implemented [THING]!" "Why?" "I... don't know..."</p>
<p>I didn't have any real plan today, but I ended up mesing with <a class="reference external" href="https://trio.readthedocs.io/">Trio</a> and <a class="reference external" href="https://pyglet.readthedocs.io/">pyglet</a>.
I followed Trio's directions for running under and arbitrary other event loop, and it worked on the first try, which is a massive testament to the quality of both projects' documentation.
(I mean, we've seen how things can go when I'm not working with such libraries or frameworks at all.
The odds are really stacked against things "just working"; I'm way more used to having to <em>make</em> them work.)
Anyway, I didn't have any specific thing in mind that I needed this for, so I guess I'll just back-burner this and keep it in mind as "a thing I can do".</p>
<p>Here's the code I wrote, including a weird hybrid "hello world" sample.
This differs from the original "just works" code in that I did some minor refactorings to simplify and shorten some of the code, and I added some basic documentation of what I did and why.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span>
<span class="normal">74</span>
<span class="normal">75</span>
<span class="normal">76</span>
<span class="normal">77</span>
<span class="normal">78</span>
<span class="normal">79</span>
<span class="normal">80</span>
<span class="normal">81</span>
<span class="normal">82</span>
<span class="normal">83</span>
<span class="normal">84</span>
<span class="normal">85</span>
<span class="normal">86</span>
<span class="normal">87</span>
<span class="normal">88</span>
<span class="normal">89</span>
<span class="normal">90</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""Adapter widget to run the Trio and pyglet event loops together.</span>
<span class="sd">I tried and failed to come up with a Three Little Pigs joke.</span>
<span class="sd">"""</span>
<span class="kn">import</span> <span class="nn">pyglet.app</span>
<span class="kn">import</span> <span class="nn">pyglet.event</span>
<span class="kn">import</span> <span class="nn">pyglet.window</span>
<span class="kn">import</span> <span class="nn">trio.lowlevel</span>
<span class="k">class</span> <span class="nc">TrioLoop</span><span class="p">(</span><span class="n">pyglet</span><span class="o">.</span><span class="n">event</span><span class="o">.</span><span class="n">EventDispatcher</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Custom widget for running a Trio event loop concurrently with pyglet."""</span>
<span class="n">started</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">def</span> <span class="nf">start_trio</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">trio_main</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Queue the Trio mainloop to run when the app starts.</span>
<span class="sd"> This function should be called once, before pyglet.app.run().</span>
<span class="sd"> """</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">started</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">RuntimeError</span>
<span class="bp">self</span><span class="o">.</span><span class="n">started</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">pyglet</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">platform_event_loop</span><span class="o">.</span><span class="n">post_event</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">"on_trio_start"</span><span class="p">,</span> <span class="n">trio_main</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_schedule_callback</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">callback</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Schedule the guest loop callback in pyglet's event loop."""</span>
<span class="n">pyglet</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">platform_event_loop</span><span class="o">.</span><span class="n">post_event</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">"on_trio_callback"</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_done_callback</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">outcome</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Schedule the done callback in pyglet's event loop."""</span>
<span class="n">pyglet</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">platform_event_loop</span><span class="o">.</span><span class="n">post_event</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">"on_trio_done"</span><span class="p">,</span> <span class="n">outcome</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">on_trio_start</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">trio_main</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Handle the on_trio_start event. Start Trio in guest mode."""</span>
<span class="n">trio</span><span class="o">.</span><span class="n">lowlevel</span><span class="o">.</span><span class="n">start_guest_run</span><span class="p">(</span>
<span class="n">trio_main</span><span class="p">,</span>
<span class="n">run_sync_soon_threadsafe</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_schedule_callback</span><span class="p">,</span>
<span class="n">done_callback</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_done_callback</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">on_trio_callback</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">callback</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Handle the on_trio_callback event."""</span>
<span class="n">callback</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">on_trio_done</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">outcome</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Handle the on_trio_done event. Stop the event loop.</span>
<span class="sd"> This function should, but does not yet, do something with the "outcome"</span>
<span class="sd"> parameter.</span>
<span class="sd"> """</span>
<span class="n">pyglet</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">event_loop</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span>
<span class="n">TrioLoop</span><span class="o">.</span><span class="n">register_event_type</span><span class="p">(</span><span class="s2">"on_trio_start"</span><span class="p">)</span>
<span class="n">TrioLoop</span><span class="o">.</span><span class="n">register_event_type</span><span class="p">(</span><span class="s2">"on_trio_callback"</span><span class="p">)</span>
<span class="n">TrioLoop</span><span class="o">.</span><span class="n">register_event_type</span><span class="p">(</span><span class="s2">"on_trio_done"</span><span class="p">)</span>
<span class="k">async</span> <span class="k">def</span> <span class="nf">mainloop</span><span class="p">():</span>
<span class="w"> </span><span class="sd">"""Run a combination of the Trio and pyglet tutorials.</span>
<span class="sd"> This code isn't really useful on its own, but functions as a</span>
<span class="sd"> proof-of-concept and manual test.</span>
<span class="sd"> """</span>
<span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
<span class="n">window</span> <span class="o">=</span> <span class="n">pyglet</span><span class="o">.</span><span class="n">window</span><span class="o">.</span><span class="n">Window</span><span class="p">()</span>
<span class="n">label</span> <span class="o">=</span> <span class="n">pyglet</span><span class="o">.</span><span class="n">text</span><span class="o">.</span><span class="n">Label</span><span class="p">(</span>
<span class="s2">"Hello from Trio"</span><span class="p">,</span>
<span class="n">font_name</span><span class="o">=</span><span class="s2">"Times New Roman"</span><span class="p">,</span>
<span class="n">font_size</span><span class="o">=</span><span class="mi">36</span><span class="p">,</span>
<span class="n">x</span><span class="o">=</span><span class="n">window</span><span class="o">.</span><span class="n">width</span> <span class="o">//</span> <span class="mi">2</span><span class="p">,</span>
<span class="n">y</span><span class="o">=</span><span class="n">window</span><span class="o">.</span><span class="n">height</span> <span class="o">//</span> <span class="mi">2</span><span class="p">,</span>
<span class="n">anchor_x</span><span class="o">=</span><span class="s2">"center"</span><span class="p">,</span>
<span class="n">anchor_y</span><span class="o">=</span><span class="s2">"center"</span><span class="p">,</span>
<span class="p">)</span>
<span class="nd">@window</span><span class="o">.</span><span class="n">event</span>
<span class="k">def</span> <span class="nf">on_draw</span><span class="p">():</span>
<span class="n">window</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
<span class="n">label</span><span class="o">.</span><span class="n">draw</span><span class="p">()</span>
<span class="k">await</span> <span class="n">trio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
<span class="n">trio_loop</span> <span class="o">=</span> <span class="n">TrioLoop</span><span class="p">()</span>
<span class="n">trio_loop</span><span class="o">.</span><span class="n">start_trio</span><span class="p">(</span><span class="n">mainloop</span><span class="p">)</span>
<span class="n">pyglet</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
</pre></div></td></tr></table></div>
<p>Honestly, I spent some time trying to work out if I somehow implemented this wrong in a way that looks right to me for simple cases.
I can't see any way that could happen, given the behavior I'm seeing.
The fact that five windows get created means that the callback function is definitely being called, and that can only happen if pyglet's event loop is handling events properly.
In addition, the <tt class="docutils literal">on_draw</tt> events are firing.</p>
<p>Anyway, I'm sure there's a lot of potential here that I'm not seeing at the moment because I've been so caught up in low-level details.
Maybe I should try to design a Zach-like to try and implement in it.
I'll have to think about it.</p>
<p>Good night.</p>
Diary 2020-06-282020-06-28T04:00:00-04:002020-06-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-28:/diary-2020-06-28<p class="first last">Loading stuff into my Kindle to save my eyes.</p>
<p>I keep on trying to force myself to work on one of the coding projects, before going "no, wait, that's a bad idea".
So, today was mostly writing, and a bunch of <a class="reference external" href="https://www.megacrit.com/">Slay the Spire</a>.
I also spent a bit of time trying to figure out what kind of interface I want for the virtual tabletop, and messing with other people's projects using <a class="reference external" href="http://pyglet.org/">Pyglet</a>.
The two parts of that sentence may or may not end up coming together; I haven't gotten enough into either to be sure.</p>
<p>One thing I was kind of thinking of doing, and I don't know that this would make for an in-depth post, was to hit up math textbooks some, see if I can get anything recreational out of that.</p>
<p>For now, I guess I'm just kind of decompressing.</p>
<p>Good night.</p>
Diary 2020-06-272020-06-27T04:00:00-04:002020-06-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-27:/diary-2020-06-27<p class="first last">Hard to write under the crushing weight of summer.</p>
<p>Today, I started working on transferring my World Maker notes to paper.
I seem to be a bit out of practice with using notebooks.
In any case, I'll try to work on that some over the weekend.</p>
<p>I thought I had more to say, but then I spaced out.
I am hopefully going to look over other things I can try to use with World Maker.</p>
<p>Right now, I'm going to play Dissembler while the post publishes, then go to bed.</p>
<p>Good night.</p>
Diary 2020-06-262020-06-26T04:00:00-04:002020-06-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-26:/diary-2020-06-26<p class="first last">Slightly worried I won't know where to start with this setting...</p>
<p>Today, I didn't really feel like coding, so I tried out something else I'd been interested in, <a class="reference external" href="https://sohkrates.itch.io/world-maker">World Maker</a>.</p>
<p>My first draw was kind of unlucky, because I drew character cards totaling 45 details, which, taking the other cards needed into account, adds up to more cards than there are in the deck.
This shouldn't be possible except with five characters, and it shouldn't happen that often, but it was a little awkward and I did have to fudge stuff.
The other tricky bit of drawing 45 details is that these characters kind of have everything going on.
Again, luck of the draw, but when the characters I have the best handle on are the cyborg angel and the faerie scientist... this is going to be a little out there.</p>
<p>I actually just now filled in the last of the connections between these characters.
Now that I've got notes on all this stuff, I'll have to flesh it out later.</p>
<p>I don't know how much I'll do with this first attempt, but I want to see how far I can take it.
Once I have a handle on this, I want to try using World Maker to come up with plot hooks for a setting that I have some more idea of what it's like, going into it.</p>
<p>Good night.</p>
Coding 2020-06-252020-06-25T04:00:00-04:002020-06-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-25:/coding-2020-06-25<p class="first last">This is the first entry since I added a progress meter to the upload script. Let's see how that goes.</p>
<p>I didn't get much done in the way of mockups today.
I was working on squaring away a few things, and that ended up taking a few hours.
That, and playing Minit.</p>
<p>Anyway, I was able to reason about one thing that the sheet/module code needs, and that's a version of <tt class="docutils literal">evolve</tt> from <a class="reference external" href="https://www.attrs.org/en/stable/">attrs</a> that implicitly converts a proxy to the underlying module.
That probably doesn't make much sense without context.
Basically, the way I'm trying to set up this whole modular concept, is to allow client code to define module classes using a decorator.
The decorator essentially splits the class into a container class and a proxy class.
All client logic lives on the proxy, which defines accessors to all of the fields on the container.
I haven't totally thought through the typing considerations for this; they might be really hairy or they might be fine.
Initial experimentation points towards "hairy".</p>
<p>Oh well, if this ends up needing a plugin, it'll probably be less of a hassle than my attempts at a plugin for Structured Data.
And I've already gt this monorepo setup working, so there wouldn't be much friction in getting the project spun up...</p>
<p>Regardless, I'd like real example code to test this against.
I'll try to get that specified tomorrow.</p>
<p>Good night.</p>
Coding 2020-06-242020-06-24T04:00:00-04:002020-06-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-24:/coding-2020-06-24<p class="first last">Thoughts are amorphous; they're much more reliable when given some kind of external form.</p>
<p>I did some iteration on the sheet interface.
Slightly worryingly, it seems to have a lot of false negatives around typing, even when I think I'm being restrictive.
Regardless, I rearranged a bunch of stuff, and changed which types get foregrounded, and I think it's an improvement.
I'm going to need to try this out for real to see if any more tweaks are required; there are some bits that suggest to me that I might end up needing to do some complicated metaprogramming, but I'd rather do that later than sooner.</p>
<p>I didn't have time tonight to work on the sheet editing actions, which I'm going to call "operations".
I'll have to mock up usage of those ahead of time, because I feel like there are a bunch of possibilities for the interface and I can't figure out which would work best for my intended use case solely by thinking really hard.
I'll try to do some mockups tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2020-06-232020-06-23T04:00:00-04:002020-06-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-23:/weekly-roundup-2020-06-23<p class="first last">Too tired to come up with anything unifying here.</p>
<ul class="simple">
<li>Wednesday: I wrote a command-line interface to the Ironsworn helper re-implementation, using Click.</li>
<li>Thursday: I did some tweaks to the core library, and thought about the Cement framework.</li>
<li>Friday: I started porting my character sheet prototype.</li>
<li>Saturday: I finished the port; did not finish tweaking the code.</li>
<li>Sunday: I made some important tweaks to the code.</li>
<li>Monday: I thought hard about "how character sheets will be used", which gave me some inpiration for the interfaces I'll need.</li>
</ul>
<p>Next week, I'll either work more on the interfaces, or switch gears again.</p>
Coding 2020-06-222020-06-22T04:00:00-04:002020-06-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-22:/coding-2020-06-22<p class="first last">Writing out the code sample in this helped organize my thoughts immensely. I need to start using notebooks more.</p>
<p>I spent a bit of today looking over how the Ironsworn character sheet is used in the context of the game, because that informs decisions about how to represent it.
As an extreme example, if I decided no code was going to interact with the details, I could say that it should just be freeform text.
Since I don't really want to do it like that, I know there are tasks I'd like for the system to actually be able to accomplish with it.</p>
<p>I tried out listing all of the various ways that the character sheet can change in Ironsworn, and I think I have that written up.
What I have to figure out next is how to represent this stuff in code.
I'm not exactly sure, but I'm leaning towards something like this:</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Protocol</span>
<span class="kn">from</span> <span class="nn">virtual_tabletop</span> <span class="kn">import</span> <span class="n">sheet</span> <span class="k">as</span> <span class="n">sheet_</span>
<span class="k">class</span> <span class="nc">Transform</span><span class="p">(</span><span class="n">Protocol</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">apply</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sheet</span><span class="p">:</span> <span class="n">sheet_</span><span class="o">.</span><span class="n">Sheet</span><span class="p">)</span> <span class="o">-></span> <span class="n">sheet_</span><span class="o">.</span><span class="n">Sheet</span><span class="p">:</span>
<span class="o">...</span>
</pre></div>
<p>Whether this is represented as a protocol as above, or just as <tt class="docutils literal"><span class="pre">Callable[[Sheet],</span> Sheet]</tt> depends on whether I come up with other operations besides simply applying the transformation.
The types are somewhat lax compared to what the system should be capable of, because this way is slightly more expressive than the strict idea I had in mind, and slightly more ergonomic than the next strictest idea.</p>
<p>I think what would make sense is to use the callable interface, define classes for handling specific operations paramaterized with arguments, and create a simple fluent interface on <tt class="docutils literal">Sheet</tt> to allow for calls like <tt class="docutils literal"><span class="pre">sheet.apply(transform_1).apply(transform_2)</span></tt>, or even possibly <tt class="docutils literal"><span class="pre">sheet(transform_1)(transform_2)</span></tt>.
(Or maybe indexing, or varargs. The precise details aren't relevant to the rest of the implementation, and finding a good choice means thinking more about how I want to use this.)</p>
<p>Anyway, it's getting late and I'm getting tired.</p>
<p>Good night.</p>
Coding 2020-06-212020-06-21T04:00:00-04:002020-06-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-21:/coding-2020-06-21<p class="first last">Several hours of trial and error could save you several minutes of reading the doumentation.</p>
<p>I'm going to have to come up with something for a change of pace, but for the moment...</p>
<p>I've written tests and done some minor improvements and fixes to the character sheet code.
I'm probably missing a bunch of helper functions and methods, but I can't really figure out what they should be from first principles.
I'm going to have to try to code character sheets with this library.
I'll do that some tomorrow.</p>
<p>For now, I'm very tired.</p>
<p>Good night.</p>
Coding 2020-06-202020-06-20T04:00:00-04:002020-06-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-20:/coding-2020-06-20<p class="first last">Still haven't had the time to really go in-depth on this project lately.</p>
<p>Current status of prototype character sheet port:
All of the logic has been ported over, and given various minor improvements.
All of this code needs to be tested.
Some of this code needs to be heavily refactored in some way.</p>
<p>I can't say much more because it's really late.</p>
<p>Good night.</p>
Coding 2020-06-192020-06-19T04:00:00-04:002020-06-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-19:/coding-2020-06-19<p class="first last">Status of this one type that I really want to fit into a type system: it still doesn't fit into any type system I know of.</p>
<p>I wasn't too focused on tabletop stuff today, so I ended up just now getting the very basics of the character sheet prototype ported over.
I'm going to need to plan stuff while fully awake to make more progress, so there's not much point in trying right now.</p>
<p>I did just now try to do an obvious addition, and now mypy is yelling at me in ways that I understand, but don't want to.
So, I definitely should wrap this up now.</p>
<p>Good night.</p>
Coding 2020-06-182020-06-18T04:00:00-04:002020-06-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-18:/coding-2020-06-18<p class="first last">I'm not saying don't use Cement. I just haven't figured out what it does for me yet, if anything.</p>
<p>I gave the core logic a nicer implementation in concept, but I haven't yet figured out a nice way to express it in code.
I gave the command-line interface some minor tweaks as well.
I've got some vague ideas for how I might extend it to do stuff cooperatively with the dependency injection containers, but I'd need more frontends to have an idea of what "interacting frontends" would look like.</p>
<p>Speaking of the CLI, when I think about using Click, I often think about a blog post that I've read and reread that advocates against its use.
I've tried to give the post the benefit of the doubt, and I'm looking into some of the libraries it recommends, like <a class="reference external" href="https://builtoncement.com/">Cement</a>.
The overarching problem I'm having in all of this is that while the sentiment in the post is undoubtedly heartfelt, none of it has connected with me in a way that I can look at a Click interface I put together and go "Yes, I understand why that's bad".
I'm honestly looking at the Cement documentation from the perspective of "How can I use this to replicate the interfaces I built on Click and Fire, but using a framework that will give me plausible protection against judgment from a stranger", which is just, so bad, on so many levels.</p>
<p>Anyway, I'm trying to get through the Cement tutorial, but I'm just jumping on all kinds of stuff.
I'm going to make an effort to get through this stuff, because plenty of people clearly think it's useful, but right now the odds are kind of stacked against me caring.</p>
<p>Anyway, I also thought more about my character sheet prototype, and realized that I basically set it up like my ECS concept from working on Dennis, so now I'm trying to figure out what capabilities I want.
Because I'm not really sure, the best course of action is probably to work on requirements from, say, Ironsworn and Retrocausality.
Although, thinking about it some, I've got an initial idea of how I want things to go.
I'm too tired to describe it.</p>
<p>Actually, I've been getting to bed late recently, and that's bad, so I'd better work on that.
Now's a good time t work on it.</p>
<p>Good night.</p>
Coding 2020-06-172020-06-17T04:00:00-04:002020-06-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-17:/coding-2020-06-17<p class="first last">I really tried to give some other libraries a fair shake.</p>
<p>I hooked up <a class="reference external" href="https://click.palletsprojects.com/en/7.x/">Click</a> to my new, streamlined Ironsworn implementation, and got it all working.
I think I understand Python better than the last time I used Click heavily, because I've got a lot less junk around testing.</p>
<p>I was trying to give libraries besides Click a shot, and I actually tried a few, but the ease of setting up entry points, and not requiring custom annotations, won me over.
In the current implementation, there are somewhere between two and four lines of boilerplate, in my opinion, and that feels pretty good for a cli library.</p>
<p>Now that I've got a consumer of some of this code set up, my next priority is trying to make some of the core logic a little nicer.</p>
<p>After that, porting and updating prototypes, or setting up mutation testing. We'll see.</p>
<p>For now, sleep.</p>
<p>Good night.</p>
Weekly Roundup 2020-06-162020-06-16T04:00:00-04:002020-06-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-16:/weekly-roundup-2020-06-16<p class="first last">I would really like it if time could pass at a normal rate, please and thank you.</p>
<ul class="simple">
<li>Wednesday: I talked about some of my concerns with my over-engineered card representation idea. The concerns at most tangentially related to the over-engineering.</li>
<li>Thursday: I got the basic outline of the next version of that nailed down.</li>
<li>Friday: I got the card stuff done enough for now, and made myself put it down.</li>
<li>Saturday: For some reason, I wrote code for manipulating todo.txt data. Which I only ever edit manually.</li>
<li>Sunday: I took my first pass at a "monorepo" kind of setup for the "virtual tabletop" project, to avoid having concrete implementations in the same package as the abstract helper code. I ran into trouble, and found a workaround.</li>
<li>Monday: On further investigation, I found a workaroud that was closer to just "a good way to do things", and got back to making progress on the actual project.</li>
</ul>
<p>Next week, I'm going to go over my options for command-line parsing, and maybe look into making some of the output logic more theoretically efficient.</p>
Coding 2020-06-152020-06-15T04:00:00-04:002020-06-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-15:/coding-2020-06-15<p class="first last">Hard to believe I was getting by without this, like, two days ago.</p>
<p>Good work on the virtual tabletop today.
I finally figured out what the <tt class="docutils literal"><span class="pre">--find-links</span></tt> option to <tt class="docutils literal">pip install</tt> is for.
The answer is "what I've been using weird workarounds for for probably over a year now".
So, my test runner setup is now much better.
I got extremely thorough unit test coverage on some system-specific code, so that's nice.
The code that's remaining to port is just wiring input and output around the logic I just thoroughly tested.</p>
<p>My immediate priorities for this are:</p>
<ul class="simple">
<li>Figure out whether I want to keep using <a class="reference external" href="https://github.com/google/python-fire">Fire</a> or switch to another cli library</li>
<li>Figure out how I want to hook up the internals of this to whatever I end up using</li>
<li>Do it</li>
<li>Make sure it all works</li>
</ul>
<p>After that, I want to see about either:</p>
<ul class="simple">
<li>Porting some of the prototypes I've been working on into the core</li>
<li>Setting up mutation testing</li>
</ul>
<p>Anyway, none of that's happening now, because I'm sleepy.</p>
<p>Good night.</p>
Coding 2020-06-142020-06-14T04:00:00-04:002020-06-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-14:/coding-2020-06-14<p class="first last">The commit with the workaround is just a bunch of incoherent swears.</p>
<p>So, how'd the monorepo stuff work out for me?</p>
<p>...</p>
<p>...</p>
<p>... <a class="reference external" href="https://github.com/takluyver/flit/issues/354">Great</a>.</p>
<p>...</p>
<p>...</p>
<p>In all seriousness, following some aesthetically bothersome workarounds, I've successfully installed a package with a local dependency using a generated constraints file.
So, the tech stack seems to work, aside from some code that I published months ago.
I'll put fixing that code into the pile of things to look into at some point.
Actually, I should write this stuff down...</p>
<p>Okay, it's written down.</p>
<p>So, the workflow for adding and developing packages in this setup is more-or-less stable, and now I just need to port more logic.</p>
<p>I'm actually really drained from chasing down that issue, so I'm cutting things short once again.</p>
<p>Good night.</p>
Coding 2020-06-132020-06-13T04:00:00-04:002020-06-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-13:/coding-2020-06-13<p class="first last">I wouldn't mind working on random stuff if I had a plan for it.</p>
<p>More distractedness today.
This time, I tried writing a library for manipulating <a class="reference external" href="http://todotxt.org/">todo.txt</a> files.
I got the basics into what should be a working state, but I think I should step away from it for now, because I'm frankly not sure what I would do with it.
I don't really have any use cases yet that aren't handled by my text editor.</p>
<p>I want to get back to auto-roller stuff, and my tentative plan there is to structure it as a monorepo until I can stabilize the core logic, then start splitting stuff out.
I'm not sure if that'll work like I think, but I'll see what I can do, experiment if I need to.</p>
<p>(Also, at some point I need to update my Ink port again.)</p>
<p>Anyway, it's too late and I should stop getting distracted.</p>
<p>Good night.</p>
Coding 2020-06-122020-06-12T04:00:00-04:002020-06-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-12:/coding-2020-06-12<p class="first last">It feels so off to be telling myself "no, no, this is good enough for now".</p>
<p>I didn't touch the code much today, but I did bash together the stuff I actually needed the card code for to start with: a function to generate a standard deck with a specified number of jokers.
The data structures for the code are rather nice at a conceptual level, I think, but manipulating them directly is quite awkward.</p>
<p>My plan for now is to deliberately put this prototype aside, and mess with the other prototype next.</p>
<p>This post was delayed by the decision to download <em>a lot</em> of titles from DriveThruRPG; I'm going to focus on that completely for now and try to wrap that up soon.</p>
<p>Good night.</p>
Coding 2020-06-112020-06-11T04:00:00-04:002020-06-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-11:/coding-2020-06-11<p class="first last">I wonder if there are type checkers for Python with more extensive dependent types support.</p>
<p>I didn't do too much coding tonight, but I did finish up the draft of the baseline for the second card prototype.
Everything beyond this should be a matter of specification and data entry.
This assumes that I got the implementation totally correct, which probably isn't true, though I'm confident it is at least mostly correct, by some measure.</p>
<p>I did think a little about attempting weird type-level logic, but it frankly doesn't seem worth it right now.</p>
<p>Once again, I want to wrap things up quick.
I managed to mess my back up by sitting upright for a while, so to deal with that, I need to lie down and get off my laptop.
So, that's that for now.</p>
<p>Good night.</p>
Coding 2020-06-102020-06-10T04:00:00-04:002020-06-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-10:/coding-2020-06-10<p class="first last">Still a little sad that I can't use ludicrous type hacks. I might try to come up with something.</p>
<p>I started implementing my ideas about a new take on modeling cards, and after I got a bunch of stuff roughed out, I decided that I needed to do more planning with this sometime when I'm better-rested.</p>
<p>The problem (2 problems? 1.5 problems?) I have to address has to do with which cards appear where in runtime "deck" structures.
One example is that "duplicate" cards should appear as close to the card they're duplicating as possible.
I'm kind of leaning towards, the two basic kinds of decks are single named cards, and full products of rank and suit, and other decks are made up of combinations of those, and "duplicate" decks around basic decks, and rank and suit are each similar, but without the "rank-suit product" because that only makes sense for full cards.</p>
<p>I think I understand this now well enough to implement it, but I don't want to push my luck.
I'm really tired now, so it's time to wrap things up.</p>
<p>Good night.</p>
Weekly Roundup 2020-06-092020-06-09T04:00:00-04:002020-06-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-09:/weekly-roundup-2020-06-09<p class="first last">I feel like it's rare for me to come out of a ridiculous metaprogramming exercise going "You shouldn't use this because it doesn't meet the requirements." rather than "You shouldn't use this because it's unsettling." Maybe I'm not pushing my code far enough.</p>
<ul class="simple">
<li>Wednesday: I decided to mess with my auto-roller.</li>
<li>Thursday: I threw a bunch of shade at the linter I was trying out on the project, and removed it. I specced some other stuff out.</li>
<li>Friday: I threw together a character sheet prototype. It's... very prototype-quality.</li>
<li>Saturday: I blogged about feeling kind of gross, from over-exertion and probably pollen.</li>
<li>Sunday: I got back into things, now focusing on emulating cards. I came up with a really complicated system that seemed to work.</li>
<li>Monday: The really complicated system did not work. It's going to need a rework to satisfy the basic requirements.</li>
</ul>
<p>Next week, I'm going to try to redo the card handling, given what I learned from my first attempts.
(I <em>might</em> be able to pull off some horrible melding of the current system and its planned replacement, but I should make sure the replacement works on its own first before considering stuff like that.)
I also hope to feel less sick.</p>
Coding 2020-06-082020-06-08T04:00:00-04:002020-06-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-08:/coding-2020-06-08<p class="first last">A learning experience.</p>
<p>Today, I mostly tried to rough out specifications for different kinds of decks.
This eventually got me inspired to try some improvements to my representation.
Those seem to work, but while testing them, I discovered that my "creative" use of the type system didn't quite work, and I'll have to rework some of it to get consistent and desirable behavior.</p>
<p>Thinking about this a bit more, I'll probably have to drop the "type" concept altogether and focus on making the mechanisms for generating instances explicit.</p>
<p>I've got some ideas here that I think are good, but I spent all day fighting off kind of illness, and right now I don't have what it takes to keep up with trying this or writing any more about it.</p>
<p>I have to wrap up now because I feel tired and gross.</p>
<p>Good night.</p>
Coding 2020-06-072020-06-07T04:00:00-04:002020-06-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-07:/coding-2020-06-07<p class="first last">Good turnaround from "How can I possibly do this?" to "I can do this."</p>
<p>Today, I learned about how decks of playing cards can have all kinds of confusing stuff going on when they're not the "standard" deck.
I vaguely knew about this from playing Zachtronics games, but it seems like what I've seen there so far is just scratching the surface.</p>
<p>In any case, I spent the day iterating on representing playing cards in a way that works more like an ordered set than the options that were more obvious to me.
Those options would have introduced many run-time distinctions that I would consider basically meaningless.
The implementation is, at a type level, extremely cursed, but it resolves down to really simple data at runtime.</p>
<p>The practical benefit of this is that I can extract an ordering of cards from the type that describes them, but the actual instances are also instances of a type with the same cards in a different order.
I haven't checked, but I assume these rearrangements are indistinguishable from a static analysis perspective.
The really nice thing is that it's still the same cards if I have a deck that drops some, or if I add the same cards to two different decks.</p>
<p>So, the initial prototyping went well, and what I want to focus on now is writing up a specification for every deck I try to model, because some of the prototypes came out a little wrong, now that I understand my system better.</p>
<p>I'll wrap up for now and work on documenting stuff tomorrow.</p>
<p>Good night.</p>
Diary 2020-06-062020-06-06T04:00:00-04:002020-06-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-06:/diary-2020-06-06<p class="first last">Feeling excessively aware of my sinuses</p>
<p>Not a coding entry today, because I was super out of it after going all in on work yesterday.
I did poke at the character sheet prototype a little, but not enough to merit talking about it.</p>
<p>My plan once I get back into the swing of things is to work on prototypes for some of the other content I want for the roller code, and then start figuring out desired features of all of this stuff by figuring out what's needed to adapt various character sheets and card or dice games.
Hm, thinking about it, I should also figure out what "counters" would look like.
Just a bunch of natural number fields, or something more...</p>
<p>Anyway, the air is awful right now, and my response to that at night is to go to sleep so I don't have to deal with it.</p>
<p>Good night.</p>
Coding 2020-06-052020-06-05T04:00:00-04:002020-06-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-05:/coding-2020-06-05<p class="first last">Maybe I should try outlining my posts sometime.</p>
<p>Today I was kind of pressed for time and energy because I ended up working late.
Still not entirely done with what I wanted, but it's way too late at night for me to do work worth money to other people.</p>
<p>Speaking of which, I've got most of a prototype of the character sheet concept put together.
It's currently missing key functionality in the actual sheet part, but that shouldn't be too bad to fill in over the weekend.
Previous experience tells me there are probably some howlingly bad bugs in here just because I put it together over the course of an hour or so, late at night, with no tests.
Although, to get it as far as I did, I have to credit writing, once again.
Type stuff out, organize thoughts, then treat what's there as a checklist.
While I'm implementing something, does my painfully sleepy brain need to be able to correlate it to the whole design?
Nope!</p>
<p>Anyway, I have no more focus left and do not know how to end this or connect any loose ends in my paragraphs together.</p>
<p>Good night.</p>
Coding 2020-06-042020-06-04T04:00:00-04:002020-06-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-04:/coding-2020-06-04<p class="first last">Just writing stuff down can clarify things immensely.</p>
<p>I feel like I've tried super hard to work with wemake-python-styleguide, even going so far as to have indirectly contributed <a class="reference external" href="https://github.com/wemake-services/wemake-python-styleguide/blob/75ea8907d5b2f9a93995852bb3f492b4a125b342/wemake_python_styleguide/logic/complexity/annotations.py#L41">one (1) line of code</a>.
But it's just the same kind of thing over and over: confident general statement that overreaches or <a class="reference external" href="https://www.python.org/dev/peps/pep-0570/">is just wrong</a>, followed by an eventual course correction, maybe.
I'm kind of anticipating more of those, but I'm not certain.</p>
<p>Anyway, that's sort of why I decided the most obvious improvement I could make to my dice roller code was to stop using "the strictest linter" on it.
I then rewrote a bunch of lines, and it's <em>possible</em> I overcorrected, but I'm going to have to wait and use my judgment to make that decision later.</p>
<p>With all that taken care of, I started writing down what I want out of some of my desired features, such as emulating cards instead of dice.
This helped because, before I articulated my wants, I was thinking about this stuff in a manner that was too informal to really pin down anything related to tradeoffs or alternatives.
Now that I've spent a short amount of time reasoning through things, I know what the first thing I want to try is.
Which I will be trying, not today, because I'm tired.</p>
<p>I also put together kind of a complicated specification for how I think character sheets should work.
If I manage any sort of implementation of character sheets, it'll be a pretty big expansion in possible functionality, so that's definitely exciting.</p>
<p>Not exciting enough to keep me up much longer, though.</p>
<p>Good night.</p>
Coding 2020-06-032020-06-03T04:00:00-04:002020-06-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-03:/coding-2020-06-03<p class="first last">Oh boy, I'm going to need a local package repository if I go through with this idea...</p>
<p>I didn't get much time with my code tonight, so I'm just going to go over some of my plans for one project.</p>
<p>I believe I've mentioned working on a basic dice-rolling app for some roleplaying games.
If not, I've worked on a basic dice-rolling app for some roleplaying games.
Right now, the package has all of the generic stuff in modules under the root, and things for specific games in a subpackage.
The most concrete change I want to make is to make the per-game implementations independently installable.</p>
<p>I've got various other things I want to try, but I don't have a strong sense of what to go for first, so I think what I should do is figure out where the current implementation falls short, and work on improving that area, whatever it is.</p>
<p>And, I don't have enough consciousness left for tonight to ponder this in any more detail, so I guess I'm done.</p>
<p>Good night.</p>
Weekly Roundup 2020-06-022020-06-02T04:00:00-04:002020-06-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-02:/weekly-roundup-2020-06-02<p class="first last">"The first 90 percent of the code accounts for the first 90 percent of the development time. The remaining 10 percent of the code accounts for the other 90 percent of the development time."</p>
<p>It was all coding this week.</p>
<ul class="simple">
<li>Wednesday: I got a little further on the port.</li>
<li>Thursday: I finished the port of the tests as of a few months ago, then pulled, and ported the new test added since.</li>
<li>Friday: I got those new tests to pass. Then, I fixed a random deficiency that the port has had for a while.</li>
<li>Saturday: I started working on a stripped-down CLI for the port.</li>
<li>Sunday: I got play mode working in the CLI.</li>
<li>Monday: I wired the CLI into ink-proof. Unfortunately, even once I got the vagaries of command-line output dealt with (inklecate emits mystery newlines), I didn't really get anything new out of ink-proof. I should probably contribute some tests to it once I feel up to diving back into my code.</li>
</ul>
<p>Next week, I'm going to try to change gears at least a little, and take another break from the port.
Maybe get back to other coding projects, maybe switch things up a bit more.</p>
Coding 2020-06-012020-06-01T04:00:00-04:002020-06-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-06-01:/coding-2020-06-01<p class="first last">I'm going to have to learn to debug with Mono before I can hope to resolve these test failures.</p>
<p>Well, I got my CLI hacked into ink-proof, and the results were... only sort of interesting.
There were some failures, but I don't think any of them were due to the shortcomings I know my code has, but rather as a result of a difference in behavior between my CLI and inklecate that seems like an edge case to me.
In particular, when I look at the sources, I can't see why inklecate acts the way it does.</p>
<p>I'll figure that out, and work on improving the coverage, later, but for now, I think I need a break.
I'll think some about what to work on instead.
So far, I have a reasonable idea, and a probably bad idea.
I'll take some time over the next day to see if I come up with any others.</p>
<p>Good night.</p>
Coding 2020-05-312020-05-31T04:00:00-04:002020-05-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-31:/coding-2020-05-31<p class="first last">They have overlapping functionality, but I <em>think</em> they both have some unique features.</p>
<p>I didn't do conlanging or anything else today because I was focused on relaxing, and tinkring with the Ink port is relaxing when I'm not staring at inexplicable stack traces.</p>
<p>Ink CLI status: I skipped implementing a bunch of it, but it looks like the very basics work.
I finally pulled in some external dependencies: <a class="reference external" href="https://pypi.org/project/blessings/">blessings</a> for tty-aware ANSI escape codes, and <a class="reference external" href="https://pypi.org/project/colorama/">colorama</a> to make ANSI escape codes work with Windows.
(I haven't tested that that all works on Windows.)</p>
<p>Tomorrow, I'm probably going to try to hack my port into ink-proof, and see what's missing from the implementation according to it.</p>
<p>Good night.</p>
Coding 2020-05-302020-05-30T04:00:00-04:002020-05-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-30:/coding-2020-05-30<p class="first last">Blurring the line between self-isolation and just really not wanting to be out in that weather.</p>
<p>Ink CLI status: I've got a command-line interface sketched out, with much of it put behind a conditional because I haven't written a compiler.
Hopefully, the actual meat of it shouldn't be too much more code, since the code responsible is pretty short in the C# version.</p>
<p>Sorry I'm not up for writing more, but the weather still just, like, really sucks.</p>
<p>Good night.</p>
Coding 2020-05-292020-05-29T04:00:00-04:002020-05-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-29:/coding-2020-05-29<p class="first last">There are some tests I wrote before I worked out the Ink VM that don't, like, make sense. I should get rid of them, probably.</p>
<p>Well, it took some fields that I'm not really sure if that's how I want it to actually work, but my port of Ink has reached test parity with the current GitHub master.</p>
<p>I think next I want to write a CLI around this to mimic inklecate's play mode, and use that to create and manually verify test cases around all of the missing implementation stuff.
Also, I never did implement the initial random seed correctly, so I ought to get that right.
I'll see if that's something I can just knock out now.</p>
<p>Yep, it was relatively straightforward to get feature parity there.</p>
<p>It is oppressively humid in here, so I'm just going to wrap things up as quickly as I can again.</p>
<p>Good night.</p>
Coding 2020-05-282020-05-28T04:00:00-04:002020-05-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-28:/coding-2020-05-28<p class="first last">This space unintentially left blank.</p>
<p>I got through the Ink tests as of when I'd last pulled.
Then I updated, and got one additional test, which I opted to split into two tests.
Getting them to work promises to be a doozy.
I'm going to either need to rewrite a bunch of function signatures in an obnoxious way, or add extra fields to the StoryState object.
I'm leaning towards fields on the StoryState, but I've decided to sleep on this.
Given the rate of changes to Ink right now, I don't think I'm in a hurry.</p>
<p>As far as completeness of implementation, there are still around twenty stubbed-out branches in my code; hopefully getting set up with ink-proof will shake some of that out.</p>
<p>I've got to wrap up for now, I'm exhausted.</p>
<p>Good night.</p>
Coding 2020-05-272020-05-27T04:00:00-04:002020-05-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-27:/coding-2020-05-27<p class="first last">Once I start refactoring in earnest, I'm probably going to try to convert the conditionals that work on commands into a bunch of separate functions, because that's just a huge if-else block right now.</p>
<p>I went through a few more tests in the Ink port.
I think it's nearly done, just a few more to go.</p>
<p>Not much to say in detail.
It's gotten to the point where sometimes tests just find weird bugs.
Also, I found some behavior in mypy that sure seems like a bug; I'll have to look into that.</p>
<p>I'm working on another kind of abstract coding project, so that's some kind-of questionable judgment on my part, but I'm hoping to just learn stuff from it.</p>
<p>Anyway, nothing more to be done right now.</p>
<p>Good night.</p>
Weekly Roundup 2020-05-262020-05-26T04:00:00-04:002020-05-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-26:/weekly-roundup-2020-05-26<p class="first last">Attacked by trees and the sun. I think I've figured out where Captain Planet villains come from.</p>
<ul class="simple">
<li>Wednesday: I complained about the part of the Ink port I'm currently working on.</li>
<li>Thursday: I noticed some problems with how I was handling basic setup stuff in Ink, fixed those, and then ran into some bad organizational issues that I haven't fixed, just worked around.</li>
<li>Friday: I had the deserialization code almost wrapped up. (A subset of it, at least.)</li>
<li>Saturday: I shrank the test code by a bunch, which was nice. Then nature itself started attacking me.</li>
<li>Sunday: I thought over my progress reading the linguistics paper that I'm currently reading.</li>
<li>Monday: I was feeling too out of it, so I just did a diary about how out-of-it I was feeling.</li>
</ul>
<p>Next week, I'm going to try to get through some more of the tests in the Ink codebase, and maybe look into <a class="reference external" href="https://github.com/chromy/ink-proof">ink-proof</a>.
I've also got some other code projects I might look into.
Also also, I want to see about getting into creative stuff outside of coding again.</p>
Diary 2020-05-252020-05-25T04:00:00-04:002020-05-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-25:/diary-2020-05-25<p class="first last">I have been viciously attacked by the sun. (… I should keep a list of these somewhere.)</p>
<p>Just a diary entry for today, because I was zonked out and just did some light reading, pretty much.</p>
<p>I think how I'm feeling is that I've gotten kind of out into the weeds with various projects.
The Ink port is just a few dozen tests away from parity according to the tests, but that's not feature parity, because I'm sure the tests have gaps.
Conlanging is mostly waiting for feature grammar code, which is somewhat waiting on me reading the other half of the paper I've found, as well as possibly chasing a few references that sounded significant.
I've got grid-based game stuff I want to mess with, but getting that working means either learning an engine, or porting Dennis from Coconut to Python, which… hm.
I had to use a bunch of type ignore comments anyway, so maybe it'd be worth trying that in a branch.</p>
<p>Anyway, I'm also going to try to come up with a project that's fewer layers of abstraction away from mattering to other people.</p>
<p>Good night.</p>
Conlanging 2020-05-242020-05-24T04:00:00-04:002020-05-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-24:/conlanging-2020-05-24<p class="first last">When this paper makes any sense to me, it makes a lot of sense to me.</p>
<p>I didn't focus too much on conlanging today, but I did take some of what I've read about feature geometry and turn it into specific statements for the behind-the-scenes stuff.
If this all works out when I get to coding it, then I think it'll be much easier for me.
And if it doesn't, I'll still have a more principled idea of how to create rewrite rules.</p>
<p>It's getting late now, so I should wrap up even though I didn't have much to say.</p>
<p>Good night.</p>
Coding 2020-05-232020-05-23T04:00:00-04:002020-05-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-23:/coding-2020-05-23<p class="first last">I'm starting to get a little skeptical about the level of coverage I'll get after all of the tests I'm going for are ported.</p>
<p>Today in the Ink port, I wrote a tiny helper function and rewrote a bunch of tests to use it.
Then I wrote a few more tests.
I'm feeling good about working on this stuff again, but I can't do any more right this moment because the late spring (wow what) weather is keeping me down.
The pollen out there has done something to my sinuses, and the heat is making it feel like I'm melting.
Once again, reality has fallen short of an idealized environment, as is its wont.</p>
<p>I cannot accomplish anything else right now.</p>
<p>Good night.</p>
Coding 2020-05-222020-05-22T04:00:00-04:002020-05-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-22:/coding-2020-05-22<p class="first last">"In Spite of Some Glaring Omissions" is another good name.</p>
<p>I got a little further with the port.
Looking at what I encode, it's just a little further before most of the deserialization code falls into place.</p>
<p>It occurs to me that there hasn't really been much going on in these coding posts.
I should figure out something I can do with screenshots or video when this is more fully-featured.</p>
<p>Anyway, I talked up how close I was to done, enough that I decided to get it over with, and now, in spite of some glaring omissions in the code, the test passes.
Let's see what's in line for tomorrow...</p>
<p>Hm, looking at these tests, I don't have a sense for what'll fail.
I think tomorrow might be a good time to work on reducing test boilerplate.
Then, try out an idea I had to just port over all of the rest of the tests now, and mark them xfail so I can selectively enable them and avoid switching between the test files in the two projects.</p>
<p>Anyway, I'm super tired, so I guess I'm done for now.</p>
<p>Good night.</p>
Coding 2020-05-212020-05-21T04:00:00-04:002020-05-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-21:/coding-2020-05-21<p class="first last">I'm confident this code can be made better. I'm just not totally sure what and how much that will require.</p>
<p>My port of the serialization code is growing somewhat more cursed.
I think I see a way to rescue some of it, but it'll need some test rewrites to reduce boilerplate first.</p>
<p>The basic issue I have to address is that a bunch of the StoryState deserialization in the C# version strongly expects the StoryState to already exist.
This really isn't intuitive to me, but I can deal with it.
The only logical value for the StoryState to start with is the initial value that can be generated by going through the <tt class="docutils literal">global decl</tt> container.
Currently, this is generated from a top-level function in the package root, but I can switch it to a class method easily enough.</p>
<p>In fact, I'll take care of some of that now.
And when I did, I removed some imports and that made it fail with a circular import error.
<em>Somewhat</em>.
<em>Cursed</em>.
(Am I going to need to write a distinct test run for importing each module at the top level of the test script?
Because the fact that importing modules in the wong order can mess things up this bad is... bad.)</p>
<p>Anyway, I'm going to go lie down and try not to think about that too hard.</p>
<p>Good night.</p>
Coding 2020-05-202020-05-20T04:00:00-04:002020-05-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-20:/coding-2020-05-20<p class="first last">Writing like five lines or whatever, but they're really mentally taxing lines.</p>
<p>Did some more reading on phonology today, and I can see now that the stuff I'm reading will have me in for the long haul.
Just casually dropping the fact that some of the stuff it shows off in figure 11 will be elaborated on in <em>figure 123</em>.</p>
<p>Anyway, I got back to working on the Ink port.
It was nice to come back to it after the break.
Although, I'm currently in the guts of the serialization code.
It's giving me wistful flashbacks to the serialization code in Dennis, which was much easier to write, and worked with, I think, more complicated data.
(This is because, rather than using the standard library to work at a level just slightly higher than the C# version, I was using the <a class="reference external" href="https://camel.readthedocs.io/en/latest/">camel</a> library, which is, regrettably for me in this exact context, not a drop-in replacement for stdlib json, and I don't know if C# has an equivalent.)</p>
<p>I'm probably going to be in slow-and-steady mode a bit on everything, since I'm like a sixth of the way through the article I'm looking at now, and the serialization code is... kind of a slog, if I'm being honest.</p>
<p>Good night.</p>
Weekly Roundup 2020-05-192020-05-19T04:00:00-04:002020-05-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-19:/weekly-roundup-2020-05-19<p class="first last">I was listening to Takamachi Walk's Permanence while writing this. It helped.</p>
<ul class="simple">
<li>Wednesday: I got my rewrite of SCA² working. It needed some usability improvements.</li>
<li>Thursday: I made some usability improvements, and started messing with the idea of trying out a different design and having this as a fallback.</li>
<li>Friday: I thought I'd researched enough to get a prototype for the new system out in a few days.</li>
<li>Saturday: I was wrong.</li>
<li>Sunday: I pulled some of my old notes into the new repository, and thought more about the design of the feature geometry stuff. (I'm updating the link when this post goes live.)</li>
<li>Monday: I took things easy, and figured out what's next for conlang development.</li>
</ul>
<p>(Today, I got fucked up because I saw what some</p>
<p>…</p>
<p><strong>person</strong></p>
<p>…</p>
<p>decided to put on their Twitter timeline.</p>
<p>This isn't some kind of ironic "hahah, this is terrible" thing.
Somebody working content moderation is going to have to look at it at some point, and if they're lucky (but not by much), they won't yet be numb to the horror.)</p>
<p>Next week, I'm going to try to get back into the Ink port.
And to feel better.</p>
Conlanging 2020-05-182020-05-18T04:00:00-04:002020-05-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-18:/conlanging-2020-05-18<p class="first last">Have to remember not to overthink things…</p>
<p>I mostly read stuff today, but I did a little more work conlanging.
I realized that, although I don't yet have a better option for glosses than the tabular approach I'm taking (which has some issues to iron out), for tracking changes in syntax, representing each version of a sentence as a list item should be sufficient.</p>
<p>I came up with a few simple sentences to try to track over the course of the language's fictional history.</p>
<p>I don't have much more to say.
I guess I'm a little burnt out again, which is hardly surprising.
So, I should wrap things up for now.</p>
<p>Good night.</p>
Conlanging 2020-05-172020-05-17T04:00:00-04:002020-05-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-17:/conlanging-2020-05-17<p class="first last">Slow but steady(?)</p>
<p>Today I mostly focused on reading more about phonology.
I did take some time to migrate some of my old notes into the new repository.
My basic plan is to sketch out grammatical details and work my way from there, combined with a mixture of plausible loanwords and generated ancient roots.</p>
<p>From my reading-up, I'm getting the impression that I can use the models I'm reading about to create a more fully-featured model of syllable structure than "whatever's there after the sound change rules are done".
My dream here is to have a system that can encode information about the world, as well as language-specific constraints.
This encoding would be <a class="reference external" href="https://www.hillelwayne.com/post/constructive/">predicative rather than constructive</a>, both because I think that would be easier to tinker with, and because much of linguistics is concerned with reasoning about the acceptableness of possible sequences, or sometimes their <em>marginal</em> acceptableness.
I want to make tinkering easy because I hope it's possible to make something that works both on human speech, and, say, on bird-like vocal systems, which it seems to me would have to have a different feature tree because they're not shaped the same.</p>
<p>Anyway, to make progress conlanging, I'm going to need to study historical linguistics more broadly, especially the notation.
I've got ideas about changes in syntax over time, but I don't know how to represent those changes.
I tried to track down some sources there immediately after typing that, but no dice.
I should wrap up for now.</p>
<p>Good night.</p>
Coding 2020-05-162020-05-16T04:00:00-04:002020-05-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-16:/coding-2020-05-16<p class="first last">Turns out this stuff is hard. Who knew? (The answer is every linguist.)</p>
<p>I've read even more about the concepts around distinctive features in linguistics, and my conclusion so far is...
That I need to read <em>even more</em>.</p>
<p>I think I'm close to having a workable design based on the ideas I'm reading about, but I'm itching to code <em>something</em>, so next week I'm going to switch back to actively developing my Ink port, and reading papers so I can do design work on this stuff.</p>
<p>I wanted to say more, but I guess I'm tired, the weather is gross, and I didn't do much today that fits well in a post.</p>
<p>Good night.</p>
Coding 2020-05-152020-05-15T04:00:00-04:002020-05-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-15:/coding-2020-05-15<p class="first last">I've got a plan. We'll see how it works out.</p>
<p>I spent some time today trying to synthesize the various things I've read about representing linguistic features into something that makes sense to me.</p>
<p>What I'm going for right now—tentatively—is to try to do something with feature geometry.
I just found out about it... it must be less than an hour ago, as I write this, but it seems interesting, and accords with some of my previous attempts to understand how features are reasoned about.</p>
<p>Per Wikipedia:</p>
<blockquote>
In 2008 Jeff Mielke argued that feature geometry merely recapitulated physiological organization, and that since the influence of articulation on sound change will independently create patterns in the behavior of features, feature geometry recapitulates diachrony and is redundant as a theory of the mental organisation of phonology.</blockquote>
<p>This criticism doesn't seem to speak against using feature geometry for my purposes, because I'm not interested in specifically modeling mental processing; rather, I'm interested in the observable changes in phoneme usage in particular contexts over time.</p>
<p>Unlike some other areas of this project, where I can look at a theoretical concept and work out "Well, obviously this should work for my purposes, and if I make these concessions here, it'll simplify the overall implementation", I am not qualified to weigh in on the debates that appear to exist on these matters.
The best I can do is to go through a few rounds of prototyping and see if anything is obviously and foundationally wrong with the idea.</p>
<p>I'll get on the prototyping tomorrow, but I'm going to try to take things easy for now.</p>
<p>Good night.</p>
Coding 2020-05-142020-05-14T04:00:00-04:002020-05-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-14:/coding-2020-05-14<p class="first last">Trying to be a humble STEM major.</p>
<p>I came up with a more concise interface for creating phonological rules in my sound change rewrite, so now it only takes up 20 lines, which is fine.</p>
<p>My next concern is that the current design operates on specific named phonemes, and explicit collections of them.
I'd like to overhaul it to work with distinctive features, which would simplify some of the rule definitions.
First, though, I need to figure out which theories of distinctive features I want to support, and how to do so.
This is a question of specification, and I can't fall back on replicating behavior or porting tests this time.</p>
<p>Here's what I've got from a cursory inspection of Wikipedia and its sources:</p>
<ul class="simple">
<li>Maybe "distinctive features" aren't universals</li>
<li>Maybe the distinctive features for vowels aren't what most linguists think. Then again, maybe they are. Maybe it varies by language.</li>
<li>Historically, distinctive features were thought of as having two values which can both be explicitly reasoned about</li>
<li>More recently, the idea of features whose absence cannot be explicitly reasoned about gained traction</li>
<li>Some frameworks use both kinds of feature for different purposes, some go all in on one or the other</li>
<li>Some that use both (and maybe some that use only binary features?) have the possibility that a binary feature is "unspecified" for some concrete phonemes.</li>
</ul>
<p>Since I'm currently interested in this for the potential to improve phonological rules, I'm not interested in totally general applicability, just how different approaches apply to phonological rules specifically.
Also, for some of this I sort of have an out, in that, whatever categories of feature I include, I don't have to model the details of the feature in the low-level implementation code.</p>
<p>Speaking of that code, at a high level, there are just a few basic tasks that have to be supported:</p>
<ul class="simple">
<li>Match a concrete phoneme against a concrete phoneme</li>
<li>Match a concrete phoneme against a category—that is, a subset of that phoneme's features. Under some theories, I believe a "category" in the sense I'm defining it here is considered an equally real phoneme that the "concrete" phoneme is in some sense a refinement of.</li>
<li>Match a concrete phoneme against a category and transfer the distinctive aspects of the phoneme within that category to another category.</li>
</ul>
<p>This last one is, I think, most likely to be problmatic, especially with some of the theories I mention above.</p>
<p>For example, suppose a phoneme changes its place of articulation, perhaps due to assimilation.
If doing so causes it to gain or lose featural distinctions, how do I account for that?
This sounds like an obvious question to ask, so it should have an answer in the literature already.
Hopefully, it's out there, and I just havn't seen it yet because I'm only skimming right now because it's late.</p>
<p>Anyway, tomorrow I'll work on research and specification.
I might also start breaking the code up some, because working with a 500-line module is still super-obnoxious.</p>
<p>Good night.</p>
Coding 2020-05-132020-05-13T04:00:00-04:002020-05-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-13:/coding-2020-05-13<p class="first last">Surprisingly low amount of horrible brokenness, for code that I only just started testing.</p>
<p>I made myself actually use the SCA² rewrite with writing tests.
Impressions so far:</p>
<ul class="simple">
<li>The design is solid</li>
<li>There were some howlers in the implementation</li>
<li>It's hard to navigate the source code, and I should probably break it into a bunch of modules.</li>
<li>In my opinion, which it should be understood is likely to be biased to see the various facets of this code in the best light possible... using the current interfaces to write phonological rules is like digging a trench with a spoon. And not a big spoon, either.</li>
</ul>
<p>This last point is basically a result of the fact that, instead of the original's style of mingling parsing and processing, there's virtually no parsing in this whatsoever.
Which is an improvement in some ways, but a massive reduction in usability.</p>
<p>To address this, I think I should, before I mess with any further enhancements, document everything wrong with the code in the tests, starting with the fact that 14 rule definitions somehow require 134 lines of code.
I'll get on it tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2020-05-122020-05-12T04:00:00-04:002020-05-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-12:/weekly-roundup-2020-05-12<p class="first last">Let's see what other cool things I come up with excuses to use in code.</p>
<ul class="simple">
<li>Wednesday: I started working out exactly how I want environment matching to work in my SCA rewrite.</li>
<li>Thursday: I came up with a few things that would be really useful for writing tests again the rewrite.</li>
<li>Friday: I got as far as implenting the code for performing environment matches, but not generating the specific instances required by a high-level description of the matching.</li>
<li>Saturday: I mostly finished the generation code. (I ended up filling in the gaps over the weekend.)</li>
<li>Sunday: I worked out some of the history of the con-culture by hand.</li>
<li>Monday: I transcribed my notes into my laptop.</li>
</ul>
<p>Next week, I'm going to write tests against the rewritten code, and consider some further refinements.
I'm also working on a writeup of the environment matcher design I came up with, because it's really cool, but it's looking like it'll be really long, because I want to try to make it accessible, which means I have to explain and motivate a lot of background material.</p>
Conlanging 2020-05-112020-05-11T04:00:00-04:002020-05-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-11:/conlanging-2020-05-11<p class="first last">I'd say this is the bare minimum of effort that's gone into a post, but I'm sure that's not true.</p>
<p>Today I was more focused on writing up my latest SCA² rewrite.
This turned out to be... a lot.
I'm not sure how many posts it's going to be; my goal is to make it generally accessible, and in service of that, I'm explaining or leaving myself notes to explain <em>a lot</em>.</p>
<p>To get something done conlanging, I transcribed my notes from yesterday.
This should be a starting point for the ancestral lexicon.</p>
<p>Moving forward with the behind-the-scenes, I'm going to need to rearrange the source files in there some, since the behind-the-scenes version needs to account for many more lexicons and syntax writeups than the public-facing version.</p>
<p>I guess I don't have anything else to say on the matter right now.</p>
<p>Good night.</p>
Conlanging 2020-05-102020-05-10T04:00:00-04:002020-05-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-10:/conlanging-2020-05-10<p class="first last">There is so much history that I don't know, or, more charitably, remember.</p>
<p>I didn't touch the files much today, but I was able to rough out the beginning of an idea of a timeline for when the con-culture was where.
I'll have to learn more history to figure out if my first ideas there are at all reasonable.</p>
<p>But, it's something.
I'm going to wrap up early-ish, because all the sun today gave me a headache, I think.</p>
<p>Good night.</p>
Coding 2020-05-092020-05-09T04:00:00-04:002020-05-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-09:/coding-2020-05-09<p class="first last">I should probably put together a post where I try to explain all of this, with diagrams.</p>
<p>I got a bit of work done on the port/rewrite: the code to represent and reverse a raw environment is in, as is most of the code required to convert a raw environment to a matcher automaton.</p>
<p>What's missing from that is the code to handle categories, which is complicated somewhat by the fact that it's also the code to handle word boundaries.
What's missing from the rest is the metathesis code, still, and some wiring-together logic that should be trivial.</p>
<p>I've been having kind of a rough week in general, but I think I'm making some minor breakthroughs in productivity, which is a nice bone to be thrown after over a month.</p>
<p>Anyway, I'm done for the night, so I'm wrapping up.</p>
<p>Good night.</p>
Coding 2020-05-082020-05-08T04:00:00-04:002020-05-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-08:/coding-2020-05-08<p class="first last">Fingers crossed for using this in a week.</p>
<p>Status on SCA² port/rewrite/I-don't-know: I've set up the code to implement matching via an automaton, but I haven't written the code required to <em>generate</em> an automaton, and expecting consumers to hand-write one would be... really bad.</p>
<p>I also haven't implemented targets yet, which is easy, I'll get it last.</p>
<p>Generating the automata shouldn't be a big deal; I just need to make sure my input format can handle everything.
It basically needs to handle word boundary matching, geminates, wildcards, categories (possibly including boundary matches) and literals, as well as nesting to represent optional sections.
The only interesting thing that it needs to be possible to do to the data for this is to reverse it.
Actually generating it is just a matter of iterating over the data and accumulating it into the automaton.</p>
<p>All in all, I should have this ready to go soon, and then I can write tests for it, which will probably reveal all manner of fascinating things.</p>
<p>For now, though, I'll just be glad to have made some more progress.</p>
<p>(One thing of note is that I'm making a bunch of basically-arbitrary choices because the design is underconstrained.
I haven't been able to predict what constraints could apply in the future, so I'm just making whichever choices make sense to me at the moment, since I don't have a stronger consideration yet.)</p>
<p>Good night.</p>
Coding 2020-05-072020-05-07T04:00:00-04:002020-05-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-07:/coding-2020-05-07<p class="first last">Well, it makes sense to me.</p>
<p>Today, I'd like to do the planning/design for the environment matching in here.</p>
<p>I'm thinking a helper class that combines a phoneme sequence and an index; it can perform one of several checks on demand.</p>
<p>Anyway, the trickiest bit is the automaton design.
Here are a few points to keep in mind:</p>
<ul class="simple">
<li>The automaton corresponding to an empty sequence always matches</li>
<li>The "earliest" that any state will refer back in the collection of states is to itself</li>
<li>Python's builtin sequences allow for indexing from the end.</li>
</ul>
<p>This means that the automaton can be built in a single pass by starting at the end of the match, and if it's done arena-style (I can't stomach the idea of repeatedly hashing the entire state graph), then the start state has index -1, and the state at index 0 is the success state.</p>
<p>States need to be capable of:</p>
<ul class="simple">
<li>perform a literal match and advance</li>
<li>check for set membership and advance</li>
<li>provide two states to check against the current position</li>
<li>accept any input and provide two indices</li>
<li>check the gemination status and advance</li>
<li>check the word boundary status, and provide another state to check against the current position</li>
<li>Being detectable as the success state before any further processing occurs</li>
</ul>
<p>Specific cases to check for: optionals or wildcards on their own should succeed immediately; this means that my "single-pass" idea might not pan out, unless the matching process is broken up very carefully:</p>
<p>Given an initial set of states (from the starting conditions or the previous step), generate a set of states that advance the string.
If the success state is encountered in this process, the match succeeds.
The following three states must be processed as part of this stage:</p>
<ul class="simple">
<li>The branch state must give its two targets as candidates</li>
<li>The wildcard state must give its successor as a candidate, and itself as a thing to perform a match</li>
<li>The word boundary state must give its successor as a candidate, but only if the word boundary condition evaluates to true.</li>
</ul>
<p>This can be viewed as a combination of "does this state have transitions that consume a phoneme?" and "what transitions does this state have that do not consume a phoneme?"</p>
<p>The stage can then be broken up into:</p>
<p>While there are candidates: process each candidate by adding its candidates to a new set, and possibly itself to a consumer set; if the success state is encountered, succeed; at some point filter out all candidates that have been seen from the new set; make the new set the candidate set; the output of this stage is the consumer set; if the consumer set is empty, then fail.</p>
<p>Although, if the consumer set is empty, then processing it will yield no candidates, so if the loop condition is the truthiness of the candidate set, then I could have an early return true inside the loops, and a fallback return false afterwards.</p>
<p>Wait, I'm confusing myself.
This isn't a while loop, it's a for loop.
Unless I make it a while loop and have the cursor handle advancing, which seems acceptable, and allows me to perform processing steps even when there aren't phonemes to process, which is necessary for the empty sequence to match the empty sequence.</p>
<p>I think I've got it all together.
Now I just need to be focused on this stuff long enough to get it all into code.</p>
<p>Good night.</p>
Coding 2020-05-062020-05-06T04:00:00-04:002020-05-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-06:/coding-2020-05-06<p class="first last">If I can keep the latest attempt from doubling in length, it'll end up shorter than the last one.</p>
<p>Today, I did the match logic for the "target" section of SCA² rules, which is one of the easiest parts, I think.</p>
<p>The logic for handling the replacement section is almost as easy, it just needs some subclasses or protocols or something.</p>
<p>Environment matching is the big hole so far.
It'll need some mild special-casing to handle degemination, and I think the main logic will have to operate on a sliding window of trigraphs or something.
I might need to just lay out all of the logic imperatively and see how much I can simplify it.</p>
<p>I mean, what I want to do there is convert the matching logic to a nondeterministic finite automaton, then convert that to a deterministic finite automaton, then make sure that runs properly off of a stream of phonemes.</p>
<p>The key weirdness in that is getting the matches right.
There's "literal phoneme", "list of phonemes", arbitrary-length sequence of anything, "the phoneme in the input word at the next lowest index", "word break (do not advance the stream)", and "optional sub-sequence".</p>
<p>This might sound like absurd premature optimization, but my intention here is to construct the logic from simple pieces in a principled fashion, rather than trying to enumerate every high-level special case.</p>
<p>Thoughts for how to do some of this:</p>
<ul class="simple">
<li>Include a "geminated" flag in the iterator implementation so the gemination test doesn't have to know about indices</li>
<li>Make sure it's possible to move through multiple states in a single iteration step</li>
<li>Oh, wait, my plan for gemination was to fold it into the category data, since a non-category gemination can be statically converted to a specific phoneme</li>
<li>Hm. Either one probably works, but having an explicit flag sounds like less work, I think.</li>
</ul>
<p>We'll see what works in a few days, hopefully.</p>
<p>Good night.</p>
Weekly Roundup 2020-05-052020-05-05T04:00:00-04:002020-05-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-05:/weekly-roundup-2020-05-05<p class="first last">Time status: possibly not real?</p>
<ul class="simple">
<li>Wednesday: I filled in some gaps in the second(?) SCA² port attempt I've made.</li>
<li>Thursday: I got the project all set up. (Although I think my backup system wiped out the commit? It's weird like that.)</li>
<li>Friday: I started planning the third attempt.</li>
<li>Saturday: I started working on the third attempt.</li>
<li>Sunday: I worked on my conlanging notes a little.</li>
<li>Monday: I ported some more from the notes to my current repository.</li>
</ul>
<p>Next week, I'm going to try to get the third attempt to a position where it can run a test, then maybe get back to the Ink port if there's time.</p>
Conlanging 2020-05-042020-05-04T04:00:00-04:002020-05-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-04:/conlanging-2020-05-04<p class="first last">Why is it suddenly so hot?</p>
<p>Conlanging side: ported the rest of the correlatives chart to reStructuredText, ecause that was easy and I'll need it eventually.</p>
<p>Everything else side: barely leaving the house for over a month now seems to be taking some kind of toll.</p>
<p>Good night.</p>
Conlanging 2020-05-032020-05-03T04:00:00-04:002020-05-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-03:/conlanging-2020-05-03<p class="first last">Just keep taking it easy, I guess.</p>
<p>I did some planning work for the SCA port, but I didn't try to push it forward yet.</p>
<p>On the conlanging side, that's waiting on a usable form of SCA, but I did refer to some of my old notes and worked a little on the proto-language grammar.</p>
<p>I'll probably be taking it easy until I get the code to be usable.</p>
<p>Good night.</p>
Coding 2020-05-022020-05-02T04:00:00-04:002020-05-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-02:/coding-2020-05-02<p class="first last">"I don't foresee any issues with this course of action." would go <em>great</em> on a tombstone.</p>
<p>I started on what's apparently the third (maybe fourth?) iteration on porting SCA².
Fortunately, I'm understanding it better each time, so I think there's a chance this time will get it into a state I want to use.</p>
<p>There's not much to say specifically about it, since it's just been a matter of filling in stub implementations with the stuff I wrote up yesterday.
It's not all done, and some of the things I haven't gotten to are definitely fiddly, but I don't foresee any issues with this course of action.</p>
<p>Okay, I should wrap up for tonight.
Sorry I didn't have much to say, but it's just like, it looks like my plan was solid.
Not really a lot to write about; maybe some of the bits I currently have stubbed out will be more, um, fruitful.</p>
<p>Good night.</p>
Coding 2020-05-012020-05-01T04:00:00-04:002020-05-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-05-01:/coding-2020-05-01<p class="first last">You'd think I would learn about making big, sweeping changes.</p>
<p>Instead of writing more tests, I thought about the datatypes involved in SCA², and I concluded that I wanted things to be less stringly typed before I went forward.
I started redoing a bunch of stuff, and that was probably a mistake, because now it's kind of frankensteined together.</p>
<p>Hm.
Yes.
I'm going to save a diff, revert, fix some bugs I found in the rewrite, and start over with an actual plan.</p>
<p>Bits of a plan:</p>
<ul class="simple">
<li>Specific types of morphemes, lines, categories, environments, targets, replacements. (There are valid replacements that aren't valid targets)</li>
<li>For environments, have explicit separation between "before" and "after", and check before <em>backwards</em> from the current index into the line. This should allow for some capabilities that don't exist in SCA².</li>
<li>Targets are optionally a category, followed by phonemes</li>
<li>Replacements are a sequence of phonemes, and if the target started with a category, optionally a category; or metathesis or gemination</li>
<li>Morphemes are wrappers around string constants</li>
<li>Lines are wrappers or aliases for a sequence of morphemes (including word boundaries)</li>
<li>Categories are wrappers for a sequence of morphemes, and can be combined.</li>
<li>Environments allow for special sequences for word boundaries (can't be a space, because it matches at the beginning), degemination, and wildcards</li>
<li>Replacements operate on the input word, and construct an output word</li>
<li>It may be possible to use some kind of enhanced iterator to implement the transformations as a stream, but given the expected length of a word, it's not going to be worth it.</li>
</ul>
<p>I'm exhausted right now, but let's see if I can put any of this into action tomorrow.</p>
<p>Good night.</p>
Coding 2020-04-302020-04-30T04:00:00-04:002020-04-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-30:/coding-2020-04-30<p class="first last">I'm not sure how much faster I want doing this with cell to be, but it's got to be at least an order of magnitude.</p>
<p>So, I kind of procrastinated on setting up a flit project.
Instead, I've theoretically got a full implementation of every function I copied over so far.
We'll see; the code is more-or-less at "eyeballed vigorously" level of quality assurance, so I wouldn't trust it.
On a related hand, however, I don't have an interface designed for it, so really, this is all kinds of a tossup right now.</p>
<p><em>Anyway</em>, I'm going to document all of the steps I need to do, and do them, so I can hopefully get this done tonight.</p>
<ul class="simple">
<li>Create artifacts directories outside of my synched directories. This step is specific to my kind of lazy and janky home directory setup. Basically, I don't want to deal with conflict files in my build artifacts. I did this earlier today because it's quick, although I didn't symlink the directories in yet. I'll get that now.</li>
<li>Create a source control repository. I've mostly been using <a class="reference external" href="https://pijul.org/">pijul</a> for my new projects, so I'll keep that up.</li>
<li>Next I'll need an ignore file. Let's see if I can grab one from another project... All set, although it does indicate that I might have created some unneeded directories in the first step. Eh.</li>
<li>Need a bunch of configuration files, and some minor reorganization... Okay, the source is in the right place, now, setup.cfg, requirements.txt, README.rst, pyproject.toml, noxfile.py, more requirements files, mypy.ini, .coveragerc, and now I'm suddenly remembering why I want to write cell, sheesh.</li>
<li>Create a python environment...</li>
<li>Run the tests so I remember what I haven't handled yet... Added a few things, like docs directory, some metadata, and updated checker requirements.</li>
<li>Okay, let's do the initial commit.</li>
</ul>
<p>And, that's enough for now.
Tomorrow, I'll sketch out how I want to use this code, and maybe start getting the coverage up from 4%.</p>
<p>Good night.</p>
Coding 2020-04-292020-04-29T04:00:00-04:002020-04-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-29:/coding-2020-04-29<p class="first last">I refuse to git gud.</p>
<p>Earlier this afternoon, I added some tentative implementations to my SCA² port.
I puzzled over some of my past implementation choices enough that I think I ought to have some proper documentation in here.</p>
<p>I could have worked on that later tonight, but instead I hate-read documentation on how the Git server is configured at work.
It has been over a year since it got set up, and the pain from the workflow hasn't gotten any less bad, just more predictable.
If I had to sum it up, I'd say that it feels like everything is being sacrificed on the altar of conforming to a specific set of commit history aesthetics that nobody has given me a reason to care about.
(I think the basic crux of it is that the server is configured—I think, it's confusing—to require fast-forward merges to certain kinds of branch, and also to disallow "foxtrot merges" to them.
The explanations I've read of foxtrot merges say you can do anything you want on topic branches, you just have to merge them back correctly.
But my actual experience with plugins that are supposed to prevent this stuff is that the quickest way to address these merges is to... rewrite history on the topic branch.)</p>
<p>Sorry to go off like that and not edit it back out, but I really needed to vent.</p>
<p>Anyway, I'm going to work on converting my porting effort into a flit project and look into writing tests for it.
Tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2020-04-282020-04-28T04:00:00-04:002020-04-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-28:/weekly-roundup-2020-04-28<p class="first last">Lot of failure, for some reason. Oh well.</p>
<ul class="simple">
<li>Wednesday: I tried to totally redo the analogue to "Pointers", and failed.</li>
<li>Thursday: I tried again with a weird Frankenstein half-measure that gets things just close enough to the right format. The half-way nature of it bothers me, but for now I'd rather move on. Then I hit a Mypy bug that I never understood well enough to file.</li>
<li>Friday: I tried to understand the Mypy bug, and failed.</li>
<li>Saturday: I finished writing a serializer, but I'm missing deserializer components.</li>
<li>Sunday: I finished some needed reorganization of the conlang writeup.</li>
<li>Monday: I started working on a fork of the conlang writeup that includes worldbuilding details that I don't want to publish. Hopefully, these will allow me to fill in enough information to have pronunciations finally.</li>
</ul>
<p>Next week, I'm going to revist porting SCA², and probably also port over some more of Ink'd deserializers.</p>
Conlanging 2020-04-272020-04-27T04:00:00-04:002020-04-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-27:/conlanging-2020-04-27<p class="first last">Progress is progress.</p>
<p>I didn't get a particularly early start on conlanging today, but I got some needed planning done, and started porting stuff over from my old notes.</p>
<p>My basic plan is that I made a new branch of the repo where I'm writing the grammar.
That branch is going to be "everything in the published version [when it's published] PLUS world-building details that guide the creative process, but I don't want to include them".</p>
<p>So far, that just has brief details on the different forms of the language that I want to flesh out.</p>
<p>It just occurred to me that I'm going to want to have some kind of verification that the different versions of the lexicon actually do link up via sound change.
Perhaps this would be a case for doctests?
Which would need me to get back to that other porting effort I was doing recently.
I don't think I'd mind that, but I'm not doing it right now.</p>
<p>Good night.</p>
Conlanging 2020-04-262020-04-26T04:00:00-04:002020-04-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-26:/conlanging-2020-04-26<p class="first last">I had trouble coming up with a summary, and spaced out for half an hour. Not a good move.</p>
<p>I got a late start today, but I have the first version of the glossary put together.
Next version: put spellings to words and use those.</p>
<p>Getting actual pronounceable spellings does feel like something I want to get on soon; I started trying to put together a basic lesson to give me some idea of how to structure the grammar, and using just placeholders here feels kind of empty.</p>
<p>I'm probably too sleepy right now to handle this well, but here are some ideas:</p>
<ul class="simple">
<li>Put together a list of the grammatical changes that have taken place since the ancestral form</li>
<li>Mark particular changes as likely to result in the re-analysis of words</li>
<li>Place candidate sound changes in relation to all of this.</li>
<li>Work out general flow for lexicon entries through all of this.</li>
<li>Start trying stuff out in the ancestral language and see where it ends up.</li>
</ul>
<p>I should get on this earlier tomorrow, it seems like a lot of work.</p>
<p>Good night.</p>
Coding 2020-04-252020-04-25T04:00:00-04:002020-04-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-25:/coding-2020-04-25<p class="first last">I thought I was all set to continue porting tests, until I remembered that to do a round trip, you need to go <em>both ways</em>.</p>
<p>I now seem to be able to serialize arbitrary StoryStates, but I can't yet deserialize them.
Soon.</p>
<p>I don't have much to say about getting the serialization working, as it's a straightforward port of the C# version, with some slight sanity checks based on remembering how the deserialization logic that does exist works.</p>
<p>Having more to say about anything would be cool, but I'm way wiped out so I guess I won't.</p>
<p>Good night.</p>
Coding 2020-04-242020-04-24T04:00:00-04:002020-04-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-24:/coding-2020-04-24<p class="first last">Not a fan of thinking I know the essence of a behavior, and not being able to replicate it.</p>
<p>Update on the Mypy issue I hit: I was able to reduce the issue to a few lines of code, but I couldn't reproduce it outside the context of the port.
I was able to work around the issue, and move on.</p>
<p>I'm going to try to describe what I worked out about the issue, because it's weird:</p>
<p>There are two modules.
They import each other.
One module defines a type and an instance of that type, as a global value, un-annotated.
The other defines a function.
In the function, and it's possible I missed some opportunities for reduction, but what I got was:
A variable annotated with a type defined in the other module, a variable that is equal to an expression that depends on the first variable and the global value from the other module, and a flow control statement that includes an expression of the form <cite>isinstance(var := expr, ...)</cite>.
Under some but not all circumstances, this will crash Mypy.
I cannot tell what differentiates things.</p>
<p>Anyway, I'm now working on writing serializers for Ink objects, to go along with the de-serializer I sort of forgot I had to write to make any of this work.</p>
<p>I did that a bit, and now I'm done for tonight.</p>
<p>Good night.</p>
Coding 2020-04-232020-04-23T04:00:00-04:002020-04-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-23:/coding-2020-04-23<p class="first last">I should learn electronic music production, and make sad songs under the name "Technically Sufficient and Deeply Unsatisfying"</p>
<p>I ended up not being able to swap out the core logic of the port to use pointers, but I was able to convert everything I needed at the edges.
This is both technically sufficient and deeply unsatisfying, but I've got work to do.</p>
<p>The biggest obvious hole in the serialization code, after I handled the pointer stuff, is the lack of serializing runtime objects.
I'm still not excited to try to mix subclassing with the way I did this, so I've got a big Union of all of the subclass equivalents.
It turns out that a fifteen-plus-variant union generates <em>a lot</em> of type errors.</p>
<p>I've been working my way through things, getting bits of code actually typed, but I've hit a snag that I'm too sleepy to handle right now: I've somehow broken Mypy.
(Again.)
I tried to do a simple refactor, and suddenly it's telling me to test against master and file a bug.
I kind of need a reproduction first, and my attempts so far have not reproduced the issue.</p>
<p>Anyway, time to wrap up.</p>
<p>Good night.</p>
Coding 2020-04-222020-04-22T04:00:00-04:002020-04-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-22:/coding-2020-04-22<p class="first last">A learning experience.</p>
<p>The change I've been psyching myself up for is to convert from using paths everywhere, to having an explicit analogue to Ink's "Pointer" type.
C# Ink Pointers are a combination of a Container object and an integer index.</p>
<p>What I want is a combination of a CanonicalPath (which is a rough, rough equivalent of the path attribute on Ink Objects) with an index.
I tried to do this, and I ended up changing too much at once.
It was supposed to be a refactor, but there was just so, so much red.</p>
<p>Tonight ended up being a bust, but at least now I know what to do next: figure out how to roll out the changes bit by bit, using a compatibility interface between old and new to gradually expand the coverage to the entire codebase.</p>
<p>Once that's done, I can finish implementing serialization and deserialization, and get back to work on the tests.</p>
<p>Good night.</p>
<p>EDIT: What are "days"?</p>
Weekly Roundup 2020-04-212020-04-21T04:00:00-04:002020-04-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-21:/weekly-roundup-2020-04-21<p class="first last">I think I know what I want to work on when I decide to take a break from this: revisiting the whole Mypy plugin thing.</p>
<ul class="simple">
<li>Wednesday: I got into unexplored territory with the Ink port again.</li>
<li>Thursday: I finished writing tests for calling Ink functions from game code.</li>
<li>Friday: I psyched myself up for implementing Ink-style lists.</li>
<li>Saturday: Started the implementation...</li>
<li>Sunday: I did a little housekeeping in the conlang lexicon.</li>
<li>Monday: I figured out the answers to some questions I had on categorization.</li>
</ul>
<p>Next week, I'm going to redo some of the data representations in the Ink port to make serialization easier.</p>
<p>Also: since I'm emulating all of the variable observer logic myself, I need to make sure that everything that mutates the state that's visible to the consumer fires off the observer logic.
This might be a case for a decorator?</p>
Conlanging 2020-04-202020-04-20T04:00:00-04:002020-04-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-20:/conlanging-2020-04-20<p class="first last">Out-of-context thing I typed just now: "don't let Strunk and White say I never did anything for them."</p>
<p>I wasn't too focused on conlanging today, so I once again put out some quick work a few minutes ago.
I'm glad I did it though, since it's helping to clarify the grammatical role of some words I wasn't really sure what to do with, and I should have a way forward when I'm a bit better rested.</p>
<p>On the Ink front... I've got some architectural walkbacks planned that I want to sleep on before I commit to them.
Nothing as drastic as reintroducing reference cycles, but I'm not sure whether making the changes I have in mind, or not, would be better overall.</p>
<p>Good night.</p>
Conlanging 2020-04-192020-04-19T04:00:00-04:002020-04-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-19:/conlanging-2020-04-19<p class="first last">I should look into doing more glosses soon.</p>
<p>Nothing too exciting for today.
I got a few entries ready to put into glossaries, moved some sections into the proper file, and started consolidating the glossaries.
The big barrier right now is the section on anaphors.</p>
<p>Besides that, I wrote up a little more worldbuilding, this time of fringe religious beliefs, and some brief notes on possible loanwords from various periods.</p>
<p>Aside from that, I was still doing some stuff with the Ink port, which was tricky, because now it's kind of all in on "bugs are probably caused by code that was neither ported nor stubbed, so it just goes merrily past."</p>
<p>Good night.</p>
Coding 2020-04-182020-04-18T04:00:00-04:002020-04-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-18:/coding-2020-04-18<p class="first last">I think I've managed to have <em>more</em> stubbed-out suites than I did the last time I checked. Apparently implementing things results in more things explicitly not being implemented?</p>
<p>Okay, I've gotten through one list test.
Getting stuff to pass is requiring some relatively subtle tweaks to make sure things have the right value at the right time.
The latest bit of missing functionality looks like it's going to require plumbing more data through some of the functions.</p>
<p>Regardless, I may be really unsure what some of my latest changes are actually, like, doing, but the tests pass, so it must work perfectly.
(It does not work perfectly.)</p>
<p>I've been looking into some other projects to try, so I might be due for a break from this; I'll see what I think next week.</p>
<p>Good night.</p>
Coding 2020-04-172020-04-17T04:00:00-04:002020-04-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-17:/coding-2020-04-17<p class="first last">I'm basically done after this, right? (I am not.)</p>
<p>Well, I got calling functions from outside working, and getting the tests to pass wasn't too bad.
I went a bit further.
Implementing tags wasn't too much of a hassle.
Now, I have to handle lists, finally, which I suspect might end up being nearly as much of a hassle as the original few tests were, where there was practically nothing implemented.</p>
<p>Here's what needs to happen, more or less...
There are a bunch of support classes just for working with Ink lists, and I need to follow each one from creation until I'm sure it's done mutating.
Given that some of these classes have members called "cache" on them, that might technically not happen.</p>
<p>But, when the time comes (tomorrow), I'll get to work on it and see what I can get out of the source code.</p>
<p>Good night.</p>
Coding 2020-04-162020-04-16T04:00:00-04:002020-04-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-16:/coding-2020-04-16<p class="first last">I feel like I'm getting very good at doing this extremely specific kind of translation.</p>
<p>Ink port status: I've gotten through most of the tests around calling functions from outside the VM code.
The next test is around setting non-existent variables, and I'm fairly sure I haven't covered that, so I'll try to do it tomorrow.</p>
<p>I'm noticing some gaps in coverage that are brought about by how I implemented things.
For example, I'm explicitly managing the list of events to send to the variable observers, which means I should probably write a test around using variable observers with function calls "from the game".</p>
<p>Thinking over the stuff I'm missing, I'm probably going to have to review the public API when I'm done, and figure out how to address the many, many discrepancies that are going to show up.</p>
<p>Anyway, I've been spacing out once again, so I should call the entry now.</p>
<p>Good night.</p>
Coding 2020-04-152020-04-15T04:00:00-04:002020-04-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-15:/coding-2020-04-15<p class="first last">"Drastic Undercount" sounds like someone pretending to be drow royalty.</p>
<p>I tossed together an unrelated coding project yesterday.
I'll see if that goes anywhere.</p>
<p>Anyway, on the Ink port front, I got one more test ported today, and then the next one was kind of a doozy.
This is the first test that involves triggering a function evaluation from outside the VM context, and since I've only implemented functions and complicated code paths as I've needed, support for that functionality right now is patchy at best.
(Also, I just noticed that I've somehow been drastically undercounting the tests that target the Ink VM.
I thought I was almost done, and it's more like not-quite 2/3 of the way through, apparently.
That number makes sense, but I'm not sure how I messed up.)</p>
<p>Here's what I'm thinking: the interface I expose has a return value of (the state, the function result, the text).
Possibly the result and the text will be bound up in a namedtuple.
There's probably more to this, but I think the best way to move forward there is to just try a bunch of stuff.</p>
<p>In other, non-coding news, I've been following the development of <a class="reference external" href="https://penguinking.com/gone-to-hell/">Gone to Hell</a>, and I'm kind of tempted to try to make an unofficial Slayer character outside the core focus: THE CHOSEN ONE, a JRPG-inspired hero's-journeyer who can solve problems through such means as throwing an absurd amount of money at overcoming them, and has a light action to mindlessly grind for resources.
I'll try to do something with that idea when I'm better-rested than I was today.</p>
<p>Hopefully I'm not messing that up too much right this instant.</p>
<p>Good night.</p>
Weekly Roundup 2020-04-142020-04-14T04:00:00-04:002020-04-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-14:/weekly-roundup-2020-04-14<p class="first last">It is frankly astonishing how many bugs can exist around visit counts, while the code still "mostly works".</p>
<ul class="simple">
<li>Wednesday: I discovered a subtle but pervasive bug in some of the new code I wrote for the port. Finding it was... interesting.</li>
<li>Thursday: I implemented the type coercion in Ink.</li>
<li>Friday: I walked back some of the more radical design changes I made, because they weren't doing what they were supposed to.</li>
<li>Saturday: I prepared to do a little extra code work on the weekend.</li>
<li>Sunday: I added a little more content to the lexicon, and then got a little sidetracked reorganizing it.</li>
<li>Monday: I rewrote the glosses so they're hopefully a little more stable.</li>
</ul>
<p>Next week, I'm going to try to push through the remaining tests of the Ink VM, and maybe try to add tests of functionality that's not covered.
On the conlanging side of things, I want to review the outline organization, and then get to filling stuff in.</p>
Conlanging 2020-04-132020-04-13T04:00:00-04:002020-04-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-13:/conlanging-2020-04-13<p class="first last">I should probably do a writeup on how I'm using Sphinx, once this is in a publishable state.</p>
<p>One of the speed bumps I've been encountering in using Sphinx is that the link syntax is a little heavy-handed for the contexts I'm using it, and it's sensitive to the details of the exact target of the link.
As a result, when I tweak the lexicon, it results in a bunch of crazy diffs in my glosses.
I finally got fed up enough with this to figure out that substitutions will help me.
Basically, I'm currently working with gloss abbreviations rather than "actual words", and the big change I made today was to define substitutions for every abbreviation rather than copying the same link syntax everywhere.
As a result, when I update the way the links work, I just need to change the substitution, which isn't defined in a table, so it doesn't have a bunch of inevitable knock-on effects.
I'll still end up changing stuff in the future, but only when I actually change something about the visible content in the glosses.</p>
<p>As far as the updates that inspired this change, I've got most of the glossed words updated, but I haven't yet tried to merge the glossaries together.
I'd kind of like to find a new home for the parts-of-speech link targets first, and that means I need to make sure I have a proper handle on the organization of the grammar.</p>
<p>So that today wouldn't be just housekeeping, I did a rough draft writeup of the different major paradigms in the conlang, laying out the kind of variation to expect from nouns, verbs, and a few major categories.</p>
<p>Moving forward, I want to finish glossary-ifying the lexicon, and then get the draft of the correlative table ported.
When I start filling that in, I think I'll end up redoing some of the stuff that went into the glosses, so there'll be minor adjustments there.
Once that's done, I want to review all the sections of the grammar, and figure out what needs to be in each.
After that, I want to start tracing out the histories of various words, so I can hopefully get some diachronics done and get this to a point where anything at all has a pronunciation.
Hopefully I'll also get some worldbuilding in there; I've already added a few notes on religion.</p>
<p>Anyway, I'd like to take it easy for the rest of tonight, so I'm calling this entry here.</p>
<p>Good night.</p>
Conlanging 2020-04-122020-04-12T04:00:00-04:002020-04-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-12:/conlanging-2020-04-12<p class="first last">I should figure out how to fix up the PDF output. There's just so much overfull hbox right now...</p>
<p>Today, I started working on the correlative table.
I made a few decisions, then realized that I really should get the lexicon into the form of a definition list.
I'm working on adapting each individual section of the lexicon, and I'll merge them together later.
Doing it incrementally does have the slight disadvantage that I have to <em>keep on</em> fixing the table layout for the glosses, but oh well.</p>
<p>Anyway, as I put stuff into the glosses, I get links to parts of speech out of it, and I'll start filling actual details into those afterwards.</p>
<p>I mentioned I made some decisions.
One was to make a four-way distinction in the demonstratives.
This is a little outside of the norm of languages I know (one or three seems like the most common to me), but it's not totally crazy, and it should be too much of a hassle to work with.</p>
<p>I might have gotten a bit more done on all of this, but I put in a bit more time on the Ink port instead.
As the test coverage increases, the remaining bugs get gnarlier and more ridiculous.
One bug covers up the existence of another, causing the fix for it to result in fresh test failures.
It kind of feels like this:</p>
<div class="youtube youtube-16x9"><iframe src="https://www.youtube.com/embed/aI0euMFAWF8" allowfullscreen seamless frameBorder="0"></iframe></div><p>Hopefully, there aren't too many more unpleasant surprises, but I can't know until I get through all this.</p>
<p>Good night.</p>
Coding 2020-04-112020-04-11T04:00:00-04:002020-04-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-11:/coding-2020-04-11<p class="first last">I didn't put the wrong timestamp on yesterday's entry. YOU put the wrong timestamp on yesterday's entry. I'm not getting defensive.</p>
<p>Overall, I didn't implement new functionality in the Ink port today, because I was noticing simplifications I could make to the code now that I'm not trying to make the state machine a thing, and then I was working on the design for the variable observer feature.
I just now wrote a test for it according to my initial plan.</p>
<p>My initial plan is something I'm not totally sure about, but I can defend it to myself.
Basically, the context is that most of the rest of the interface I put together is about having the consumer manage immutable state.
So, I could, in theory, emit the state changes explicitly and have the caller dispatch them.
But that seems kind of awkward, even by the standards of the designs I've inflicted on this port in the past.
When I get to the end of the equivalent of the "continue" function, I know that the consumer "should" continue on, and therefore wants the observer functions to have triggered by then.</p>
<p>So, for my initial implementation, my plan is to have some kind of accumulator queue of variable changes that gets populated from the VariablesState, and cleared and processed at the end of the "continue" function.
I'll probably want to have some kind of aggressive exception handling on the observer functions, because this code doesn't care what they do, and implementing any kind of control flow via exceptions in consumer code seems perverse.
(Also, observer code should probably be putting stuff on message queues or something like that anyway, I think.)</p>
<p>(While I'm thinking in this area, I think it'd be safe to remove the string part of the output from the function, which would then be more-or-less fluent.
That kind of big rewrite would be helped by another idea I have in mind, which is to reduce boilerplate in the test code.
I have some ideas in mind that would reduce many tests to one-liners.)</p>
<p>Anyway, if I try to work on that now, I'll probably mess it up in some ludicrous way, so I'll wait until later for that.</p>
<p>Good night.</p>
Coding 2020-04-102020-04-10T04:00:00-04:002020-04-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-10:/coding-2020-04-10<p class="first last">"Why is the code like this? Well, there's a good reason..." (several weeks later) "Actually, it wasn't a very good reason."</p>
<p>I recently finally admitted that the whole "state machine" idea isn't working for the Ink port, so I pulled that out, and was then able to get rid of the "CommonState" concept.
While I was at it, I made the choice-choosing logic more in line with the original API, because what I was having it do was not accomplishing anything that I wanted it to.</p>
<p>I made these changes because I finally reached the tests that involve manipulating the VariablesState, and having all of the different states lying around would have made it difficult to implement an API that I could reliably expect to have access to.
Shout-out to all of the tests I ported, which showed me that I apparently got the refactors all right on the first try, which is great, and not something I could have relied on happening.</p>
<p>It looks like there around around twenty tests left for me to finish up the initial port.
Unfortunately, the next test is of variable observers, which I'm going to have to think about to figure out how I want to implement them.
And also look over the C# code pretty closely.</p>
<p>Also, looking over the stuff I haven't tested yet, I think I've found some testing gaps in the C# codebase.
So, that'll be fun.</p>
<p>Anyway, it's too late at night, because I kept spacing out while writing this.</p>
<p>Good night.</p>
Coding 2020-04-092020-04-09T04:00:00-04:002020-04-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-09:/coding-2020-04-09<p class="first last">Miss me with anything related to "strong" or "weak" typing.</p>
<p>I got through a few more tests in the Ink port.
The big new thing from tonight is implicit coercion between value types.
My gut feeling is that I'd lke to somehow not have that, but I don't have a good enough replacement yet, and besides, I should focus on feature parity for now.</p>
<p>So far as that goes...
Aside from some builtins, and the entire list concept, the functionality is mostly done, if somewhat algorithmically questionable in places.</p>
<p>It's in a good place, and hopefully it gets to feature parity in a week or two.
Not much happening with it in the very immediate future, though, because it's almost midnight.</p>
<p>Good night.</p>
Coding 2020-04-082020-04-08T04:00:00-04:002020-04-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-08:/coding-2020-04-08<p class="first last">Commit message: "Trust no one, not even yourself"</p>
<p>I got a few more tests knocked out easy, and then I hit TestNestedPassByReference.
A test that contains the comment "Bloody whitespace", which is a sentiment that I really agree with right now.
Investigating the test's history leads to <a class="reference external" href="https://github.com/inkle/ink/commit/a478f1b237a0f86165375edc2b28389fe746da0f">this commit</a>, which involves changes that produce a more pleasant output.
Formerly, the test output would include a snippet of whitespace outputted by the top-level function call, as well as an extra newline.
Afterwards, it emits neither.
I've somehow managed to write code that includes the extra newline, but not the inline whitespace.
(Technically, the inline whitespace is generated, but not rendered.)</p>
<p>Somewhere in the steps of "first line generates newline, execution steps through function, hits next content line, rolls back, outputs line, and steps back through function", something is going wrong.</p>
<p>Okay, I went back to it, because I was just so bothered, and I found the problem.
This is pretty much entirely on me; I'll see if I can sum it up quickly.</p>
<p>The C# Ink VM defines boxed versions of various built-in types, including strings.
The boxed string includes some pre-calculated common properties, which I foolishly did not port in any capacity, and just tried to do stuff inline where needed.
One of these instances is the function TrimWhitespaceFromFunctionEnd, which should have been preventing the whitespace from getting pushed to the output stream in the first place.
But there was a problem.
In a fit of extreme fanciness, I expressed the isInlineWhitespace property as <tt class="docutils literal">set(obj.value) == {" ", "\t"}</tt>.
The correct expression is, obviously <strong>in retrospect</strong>, <tt class="docutils literal">set(obj.value) <= {" ", "\t"}</tt>.
The difference between them is that the original form wouldn't catch strings that only contained one of these characters.
Which is most strings we're interested in.
The new form does also theoretically drop empty strings, but I'm too tired right now to handle the levels of zen in "does it make a difference to discard the empty string?"</p>
<p>Anyway, I sincerely hope I don't have any more of these tiny oversights on my part to deal with, but that seems unlikely.
Technically, I won't have to deal with any of them tonight, because that's enough for now.</p>
<p>Good night.</p>
Weekly Roundup 2020-04-072020-04-07T04:00:00-04:002020-04-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-07:/weekly-roundup-2020-04-07<p class="first last">I'm not sure how much more of "being wrong about what's easy to tweak in Ink" I can take...</p>
<ul class="simple">
<li>Wednesday: I made the type annotations in the Ink port a little less sloppy. I also figured out how to get the conlang stuff into a more inspectable form without <em>immediately</em> starting to yak-shave.</li>
<li>Thursday: I tried to make the code follow the structure of the C# version a little better.</li>
<li>Friday: I got the rest of the way through those updates, and started porting tests again.</li>
<li>Saturday: I realized that the Ink VM is too low-level to unilaterally implement the semantics tweak I want for it. Between this entry and the next, I realized that I need to get into compiler hacking for that.</li>
<li>Sunday: With some efforts on the side in the days before, I got the glosses I've written put into Sphinx.</li>
<li>Monday: I started pulling from my other documentation efforts into the Sphinx project. Ended up thinking about how to arbitrarily divide these fictional words into specific categories. In my defense, I don't think the specific issue I'm worried about is settled for natural languages (where applicable).</li>
</ul>
<p>Next week, I'm going to try to reach another failing test in the Ink port.
"Approximately alphabetically" might not be a great order to port the tests in, but it's good for being able to compare later.
Also, I'm going to just commit to a position on the conlang stuff.</p>
Conlanging 2020-04-062020-04-06T04:00:00-04:002020-04-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-06:/conlanging-2020-04-06<p class="first last">Super excited to realign the tables later. Ugh.</p>
<p>I copied some more out of the old outline into the new one.
I think the next thing I need to look at from the old outline is correlatives.
Working on that may or may not end up changing the glosses, we'll see.</p>
<p>From my perspective right now, it sort of comes down to what's a "correlative" and what's an "article", and whether the distinction makes sense in this context.
I think the way I'm thinking about it is that articles have a 4-by-4 grid of inflections, while correlatives fit into series on other axes, and may lack inflection for gender to some degree.</p>
<p>I'll think about it next week.
For now, I've been spacing out and should wrap up.</p>
<p>Good night.</p>
Conlanging 2020-04-052020-04-05T04:00:00-04:002020-04-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-05:/conlanging-2020-04-05<p class="first last">I should probably redo the heading markup, but eh.</p>
<p>Quick note on the Ink stuff: I realized that the behavior changes I want can't be introduced in the interpreter, and I should instead work on hacking the compiler when I feel like it.
This is helpful, because it means that my goal with the interpreter port is entirely to get it functioning to spec.
The most complicated thing I might end up doing is having separate branches for mutation testing coverage, and profiling and optimization.
But none of that is relevant right now, since I still haven't implemented all of the opcodes.</p>
<p>Anyway, as far as conlanging goes, I've got all of the glosses put into tables now, which renders hideously, but I'll look into that later.
I've added sections for all of the sections from my original outline, and started copying stuff over.
My task now is to collate and categorize all of the disorganized thoughts I've had so far, and fit them into the outline.</p>
<p>In the process of inputing the glosses, I found a few more errors in the glosses I posted, but I kind of don't feel like correcting them in the post.</p>
<p>I don't have much more to say now, because this has mostly been just taking things I've already talked about somewhat, and putting them together so they can usefully interact.</p>
<p>Anyway, I am sleepy and should go to bed.</p>
<p>Good night.</p>
Coding 2020-04-042020-04-04T04:00:00-04:002020-04-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-04:/coding-2020-04-04<p class="first last">This is more understanding of the Ink VM than I expected to have, at least.</p>
<p>I got a little bit more done on the port earlier today, but I also looked over the code, and realized that I'd already gone over all of the code that would have to be changed for a particular behavior change I wanted, and I hadn't changed it, which means it must be possible to write a failing test case for that behavior.
And it is.
Given the following Ink file:</p>
<div class="highlight"><pre><span></span>* Text: {a|b}
-
</pre></div>
<p>The choice displays initially as "Text: a", and, after it is taken, as "Text: b".
(Followed by a newline.)
I spent a bit of time trying to figure out how to change this behavior, and, once again contrary to my initial expectations, it's not obvious to me right now.
The problem is that, at least according to my ad-hoc prints, it's hard to get a sense of "context" within the VM's stack-based execution.</p>
<p>I've got an idea, which I'm just going to write up, and not attempt yet, that the following might be a workable starting point:</p>
<p>When the parent of the "previous path" is not an ancestor of the "current path", stop visiting containers "at the start", until the "current path" is not a descendant of the first "current path", modulo sticking a tunnel in the middle, so I guess this would have to be tracked on the stack.
Or maybe following a choice needs to put some new data on the stack to determine when to start tracking data again.</p>
<p>I'm pretty sure that first idea would break most things catastrophically, so I'm not going to try it right now.</p>
<p>One thing that all this messing around has made me realize is that I've got a bunch of not-all-compatible things I want out of this port.</p>
<p>One is to basically audit the codebase, and submit the Python version to automatic analysis that can hopefully shed light on the C# version.
This requires relative fidelity to the original codebase.</p>
<p>Another is to have a version of Ink that I can easily use in my Python projects.
The big priority here is optimization, followed by adding features that I want.</p>
<p>I'm going to take a stab at explaining what happens with the Ink code I posted above, so I can get my thoughts in order:</p>
<ul class="simple">
<li>Ink begins expression evaluation.</li>
<li>It assigns the label "0.0.$r1" to the local variable "$r"</li>
<li>It begins string evaluation.</li>
<li>It jumps to "0.0.s"</li>
<li>"0.0.s.0" pushes text to the stack</li>
<li>"0.0.s.1" contains the sequence logic. This is the part where I want to monkey with the visit count logic. Several internal diverts are hit in this.</li>
<li>"0.0.s.2" diverts to the label stored in "$r"</li>
<li>At this stage, the code after the label ends string evaluation, ends expression evaluation, bundles the value into a Choice, and knows to stop and not output anything else because... I'm not sure right now.</li>
<li>Anyway, the test follows the generated Choice, which ultimately redirects to "0.c-0"</li>
<li>This increments the visit count, which is necessary.</li>
<li>Anyway, next it stores the label "0.c-0.$r2" in "$r", and redirects back to "0.0.s". This increments the visit counts, which I would like not to happen.</li>
<li>"0.0.s" runs through its logic as normal, but now the final divert leads to "0.c-0.$r2".</li>
</ul>
<p>Perhaps if following a choice made it so that:</p>
<ul class="simple">
<li>Detect entering the target path of the choice</li>
<li>When the choice's container is diverted out of</li>
<li>Suspend visit count increments until</li>
<li>The container is diverted back into.</li>
</ul>
<p>That might work.
Maybe.
And it still might break things.
I'll have to try this out later.
For now, it's late and I'm tired.</p>
<p>Good night.</p>
Coding 2020-04-032020-04-03T04:00:00-04:002020-04-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-03:/coding-2020-04-03<p class="first last">Somewhat scared to see how a port with stricter typing would handle the external function stuff.</p>
<p>The Ink port is now a little better about how it does errors, although one thing that I'm not sure if I want to deal with is the fact that the error logic in the equivalent of "continue" will "automatically" do rollback before attaching errors.
(Really, it's that it does not have access to the state at the time of the error, and giving it access would be kind of a pain.)</p>
<p>Anyway, I got a few more tests ported.
The relationship between the number of passing tests and the number of tests ported over is getting increasingly tenuous (tonight, one test became three tests, one of which xfails because I'm not testing the compiler, one test became two tests to highlight a semantic flexibility introduced in the port), so I'll just say that I've gotten up through calculating factorial by reference.</p>
<p>I've still got about a dozen NotImplementedErrors kicking around, and probably a few more bits where I skipped over the code like a dope, and also some of those NotImplementedErrors are doing <em>a lot</em> of work, but I'm making progress on this, for sure, and it feels good.</p>
<p>Good night.</p>
Coding 2020-04-022020-04-02T04:00:00-04:002020-04-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-02:/coding-2020-04-02<p class="first last">Turns out that using LaTeX as an intermediate layout representation doesn't automatically make your document look awesome.</p>
<p>No movement on porting over Ink tests, but I did get some of the error-related methods ported over.
I still need to port <tt class="docutils literal">AddError</tt>, but once that's in, I'll have no reason not to get back to the tests.</p>
<p>I got another part of the gloss put into the Sphinx book version of the conlang stuff.
Right now I want to focus on getting content in, but I'm going to have to focus on styling somehow eventually; the way I'm doing this looks atrocious.</p>
<p>Wrapping up now because I was tired all day, and am moreso now.</p>
<p>Good night.</p>
Coding 2020-04-012020-04-01T04:00:00-04:002020-04-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-04-01:/coding-2020-04-01<p class="first last">Give this a few weeks, and it might be usable. Slow, but usable.</p>
<p>I got up to 27 tests ported over the weekend, though two of them kind of freak me out; it's not clear to me how they pass in the C# version, but I verified for myself that they do, so this is my problem.</p>
<p>Anyway, I know the next tests to go for will work out poorly for me, because I've been really lax in populating the error/warning data.
That's why I spent today shoring up the typing system and discovering a bug thanks to that.
I'm going to try to psych myself up to fix the error/warning code tomorrow, so I can hopefully keep breezing through tests after that.</p>
<p>I also realized yesterday that if I relax some preconceptions I had about how it should all work, then <a class="reference external" href="https://www.sphinx-doc.org/en/master/">Sphinx</a> might be a good fit for conlanging work.
Lets me link stuff from my glosses, adding a lexicon entry is relatively lightweight, and if I get really desperate for some kind of generated data, I can do terrible things to the contents of Python docstrings.</p>
<p>I'm going to work on loading my disparate notes into it, when I'm not up for puzzling out what's happening in Ink.
(I'm honestly still not sure what's actually different between how I had some code implemented, and what I changd it to; I just know that the former was an attempt to match my understanding of Ink's continue logic, and the latter is an extremely close translation of the actual code. They do not behave the same.)</p>
<p>Anyway, that's enough for now.
Maybe I'll actually get to bed in a timely fashion tonight.</p>
<p>Good night.</p>
Weekly Roundup 2020-03-312020-03-31T04:00:00-04:002020-03-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-31:/weekly-roundup-2020-03-31<p class="first last">Slow progress.</p>
<ul class="simple">
<li>Wednesday: Three tests ported over, and I managed to simultaneously lament my hubris and continue to engage in it.</li>
<li>Thursday: Four tests ported over. A little worried about trying to port over the random number stuff, since C# and Python provide different random generators out of the box.</li>
<li>Friday: Six tests. Getting kind of tired of all of the bits where I mixed up "and" and "or" or "parent" and "first child". I think I also managed to push some values to the wrong stack, which took a surpisingly long time to mess things up.</li>
<li>Saturday: More dealing with hubris.</li>
<li>Sunday: I did a quick look at the syntactic bestiary, then tried to do a semantic analysis of part of the post I was writing. Even at the time, it was quickly clear to me that it was too late at night for me to be trying that.</li>
<li>Monday: A bit more unfocused work.</li>
</ul>
<p>Next week, definitely more porting Ink.
This is an interesting experience.
While I do have specific complaints about parts of Ink's code, overall I feel the codebase has earned far more respect from me than I had for the code from TStand90's roguelike tutorials.
It's a matter of, the requirements put on Ink are much stricter than those on the tutorial code.
The ultimate form of the VM will probably actually end up extremely similar to the C# code.
I'd like to pull off some kind of bonkers refactor, for the dopamine hit, but the likely targets for improvement are the awful interfaces I've imposed on it.
(Every three tests or so, I'm just like "I've made a huge mistake, but I can cope".)</p>
<p>On the conlanging side, I want to clean up my glosses and make them cross-referenceable somehow.
I've got some ideas I'll look into for that.</p>
Conlanging 2020-03-302020-03-30T04:00:00-04:002020-03-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-30:/conlanging-2020-03-30<p class="first last">I wonder if there's a good format I can record my glosses in so I know which glosses still need an associated word.</p>
<p>Well, I didn't really have the priorities I was hoping for today, so let's have another quick stream-of-consciousness.</p>
<p>I've got the equivalent of basic declarative sentences, and I've worked out rules for converting them to yes-or-no or wh- questions, and rules for converting those to emphatic utterances.</p>
<p>I've got some rules for negation, but there are some edge cases I don't think I've fully covered.
I'm basically not quite sure what I want to happen when the negation applies to a proper noun, but I have some ideas.</p>
<p>There are various constructions and phrases that require a nonce object.
The neutral pronoun probably makes the most sense.
However, I also want the ability to attach the nonce object to an intransitive verb, which means I should probably designate a preposition for that.
(Or have it vary by verb?)</p>
<p>Open question: are the relative and interrogative pronouns the same?
My gut preference is "no".</p>
<p>I haven't worked out the causative yet.</p>
<p>And now I'm both getting quite late at night, and to a point in my notes where I really should have taken more notes.
There is no more post to be had, it must be done now.</p>
<p>Good night.</p>
Conlanging 2020-03-292020-03-29T04:00:00-04:002020-03-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-29:/conlanging-2020-03-29<p class="first last">Editing? What's that?</p>
<p>I kind of didn't focus much on conlanging today, but I did take some time to go over a few more syntactic transformations.</p>
<p>What I should have thought to do was go over last week's entry.
Oh well.</p>
<p>Trying to figure some of this stuff out is making me hyper-aware of stuff that English does.
Like, look back at that last paragraph:
"What I should have thought to do was go over last week's entry."
Means about the same as:
"I should have thought to go over last week's entry."
But emphasizes what I did or didn't do.
I can notice some of this, but not necessarily understand it.
Like, does that rearrangement basically frame the sentence as a question that I ask myself and then answer?</p>
<p>Oh, wait, I'm sleepy.
"What I should have thought to do" is a relative clause.
It's just kind of big.</p>
<p>Now I want to figure out how that kind of construction would work in the conlang, because that's a whole bunch of verbs.
Like, the subject and the object are both verbs, right?</p>
<p>Okay, start with "I should have thought to X"</p>
<p>First roadblock: "think" is intransitive in English.
I don't think (that) I want that here, so let's have the verb in question be more like "think about" or "think of" in its basic form.
"should have" expresses irrealis mood I think, obligation, and whatever the heck "have" even means in a tense/aspect sense by now.</p>
<p>"I [tense aspect mood] think to X"</p>
<p>I want to layer things in a little different of an order.
Because the obligation/duty had a point where it should have been handled, and passed by, I want to have the aspect verb first, followed by a modal verb expressing obligation, and to have the object be irrealis, because it's a thing that I didn't do.
Maybe I'll go back on the ordering if it turns out that I want to enforce mood before aspect, but I want to start by seeing what happens if I don't.</p>
<p>The highlights of all of this are that the relative pronoun is in the accusative, while "go over last week's entry" is in the nominative (and irrealis. It would be in indefinite or definite if I'd been saying "I was supposed to do this thing, and I <em>did</em>.").
The word order of "last week's entry" is "entry last week", where "entry" is in the accusative, and "last" and "week" are in the genitive.</p>
<p>Tomorrow, I should try diagramming this stuff in English and the conlang.
Can't handle it now, though.
I could barely handle what I did do...</p>
<p>Good night.</p>
Coding 2020-03-282020-03-28T04:00:00-04:002020-03-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-28:/coding-2020-03-28<p class="first last">Hello hubris my old friend...</p>
<p>I haven't got any more tests working, but I've cracked 85 percent coverage.
However, I've come to the conclusion that my mental model of how StoryStates work is flawed, and I should probably collapse most of the states together.
I'm not exactly sure how big of a deal this will be, but hopefully it'll make things easier.</p>
<p>Basically, I'd been visualizing the states as cleanly switching between streams of different kinds of output (text and choices), when what actually seems to happen is that choices are generated throughout the course of streaming text output, then expected to be looked at when the text stream ends.
This was not obvious to me, because it's not immediately obvious how to author content that causes the distinction to matter.
The test that had me realize this accomplishes such a thing by generating the choices, then generating the content using a thread.
The choices will show up in the same place as usual in the interface, but they were actually generated first.</p>
<p>I think all I need to do to handle this is to eliminate <tt class="docutils literal">ChoiceState</tt> and have <tt class="docutils literal">LineState</tt> go directly to <tt class="docutils literal">ReadyState</tt> when it can't continue.
I might change how I model this stuff, and have <tt class="docutils literal">LineState</tt> be the only state that's permissible in most functions, and have <tt class="docutils literal">ReadyState</tt> just wrap it.</p>
<p>It's possible that I'll end up dropping more distinctions by the time I'm done working with this, but I want to try having them.</p>
<p>I'm going to hope there are no more complications, but we'll see.
For now, I really should get to bed.</p>
<p>Good night.</p>
Coding 2020-03-272020-03-27T04:00:00-04:002020-03-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-27:/coding-2020-03-27<p class="first last">The mistakes I've made on this code indicate that I casually think of a disturbing number of distinct abstract concepts as "basically the same thing."</p>
<p>Six passing tests.
One of them just worked with no further code changes.
Unfortunately, now I'm working with ChoicePoints, which means remembering the proper equivalent to ResolvePath.
It's too late at night, and I'm too tired, for me to try to work this out right now, but I'm pretty sure it can be done.</p>
<p>It's just that I've fixed enough absent-minded typos in this code that I don't want to make more.</p>
<p>Anyway, coverage is almost at 85%.
And I have nothing more to say.</p>
<p>Good night.</p>
Coding 2020-03-262020-03-26T04:00:00-04:002020-03-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-26:/coding-2020-03-26<p class="first last">I think at some point the number of passing tests will ramp up noticeably.</p>
<p>Up to four passing tests against the Ink interpreter port.
Things started working a lot better after I started actually using the functions I wrote a while ago.</p>
<p>So, the next one I'm trying to implement is related to random numbers, which means I need to port the random number code, which... eeeeeeeh.
I don't object to it on any specific grounds right now, it's just that it's a lot of fiddly stuff to ultimately get a number out at the end.
Even if I wanted to come up with my own take on it, I kind of can't, because it's supposed to be compatible with the test output.</p>
<p>Anyway, I'll get to that later, when I've got a bit more energy.</p>
<p>I'm thinking about getting the style checkers to accept the code, but that'll also take some effort and thought.</p>
<p>I'm messing with other stuff, and I think it might be possible for me to get back into Nova Drift on this laptop.
We'll see how that goes in a few days, I think.</p>
<p>Anyway, I was up too late last night and paid the price, so I'm going to wrap things up now.</p>
<p>Good night.</p>
Coding 2020-03-252020-03-25T04:00:00-04:002020-03-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-25:/coding-2020-03-25<p class="first last">The lack of documentation I left myself sometimes really hurts, but oh well.</p>
<p>All right, I've got the lookahead logic at least sort of sometimes working.
That's three whole tests ported over.
I feel like I should add some more anecdata about how raw coverage metrics aren't helpful: right now, this is at 77% branch coverage.
As an Ink interpreter, this code is still basically useless.</p>
<p>I don't know if I have much to say about this.
I'm really not following good commit message practices.
If I get this in a state where I put it out in the world, I'll probably do a fresh repo starting from whatever state the project is in.
I don't want to explain what's going on in the commit that's just labeled "HSDJKLFHSLKJDHFLKJDSHFLKDSJHFLKSDJHFLKSJDLKS".
(Mostly, I was confronting the consequences of my hubris.)</p>
<p>Anyway, I'm still pretty excited about this whole project.
I've already made some pretty sweeping changes to the design, and I'm fairly sure there are more improvements to make, both in the stuff I've yet to port, and the stuff I've already ported.
(Teaser of the kinds of stuff I've done: the Pointer type has no need to exist in my design. I'm replacing it entirely with AbsolutePath, which is one of the two distinct subclasses of Path I have. I kind of suspect that I should be able to eliminate usage of the base class entirely, but I think I need more code ported before I can be sure. I'm also trying to get as far as I can without having the Object base class; much of its functionality was folded into Path.)</p>
<p>Anyway, I should wrap up now.
It's late.</p>
<p>Good night.</p>
Weekly Roundup 2020-03-242020-03-24T04:00:00-04:002020-03-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-24:/weekly-roundup-2020-03-24<p class="first last">Scrabbling for structure in weeks of blurred-together days...</p>
<ul class="simple">
<li>Wednesday: I made some minor adjustments to the Ink port code. I broke things, and decided not to delay the entry trying to fix them.</li>
<li>Thursday: I fixed the issue that was entirely my fault, then started trying to work out what I actually need to track as part of the state object. This is tricky because the member declarations seem to be scattered throughout the class bodies, which in some of these files are nested, and also I'm not used to languages with implicit self. Also, the whole "we need a zero-argument constructor for deserialization" thing adds a whole extra layer of indirection. (My code does not explicitly attempt to have zero-argument constructors.)</li>
<li>Friday: Putting that stuff into practice was helpful, because I'd messed up the layout of LineState, because it's hard to guess whether something is a member or a getter/setter when I don't have a clear idea of where to look for the definitions.</li>
<li>Saturday: I cut over to the new layout, and got things exactly as broken as before.</li>
<li>Sunday: A bit of work conlanging, focusing on the broad contours of what is and isn't in the syntax.</li>
<li>Monday: A little bit more of that, but not much.</li>
</ul>
<p>Next week, I'm really getting into this Ink port stuff, so I see no reason to stop right now.
I'm up to two out of three ported tests passing; I'm kind of hoping to get some kind of Pareto situation where most of the effort is in getting the basics to work, and things are just minor tweaks by the time I get to the hundredth test.</p>
Conlanging 2020-03-232020-03-23T04:00:00-04:002020-03-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-23:/conlanging-2020-03-23<p class="first last">Another day mostly lost to Minecraft. I ought to take a break...</p>
<p>Okay, real quick because I mostly did other stuff today and it's late.
I went through the syntactic bestiary from the Syntax Construction Kit some more.
Most of the ones I looked over today, I decided to skip for now because I don't have a clear picture of the aesthetics in those areas.</p>
<p>I guess I'm hoping to see something that I can latch onto as interesting, aesthetically pleasing, and distinct from languages that I know.</p>
<p>I should wrap up for now.
Next time, I should take inventory of the stuff I more-or-less know how to do, so I know what to focus on next.</p>
<p>Good night.</p>
Conlanging 2020-03-222020-03-22T04:00:00-04:002020-03-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-22:/conlanging-2020-03-22<p class="first last">Maybe there's some way to replicate the complexity of do-support in other contexts. Something to do with measure words, perhaps...</p>
<p>I started going over a listing of transformations/constructions to consider for conlangs, and figuring out how they would or wouldn't apply to what I'm working on right now.
I think when I actually get this into a publishable state (... whenever that ends up being), I should try to write up my justifications for the various decisions that went into the design.</p>
<p>One thing I ended up thinking about was another bit of The Syntax Construction Kit, the book I got the list from, where the author seems kind of sad as a conlanger that do-support is a feature of English, because it's objectively pretty strange and interesting.
Here are rules that you can't use most verbs in certain ways, so you have to bring in a helper verb, and that results in all kinds of transformations of the sentence.
But all of this weirdness is a feature of one of the most widely-spoken languages in the world.
Given that one of the failure modes in attempting to make a naturalistic conlang is to make a cipher of one's native language, it feels kind of wrong to intentionally reach for that sort of thing.</p>
<p>Which is something that I'm really cognizant of in my attempts to riff on Standard Average European.
I didn't include do-support (since it's not a part of Standard Average European, as near as I can tell), but researching Standard Average European turned up quite a few things for me that I hadn't realized were mostly confined to Europe.</p>
<p>Anyway, I'll get back to this tomorrow.</p>
<p>Good night.</p>
Coding 2020-03-212020-03-21T04:00:00-04:002020-03-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-21:/coding-2020-03-21<p class="first last">I really should have documented some of my thought process. Oh well.</p>
<p>I got distracted from porting Ink for most of today again, but I seem to be doing okay at getting in short bursts of work.
I switched things over to the "CommonState" setup, and updated enough calls to <tt class="docutils literal">dataclasses.replace</tt> that the tests behaved the same.
I should <em>probably</em> turn those replace calls into methods on the objects in question, because they're really hairy, and the type-checking around them doesn't seem super strict?
Anyway, I made some judgment calls on how to move forward from there, and I might have to come back to some of this later and fix it up, but now I'm getting helpful error messages again, so I'm going to just go with it for now.</p>
<p>I'm going to see if I can squeeze some work on this around the conlanging tomorrow.</p>
<p>Good night.</p>
Coding 2020-03-202020-03-20T04:00:00-04:002020-03-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-20:/coding-2020-03-20<p class="first last">Got to get things done right before I can have fun...</p>
<p>I was mostly doing not-this-hobby-code today, so I just now quickly put together the layout of the common state class I worked out last night.
In doing so, I discovered that some of the state I'd been tracking in LineState, I should not have been.</p>
<p>So, I'm kind of pondering how to update stuff, when all of the states are going to wrap a helper class that contains twelve attributes, some somewhat complex.
Now, to start with I'm going to just keep nesting calls to <tt class="docutils literal">dataclasses.replace</tt>, but it's fun to imagine more involved implementations, like having a helper method that takes all attribute names and does dispatches on them.
Or a helper that, rather than mapping names to values, maps names to functions that transform the value.</p>
<p>More value for now in getting the flow of data correct, which it right now... isn't.
Anyway, I let things go late, so I should once again wrap up a short post.</p>
<p>Good night.</p>
Coding 2020-03-192020-03-19T04:00:00-04:002020-03-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-19:/coding-2020-03-19<p class="first last">I'm not sure how well I've motivated the whole multiple-state concept, but it makes sense to me, and that's what's most important here.</p>
<p>After last night's post, I figured out what I was doing wrong: I had two arguments in the wrong order.
When I swapped them, it worked fine.</p>
<p>Before I touch anything else, I want to figure out what is in the StoryState class that I care about.
I'm going to do that in here.
Fair warning: I don't really know .NET or C#, so I'm going to be playing fast and loose with some of the terminology.</p>
<p>All right, so the following attributes get touched inside the Copy method:</p>
<ul class="simple">
<li>outputStream (manipulating this appears to also involve OutputStreamDirty()); this is a getter around _outputStream.</li>
<li>_currentChoices; this is a variable.</li>
<li>hasError and currentErrors; hasError is free in Python, syntactically speaking, and currentErrors is a semi-protected variable.</li>
<li>callStack and _originalCallstack; callStack is a variable, and _originalCallstack is a slot that's needed for some function calls or something.</li>
<li>variablesState (which has stuff to do with callStack and story.listDefinitions); variablesState is a variable.</li>
<li>evaluationStack and _originalEvaluationStackHeight; evaluationStack is a semi-protected variable and _originalEvaluationStackHeight is another sometimes-needed thing.</li>
<li>divertedTargetObject; this is a variable.</li>
<li>previousContentObject; this is a calculated value that lives in the callStack, so I'm not entirely sure why Copy is setting it explicitly when it should, just... have the right value because the callStack gets copied...</li>
<li>visitCounts; this is a semi-protected variable.</li>
<li>turnIndices; this is a semi-protected variable.</li>
<li>currentTurnIndex; this is a semi-protected variable.</li>
<li>storySeed; this is a variable.</li>
<li>previousRandom; this is a variable.</li>
<li>didSafeExit; this is a variable.</li>
</ul>
<p>In the jsonToken property, we get...</p>
<ul class="simple">
<li>_currentChoices (above)</li>
<li>callStack (above)</li>
<li>choiceThreads isn't an attribute, rather it's derived from _currentChoices and callStack</li>
<li>callStack (above)</li>
<li>variablesState (above)</li>
<li>evaluationStack (above, though I got thrown off for a sec because the serialization names don't match the variable names for... some reason)</li>
<li>_outputStream (above)</li>
<li>divertedTargetObject (above)</li>
<li>visitCounts (above)</li>
<li>turnIndices (above)</li>
<li>currentTurnIndex (above)</li>
<li>storySeed (above)</li>
<li>previousRandom (above)</li>
<li>didSafeExit is not in there, that I see</li>
</ul>
<p>Now, I came up with the idea to divide the StoryState behavior into three (now four) states: LineState, ChoiceState, ReadyState, and EndState.
When the story is in LineState, it has produced zero or more lines of text since the last state it was in, and could produce zero or more lines before transitioning to ChoiceState or EndState.
In EndState, the state is functionally inert, until it's brought back to LineState by setting the path.
In ChoiceState, it has produced zero or more choices since the last LineState, and could produce zero or more choices before transitioning to ReadyState; I don't think it can go directly to EndState, but implementing that if I need it shouldn't be a problem.
Actually, what should it do if it tries to transition without producing a Choice...?
In ReadyState, it has (hopefully!) produced at least one Choice, and, given one of those choices, it will transition to either LineState or EndState; the latter transition might not be necessary, depending on how diverts to END are coded.</p>
<p>For serialization purposes, I don't think it poses any problems to deserialize no choices as a LineState, and some choices as a ChoiceState.
The "real" state might be EndState or ReadyState, but it'll immediately enter them if needed.
I could be wrong.
We'll see.</p>
<p>Anyway, the conclusion I draw here is that all the states need most of these values, except for _currentChoices.
So, I should probably define a helper that tracks all of that state and use that in the State classes, since I expect most data to need to persist through transitions.</p>
<p>Anyway, that's a good thing to work on the next few days.
For now, I should get to bed.</p>
<p>Good night.</p>
Coding 2020-03-182020-03-18T04:00:00-04:002020-03-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-18:/coding-2020-03-18<p class="first last">The fabled red to red refactor...</p>
<p>Today, I did stuff in Minecraft, mostly.
I did end up doing some basic reorganization of the Ink port's code; just moved a few classes into their own modules.</p>
<p>I made a draft of the new state I'm going to want.
I think before I charge ahead on implementing this kind of sweeping change, I want to work on having a concrete plan for some of this stuff.</p>
<p>For the moment, I'm trying to get the type annotations a little more detailed to hopefully avoid unpleasant surprises.
That didn't go so well, because I ran into some unexpected behavior in code that's all on me, so I'm going to spend a few minutes trying to diagnose that after I finish this entry.</p>
<p>Which is... right... about... now.</p>
<p>Good night.</p>
Weekly Roundup 2020-03-172020-03-17T04:00:00-04:002020-03-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-17:/weekly-roundup-2020-03-17<p class="first last">A week almost totally indoors...</p>
<ul class="simple">
<li>Wednesday: I switched to doing more coding during the week, and started off mostly just criticizing wemake-python-styleguide.</li>
<li>Thursday: I write some tests.</li>
<li>Friday: I switched to porting Ink again, and spent the first day of that battling technical difficulties.</li>
<li>Saturday: I got a test to pass.</li>
<li>Sunday: I got distracted, so I ended up just drafting some glosses.</li>
<li>Monday: I improved the glosses, and posted them, because I could.</li>
</ul>
<p>Next week, I'm going to have to make some design changes to the Ink port.
I'd also like to do a refactor of it to make it easier to find stuff, but I'd be a little bit more comfortable with refactoring if there were more than one green test currently.</p>
Conlanging 2020-03-162020-03-16T04:00:00-04:002020-03-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-16:/conlanging-2020-03-16<p class="first last">A bunch of abbreviations.</p>
<p>I made glosses, minor revisions, and updates to my grammar notes.
Somehow, making detailed glosses was exhausting.
I don't know if that's typical, something that can just be like that for some people, or a reaction to the prospect of not leaving the house for the next week.</p>
<p>For the heck of it, I'll paste (and lightly edit) the glosses I wrote.
I doubt they'll make much sense without the context of what I have worked out about the grammar, but eh.
They're still a little rough, but most of the important ideas are there.
The source is the beginning of a sermon based around the folklore of the con-culture.
When I have some time, I'll change some of the hyphens to dots, but which should be which is a matter of derivational morphology, which I'm punting on.
The "g#" markers are arbitrary gender markers, because I don't have a lexicon.
The pronouns are kind of wobbly right now, and some of them are almost certainly under-specified currently.
I didn't figure out what I want to call "every" in the context of the glosses, but I knew how I wanted to treat it.
(According to my notes, "result-verb" ought to be "should", but I don't know if I'm keeping that.)</p>
<blockquote>
art-def-g1-nom first-g1-nom sin-g1 be-3s be-prep art-def-g2-nom hubris-g2-nom.
art-def-g1-nom devil-g1-nom think-3s refl-3s-acc be-prep art-irr-g1-nom great-g1-nom com-(?) art-def-g2 god-def-g2.
g1-nom result-3s art-def-g1-nom wield-inf-g1-nom art-def-g2-dat creation-g2-dat art-def-pl-acc tools-pl-acc.
art-def-g1-nom god-g1-nom result-3s art-def-g1-nom punish-inf-g1-nom g2-acc inst-prep art-def-n-dat cast-inf-n-dat into-prep art-g3-dat world-g3-dat imperfect-g3-dat relative-acc g2-nom create-3s.
art-pl-nom army-pl-nom hell-g1-gen be-3p be-prep art-pl-nom reflection-pl-nom diminished-pl-nom g2-gen.
pl-nom seek-3p art-def-n-nom usurp-inf-n-nom art-def-g1-dat god-g1-dat art-def-g2-acc creation-g2-acc for-prep art-def-n-nom improve-inf-n-nom refl-3p-acc.
g1-nom believe-3s art-irr-n-nom bolster-inf-n-nom (every)-g2-nom bit-g2-nom creation-g3-gen god-g4-gen relative-acc g1-nom incorporate-3s into-prep art-def-g5-dat refl-3p-gen refl-3p-dat art-def-pl-acc power-pl-acc creative-pl-acc.</blockquote>
<p>It'd be kind of cool if I could say that this is all part of a method I've worked out to conlanging, but I really haven't done enough of it.
Basically, I'm feeling my way around, seeing what's easy to do that seems promising.
I want to do some analysis of these glosses, then figure out what other features I want to show off, write sentences for those, analyze them, and try getting the analysis loaded into software.</p>
<p>Anyway, that's it for now.
I'm sleepy and I can't reasonably expect to get any given task all the way to completion in the next few minutes.</p>
<p>Good night.</p>
Conlanging 2020-03-152020-03-15T04:00:00-04:002020-03-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-15:/conlanging-2020-03-15<p class="first last">Literal translation of the sentence I'm worried about: "He believes some bolster every bit creation's God's what he incorporates into the world hisselves himself the powers creative." (EDIT2: Moved "himself" from the end of the sentence. EDIT1: Final word changed from "hisselves".) It makes sense in context. Actually, I'm a little shocked by the level of nuance and clarity that got lost in the process.</p>
<p>So.
Weekend conlanging.
I didn't get so much of that done, because I got distracted porting over more of Ink.</p>
<p>I did manage to work out candidate structures for some of the in-setting sentences I came up with.
They seem pretty good to me, though I'm worried that one of the more complicated ones (a bunch of nested clauses) might be a <a class="reference external" href="https://en.wikipedia.org/wiki/Garden-path_sentence">garden path</a> or a <a class="reference external" href="https://en.wikipedia.org/wiki/Syntactic_ambiguity#In_headlines">crash blossom</a>, and I might need to consider some kind of rewrite or repair rule.</p>
<p>Since I've been interested in syntax recently, I'll try analyzing them according to different syntactic frameworks, once I have proper glosses and not just a list of parts of speech.</p>
<p>That's not now, though, because it's almost midnight, again.</p>
<p>Good night.</p>
Coding 2020-03-142020-03-14T04:00:00-04:002020-03-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-14:/coding-2020-03-14<p class="first last">Turns out the code won't complain about parts not being written, if you don't actually try to execute them...</p>
<p>Weird technical issues are dealt with.
It turns out I was actually really close to getting the first interesting test to pass; I just needed to tweak the default display of floating point numbers.</p>
<p>Now, the next test works with variables, which I haven't really handled at all.
Doing this requires a surprising amount of <em>stuff</em>.
Variable initialization is handled by diverting to "global decl", so I'm going to need to handle that.
Once I get that working, it'll hit the variable assignments, and I'll have to implement those... which means actually storing the variables.
Hopefully, after that, it'll just kind of go, but it's quite hard to say.</p>
<p>Once this is in a workable state, I think it'd be very interesting to port it to other languages, because I believe the way I'm writing it is relatively language-agnostic.
But, I can't do that soon, and I shouldn't do anything else tonight, because it's late.</p>
<p>Good night.</p>
Coding 2020-03-132020-03-13T04:00:00-04:002020-03-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-13:/coding-2020-03-13<p class="first last">It is a little frustrating to be sidetracked from doing actual work by weird technical issues.</p>
<p>I decided today that I wanted to switch gears from the auto-roller to revisiting my attempt to port Ink to Python.
I ended up getting on that kind of late in the day, and it went kind of like this:</p>
<ul class="simple">
<li>Update repo</li>
<li>Realize I'd been in the middle of some changes</li>
<li>Turns out the repo is corrupted</li>
<li>Fix it using an arbitrary sequence of steps that kind of seems like it maybe shouldn't work, but does</li>
<li>I should probably get my online backups synchronized before I mess with this any more</li>
<li>... He said, by typing into a new file that exists in the same directory tree.</li>
</ul>
<p>Anyway, migrating to flit in the middle of whatever I'd been doing seems to have worked, so I just need to work out what I was doing and finish doing it.
That's going to have to be tomorrow or later, because right now my backups are busy synching a bunch of files that they absolutely should not be synching, but whatever.
I'm going to try something with this repo to deal with that, and if it works, I'll do it for the other repos.
Basically, I'm pretty sure this doesn't follow symlinks, even if it sometimes looks like it says it does.
So, volatile folders should be symlinked to outside of the backed-up directories.
I probably should have done this all the way in the first place, with no half measures, but, effort.</p>
<p>Anyway, I'm going to try to let this finish up, then wrap up for tonight and get to actual work on this stuff tomorrow.</p>
<p>Good night.</p>
Coding 2020-03-122020-03-12T04:00:00-04:002020-03-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-12:/coding-2020-03-12<p class="first last">Coming up with test cases for this code isn't as fun as it was for Structured Data.</p>
<p>Still took things easy today, evidently.</p>
<p>I did spend some time getting the auto-roller test coverage up a little.
It's kind of tricky to psych myself up to do, because a lot of the observeable behavior of the auto-roller code is kind of trivial, so I have to look at the source code, sigh, think "the tests for that would be incredibly simplistic", and then muscle my way to "so, I shouldn't worry about writing them, and just get it over with".</p>
<p>Since I spaced out reading wiki articles for the last fifteen minutes, that's it, I guess.</p>
<p>Good night.</p>
Coding 2020-03-112020-03-11T04:00:00-04:002020-03-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-11:/coding-2020-03-11<p class="first last">A bunch of links to cover up the fact that I zoned out 100%-ing Snakebird Primer over the course of two hours of play time.</p>
<p>I let things go late today, so I'm going to have to wrap things up quickly.
For the latest attempt at conlang software, I think I mentioned that I'd like to try using an existing conlang as test data.
For now, I just grabbed <a class="reference external" href="https://www.zompist.com/verdurian.htm">Verdurian</a>.
We'll see how that goes when I actually work on it instead of playing Snakebird.</p>
<p>I've also been thinking about coding standards and exercises, like <a class="reference external" href="https://www.cs.helsinki.fi/u/luontola/tdd-2009/ext/ObjectCalisthenics.pdf">Object Calisthenics</a>, and the fact that I'm still kind of iffy on the <a class="reference external" href="https://wemake-python-stylegui.de/en/latest/">wemake-python-styleguide</a>.
One thing that I keep on mentally nitpicking is the justification for wrapping lines at 80 characters.
Now, to be clear, I don't mind that kind of length limit, though I would like it if I could remember that docstrings are supposed to wrap at 72 instead, I think.
I mean, I think the wrapping that makes sense for code samples on this blog, when (<em>when</em>) I remember to do it, is like 40 characters.
I don't mind the limit.
What I take issue with is the idea that "The first and the most obvious complexity metric for a line is its length." (<a class="reference external" href="https://sobolevn.me/2019/10/complexity-waterfall#lines">Complexity Waterfall</a>)
Complex lines have internal structure that allows for easy splitting onto multiple lines.
In trying to use (more or less) WPS, I pretty consistently got that the lines of problematic length were extremely simple, but involved long names or literals.</p>
<p>Also, I still think it's rich to criticize <a class="reference external" href="https://github.com/psf/black">black</a> for violating <a class="reference external" href="https://www.python.org/dev/peps/pep-0008/">PEP 8</a> from the same project that mandates always having an encoding comment.
(<a class="reference external" href="https://wemake-python-stylegui.de/en/latest/pages/usage/integrations/auto-formatters.html#black">black criticism</a>, <a class="reference external" href="https://github.com/tk0miya/flake8-coding#rules">encoding comment violation</a>, <a class="reference external" href="https://www.python.org/dev/peps/pep-0008/#id22">PEP 8 on encoding comments</a>)
(Or, I guess they're getting rid of that in the next version? Or something?)</p>
<p>Also, <a class="reference external" href="https://wemake-python-stylegui.de/en/latest/pages/usage/violations/best_practices.html#wemake_python_styleguide.violations.best_practices.PositionalOnlyArgumentsViolation">WPS451</a> is getting disabled the instant I have to deal with it.
It's not <em>impossible</em> to replicate <tt class="docutils literal">def method(self, an_arg, /, **kwargs)</tt> without using positional-only syntax, but it is <em>highly</em> unpleasant, and worse code.
Code is better when the surface appearance reflects the intent, and "using the syntax" reflects the intent far better than "weird decorator where you have to define the kwargs dictionary as a positional argument".</p>
<p>Anyway, before I mess around with rewriting the auto-roller any more, actual tests, right, yes.
But that's not happening now, because it's already way too late.</p>
<p>Good night.</p>
Weekly Roundup 2020-03-102020-03-10T04:00:00-04:002020-03-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-10:/weekly-roundup-2020-03-10<p class="first last">So... tired... and... forgetful...</p>
<p>Even more than usual, I don't really remember what I did this week.
Changing the clocks <em>sucks</em>.</p>
<ul class="simple">
<li>Wednesday: I circled back around to "I should really work on documenting my conlangs"</li>
<li>Thursday: "I think to do that I'll need to switch this to the weekend and do something more bite-sized during the week." An interesting idea. Let's try following up on it.</li>
<li>Friday: I looked into new Python web frameworks.</li>
<li>Saturday: I looked into Python web frameworks that I <em>think</em> aren't as new.</li>
<li>Sunday: I added some weird code to the auto-roller that allowed for technical simplifications.</li>
<li>Monday: I replaced the weird code with more straightforward code that put some somewhat bothersome requirements on niche cases, in return for simplifying the code base considerably.</li>
</ul>
<p>Next week, I've been reading about "object calisthenics", so I might try applying that to the auto-roller.
The code is already ahead of the curve on some metrics.
There are no instance variables or setters, and most of the classes are tiny.
First, though, I really should work on the coverage.
It's at 75%, but most of the 25% remaining is the bulk of the business logic.</p>
Coding 2020-03-092020-03-09T04:00:00-04:002020-03-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-09:/coding-2020-03-09<p class="first last">Tanking my coverage stats by deleting questionable-but-tested code</p>
<p>I hacked some more on the auto-roller code.
I basically got rid of some of the functionality I added earlier, in favor of something that's a little more transparent, I think.
As an added bonus, it eliminated a bunch of low-level classes, meaning that they no longer need to get instantiated, and some of the functionality is more useful on its own.</p>
<p>I did manage to kind of mess up my pijul state, by forgetting to add a new file, and then getting a bunch of mysterious conflicts that made no sense to me.
All like, "did you mean this text block, or this identical text block?"</p>
<p>Ubfortunately, I dont have much time to reflect on this because it's getting late and I'm tired.</p>
<p>Good night.</p>
Coding 2020-03-082020-03-08T05:00:00-04:002020-03-08T05:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-08:/coding-2020-03-08<p class="first last">I'm not at all confident in my usage of the contextvars library, but the tests do all pass...</p>
<p>Not a terribly focused day.
I did some writing along with some coding, and unfortunately I'm very sleepy so it's hard to talk about it.
I made some improvements to my auto-roller code; mostly some way-too-complicated stuff that means I can get rid of some boilerplate, and also this code could transparently support using a library like greenlet for true coroutines.
I think.
The code that allows this to happen is in the intersection of "typechecks", "appears to work", and "gives me the willies".
Just now I got a bit more of the old Mythic code ported.
My plan there is to figure out porting the interactive frontend, and then adapt that to other systems.</p>
<p>I realized that I should wrap things up, though, when I tried to copy a sentence over, and I typed it so it came out lpjiing lhsu tsgis.
I'm not getting any less sleepy, so I really should go to bed, especially since I'm going to lose an hour.</p>
<p>Good night.</p>
Coding 2020-03-072020-03-07T05:00:00-05:002020-03-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-07:/coding-2020-03-07<p class="first last">"Here's an example where you make ten buttons in a loop!" Sheesh...</p>
<p>Not a really exciting day today.
I cleaned up some of my code and read more about JustPy.
I think I'm having trouble translating the arbitrary example code into stuff that's of interest to me.
I'm not up for trying too hard to do this tonight, but I should probably try to design the site I want to use this for, and then see about making it happen.</p>
<p>I also looked around for similar frameworks, and I found <a class="reference external" href="https://flexx.readthedocs.io/en/stable/index.html">Flexx</a>, which I think could be useful for some other project ideas that I've had on the back burner for some time.</p>
<p>Anyway, thinking about the reference stuff, I guess first I need to have some data to load up and check that it works the way I want it to.
For that, maybe it'd make sense to try using snippets of an existing reference grammar, so I'm not second-guessing myself about the content.</p>
<p>Anyway, it's getting late, and I'm not going to try to stay up much longer.</p>
<p>Good night.</p>
Coding 2020-03-062020-03-06T05:00:00-05:002020-03-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-06:/coding-2020-03-06<p class="first last">It's kimd of hard to play to my strengths in front-end development, but this blog manages it.</p>
<p>One thing that I've wanted with conlanging is something that makes it easy to interact with the language, to slice it in different ways, to trace the histories of words.
That is a lot of effort, such a thing would probably take months, minimum, but all the more reason to get started.</p>
<p>I'm trying out a web interface for this, using a project I heard of recently called <a class="reference external" href="https://justpy.io">JustPy</a>.
JustPy sounds interesting to me because I am bad at JavaScript, and good at Python.
I've gotten through the first page or so of the tutorial, I think, and that's not enough to make a call one way or the other.
One thing that I'm really not sure what I think about is the idea of using <a class="reference external" href="https://tailwindcss.com/">Tailwind</a>.
It might be relevant to note that the source code for this blog's CSS looks <a class="reference external" href="https://mwchase.neocities.org/theme/css/main.scss">like this</a>.
And that I enjoyed writing it.</p>
<p>Anyway, that's enough talking for tonight.
So sleepy.</p>
<p>Good night.</p>
Conlanging 2020-03-052020-03-05T05:00:00-05:002020-03-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-05:/conlanging-2020-03-05<p class="first last">Many troubling aspects...</p>
<p>Quick update on conlang stuff:
I haven't yet settled on a school of thought for syntax.
I've got notes that go in all sorts of directions.
Maybe what's important to me is transformations.
Or constructions.
Or argument types.</p>
<p>I'm going to have to get this all settled down and organized, but I think to do that I'll need to switch this to the weekend and do something more bite-sized during the week.</p>
<p>Also, I read enough about aspect that at this point I'm thinking "okay, let's try again and get it over with".
I've got some more resources to go over if things end up really rough.</p>
<p>Anyway, I'm struggling to stay awake, so I should stop doing that.</p>
<p>Good night.</p>
Conlanging 2020-03-042020-03-04T05:00:00-05:002020-03-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-04:/conlanging-2020-03-04<p class="first last">Pondering writing an interactive website just so I can get nice tables, but edited in a text editor rather than through the browser.</p>
<p>Quick post today because things were kind of hectic and stressful, and I want to try to be more-or-less calm.</p>
<p>I'm right now working on getting the (substantial) list of things that need to be done for Dabupan/The Tongue of Light written up in a single file.
I also spent a bunch of today pondering a good format for writing things up in, since I don't really enjoy using LibreOffice.
It's, like, it's fine.
It's fine.
It's not great.</p>
<p>I've got some ideas for stuff to try there, but I'm going to need a bit more time to investigate.
I'm also reading up on different theories of syntax, and trying to figure out what makes sense for what I'm doing here.
My notes so far are kind of a combination of different schools of thought, but in more of a "didn't know what I was doing" than "principled" kind of way.
My hunch is that thinking about things in terms of transformations might make more sense from a diachronic perspective, but thinking in terms of constructions could be more useful synchronically.
I'm not sure if combining them like that works, but I think it'd be nice if it did.</p>
<p>Anyway, anything further has to wait for tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2020-03-032020-03-03T05:00:00-05:002020-03-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-03:/weekly-roundup-2020-03-03<p class="first last">A very coding week.</p>
<ul class="simple">
<li>Wednesday: I tried to work out the parts of speech in my made-up language, to hopefully avoid treating words in an ad-hoc way.</li>
<li>Thursday: I asymptotically approached grappling with what the heck verbs are.</li>
<li>Friday: I did an informal comparison of Poetry, flit, and enscons. I concluded that I prefer flit to Poetry, but I'll sometimes need something like enscons, at least temporarily. Four hours after the post went up, my PR to Poetry got approved. 🤷</li>
<li>Saturday: I started switching from Poetry to flit.</li>
<li>Sunday: I hacked on an auto-roller, and thought about style checkers.</li>
<li>Monday: I revived some code that I'd put aside temporarily.</li>
</ul>
<p>Next week, I'm going to try using a <a class="reference external" href="http://todotxt.org/">todo.txt</a> for organizing work on conlanging, because it really hasn't been organized so far.
Also, I remembered that I'm trying to port the SCA to Python, so that might make its way into the coding.</p>
Coding 2020-03-022020-03-02T05:00:00-05:002020-03-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-02:/coding-2020-03-02<p class="first last">The level of my coverage metrics on this over the course of the day has me really freaked out about projects with 60% coverage. Like, what are they even testing.</p>
<p>More coding, pretty much.
I'm working on porting over previous versions of attempts at rollers.
I should see about showing this stuff off once I have good mutation testing coverage.</p>
<p>I also grabbed a bunch more tabletop games today; I might look into writing auto-rollers for some of them, once I've adapted the stuff I've already written up for use.</p>
<p>Anyway, it's once again later than I meant it to be.</p>
<p>Good night.</p>
Coding 2020-03-012020-03-01T05:00:00-05:002020-03-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-03-01:/coding-2020-03-01<p class="first last">It just feels so good to be working on this stuff again.</p>
<p>Third coding entry this week, because I got just so excited about finally working on these projects again.
Nothing much to say about it, I guess.
I got coverage stats up from 2% to 90%.
Made some changes that I had planned for like a month.
I had some kind-of-janky code in there meant to work with my old Mythic V1 code, which I took out, but I want to try to bring it back.
When I do, I can make a cleaner implementation of that code.</p>
<p>One thing I've been feeling from working with <a class="reference external" href="https://wemake-python-stylegui.de/en/latest/">wemake-python-styleguide</a> is that there are enough points where I'm looking at the documentation and getting frustrated, that I'd kind of like to try making my own style thing.</p>
<p>Points to keep in mind for such a project:</p>
<ul class="simple">
<li>Pick an auto-formatter, like <a class="reference external" href="https://black.readthedocs.io/en/stable/">black</a>, and don't warn for <em>anything</em> that it handles. This includes line length and quote style. Basically, if it can be handled automatically, it should go in an auto-formatter, and if it can't, it... can't, and therefore shouldn't.</li>
<li>I'd really like to figure out if it's possible to statically annotate scopes so as to indicate what kind of conventions, such as naming, to follow.</li>
<li>It ideally should not crash when run against Sructured Data.</li>
</ul>
<p>Is it mean of me to keep bringing that last one up?
Probably.
Will I stop?
Probably not.</p>
<p>Anyway, I let writing this go late.
I should wrap up now.</p>
<p>Good night.</p>
Coding 2020-02-292020-02-29T05:00:00-05:002020-02-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-29:/coding-2020-02-29<p class="first last">Turns out things are more enjoyable when you're not constantly thinking about how your tools are doing extra "helpful" things that you don't want, not even a little bit.</p>
<p>I ended up just adapting a single project to flit today.
I pulled in a bunch of stuff from Structured Data, and discovered that my whole hack to get around <tt class="docutils literal">pip install .</tt> doesn't actually work on flit (yet, there's a PR), but the install is fast enough that it turns out not to matter in practice, at least for this project.
Now that I've got everything together nicely for this project, I just need to write tests for the code, and then I can start working on the various refactors I have in mind.</p>
<p>I think the next repository I'll look into adapting is from my latest attempt to port/rewrite Ink.
In some ways that'll be a little tricky, because it's not that there are no tests, it's that the tests don't pass because I haven't ported enough logic over yet.
Oh well.</p>
<p>At some point I'll want to try out mutation testing against something, but that requires tests, that work.
My best candidate is probably Structured Data.</p>
<p>Once I've done as much with flit as possible (probably up to porting the Cell nucleus file for Python projects to use it), I'll try to learn SCons.
I wouldn't terribly mind putting that off.</p>
<p>Speaking of putting things off, I need to post.
Now.</p>
<p>(Last note, I feel like mentioning that my PR to Poetry finally got an approval shortly after the last post got published.
The merging is still blocked, which I don't feel like figuring out right now.)</p>
<p>Good night.</p>
Coding 2020-02-282020-02-28T05:00:00-05:002020-02-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-28:/coding-2020-02-28<p class="first last">Friendship ended with POETRY Now FLIT is my best friend</p>
<p>One of the long-standing problems developing Python projects has been the packaging libraries.
The default libraries are extremely flexible, but give users the ability to define nonsensical behavior, or omit vital data from the final package.</p>
<p>With <a class="reference external" href="https://www.python.org/dev/peps/pep-0517/">PEP 517</a>, the situation changed.
Now, there's a standard to write packaging tools against, that gives them the ability to define packages in a declarative manner.
Various packaging alternatives have been developed, but I'm going to focus on just a few: <a class="reference external" href="https://python-poetry.org/">Poetry</a>, <a class="reference external" href="https://flit.readthedocs.io/en/latest/index.html">flit</a>, and <a class="reference external" href="https://pypi.org/project/enscons/">enscons</a>.
The first two focus on making it easy to develop simple projects, each taking a somewhat different approach, while enscons should allow for more complicated means of building, which is necessary for some of my projects.</p>
<p>I'm most familiar with Poetry, because it was the first setuptools alternative I know of to support the src layout.
As such, that's what I used for a while.
However, in some ways it wasn't a good fit.
It has a number of features I ignored or worked against, such as managing virtual environments, and making editable installs of the project next to the dev dependencies, and some operations are extremely slow.
Part of my goal these next few days is to determine how much of the performance issues I ran across in Poetry several months ago are still a problem, and how specific they are to Poetry.</p>
<p>My ultimate goal is to migrate most of my projects from Poetry to flit, and Dennis to enscons (and later to flit), but first I want to do some basic comparisons of the three tools.</p>
<p>My basic plan is to make three separate projects the way I'd like to lay things out with each tool, and give them dependencies that pull a lot of stuff in.
Then, for each one, time <tt class="docutils literal">pip install .</tt> and the tool's build command, followed by pip installing the wheel.</p>
<p>After going through the basics with the tools, I've come to the following conclusions:</p>
<ul class="simple">
<li>pip installing a wheel is about the same regardless of what produced it</li>
<li><tt class="docutils literal">pip install .</tt> is kind of slow under flit</li>
<li><tt class="docutils literal">pip install .</tt> is still <em>painfully</em> slow under Poetry</li>
<li>It is too late at night for me to figure out how to make enscons work. ... Okay, one more try.</li>
<li>All right, I've concluded the following things about enscons: <tt class="docutils literal">pip install .</tt> is intermediate in speed between Poetry and flit, and the documentation is super confusing. <tt class="docutils literal">python <span class="pre">-m</span> SCons</tt> does not work <em>at all</em>, but <tt class="docutils literal">scons</tt> appears to, so, note to my future self there.</li>
<li>In summary, as janky as it is, the build-wheel-and-install <em>might</em> still be worth it under flit, but I should probably judge that by adapting a project that uses it, and dropping it.</li>
</ul>
<p>I appreciate that enscons is there when I need it, but I hope to not need it much.
(Also, I'm assuming I can make it work with <a class="reference external" href="http://coconut-lang.org/">Coconut</a>, but I'm hoping that's a fair assumption.)</p>
<p>Good night.</p>
Conlanging 2020-02-272020-02-27T05:00:00-05:002020-02-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-27:/conlanging-2020-02-27<p class="first last">Almost ready to try to put everything together again...</p>
<p>I filled out my latest version of notes on conlanging some more today.
I noted some basic aspects of mood that I want to somehow implement, though I'm not sure how I want to do it, exactly.
My original idea was to have most aspect-mood information conveyed using auxiliary verbs, more or less, though I'm not sure if using an auxiliary to communicate the imperative mood is a thing much.</p>
<p>One thing that just occurred to me as a possibility is to form contractions with pronouns and auxiliaries.</p>
<p>Anyway, I thought I was going to finish this post twenty minutes ago and I spaced out.
I'm going to need to get better about getting sleep if I want to make more substantial posts...</p>
<p>Good night.</p>
Conlanging 2020-02-262020-02-26T05:00:00-05:002020-02-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-26:/conlanging-2020-02-26<p class="first last">Getting right up to the edge of admitting I need to talk about some of this stuff soon.</p>
<p>I took another stab at working out the grammar of these made-up languages, this time taking the tack of documenting the parts of speech so I can try out different means of reasoning about the grammar.
Because grammatical peculiarities often have a historical basis, hopefully this will help when I get back around to attempting diachronics.</p>
<p>Right now, I'm procrastinating a little when it comes to documenting the verbs, because aspect and mood are complicated.</p>
<p>In any case, I'm really tired, so I'm going to call this post here.</p>
<p>Good night.</p>
Weekly Roundup 2020-02-252020-02-25T05:00:00-05:002020-02-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-25:/weekly-roundup-2020-02-25<p class="first last">Going off in some direction.</p>
<ul class="simple">
<li>Wednesday: A little bit of conlanging background.</li>
<li>Thursday: I got some more ideas down.</li>
<li>Friday: I cut back on the scope of the changes I want to make to punq.</li>
<li>Saturday: I made the changes. I don't yet feel comfortable openig a PR, for various reasons.</li>
<li>Sunday: I mostly read, and thought about Python style guides.</li>
<li>Monday: I read some more, and started writing some bizarre fanfiction.</li>
</ul>
<p>Next week, I'm going to keep on trying to take it easy.</p>
Diary 2020-02-242020-02-24T05:00:00-05:002020-02-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-24:/diary-2020-02-24<p class="first last">Fey mood.</p>
<p>I seem to be planning and writing some ridiculous crossover fanfiction.
It might come together in a few months, or it might not.
For now, I'm just going to go where inspiration takes me.</p>
<p>I spent most of today working on writeups for the fanfiction, so I've got no time to spend on this post right now.
Oh well.</p>
<p>Good night.</p>
Diary 2020-02-232020-02-23T05:00:00-05:002020-02-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-23:/diary-2020-02-23<p class="first last">Taking it as easy as I can right now...</p>
<p>I'm recovering, I think.
I'm reading more than writing or doing any other such thing.</p>
<p>One thing I've been thinking about is trying to put together some kind of a meta-style guide, and seeing whether existing style checkers for Python have the ability to implement what I write up.
I'm going to have to call this entry short.
I'm feeling kind of iffy right now.</p>
<p>Good night.</p>
Coding 2020-02-222020-02-22T05:00:00-05:002020-02-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-22:/coding-2020-02-22<p class="first last">Simple, obvious, and wrong?</p>
<p>I spaced out doing other stuff today, so when I wanted to work on punq, I decided to just make the changes I had in mind and see what happened.</p>
<p>It's sadly not quite as simple as I thought I was making it.
I took some time to make everything pass, but it's very much an "at what cost?" kind of deal.</p>
<p>It's super late, so I don't want to elaborate right now.</p>
<p>Good night.</p>
Coding 2020-02-212020-02-21T05:00:00-05:002020-02-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-21:/coding-2020-02-21<p class="first last">Trying to wrap up sooner...</p>
<p>I was thinking about my proposed changes to punq earlier today, and suddenly realized that, in thinking about this, I'd somehow managed to be everyone in <a class="reference external" href="https://xkcd.com/1172/">this xkcd comic</a>, several times.
I was trying to design an over-complicated workaround for the fact that my desired usage of punq was sort of adjacent to the bug I found.</p>
<p>So, today, I decided to do two quick things, since I've been really tired recently.
One was, I slightly rewrote the test I wrote against punq, so that it was a little more consistent with punq's other tests.
The other was, I replaced the "horrifying" part of my workflow with something that makes enough sense at runtime, I think, and sort of makes sense from a static analysis perspective.
Basically, instead of aliases, I'm differentiating types with NewTypes.
From a typing perspective, this is <em>technically</em> backward, because I'm using the NewType as some kind of phantom superclass.
If this really bothers me, I can define an adaptor function something like</p>
<div class="highlight"><pre><span></span><span class="c1"># I didn't test this.</span>
<span class="k">def</span> <span class="nf">constructor</span><span class="p">(</span><span class="n">new_typ</span><span class="p">:</span> <span class="n">Type</span><span class="p">[</span><span class="n">T</span><span class="p">],</span> <span class="n">constructor</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-></span> <span class="n">Callable</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="n">T</span><span class="p">]:</span>
<span class="k">return</span> <span class="n">constructor</span>
</pre></div>
<p>Anyway, tomorrow I'll try to work on the more restricted ideas I came up with for punq today.</p>
<p>Good night.</p>
Conlanging 2020-02-202020-02-20T05:00:00-05:002020-02-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-20:/conlanging-2020-02-20<p class="first last">Language is hard, yo.</p>
<p>I went over the little bit of text I wrote for Dabupan, and I've gotten some interesting ideas and thoughts out of it.
In no particular order:</p>
<ul class="simple">
<li>The non-passivizing use of the copula (which I wasn't actually sure was a thing before)</li>
<li>I want to copy the way Spanish has its words for "first" etc before the noun instead of after.</li>
<li>I'm slightly more confused about aspect than I was before. I've got to hit bottom sometime!</li>
<li>I got some ideas about dependent clauses. Except that the ideas make them somewhat less obvious to analyze as distinct from independent clauses, which I feel like is probably a good sign, because it means that I'm not exactly fitting into the molds of the languages I know.</li>
</ul>
<p>To make progress here, I want to try to really get a handle on aspect and mood, and then try to create some diagrams.</p>
<p>I just spent way too long trying to get a good workflow for ebooks on this laptop, oh well, better make the best of this.</p>
<p>Good night.</p>
Conlanging 2020-02-192020-02-19T05:00:00-05:002020-02-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-19:/conlanging-2020-02-19<p class="first last">Okay, let's make this quick.</p>
<p>I drafted out the ideas of the historical figure I mentioned; I'm probably going to run them by other people before I commit to them.
Once I'm happy with the substance, I'm going to work on how to express the aspects and moods.</p>
<p>Quick thoughts on the kinds of things I want to be able to express: cause and effect, proximity, some form of exclusiveness (Y was able to happen because X had stopped or completed), simultaneity, probably other things.</p>
<p>Anyway, it is late.</p>
<p>Good night.</p>
Weekly Roundup 2020-02-182020-02-18T05:00:00-05:002020-02-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-18:/weekly-roundup-2020-02-18<p class="first last">I think I was tired this week.</p>
<ul class="simple">
<li>Wednesday: I started fleshing out the beliefs of the fictional culture that gave rise to the conlang, in the hopes that this would give me a more substantial hook for writing texts to render into the conlang.</li>
<li>Thursday: I established the existence of one (1) fictional historical figure.</li>
<li>Friday: I got myself up to speed on Structured Data, and started learning Lean for some reason.</li>
<li>Saturday: I started sketching out ideas for a rework/maybe fork, maybe not, of punq.</li>
<li>Sunday: I existed in time and space.</li>
<li>Monday: I continued to exist in time and space.</li>
</ul>
<p>Next week, I should figure out some way to pick up the pace in the solo RP stuff.
I've been working on it off and on, and right now it feels kind of... floaty, I guess.
It's possible that I've missed some rules related to plot progression.</p>
Diary 2020-02-172020-02-17T05:00:00-05:002020-02-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-17:/diary-2020-02-17<p class="first last">These days don't feel productive. I'm just kind of out of it, I guess.</p>
<p>I took some notes on punq just now.
I think the magnitude of changes to the interface is smaller than I thought, but it will take some pretty extreme internal adjustment to make it all work.</p>
<p>Besides that, I didn't do much that was "creative" today, I don't think.
I think I'm just more in the mood to read stuff like weird RPG rulebooks, at least for now.</p>
<p>Good night.</p>
Diary 2020-02-162020-02-16T05:00:00-05:002020-02-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-16:/diary-2020-02-16<p class="first last">Today sure was a day, I think.</p>
<p>I'm not totally sure what happened today.
I guess I was kind of unfocused, but I did get a bit done on everything I wanted to.
So, that's good?</p>
<p>I think tomorrow I would like to take notes on how punq works, and how I'd like to change it.</p>
<p>Good night.</p>
Coding 2020-02-152020-02-15T05:00:00-05:002020-02-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-15:/coding-2020-02-15<p class="first last">It's kind of hard for me to fit all of the ideas here in my head.</p>
<p>Another slow day in terms of the blog stuff.
I might see about stretching this over the weekend.</p>
<p>I did do some design/planning for my punq changes/fork.
Mostly focused around realizing that I'm going to have to be very careful implementing all of this.
I'll just dump the notes I was taking in here.</p>
<blockquote>
<p>Type References are used at definition time, at registration time, and at resolution time.</p>
<p>Type References at definition time are resolved contextually.
Other type references are resolved globally.</p>
<p>One-part names, resolved contextually, must <em>fall back</em> to resolving against the builtins module.
Resolved globally, they must be resolved against the builtins module.</p>
<p>Resolution involves locating a module, getting the name from it, and extracting the qualname.
The canonical name of a Type reference is the right-most segment in its name, followed by the canonical names of its <tt class="docutils literal">__args__</tt> values, if any.
Next, the <tt class="docutils literal">__qualname__</tt> of the actual class object.
Finally, the canonical names of the arguments to the type.</p>
<p>Miscellaneous notes:
List[Any] -> list. In other words, if a generic type is subscripted entirely with Any, it should be replaced with its <tt class="docutils literal">__origin__</tt>.
It looks a little tricky to determine this.</p>
<p>Examples:</p>
<p>int -> int:int
list -> list:list
List -> list:list
List[int] -> typing.List:typing.List:[int]
List[T] -> not implemented</p>
<p>given Writer = Tuple[T, str], Writer[int] -> mod.Writer[mod.T, str]:typing.Tuple:[int]</p>
</blockquote>
<p>Good night.</p>
Coding 2020-02-142020-02-14T05:00:00-05:002020-02-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-14:/coding-2020-02-14<p class="first last">Super distracted.</p>
<p>Well, I thought today I was going to work out the details of the reworking I want to do of punq, and I did work out some good ideas in my head, but mostly I ended up getting reacquainted with Structured Data and getting the tests to pass again, and <a class="reference external" href="http://wwwf.imperial.ac.uk/~buzzard/xena/natural_number_game/">learning Lean</a> for some reason.</p>
<p>Good night.</p>
Conlanging 2020-02-132020-02-13T05:00:00-05:002020-02-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-13:/conlanging-2020-02-13<p class="first last">I don't like writing short entries, but I also don't like feeling like I'm going to pass out.</p>
<p>Extensive conlanging was preempted by game night and then spacing out, but I got a bit done.
I came up with a historical figure who used a version of the conlang, so next I want to work on his writings.</p>
<p>But for now, I need to get to bed asap.</p>
<p>Good night.</p>
Conlanging 2020-02-122020-02-12T05:00:00-05:002020-02-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-12:/conlanging-2020-02-12<p class="first last">This has gotten a little ridiculous.</p>
<p>Quick entry, because yet again I let things go late.
I decided that I'd probably enjoy trying to come up with "translations" more if I came up with stuff from the fictional culture to use, rather than existing stuff.</p>
<p>So, now I've got some idea of the beliefs and folklore of this fictional European region.
I'll have to develop them a bit more, because right now it's kind of shallow and broad in how it draws from stuff, which, fair, since I've been working on this for like ten minutes.</p>
<p>Unfortunately, I'm already out of time.</p>
<p>Good night.</p>
Weekly Roundup 2020-02-112020-02-11T05:00:00-05:002020-02-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-11:/weekly-roundup-2020-02-11<p class="first last">Orienting and re-orienting</p>
<ul class="simple">
<li>Wednesday: I realized that I needed to consider mood more in conlanging.</li>
<li>Thursday: I summed up parts of the paper I've been referring to.</li>
<li>Friday: I got my environment a bit more set up for coding.</li>
<li>Saturday: I wrote tests demonstrating what I believe is a bug in punq.</li>
<li>Sunday: I did a little bit of the solo RP stuff, and started thinking about how I'm assigning numbers to things, and other rules to mess with in some other context.</li>
<li>Monday: I did stuff, and didn't have time to write about it.</li>
</ul>
<p>Next week, I'm going to try to do a bit of RP every day, and come up with something different for the weekend.</p>
Solo RP 2020-02-102020-02-10T05:00:00-05:002020-02-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-10:/solo-rp-2020-02-10<p class="first last">Bite-size roleplaying.</p>
<p>Solo RP, I did a bit of it.
Now that I'm getting a bit better of a handle on the rules, I'm thinking I'll look at the system hacking stuff, just to see how far the system can be pushed.</p>
<p>Writing things up tonight, I figured out some stuff about my character concept that's really obvious in retrospect.
He's trying to be the mentor character who seeks out the chosen one and unlocks their potential, but he's really young.</p>
<p>It's getting kind of late, so I'm going to just cut things off now.</p>
<p>Good night.</p>
Solo RP 2020-02-092020-02-09T05:00:00-05:002020-02-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-09:/solo-rp-2020-02-09<p class="first last">Maybe I should pick a new topic for weekends and try to make this into more of a pick-up-and-play thing throughout the week...</p>
<p>I mostly took things easy today, but I did get a bit done with the solo rp.
I think I need some more experience handling normal misses.
I got a miss on a ward roll, and ended up thinking, "Uh, suffer -1 supply" and just going with that.
I feel like I don't have a sense of how I should be deciding what kind of consequence failure should have.
I suppose if it's negative, it's all right.</p>
<p>Now that I'm getting a satisfactory amount written, I feel like maybe my procrastination impulses are getting channeled into other rules and design challenges for the auto-roller.
Like, maybe trying to get my ECS ideas into a fit state so I can try to build a character sheet in that out of the various "sort of let you just stick different rulesets together" systems I've been looking at, like Retrocausality or stuff from Word Mill.
Got to keep focused.
Play these things off each other, like the fact that I'm not really enthused about doing hobby work in Python until my PR to give Poetry a "please don't try to install the package in the development environment" mode goes through.</p>
<p>Good night.</p>
Coding 2020-02-082020-02-08T05:00:00-05:002020-02-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-08:/coding-2020-02-08<p class="first last">Turns out if I'm not sure what's the best way forward, <em>then</em> I can write a test before an implementation.</p>
<p>Today, I mostly got distracted by Exapunks again, but I also had a chance to put together a <a class="reference external" href="https://travis-ci.com/mwchase/punq/builds/148016105">reproduction</a> of the punq issue I had.</p>
<p>This should help nail down the desired behavior, because I think I was kind of vague in the actual ticket.</p>
<p>Good night.</p>
Coding 2020-02-072020-02-07T05:00:00-05:002020-02-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-07:/coding-2020-02-07<p class="first last">Augh, it's late again.</p>
<p>After last week, I understand better how punq works in terms of type hints, and I believe it shouldn't work quite like it does.
However, I worry that my current solution may be more disruptive than the bugs I've found.</p>
<p>As such, the first thing I want to do is put together a reproduction of the issue.
I believe it requires multiple modules to fully manifest, so I'll have to add a bunch of auxiliary junk to the test directory.</p>
<p>I didn't actually do any of that today, because I was busy setting up more tooling.
Speaking of which, here's my current status with git:
At work, I managed to break every GUI I tried, so now I'm using the same three or so commands from the command line and trying not to think about it too hard.
For personal stuff, the GitHub Desktop client has been fine, in the past, but it doesn't seem to have a linux version, so I went and installed <a class="reference external" href="https://hub.github.com/">hub</a>.
I'll only be using it for other people's projects, like punq.
For my own, I prefer to use <a class="reference external" href="https://hg-git.github.io/">hg-git</a>.
For new projects that I don't feel like putting on GitHub, I'm using <a class="reference external" href="https://pijul.org/">pijul</a>.</p>
<p>Anyway, as I was saying, I was doing other things for a lot of the day, then focusing on this tooling, so I haven't yet added tests to punq to determine that there could be a bug.
That's step one tomorrow, and then, I'll try fixing it.
We'll see how it goes, but for now, I've let things go too late once again.</p>
<p>Good night.</p>
Conlanging 2020-02-062020-02-06T05:00:00-05:002020-02-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-06:/conlanging-2020-02-06<p class="first last">Linguistics is still hard.</p>
<p>I'm not going to have a chance to do much today, because I was taking things easy, and then also watching a very silly movie.
Let's have a look at the aspect-moods in Yucatec.</p>
<ul class="simple">
<li>Perfective: considering a completed action</li>
<li>Imperfective: considering an ongoing or potential action</li>
<li>Terminative: considering the consequences of an action, I think</li>
<li>Progressive: considering a definite ongoing action</li>
<li>Prospective: considering potential or ongoing actions</li>
<li>Necessitive: considering a needed action</li>
<li>Obligative: considering an action that must be carried out</li>
<li>Assurative: considering an action that the speaker is assuring the listener will (did?) occur</li>
<li>Desiderative: considering an action that the speaker wants to happen</li>
<li>Penative: considering an action that nearly occurs</li>
<li>Remote future: considering an action that happens with such remoteness that its happening is uncertain</li>
<li>Proximate future: considering an action that happens soon after another action</li>
<li>Immediate past: considering an action that happens soon before another action</li>
<li>Recent past: considering an action that happens somewhat longer before another action</li>
<li>Remote past: considering an action that happens long before another action</li>
</ul>
<p>The basic set of aspects I had in mind for Dabupan were perfective, imperfective, prospective, terminative, repetitive, habitual.
The moods I'd like to work with are indicative, imperative, subjunctive, honestly most of the moods up there seem pretty good, so I'll have to think about them more later.</p>
<p>One idea I'm toying with is decoupling temporal or causal "distance" from "direction", and perhaps representing that as some kind of connective.</p>
<p>This is all still really confusing.
Maybe I'll understand things better after a few more reads (I still haven't read the paper all the way through), but I wonder if the "tenselessness" that I want to replicate is an emergent property of the language, rather than something I could just kind of, break up into distinct indepedent components and make sure they work on their own.
It's possible the paper says so one way or the other, and I just haven't gotten to it or understood.</p>
<p>I get the impression that ideas of "tenselessness" and "temporal anaphora" are operating at a level of detail that I don't fully grasp.
The distinctions seem subtler than I initially expected.</p>
<p>Okay, I have to stop now, it's super late and I'm not ready for bed.</p>
<p>Good night.</p>
Conlanging 2020-02-052020-02-05T05:00:00-05:002020-02-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-05:/conlanging-2020-02-05<p class="first last">I'm not sure how many times I've been told some of this stuff, but it's a lot.</p>
<p>I made a little more progress reading about Yucatec, and I realized something from the reading, that I think I must have been willfully ignoring somehow.
Aspect and mood are related, so I should be considering mood in the context of aspect, and I can't design them as totally orthogonal systems.
I mean I could, but it would be gratuitously unnatural, and harder to get "right" than combining them would be.</p>
<p>If I'm reading the paper right, each "aspect-mood" marker implies a "status".
The "statuses" are:</p>
<ul class="simple">
<li>completive</li>
<li>incompletive</li>
<li>subjunctive</li>
</ul>
<p>I'm not up for it right now, but I think what I should do next is categorize the different AM markers by aspect and mood, and figure out how I want to express the concepts and which I want to grammatialize.</p>
<p>One idea that occurs to me is that it might be interesting to condense "not X but rather Y" into a conjunction of some kind, which could be used to express concepts like "tried and failed" within the verb's arguments, instead of on the verb.</p>
<p>For now, though, I should get ready for bed.</p>
<p>Good night.</p>
Weekly Roundup 2020-02-042020-02-04T05:00:00-05:002020-02-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-04:/weekly-roundup-2020-02-04<p class="first last">Do printers have fumes? If so, I might be woozy from them.</p>
<ul class="simple">
<li>Wednesday: I realized that I didn't have a firm enough grasp on aspect in general.</li>
<li>Thursday: I started reading an actual paper instead of constantly rewatching some youtube videos. It's... a lot.</li>
<li>Friday: I vagued about the wemake-python-styleguide.</li>
<li>Saturday: I reviewed the Ironsworn rules, to notice that I missed a kind of roll to code. I also found probably-a-bug in punq.</li>
<li>Sunday: I realized that I'd missed some of the rules to Ironsworn, which is a problem.</li>
<li>Monday: I got myself a little more caught up on the rules to Ironsworn.</li>
</ul>
<p>(The next day, spent several hours trying to print Exapunks feelies on a printer that reacts to double-sided printing by <em>freaking out</em>, and also crashing, and also only half of some pages would print from linux???)</p>
<p>Next week, I've got something I want to try in terms of coding.
I'll get to that when I get to it.</p>
Solo RP 2020-02-032020-02-03T05:00:00-05:002020-02-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-03:/solo-rp-2020-02-03<p class="first last">A little procrastinatey, but hopefully this is the last of it for a while.</p>
<p>I took today easy again, but I did take the time to review most of the rules, and get reference material printed out and put in the binder I have. I might try transferring the rulebook to my e-reader, but probably not.</p>
<p>I figured I'd wait to see if I had anything else to say.
I guess I don't.
Here's hoping I do better next weekend.</p>
<p>Good night.</p>
Solo RP 2020-02-022020-02-02T05:00:00-05:002020-02-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-02:/solo-rp-2020-02-02<p class="first last">Someone has to know all of the rules, and it hasn't been me...</p>
<p>I had a bit of a rough day today, so instead of more RP, I reviewed the Ironsworn rules and founds some stuff that I missed.
The rules are put together well enough that I don't have anything blatantly wrong as a result of missing what I missed, and it so happens that I don't have a strong desire for a do-over of anything so far, but it's something to keep in mind for later.
I also noted one other roll that I'm going to have to add to the auto-roller.</p>
<p>I'm thinking I'll print some stuff out and add a new section to my reference binder, because it is nice to be able to look over this stuff without having light blasted in my face.</p>
<p>For now, though, I'll just read this stuff off my screen, and take care of printing it out tomorrow.</p>
<p>Good night.</p>
Coding 2020-02-012020-02-01T05:00:00-05:002020-02-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-02-01:/coding-2020-02-01<p class="first last">I feel like maybe it should be doing the resolutions based on the defining module? Or, I guess typing defines things so it works well? I'll have to actually try it.</p>
<p>I think I've been a little burned out on coding recently.
I guess it's partly that I'm frustrated because I don't want to use Poetry until my pull request against it gets merged and released, and it seems to me to be still in a kind of bikeshedding phase.</p>
<p>If I want to do more, I should probably switch languages for a bit.</p>
<p>To get something done, I reviewed my reference material for the old solo RP.
I basically just established that Risus uses d6s, and the rest uses mostly d10s and d100s, with a single d20 added as a result of the exensive mixing of sources for the fate check.
Most sections had at least a little bit that could be entered into a tabular data file.</p>
<p>I was considering a bit the best practices for the library I'm putting together.
Because there's always at least some level of reliance on strings for the registrations, at least the way I write this stuff, the class names and aliases should probably be namespaced, which will probably look a little clunky.
I may want to look into changing how I do the dependency injection, since it's (almost) totally decoupled from the class definitions.</p>
<p>For some context, here's what some of these classes look like:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span></pre></div></td><td class="code"><div><pre><span></span><span class="nd">@typing_extensions</span><span class="o">.</span><span class="n">final</span>
<span class="nd">@attr</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">slots</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Roll</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Handle rolling a dice for some reason."""</span>
<span class="n">_random</span><span class="p">:</span> <span class="n">Random</span>
<span class="n">_roll_log</span><span class="p">:</span> <span class="n">RollLog</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">top</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">purpose</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Log the purpose of the roll, and the outcome.</span>
<span class="sd"> Args:</span>
<span class="sd"> top: The maximum value of the die to roll.</span>
<span class="sd"> purpose: The reason the die is being rolled.</span>
<span class="sd"> Returns:</span>
<span class="sd"> The outcome of rolling the die.</span>
<span class="sd"> """</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_roll_log</span><span class="p">(</span><span class="s2">"Rolling </span><span class="si">{purpose}</span><span class="s2">."</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">purpose</span><span class="o">=</span><span class="n">purpose</span><span class="p">))</span>
<span class="n">roll</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">top</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_roll_log</span><span class="p">(</span><span class="s2">"Rolled </span><span class="si">{roll}</span><span class="s2">."</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">roll</span><span class="o">=</span><span class="n">roll</span><span class="p">))</span>
<span class="k">return</span> <span class="n">roll</span>
</pre></div></td></tr></table></div>
<p>This is written to be mostly compliant with <a class="reference external" href="https://wemake-python-stylegui.de/en/latest/">wemake-python-styleguide</a>, which I think is a combination of interesting ideas, overreach, and I'm pretty sure it still crashes on Structured Data.</p>
<p>Anyway, I was just looking over the source code to <a class="reference external" href="https://punq.readthedocs.io/en/latest/">punq</a>, and I'm not convinced I understand its usage of type hints.
I'm going to have to experiment with it and see if I find some kind of shortcoming or edge case.
(Probably related to giving two classes the same name.)
But I'm too tired right now.</p>
<p>Good night.</p>
Coding 2020-01-312020-01-31T05:00:00-05:002020-01-31T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-31:/coding-2020-01-31<p class="first last">Situation: there are fourteen competing style guides...</p>
<p>I wasn't really focused today, so I got just a little work done on the coding front.</p>
<p>One change I wanted to make to the auto-roller code was to turn some of the code that I pulled in from the old Mythic setup into data files.
That will let me make the code much more compact, and stop wemake-python-styleguide from raising quite so many warnings/errors/whatever.</p>
<p>Speaking of wemake-python-styleguide, I kind of disagree with some of the underlying philosophy, so I'm trying to put together my own ideas.</p>
<p>One aspect that I'm currently kind of skeptical of is the sense I get of a one-size-fits-all approach.
Like that all code of a broad category is "basically the same", and that means that if code in that category deviates from the set standard, either the code must be changed, or the standard has to be changed across the board.
I don't know if that's the actual process, that's just how it seems from my reading of the documentation and experience filing bugs so far.</p>
<p>Speaking for myself, one idea that occurred to me is to have some kind of comment-based annotation syntax that could communicate verifiable assertions that it's not reasonable to expect the linter to check itself.
Like, "this class is an enum" or "this decorator applies classmethod" or "this is a context manager".
Ideally, such things could have default configuration, and also some kind of per-project or library-based component, so there could be custom stuff like "this is an adt.Sum".
(Structured Data convention is that Ctors are CamelCase, though I don't think anything actually enforces that; I could be wrong.)</p>
<p>I'll have to look into this idea tomorrow.
Right now it's late and I'm sleepy.</p>
<p>Good night.</p>
Conlanging 2020-01-302020-01-30T05:00:00-05:002020-01-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-30:/conlanging-2020-01-30<p class="first last">Dragging myself kicking and screaming into "learning how to study".</p>
<p>I'm working on understanding Jürgen Bohnemeyer's <em>Temporal anaphora in a tenseless language</em>.
A summary of it was what got me wanting to make a language that relies on aspect rather than deictic tense.
Since I'm mostly self-taught when it comes to linguistics, it's pretty slow going, and I'm probably going to need to read the whole thing several times before I understand it well enough.</p>
<p>One problem I think I'm having is that I was able to get by academically with terrible note-taking habits for too many years.
(See also, my comments from the Solo RP post a few days ago.)
Anyway, what this means is that right now it feels like I'm kind of cargo-culting the act of note-taking, based on my vague memories of other people's descriptions.
Is it helping?
We'll have to wait and see.</p>
<p>Anyway, because I was doing other stuff tonight, that's all I really had time for.
Oh well.</p>
<p>Good night.</p>
Conlanging 2020-01-292020-01-29T05:00:00-05:002020-01-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-29:/conlanging-2020-01-29<p class="first last">Linguistics is hard.</p>
<p>I took a stab at assigning Dabupan aspects to the sentences in Schleicher's fable, and I've come to two conclusions.</p>
<p>One is that I need a better intuitive grasp on aspect, because I have confused myself mightily.</p>
<p>The other is that I need a better idea of how I want to handle relative clauses, because my impulse was to mostly break them out into their own sentence.
I'm going to have to figure out how to make this work with aspect, and it's possible I'm going to need to redo some of the aspect verbs.</p>
<p>Thinking about how I would paraphrase a relative clause that had associated aspects...</p>
<p>"The man who builds a house"
"The man who is building a house"
"The man who builds houses"
"The man who constantly builds houses"
"The man who builds as house as a result"
"The man who caused this by building a house"</p>
<p>These phrases don't sound invalid, but my inclination is that the second should be the easiest to say, and if I'm going to do that, I need to shuffle around the aspect verbs.</p>
<p>So, what I need to figure out now is how to have imperfective be unmarked, and mark perfective.</p>
<p>Another possibility is that I'll want to have multiple paradigms of aspect, depending on the lexical aspect of the meaning verb.</p>
<p>This is all a lot to consider right now, and for the moment, I'll wrap up, and tomorrow do some more research.</p>
<p>Good night.</p>
Weekly Roundup 2020-01-282020-01-28T05:00:00-05:002020-01-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-28:/weekly-roundup-2020-01-28<p class="first last">A little better than recent weeks, I think.</p>
<ul class="simple">
<li>Wednesday: I figured out some details of the conlang, which is pretty much how these go lately.</li>
<li>Thursday: I put together some stuff to work on in the coming week.</li>
<li>Friday: I tried out a... design pattern, I guess.</li>
<li>Saturday: I switched my blog publishing pipeline over to my new laptop, and tried to remember how things worked in the previous solo RP.</li>
<li>Sunday: I made an appreciable amount of progress on the current solo RP.</li>
<li>Monday: "Yeah! Suffering!"</li>
</ul>
<p>Next week, I'll try to keep things up.</p>
Solo RP 2020-01-272020-01-27T05:00:00-05:002020-01-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-27:/solo-rp-2020-01-27<p class="first last">"Yeah! Suffering!"</p>
<p>So I was saying yesterday that the last thing I did in the session should have triggered a compel roll.
Well, I did that, and...</p>
<p>So one consequence of Ironsworn's rules is that any time you make an action roll, there is a one percent chance that the outcome will be incredibly bad, and no bonus can mitigate it.
I think one indicator of how much I've bought into Ironsworn's ideas is that my response to getting that roll was "Yeah! Suffering!"</p>
<p>So, now there's a guy who wants to kill my character.
As one does.</p>
<p>I didn't get a chance to do too much more because we had a bit of a rough night, and I want to take it easy, but I feel like I'm kind of over the hump now.
Of course, we've got more stuff planned for next weekend, but I don't want to worry about that right now.</p>
<p>Good night.</p>
Solo RP 2020-01-262020-01-26T05:00:00-05:002020-01-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-26:/solo-rp-2020-01-26<p class="first last">Session 1: attained!</p>
<p>I put myself up to it, and worked on the solo RP for a bit over an hour, with a little time in there to code up oracle rolls, which are basically just percentiles where sometimes it matters if the digits match.</p>
<p>There were some nice twists and details in what I got written.
(Although, I just noticed that I should have ended with a Compel.
I need to have a better handle on all of the moves.)</p>
<p>I think maybe I should contrast this with my earlier attempt to use Risus.
Now, I got further with Risus than I have so far, but thing going on with Risus is that the NPCs are constructed pretty much like the PCs, which isn't too cumbersome from a bookkeeping perspective because you could fit several character sheets on an index card.
However, it does mean that the GM is somewhat expected to run NPCs like a stable of PCs, which turns out to be kind of awkward when the entire game is one person doing a bunch of mental juggling.
Some of the commentary I've seen on Ironsworn points out that NPCs can't use combat moves, which is fine by me, since it gets rid of some weirdness I encountered running Risus solo.</p>
<p>Although I suppose part of the weirdness I hit is down to my general tendency to forget that <em>writing things down</em> is a thing.
Maybe if I'd actually determined an initiative order...</p>
<p>In any case, this is feeling good so far, and I'm gratified that I actually got some amount written.
I'm going to call the entry a little early and read for a bit, because I don't want to take things up to or past the wire again.</p>
<p>Good night.</p>
Coding 2020-01-252020-01-25T05:00:00-05:002020-01-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-25:/coding-2020-01-25<p class="first last">I switched over to the new laptop. It was an experience.</p>
<p>So, there's still some work to do to migrate all of my stuff over to this laptop, but I got the blog publishing working.
And I'm not just saying that because this wouldn't be online if I were wrong.
I tested this beforehand.</p>
<p>Anyway, I've got my roller ready for tomorrow, so for now I'm going to plan out some stuff to mess around with.
The previous solo RP rules I was using were some somewhat aggressive homebrew, that also just straight-up included some entire systems.
I'm going to start by planning how to pull stuff into my auto-roller repo from all that.</p>
<p>First, one thing I realized, is that to get wemake-python-styleguide happy, I'm going to need to put some of the tabular data this is going to use, into data files that get parsed at runtime.</p>
<p>Anyway, let's see what I need to model Risus.
Risus has several kinds of roll.
Unopposed rolls use a number of d6 determined by the character, to try to beat a difficulty number set by the GM.
Because the rules give multiple targets for a single example (that is, one example features different targets for different levels of success), the "beats" logic should probably live at a different level than the "roll the dice and add them up" logic.
This core logic is the same for the combat system, the main differences being around the interpretation of the outcomes.
The one thing that needs to be added is "roll some number of dice, and drop all non-6 results".</p>
<p>That should be sufficient for the parts of Risus I was using.
I'll move on for now.</p>
<p>The remainder of the reference binder I put together is a blend of The Adventure Crafter and Mythic, that I don't fully remember some of the details for.
Let's see how I was using this.
So, the starting Chaos Factor is set to 5, which is the norm for most themes; I don't remember if I was going to enforce the minimum Chaos Factor of the Mystery theme.
Anyway, it starts by generating a turning point for the initial scene.
There's no Chaos roll initially.
Anyway, generating a turning point gets heavily into Adventure Crafter stuff.
I think it would be comparable effort to doing the rest to write the rest of the reference up in prose.</p>
<p>I think what I'll do for next time is get the current folder properly version-controlled, make an effort to get my old code in, and then start adapting material.
Make sure to have tests of some kind.</p>
<p>Anyway, I would have preferred a little more coding or planning and a little less setting-up-my-environment tonight, but hopefully I don't need to do that again.
I'd better wrap things up for now.</p>
<p>Good night.</p>
Coding 2020-01-242020-01-24T05:00:00-05:002020-01-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-24:/coding-2020-01-24<p class="first last">I need to switch all the way over to the new laptop.</p>
<p>Okay, the battery in this is getting weird enough that I need to make the switch to publishing with the new laptop.</p>
<p>Anyway, last week I reread a blog post that gave advice for a design pattern to use with Python.
I recognized the problem it was solving as one that I'd had with a previous project, to make an auto-roller for some RPGs I wanted to play solo.
Basically, I was uncomfortable with the idea of hardcoding a reference to a particular global value, like the <tt class="docutils literal">random</tt> module.
I had similar issues when I wanted to have some functions "emit" information about what they were doing.
And then I wanted to sometimes control the indentation...
I ended up with a weird grab-bag of parameters that various functions took, only to forward along to the next function in the call chain.</p>
<p>I don't want to go into details about the post right now (it's late, again; I'll try to start writing stuff up earlier tomorrow), but reading it was sort of the point in the infomercial where it shifts to color.
Using the techniques in the post, I was able to pass fewer parameters in a way that gave me more robust behavior.</p>
<p>Before I started on this post, I did some informal testing of an auto-roller for Ironsworn, so that's ready for the weekend, and now I can freely tinker with this; maybe try to convert the reference guide I put together for my previous solo effort to code.</p>
<p>Again, I'll go into more detail tomorrow, but this technique is really great when it makes sense.
My biggest reservation with it is that it looks... kind of weird.
Oh well, I'm done for tonight, super sleepy.</p>
<p>Good night.</p>
Conlanging 2020-01-232020-01-23T05:00:00-05:002020-01-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-23:/conlanging-2020-01-23<p class="first last">Time management. Ennh?</p>
<p>Another day that took a bunch out of me, not sure why this time.
Anyway, I didn't get much done conlanging, but I did decide that I'd like to work with longer text in my attempts to create glosses.
So, I've got <a class="reference external" href="https://en.wikipedia.org/wiki/Schleicher%27s_fable">Schleicher's Fable</a> copied into my reference document, and I'm going to try to work from that.</p>
<p>If the stuff I'm going to try this weekend to deal with procrastination works out, I'll see what I can apply to working on this next week.</p>
<p>Anyway, I need to get to bed ASAP, and I'm not quite ready, so, time to go do that.</p>
<p>Good night.</p>
Conlanging 2020-01-222020-01-22T05:00:00-05:002020-01-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-22:/conlanging-2020-01-22<p class="first last">Lesson learned: Write something, and maybe you'll get more writing done than you expected. Also, maybe don't do this at 11:30 PM.</p>
<p>I wasn't up for conlanging today, so I'm going to quickly mention some ideas I had shortly after the last post, for trying to deal with the issue.</p>
<p>Somewhat weird option: put the meaning verb in the genitive, since the genitive doesn't exist on its own in normal sentence structure.</p>
<p>Somewhat bulky option: put it in the accusative, but require some form of determiner for all noun phrases.
The latter part sounded to me like an interesting touch, regardless of whether I go with that actual solution.
It would basically be like "some of the other languages I know, but more".
"My thing"? No, "The my thing".
(All right, "The thing of mine".)</p>
<p>In any case, if the verb isn't taking a determiner because it's not a noun phrase, then that means I could put it in any case I want.
I choose... nominative.
That way, when a verb is participating in this system, it's always nominative, regardless of the aspect.</p>
<p>That is my initial feeling on this idea.</p>
<p>Anyway, that's way more than I expected to get accomplished here today, good job me, I need to get ready for bed now, wow, so tired.</p>
<p>Good night.</p>
Weekly Roundup 2020-01-212020-01-21T05:00:00-05:002020-01-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-21:/weekly-roundup-2020-01-21<p class="first last">Using linux milestone: messing up command sequences on the Macbook</p>
<ul class="simple">
<li>Wednesday: I realized that I hadn't though through all of the implications of my conlang ideas.</li>
<li>Thursday: I came up with some ideas for how to resolve the weirdness.</li>
<li>Friday: I made progress on the port.</li>
<li>Saturday: I made more progress on the port.</li>
<li>Sunday: I got really close to getting started with the RP.</li>
<li>Monday: I admitted that I'm procrastinating.</li>
</ul>
<p>Next week, I'm not sure how much I'll get done, because there's some big company meeting.
Hopefully that doesn't jar things too much.
I've got a plan for dealing with procrastination when the time comes.
We'll see how that goes.</p>
Solo RP 2020-01-202020-01-20T05:00:00-05:002020-01-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-20:/solo-rp-2020-01-20<p class="first last">Okay, I've got a problem.</p>
<p>I took some time today to make sure I knew the rules for Ironsworn moves in general, and swearing an iron vow in particular.</p>
<p>Then, instead of actually applying them, I did another iteration on one of my occasional little projects, which is trying to code up a nice dice roller to compensate for the fact that I don't have any dice handy besides some d6s that I think technically don't belong to me, and I never think to look for a ready-made application.</p>
<p>I'll go into more detail about what I wrote in a few days, I think it's pretty interesting, but it's not on topic for this post.</p>
<p>Anyway, I'm now pretty confident that I've been procrastinating, and I should work on it.
I don't know how best to deal with it, but, and this is going to sound bad, I've got almost a week to look into it.
With that in mind, I've just googled an article to read tomorrow, because I want to try to get this taken care of sooner than later.</p>
<p>I don't know what to say, besides that I don't think I have any excuses not to get right into this next week.</p>
<p>We'll see.
Anyway, it's super late already, and I should sleep.</p>
<p>Good night.</p>
Solo RP 2020-01-192020-01-19T05:00:00-05:002020-01-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-19:/solo-rp-2020-01-19<p class="first last">Asymptotically approaching starting the dang campaign.</p>
<p>(I'm going to hope that if I ever do any kind of collaborative RP, I can manage to get all the prep down into at most a week.)</p>
<p>I was mostly ignoring the stuff I usually do today, but I did take a look at the Ironsworn rules, and put together everything I think I need for the fiction component of swearing the initial iron vow.</p>
<p>Why yes, I <em>have</em> heard of Zeno's paradoxes of motion.</p>
<p>Anyway, I'm going to hope that I've done enough that tomorrow I can just take care of any rolls I need to do, and then start working on the stuff after character creation.</p>
<p>For now, though, I sleep.</p>
<p>Good night.</p>
Coding 2020-01-182020-01-18T05:00:00-05:002020-01-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-18:/coding-2020-01-18<p class="first last">I sure am using a new laptop.</p>
<p>I'm still feeling kind of rough, but I got some work done on the port.
It's just kind of a slow process of figuring out the code a little, then getting a bit more ported.
Nothing terribly interesting to report; the original code would probably benefit from a linting pass and taking full advantage of version control.
(If there are commented-out bits of code in your source file, you're not taking full advantage of version control.)</p>
<p>I'm still getting to grips with the new laptop (I still haven't put in the effort to make the publishing pipeline cross-platform).
I've been tempted to switch up some stuff pretty drastically, but I think what would be best would be to use it enough to figure out which thing legitimately bothers me the most, then work on addressing that.
Try to improve my user experience in priority order, or something.
Also, I should get backups set up before I do anything too drastic.</p>
<p>(Also, at some point I'm going to be developing in Python really seriously, and I'm going to have to transfer my custom keybinds over.
It's weirdly inconsistent from person to person what behavior is sensible or unintuitive, but I know what bothers me, and I'm on borrowed time until I need to put my "sane_reindent.py" script somewhere that Sublime can get at it.)</p>
<p>Good night.</p>
Coding 2020-01-172020-01-17T05:00:00-05:002020-01-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-17:/coding-2020-01-17<p class="first last">Getting ready to code involves a lot of fiddling with package managers.</p>
<p>I was in kind of a haze by the time I got to work on anything blog-worthy, so I mostly just tried to get my coding environment somewhat set up.</p>
<p>I don't know if there's anything particularly interesting for me to say about what I did.
It was mostly running curl-sh commands and copying over stuff I had installed through Sublime Text's package manager.
There are a few loose ends I need to take care of, like installing some of the command-line tools needed to actually implement some of the packages I just installed, but I'm way too tired to work through the basic set of steps involved there.
I'll try to do actual coding tomorrow, but for now, I need to unwind more.</p>
<p>Good night.</p>
Conlanging 2020-01-162020-01-16T05:00:00-05:002020-01-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-16:/conlanging-2020-01-16<p class="first last">At some point I should research the different ways natural languages handle this kind of thing. Maybe they use a less confusing system than I locked myself into via "aesthetics".</p>
<p>So, I ended up focusing on other stuff today, but I'm going to try to work through some of the stuff I was worried about yesterday, really quickly.</p>
<p>There are several verbs that can be used in an aspectual sense, which combine with another verb to form the meaning.
The meaning verb is in the infinitive form, then declined like a noun.
Aspect verbs can be divided into "transitive" and "intransitive".
Intransitive aspect verbs treat the meaning verb as an extension of the subject.
Transitive aspect verbs treat the meaning verb as a direct(?) object.</p>
<p>The problem, then, is, what happens when the meaning verb needs an object?
I could imagine a specific preposition for marking the "displaced" noun phrase, or the meaning verb could attach to the direct object somehow, rendering them as a single phrase.
I'd be interested with the possibilities there, but I'll have to figure out how it works with relative clauses.
I mean, it could be that the "transitive aspect verbs" basically act on a relative clause.
I think that sounds interesting.</p>
<p>At some point, I'll have to take stock of how I've ended up doing things, since I've diverged pretty heavily in some respects from my initial drafts.</p>
<p>Anyway, I can't write any more tonight.</p>
<p>Good night.</p>
Conlanging 2020-01-152020-01-15T05:00:00-05:002020-01-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-15:/conlanging-2020-01-15<p class="first last">It's apparently somewhat surprising to actually apply every idea I had for this together...</p>
<p>I was mostly taking it easy and replaying puzzle games today, but I did some work on The Tongue of Light, or rather its immediate ancestor language.
When I actually started putting stuff together, I realized I'd rather use stative verbs, and have a way to transform verbs into nouns that can be in noun phrases, than to have adjectives be inherently nounlike.
I'll have to think over the implications of this, but I think it addresses some concerns I had about natural ways of expressing simple ideas.</p>
<p>I'll try to go into a little detail...
Basically, there are several aspect distinctions that get drawn, and they're all periphrastic.
The thing was, I was trying to have the aspectually-modified verb act as an object to the aspect verb, which meant I was ending up with confusing combinations of noun case.
Switching to stative verbs made the sentences shorter and left them with fewer parts to worry about getting to agree.</p>
<p>Now that I lay all of this out, I see it's possible that I might have just pushed off the complexity, and maybe I can formulate a sentence that has the exact same issues.
(Try constructing sentences with "to help", for example, and see if they still make sense. I have a suspicion that I'll end up extending the use of a word I came up with for a slightly different purpose. This has happened a few times already, and it's nice when it does.)
I should also make sure that using stative verbs to modify nouns still makes sense to me.</p>
<p>In any case, I hope I explained that well enough; I should maybe start being specific in my examples.
Next time, or next week, maybe.</p>
<p>(I also started working on porting the blog publishing pipeline to out-of-the-box Ubuntu. I believe the only change I needed to make was to have a different command for generating the notifications, but that's probably not enough, somehow. I'll also need to remember to install the various dependencies, including sass, whatever I'm using to compress the images, some stuff for pyenv... It's probably not too much...)</p>
<p>Good night.</p>
Weekly Roundup 2020-01-142020-01-14T05:00:00-05:002020-01-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-14:/weekly-roundup-2020-01-14<p class="first last">I was under some stress last week. It showed.</p>
<ul class="simple">
<li>Wednesday: I put together a table.</li>
<li>Thursday: I wrote some sample sentences.</li>
<li>Friday: I figured out that the stuff that SCA² was doing with globals could mostly be done more easily with multiple returns.</li>
<li>Saturday: I got more SCA² porting done in a way that I'm optimistic about.</li>
<li>Sunday: I made a little bit of progress in naming characters and places.</li>
<li>Monday: I got a little closer to finishing up the last part of my character sheet.</li>
</ul>
<p>Next week, I think I might end up getting even less done on these fronts.
I've got to migrate to the new laptop and figure out my workflows for it, which is a bit of an adjustment.
Among other things, I need to manually transfer my repos, since my NAS doesn't seem to sync dotfiles by default.</p>
Solo RP 2020-01-132020-01-13T05:00:00-05:002020-01-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-13:/solo-rp-2020-01-13<p class="first last">I did a thing.</p>
<p>Not much work done today.
I was focused on getting my new laptop set up; this is still from my old one, because one thing I didn't handle was getting repository metadata copied over.</p>
<p>For the solo RP, I worked on the iron vow my character is going to swear to kick things off.
I'll have to work out how to represent this on the sheet and such, but I can't focus on that right now.
I need to get ready for bed.
I wish this weekend had been more relaxing.
Oh well.</p>
<p>Good night.</p>
Solo RP 2020-01-122020-01-12T05:00:00-05:002020-01-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-12:/solo-rp-2020-01-12<p class="first last">I couldn't figure out what to put here.</p>
<p>Things are going to be kind of disorganized for a while.
I'm trying to migrate to a new laptop, and it's not a smooth transition, because I can't just grab everything and switch it over.
I'm trying to do that with the data, and the fans in the new laptop are Not Having It, but the bigger problem is figuring out proper replacement applications.
Sometimes it's straightforward, and sometimes it's... not.</p>
<p>Anyway, let's see about having some outlines for the solo rp backstory.</p>
<p>Okay, I filled in some names, events, and geography.</p>
<p>For now, this'll do.</p>
<p>Good night.</p>
Coding 2020-01-112020-01-11T05:00:00-05:002020-01-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-11:/coding-2020-01-11<p class="first last">This might <em>technically</em> be the third time...</p>
<p>Things are going okay with the porting effort.
I started over, and I've gotten further now, with fewer obvious roadblocks.
Now that I understand the code better, I did attempt some "refactors", which may have been a bad decision, but eh.
What's left to do is to fill in some of the functions and write some scaffolding for creating the data.</p>
<p>Not much else to say on this.</p>
<p>I also went into the standalone ECS project I mentioned a while ago, and reversed one of the decisions I made in the port.
The idea there is to make it easier in the future to support stuff like indices and other modifications to a component's storage.
All there was to do for this now was to create a wrapper class that can have optional arguments added later.
Pretty simple.</p>
<p>Anyway, I'm done for the night.
Extremely done.</p>
<p>Good night.</p>
Coding 2020-01-102020-01-10T05:00:00-05:002020-01-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-10:/coding-2020-01-10<p class="first last">This code could really benefit from some features that may have come out after its last revision.</p>
<p>Most of the stuff that was bothering me this week is taken care of, though some of the stuff that's left is a bit of a doozy.</p>
<p>I was doing other stuff to unwind again, but I just had a breakthrough on SCA².
It looks like most of the globals can be replaced by multiple returns.
Which means I wouldn't need the temporary variables to hold the values, because I can just <em>pick different names</em>, or <em>not assign to names in the first place</em>.
I think I'm making much better progress now that I know what I can basically ignore.</p>
<p>I'm currently sticking to the higher-level side of this, which means figuring out the <tt class="docutils literal">CatSub</tt> function.
I guess it needs some way to refer to the categories.
Oh well, I'll try to figure this out tomorrow.</p>
<p>Good night.</p>
Conlanging 2020-01-092020-01-09T05:00:00-05:002020-01-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-09:/conlanging-2020-01-09<p class="first last">It's hard to work on stuff I like when it's such a pain to work on stuff I need.</p>
<p>I had kind of a weird and unpleasant day today.
UPS behaved completely typically.
If they pull this again tomorrow, I'm going to spend Friday on the porch, no matter the weather.</p>
<p>Anyway, I was doing other stuff to unwind today, but I put together a bunch of sentences that should give me some grasp on syntax.
I'll gloss them with placeholder words, then try to diagram the glosses and see if I can come up with something consistent.
I started writing the glosses and then I realized that I don't seem to have transcribed my notes on aspect, and it's dark, so I don't want to do it now.</p>
<p>Tomorrow, I think I'll try to write up the SCA² before going back to porting it, because my efforts last week were kind of confusing me.
I might try forcing myself to reason locally, but I'm not feeling great about that idea when there are so many globals.
Best try to document each function I'm interested in.
Also, once I do port, maybe accept some un-idiomatic code for the sake of getting things together enough to write tests, then refactor.</p>
<p>Good night.</p>
Conlanging 2020-01-082020-01-08T05:00:00-05:002020-01-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-08:/conlanging-2020-01-08<p class="first last">Until today, I forgot I could link to the LCK website.</p>
<p>This week started off kind of stressful, so I didn't end up focusing much on conlanging today, but I did put together a table of <a class="reference external" href="https://www.zompist.com/kitgram.html#otherpron">correlatives</a>, so that I have a checklist of pronouns to come up with, more or less.
Right now, I'm kind of thinking about this language in terms of how it expresses the Europeanisms that it acquires, and that turns out to make a bunch of decisions for me.
I feel like this area is going to need a lot of focus, because the use of "correlatives" is one of the things that will make this language resemble German a lot, and in a way that English does somewhat, which means that I need to look for degrees of freedom to allow me to express features like "Forming questions the way English does" without making it a relex.
Fortunately, some of the stuff I'm putting in has implications I'm just now realizing, that make some things look really different.</p>
<p>I should wrap it up now.
My schedule tomorrow is super weird, at least by my standards.
I think tomorrow I'd like to try developing some idea of the evolution of syntax.</p>
<p>Good night.</p>
Weekly Roundup 2020-01-072020-01-07T05:00:00-05:002020-01-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-07:/weekly-roundup-2020-01-07<p class="first last">Things are going well.</p>
<ul class="simple">
<li>Wednesday: I got almost enough sound changes for a baseline of "here's how to get between the phonologies and phonotactics".</li>
<li>Thursday: I worked a bit on the history of the grammar.</li>
<li>Friday: I decided on trying to port the core of SCA² into some kind of library.</li>
<li>Saturday: I started on the porting effort. It's not going super-fast, but it's going.</li>
<li>Sunday: I made some decisions on my character build, and also got more information into my actual character sheet (which is a Lua file, because the idea of doing that always makes more sense to me than maybe it should.)</li>
<li>Monday: I got my character concept worked out enough that I felt comfortable writing stuff in-character.</li>
</ul>
<p>Next week, I'm going to keep it up.</p>
Solo RP 2020-01-062020-01-06T05:00:00-05:002020-01-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-06:/solo-rp-2020-01-06<p class="first last">Almost there!</p>
<p>I've got everything I need for my Ironsworn character sheet, except that I haven't actually sworn the iron vow relating to my inciting incident.
I've got things mostly figured out, it's just that I want to actually write up the leadup to the incident in-character, which I've started doing.
More substantial progress, it's great.</p>
<p>I'm not going to share too much of what I've written yet, since what I just now wrote is rough-draft quality, much like... virtually every blog post I publish.
Hm.
Well, I'm still not sharing it now, is the point.</p>
<p>I hadn't actually worked out what the process for this was going to be like, so we'll kind of have to see how much I write when, but I'm really glad to have as full a picture of the beginning of the arc as I do now.</p>
<p>I'm going to try to wrap things up early tonight, because I've got, like, work tomorrow, and my sleep schedule is still kind of iffy.</p>
<p>Good night.</p>
Solo RP 2020-01-052020-01-05T05:00:00-05:002020-01-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-05:/solo-rp-2020-01-05<p class="first last">Slow but definite progress, again, again.</p>
<p>Now that I'm putting the weekend aside for working on the Solo RP stuff, I got enough focus to finally nearly finish up my character sheet for Ironsworn.
I've just got to decide on any other starting bonds I want, and figure out my inciting incident.
I think I just got it.
Hm.
I'll sleep on it.
Anyway, I'll try to get this finalized tomorrow.</p>
<p>For now, I should, once again, sleep.
It's kind of annoying how that needs to happen over and over.</p>
<p>Good night.</p>
Coding 2020-01-042020-01-04T05:00:00-05:002020-01-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-04:/coding-2020-01-04<p class="first last">Slow but definite progress, again.</p>
<p>I'm working on porting SCA².
It's not looking like it'll be especially hard to do it; the JavaScript code isn't doing anything too exotic.
The big hurdle I have to clear every once in a while is that the coding style is not what I would do in Python, but it's a lot less thought to port things over directly than to try to work out how I would have done it.</p>
<p>Right now, I'm working on the parser/interpreter for the DSL.
I think I'd like to factor those apart, probably.</p>
<p>Anyway, I'm sure things will work out.
I just need to pace myself until my sleep schedule gets un-ruined from being on vacation.</p>
<p>Good night.</p>
Coding 2020-01-032020-01-03T05:00:00-05:002020-01-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-03:/coding-2020-01-03<p class="first last">What if I try to do a thing that sounds manageable, rather than crazy-ambitious?</p>
<p>So, Mark Rosenfelder's <a class="reference external" href="https://www.zompist.com/sca2.html">SCA²</a> basically provides a nice interface for bulk application of string rewriting operations written in a <abbr title="domain-specific language">DSL</abbr>.
There are options for how to display the output, an interface for saving the rewrite rules, and concepts of predefined and nonce categories.</p>
<p>I'm interested in getting the core functionality into a form that can be somehow pipelined or otherwise automated.
This means not trying to port all of the functionality one-to-one.
Rather than applying a sequence of rules to an ordered lexicon, I'd like to port the logic for "applying a single rule to a single entry".
The rest of the functionality can be built up naturally.</p>
<p>My plan, then, is to first port the existing DSL-based implementation, and then work on taking it in a direction that makes sense to me.
For example, the <abbr title="International Phonetic Alphabet">IPA</abbr> divides phonemes up according to features.
Perhaps phonemes could be specified like that, and allophonic variation specified as well, since I assume allophones exert influence on sound change, especially when they're in complementary distribution.
I am not a linguist, however.
Anyway, that's for later.</p>
<p>My task for tomorrow is to write up the core logic of SCA², so I can port it soon.</p>
<p>My task for now is to sleep.</p>
<p>Good night.</p>
Conlanging 2020-01-022020-01-02T05:00:00-05:002020-01-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-02:/conlanging-2020-01-02<p class="first last">I also might look into trying to base something off Ned Batchelder's Cupid library to render diagrams for this stuff.</p>
<p>I planned out some of the grammatical history today, but we traveled back today, so that took another chunk of time.
I'm hoping I'll be in better shape for this next week now that I'm home again.
I've got to focus right now on un-messing-up my sleep schedule so I can get to work tomorrow.</p>
<p>After that, it's coding, and I think I might look into the SCA² tool; it'd be really nice to have something like it that worked on files.</p>
<p>I can't think of anything more to write and I probably shouldn't.</p>
<p>Good night.</p>
Conlanging 2020-01-012020-01-01T05:00:00-05:002020-01-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2020-01-01:/conlanging-2020-01-01<p class="first last">I was worried that the changes I had in mind would be "not enough", then I realized the ancestor for "trra" would be, like, "tīnrā[something]" so I just need to work out the "something" and I should be good.</p>
<p>For the last night of the new year, I put in some more work on my weird sort-of-joke conlang.
I've put together a draft collection of sound changes, not yet organized into a proper sequence, that should properly convert from the ancient to the modern phonology.
Probably of more interest is putting together the histories of particular words.
I think what I need to do is figure out at which points major bits of grammaticalization happened (like the development of the case system), and break up the sound changes so they take the words to each such event, and apply any required changes manually.
Figuring out how to apply those changes automatically is the major hurdle to clear to get nice tooling around this process.</p>
<p>One thing I'd like to do is port the <a class="reference external" href="https://www.zompist.com/sca2.html">SCA²</a> tool to run offline.
I tried this one before, and got tripped up by the way the code was written.</p>
<p>Anyway, I should wind down for now, then get into grammatical history tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2019-12-312019-12-31T05:00:00-05:002019-12-31T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-31:/weekly-roundup-2019-12-31<p class="first last">You wouldn't think not going to work would leave me so little time for posts, and yet...</p>
<ul class="simple">
<li>Wednesday: I did some research for conlanging.</li>
<li>Thursday: I did a little conlanging work while writing the post, but not much else.</li>
<li>Friday: I tried to automate away some of the work required for conlanging. It didn't work.</li>
<li>Saturday: I put the entry up way early. The entry explained that I was putting up the entry way early.</li>
<li>Sunday: I thought some about the direction I'd like to take my minecraft skyblock stuff. And the blog.</li>
<li>Monday: I gave automating linguistic evolution another try, before deciding I'd need a better understanding to attempt it.</li>
</ul>
<p>Next week, I'm going to try out the idea I had on Sunday.
I'll try... conlanging, coding, solo RP, and we'll see how that treats me.</p>
Diary 2019-12-302019-12-30T05:00:00-05:002019-12-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-30:/diary-2019-12-30<p class="first last">Doing things the hard way, because I'm not sure how to get to the easy way.</p>
<p>I played a little more skyblock, and made some progress.
I'm pretty bottlenecked on infrastructure.
My temptation is to rush Applied Energistics and try to set up autocrafting for common components.
I don't know if that would actually work, especially since I don't have any kind of unified power system.</p>
<p>I tried to put together a helper library for modeling linguistic evolution, but it turns out parts of such a thing are very complicated, and I need more hands-on experience with what I'm trying to make shortcuts for.</p>
<p>So, I'm right now trying to put together a bunch of examples, manually.
It's going to be pretty nuts, I can tell, but hopefully I'll learn something from it.</p>
<p>I'll get back to that for now.</p>
<p>Good night.</p>
Diary 2019-12-292019-12-29T05:00:00-05:002019-12-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-29:/diary-2019-12-29<p class="first last">I should really make some screenshots of this, huh.</p>
<p>I got in super late last night, so my prediction was validated.</p>
<p>Anyway, I got to thinking, maybe I'd like to switch back to working on a per-day kind of thing, see if that feels good.
Six days I need.
Coding.
Solo RP.
Conlanging.
Maybe split the days up into pairs.</p>
<p>I'll try that starting next week.</p>
<p>For now, I spent most of today playing the more Minecraft.
It's been the <a class="reference external" href="https://www.curseforge.com/minecraft/modpacks/equivalent-skies">Equivalent Skies</a> modpack.
I believe I've gotten past the very basics, and now that I have miniaturization crafting, I now have the option to shove stuff into compact machines.
But I think I don't want to shove stuff in if it's like Immersive Engineering and it's kind of meant to have associated decorations and such.
I kind of have this idea of having floating islands focused around each mod, where for example there'd be a tree for Botania, a wizard tower for ThaumCraft, some kind of factory for Immersive Engineering, and maybe just a giant smeltery tank for Tinkers Construct.</p>
<p>What I have to figure out is, which mods don't want to be shoved aside.
I think it's Botania, ThaumCraft, and Immersive Engineering for sure, and I don't know what else.
ProjectE itself, I guess.</p>
<p>I also want to somewhat future-proof this whole concept, so I don't need to do really obnoxious changes when I hook up everything into an AE2 network.</p>
<p>I'm thinking I'll have the Botania island just clockwise from the mob farm, the ThaumCraft island clockwise from that, and the Immersive Engineering island clockwise from that.
I wish I knew how big to make these, but maybe I can just make sure to mostly expand them away from my spawn point.
Anyway, I've got some Actually Additions and Integrated Dynamics machines where this plan would put ThaumCraft, so I'll have to break those down and put them elsewhere.
Maybe have a big compact machine for the mostly stand-alone kind of single-block machines, and have dedicated compact machines for crystallization and each empowerer recipe.
I'm regularly throwing around absurb amounts of EMC from a tiny farm (Hopping bonsai slime trees on orange soil. So good, since the 9-slime block is ore-dictionaried.), so I'm not particularly bothered by the idea of making a bunch of empowerer multiblocks.
Maybe if I stick them together somewhat, I can get a whole bunch into one block and just route stuff using item conduits.</p>
<p>I'll try to make some progress on this tomorrow, and also throw something together for the conlanging.</p>
<p>Good night.</p>
Diary 2019-12-282019-12-28T05:00:00-05:002019-12-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-28:/diary-2019-12-28<p class="first last">Preemptive not-much-to-write-about</p>
<p>I found out this morning about some traveling that's happening today, so I'm posting this early to get a post for this day in.
So early, that all I have to say is that I added a few more roots to try in my conlanging efforts, and I'll try them out sometime after I post this.</p>
<p>Good afternoon.</p>
Diary 2019-12-272019-12-27T05:00:00-05:002019-12-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-27:/diary-2019-12-27<p class="first last">Me, a mathematician: "Wow, exponential growth is terrifyingly potent."</p>
<p>So, I decided to try generating a subset of all possible roots in Ancient Dabupan according to my current rules.
I keep on putting restrictions on what's generated, and it's still <em>a lot</em>.
I'm going to need to develop some kind of skill for isolating representative samples to inspect in more detail, because I don't want to go in-depth <em>and</em> in-breadth with a bunch of un-tested sound changes on thousands of roots.
I think I need to, like, pick one to start with, see what it does, and guess which ones could end up different.
Then pick one of those, and try to get coverage that way.</p>
<p>I think I'll have to clean up my outline first.
I've been working in a kind of grab-bag section at the very end of it, and it's kind of a mess.</p>
<p>I'm going to call this entry now, and try to do the cleanup after I post it.</p>
<p>Good night.</p>
Diary 2019-12-262019-12-26T05:00:00-05:002019-12-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-26:/diary-2019-12-26<p class="first last">Slow progress: because I can't always have fast progress.</p>
<p>As I sort of anticipated yesterday, traveling today made it hard to get much done, but I did make some good progress on some of the details of the proto-language, so I should be able to write up how I want it to work, and then start messing around.</p>
<p>I'll try and do that now.</p>
<p>...</p>
<p>Done.
It's like a cooking show, but really underwhelming.
Anyway, I've got some rules to try out, so tomorrow, I'll try them out.</p>
<p>Also, I just disabled all comments on my old blog, because shut up, spambots.</p>
<p>Good night.</p>
Diary 2019-12-252019-12-25T05:00:00-05:002019-12-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-25:/diary-2019-12-25<p class="first last">Turns out I'm not quite ready to just jump in and start trying to do stuff. Maybe tomorrow. Although I am traveling tomorrow...</p>
<p>A little calmer of a day today.
I mostly spent it playing Minecraft, but I also put in some more high-level conlanging work.
I think what's happening there is that I don't quite understand some of the stuff motivating my goals well enough to jump in.
Some of the high-level summaries of "Euroversals" on Wikipedia are pretty abstract, so I've been reading over the original <a class="reference external" href="http://www.anglistik.uni-freiburg.de/seminar/abteilungen/sprachwissenschaft/ls_kortmann/Courses/Kortmann/Variation/index_html/2008-05-27.8724094854">Haspelmath article</a> to get a better idea, for example, of what an "equative" is, and how stuff like "так" and "как" relate to it.</p>
<p>Getting a good idea of what is and isn't typical in languages is interesting.
I kind of want to, once I nail down more details, develop a distant relative language that didn't take on SAE features.
(Although it probably is worth noting that one way I'm maybe kind of cheating to make this more exotic is, if something is common outside of Europe and therefore not a Euroversal, that gives me license to not use it. Even though this doesn't really make sense. So, if I'm not specifically trying to do that, the result might end up having some superficial resemblances to European languages that the first language lacks.)</p>
<p>Good night.</p>
Weekly Roundup 2019-12-242019-12-24T05:00:00-05:002019-12-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-24:/weekly-roundup-2019-12-24<p class="first last">I should stop starting these after 10 PM</p>
<ul class="simple">
<li>Wednesday: I started figuring out what I'd need to do for my current conlanging project.</li>
<li>Thursday: I was super tired for no apparent reason.</li>
<li>Friday: I was super tired for an apparent reason.</li>
<li>Saturday: I made a little progress.</li>
<li>Sunday: I did a bunch of stuff. Some of these entries I did super-late and rushed them out.</li>
<li>Monday: I wrote almost nothing because of early holiday celebrations.</li>
</ul>
<p>Next week, I'm going to try to approach this stuff with a little more discipline.</p>
Diary 2019-12-232019-12-23T05:00:00-05:002019-12-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-23:/diary-2019-12-23<p class="first last">Christmas came early and I got distracted from writing an entry.</p>
<p>Hi.
Still alive.
Mostly played Minecraft.</p>
<p>Good night.</p>
Diary 2019-12-222019-12-22T05:00:00-05:002019-12-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-22:/diary-2019-12-22<p class="first last">Once the big holidays are past, I should try using Pomodoro or something again.</p>
<p>Things I did today:</p>
<ul class="simple">
<li>A bunch of writing</li>
<li>Minecraft</li>
<li>A little bit of work conlanging</li>
<li>Figuring out what I need to design an AI system inspired by the paper on F.E.A.R.</li>
</ul>
<p>I'm not going to say anything about the writing.
I'm doing well enough in Minecraft that I think I can spare the resources to put ridiculous ALLCAPS signs on everything like it's a sixties Batman set (back when they had sets).
On the conlanging front, I just applied the sound change I want to try, to see how it looks.
I would like to come up with some more varied roots to try it with, and also to have something to do this with that makes it easier than just typing stuff manually into a word processor for every conjugation.
For the AI, I think the notes I have are good enough to turn it into a design, but I haven't yet written up a design, and I would like to.</p>
<p>Good night.</p>
Diary 2019-12-212019-12-21T05:00:00-05:002019-12-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-21:/diary-2019-12-21<p class="first last">Took things easy, but made some progress.</p>
<p>I didn't exactly do a ton of work today, but I found some promising sound changes to base stuff on.
The whole endeavor feels somewhat abstract.
I think I'm going to have to just experiment with some possible words and see what comes out.</p>
<p>Nothing more to say right now.</p>
<p>Good night.</p>
Diary 2019-12-202019-12-20T05:00:00-05:002019-12-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-20:/diary-2019-12-20<p class="first last">I know exactly why I was so tired.</p>
<p>We were on the road again today, and as usual, it took a lot out of me, and as usual, I didn't anticipate this or plan for it in any way.</p>
<p>I did get some work done though.
I went over the factored out ECS code from Dennis, ran Mypy over it, fixed some bugs that found, and got the strictness as high as I can manage for now.
It kind of seems like it's still accepting some stuff that it really shouldn't, but I haven't figured out how to express the constraints that would justify accepting my code, so it sort of cancels out.
Sort of.</p>
<p>Hopefully I'll be up for getting more done tomorrow.</p>
<p>Good night.</p>
Diary 2019-12-192019-12-19T05:00:00-05:002019-12-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-19:/diary-2019-12-19<p class="first last">I don't know why I was so tired.</p>
<p>I spent most of today fighting to remain conscious, ended up keyed-up in the afternoon, and now I'm really tired.
I'm putting together more stuff for conlanging.
Short sample sentences and breaking them down into necessary roots.
I'm going to have to spend a day where I'm better-rested than this, coming up with the history of each root.
This is hard work.</p>
<p>And I'm done for now.</p>
<p>Good night.</p>
Diary 2019-12-182019-12-18T05:00:00-05:002019-12-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-18:/diary-2019-12-18<p class="first last">Laying groundwork for my made-up, sort-of-a-joke language.</p>
<p>I still don't quite have a handle on how to do time management in the winter, I think, so I did some quick conlang work in the last hour or so.
I basically just transcribed some of the basic stuff I wrote down.
Moving forward, I'd like to have some sample sentences that hold my interest, so I think my best bet is to make samples for Dabupan instead of The Tongue of Light, and have the samples be of the debates over the reforms.
So, first write stuff up in English so I have some idea of the words I want, figure out back-derivations to the "earliest attested form", determine the meaning of the root at that time, and figure out which sound changes occurred when.</p>
<p>This sounds like it's going to be a lot of much harder work than my usual stuff, so I'll just have to put aside some time every day, I guess, and chip away at it.</p>
<p>Quick timeline thought: Ancient Dabupan is "analytic", Old Dabupan is "agglutinative", Dabupan is "fusional".
I think I'll just copy the lexicon around a bunch until I've got four sections to work with.
That'll be it for tonight, it's pretty late now.</p>
<p>Good night.</p>
Weekly Roundup 2019-12-172019-12-17T05:00:00-05:002019-12-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-17:/weekly-roundup-2019-12-17<p class="first last">What you have to understand is, I made * a lot* of progress on Baba Is You</p>
<ul class="simple">
<li>Wednesday: I got unstuck regarding the Ink issue I filed.</li>
<li>Thursday: I realized that the C# design uses rollback all the time.</li>
<li>Friday: I did kind of a grab bag of tasks. And things that weren't really tasks.</li>
<li>Saturday: I did some design work for the Ink port, but I haven't had the focus yet to check it and put it into practice.</li>
<li>Sunday: I posted.</li>
<li>Monday: I got distracted from everything else I've been doing to try turning part of the Dennis code into its own library.</li>
</ul>
<p>Next week, I'd be up for some more conlanging, reviewing the current slice of Ink Py design, or fleshing out ideas inspired by the paper on F.E.A.R.'s AI.</p>
Diary 2019-12-162019-12-16T05:00:00-05:002019-12-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-16:/diary-2019-12-16<p class="first last">Taken by a fey mood!</p>
<p>I reread a <a class="reference external" href="https://alumni.media.mit.edu/~jorkin/gdc2006_orkin_jeff_fear.pdf">GDC paper from 2006</a> on procedural NPC AI, and that gave me the urge to mess around with that general idea.
I decided, based on gut feeling mostly, that the first thing I wanted to do for this was to port out and update the <abbr title="Entity Component System">ECS</abbr> engine from <a class="reference external" href="https://mwchase.neocities.org/category/dennis">Dennis</a>.</p>
<p>Getting the code to a state where I think it should work took most of the day.
I'm not exactly sure how I want to progress once I have it in a working state (with tests, typechecking, and published on PyPI).
I can either try to put together a rudimentary world model, or port other bits of Dennis piecemeal until I've got enough to put it all together into "a game", then hack on top of that.</p>
<p>I don't have anywhere to go from that, so I might as well mention the changes I made.
Looking through the Ink codebase has me kind of soured on the concept of "zero-argument constructors for objects that get all of their state injected in deserialization", so I redid the constructor to handle much of the logic that is done in the deserialization routines in Dennis, and also added a helper to do most of the work needed for serialization.
One of the weird janky bits of Dennis's implementation is that the component fields were wrapped in a descriptor that contained a tiny bit a metadata, and all access to the components was done by dynamically generating attribute names to use with getattr.
Essentially, it was a layer of syntactic sugar that wasn't actually really visible outside the module where it was defined.
This doesn't really make sense.
Since I kept the idea of a "Component" base marker class, I just had it detect when class attributes were subclasses of the marker class, and assemble a dictionary at instantiation time.
This approach might end up being harder to typecheck, but I'm pretty sure that the version in Dennis now only typechecks because all of the getattr stuff is implicitly tossing out <tt class="docutils literal">Any</tt> values that then get coerced to the expected type implicitly.</p>
<p>Okay, it's getting late.
I have to call this now.</p>
<p>Good night.</p>
Diary 2019-12-152019-12-15T05:00:00-05:002019-12-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-15:/diary-2019-12-15<p class="first last">Lowest-effort post without being sick, I think.</p>
<p>Oops.
I did a bunch of things today that didn't lend themselves to blog posts, and I don't want to reach for anything now, so, I'm just posting this to post something.</p>
<p>Good night.</p>
Ink-Py 2019-12-142019-12-14T05:00:00-05:002019-12-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-14:/ink-py-2019-12-14<p class="first last">Short entry because head hurty.</p>
<p>I worked a little bit on Ink today.
I <em>think</em> I've established that my implementation of the function I'm investigating now will be simpler, but I'm not totally confident.
Unfortunately, I'm really not up to looking at screens any more today, so I have to call this now.</p>
<p>Good night.</p>
Ink-Py 2019-12-132019-12-13T05:00:00-05:002019-12-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-13:/ink-py-2019-12-13<p class="first last">I'm skipping over a lot of Ink's caching logic, so it's probably going to chug once it actually, like, works.</p>
<p>Worked on a bunch of stuff today.
Discussed my open PR/feature request against Poetry.
Started rewriting the step code in Ink Py to be a bit more like the source, which is why this post is in the category it's in.
I made a solid start there, but I need to take some time to be careful about how I'm doing this, because it's pretty confusing.
Anyway, I started working on a reference for The Tongue of Light, and got <a class="reference external" href="https://im-in.space/@mwchase/103298235112936675">distracted by bad kerning</a>.
Then, when I wanted to be writing this entry, I got <a class="reference external" href="https://vastnope.wordpress.com/2017/04/21/this-is-a-very-wikipedia-sentence/">distracted by looking up who made weird edits to Wikipedia, and commented about it on my old blog for some reason</a>.</p>
<p>I also played a bunch of Baba is You, which remains a very confusing game.</p>
<p>Good night.</p>
Ink-Py 2019-12-122019-12-12T05:00:00-05:002019-12-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-12:/ink-py-2019-12-12<p class="first last">The C# design walks out of the shadows saying "We're not so different, you and I" and I bolt from the room.</p>
<p>Looking at the way Ink figures out how far to advance in outputting a line, I see that I've been thinking about it all wrong, because I wasn't taking lookahead into account.
Little bit of tunnel vision on my part.
My experiences with rollback in an imperative context, when I'm the one responsible for implementing it, have been kind of a nightmare.
But, all I really need to know is that it's on the table, and then I can sketch out the logic, and clean up the functions that I put together kind of wrong.
Looks like some of implementing this will involve putting new fields on the state to make it a linked list thing.
Oh well.</p>
<p>One thing that's kind of bothered me about this porting effort is, their C# feels really verbose relative to my Python.
I have to assume the fact that I'm not porting comments plays a role, but even still, it feels like I'm often teasing out a simpler structure.</p>
<p>Regardless of whether my opinions have anything to do with reality, I've just got to push on with this over the next few days.</p>
<p>Good night.</p>
Ink-Py 2019-12-112019-12-11T05:00:00-05:002019-12-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-11:/ink-py-2019-12-11<p class="first last">Getting extremely close, trust me.</p>
<p>After some minor back-and-forth on the bug I filed (the bug was definitely a bug, and my proposed fix is technically correct and, so far as we know, harmless, but the actual impact of the bug is low, and the question is, is there any way at all to trigger it against extant code? My answer is a solid maybe.) I made a judgment call and moved forward a little further with the porting effort.</p>
<p>I'm going to figure out what comes next (basically, I need to refresh my memory about where the logic is that handles string concatenation for output purposes), and then get to bed.</p>
<p>Good night.</p>
Weekly Roundup 2019-12-102019-12-10T05:00:00-05:002019-12-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-10:/weekly-roundup-2019-12-10<p class="first last">Excellent correlation as usual between a stressful week and not having much to write about.</p>
<ul class="simple">
<li>Wednesday: I thought about what I'd like to accomplish in terms of conlangs.</li>
<li>Thursday: I speculated about what kind of conlanging techniques would make sense for me and what I want to accomplish.</li>
<li>Friday: My laptop did weird stuff and I didn't do much.</li>
<li>Saturday: It was an eventful day, but you don't get to hear about the events.</li>
<li>Sunday: I looked at Ink just enough to go "here's a new thing that freaks me out just by existing"</li>
<li>Monday: I decided to go back to taking a break from Ink-Py.</li>
</ul>
<p>Next week, I'm going to try to put together a lexicon for The Tongue of Light in, I don't know, LibreOffice or something.</p>
Diary 2019-12-092019-12-09T05:00:00-05:002019-12-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-09:/diary-2019-12-09<p class="first last">Sometimes coding means looking at something that is clearly wrong, but the overall system works, and getting really worried.</p>
<p>I was doing more taking-things-easy today, so I don't have much to write about.
I was looking at Ink, and I'm kind of apprehensive about porting <tt class="docutils literal">TrySplittingHeadTailWhitespace</tt> until I get feedback on the bug I filed.
Basically, it's not working as intended, but it's not obvious to me whether there's some compensating factor elsewhere in the code, or if this individual bit of design is wrong.
If I want to make progress on this stuff, I might have to see about running the tests and attempting to fix some of this myself and see what breaks, if anything.</p>
<p>We'll see how things shake out tomorrow.
I'll try to figure out a good flow for working on conlang stuff, because I don't have as much license to complain about other people's code or tooling with that.</p>
<p>Good night.</p>
Ink-Py 2019-12-082019-12-08T05:00:00-05:002019-12-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-08:/ink-py-2019-12-08<p class="first last">Usually when I file bugs I try to lay out the expected behavior. Not so with Ink.</p>
<p>I didn't do too much today, mostly took it easy, but I did look over the Ink code some, file yet another bug based on code inspection, and port some code over.</p>
<p>I don't have any definite idea of how much effort/progress I'm going to have here in the coming days.
I guess I'm kind of viewing this as "this might be cool to have for messing with Dennis", but I don't want to work with Dennis until I have a 1.0-worthy release of Structured Data, and I don't want to do too much more there until Read the Docs has support for Python 3.8, which, according to the configuration documentation, it doesn't have yet.
And I have no interest in trying to expedite that when there's already projects beta-testing it.
I could try to get into the beta, but I don't feel like it.</p>
<p>I think maybe sometime I should experiment with different formats for this kind of "daily code update" thing.
For now, I'm going to curl up with my e-reader.</p>
<p>Good night.</p>
Diary 2019-12-072019-12-07T05:00:00-05:002019-12-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-07:/diary-2019-12-07<p class="first last">I think I've been staring at this for like ten minutes trying to figure out "a bunch of stuff happened, but I don't want to put any details in a blog post".</p>
<p>Today was an extremely eventful day that left me kind of wiped out.
I'm not going to go into any more detail, or try to get anything more done with my projects.</p>
<p>I did sketch some rough ideas about diagramming Dabupan/The Tongue of Light, but I think I should work on creating glosses for example sentences before I put too much effort into nailing things down at an abstract level.</p>
<p>I'll try to pick up the pace a bit tomorrow, depending on how things are then.</p>
<p>Good night.</p>
Diary 2019-12-062019-12-06T05:00:00-05:002019-12-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-06:/diary-2019-12-06<p class="first last">Something's up with the rendering on my laptop, sometimes.</p>
<p>My laptop was kind of unreliable today, and then we traveled after dinner, so I didn't have a chance to do much.</p>
<p>I'm thinking about declension in The Tongue of Light and its ancestral forms.
I've got some ideas, but I'm going to have to draft some actual words to figure out what works, I think.</p>
<p>Not up for thinking any more; I'll try to make up for it tomorrow if I can.</p>
<p>Good night.</p>
Diary 2019-12-052019-12-05T05:00:00-05:002019-12-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-05:/diary-2019-12-05<p class="first last">Setting up some folders to hold this stuff...</p>
<p>I was kind of worn out today, and I'm not sure why.
In any case, I did some work coming up with historical details for the conlang I've been talking about, which I'm going to give the working title of The Tongue of Light.
I'm basically trying to focus on the particular form that I want to work with, but occasionally noticing that it's easiest to think about certain things I want in terms of a history.</p>
<p>Now, in the past, when I've seen advocacy for using proto-languages in conlanging, I was usually interpreting that like "get the proto-language all set, then apply changes, and see where it ends up".
That seems to me like it'd work in the context of following the story of a nation, but I never really liked trying to do that.
For this project, where the idea is kind of to have a fictional moment in time where the language has a particular form, the idea of taking a more ad-hoc approach seems more appealing.
Like "Okay, this bit is kind of irregular, so it ought to be derived from a more intuitive paradigm in the past, like so".
I should probably figure out how best to represent a timeline of changes before I go too far, because it would be kind of awkward if I ended up needing to have a bunch of essentially unrelated changes happening all at once somehow.</p>
<p>Okay, that's enough writing for now.</p>
<p>Good night.</p>
Diary 2019-12-042019-12-04T05:00:00-05:002019-12-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-04:/diary-2019-12-04<p class="first last">Trying to get my bearings, and also I don't have much to say about what I've done.</p>
<p>It seems I'm still taking a break from Ink-Py, so today I worked on conlang stuff while being cooped up inside because of the snow.</p>
<p>I don't have much specifically to show for the SAE idea, though I'm sketching stuff out for it.
I think I'll make this a short entry and just mention the conlangs I'd like to make progress on.</p>
<ul class="simple">
<li>There's the SAE-inspired one. I feel like the sketches so far are the most thought-out grammar I've done.</li>
<li>For the Ironsworn solo campaign, I'd like to have a naming language that has: consonant-heavy codas, syllabic sonorants, gemination, and a runic abugida. To get a better idea of how I want to go with it, I should study Scandinavian languages.</li>
<li>For the Adventure Crafter/Mythic/Risus solo campaign, I've got a few languages I want to work out. The language of the less-ancient ancients, the language of the nation that used to occupy the desert, the language of the protagonist and the current majority population, the language of a nation that borders both of them, and maybe a few other miscellaneous ones.</li>
</ul>
<p>Looking at the amount of stuff that I'm thinking "I'd like to get to this, but I'm currently not", I think I might be a little burnt out.
I'm going to have to take it easy, which shouldn't be too hard.
Aside from the fact that we've got some more travel in the near future, and right now everything is <em>so cold</em>.</p>
<p>Good night.</p>
Weekly Roundup 2019-12-032019-12-03T05:00:00-05:002019-12-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-03:/weekly-roundup-2019-12-03<p class="first last">It would have been cool if I'd consciously decided to take a break, but it's fine, probably.</p>
<ul class="simple">
<li>Wednesday: I got most of the auxiliary stuff for the Ink Python VM working, though some of it isn't working quite the way I think it should be.</li>
<li>Thursday: I ported a test, and it failed. I tried to get it working.</li>
<li>Friday: I figured out that I need ("need") to make design changes to Ink as I port.</li>
<li>Saturday: I made the changes.</li>
<li>Sunday: I thought I might have gotten far enough for the test to pass, but I did not. I figured out what needed to happen next.</li>
<li>Monday: Instead, I started working on a conlang that may or may not be a clever idea, I don't seem to be able to decide.</li>
</ul>
<p>Next week, some mix of more conlanging, getting back to Ink, and <em>hopefully</em> Ironsworn.</p>
Diary 2019-12-022019-12-02T05:00:00-05:002019-12-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-02:/diary-2019-12-02<p class="first last">No coding today, I guess.</p>
<p>So I don't really remember what I did today besides go shopping, and like an hour ago start writing up ideas for a conlang that is basically a really subtle troll.
The concept for it started when I heard about the concept of <a class="reference external" href="https://en.wikipedia.org/wiki/Standard_Average_European">Standard Average European</a>.
Because English is part of the sprachbund, it seems to me like the "Euroversals" could be useful to English-speaking conlangers who don't want their language to sound particularly "European", or to someone working on an auxiliary language.</p>
<p>I had the idea of "what if I leaned into this as hard as possible, when it comes to stuff that people mentioned, but I take whatever approach I feel like for everything that isn't specifically mentioned (or that I really don't feel like having)"</p>
<p>So far, the result is looking like a mix of "that is exactly what English does", "that's what some languages that aren't English do", and "I only assume there's a natlang that does that because I'm not <em>that</em> creative", which is probably the best that can be hoped for, given the constraints I gave myself.</p>
<p>Anyway, I absolutely need to go to bed now.</p>
<p>Good night.</p>
Ink-Py 2019-12-012019-12-01T05:00:00-05:002019-12-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-12-01:/ink-py-2019-12-01<p class="first last">The test actually went through to completion before failing a few times today! Wow!</p>
<p>No real surprises working through Ink Py. I still don't have the test passing, but it's progressing further.
I think it might actually almost pass if I can get through this command implementation, but maybe not.</p>
<p>Answer from the future: Nope!
The next step is to actually format the output for display, which is something that I tried to factor out of the traversal logic, and into a separate presentation step (good, I think), which I haven't yet tried to implement (less good).</p>
<p>I know every entry on this has been like, here's a new thing that doesn't work, but formerly, absolutely none of this worked, and after each entry I got a bit more working.</p>
<p>Anyway, once I have a test passing, I'm going to look into refactoring stuff because my <tt class="docutils literal">__init__.py</tt> is a giant horrifying grab-bag.
Then, I might consider putting the still highly-incomplete code up online to show off.
In spite of my insistence on making the immutability enforced at runtime, and some overly-clever concepts, there are some things I'm noticing that I think could make the C# Ink leaner and better-organized.
(For one, some of my Path implementation corresponds to parts of the InkObject implementation, because the function in question basically just manipulates Paths.
For another, I don't currently see how the <tt class="docutils literal">_startOfRoot</tt> Pointer ever wouldn't have a null container.
And also there's some internal functions that never get called.)</p>
<p>In any case, now I know what to try to implement tomorrow: coercing internally generated text to nicely rendering text.
Hmm.
Oh dear.
My <tt class="docutils literal">push_to_output_stream()</tt> function isn't nearly gnarly enough.
I guess that's the first thing to address.</p>
<p>Good night.</p>
Ink-Py 2019-11-302019-11-30T05:00:00-05:002019-11-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-30:/ink-py-2019-11-30<p class="first last">Adequate progress!</p>
<p>Grinding away at this some more.
I've ditched the Pointer type, and now I'm working on native function calls.
There's probably going to be some awkwardness there because I haven't really implemented the boxed value types yet (I've got basic implementations of some of them), but the next priority to getting them set up is getting the "evaluation stack" implemented.</p>
<p>I'm not sure I have much to say on that.
I basically just did what I described yesterday, and that stuff seems to work.</p>
<p>And maybe I can't think of anything to say because it's kind of hard to focus when I hang out with my in-laws for extended periods.
I'll be happy to get back home tomorrow.</p>
<p>Good night.</p>
Ink-Py 2019-11-292019-11-29T05:00:00-05:002019-11-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-29:/ink-py-2019-11-29<p class="first last">This is a really big initial hump, but I'm confident.</p>
<p>I didn't work on this much today, because Thanksgiving, but I understand the C# codebase for Ink enough to know that I'm going to need to make some obnoxious changes if I want to keep up my current design sensibilities.</p>
<p>Basically, I'm trying to work solely with immutable data, because that's easier for me to think about, but that means no cyclic references, which means no parent references, which means anything that uses them needs a rewrite.
In practical terms, I believe this means I need to ditch the concept of a "Pointer", and replace all of the Pointers in the ported codebase so far with AbsolutePaths.
And possibly references to the root.</p>
<p>"Max, aren't the problems you're running into with this approach essentially self-inflicted?"</p>
<p>I'm attempting this port because I want to, so "because I want to do it" is a valid reason to do anything as part of the effort.</p>
<p>Anyway, I could make fancy changes to the Container layout to try to "optimize" stuff, but my best bet for getting anywhere with this is to focus on making the code as simple as possible.</p>
<p>And I can't make things simple without a clear head, so I've got to call this now.</p>
<p>Good night.</p>
Ink-Py 2019-11-282019-11-28T05:00:00-05:002019-11-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-28:/ink-py-2019-11-28<p class="first last">A quick entry because I was just iterating on a single test for a while.</p>
<p>The first test I ported now gets more done before it fails, but I'm still working out how things actually get initialized.</p>
<p>I'm in the middle of working out how the initial StoryState gets assembled, and I'm pretty confident that <tt class="docutils literal">StoryState.rootContentContainer</tt> will always be <tt class="docutils literal">null</tt>.
I've figured out, I think, what happens to get the pointer to have the correct value, and I'll try to trace all of the relevant logic later.</p>
<p>I'm too sleepy now.</p>
<p>Good night.</p>
Ink-Py 2019-11-272019-11-27T05:00:00-05:002019-11-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-27:/ink-py-2019-11-27<p class="first last">Computers, everyone...</p>
<p>Ink-Py status: I've got documentation building, but not in, like, a useful way.
I've shoved everything I can think of into the noxfile.
Right now I've got a distinct step for generating all compiled story files up front, which is... kind of slow.
Getting the coverage data to generate correctly appears to require a bunch of stuff that it really shouldn't.</p>
<p>I've added a test, but since I just ported the test straight over from the C# codebase, getting it to pass requires either implementing a whole bunch of functionality, or, like, taking the lazy way out like I guess TDD says I'm supposed to.
Honestly, I'd rather just port stuff over as much as possible and see what that gets me.
My hope is that getting one test to pass will take most of the effort, since this one test touches a lot of functionality.</p>
<p>I spent most of the day trying and failing to trim down the coverage configuration, so I can't get any further tonight on trying to make the new test pass.
We'll see what I have time for tomorrow.</p>
<p>Good night.</p>
Weekly Roundup 2019-11-262019-11-26T05:00:00-05:002019-11-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-26:/weekly-roundup-2019-11-26<p class="first last">Fine week, rough days.</p>
<ul class="simple">
<li>Wednesday: I was very tired because of meetings, but I put in some work on Poetry.</li>
<li>Thursday: I put in some more work on Poetry, and also worked on my Ironsworn solo campaign a little.</li>
<li>Friday: I got the PR against Poetry in. A little more Ironsworn, and we watched more goofy horror movies.</li>
<li>Saturday: I started trying to port Ink to Python again, and didn't make it too far. I did, however, figure out which of my Sublime Text plugins was "sabotaging" my Python files.</li>
<li>Sunday: I tried to take a different approach to porting Ink to Python.</li>
<li>Monday: I made a new category for trying to port Ink to Python. This would be my third attempt in as many days. ¯\_(ツ)_/¯</li>
</ul>
<p>Today I had a late lunch, and it <em>wrecked me</em>.
I came home, collapsed in bed for like an hour and a half, and woke up really disoriented.
Really glad I'm theoretically able to take things easy for the next week or so.</p>
<p>Next week, I'm going to work on porting Ink's tests to the Python interface I'm prototyping, and also I'd like to try <em>actually starting the Ironsworn campaign</em>.</p>
Ink-Py 2019-11-252019-11-25T05:00:00-05:002019-11-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-25:/ink-py-2019-11-25<p class="first last">I tried to come up with a pun on "ink" and "snakes", and I got nothing.</p>
<p>Things are a little out-of-control right now, but I'm trying to stop it from getting to me.</p>
<p>I'm starting a new category today because I seem to be going in on this whole "Hey, let's try porting Ink to Python again" idea, and that's fine with me.</p>
<p>I've tried a few times in the past, and my efforts have mostly just led to bug reports and PRs against the C# version.
(I actually forgot about the PRs, and was really confused for a little bit, seeing the "Contributor" badge on GitHub.)</p>
<p>What tripped me up in previous attempts was not, as other people's attempts might have it, that Python just isn't practical for implementing a VM like Ink.
I would argue that PyPy stands as a counter-example to that sentiment.</p>
<p>My big issues adapting the C# codebase centered around non-local reasoning, circular references, dead code, and a lack of familiarity/ease on my part with some C# features.</p>
<p>For the last point, I just want to understand things well enough to come up with an equivalent in Python.</p>
<p>The other points can be summarized as: I don't know whether a given section of code is actually used, I don't know how many times a given field is set and with what range of values, and some pairs of objects are so tightly coupled that it's not clear to me which one of them "should" have a given bit of functionality.</p>
<p>That probably seemed mean, but it's the truth.
I really was looking at some functions thinking "Okay, what on earth is the equivalent of this in Python? Like, I can't translate this directly for all possible ways this function could be called, so I'll have to specialize it for potentially each of the call sites, of which there are... none. Well, that was a waste of time."</p>
<p>So, the fundamental thing I was doing wrong in my previous attempts was, I was trying to directly translate an internal bit of code before I had the context on how it was used.</p>
<p>Now, some people advocating for particular practices to improve software quality really like tests.
"Write your tests first!" they say.
"Tests are the most important code, because you can use them to recreate correct product code, but you can't derive correct tests from your product code!"
I haven't had the guts to take them up on the second assertion, but it looks like my best bet for getting this project off the ground.
Focus on designing an interface that I can do local reasoning about, then port the tests to handle that interface.</p>
<p>Here's where I am on that currently:</p>
<ul class="simple">
<li>I've got a file full of stub functions with type signatures that are approximately correct. I may tweak them depending on how I write the convenience functions.</li>
<li>I copied 100+ Ink snippets out of the test suite for Ink. I've got some steps put together that should handle converting the snippts to story json, but I haven't ported the tests over yet.</li>
<li>I've created a Poetry project for this, and got it building. The dependencies still need to be adjusted, and I haven't written most of the noxfile, but this step is something like an hour of fiddling around, tops.</li>
<li>I'm going to need to add coverage, in particular.</li>
</ul>
<p>Hopefully in a week or so, I'll be able to put up the very, very early prototype code for public consumption.
Nothing else to be done right now, though.</p>
<p>Good night.</p>
Diary 2019-11-242019-11-24T05:00:00-05:002019-11-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-24:/diary-2019-11-24<p class="first last">Let's try porting from the outside in.</p>
<p>Today we watched <em>Them!</em>, which is some pretty good 50s schlock.
Maybe we should see what else is out there in terms of movies named after pronouns.</p>
<p>Anyway, I later tried some more to adapt Ink's code, and I'm now heavily suspecting that I'm going to need to try prototyping something that follows the very high-level interface, and work with that a bit until it makes sense to me, because I don't really use programming languages that treat field access like C# does.</p>
<p>I'll try and sketch out some of the ideas I have here.</p>
<p>At a very abstract level, a Story can be serialized or deserialized.
It can be in a state where it can produce lines of text, or choices, or it can be ready to follow a choice.</p>
<p>Now, following a choice will add lines of text.
(Last I checked, in the reference implementation, none of the text is saved, so procedural text gets regenerated.
I'll check that now.
Yep, still a footgun.)</p>
<p>I'm going to sketch some of this on paper.</p>
<p>Okay, I've got a very informal state machine diagram that represents an extremely opinionated system without many external capabilities.
Seems like a good target for prototyping.</p>
<p>And now I've got a separate file for prototyping this stuff, and it's got some code in it.</p>
<p>I guess the next thing to work on is the serialization and deserialization, because it's not really an implementation of Ink if it can't work with the save format.</p>
<p>Although...
I also need to change around the interface to reflect the different responsibilities I'm giving different parts of the system.</p>
<p>Good night.</p>
Diary 2019-11-232019-11-23T05:00:00-05:002019-11-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-23:/diary-2019-11-23<p class="first last">Technology!</p>
<p>Tonight, I was mostly messing with trying to port the Ink runtime to Python.
I'm going the route of doing heavy refactorings as I go, which is a definite gamble, but the source code in this case is more likely to be in a valid state than previous times I've attempted that.</p>
<p>Unfortunately, I got myself seriously wound up because Sublime Text was being Helpful™ again.
I eventually determined that the behavior that was bothering me was the isort plugin working as designed, so, um, I would not recommend the isort plugin?
It will ignore your project settings, sometimes, I think?
Basically it was a huge pain and I'm glad I figured out what was sabotaging my files.</p>
<p>Hopefully from now on everything should be more predictable, but that just, really sucked for a while there.</p>
<p>I can't be up much longer.</p>
<p>Good night.</p>
Diary 2019-11-222019-11-22T05:00:00-05:002019-11-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-22:/diary-2019-11-22<p class="first last">Fingers crossed.</p>
<p>I put in the PR against Poetry.
We'll see how that goes.
Hopefully there's some feedback soon.</p>
<p>I did some testing against Structured Data, and discovered that my interpretation of some of Mypy's internal documentation was incorrect, which is a pain.
I saw the following and thought "I can use this to make an invariant protocol for matching types!" and that doesn't seem to be true.
"We may encounter expressions whose values are specific classes; those are represented as callables (possibly overloaded) corresponding to the class's constructor's signature and returning an instance of that class. The difference with Type[C] is that those callables always represent the exact class given as the return type"
RIP.</p>
<p>I fleshed things out a tiny bit with Ironsworn.
I'm still trying to wrap my head around the relationship between the story I want to tell and the vows that would go into it.</p>
<p>Besides all of that, today we watched Children of the Corn II, which...
Okay, it's a sequel to a supernatural horror movie, and you may ask "Does it ramp up the supernatural weirdness, or does it try to give a scientific explanation for everything?"
The answer is yes.
That was a weird movie.</p>
<p>Good night.</p>
Diary 2019-11-212019-11-21T05:00:00-05:002019-11-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-21:/diary-2019-11-21<p class="first last">Hopefully the PR will at least serve as a rough guideline for what the feature <em>should</em> do.</p>
<p>I spent a bunch of time squinting at Poetry's source code, and now have a prototype that shouldn't break in the manner that the previous prototypes would have broken.</p>
<p>After a lot of effort, I've figured out how to write some basic tests.
As I compose this entry, I'm rerunning the test suite with a new test.
If it doesn't pass, I'll be very sad and confused.</p>
<p>Update: it didn't pass, but the reason why is clear enough that I'm just mildly unhappy.
I fixed the problem, and if it still fails, then I'll be annoyed and confused and such.</p>
<p>Hey, it passed.
That's one test down, at least two more to go.</p>
<p>The basic test I did was that a package with only runtime dependencies specified can opt into not installing anything.
Let's list some more cases:</p>
<ul class="simple">
<li>Only development dependencies, should all be installed</li>
<li>Mix of independent dependencies, only develop should be installed</li>
<li>Incompatible dependencies, should successfully install develop</li>
</ul>
<p>And complementary tests against the mason component.
I also note that I missed adding the field's default value to the "complete" fixture.
I'll get that now.</p>
<p>Besides Poetry, I made some progress on my ongoing session 0 of solo Ironsworn.
I'm right now trying to figure out the right balance of things to put in my starting vows.</p>
<p>The big thing I want to figure out with Ironsworn is, how do I want to track the character sheet stuff?
ANM has the character sheets (which are tiny) stuffed into a Lua file next to the plotlines.
I could probably do something similar easily enough for Ironsworn.</p>
<p>Okay, I've started on a textual character sheet.
I'm going to have to go over the rules some to get the details of some sections right, but it looks basically fine.</p>
<p>And that's enough for now.</p>
<p>Good night.</p>
Diary 2019-11-202019-11-20T05:00:00-05:002019-11-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-20:/diary-2019-11-20<p class="first last">It's going to be kind of a pain to chase all of the data dependencies, I suspect.</p>
<p>I was in meetings for over three hours today.
My constitution can't handle that.</p>
<p>Anyway, I started trying to really figure out how to work with Poetry's existing test libraries.
I basically discovered that my first attempt at implementing "dev-mode" was probably pretty wrong.
The interfaces and documentation, I haven't seen any reason to doubt them yet, but the changes I made to the core are likely to interact poorly with *checks notes* nearly everything.</p>
<p>With that in mind, I'm going to have to try again, because there's just no way this first attempt is right.
No time for that now, because I'm tired.</p>
<p>Good night.</p>
Weekly Roundup 2019-11-192019-11-19T05:00:00-05:002019-11-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-19:/weekly-roundup-2019-11-19<p class="first last">I got a little distracted, but eh.</p>
<ul class="simple">
<li>Wednesday: I started working on a solo Ironsworn game.</li>
<li>Thursday: I'm less stressed, and I'm working on PRs to Poetry.</li>
<li>Friday: One of the PRs proved unnecessary for reasons that I honestly still don't get.</li>
<li>Saturday: I waited too long to write the entry.</li>
<li>Sunday: I wrote code, but not tests.</li>
<li>Monday: I wrote documentation, but not tests.</li>
</ul>
<p>Next week, I had better write some tests.
Also, I've been messing with porting Ink to Python (I tried this a while ago, and mostly just filed bugs against the reference implementation).
Maybe I'll do something there, especially once I think I'm done with the Poetry PR.</p>
Diary 2019-11-182019-11-18T05:00:00-05:002019-11-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-18:/diary-2019-11-18<p class="first last">Just a whole bunch of scribbling that doesn't go neatly into a blog post.</p>
<p>All right, here's how things went today: I wrote documentation for the changes I made in my PR to Poetry, I still didn't write tests because I need to look over the existing tests to figure out what they even do, and I started a completely new writing project that I won't talk about in any further detail.</p>
<p>Also, I just now, like an hour ago, started trying to refresh my memory on music theory in a more structured way.</p>
<p>It'd be cool if I had a longer entry, but I was once again just mostly taking it easy today.</p>
<p>Good night.</p>
Diary 2019-11-172019-11-17T05:00:00-05:002019-11-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-17:/diary-2019-11-17<p class="first last">I tend to think at length about things, then do the actual thing really quickly.</p>
<p>I've got a prototype of the changes I was requesting to Poetry for the feature request that wasn't just a case of "Oh, you need to actually tell it to do the thing you thought you were telling it to do."
(I'm honestly not sure why adding the wildcards makes it work differently.)
Anyway, prototype of the config changes.
It's going to need some tests:</p>
<ul class="simple">
<li>That everything that doesn't involve using the installed project still works when the option is enabled.</li>
<li>That Poetry still works as a PEP 518 build system when the option is enabled.</li>
<li>That dev and runtime dependencies are allowed to conflict when the option is enabled.</li>
</ul>
<p>That's the obvious stuff.
This wasn't a huge change, so hopefully it doesn't have non-trivial ramifications.</p>
<p>Hm.</p>
<p>I'm not sure what the best way is to inject the setting.
That's what I'll have to look into next.</p>
<p>I'd like to try to get this over with, and make some progress on the various writing projects that I'm juggling.</p>
<p>Good night.</p>
Diary 2019-11-162019-11-16T05:00:00-05:002019-11-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-16:/diary-2019-11-16<p class="first last">Taking it easy, but also staying up way too late...</p>
<p>So, I got some feedback on one of the Poetry issues I filed.
As I mentioned yesterday, it's basically that include paths in Poetry have some (to me) weird levels or syntax, <em>or</em> the thing that I thought was the obvious way to use them doesn't work.
I mean, it doesn't always work like that, but maybe it always doesn't work like that?</p>
<p>So, all that's left is to start messing with the whole "install as little as possible idea".</p>
<p>I got distracted from writing this, so I can't write much more.
Oh well.</p>
<p>Good night.</p>
Diary 2019-11-152019-11-15T05:00:00-05:002019-11-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-15:/diary-2019-11-15<p class="first last">Sometimes it turns out that what I want is basically magic...</p>
<p>Spitballing the improvements I want made to Poetry...</p>
<p>For the dev-only concept, there needs to be some kind of configuration option added, and I think it needs to be read in the Installer, and it'll do something like <tt class="docutils literal">root = root.clone()</tt> and then <tt class="docutils literal">del <span class="pre">root.requires[:]</span></tt>.
I'm not sure how many ways there are to get at logic that needs to take this into account.</p>
<p>For the vcs exclude override concept, there are a few ways to go, but I think the lowest-friction is to remove generated "exclude" entries if there is an <em>exact match</em> in "include".
Okay, this actually looks really painful, because the current code doesn't engage with the ignore file from the vcs directly; <em>all it gets</em> is a concrete list of ignored files.
The easiest way is probably some kind of "no-seed" option that just messes with the beginning of <tt class="docutils literal">find_excluded_files</tt>.</p>
<p>I went elsewhere and rubber-ducked the issues here in more detail, and came to the conclusion that it's probably easier to just roll my own tool.
Very slightly probably.
I'm not going to do <em>that</em> now, so I'm going to settle for making some more activity on the issues.
I will, instead, try to implement the solutions I came up with and posted in the bug comments.
Just, not right now.
Tomorrow.</p>
<p>Good night.</p>
<p>ETA: Turns out I just wasn't specifying the include paths <em>hard enough</em>, so that leaves just one bug to put in a PR for at some point.</p>
Diary 2019-11-142019-11-14T05:00:00-05:002019-11-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-14:/diary-2019-11-14<p class="first last">No word yet on whether these features fit the vision for Poetry ¯\_(ツ)_/¯</p>
<p>I think I'm doing a little better managing my stress; I made some terrible jokes earlier today that I think indicate that I'm doing well enough to come up with them.</p>
<p>Anyway, making a little progress with Ironsworn.
I've decided that my character is focused on wits; I haven't picked out the other stats.
He has a boyfriend, and everyone has anime hair.
I don't know if some kind of live feed of my priorities here would make sense to anyone else, but hey, solo play.</p>
<p>Not much else to report.
There are some feature requests I filed against Poetry that I'm going to try to put in PRs for to see if that gets forward motion on them.
First I need to go through the basic checklist of setting up the repo and running the tests.
Maybe I'll get that started in the next few days, maybe not.
Let's see... looks like both PRs would be based off the <tt class="docutils literal">develop</tt> branch.
Both are focused around adding configuration options, or at least changing how the configuration is interpreted.
And that's all I want to think about for now, because I'm tired.</p>
<p>Good night.</p>
Diary 2019-11-132019-11-13T05:00:00-05:002019-11-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-13:/diary-2019-11-13<p class="first last">"No, I can't keep watching this movie, I'll turn stupid!" "Okay, but, that is what we do."</p>
<p>On the Ironsworn front, I've got the truths of the setting chosen.
For this game, I'll be playing in a version of the Ironlands that leans pretty heavily on the angle of "advanced civilizations brought low by a magical apocalypse" angle, in which a lot of the enemies will be empowered by corrupted artifacts the Ironlanders accidentally brought with them.</p>
<p>I didn't work on it much tonight because we watched A Sound of Thunder, which was just... so much nonsense.</p>
<p>I'll try to get all the materials to actually play together tomorrow.
I'll have to see if I feel like making specialized roller functions like I have for Mythic in the past, or just following flowcharts like I am for Mythic in my other writing project.</p>
<p>I don't have anything to report on the Ink front; I'll think about it after I post this, and see if I come up with any prototypes.</p>
<p>Good night.</p>
Weekly Roundup 2019-11-122019-11-12T05:00:00-05:002019-11-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-12:/weekly-roundup-2019-11-12<p class="first last">I continue to be amazed at the stuff that I did "only" six days ago. What is a sense of time?</p>
<ul class="simple">
<li>Wednesday: I finally psyched myself up to work on "structure types". This is basically a way to represent the types that go into the matches that make it possible to Actually Do Things with Structured Data, so they're kind of a big deal for getting type analysis support at some point.</li>
<li>Thursday: I got Structured Data much better typed, although there's a serious issue that I still haven't addressed.</li>
<li>Friday: I finished working on Structured Data, and resolved to take another break, then eventually try to do the plugin.</li>
<li>Saturday: I dealt with a whole big light-sensitive thing.</li>
<li>Sunday: I realized it was unresolved stress.</li>
<li>Monday: I resolved some of the stress.</li>
</ul>
<p>Next week, I'm going to try working on some new projects.
Maybe get back to some of the others later.</p>
Diary 2019-11-112019-11-11T05:00:00-05:002019-11-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-11:/diary-2019-11-11<p class="first last">Doing better...</p>
<p>I took care of a bunch of things that were bothering me, so now I'm a little calmer.</p>
<p>That kind of took all day, though, so now I'm just planning ahead.
I'm thinking I'd like to try to do a solo run of <a class="reference external" href="https://www.ironswornrpg.com/">Ironsworn</a> to get a feel for the system.
Also, I was just trying to answer someone's questions on the <a class="reference external" href="https://github.com/inkle/ink">Ink</a> engine, and I came up with some interesting ideas from pondering what they were trying to do.</p>
<p>For now, though, I have to put in the effort to make Monday but not-totally-awful.</p>
<p>Good night.</p>
Diary 2019-11-102019-11-10T05:00:00-05:002019-11-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-10:/diary-2019-11-10<p class="first last">Not feeling great. I'm trying to work on it.</p>
<p>Ugh.
I hadn't dealt with all of the stress I've been under.
I don't know if I have yet, but I think I'm doing better.
I also think my laptop is getting a little finicky.</p>
<p>I think I'm going to have to make a serious effort to do writing, because all of the stress got me feeling creatively blocked.</p>
<p>So, I've made some plans for later, but sleeping soon sounds like a good idea.</p>
<p>Good night.</p>
Diary 2019-11-092019-11-09T05:00:00-05:002019-11-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-09:/diary-2019-11-09<p class="first last">There is almost no light in here, it's the middle of the night, and I'm wearing sunglasses. I'm probably fine.</p>
<p>My head hurts real bad right now.
I'm trying to deal with it, but part of that is going to have to be wrapping up soon.
I don't have the ability to focus.
I'm going to jot down some quick thoughts elsewhere for later, then try to be good enough at doing things to get ready for bed.</p>
<p>And, I can't handle things any more.</p>
<p>Good night.</p>
Algebraic Data Types 2019-11-082019-11-08T05:00:00-05:002019-11-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-08:/algebraic-data-types-2019-11-08<p class="first last">Hopefully all of the annotations I've added actually make things clearer.</p>
<p>I spent a lot of time today improving the strictness on the type annotations.
I'm currently looking into something that I looked for a command-line option for and didn't see, but maybe I just missed it, which is to note when things could take type variables, but dont.
I took care of some of that, but it feels like slower going that some of the other improvements I've made.</p>
<p>Anyway, I think I should take yet another break from working on Structured Data, because I am yet again mired down in its guts.
When I get back into it, I should work on the plugin, because I don't think I can advance the state of the codebase much more without making it actually analyze the types.</p>
<p>I forgot to mention, but I was somewhat sick today, just enough that wandering down into the guts of this codebase was probably all I was good for today anyway.</p>
<p>Good night.</p>
Algebraic Data Types 2019-11-072019-11-07T05:00:00-05:002019-11-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-07:/algebraic-data-types-2019-11-07<p class="first last">Some of this stuff was "eh, good enough".</p>
<p>Okay, I've made a serious dent in the mypy coverage holes for Structured Data.
Now the main thing left is that I still haven't worked out what I want to do for how the <tt class="docutils literal">Descriptor</tt> classes return different proxies based on which class they're accessed from.</p>
<p>I ended up feeling kind of sick today, so I don't have the energy to figure out if there's anything else I want to talk about now.</p>
<p>Good night.</p>
Algebraic Data Types 2019-11-062019-11-06T05:00:00-05:002019-11-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-06:/algebraic-data-types-2019-11-06<p class="first last">I ended up going down quite a rabbit hole tonight.</p>
<p>I mostly hung around doing other things today, but I did put in some effort with the concept of "structure types".
It was kind of tricky at times, and, unfortunately, I'm pretty sure I was working on the easy part.
I basically did explicit implementations for Patterns, CompoundMatches, and "Literals".
Next I need to work out the proper format for representing the ability to destructure tuple subclasses.</p>
<p>I'll try it tomorrow, but this could get ugly.</p>
<p>Anyway, once I've got this done to my satisfaction and I've done another pass with mypy on stricter settings, I'll take another break before returning to the question of how to implement the descriptor owner-based branching logic from the higher-level side of things.</p>
<p>Good night.</p>
Weekly Roundup 2019-11-052019-11-05T05:00:00-05:002019-11-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-05:/weekly-roundup-2019-11-05<p class="first last">The theme of this week was thinking really hard about Structured Data, then really hard about anything <em>but</em> Structured Data.</p>
<ul class="simple">
<li>Wednesday: I wrote tests for the new code in Structured Data, and a good thing, because it was broken.</li>
<li>Thursday: I filed a mysterious pylint bug.</li>
<li>Friday: I kept on adding type annotations to Structured Data.</li>
<li>Saturday: I hit a snag in my efforts to get Structured Data typed, so I started playing Minecraft again.</li>
<li>Sunday: I played a lot of Minecraft.</li>
<li>Monday: I wrote a little, also, Minecraft.</li>
</ul>
<p>Next week, I think I'll make an experimental branch off the current development branch in Structured Data, and start experimenting.
I should take it easy, but I'd like to have some idea of which of my ideas for typechecking the core matching logic have any promise.</p>
Diary 2019-11-042019-11-04T05:00:00-05:002019-11-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-04:/diary-2019-11-04<p class="first last">Guess I was closer to burnout than I realized. I'm really throwing myself into Minecraft.</p>
<p>I did some writing today; wrote part of a rough draft of one idea, a basic outline of another, and some notes on the story I've been working on for a while, which by the way has the working title "Absolutely Nobody: Magic:".</p>
<p>Besides that, so much GregBlock.
I'll try to explain that some because I don't want to do any more writing right now.
GregBlock is a skyblock pack for Minecraft (that is, the intended experience of play is that the player spawns on a small island floating in empty space, with nothing but a tree, and has to build up to, usually, something crazy) based around GregTech, or rather a mod for 1.12 which is inspired by GregTech.</p>
<p>I first encountered GregTech years ago, and I didn't have a good experience with it, and my inclination is to put the blame for that somewhat on pack authors taking kind of a kitchen sink approach.
GregTech would pretty aggressively rework recipes for other mods in an effort to put power levels under control and have a deeper tech tree.
For me, the most obvious manifestation of this was "You can't get at any of these cool toys, because the basically trivial recipe in the wiki doesn't match up with what the game says you need, which is, like, iridium chunks or whatever."</p>
<p>In any case, I haven't gotten too far in GregBlock; I've basically just done most of the beginning quests, and started making steam-powered machines.
Of the mods I was familiar with beforehand, the only one that I noticed crafting differences from the last time I played with it is Applied Energistics 2, which, <em>yeah no kidding</em>.</p>
<p>The early game is a little tough (without a saw, a log is worth 2 sticks instead of 8), but it doesn't take much to ramp up.
Now I just need to figure out what to focus on next in the context of "Now I can make basic machines."</p>
<p>Anyway, I can't write any more, so I'm done.</p>
<p>Good night.</p>
Diary 2019-11-032019-11-03T04:00:00-05:002019-11-03T04:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-03:/diary-2019-11-03<p class="first last">Taking it extremely easy and also I can't take long to write this or I won't get a good amount of sleep.</p>
<p>Today I thought about Structured Data a little and played the Gregblock modpack <em>a lot</em> and now it's midnight and there's nothing else to say, bye now.</p>
<p>Good night.</p>
Algebraic Data Types 2019-11-022019-11-02T04:00:00-04:002019-11-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-02:/algebraic-data-types-2019-11-02<p class="first last">Looking at some of my runtime semantics like "How on Earth can I express this in the type system?"</p>
<p>Well, instead of taking a break, I took one more pass at adding annotations to Structured Data.
I don't think I can do any more until I figure how to design stuff like Structures.</p>
<p>Besides that, I mostly played Minecraft today, which got me distracted until now, so I'm writing this way too late, again.</p>
<p>Here is the plan for tomorrow: probably more Minecraft, but also writing instead of Structured Data.</p>
<p>Good night.</p>
Algebraic Data Types 2019-11-012019-11-01T04:00:00-04:002019-11-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-11-01:/algebraic-data-types-2019-11-01<p class="first last">I think today's cumulative commit messages might be longer than this post.</p>
<p>I've been adding more type annotations to Structured Data because there was a lot of low-hanging fruit, and now there isn't, as much.
Here's what I know of what's left:</p>
<ul class="simple">
<li>Annotations that I'm pretty sure require the concept of a "Structure" type to accomplish.</li>
<li>Annotations that appear to require recursive types.</li>
<li>Annotations that are so hard to type, I think I need to redesign the functions in question.</li>
</ul>
<p>I'm going to have to take another break from this stuff, then grind through the eighty or so annotations that remain, classifying them so I can figure out how much of a pain this is going to be.</p>
<p>Well, I waited way too long to write this entry, so I need to stop it now.</p>
<p>Good night.</p>
Algebraic Data Types 2019-10-312019-10-31T04:00:00-04:002019-10-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-31:/algebraic-data-types-2019-10-31<p class="first last">I've been designing this for so long that I don't know how anyone else would react to it...</p>
<p>I managed to do a good enough minimization of the pylint bug I alluded to yesterday, so now my concern is adding functionality, because I can't even tell where I should put disables to make the bug go away for now.</p>
<p>Let's see about adding some methods...</p>
<p>Okay, I'm making minor improvements, which are requiring improved Mypy annotations.
I think I might need to get back into adding more type annotations, because I think I've gotten much of the codebase to make a lot more sense with them.</p>
<p>For now, though, I'll have to mostly take it easy, because I've been having kind of a rough week.
Hopefully I won't end up filing any more bugs against tools.
Working on Structured Data has had me filing bugs against three different tools, so far.
Maybe more, if I forgot any.</p>
<p>Anyway, I can't be awake much longer.
Good night.</p>
Algebraic Data Types 2019-10-302019-10-30T04:00:00-04:002019-10-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-30:/algebraic-data-types-2019-10-30<p class="first last">Pylint is giving me over 50 warnings and a score above 9. This code base might be big.</p>
<p>Took care of some more coverage holes in Structured Data, and bugs that I found in them, on account of that was draft/prototype code.
I should probably ask about testing the new docs building stuff, because it's all set to go on my end.
I'll get to that tomorrow, maybe.
For now, I'd like to improve its pylint score some, and try to get a reproduction for some of the weird pylint bugs that I'm seeing; it seems to be misreporting line numbers, or making up errors entirely.</p>
<p>The moral of the story is don't let me use your stuff, probably.</p>
<p>Anyway, I took way too long to write this, so, again, no ending.</p>
<p>Good night.</p>
Weekly Roundup 2019-10-292019-10-29T04:00:00-04:002019-10-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-29:/weekly-roundup-2019-10-29<p class="first last">Somewhat unfocused, and I honestly thought I'd taken a longer break from Structured Data.</p>
<ul class="simple">
<li>Wednesday: I made a bit more progress on Structured Data, then took a break.</li>
<li>Thursday: I did a bit of writing.</li>
<li>Friday: I got my guitar out of the closet, which is like the farthest point in this apartment from any other point.</li>
<li>Saturday: I tried to tune the guitar, and complained about composition software.</li>
<li>Sunday: I remembered that MuseScore exists, and has a low barrier to entry for trying out basic stuff.</li>
<li>Monday: I ended up focusing on Toki Pona mostly, and not focusing on actually posting the entry.</li>
</ul>
<p>Next week, I'm going to try to do the following with Structured Data:</p>
<ul class="simple">
<li>Get that last 1.03% of coverage missing on my local branch taken care of.</li>
<li>See about volunteering to test the new ReadTheDocs stuff, if it's not already out by then.</li>
<li>Get mutation coverage into a nice state.</li>
</ul>
Diary 2019-10-282019-10-28T04:00:00-04:002019-10-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-28:/diary-2019-10-28<p class="first last">Haha whoops I don't think I posted this.</p>
<p>I guess today I was mostly focusing on Toki Pona, maybe.
I've got a rough draft of a condensed reference document based on the book.
I'm probably going to have to try some of that mind-map thing I remember people pushing years ago, to figure out how to actually lay it out.</p>
<p>I did a little bit with music.
I think I still haven't found a way of working that's really natural to me.
Maybe try coming up with nonsense poems that suggest some kind of melody to me, and seeing how I think that should be notated.</p>
<p>Other than that, tried to catch up on some responsibilities.
Initial results were... ehhh...
Oh well, we're working on it.</p>
<p>I'm thinking about getting back to Structured Data.
It kind of depends on how I feel once the work week starts back up, but I'm feeling a little less burnt out currently.</p>
<p>It's getting late and I'm sleepy, nothing more to do right now.</p>
<p>Good night.</p>
Diary 2019-10-272019-10-27T04:00:00-04:002019-10-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-27:/diary-2019-10-27<p class="first last">I feel like this would feel more like taking it easy if I hadn't slept in so extremely.</p>
<p>Just kind of messed around today.
Did a bit of writing.
Gave MuseScore a shot for composition, and put together a few measures that didn't sound awful.
I'll probably stick with MuseScore, but do initial work by hand.
I'd like to get good with something like CSound, but MuseScore is better for, like, doing stuff right now.
I also took another look at Toki Pona, and skimmed over the book way too fast.
I'm going to try starting over and focusing on sentence structure, while doing flash cards for remembering words.
Hopefully I'll get this all in a week or so.</p>
<p>If I don't get to bed now, I'm going to regret it, so...</p>
<p>Good night.</p>
Diary 2019-10-262019-10-26T04:00:00-04:002019-10-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-26:/diary-2019-10-26<p class="first last">Big lesson of today: do not play guitar on a couch, at least not on mine</p>
<p>Finally started playing guitar again, and there are just so many basics that I have to relearn, so I guess I'll be doing that.</p>
<p>I also messed around more with music theory stuff.
Alternative tunings/scales.
Maybe at some point I'll figure out how to make them sound good.
Which might be easier if I could figure out a workflow that wasn't using pure sine waves.
It kind of feels to me like the manuals for the composition software I've tried out just, like, throw me into the deep end.</p>
<p>And then hold me underwater.</p>
<p>Maybe if I switch between different systems for long enough, I'll assemble enough fragments of basic knowledge to figure out how to make actual instruments play arbitrary frequencies.</p>
<p>I've got nothing else for now.</p>
<p>Good night.</p>
Diary 2019-10-252019-10-25T04:00:00-04:002019-10-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-25:/diary-2019-10-25<p class="first last">Today's contribution to my musical development: leaning over and stretching my arm out really far.</p>
<p>I took things easy on the creative front again today.
The big thing I did was decide "you know what, I'm going to try again to learn guitar" so I got it out of storage, which was a bit involved, because it was literally at the back of an overflowing closet.
I'm not actually sure what I was stepping on.
I'm not sure what ended up rubbed on my clothes, either.</p>
<p>Anyway, that's out here now, and hopefully it'll shame me by its presence into tuning it and relearning how to play it.</p>
<p>I guess that has to be it, because it's late now and I'm not interested in pushing myself.</p>
<p>Good night.</p>
Diary 2019-10-242019-10-24T04:00:00-04:002019-10-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-24:/diary-2019-10-24<p class="first last">I didn't mean to get quite so little done, but oh well.</p>
<p>I did a bit of writing today.
A tiny bit of trying to compose songs, and a little bit more progress on the thing with The Adventure Crafter.</p>
<p>One thing that kind of slowed me down with the latter was, I managed to get into a situation that was leaning harder on me than usual to make judgment calls, and it took me a while to make a call that felt right.</p>
<p>Do I have anything else to say on this?
I guess not.
I should wrap up, like, now.</p>
<p>Now.</p>
<p>Now.</p>
<p>... Good night.</p>
Algebraic Data Types 2019-10-232019-10-23T04:00:00-04:002019-10-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-23:/algebraic-data-types-2019-10-23<p class="first last">Hopefully, I won't come up with yet another must-have feature with spiraling requirements.</p>
<p>I've implemented the dispatch and underlying types for <a class="reference external" href="https://github.com/mwchase/python-structured-data/issues/40">issue 40</a>, and I've tested the dispatch, but I haven't tested the types.
I'm kind of feeling like I don't have the wherewithal to come up with sensible test cases for classmethods and staticmethods right now, so I might need to call things here and take that break I mentioned.</p>
<p>Once I worked out exactly what the responsibilities were of the different classes that got coordinated, putting together the new wrappers was pretty simple, though I did need to change things a few times because I'd made some arbitrary choices that didn't make sense, on reflection.
(For example, the wrappers originally ignored the instance argument entirely, but if that's passed, then it must be the case that whatever is returned <em>should not</em> have a <tt class="docutils literal">when</tt> method.)</p>
<p>There are good odds that I'm missing something important that'll come to light in testing, but I can't look for that right now.
I need to focus on relaxing and dealing with some stress I have in my life right now.</p>
<p>Good night.</p>
Weekly Roundup 2019-10-222019-10-22T04:00:00-04:002019-10-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-22:/weekly-roundup-2019-10-22<p class="first last">I think I've been focusing too hard on Structured Data for too long.</p>
<ul class="simple">
<li>Wednesday: I made the noxfile faster, and started removing and revising features.</li>
<li>Thursday: I prepared to switch Structured Data to require Python 3.8.</li>
<li>Friday: I removed some features and modules from Structured Data that were only there because it wasn't on Python 3.8.</li>
<li>Saturday: I got kind of distracted, and didn't accomplish much.</li>
<li>Sunday: I started working in earnest on GitHub issues I filed against Structured Data.</li>
<li>Monday: I got it down to just a few issues.</li>
</ul>
<p>Next week, I'm going to change gears a bit, then try to finish up the last of the GitHub issues I care about right now.
Then, change gears again.</p>
Algebraic Data Types 2019-10-212019-10-21T04:00:00-04:002019-10-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-21:/algebraic-data-types-2019-10-21<p class="first last">Not sure if how little I needed to rewrite my tests was a good sign, or a bad sign.</p>
<p>I ground through a bunch of stuff for Structured Data, so what's left to work on for now is:</p>
<ul class="simple">
<li>Implement wrappers for built-in descriptors, and dispatch to them in the public decorator interface</li>
<li>Convert the <tt class="docutils literal">data</tt> classes into mixins with a default implementation (have mixins, but no convenience methods)</li>
</ul>
<p>I've pared the outstanding GitHub issues I care about to 32, and 40.
I hope I can get these done before I feel like I <em>have</em> to take a break from this, but I can't guarantee that to myself.</p>
<p>I'm feeling kind of crummy, actually, so I'm going to wrap up early.
Good night.</p>
Algebraic Data Types 2019-10-202019-10-20T04:00:00-04:002019-10-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-20:/algebraic-data-types-2019-10-20<p class="first last">So many tests that need to be written...</p>
<p>Only did Pomodoro for a bit today, but I made some progress on writing.
Before that, in the morning, I did more music theorycrafting, which was probably not too productive.
I read some more manuals on various things, but didn't make too much headway.</p>
<p>On the Structured Data front, I put together a library for that enum enhancement I've been wanting.
It's not published yet, because I haven't put in the time to get it to a similar standard to the repos I like.
I also started on the various placeholder-related reworks.
I've got a rough outline of how I want things to go:</p>
<ul class="simple">
<li>Do single dispatch from Methods (I'm around here. I've got tests passing, but there are coverage holes, type errors, and lint failures)</li>
<li>Reunite Functions and Methods</li>
<li>Implement wrappers for built-in descriptors, and dispatch to them in the public decorator interface</li>
<li>Convert the <tt class="docutils literal">data</tt> classes into mixins with a default implementation</li>
</ul>
<p>This all fits more-or-less into the following issues on GitHub: 32, 33, 36, 37, 40.
Once I have those done, I think I'll take another break from working on Structured Data.</p>
<p>And, that's enough being-awake for today.
Good night.</p>
Diary 2019-10-192019-10-19T04:00:00-04:002019-10-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-19:/diary-2019-10-19<p class="first last">Bit of a frustrating day.</p>
<p>Today, I ended up really distracted.
I watched a bunch of videos on music theory, which had me wanting to try composing again.
Some of the stuff I was looking at I can explain by "well, I wanted to learn new tools for this".
Other stuff, I was looking at just because.</p>
<p>I didn't "get much done", but the bigger problem was that I was aggressively multi-tasking, which is really bad for actually accomplishing things.</p>
<p>Let's see:</p>
<ul class="simple">
<li>I was messing with xenharmonic scales, and ended up with one that I'm curious if it can be made any good; I followed sensible-sounding rules to end up at a weird-looking scale.</li>
<li>For trying stuff out with xenharmonic (and possibly algorithmic in general) composition, I decided to try learning <a class="reference external" href="https://csound.com/">CSound</a>.</li>
<li>I was taking another look at <a class="reference external" href="http://tokipona.org/">Toki Pona</a>, just because.</li>
<li>I didn't do any work on the story I've been writing.</li>
<li>I didn't work on any Structured Data issues.</li>
</ul>
<p>Tomorrow, I'm going to try using the Pomodoro Technique or something, because there is <em>no point</em> in rapidly alternating between two conlang primers and a reference manual for a programming language that reminds me of what little I know of Fortran.</p>
<p>All in all, this could have gone better, and I'll try to do better.
Good night.</p>
Algebraic Data Types 2019-10-182019-10-18T04:00:00-04:002019-10-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-18:/algebraic-data-types-2019-10-18<p class="first last">Two of my commit messages from this are just "Yeet"</p>
<p>I updated a bunch of the code for Python 3.8.
The code is a lot nicer now.
Now I just need to wait for the tools to catch up, because it seems like everything I've tried has managed to be at least a little buggy.</p>
<p>Let's see what order I have to work on things...</p>
<ul class="simple">
<li>Design new placeholder-related behavior</li>
<li>Create alternative non-data descriptor classes for class- and static- methods</li>
<li>Collapse function and method back together, if possible</li>
<li>Use a single factory function in the external interface</li>
<li>Improve type annotations</li>
<li>Mutation testing</li>
</ul>
<p>Tomorrow I'll try prototyping backends for the placeholder stuff.
The basic idea is that if there's no placeholder, then it can act like a totally normal function, but if there is a placeholder, anywhere, then it needs to perform single-dispatch.
This should mean that the registration concept becomes unnecessary, and the same idea can be accomplished via a cache.</p>
<p>Once all that is done, it's time to check the helper-for-enums idea out again, and then I think the natural place to go is to start trying to port Dennis from Coconut to Structured Data.</p>
<p>I can't be awake any longer, again.
Good night.</p>
Algebraic Data Types 2019-10-172019-10-17T04:00:00-04:002019-10-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-17:/algebraic-data-types-2019-10-17<p class="first last">Sort of weird that some of these projects apparently didn't touch 3.8-dev, but whatever. I shouldn't judge.</p>
<p>It'd have been nice if I'd done some writing today, but, oh well!
(I did do some worldbuilding, just to deal with some questions that were bothering me, but that really shouldn't make it in unprompted.)</p>
<p>I mostly focused on getting ready to cut over to Python 3.8 as soon as possible, so I can be on that, drop 3.7, and drop some of the cruddiest bits of the library as it stands.
Everything I care about is all ready to go... except for ReadTheDocs.
(And, apparently, mutmut, by way of pony, which should be working on Monday, apparently.)
I dunno... I guess I can let it spend a few days or weeks or whatever refusing to render my documentation.
But that's unaesthetic.</p>
<p>Hm.
I think I'll just make a branch for the update, and merge it whenever.
Because I want to excise my kludgy decorators as soon as I can.</p>
<p>So, I've got a branch cut, and updated requirements.
I'll start pulling out code in the next few days.
And merge it whenever the tooling is ready.</p>
<p>I need to get ready for bed now, though.
Good night.</p>
Algebraic Data Types 2019-10-162019-10-16T04:00:00-04:002019-10-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-16:/algebraic-data-types-2019-10-16<p class="first last">Trying to remember if I've used emoji in a commit message before.</p>
<p>The noxfile is much zippier now.
I had to make some similar changes to what Dennis has.
I'd assumed the problem then was some kind of interaction with Poetry, but apparently <tt class="docutils literal">pip install .</tt> is just Like That?
I've also got a helper script that gets the mutation testing done in like ten minutes.
Which is awesome.
Now I can run the tests and, like, read an article or something, instead of, run the tests, eat a full meal, watch some videos, still not done, what is happening...</p>
<p>I'm working on shoring up the features in Structured Data, and that means removing some of them, because I do not understand them well enough to fully implement them.</p>
<p>This was a little unsettling, because removing the features didn't alter the tests or coverage any.</p>
<p>I don't have anything else in mind and I'm really tired, so, good night.</p>
Weekly Roundup 2019-10-152019-10-15T04:00:00-04:002019-10-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-15:/weekly-roundup-2019-10-15<p class="first last">Nice productivity bump from not working on it for a bit.</p>
<ul class="simple">
<li>Wednesday: I went from not having clear ideas for writing, to having SO MUCH idea, and it was a little disorienting.</li>
<li>Thursday: But I got it under control. I also filed a bunch of bugs against Structured Data.</li>
<li>Friday: I played Minit and it kind of messed with my head.</li>
<li>Saturday: I did writing with The Adventure Crafter, and not on the blog.</li>
<li>Sunday: I shifted focus back to Structured Data a bit.</li>
<li>Monday: I translated the parts of the toxfile I cared about to a noxfile, (which, among other issues, slightly hoses requires.io because now all my testing dependencies are strings in a Python file, oops; I should probably make requirements files for those and do <tt class="docutils literal"><span class="pre">session.install("-r",</span> <blah>)</tt> (Note from later: I went and did the thing.)) and spent a bit over a day getting that working well. Still a little mystified by the awful performance of <tt class="docutils literal"><span class="pre">session.install(".")</span></tt>, and not sure what the right way is to do that quickly. (Like, is it a pip thing, or...)</li>
</ul>
<p>Next week, I try and figure out how some of this stuff should actually work.</p>
Algebraic Data Types 2019-10-142019-10-14T04:00:00-04:002019-10-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-14:/algebraic-data-types-2019-10-14<p class="first last">Not the most desirable outcome.</p>
<p>I did a little writing today, but mostly I translated the tox template into a noxfile.
This took all day to get right, and required careful finesse to get working on my machine.
I'm currently doing a mutation run to see how the changes I made shook out.
Current impressions: not great, but maybe I can make some improvements.</p>
<p>I got bored with how long this is taking, so I went and made the improvements.
I can't tell if it did anything, but it really should have.
Less IO, fewer virtual environments, fewer sessions.
Probably the right way to go with this would be to take this one hot path, and write a shell script for it or something.
Maybe have a nox session just for setting up the test environment.
Maybe throw together a tiny wrapper in Rust because I don't want to figure out how to do string processing in bash.</p>
<p>These are interesting ideas that I am currently too sleepy to do justice to.
I can at least get things set up to develop for it, though.</p>
<p>I say that, and then I go and get a project set up that has all of the high-level functions needed, and would compile, but wouldn't actually do anything, because I'm too sleepy to implement the helper functions.</p>
<p>There's nothing more to be done now.</p>
<p>Good night.</p>
Diary 2019-10-132019-10-13T04:00:00-04:002019-10-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-13:/diary-2019-10-13<p class="first last">Preparing for some severe refactoring...</p>
<p>A little more writing.
I should try to work on this some in the afternoons.</p>
<p>Anyway, I think I'm about ready to start acting on those bugs I was filing against Structured Data.
First area to focus on: redoing the testing configuration, and possibly the <abbr title="continuous integration">CI</abbr> configuration as well.
After that, addressing some of the holes in the specification.
I'll probably do the mutation testing changes last, because I'm going to be messing with the coverage anyway as a result of adding functionality.
I'm really excited for those changes, though.
I think there's a good chance they could take the turnaround time on mutation testing to under 5 minutes, and hopefully no longer than 10 minutes.
Although, they'll also mean adding more tests, so it might cancel out.
We'll see.</p>
<p>Back to writing, I'm going to have to work on getting the pace up, because I'm still kind of getting blocked or slowed, and it's a little frustrating doing that with stuff like Mythic and The Adventure Crafter, because I'm like "Come on, I want to know what happens next! Oh, wait, I'm supposed to be doing that."</p>
<p>Anyway, it's closing in on midnight, so, good night.</p>
Diary 2019-10-122019-10-12T04:00:00-04:002019-10-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-12:/diary-2019-10-12<p class="first last">I did it.</p>
<p>I got some writing done just now.
I finished up the scene I was talking about earlier, so now it's time to move on from that and develop it.</p>
<p>I don't have much else to say.
I was able to get this writing done, but now I'm tired.</p>
<p>Good night.</p>
Diary 2019-10-112019-10-11T04:00:00-04:002019-10-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-11:/diary-2019-10-11<p class="first last">Tired...</p>
<p>Didn't do much today.
I played a bunch of Minit, and I think it's messing with my head a bit, so I need to chill out some.</p>
<p>I entered some more bugs against Structured Data.
I'm going to have a time of it when I start addressing this stuff.</p>
<p>Anyway, I also thought some about writing.
I'm not ready to move on from the current scene; I'll need to think about it more later to figure out some of the stuff that one of the characters does, and to make sure I actually hit all of the beats I rolled.</p>
<p>I'm spacing out.
I guess that means I'm done.
Good night.</p>
Diary 2019-10-102019-10-10T04:00:00-04:002019-10-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-10:/diary-2019-10-10<p class="first last">I should figure out how to write formal specifications for Structured Data, since the coverage is excellent but there are still bugs.</p>
<p>Getting things done early tonight.
I made some headway on figuring out the next scene in the story.
I got a high-level outline, and now I'm filling it in because some of the outline is too vague.
One thing I'm liking about using The Adventure Crafter is that, because it gives all of the plot aspects associated with a scene ahead of time, I can basically use it as a checklist instead of just focusing on what I've just now written, and what I can write next.
It's freed me up to draft at whatever level of detail I feel is necessary, because I can refer to the plot details and just ask the question "Have I sufficiently addressed all of these?"
If not, I know what I need to work on.
If so, I can wrap up for now and move on.</p>
<p>I also like how it has me developing characters in ways I wouldn't necessarily think of on my own.
Without the random rolls, I probably wouldn't have thought "Okay, this wanderer character who doesn't really talk about where he came from, let's have someone from his past coincidentally turn up."
But that was the most natural interpretation of the rolls I got, and the resulting character... I don't know what anyone else would think of him, but I'm happy with him.</p>
<p>Other stuff I did today...
Now that I'm not deep in the guts of Structured Data, I went and filed five or so bugs in reflection of the fact that various parts of the design on recently-added stuff are wrong or underspecified.
I'm going to see how much further I can push this whole "thinking about what I'm doing" thing, and then maybe get back into the code on the weekend.</p>
<p>Okay, that's enough for now, I feel like.
Good night.</p>
Diary 2019-10-092019-10-09T04:00:00-04:002019-10-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-09:/diary-2019-10-09<p class="first last">Be nice to your procgen algorithms. They are working very hard.</p>
<p>I was doing other stuff earlier, so when I went to write, I got as far as "I need to roll up a scene that is similar to 'the characters proceed through the desert under cover of night'", except focusing on the ill will between one of the revolutionaries and the local thugs, some kind of coercion being applied to a "rude ruler" who is "connected to" the main character, the discovery of a mysterious artifact, a covert observer, and discovery of a lie.</p>
<p>The Adventure Crafter can be <em>a lot</em>, is what I'm getting at.
It's not that I don't think I can do this, I just probably can't do it right now.
I'm starting to see why, as a GM tool, it's recommended to use it ahead-of-time.</p>
<p>In any case, I decided to work on this today, and that's what I got done.
I'll try to do more later, of course.</p>
<p>Good night.</p>
Weekly Roundup 2019-10-082019-10-08T04:00:00-04:002019-10-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-08:/weekly-roundup-2019-10-08<p class="first last">Getting closer and closer to a sensible interface. Shame it's probably <em>super</em> slow.</p>
<ul class="simple">
<li>Wednesday: I started working on red-black trees using Structured Data.</li>
<li>Thursday: I finished the first iteration of red-black trees, which generated yet another feature idea to try to improve the ergonomics.</li>
<li>Friday: I thought more about type-checking.</li>
<li>Saturday: I revisited the feature idea, then realized my initial concept was way too complicated.</li>
<li>Sunday: I got the feature done, then looked into addressing coverage gaps.</li>
<li>Monday: I closed as many gaps as I felt comfortable with, then went to bed as soon as I could.</li>
</ul>
<p>Next week, I want to take a break for a bit to focus on writing, then come back and work on improving the type coverage.</p>
Algebraic Data Types 2019-10-072019-10-07T04:00:00-04:002019-10-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-07:/algebraic-data-types-2019-10-07<p class="first last">Honestly not sure if I want the MatchDict to keep being a thing. It's kind of a painful level of boilerplate next to the new wrappers, but in the case of doing a match <em>within</em> a function...</p>
<p>Today, I got the mutation coverage as thorough as I feel like right now.
6 surviving mutants out of 485.
Now I'm going through and making incremental improvements to the typing.</p>
<p>Then an hour ago, I thought "I'll get this over with quickly." and ended up working a little, but mostly spacing out, so I'm going to call this now because I see where this is going.</p>
<p>Good night.</p>
Algebraic Data Types 2019-10-062019-10-06T04:00:00-04:002019-10-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-06:/algebraic-data-types-2019-10-06<p class="first last">Still raising my eyebrows at crashing with <tt class="docutils literal">AssertionError: unreachable</tt></p>
<p>I spent most of today polishing the implementation for placeholders, and doing general minor improvements to the codebase.
Among them was rewriting one function so that it doesn't crash newer releases of Mypy.
My code is extremely normal.
I should probably cut another release soon, but the more I add type annotations, the more I think that I'd like to put together something to represent the type relations around structural matching.</p>
<p>So, my plan right now is to go over the mutmut results seeing how I can close gaps in testing, then make the type checking as strict as I can manage for now.
Once I get to a good stopping point, cut a release and continue working on Rosetta Code stuff.
Maybe actually make a commit to that repo at some point.</p>
<p>I can't figure out what I meant to say next, and it's late, so...</p>
<p>Good night.</p>
Algebraic Data Types 2019-10-052019-10-05T04:00:00-04:002019-10-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-05:/algebraic-data-types-2019-10-05<p class="first last">Genuinely unsure if this library will make sense to anyone else by the time I'm done with it.</p>
<p>It took very little time for me to give the red-black tree draft some almost-decent implementations of various methods, so that's set to go soon.
Looking at it inspired me to take care of an old PR I'd forgotten about, and to open a new one for one of the features I'd concluded would be nice-to-have.</p>
<p>I quickly realized, however, that I'd been glossing over a bunch of details.</p>
<p>Basically, one of the current warts with the match-based function definitions is that it's not currently possible to define the matches inside the class definition.
It would be <em>nice</em> if there were a way to specify a placeholder that could get processed at some point after the main body of the <tt class="docutils literal">__init_subclass__</tt> method, so that the placeholder effectively gets replaced with the class that was just set up.</p>
<p>Now, because the stack iteration Just Works™, I'd forgotten about the whole "arbitrary nesting" aspect to structure definitions.
Thinking about it more, I almost feel like maybe the correct solution is to just pass a callback that takes the class as a value.
Then, the post-process would just be "if there's a callback, insert it but defer checking, and pass the class to it when ready."</p>
<p>This seems like a solid approach to take, tomorrow, when I'm well-rested.</p>
<p>(In case I forget, the Property setter structure should wrap the overall structure in a callback if either argument is a callback.
And I guess the Function should wrap and defer if <em>any</em> argument is a callback.)</p>
<p>Anyway, I'm tired, once again.
Funny how that works.</p>
<p>Good night.</p>
Algebraic Data Types 2019-10-042019-10-04T04:00:00-04:002019-10-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-04:/algebraic-data-types-2019-10-04<p class="first last">Somewhat unusual day today, so things got disrupted, and I don't have much to show for it, but oh well.</p>
<p>I took things easy today, so there isn't much to report, but I thought more about how to deal with structures in a typed way.
Pretty sure it'll take a combination of generics and protocols that I'm not sure actually works, and also stuff with TypedDict that I'm pretty sure will need a separate plugin just to make things work as expected.</p>
<p>I think I'll try to move toward developing in branches, because some of the changes I have in mind could be a huge pain if they're not isolated.</p>
<p>Okay, I can't stay awake any longer.
Good night.</p>
Algebraic Data Types 2019-10-032019-10-03T04:00:00-04:002019-10-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-03:/algebraic-data-types-2019-10-03<p class="first last">There's probably a tiny typo that renders the whole thing incorrect under excruciatingly specific circumstances.</p>
<p>I just completed the first draft of a direct translation of some functional red-black tree code from Haskell to Python with Structured data.
It's about 5-6 times longer than the source material, some of which is attributable to the way Structured Data's interface interacts with Python conventions.
A previous attempt was a bit longer, but had some functionality that the draft does not currently implement, <em>but also</em> it cannot implement some of the functionality that the new version will be able to.</p>
<p>Heavy usage of the <tt class="docutils literal">function</tt> decorator reveals some challenges that type checkers will have to handle:</p>
<ul class="simple">
<li>There needs to be an idea of a "structure type" that corresponds to, and at runtime is an instance of, a tuple or an ADT class. Fortunately, none of the other matchers use instances like that.</li>
<li>In the <tt class="docutils literal">when</tt> decorator, there needs to be a connection made between pattern names and function arguments.</li>
</ul>
<p>Hopefully the last feature I come up with for Structured Data: an attribute constructor that makes placeholders representing "the current class" and which can be used in <tt class="docutils literal">when</tt> decorators instead of exfiltrating the function from the class scope.</p>
<p>Speaking of features, I should get back to that enum helper idea, probably make that its own library, unless I realize it somehow interacts with defining a <tt class="docutils literal">Sum</tt> or <tt class="docutils literal">Product</tt> class.</p>
<p>Time got way away from me.
I need to stop now.</p>
<p>Good night.</p>
Algebraic Data Types 2019-10-022019-10-02T04:00:00-04:002019-10-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-02:/algebraic-data-types-2019-10-02<p class="first last">When I think about it, it's kind of impressive how many tools the Structured Data codebase outright breaks.</p>
<p>Quick entry because I let myself get distracted and I have to move fast to get enough sleep after this.</p>
<p>I'm working on adapting immutable red-black tree code from Haskell to Python with Structured Data.
The conversion is pretty straightforward, though the Python is somewhat wordier because the means of function definition is basically embedded as a DSL.
It doesn't bother me yet, but I don't know what other people would think.
I think if I can get all of the features done for this, I'd like to look into using it as a basis for starting to get the Mypy plugin working, because that's the basic barrier I have to using this in more projects, the fact that code using Structured Data in no way typechecks.
(And Structured Data itself has... problems... with recent versions of Mypy, last I checked.)</p>
<p>Anyway, I'm done now because I have to be.</p>
<p>Good night.</p>
Weekly Roundup 2019-10-012019-10-01T04:00:00-04:002019-10-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-10-01:/weekly-roundup-2019-10-01<p class="first last">I got distracted implementing a red-black tree, and need to be in bed, like, five minutes ago.</p>
<ul class="simple">
<li>Wednesday: I explained some math that I don't know if anyone else cares about.</li>
<li>Thursday: I started getting sick.</li>
<li>Friday: I continued being sick.</li>
<li>Saturday: I recovered from being sick.</li>
<li>Sunday: I got back into writing a bit.</li>
<li>Monday: I finished with Structured Data for now, and made a joke about tooling that I waffled over the day after I published the entry.</li>
</ul>
<p>Next week, I'm going to work on more Structured Data examples.</p>
<p>(Seriously, should it have been "Yuki Nagato Georg" or "Typing Georg", and instead of an ellipsis, should I have said "who lives in a cave" or "who lives in a barely-furnished apartment", followed by "and types thousands of lines of code a second" or something?)</p>
Algebraic Data Types 2019-09-302019-09-30T04:00:00-04:002019-09-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-30:/algebraic-data-types-2019-09-30<p class="first last">Yuki Nagato Georg ... was a statistical outlier and should not have been counted.</p>
<p>After working on other stuff for a while, I was able to return to Structured Data and grind some metrics down.
The metrics are all too good to improve, currently, so I'd like to try using the new features I added.
I'll get to that in a little bit.
Speaking of metrics, though, I ran <a class="reference external" href="https://radon.readthedocs.io/en/latest/">radon</a> against this codebase, and according to the Halstead metrics, the whole codebase could be done in like four minutes.
I would pay good money to see someone type at the speed required to accomplish that.
(Seriously, I think something's wrong with how it's counting the operators and operands.
The GitHub issues back me up on this.)
Anyway, all of the new features that messed with the metrics, also gave mutmut about 70 new mutations, a bit over a dozen of which got through.
(Or... came back to life?
That bit's weird.)
I don't have the fortitude to address them right now, so I'm going to focus on doing and redoing Rosetta code stuff.</p>
<p>Anyway, I can't think of anything else to add, so this post must be done.</p>
<p>Good night.</p>
Diary 2019-09-292019-09-29T04:00:00-04:002019-09-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-29:/diary-2019-09-29<p class="first last">Constantly putting off figuring out whether what I'm doing is actually a good idea.</p>
<p>Today, I did some writing where I tried actually using the reference material I've been putting together for the past week or so.
It worked fine, although I did have to errata some rules interactions I hadn't anticipated.</p>
<p>I also made some changes to Structured Data to hopefully make individual pieces of the code easier to understand.
Honestly, I can't tell if it helped, but it occurs to me that I have seen some projects take the "define things internally and re-export" approach, so that's heartening.
If I go all the way with that (which would really help some metrics), I'll probably have to ditch the whole "type facade" idea, or else go all in on that as well.
I don't know which I really prefer.
Either way, I'm probably going to have to keep up the "split of into modules" thing, and possibly start adding more folders.</p>
<p>I've got to wrap up.</p>
<p>Oh, also, my code is so horrifyingly un-idiomatic that I had to pin Mypy to an earlier version and file a bug, because the latest stable and dev both crash with <tt class="docutils literal">AssertionError: unreachable</tt> which is <em>clearly</em> false.</p>
<p>Good night.</p>
Diary 2019-09-282019-09-28T04:00:00-04:002019-09-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-28:/diary-2019-09-28<p class="first last">As a teenager I would get really sick and trim boxtops. Same deal, just less relevance to helping people.</p>
<p>Still really tired, so I did more stuff that I wasn't taking the time to do earlier, like separating out the writing project so it works better in the text editor, doing basic typo passes, and taking notes on all of the names I made up.
I also got the pages I printed punched, in the binder, and flagged for easy reference, as well as some important bits highlighted.
I will totally be ready to get back into writing once I stop being, like <em>super</em> tired.</p>
<p>I also rewrote a Python module that I originally rewrote from some code I found on the internet.
The code is concerned with adding tail calls to Python as a library.
I guess my thinking was, I feel bad, and refining this code kind of gives that specific feeling of badness form, because this code is basically just nothing but a bad idea.
That's why I put a lewd Elder Scrolls reference in the name of it, so the only people it can hurt are people who use it """ironically""".</p>
<p>I don't feel like writing any more here.
Good night.</p>
Diary 2019-09-272019-09-27T04:00:00-04:002019-09-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-27:/diary-2019-09-27<p class="first last">I don't recommend any part of this.</p>
<p>I'm sick and tired right now, so today I did stuff that didn't need too much thought, like printing stuff out for later, and finally renaming Seed.</p>
<p>I'm feeling even worse now than I did yesterday, so that's it.</p>
<p>Good night.</p>
Diary 2019-09-262019-09-26T04:00:00-04:002019-09-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-26:/diary-2019-09-26<p class="first last">Brain no work.</p>
<p>It'd be cool if I had something to write, but I'm having a lot of trouble forming sequences of thoughts.</p>
<p>I don't know why I'm so tired, but I am.</p>
<p>I'm going to ramble a bit while I wait for this song I have playing to finish.</p>
<p>I'm not sure what's up, exactly.
It seems like maybe my exercise today hit harder than usual.
I'm feeling unusually sore, and maybe that brought tiredness at the same time.
It's a possibility.</p>
<p>I got nothing else.
Oh well.</p>
<p>Good night.</p>
Diary 2019-09-252019-09-25T04:00:00-04:002019-09-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-25:/diary-2019-09-25<p class="first last">MATH</p>
<p>A few things happened today.
For one, I think I finally have proof that the recreational math idea I was messing with just doesn't work as far as I was trying to take it.
For another, Coverage released another alpha, and I realized that limit-coverage was broken outside of my specific use case, so I pushed out some quick fixes that didn't break my stuff, and <em>probably</em> make things better; that it would be hard for them to make worse.
Discovered something about Coverage that I'm going to report as an issue when I have time to put together minimal reproduction.
It probably won't matter to most people.
I'm putting together notes for something on software metrics, but I'm not rushing that, because that's a topic that's not going anywhere.</p>
<p>I figured I'd try to explain the recreational mathematics stuff, since I've mentioned it enough.</p>
<p>First, some background:</p>
<p>There are various conventions for representing numbers in base 10, using binary coding.
Basically, different systems for turning a few binary digits into a single decimal digit.
What inspired me was the <a class="reference external" href="https://en.wikipedia.org/wiki/POSTNET">POSTNET</a> system, in which each digit is assigned a number, and the numbers from 0 to 9 are represented as sums of exactly two of these numbers, with just one special case (4 + 7 = 0).
I found myself wondering under which circumstances a <a class="reference external" href="https://en.wikipedia.org/wiki/Constant-weight_code">constant-weight code</a> could have a number assigned to each digit as in POSTNET, but with no special cases.</p>
<p>Clearly, if just one digit is on, then the answer is to just give each digit a number, consecutively, up to the maximum.
This is basically a way of thinking about normal positional systems that ignores the specific symbols: 0 is the first light, 1 is the second, 2 is the third, and so on.
And if one digit is off, then it trivially corresponds to the case of one digit on, though getting the numbers to actually line up may require some fractional parts.</p>
<p>We can call these cases of representing N symbols with N bits the trivial solutions to this idea.
What's of interest is representing <em>more than</em> N symbols with N bits.
I have found two solutions to this (similar solutions can be obtained through symmetries, but they're the same structures): two of -1, 1, 2, 3, and three of -5, 2, 3, 4, 6, 9.
From my attempts to find a solution for four of eight numbers, I doubt there are any further non-trivial solutions; I would love to be wrong, and I'd especially love it if there's literature on this that I just failed to find.</p>
<p>Before I get into the theory behind the computer search I did for the 4-of-8 case, I'll mention how things went doing stuff manually.</p>
<p>2-of-4 was simple enough to do in my head.
I wasn't able to work out 3-of-6 by guessing, but I was able to express it as an extension of 2-of-4, and from there basically just solve some linear equations to find it.
I attempted to extend this result to 4-of-8, and I only got negative results.</p>
<p>Unfortunately, my attempts weren't very rigorous, and it's hard for me to write them up in an airtight way, especially given what I found next:</p>
<p>Computer search for the 4-of-8 case...</p>
<p>Four out of eight digits would yield a base-70 code.
Testing every candidate for 3-of-6 is more-or-less fine.
Testing every candidate for 4-of-8... is not.
Something must be done to narrow down the candidates we look at, to come up with standards from which we can generate only the candidates that meet those standards.</p>
<p>We can generalize the problem of finding numbers that add up to each number from 0 to 69 to adding up to 70 consecutive numbers, or further, to each number mod 70.
If there is a 4-of-8 coding that sums four numbers to obtain a number between 0 and 69, then there is a 4-of-8 coding that sums four numbers to obtain every number mod 70.</p>
<p>Given every number mod 70, we can modulo them with much smaller numbers, to get every number mod 10, 7 times, or every number mod 14, 5 times.
Looking for candidates in these spaces is much faster than the full 70, because all 8 digits have a much smaller range of values, so the search is exponentially quicker.</p>
<p>Supposing we had a solution, and we took its moduli mod 2, 5, and 7.
From the three sequences that result, we could recover the original solution.
Using 10 and 14 lets us optimize somewhat, because we know that evens have to match with evens, and odds with odds.
This lets us divide up candidate sequences by the number of even numbers they contain, and solve four smaller problems instead of one big one.
In addition, within each problem, we know that we can't match evens and odds, so that lets us discard more possibilities out of hand.
It so happens that none of the possibilities mod 14 repeat a digit, so we just need all by-value unique permutations of the possibilities mod 10.
A permutation of a 10, combined with a 14, uniquely identifies a candidate sequence mod 70, which can then be quickly checked.</p>
<p>I ran the numbers, had code calculate everything, and... nothing.
No candidates meet the loosened standard of "each number mod 70".</p>
<p>Therefore, there's no coding for 4-of-8 that works like -1, 1, 2, 3, or -5, 2, 3, 4, 6, 9.
I don't know about higher numbers.
For all I know, the "problem" with 4-of-8 is just that 70 is congruent to 1 mod 3.
I think I can gather enough low factors of the next number, 252, to have a chance of doing a search in a reasonable time, but I don't want to try right now.</p>
<p>So, that's how I spent my weekend.</p>
<p>It's late, I should stop writing.</p>
<p>Good night.</p>
Weekly Roundup 2019-09-242019-09-24T04:00:00-04:002019-09-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-24:/weekly-roundup-2019-09-24<p class="first last">Legitimately surprised at how few days it took to accomplish these things.</p>
<ul class="simple">
<li>Wednesday: I decided to try and showcase using Structured Data to solve problems.</li>
<li>Thursday: I put together a proof of concept for using Structured Data, but it was iffy enough that I don't think I actually pushed it... I ended up deciding that my attempt justified getting the alternative function definition idea implemented.</li>
<li>Friday: I sketched out designs for the function feature, and started working on condensing the various things I'm using as writing aids.</li>
<li>Saturday: I discovered that I like laying out tree data in spreadsheets, did some more design work for Structured Data, and started messing with some recreational math.</li>
<li>Sunday: I made progress on condensing stuff, and I put together a scary-looking prototype for the Structured Data feature. I pledged that I'd write tests for the feature and reimplement the prototype as required, rather than just paste it in and go.</li>
<li>Monday: I just pasted it in and went. I also thought about some of the code metrics that services provide, and whether they make sense. Finally, all of the condensed rules are probably ready to print, but we're skeptical that the printer can handle it, so I'm holding off on printing it right now.</li>
</ul>
<p>Since then, I've applied some of the stuff I learned implementing the function dispatch feature to simplify the implementation of the <tt class="docutils literal">Product</tt> class.
No definite results on the math front; I'm working on reducing the search space.</p>
<p>Next week, I'd like to try doing some essay-writing on code metrics.
That might take a while.</p>
Diary 2019-09-232019-09-23T04:00:00-04:002019-09-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-23:/diary-2019-09-23<p class="first last">Not sure how to move code into new modules in a principled manner. I mean, I could just shotgun everything out into tiny modules, but that seems wrong.</p>
<p>Today, for Structured Data, rather than carefully adding tests for the new functionality, I just did the easier thing of pasting in the prototype and throwing tests at it until the coverage was acceptable.
Then added some functionality.
Then fixed long-standing bugs in the original code that all of this revealed.
And did some refactoring.
The rating services are still yelling over the code, stuff about how the modules should be smaller and some of the functions should have a lower cyclomatic complexity.</p>
<p>I was reading various literature on cyclomatic complexity, and I don't have citations to hand, but the impression I got was that cyclomatic complexity is best used as a measure of "how hard the code would be to test".
But I have a comprehensive test suite and mutation testing!
I don't need metrics about how hard a thing would be, when I can produce metrics about how close I am to achieving it!</p>
<p>I'll still try to improve on the situation later, but I need to take some time to decide what "improvement" looks like.</p>
<p>Aside from that, I think I'm done compressing down reference materials.
It's a bit under 50 pages, which just need to be printed out and marked up; I'll do that in the next few days.</p>
<p>For now, I really need to wrap up (and stop tweaking the Structured Data code).
Good night.</p>
Diary 2019-09-222019-09-22T04:00:00-04:002019-09-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-22:/diary-2019-09-22<p class="first last">Strong contender for "most horrifying code I have ever written"</p>
<p>I've got the guidelines for the various rules mostly boiled down.
I just need to summarize the rules for The Adventure Crafter itself, and I should be set to turn all of this into a hardcopy reference.</p>
<p>Aside from that, I put together a prototype for multiple-definition functions.
This code is... horrifying.
I noticed that I'd somewhat reinvented the wheel elsewhere in Structured Data, insofar as the <tt class="docutils literal">inspect</tt> module provides facilities to tell you how the arguments to a function <em>would</em> be dispatched, given some <tt class="docutils literal">*args</tt> and <tt class="docutils literal">**kwargs</tt>.
With this, I was able to:
Extract all non-variable-length arguments as a dictionary, convert it into a <tt class="docutils literal">Matchable</tt>, match it against a sequence of <tt class="docutils literal">structure, function</tt> pairs, and for the first match, extract all values from that into the variable-length arguments (erroring in the case of a collision), figure out how the target function would have just the keyword arguments dispatched, inject the variable positional arguments, if any, then actually generate the call.
I can't see any reason why it wouldn't work, except that it's so complex that it'll take significant effort to actually define "working".</p>
<p>I just now worked out some functionality I want that is too complicated to put in the prototype, so I'll have to try to <abbr title="test-driven development">TDD</abbr> it in.</p>
<p>I hoped I would come up with something else to say, but I didn't.</p>
<p>Good night.</p>
Diary 2019-09-212019-09-21T04:00:00-04:002019-09-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-21:/diary-2019-09-21<p class="first last">"I hate WYSIWYG editors and overly fancy GUIs. Just let me work with the data in code form!" *lays stuff out in a spreadsheet* "<em>Okay, fine.</em>"</p>
<p>I've spent most of today distilling down information from various sources; I'm basically aiming to collapse a couple hundred pages of sourcebook to a few dozen of reference, which I will print out and mark up.</p>
<p>I started sketching out what the latest additions to Structured Data will look like, and then half an hour ago I got distracted with some recreational mathematics stuff that's currently looking like it's not going to pan out.</p>
<p>Because of that, I have to end the post even more abruptly than I have been lately.</p>
Diary 2019-09-202019-09-20T04:00:00-04:002019-09-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-20:/diary-2019-09-20<p class="first last">I almost think I would've preferred to get some of these rules in pseudocode...</p>
<p>I came up with a bunch of designs for the new Structured Data feature I mentioned, and I think I've gotten to one that makes sense.
Mostly today, though, I upgraded my laptop, and started working on trying to consolidate Mythic-related materials so I can use it without cross-referencing between four or so different documents.
For some of this, there are so many conditionals involved that reading it in prose form makes my brain shut down.
I think I might have to write code to calculate this, just to figure out how to convert it to a nice table.
I just did that, and I think I've got it figured out.</p>
<p>Basically, when you bring in homebrew on Variations II, it becomes necessary to calculate three different axes separately, even though they share some logic: yes/no, marginal/normal/extreme, and whether a random event occurred.</p>
<p>Hopefully, I should get most of this sorted out in a few days.</p>
<p>For now, I desperately need to get to sleep.
Good night.</p>
Algebraic Data Types 2019-09-192019-09-19T04:00:00-04:002019-09-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-19:/algebraic-data-types-2019-09-19<p class="first last">It'd be cool if Rosetta Code were using a vcs instead of MediaWiki, because I don't think opening a PR against the content of a MediaWiki site is a thing.</p>
<p>I did a little more mutation testing, but it's getting a little boring, so I'm taking a break like I should be anyway.</p>
<p>I took a look at Rosetta Code tasks, and tried to adapt the <a class="reference external" href="https://rosettacode.org/wiki/Arithmetic_evaluation">Arithmetic Evaluation</a> task to my sensibilities.
This was kind of tricky because the Python code I based it off of was abbreviated to the point of obfuscation, and the error handling was so confusing that I worked out just enough to strip most of it out.
I haven't yet expanded all of the names to something sensible.
Trying this out has me firmly on the side of "make a multiple dispatch decorator" now, so I'll get into that next and see about cleaning things up.
After that, I'll probably try implementing red-black trees along the lines of <a class="reference external" href="http://matt.might.net/papers/germane2014deletion.pdf">Germane and Might</a>, referring also to a previous time I tried to do that.</p>
<p>I spaced out thinking about some other stuff, so I need to call this now.</p>
<p>Good night.</p>
Algebraic Data Types 2019-09-182019-09-18T04:00:00-04:002019-09-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-18:/algebraic-data-types-2019-09-18<p class="first last">My wife used to be a big fan of X-Men, so it's a little awkward to have spent so much time going "Come on, got to kill these last few mutants"</p>
<p>I got really into improving Structured Data's tests from the standpoint of mutation testing, so I think most of the few surving mutants are some combination of "Oh, that's interesting", "Oh, that's... interesting", and "I don't understand why that commit didn't fix these problems".</p>
<p>I was thinking about this earlier, and I think I might be getting into a situation, again, where I'm neglecting some work in favor of lower-priority work that's (relatively) easier and more enjoyable.
In this case, the fact that I'm trying to improve test coverage, when some of the desired behavior isn't actually specified in a well-justified way.
And it's not specified in a well-justified way, because I don't have use cases yet that would motivate any particular behavior.
I think the only way around this is to get people, including me, using this code outside of the context of its own test suite.</p>
<p>I'm thinking the way to go for that is to find problems on <a class="reference external" href="https://rosettacode.org/">Rosetta Code</a> or something, that lend themselves well to the strengths of the library.
Rough priorities for doing this:</p>
<ul class="simple">
<li>Update the changelog as needed, and cut a new release.</li>
<li>Put up a repo for this stuff, probably on GitHub, and start working on problems in it.</li>
<li>If needed, get to work on the alternative function decorator idea.</li>
</ul>
<p>Besides working on that, and unrelated to Structured Data, I want to have a nice hard-copy reference for the writing aids I'm working on, so I'm also figuring out what I want to have for that.</p>
<p>Okay, pretty loopy right now, definitely need to get ready for bed.</p>
<p>Good night.</p>
Weekly Roundup 2019-09-172019-09-17T04:00:00-04:002019-09-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-17:/weekly-roundup-2019-09-17<p class="first last">Debugging command-line systems that by default take like an hour to give results, while not getting enough sleep: heavily disrecommended!</p>
<ul class="simple">
<li>Wednesday: I shelved the Mypy plugin for Structured Data again, and started thinking about writing.</li>
<li>Thursday: I <em>definitely</em> shelved the Mypy plugin. I did some work for other projects that, so far as I know, hasn't been merged, and did prep work for writing, and got back to mutation testing.</li>
<li>Friday: Legs hurty.</li>
<li>Saturday: I put together an interface around the GPT-2 model. It more-or-less works. Watched a movie, and started writing.</li>
<li>Sunday: Mutation testing is hard. I actually only got it working shortly before posting this entry. Started writing just after that entry.</li>
<li>Monday: More writing, and other stuff.</li>
</ul>
<p>Next week, I'd like to keep up the writing, because now that the mutation testing is reliable, I have to actually confront the fact that it's giving me mutations like this:</p>
<div class="highlight"><pre><span></span><span class="gd">--- src/structured_data/_patterns/mapping_match.py</span>
<span class="gi">+++ src/structured_data/_patterns/mapping_match.py</span>
<span class="gu">@@ -108,7 +108,7 @@</span>
<span class="w"> </span> def exhaustive_length_must_match(self, value: typing.Sized):
<span class="w"> </span> """If the match is exhaustive and the lengths differ, fail."""
<span class="gd">- if self.exhaustive and dict_pattern_length(value) != dict_pattern_length(self):</span>
<span class="gi">+ if self.exhaustive and dict_pattern_length(value) == dict_pattern_length(self):</span>
<span class="w"> </span> raise MatchFailure
<span class="w"> </span> def destructure(
</pre></div>
<p>How 'bout those coverage metrics?</p>
Diary 2019-09-162019-09-16T04:00:00-04:002019-09-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-16:/diary-2019-09-16<p class="first last">Probably not the right way to go about that.</p>
<p>I manually disabled the troublesome mutation tests.
I mean I probably should have just added a one-second sleep to the test runner to stop the metadata from ever matching, but oh well, I don't feel like going back to fix that up right now.</p>
<p>I'm doing a bit more of the writing-with-rpg-rules.
The first combat is kind of dragging, but hopefully that's just because I'm doing it over multiple days.</p>
<p>Mostly today we went shopping, so now the bed is nicer and I have more pants that fit, both very important things.</p>
<p>Okay, once again, writing stuff down here got me a little further in the writing there.
I think it's time to switch to Mythic rules for a bit, but we'll see.
I hope I get faster with this stuff, because I feel like I made more progress on this than I would have just trying to "write something" for the same amount of time.
I probably need to print some stuff out and put it in a binder or something, so I can just look at it without scrambling around in a PDF.</p>
<p>I want to wrap things up for now.</p>
<p>Good night.</p>
Diary 2019-09-152019-09-15T04:00:00-04:002019-09-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-15:/diary-2019-09-15<p class="first last">I think I have been having a bit of caffeine each day recently, which just hit me all at once today.</p>
<p>Today felt kind of iffy, but I got some stuff done.
I made a few of the Structured Data tests stricter, which caught some more mutants.
One persistent annoyance I've been hitting is that running the mutation tests seems to leave particular pyc files in a bad state, which implies to me that I've somehow managed to get a hash collision or something (my money's on "or something"), and some mutants may be incorrectly showing up as killed, when actually it's that a different mutant didn't get properly uncached.</p>
<p>This kind of gets to one of the persistent stumbling blocks I've had with mutation testing: it kind of requires that your tests fail for the right reasons, and not any of:</p>
<ul class="simple">
<li>Dependencies not installed in the test environment</li>
<li>Caught mutations persisting in source</li>
<li>Caught mutations persisting in <em>binaries</em></li>
<li>Including too many tests, including ones that detect the backup files</li>
<li>I forgot to turn off folder syncing and the repo got filled with gibberish because the mutation testing was moving files around too quickly.</li>
</ul>
<p>Anyway, that's kind of mostly frustrating, so for the moment, I'm messing around with gtp2 and pushing it to its limits.
No, really.
I gave it an input text that tokenized into just slightly too many tokens, and the implementation I'm using will <em>tell you</em> "That's not going to work" but it doesn't suggest any means of remediation.
I came up with something on my own that might work, but it does still throw up the same warning.
It produces results of some kind, but because of how I coded the wrapper, I won't see them until it's all the way done, which is going to take, like, over an hour.</p>
<p>My laptop is not intrinsically a good source of fake news, is how this is looking.</p>
<p>Anyway, I'd like to make some progress on the writing.
My plan is to just set a goal of setting up the bookkeeping for the first combat encounter.
Actually running the combat is going to involve learning a lot of things all at once, so I need to have more than a few hours late at night to get through it.</p>
<p>I'm going to wrap up this entry and then do that, because that's just going to be taking a bunch of notes, and I want to get this post over with.</p>
<p>Good night.</p>
Diary 2019-09-142019-09-14T04:00:00-04:002019-09-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-14:/diary-2019-09-14<p class="first last">A nice day that I'm not sure how well I wrote it up.</p>
<p>Today, I think my shins got better.</p>
<p>Instead of messing with any of my existing code, I put together an alternative interface around the PyTorch implementation of the GPT-2 models.
In layman's terms, I point it at a text file, wait a few minutes, and then get back a bunch of ideas about what could go next.
Most of these ideas are kind of bad, or at least don't appeal to me, but it does seem like this has potential to break writer's block.
Like "I bet you can do better than this."
I don't know how long this takes on really long files.
It might take a really long time!</p>
<p>A while ago, we watched <em>The Prophecy</em>.
I might have mentioned it then.
Anyway, today we watched <em>The Prophecy II</em>.
Still bonkers, so we got at least our money's worth from that rental.
It more or less sticks to much of the formula established in the first one, but that formula is super weird, so it works out.
I assume there's no Planet of the Apes movie starring Christopher Walken, but The Prophecy movies so far have been an oddly decent replacement for such a thing.</p>
<p>Finally, I decided to really get started on that whole writing thing.
Basically, I'm trying to put a bunch of things together:
The character and plotline management of The Adventure Crafter, the GM emulation of Mythic (Variations II (probably with some homebrew (I haven't decided yet))), and the rules of Risus.
It's a little slow going to start with, because The Adventure Crafter is A Lot, and I made some rolls I'm having trouble with, but I'm happy with the stuff I've worked out from it so far.
It just might take a little bit more effort to get this off the ground.
Although, writing this entry seemed to be the push I needed to interpret the rolls and get the beginning the rest of the way done.
I think I got through the first use of The Adventure Crafter.
Just took a bunch of effort.</p>
<p>So much so that I'm definitely done for now.
Good night.</p>
Diary 2019-09-132019-09-13T04:00:00-04:002019-09-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-13:/diary-2019-09-13<p class="first last">Not recommended: having two limps at once</p>
<p>Today, I messed up my shins, and made a little more progress on the writing front.
I mostly dealt with the former.
Over the weekend, I'm going to try to jump into things with the latter.</p>
<p>For the moment, I am too tired to say anything interesting, so I can't really do anything but call this entry here, short as it is.</p>
<p>Good night.</p>
Diary 2019-09-122019-09-12T04:00:00-04:002019-09-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-12:/diary-2019-09-12<p class="first last">I didn't get enough sleep, so it took a lot of effort to remember what I actually did today.</p>
<p>I got to bed <em>way</em> too late last night and paid the price for it all day, but was able to get some work done, like putting in PRs against open source projects, and deciding on some details for the writing project I've been mentioning.</p>
<p>I did some prep work there, and I'm going to have to take some time this weekend to nail down the process details.</p>
<p>Oh yeah.
I also decided to punt on writing a Mypy plugin for Structured Data, and got mutation testing running against it with typechecking.
Plenty of tests that's suggesting, when I'm a little more alert and capable of working out how to test these various cases.</p>
<p>For now, I've got to wrap things up quickly again, so, good night.</p>
Diary 2019-09-112019-09-11T04:00:00-04:002019-09-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-11:/diary-2019-09-11<p class="first last">Every minute I stray further from lucidity.</p>
<p>Ugh.
I'm wiped out right now, and Mypy has outstanding bugs to provide some of the functionality I want it to have to make Structured Data's consumers typecheck.
The rest of the functionality, the chat has yet to get back to me about, so who even knows at this point?
Not me, clearly.</p>
<p>I am spacing way out right now, so I'm kind of skeptical I can do anything significant right now.
I'll try to switch gears later, and for the moment work on bits of writing.</p>
<p>Hopefully, if I try to help/"help" with Mypy, I'll see my way to having a quicker turnaround time on my end than I did with Jedi.</p>
<p>Anyway, taking a break from crowbarring new capabilities in Python to try out some stuff from Word Mill Games.
In the past I've tried to work out a bunch of stuff up front and not gotten anywhere, so this time I'm trying to get moving with as little as possible.
We'll see how that works out, but for now, I once again need to go lie down.
It never ends.</p>
<p>Good night.</p>
Weekly Roundup 2019-09-102019-09-10T04:00:00-04:002019-09-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-10:/weekly-roundup-2019-09-10<p class="first last">It's a software development about cycles.</p>
<ul class="simple">
<li>Wednesday: I took a look at the Mypy plugin for Structured Data, which, strictly speaking, has never worked, as such.</li>
<li>Thursday: I got distracted by shiny mutation testing.</li>
<li>Friday: I switched to a shinier mutation testing framework. Then switched back to type checking. Came up with a big confusing design for how Product classes should work.</li>
<li>Saturday: Somewhat simplified the design.</li>
<li>Sunday: Reviewed the design until I realized that the current behavior is good enough until we have use cases demonstrating otherwise.</li>
<li>Monday: I took at easy on Sunday. (Which is the day I write about for Monday's post.)</li>
</ul>
<p>Next week, all I can think about right now is continuing to take it easy, because I am exhausted currently.</p>
Diary 2019-09-092019-09-09T04:00:00-04:002019-09-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-09:/diary-2019-09-09<p class="first last">Something something lazy Sunday.</p>
<p>I took it easy today, more or less.
I've been trying to do some preparation for yet more writing that probably wouldn't show up here, so there's that.</p>
<p>We're caught up on She-Ra and smoothly transitioned into wondering when the next season is, because that doesn't seem to be public knowledge yet, possibly because several months of low-grade stress/anxiety counts as "fan engagement" to Netflix's metrics.</p>
<p>Let's see, would I rather try for a longer post or try to get to bed as soon as possible?</p>
<p>...</p>
<p>Good night.</p>
Algebraic Data Types 2019-09-082019-09-08T04:00:00-04:002019-09-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-08:/algebraic-data-types-2019-09-08<p class="first last">Strategically redefining the parameters for success until I was done before I started.</p>
<p>Today's progress: I realized that I had not made quite as much progress as I previously thought!</p>
<p>Less flippantly, I realized that I'd thought the descriptor protocol was more powerful than I now think it reasonably can be, and I can't define an attribute in a base class that controls the behavior of assigning to that name in subclasses.</p>
<p>Which means that I can't define stuff in the base class that makes monkeypatching subclasses "just work".
Getting things to "just work" takes metaclass fiddling, and I don't think that's acceptable for a class that I want to allow arbitrary subclassing from.
I've dealt with enough nonsense juggling metaclasses in previous iterations of this project, and I'd rather find another way.</p>
<p>What I'm kind of leaning towards is some kind of proxy object that exposes the underlying function objects that the user defines for the specific protocol methods that <tt class="docutils literal">Product</tt> generates, and intercepts sets and deletes to translate them to operations on the class.
Therefore: monkeypatch the proxy, and the class updates appropriately.</p>
<p>Hm.
Somewhere in here, I forgot how I wanted to handle the case of defining stuff in a class, and then trying to <em>un</em>-define it in a subclass.
Probably assigning over the methods from the <tt class="docutils literal">Product</tt> class would work, and the main things I'm missing are: tests of this idea, and special-casing for the specific instance of: <tt class="docutils literal">__eq__</tt> was overridden, but <tt class="docutils literal">__ne__</tt> was not.</p>
<p>These tasks are much smaller, and I hope they're all I really need, because the designs I had before were really getting out of hand.</p>
<p>Oh hey, I had tests for some of this behavior already, and they pass. ... This project is too big.</p>
<p>Oh well, I was able to avoid some really unpleasant scope creep.
So, next task: translate a bunch of this logic into a form that Mypy can deal with, because, unfortunately, I'm pretty sure I need to mirror this stuff pretty closely to have any chance of getting things to match.</p>
<p>But, regardless, in terms of how much work I think I need to do, this post was <em>excellent</em> for progress.</p>
<p>Tomorrow, I would like to take a break I think, though.
And also wind down now.
Good night.</p>
Algebraic Data Types 2019-09-072019-09-07T04:00:00-04:002019-09-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-07:/algebraic-data-types-2019-09-07<p class="first last">Planning! It helps!</p>
<p>Bit of a stressful day at work today, so I unwound a bit, and then did a small amount of planning for Structured Data.
And that planning was very helpful!
It got me looking past special cases and such to see how things could cleanly generalize, and to think about how this stuff could actually be used in practice.
(An area which the current code sorely lacks.)</p>
<p>I need to give this stuff some names, but overall I think this stuff is a couple days work out, at most.
I don't want to work on it right now, and I'm probably not in a good condition to do so, so let's wrap up for now, and I'll get to work on this tomorrow.</p>
<p>Good night.</p>
Algebraic Data Types 2019-09-062019-09-06T04:00:00-04:002019-09-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-06:/algebraic-data-types-2019-09-06<p class="first last">Weeks of coding can save you hours of planning</p>
<p>I ended up trying out <a class="reference external" href="https://github.com/boxed/mutmut">mutmut</a>.
It's mostly a more polished and streamlined experience than Cosmic Ray was, although it did run into some areas where it should have timed out, but instead just stayed stuck in a loop.
I had to manually whitelist the lines responsible, to remove those cases.
All of this was pretty interesting, but when I looked over some of the mutations, I saw that they were to code that only matters in terms of type-checking.</p>
<p>Which means that if I want reasonable tests that catch those mutants, I need to add type-checking.
Which means that I need to finish the plugin.
Which means that I need to re-implement Product types.</p>
<p>Ugh, I don't want to do this right now, and to try to explain why I at least don't want to do it tonight, I'll plan out what needs to be supported.</p>
<p>There are three groups of methods: repr methods, equality methods, and ordering methods.
These methods are in one of three states: unimplemented, generated, and custom-implemented.
I tried to work out some elaborate interrelationships between order and equality methods, beyond the fact the generating order requires successfully generating equality, but I think that was a bad idea, and I'm just going to say:</p>
<ul class="simple">
<li>Unimplemented means the methods aren't in the class namespace, but something is probably visible due to the class hierarchy.</li>
<li>Generated methods do not use <tt class="docutils literal">super()</tt>, and act as pass-through when called from an "incompatible" class. (This can be implemented by checking the type of <tt class="docutils literal">self</tt> against the class they belong to.)</li>
<li>Custom methods can use <tt class="docutils literal">super()</tt>, and are visible when called from a "compatible" class: one in which the same method group is custom, and the fields list matches exactly. (Just names, or order as well. Not sure, leaning towards order.)</li>
</ul>
<p>A method group can't change its state after the subclass is initialized.
This means the following:</p>
<ul class="simple">
<li>It is an error to assign over a generated method.</li>
<li>It is an error to assign to an unimplemented method. (This <em>may</em> get relaxed, but I want to be cautious.)</li>
<li>It is not an error to assign to a custom method, but some manner of processing is needed.</li>
<li>It is acceptable to assign a dummy value to a method to make it custom, and later inject the actual implementation.</li>
<li>Deleting is probably not a thing that can be done, unless the custom and unimplemented groups can be unified.</li>
</ul>
<p>It might be that repr and equality are tri-state, and order is a boolean.
Maybe it's acceptable to switch between custom and unimplemented only if the associated option is <tt class="docutils literal">False</tt>.</p>
<p>I feel like it would be folly to move forward on this without doing more design work, so I guess that's what I've got to do next.</p>
<p>I'm really unlikely to get this right without sleep, so I should probably get on that soonish.
Good night.</p>
Algebraic Data Types 2019-09-052019-09-05T04:00:00-04:002019-09-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-05:/algebraic-data-types-2019-09-05<p class="first last">Describing what I'm doing, and thereby discovering that what I'm doing kind of doesn't make sense.</p>
<p>Looking more at the dataclasses plugin, I realize that, unsurprisingly, it's based on the implementation, so, if I want to have my code make sense, I'm going to have to mirror the implementation of the <tt class="docutils literal">__init_subclass__</tt> methods.</p>
<p>Several hours later, I got sidetracked because, well, I've heard about mutation testing, and here's a big well-tested code base for me to try it out on.
It really puts my coverage numbers into perspective, in that over a hundred mutations got past the tests.
Unfortunately, it's hard for me to act on this stuff right now, because the library I'm trying out right now, <a class="reference external" href="https://cosmic-ray.readthedocs.io/en/latest/index.html">Cosmic Ray</a>, I haven't figured out how to narrow down the results, and it's not really worth it to go through 700+ results to figure out which ones timed out, and why all the mutations that survived, did so.
I mean, I'm probably going to try to get some kind of mutation testing done before I consider this 1.0, but it turns out it's not worth it right now, and I should focus on sketching out the way those <tt class="docutils literal">__init_subclass__</tt> methods work.
So, let's see...</p>
<p>Sum.</p>
<p>Subclassing a subclass of Sum is an error.
It first checks that <tt class="docutils literal">eq</tt> and <tt class="docutils literal">order</tt> are compatible.
It then scans all annotations in the MRO, <em>backwards</em>, with non-Ctor values deleting the annotation.
When it gets to the final result, it creates a constructor for each Ctor annotation.
It creates a custom <tt class="docutils literal">__new__</tt>, which we can model as "cannot instantiate this class except through its constructors".
If there's no <tt class="docutils literal">__setattr__</tt> or <tt class="docutils literal">__delattr__</tt> defined, then those are disallowed.
There's basically the same logic around equality checking and hashing as in <tt class="docutils literal">dataclasses</tt>, and the some around order as well, pretty much.</p>
<p>The big differences from <tt class="docutils literal">dataclasses</tt> are that the arguments are passed to the class creation statement, there's no <tt class="docutils literal">frozen</tt> or <tt class="docutils literal">init</tt>, and the only annotations it counts use the Ctor form.</p>
<p>Product.</p>
<p>It first sets attributes on the class from the creation arguments, then relies on the values on the class for the remainder of the behavior.
It checks that <tt class="docutils literal">__eq</tt> and <tt class="docutils literal">__order</tt> are compatible.
It then scans all annotations in the MRO, <em>backwards</em>, with <tt class="docutils literal">None</tt> and <tt class="docutils literal">ClassVar</tt> values clearing the annotation.
It determines the default values, and errors if there are gaps.
It considers <tt class="docutils literal">inspect.Parameter.empty</tt> to mean "leave this unset".
It creates a custom <tt class="docutils literal">__new__</tt>, which we can model as "If the class defines a <tt class="docutils literal">__new__</tt> method, use it as-is, otherwise create a <tt class="docutils literal">__new__</tt> method based on the fields and defaults."
It checks what behavior to use for equality and ordering methods, at which point things get <em>weird</em>.
I think my informal specification for what this stuff does isn't sufficiently motivated by use-cases.
In plain English, this code is doing complicated, albeit consistent, stuff, possibly because I wanted to show off, and not for any better reason currently.
I think the current behavior may simply be broken for advanced use cases.
I think I can paper over the issues by making a new setter function that specifically checks for <tt class="docutils literal">None</tt> to decide whether it can set over, but that's a bit hacky, especially the way I'd employ it.
Maybe the thing to do is make all of the various special methods behave like its <tt class="docutils literal">__new__</tt> stuff currently does.
That'd be some effort, but my head wouldn't hurt as much, so it's probably a good idea.
I'll have to revisit this idea when I'm better-rested.
(Maybe instead of class identity, it keys off fields to determine whether to use the provided function?)
(This would also mean that the "setter" functions would inspect only the local namespace, and would also remove some dependencies.
I'm feeling good about this, but I can't do it right now.)</p>
<p>This was some good progress, but it's time to wrap up for now.
Good night.</p>
Algebraic Data Types 2019-09-042019-09-04T04:00:00-04:002019-09-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-04:/algebraic-data-types-2019-09-04<p class="first last">In which I remember how various things work.</p>
<p>Okay, I'd like to take a break from messing with Structured Data for now, so let's shift gears slightly to look at its Mypy plugin.</p>
<p>This is... oof.
I was in the middle of some kind of update to this code before I stopped for some reason, meaning that currently it looks like it probably shouldn't work.
Also, the interfaces are drastically changed now.</p>
<p>I mean, I guess the handling for <tt class="docutils literal">Ctor</tt> shouldn't really be different, but aside from that...</p>
<p>Previously, there was a single class decorator, <tt class="docutils literal">adt</tt>.
That's been replaced with the <tt class="docutils literal">Sum</tt> base class.
In addition, I've added the <tt class="docutils literal">Product</tt> base class, which is a souped-up combination of <tt class="docutils literal">NamedTuple</tt> and <tt class="docutils literal">dataclasses</tt>.</p>
<p>Okay, I've sort of remembered what I was doing: I was copying the way the dataclasses plugin is implemented, and it was full of confusing stubs because I hadn't gotten that far.
I've got a little bit of the redo done, but I just realized that, to test this, I'm going to need to release a new version of Structured Data.
I'm going to do that, and call that done for today.
I don't get much productive done on these entries after 10, anyway.</p>
<p>I'll take care of it while this uploads.
Good night.</p>
Weekly Roundup 2019-09-032019-09-03T04:00:00-04:002019-09-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-03:/weekly-roundup-2019-09-03<p class="first last">A bit of a slow week, oh well.</p>
<ul class="simple">
<li>Wednesday: I redid the Product classes.</li>
<li>Thursday: I improved some metrics in somewhat-questionable ways.</li>
<li>Friday: I showed off a particularly bad way to improve metrics, which I've since removed.</li>
<li>Saturday: I vaguely called for other people to critique my code.</li>
<li>Sunday: I burned myself out doing foolish things, which I then swore off.</li>
<li>Monday: I did some work on new features.</li>
</ul>
<p>Next week, I'll either try to start fresh on the plugin, or do something else.</p>
Algebraic Data Types 2019-09-022019-09-02T04:00:00-04:002019-09-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-02:/algebraic-data-types-2019-09-02<p class="first last">I'm trying to muddle through.</p>
<p>I fixed the issue I mentioned yesterday, and I'm at least trying to make things clearer in my own judgment.</p>
<p>In support of my whole "I don't think I should be blindly trusting metrics" thing, I note that I'm not seeing any focus on some really questionable uses of iterators and the <tt class="docutils literal">break</tt> statement, even though whenever I happen to look at them, I think "Yeah, that's a hack."
I'd like to figure out another way to handle them, but I'm having a lot of trouble doing so.</p>
<p>Oh well, it's late, or, at least, it feels late, and we did a bunch of traveling today so, um, I'm done.
Good night.</p>
Diary 2019-09-012019-09-01T04:00:00-04:002019-09-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-09-01:/diary-2019-09-01<p class="first last">Don't be like me. Have good judgment.</p>
<p>I didn't do enough with Structured Data today to feel like it could go in the category today, so it's not.
I basically just filed one issue that'll probably be kind of a pain to address, but promises to make the overall implementation kind of... be forced to make more sense, I expect.</p>
<p>Besides that, let's see...
We've been watching She-Ra and the Princesses of Power finally.
It's pretty good.</p>
<p>I've decided that I'm not going to pay attention to the Duolingo leaderboards any more, because I just tried actually engaging with them, and that was just... too much.
Like, I feel like a shounen character who just did their ultimate finishing move, but it was in the service of <em>acquiring virtual currency</em>.
Having done that, my advice is, <em>don't</em>.
I know I won't be.</p>
<p>And, I can't string together a sentence usefully now.
Not much.
I guess that's it.
Good night.</p>
Algebraic Data Types 2019-08-312019-08-31T04:00:00-04:002019-08-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-31:/algebraic-data-types-2019-08-31<p class="first last">I don't think I can do this alone.</p>
<p>I was mostly doing other stuff today, but I'm trying to look over Structured Data's code with fresh eyes.
It's somewhat tricky.
Scratch that, it's really freaking hard to disregard my knowledge about how this all fits together.
If I want to get this code into a state where I can be proud of it, I need to get someone else's perspective on it.</p>
<p>I'm asking around elsewhere, and I just pushed some updates to the GitHub page at <a class="reference external" href="https://github.com/mwchase/python-structured-data">https://github.com/mwchase/python-structured-data</a>.
I guess that's all there is for me to say right now.
I need to wind down; it's too hot to think.
Good night.</p>
Algebraic Data Types 2019-08-302019-08-30T04:00:00-04:002019-08-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-30:/algebraic-data-types-2019-08-30<p class="first last">Complexity metrics considered... mostly orthogonal to relevant concerns.</p>
<p>Presented without context:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">_conditional_update</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">attrs_and_values</span><span class="p">):</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">attrs_and_values</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="nb">setattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
<span class="o">...</span>
<span class="k">class</span> <span class="nc">Product</span><span class="p">(</span><span class="n">ADTConstructor</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">__init_subclass__</span><span class="p">(</span>
<span class="bp">cls</span><span class="p">,</span>
<span class="o">*</span><span class="p">,</span>
<span class="nb">repr</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="c1"># pylint: disable=redefined-builtin</span>
<span class="n">eq</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="c1"># pylint: disable=invalid-name</span>
<span class="n">order</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="o">**</span><span class="n">kwargs</span>
<span class="p">):</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">__init_subclass__</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="n">overrides</span> <span class="o">=</span> <span class="n">types</span><span class="o">.</span><span class="n">SimpleNamespace</span><span class="p">()</span>
<span class="c1"># This is really gross, but it seems to work, and it reduces the</span>
<span class="c1"># cyclomatic complexity, so it must be good!</span>
<span class="n">overrides</span><span class="o">.</span><span class="n">__repr</span> <span class="o">=</span> <span class="nb">repr</span> <span class="c1"># pylint: disable=protected-access</span>
<span class="n">overrides</span><span class="o">.</span><span class="n">__eq</span> <span class="o">=</span> <span class="n">eq</span> <span class="c1"># pylint: disable=protected-access</span>
<span class="n">overrides</span><span class="o">.</span><span class="n">__order</span> <span class="o">=</span> <span class="n">order</span> <span class="c1"># pylint: disable=protected-access</span>
<span class="n">_conditional_update</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="nb">vars</span><span class="p">(</span><span class="n">overrides</span><span class="p">))</span>
</pre></div>
<p>I have a <em>problem</em>.</p>
<p>And part of that problem is blindly trusting code metrics because they're hooked up to a SaaS that serves up a badge.</p>
<p>I'm about ready to revisit the Mypy plugin like I think I mentioned, but the way I've responded to having the metrics move around in unfavorable ways in after I implemented Products has me thinking that right now I need to think about what "quality" means in the context of this code, and whether these GitHub badges are actually delivering anything helpful.</p>
<p>I believe what I should actually be trying to do is make it easy for people who aren't me to understand my code.
And I haven't been doing that.
For example, one common thing I've gone and done is, I've put tiny conditionals into functions and factored them out, because that makes most complexity metrics think my functions are straightforward.
It's like, I'm acting like I'm tricking the rating service, but I'm really just cheating the code by splitting it up into chunks with a cyclomatic complexity of around 5.</p>
<p><em>On the other hand</em>, I think the stack iteration concept came from similar attempts to grind out branches, and I actually like that.
The core logic is confined to a tiny file, and all the code that consumes it has to do is typecheck... which I don't <em>currently</em> check, but it's possible in principle.</p>
<p>So, I guess what I think is that helpful abstractions might not always jump out at me, and maybe my focus should be on "Okay, does this part of the code make sense, and can I make simple changes that would improve it on that axis?"</p>
<p>Once I've dealt with that some, though, I'm almost certainly going to back out the changes I excerpted above, because that code is <em>ridiculous</em>.</p>
<p>In any case, to make improvements here, I can't rely on tools to tell me what to focus on.
I'm going to have to rely on... my own judgment!</p>
<div class="youtube youtube-16x9"><iframe src="https://www.youtube.com/embed/a1Y73sPHKxw" allowfullscreen seamless frameBorder="0"></iframe></div><p>(Haha, I was legally a child when that video was posted over ten years ago.
*crumbles into dust*)</p>
<p>Anyway, I don't have anything more for now.
Good night.</p>
Algebraic Data Types 2019-08-292019-08-29T04:00:00-04:002019-08-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-29:/algebraic-data-types-2019-08-29<p class="first last">I probably shouldn't be allowed access to complexity metrics.</p>
<p>Brief status update: I'm dividing my time between noticing new bugs in the ADT code introduced by the amazing amount of churn I've given it in the past few weeks, non-virtuously increasing my code ratings mostly by figuring out how to hide cyclomatic complexity, and more-virtuously increasing my Pylint scores mostly by documenting things thoroughly.</p>
<p>Once I've finished pushing cyclomatic complexity to just barely acceptable, I'll work on pulling out standalone functions into their own modules, which should take some pressure off.</p>
<p>And once <em>that's</em> done, I'll cut a new minor version, and then start looking into reviving the Mypy plugin, which, I don't know what that needs precisely, but it's probably changed since the last time I tried to work on it.</p>
<p>I'm zoning out, so that means this entry has to be over.
Good night.</p>
Algebraic Data Types 2019-08-282019-08-28T04:00:00-04:002019-08-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-28:/algebraic-data-types-2019-08-28<p class="first last">In which machines try to tell me how to talk to people.</p>
<p>Okay, I'm going to try to make this quick:</p>
<p>I've been doing a lot of work getting Product classes to behave in a manner that makes sense to me.
In the process, I tanked some of the code metrics, and, unusually for me, I'm kind of having trouble caring about it.
Basically, the various sites have a bunch of complaints, mostly around the <tt class="docutils literal">__init_subclass__</tt> methods, which have a lot of stuff in them <em>because they have to do a lot of stuff</em>.
I could chop them up into smaller semi-independent bits, as I have in the past, but it's really obnoxious to navigate the file as-is, so I kind of doubt further indirection would make things clearer.</p>
<p>What I'm basically leaning towards in terms of architecture is that there's a thin layer of generated methods in each Product subclass, coupled with enough metadata for methods defined on the base class to dynamically change their behavior.
Each subclass has to do a lot of heavy lifting to generate this metadata, so, for the time being, the methods will be big.</p>
<p>I'm pretty sleepy right now, so this is kind of disorganized, but I decided to try running Pylint against the code to see what I can do to improve it.
As per usual, I found a bunch of weird bugs in Pylint.
I guess that's the next thing to work on, filing those.</p>
<p>I've got maybe ten more minutes of consciousness left, though.
Good night.</p>
Weekly Roundup 2019-08-272019-08-27T04:00:00-04:002019-08-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-27:/weekly-roundup-2019-08-27<p class="first last">Week of the somewhat functional prototypes.</p>
<ul class="simple">
<li>Wednesday: I started working on figuring out what features Structured Data needs.</li>
<li>Thursday: I started specifying how I'd like to process the coverage database.</li>
<li>Friday: I thought about the successor to Divide and Cover.</li>
<li>Saturday: I made a prototype of the successor to Divide and Cover.</li>
<li>Sunday: I got the prototype working well enough.</li>
<li>Monday: I tossed together a prototype of some of the new features in Structured Data. It was pretty buggy, is probably still pretty buggy, and when I look at the code, I think it should have bugs that it doesn't seem to, so that's weird.</li>
</ul>
<p>Next week, I'm going to try explaining the new code in Structured Data, because as I mentioned above, there's stuff going on right now that's a mystery even to me.</p>
Algebraic Data Types 2019-08-262019-08-26T04:00:00-04:002019-08-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-26:/algebraic-data-types-2019-08-26<p class="first last">I should probably pay a bit less attention to code metrics, given that they're not saying anything about the code that bothers me the most...</p>
<p>After a bunch of hacking, I have a prototype implementation of product types for Structured Data.
Since I just now got the tests to pass, it's probably pretty bad, but I don't care right now.</p>
<p>It's nice to have a clear vision for the stuff I want to work on again.
Makes it possible to just point myself at a task and go.</p>
<p>I think maybe later I'll try to explain what's up with the product types, but right now I should really get ready for bed.
Good night.</p>
Diary 2019-08-252019-08-25T04:00:00-04:002019-08-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-25:/diary-2019-08-25<p class="first last">This tiny repository brought to you by Poetry.</p>
<p>Following a night of some sort of sleep, I ironed out the issues in the project, now called <tt class="docutils literal"><span class="pre">limit-coverage</span></tt>, and put up a barebones prototype on <a class="reference external" href="https://github.com/mwchase/limit-coverage">GitHub</a> and <a class="reference external" href="https://pypi.org/project/limit-coverage/">PyPI</a>.</p>
<p>I'm planning to, instead of redoing the old in-code metadata thing I had, figure out a config file format and have the metadata in there.
If test code wants to access the metadata, it can query the file the same way as the script will.</p>
<p>That all seems pretty reasonable.
Because limit-coverage currently fulfills my needs well enough, my next plan is to start working on the fiddly refactors and internal documentation required to get Structured Data to support product types.</p>
<p>I don't think I have the focus to talk about this any further right now.
I'm mostly just having conversations with myself in the issue comments.
Okay, can't keep this up any longer.
Good night.</p>
Diary 2019-08-242019-08-24T04:00:00-04:002019-08-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-24:/diary-2019-08-24<p class="first last">It almost worked on the second try. Pretty cool.</p>
<p>All right, I've got a prototype of the successor to Divide and Cover.
I'm calling it limit-cover for now, and I'm thinking I'll just test it directly on Structured Data, rather than getting it set up in PyPI and such first.</p>
<p>I just confirmed that Structured Data's tests don't customize the module discovery any, so I don't need to worry about those features yet.</p>
<p>And, something is broken, but I'm too tired to figure out what.
Better sleep on it.
Good night.</p>
Diary 2019-08-232019-08-23T04:00:00-04:002019-08-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-23:/diary-2019-08-23<p class="first last">What was once a nightmare of copy-and-pasted code run through with minor patches, will now be... probably a couple dozen lines of code.</p>
<p>I've got my notes from yesterday on Divide and Cover reimplementation.
It shouldn't be too hard to put together a non-optimized version.
I've started sketching that out, but I'd like to switch to paper for a bit first, to sketch things out without worrying about whether it's executable.</p>
<p>But for now I'm loopy and tired, so, um, another short entry.
It shouldn't take more than a few days to get this done; I'm about as excited right now as I can be, which is not much, what with being so tired.</p>
<p>Good night.</p>
Diary 2019-08-222019-08-22T04:00:00-04:002019-08-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-22:/diary-2019-08-22<p class="first last">There's dead code in Divide and Cover. <em>Why is there dead—</em></p>
<p>Notes on processing the coverage database:</p>
<ul class="simple">
<li>There is one context with an empty name. It is valid coverage for all arcs, and should be associated with the first statement in each file.</li>
<li>All coverage within test modules is valid.</li>
<li>All other names are module paths to test modules. The default target can be extracted by the regex <tt class="docutils literal"><span class="pre">tests.(.*\.)test_([^.]*)\.[^.]*</span></tt> or something like that, I just eyeballed it.</li>
<li>The file names are stored as absolute paths. They should be converted into paths relative to the cwd, probably.</li>
<li>I expect files to include the tests under the <tt class="docutils literal">tests</tt> directory, and the code under test, in the <tt class="docutils literal">src/whatever</tt> directory. I <em>guess</em> I should try to support the src-less layout.</li>
<li>In any case, the file paths can be converted into module paths.</li>
<li>Then, the following expansions can occur: test file to all contexts that originate from it, and test file to the files associated with all modules considered to be under test for it.</li>
<li>From there, it's a matter of discarding all arcs where the combination of file_id and context_id doesn't match any known combination.</li>
</ul>
<p>I'm kind of rusty on doing sophisticated things with SQL in a non-terrible way; I don't know if there's an efficient way to do that.</p>
<p>Okay, I pushed this entry as late as I could; later, probably.
I have to call it now.
Good night.</p>
Algebraic Data Types 2019-08-212019-08-21T04:00:00-04:002019-08-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-21:/algebraic-data-types-2019-08-21<p class="first last">"Doesn't the stdlib have that?" Eeeeenh...</p>
<p>I did a survey of my uses of the <tt class="docutils literal">data</tt> keyword in Dennis, to figure out what functionality I want to have in Structured Data, or possibly new libraries.
The three things I concluded I needed, in priority order, are:</p>
<ul class="simple">
<li><a class="reference external" href="https://github.com/mwchase/python-structured-data/issues/20#issuecomment-523260449">Product types that behave how I want them to</a></li>
<li><a class="reference external" href="https://github.com/mwchase/python-structured-data/issues/23">Attribute forwarding for enums (possibly a new project)</a></li>
<li><a class="reference external" href="https://github.com/mwchase/python-structured-data/issues/24">More Haskell-ish destructuring function definition</a></li>
</ul>
<p>That first item is a little disappointing, but namedtuples are just so aggravating to do serious work with, outside of their use cases.</p>
<p>Before I start messing with these ideas, I want to figure out how to process the coverage divide-and-cover style.
(This would be more like cover-and-divide, I guess.)
And probably make other changes to the tooling for the project.</p>
<p>I can't figure out how to write about this in more detail than I put in the issues.
So, um, calling it here.
Good night.</p>
Weekly Roundup 2019-08-202019-08-20T04:00:00-04:002019-08-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-20:/weekly-roundup-2019-08-20<p class="first last">I can't work in these conditions. I've just been stewing in sweat for weeks, and it's really unpleasant. Would not recommend.</p>
<ul class="simple">
<li>Wednesday: I was sweaty and tired.</li>
<li>Thursday: I did a little work on Revelation.</li>
<li>Friday: I was burnt out and tired.</li>
<li>Saturday: I started thinking about getting back to Structured Data.</li>
<li>Sunday: I started hacking on Structured Data again.</li>
<li>Monday: I did some more work on Structured Data.</li>
</ul>
<p>Next week, I'm going to write up all uses of the <tt class="docutils literal">data</tt> keyword in Dennis, and hopefully convert Seed to Cell finally.</p>
Algebraic Data Types 2019-08-192019-08-19T04:00:00-04:002019-08-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-19:/algebraic-data-types-2019-08-19<p class="first last">Some people didn't see the point of PEP 570. They were objectively wrong.</p>
<p>I continue to wilt in this heat.
Just a month-ish more, I hope.</p>
<p>I just took a cursory look at Structured Data to make sure I wasn't missing anything when I just kind of ripped stuff out; I think I might need more doctests.
But it looks like removing guards didn't alter the documentation, which... eh?
I'll try to get back to it, but first, I read <a class="reference external" href="https://www.jwz.org/blog/2019/08/join-twitter-today/">another blog</a>, and it's clear to me that in addition to fixing things so that there are actual links to all of the pages I'm generating, I need to seriously up my aesthetic game.
Ideally in some kind of opt-in way.
More on Structured Data... the highest-priority bug is probably the documentation.
Let's see what state that's in...
Everything visible in the documentation is documented, but I should probably see if there are any return types that can show up...</p>
<p>I decided to add bits of documentation and annotation here and there, and ended up checking on the issues being flagged by the various code inspection services I have hooked up to the repo.
And then undoing a bunch of ignores, and pushing more changes, to see what happens.
The result is confusing.
I'll have to check on it later to see if it manages to make sense.</p>
<p>I'm going to figure out what's actually needed to get this to 1.0.
Previously, things were kind of stalled out by the immense complexity of a design that attempted to subsume the basic concepts of function application into a more declarative framework, which was also a bad idea for a single-person project that didn't specifically need the capabilities that would provide.
Now that that plan has been replaced with "ask people to write functions specific to their use-case", I think maybe I need to redo my limited-to-myself requirements gathering and see how Dennis does what it does.</p>
<p>That's enough messing around for tonight.
Good night.</p>
Algebraic Data Types 2019-08-182019-08-18T04:00:00-04:002019-08-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-18:/algebraic-data-types-2019-08-18<p class="first last">I wrote long posts a year ago, wow.</p>
<p>I decided to work a little on Structured Data, oh, about half an hour ago.
I first increased the required version of Coverage, then I started removing code that I realized I didn't need.
Now that that's done for now, I'd like to take a look at the generated coverage data and see about making filters for it.
I think it basically needs to be some kind of Python script that takes the sqlite database and does some heavy processing to it to remove coverage that "doesn't count".
Once I've written that script, I'll get it into the Cell for Python, probably inside the noxfile.
But first I need to turn Seed into Cell.</p>
<p>It's way too late already.
Good night.</p>
Diary 2019-08-172019-08-17T04:00:00-04:002019-08-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-17:/diary-2019-08-17<p class="first last">I wish it were easier to distinguish burnout from background-level executive dysfunction.</p>
<p>I set myself some goals in a new bug on Structured Data today.
I'm kind of interested in getting back to it this weekend, now that I've got a nicely reduced scope for it.
Also, getting the tooling updated is good for getting things put together right in the Python Cell project, which, um, I haven't actually renamed Seed to Cell on the filesystem.
Anyway, this'll be good work to do while I wait for a new Pijul release.</p>
<p>I spent most of today hanging around and playing some newly acquired games.
Also waiting for the Nova Drift updates to reach Itch.</p>
<p>Do I think I have the wherewithal to do something that'll give me something more substantial to put in this entry? ... No.
Good night.</p>
Diary 2019-08-162019-08-16T04:00:00-04:002019-08-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-16:/diary-2019-08-16<p class="first last">My body will remember how to handle a basic amount of exercise eventually.</p>
<p>Ugh.
Just wanted to play games and zone out.
Maybe tomorrow I'll look at the state of Structured Data, to take a break from Revelation.
I don't know.</p>
<p>Good night.</p>
Revelation 2019-08-152019-08-15T04:00:00-04:002019-08-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-15:/revelation-2019-08-15<p class="first last">Progress and exhaustion</p>
<p>I just now got working a bit on my first test character for the Urban Fantasy setup.
The result thus far is definitely something.</p>
<p>I've got the vague idea that some of the randomness provided by the game is in some form of gnomic combinations of words, that imply a situation without spelling things out.</p>
<p>Anyway, I made a crack earlier about project management, and I probably should put the stuff I have so far into a todo list.</p>
<p>I think what I would like to do, is publish this post, and while it publishes, throw that todo list together.
That sounds nice, to my sleepy sleepy brain.
Good night.</p>
Diary 2019-08-142019-08-14T04:00:00-04:002019-08-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-14:/diary-2019-08-14<p class="first last">Everything is sore.</p>
<p>I can't work on Revelation today.
I got behind on exercise for a while because it was so dreadfully hot, and I started back up this week to get some of the weight off (and keep cholesterol to healthy levels I guess, can't measure that easily), and I was okay-ish yesterday, but now I'm wiped out.</p>
<p>For Revelation, it might be a good idea for me to come up with a character concept and put it through story-telling, seeing when I want to invoke randomness.</p>
<p>Anyway, I was trying to trick myself into getting something done, but it's not happening, so, um, good night.</p>
Weekly Roundup 2019-08-132019-08-13T04:00:00-04:002019-08-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-13:/weekly-roundup-2019-08-13<p class="first last">Conflicting Revelations</p>
<ul class="simple">
<li>Wednesday: I introduced the Revelation project, which continues the vague trend of giving my hobby projects overly portentous names. (I mean, I guess "Dennis" isn't too ridiculous, but some of the others make up for it.)</li>
<li>Thursday: I moved the Revelation project to <span class="math">\(\TeX{}\)</span>.</li>
<li>Friday: I moved the Revelation project again, this time to TiddlyWiki and Timimi, and then didn't touch that for the rest of the week.</li>
<li>Saturday: I scribbled stuff relating to the Revelation project.</li>
<li>Sunday: I tried to figure out what content I should be working on for the Revelation project.</li>
<li>Monday: I tried to prioritize the things I came up with for the Revelation project, and pondered how to make the core gameplay loop, like, work.</li>
</ul>
<p>Next week, I'm going to keep up the focus on the Revelation project, but also, today I had some thoughts about Structured Data, which I want to revisit later because I'd like to not have to use Coconut for stuff like Dennis.</p>
<script type='text/javascript'>if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
var align = "center",
indent = "0em",
linebreak = "false";
if (false) {
align = (screen.width < 768) ? "left" : align;
indent = (screen.width < 768) ? "0em" : indent;
linebreak = (screen.width < 768) ? 'true' : linebreak;
}
var mathjaxscript = document.createElement('script');
mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
mathjaxscript.type = 'text/javascript';
mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';
var configscript = document.createElement('script');
configscript.type = 'text/x-mathjax-config';
configscript[(window.opera ? "innerHTML" : "text")] =
"MathJax.Hub.Config({" +
" config: ['MMLorHTML.js']," +
" TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
" jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
" extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
" displayAlign: '"+ align +"'," +
" displayIndent: '"+ indent +"'," +
" showMathMenu: true," +
" messageStyle: 'normal'," +
" tex2jax: { " +
" inlineMath: [ ['\\\\(','\\\\)'] ], " +
" displayMath: [ ['$$','$$'] ]," +
" processEscapes: true," +
" preview: 'TeX'," +
" }, " +
" 'HTML-CSS': { " +
" availableFonts: ['STIX', 'TeX']," +
" preferredFont: 'STIX'," +
" styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
" linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
" }, " +
"}); " +
"if ('default' !== 'default') {" +
"MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
"var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
"VARIANT['normal'].fonts.unshift('MathJax_default');" +
"VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
"VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
"VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
"});" +
"MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
"var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
"VARIANT['normal'].fonts.unshift('MathJax_default');" +
"VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
"VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
"VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
"});" +
"}";
(document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
(document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
</script>Revelation 2019-08-122019-08-12T04:00:00-04:002019-08-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-12:/revelation-2019-08-12<p class="first last">Rudimentary project management.</p>
<p>You know how you can't always control inspiration, and choose what you're going to write about?
That's why I'm trying to get the work on Revelation done now, at like 10:30, after a day of writing... stuff.</p>
<p>Let's take a look at the stuff I came up with yesterday and at least try to prioritize it.</p>
<ul class="simple">
<li>Plot hooks</li>
<li>Factions and alliances</li>
<li>Optional character connections</li>
<li>Spells</li>
<li>Customization</li>
<li>Protagonist-only abilities</li>
<li>Drawbacks</li>
</ul>
<p>And figuring out which resources to track is its own thing.</p>
<p>My gut inclination with plot hooks is to bias them towards some kind of investigative play, but I'm not sure if an investigative solo game is even a thing like this.
I kind of want it to be.</p>
<p>Let's think about this in terms of like mad libs...
Something is not as it should be, and the people who care about this particular problem can't see how to fix it.
It seems to me like there should be some element of mystery to any kind of narrative, even if it's not a mystery or a detective story per se, but what I'm visualizing currently is something like the player is making up the mystery as they uncover it, which means that if there's any kind of random element, then there's no check on the plausibility of what shakes out, and if there's no random element, then the player is essentially working things out ahead of time and sending their character through a kind of investigative obstacle course.</p>
<p>Maybe the most I should aim for in terms of mystery is some kind of "mysterious occurences" table that basically just provides atmosphere.</p>
<p>Maybe I should do some research instead of trying to work out all of this from first principles...</p>
<p>Okay, I found some other efforts in this area that I think are giving me some ideas.</p>
<p>First up, the primary thing the player needs is a Goal.
This is a statement that informs their character's decisions, and ultimately is either attained or discarded.
There should probably be general moves for "when you forsake your goal for something else" and "when you forsake something else for your goal".</p>
<p>I'd like to get more done, but I'd also like to sleep, and I think sleep now and more stuff later and better than sleep later and not as much stuff now.
Good night.</p>
Revelation 2019-08-112019-08-11T04:00:00-04:002019-08-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-11:/revelation-2019-08-11<p class="first last">Nothing, nothing, oh no, I have to do a post, do all of the work in the ten minutes after my self-imposed deadline.</p>
<p>I got distracted from working much on Revelation today, but I'm still putting in in the category because nyeh.
Before I start trying to code stuff in, or to work out how best to code it in, I need to think about how to add breadth and depth to the character creation.
That means adding onto the list of options I've come up with for specific categories, but more importantly, and less worked-on-thus-far, is to get more categories to put stuff in.</p>
<p>Right now, I've got stuff roughed out for "how did you enter the masquerade?" and "what mundane skills are you bringing to the table?"
I'm going to need to work on stuff such as:</p>
<ul class="simple">
<li>Spells</li>
<li>Plot hooks</li>
<li>Optional character connections</li>
<li>Figuring out what resources I want the player to track, and how they can obtain and spend them.</li>
<li>Factions and alliances</li>
<li>Drawbacks?</li>
<li>Fancy protagonist-only abilities.</li>
<li>General customization such as overall elemental affinity, perhaps.</li>
</ul>
<p>I'm going to need to prioritize all of this stuff and figure out what to try to work on first, because it's probably not all strictly necessary, but it would mostly be nice.</p>
<p>It is actually taking an absurd amount of effort to type this.
I should have just bailed on this for today.</p>
Revelation 2019-08-102019-08-10T04:00:00-04:002019-08-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-10:/revelation-2019-08-10<p class="first last">A productive day with a short writeup.</p>
<p>As planned, today I focused on roughing stuff out on paper.
I basically have some very rough wireframes of what the different kinds of tiddler should look like for this project.
My plan now is to work on content a bit more, either on paper or in a text editor, so I end up with some idea of what functionality I need to support the mechanics.</p>
<p>I guess I don't have anything more to say really, and I'm suddenly really tired.
Good night.</p>
Revelation 2019-08-092019-08-09T04:00:00-04:002019-08-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-09:/revelation-2019-08-09<p class="first last">Losing momentum to getting annoyed with tools; hopefully done with that.</p>
<p>As I was saying yesterday, I switched off of <span class="math">\(\TeX{}\)</span>, more or less.
I'm trying to migrate to a <a class="reference external" href="https://tiddlywiki.com/">TiddlyWiki</a>.
I'm trying out <a class="reference external" href="https://beakerbrowser.com/">Beaker Browser</a> for this.
It's similar to <a class="reference external" href="https://github.com/Jermolene/TiddlyDesktop/">TiddlyDesktop</a> in that, judging by my initial impressions of Beaker and my memories of TiddlyDesktop, neither one has spellcheck for TiddlyWiki.</p>
<p>I'm now trying out some Firefox extensions, which work, as long as the file is in the downloads directory.
<a class="reference external" href="http://gunshowcomic.com/648">This is fine.</a>
In all seriousness, I'll see what I think.
It just feels weird to be shoving stuff in my downloads directory on purpose.</p>
<p>This was such a smoother user experience like ten years ago.
Oh well.</p>
<p>Moving on from technical difficulties, I started throwing stuff—</p>
<p>Wait, no, I just tried <a class="reference external" href="https://ibnishak.github.io/Timimi/">Timimi</a> and this is great.
Seamless.</p>
<p>Anyway, I started copying stuff into tiddlers, and now I know I need to actually make a dang outline of how this stuff is meant to fit together.
The general way I want this to work is that the first tiddler shown gives an overview of things, focusing on qualitative descriptions and keeping the tables out of the way.
Then, if the player sees something with interesting flavor, they can drill into it for mechanical details.</p>
<p>I'll try and get that outlining done tomorrow, but I just went from "pretty sleepy" to "<strong>really sleepy</strong>" so, um, good night.</p>
<script type='text/javascript'>if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
var align = "center",
indent = "0em",
linebreak = "false";
if (false) {
align = (screen.width < 768) ? "left" : align;
indent = (screen.width < 768) ? "0em" : indent;
linebreak = (screen.width < 768) ? 'true' : linebreak;
}
var mathjaxscript = document.createElement('script');
mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
mathjaxscript.type = 'text/javascript';
mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';
var configscript = document.createElement('script');
configscript.type = 'text/x-mathjax-config';
configscript[(window.opera ? "innerHTML" : "text")] =
"MathJax.Hub.Config({" +
" config: ['MMLorHTML.js']," +
" TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
" jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
" extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
" displayAlign: '"+ align +"'," +
" displayIndent: '"+ indent +"'," +
" showMathMenu: true," +
" messageStyle: 'normal'," +
" tex2jax: { " +
" inlineMath: [ ['\\\\(','\\\\)'] ], " +
" displayMath: [ ['$$','$$'] ]," +
" processEscapes: true," +
" preview: 'TeX'," +
" }, " +
" 'HTML-CSS': { " +
" availableFonts: ['STIX', 'TeX']," +
" preferredFont: 'STIX'," +
" styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
" linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
" }, " +
"}); " +
"if ('default' !== 'default') {" +
"MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
"var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
"VARIANT['normal'].fonts.unshift('MathJax_default');" +
"VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
"VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
"VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
"});" +
"MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
"var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
"VARIANT['normal'].fonts.unshift('MathJax_default');" +
"VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
"VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
"VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
"});" +
"}";
(document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
(document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
</script>Revelation 2019-08-082019-08-08T04:00:00-04:002019-08-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-08:/revelation-2019-08-08<p class="first last">Extreme fanciness for minimal effort, wasted?</p>
<p>I decided that for today, I'd focus on just transferring the current draft of the prototype Revelation system, which is kind of a generic urban-fantasy thing, in TeX.
Excuse me, <span class="math">\(\TeX{}\)</span>.
(In draft view, that last bit keeps on taking a sec to render, then rendering properly, then glitching out.
Computers!)
This is different from the way it seems like most people create similar content, and it might have been a mistake to do it this soon.
Probably I should be working on getting stuff down on paper.</p>
<p>Anyway, let's think about organization.
Basing stuff off the moves from PbtA stuff kind of bakes in an assumption that there's long-term stuff to keep track of, so it might make sense to try creating a character sheet.
On the other hand, I want to avoid raising the barrier to entry for authoring Revelation content too high.</p>
<p>Anyway, it seems to me that the most important things to put on a character sheet are various stats and attributes, and the conditions under which the different moves are triggered, and either the text of the move, or a reference to it.
Putting it like this suggests to me another possible medium for Revelation: TiddlyWiki.
The various choices and moves could be their own tiddlers, and have some kind of preview rendering for the big lists.
And, it could perhaps be possible to incorporate character creation workflows into the wiki itself.
That can be a stretch goal; the basics would be a good thing to work on... later.</p>
<p>I've got to wrap things up quickly here.
Good night.</p>
<script type='text/javascript'>if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
var align = "center",
indent = "0em",
linebreak = "false";
if (false) {
align = (screen.width < 768) ? "left" : align;
indent = (screen.width < 768) ? "0em" : indent;
linebreak = (screen.width < 768) ? 'true' : linebreak;
}
var mathjaxscript = document.createElement('script');
mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
mathjaxscript.type = 'text/javascript';
mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';
var configscript = document.createElement('script');
configscript.type = 'text/x-mathjax-config';
configscript[(window.opera ? "innerHTML" : "text")] =
"MathJax.Hub.Config({" +
" config: ['MMLorHTML.js']," +
" TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
" jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
" extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
" displayAlign: '"+ align +"'," +
" displayIndent: '"+ indent +"'," +
" showMathMenu: true," +
" messageStyle: 'normal'," +
" tex2jax: { " +
" inlineMath: [ ['\\\\(','\\\\)'] ], " +
" displayMath: [ ['$$','$$'] ]," +
" processEscapes: true," +
" preview: 'TeX'," +
" }, " +
" 'HTML-CSS': { " +
" availableFonts: ['STIX', 'TeX']," +
" preferredFont: 'STIX'," +
" styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
" linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
" }, " +
"}); " +
"if ('default' !== 'default') {" +
"MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
"var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
"VARIANT['normal'].fonts.unshift('MathJax_default');" +
"VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
"VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
"VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
"});" +
"MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
"var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
"VARIANT['normal'].fonts.unshift('MathJax_default');" +
"VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
"VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
"VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
"});" +
"}";
(document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
(document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
</script>Revelation 2019-08-072019-08-07T04:00:00-04:002019-08-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-07:/revelation-2019-08-07<p class="first last">Powered by <em>something</em></p>
<p>Okay, I'm writing this at like 11, so I'm not going to have examples handy to point at, of the stuff I'm describing.
A while ago, I encountered the definition of "Choose Your Own Adventure" that parts of the internet are using now.
Given how trademark protection has been for that term, and the fact that it bears little resemblance to the books that bear the name, I'll be moving right along from it, and switch to talking about the iteration on it that I'm going to try to design, which is currently called, for reasons that will later become less non-obvious, the Revelation (Meta-)System.</p>
<p>Before describing Revelation, I'll try to describe its direct inspiration.
These so-called "CYOAs" are typically presented in the format of one or more images of somewhat reasonable width and utterly ridiculous height.
There is usually an introduction at the beginning, and the remainder is mostly rows of titled and captioned pictures corresponding to things players can take for a "build", providing they meet the requirements, such as number of points, or other things.
So, in a fantasy theme, a player might have the option to select proficiency with a bow, or affinity for different schools of magic.
In a science-fiction theme, there could be options for cybernetic implants, or otherworldly allies.
The thing that kind of bothered me, and maybe it doesn't bother many other people, is that once the player designs their build, they can't precisely "test" it.
There are no facilities for putting builds through their paces more rigorous than free-form RP.
So I tried to figure out a variation on the format that would allow a player who wants a feeling that the destiny of their build is being decided, in part, by impartial forces.</p>
<p>Revelation is supposed to be a small core of rules, and guidelines for expanding on them.
The intention is that allows authors can put in somewhat more effort than is required to design a typical "cyoa", but the result is similar to a solo-able tabletop RPG.
So far, I have two ideas that I'm going to try to use for this: rolls as in various "Powered by the Apocalypse" games, and d66 tables, from which rolling is sometimes mandatory, but in other contexts, the player can choose freely.</p>
<p>For now, I'm just working on a single system that's honestly probably not going to be too interesting, but I want to work my way up to having some kind of core rules, and then each specific system adds in some common rules, and each choice the player can make brings in rules that are specific to that choice.</p>
<p>One thing that I'm going to have to see how it shakes out is, everything I've come up with so far just adds length to the document, and I don't have a good idea of where it should go, whether there should be cross-links of some kind.
I also want these to be primarily some kind of hypertext, because navigating text in the form of image galleries is obnoxious, at least to me.</p>
<p>I'm currently roughing out how things are set up in the first system, but it's slow going right now, and probably a case for outlining.
I'll try to get on that tomorrow.</p>
<p>Okay, I'm not at an obvious end-point, but it's midnight, so, I want to end this, regardless.
Good night.</p>
Weekly Roundup 2019-08-062019-08-06T04:00:00-04:002019-08-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-06:/weekly-roundup-2019-08-06<p class="first last">What does it take to have a vacation be relaxing?</p>
<ul class="simple">
<li>Wednesday: I tried to reason through some stuff I want to have in Seed.</li>
<li>Thursday: I tried to outline. It went meh.</li>
<li>Friday: I decided to rename Seed and its commands/concepts. I haven't actually touched the code yet.</li>
<li>Saturday: FOUR HOURS DRIVE!</li>
<li>Sunday: I mentioned a new project, and fantasized about being organized again.</li>
<li>Monday: I didn't have an entry because I had less to say than I do for entries that start "I don't have much to say".</li>
</ul>
<p>Next week, I'm going to try to take things easy, but also work on some of these new projects.
I might actually go into some detail about them.</p>
Diary 2019-08-042019-08-04T04:00:00-04:002019-08-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-04:/diary-2019-08-04<p class="first last">Very little to say.</p>
<p>Nothing to talk about, since I spent most of the day away from project-y stuff.
I did start working on a new project that I'm probably not going to talk about.
Going forward, I'd like to get my various non-software ideas organized and start working on them in a more principled way.</p>
<p>For now, though, sleep.
Good night.</p>
Diary 2019-08-032019-08-03T04:00:00-04:002019-08-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-03:/diary-2019-08-03<p class="first last">So much traffic.</p>
<p>We were on the road for four hours today, and two of those were due to traffic.
After all that, I don't really have the mental acuity to work on anything more complicated than improvising Nova Drift builds.</p>
<p>If past experience is any indication, I'm going to end up taking things easy for the next few days, project-wise.</p>
<p>I'm pretty sleepy now, so I'm going to wrap things up.</p>
Seed 2019-08-022019-08-02T04:00:00-04:002019-08-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-02:/seed-2019-08-02<p class="first last">Taking time to address some stuff that's been bothering me.</p>
<p>I had kind of a rough day today in some respects.
Some stress, and a lot of staring into bright lights.
Not pleasant.</p>
<p>Anyway, I'm getting unhappy with the terminology I'm putting into Seed.
Among other things, I'm iffy on the name, since it's like, Seed manages your seeds, and also your things which are not seeds.
I think that's weird.</p>
<p>So, I'm going to take this time to try to figure out some better metaphors.
Basically, the idea is that the user draws from an initial state that defines specific ways to alter it, in addition to general alteration.
There are essentially three layers: the baseline template, the template substitution, and everything else.
Normal operations alter the "top" layer, changes to the project metadata alter the "middle" layer, and updates to the recommended layout alter the "bottom" layer.</p>
<p>I discussed this some with my wife, and we came up with the idea of using cell biology.
Repositories would be divided into "nucleus" and "live" repositories.
Instead of <tt class="docutils literal">seed fork</tt>, there'd be <tt class="docutils literal">cell grow</tt>, which would free up the fork command to be less confusing.</p>
<p>I don't know how far I'll go with this, but it can't possibly end up more ridiculous than the way uWSGI does things.
In any case, I'll put in links to the Cell category once it exists.
I'm tired, and warm, and <em>done</em>.
Good night.</p>
Diary 2019-08-012019-08-01T04:00:00-04:002019-08-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-08-01:/diary-2019-08-01<p class="first last">Not having a good time with this weather...</p>
<p>It was a rainy and hot day, and I put in a lot of effort and work.
I can't remember doing much after I got home besides playing Nove Drift really badly, according to the top-left challenge.
Got some ships with that that had no survivability, and also some weird nonsense.</p>
<p>Just tried to do some outlining for writing.
It's a pretty sorry outline.
I remember years and years ago trying to do a directed acyclic graph in a tree-based outline with a graphical view, which really didn't work.
Now I've put together something that's basically just two levels: at the top is the story, and immediately below it is everything in the story, including some entries that are just, like, "I'm not sure what to put here???"
Kind of a dramatic reversal, all the while maintaining a factor of not-working-very-well.</p>
<p>I guess outlining is a skill, and skills can get out of practice.
Still, oof.
Anyway, again, better wrap things up, cut the post off, etc.
Good night.</p>
Seed 2019-07-312019-07-31T04:00:00-04:002019-07-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-31:/seed-2019-07-31<p class="first last">Hopefully I rewrote all of the bits that needed rewriting</p>
<p>I'm not actually touching Seed's code, but I wanted to work through some ideas that won't be in the prototype, in case they bring in design considerations.
The big idea is support for collaboration.</p>
<p>Existing collaboration paradigms I know of: sending patches to other people directly, and coordinating through a central server.
In the central server case, the PR logic would probably want to be handled against the central repo, and disallow bringing commits into master on clients.
This case would be checked for by the presence of a (default?) remote.
For the "sending patches manually" case, the recipient would pull the patches into their own branch and work with them using the normal no-remote flow.</p>
<p>The biggest implication here is that Seed should probably have e.g. the test_green functionality done as a library so it can be called from a webhook.
Even if this doesn't prove to be necessary for this specific use case (like if the webhooks available can just use the command-line interface), it still seems like generally a good idea.</p>
<p>I had another idea, but when I tried to describe it, I realized it was just a heavily rephrased version of red-green.
Good that I realized that, since it means that supporting the flow is more a question of some way to make convenient tags, or something like that.
Like, maybe independent of branches there could be "topic tags" that represent a subset of tags that can be added to, and used as a basis for reds and greens and refactors.
That kind of ergonomic thing would be nice, but I don't know ahead of time how necessary it would be, so I think I should try to get by without it and see if that's intolerable.</p>
<p>This was some helpful planning.
I'm tired.
Good night.</p>
Weekly Roundup 2019-07-302019-07-30T04:00:00-04:002019-07-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-30:/weekly-roundup-2019-07-30<p class="first last">Nova Drift Nova Drift Nova Drift</p>
<ul class="simple">
<li>Wednesday: I messed with stuff in Lua and did a little work on Seed.</li>
<li>Thursday: I showed off the Lua stuff, discussed it, and did a little more work on Seed.</li>
<li>Friday: Nova Drift! Also, I put in a feature request for Poetry that's gotten no traction as of this writing.</li>
<li>Saturday: Nova Drift, and also thinking about the Texas Chainsaw Massacre series.</li>
<li>Sunday: Videos of Nova Drift.</li>
<li>Monday: Tried out a build from the videos. It went well.</li>
</ul>
<p>Next week, I'm not sure. I'll be out-of-town for some of it.
Besides that, I'm going to maybe focus on writing until Pijul releases a new version, because I kind of don't want to actually use the <tt class="docutils literal">seed fork</tt> command until the patch hash format stabilizes.
Although, <tt class="docutils literal">seed fork</tt> isn't yet fully implemented, so I can do that at some point...</p>
Diary 2019-07-292019-07-29T04:00:00-04:002019-07-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-29:/diary-2019-07-29<p class="first last">A productive day, I guess.</p>
<p>I'm about done watching Nova Drift builds for now, I think.
I went and tried to use one, and managed to beat all my high scores, though I didn't do as well as others.
It was kind of fiddly to set up, but once I was over the initial hump, I was doing great for about a hundred waves, until I got juggled by juggernauts, which is even less pleasant than it sounds.
Here's the video of a better player explaining the build I used:</p>
<div class="youtube youtube-16x9"><iframe src="https://www.youtube.com/embed/gAg0CNSNxss" allowfullscreen seamless frameBorder="0"></iframe></div><p>I think I need to look over these builds and figure out how everything interacts.
The one thing I know for sure is that Bastion, Regenerative Shields, and Dying Star interact very poorly.</p>
<p>Anyway, I did some more writing.
I feel like there's a good amount for a single part to a story here, but I've got to step back and think about the direction I'm taking it.</p>
<p>It's super hot in here, got to wrap up.
Good night.</p>
Diary 2019-07-282019-07-28T04:00:00-04:002019-07-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-28:/diary-2019-07-28<p class="first last">Easy. Taking it.</p>
<p>More Nova Drift stuff, mostly.
Watching some videos on builds, looking for inspiration.
I think I'll try writing more tomorrow, then maybe seeing if there's anything obvious I can contribute to pip.</p>
<p>Watched videos, it's late, good night.</p>
Diary 2019-07-272019-07-27T04:00:00-04:002019-07-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-27:/diary-2019-07-27<p class="first last">Taking it easy again.</p>
<p>I was working a bit late today, so that's one reason I don't have much to write about now.
Another is that I mostly played Nova Drift and tried to write.</p>
<p>We also watched a movie.
Texas Chainsaw Massacre 3.
My wife thinks the second one was better, and I'm inclined to agree.</p>
<p>I'm not sure about this, but I think maybe the series so far doesn't really have a strong genre identity?
Like, some horror franchises are very specifically slasher movies, or whatever, but the common thread here seems to mostly be "creepy backwoods murder cult family".
Like, maybe they're hovering on the periphery of what the protagonists know.
Or maybe they're hiding out and need to be flushed out.
Or maybe they coincidentally just utterly ruin some people's lives.
The distinctions here seem somewhere between "subtle" and "non-existent", so maybe I'm just totally wrong.</p>
<p>Regardless, my biggest takeaway is that it would have been funny if someone just ran with the scenario at the beginning of the second movie, and just went full Sweeney Todd with it.
That, and I'm not sure the first two movies are directly comparable, since they're different in tone, but both are better than the third IMO.</p>
<p>And that's all I can possible write for now, super sleepy.
Good night.</p>
Diary 2019-07-262019-07-26T04:00:00-04:002019-07-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-26:/diary-2019-07-26<p class="first last">Trying to relax while the temperature skyrockets.</p>
<p>I decided that I should probably ease off on hobbyist software stuff for a bit.
Today, I played some Nova Drift and Minecraft, and wrote some.
I'd like to get back into reading, as well.</p>
<p>I'm not sure I have anything interesting to say about all of this.
I do plan to focus on Pijul and pip when I ramp back up, because those are the most important to how I want to use Seed.
Poetry is almost as important, but I haven't worked out exactly how I want to phrase my feature requests.</p>
<p>Actually, let's jump that ahead and have that be my "do it in the middle of writing the blog post" thing for tonight.</p>
<p>Okay, this is going a little long.
I'm going to hit publish on this and keep going.
Good night.</p>
Diary 2019-07-252019-07-25T04:00:00-04:002019-07-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-25:/diary-2019-07-25<p class="first last">ProCLASStination! Eh? Eh?</p>
<p>I guess I didn't feel strongly enough about working on stuff related to Seed, Pijul, Poetry, or pip, so I... didn't.</p>
<p>Instead, I've now got this Lua class stuff in... a state.
The current big deficiency is documentation.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span>
<span class="normal">74</span>
<span class="normal">75</span>
<span class="normal">76</span>
<span class="normal">77</span>
<span class="normal">78</span>
<span class="normal">79</span>
<span class="normal">80</span>
<span class="normal">81</span>
<span class="normal">82</span>
<span class="normal">83</span>
<span class="normal">84</span></pre></div></td><td class="code"><div><pre><span></span><span class="c1">---</span>
<span class="c1">-- A small class system.</span>
<span class="c1">-- @module class</span>
<span class="c1">-- Signature documentation.</span>
<span class="kr">do</span> <span class="c1">-- luacheck: ignore 541</span>
<span class="c1">--- Signatures.</span>
<span class="c1">-- @section signatures</span>
<span class="c1">--- Module table.</span>
<span class="c1">-- @field module</span>
<span class="c1">--- Metatable.</span>
<span class="c1">-- @table metatable</span>
<span class="c1">-- @field __new constructor</span>
<span class="c1">--- End Signatures</span>
<span class="c1">-- @section end</span>
<span class="kr">end</span>
<span class="c1">-- Module export</span>
<span class="c1">--- Create a class; provides sugar of the form class[M].name(meta).</span>
<span class="c1">-- @function class</span>
<span class="c1">-- @tparam module|nil M</span>
<span class="c1">-- @tparam string name</span>
<span class="c1">-- @tparam[opt] metatable meta</span>
<span class="c1">-- @treturn table</span>
<span class="kd">local</span> <span class="n">class</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">new_instance</span><span class="p">(</span><span class="n">metatable</span><span class="p">,</span> <span class="p">...)</span>
<span class="kr">return</span> <span class="nb">setmetatable</span><span class="p">(</span><span class="n">metatable</span><span class="p">.</span><span class="n">__new</span><span class="p">(...),</span> <span class="n">metatable</span><span class="p">)</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">empty_table</span><span class="p">()</span> <span class="kr">return</span> <span class="p">{}</span> <span class="kr">end</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">new_class</span><span class="p">(</span><span class="n">mod</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">metatable</span><span class="p">)</span>
<span class="n">metatable</span> <span class="o">=</span> <span class="n">metatable</span> <span class="ow">or</span> <span class="p">{}</span>
<span class="n">metatable</span><span class="p">.</span><span class="n">__name</span> <span class="o">=</span> <span class="n">name</span>
<span class="n">metatable</span><span class="p">.</span><span class="n">__new</span> <span class="o">=</span> <span class="n">metatable</span><span class="p">.</span><span class="n">__new</span> <span class="ow">or</span> <span class="n">empty_table</span>
<span class="kr">if</span> <span class="n">mod</span> <span class="kr">then</span>
<span class="n">mod</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">metatable</span>
<span class="kr">end</span>
<span class="kr">return</span> <span class="n">metatable</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">basic_metaclass</span><span class="p">()</span>
<span class="kr">return</span> <span class="p">{</span>
<span class="n">__call</span> <span class="o">=</span> <span class="n">new_instance</span><span class="p">,</span>
<span class="n">__new</span> <span class="o">=</span> <span class="n">new_class</span><span class="p">,</span>
<span class="p">}</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="n">class_class</span> <span class="o">=</span> <span class="n">basic_metaclass</span><span class="p">()</span>
<span class="n">class</span> <span class="o">=</span> <span class="n">new_instance</span><span class="p">(</span><span class="n">class_class</span><span class="p">,</span> <span class="kc">nil</span><span class="p">,</span> <span class="s2">"class"</span><span class="p">,</span> <span class="n">basic_metaclass</span><span class="p">())</span>
<span class="n">class</span><span class="p">(</span><span class="kc">nil</span><span class="p">,</span> <span class="s2">"class_class"</span><span class="p">,</span> <span class="n">class_class</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">class_in_module</span> <span class="o">=</span> <span class="n">class</span><span class="p">(</span><span class="kc">nil</span><span class="p">,</span> <span class="s2">"class_in_module"</span><span class="p">,</span> <span class="p">{</span>
<span class="n">__new</span> <span class="o">=</span> <span class="kr">function</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="n">mod</span><span class="p">)</span>
<span class="kr">return</span> <span class="p">{</span><span class="n">cls</span><span class="p">,</span> <span class="n">mod</span><span class="p">}</span>
<span class="kr">end</span><span class="p">,</span>
<span class="n">__index</span> <span class="o">=</span> <span class="kr">function</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
<span class="kr">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="o">~=</span> <span class="s2">"string"</span> <span class="kr">then</span>
<span class="kr">return</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="n">cls</span><span class="p">,</span> <span class="n">mod</span> <span class="o">=</span> <span class="nb">table.unpack</span><span class="p">(</span><span class="n">self</span><span class="p">)</span>
<span class="kr">return</span> <span class="kr">function</span><span class="p">(</span><span class="n">metatable</span><span class="p">)</span>
<span class="kr">return</span> <span class="n">cls</span><span class="p">(</span><span class="n">mod</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">metatable</span><span class="p">)</span>
<span class="kr">end</span>
<span class="kr">end</span><span class="p">,</span>
<span class="p">})</span>
<span class="kd">local</span> <span class="n">mod_types</span> <span class="o">=</span> <span class="p">{[</span><span class="s2">"nil"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span> <span class="n">table</span> <span class="o">=</span> <span class="kc">true</span><span class="p">}</span>
<span class="kr">function</span> <span class="nc">class_class</span><span class="p">.</span><span class="nf">__index</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">mod</span><span class="p">)</span>
<span class="kr">if</span> <span class="ow">not</span> <span class="n">mod_types</span><span class="p">[</span><span class="nb">type</span><span class="p">(</span><span class="n">mod</span><span class="p">)]</span> <span class="kr">then</span>
<span class="kr">return</span>
<span class="kr">end</span>
<span class="kr">return</span> <span class="n">class_in_module</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">mod</span><span class="p">)</span>
<span class="kr">end</span>
<span class="kr">return</span> <span class="n">class</span>
</pre></div></td></tr></table></div>
<p>The basic idea of this stuff is "lots of things are objects, including things that probably don't need to be".
The intended usage of this stuff is that consumers <tt class="docutils literal">local class = <span class="pre">require("class")</span></tt> (or <tt class="docutils literal">local class = require"class"</tt>; the interaction between Lua's function calls and literals is... interesting), create a module table like <tt class="docutils literal">local M = {}</tt>, and then use the syntactic sugar <tt class="docutils literal"><span class="pre">class[M].MyClass{__index</span> = {value = <span class="pre">"whatever"},</span> __new = function(value) return {value = value} end}</tt>, which in this example would create a class in <tt class="docutils literal">M</tt> called <tt class="docutils literal">MyClass</tt>, which defines a constructor (the <tt class="docutils literal">__new</tt> function, which I'm kind of just hoping nothing else that uses metatables collides with) that takes an optional argument and stores it in the <tt class="docutils literal">value</tt> key; if nothing is passed, accessing <tt class="docutils literal">value</tt> will return the string "whatever" per normal metatable mechanics.
In the course of normal usage, the class constructor expects the last argument passed, if truthy, to be a table literal; the need to pass a variable in the course of defining the system is unfortunate, but unavoidable given the semantics in question.</p>
<p>One thing that all classes, including the "built-in" ones from this module will need to document, is whether their constructor returns a completely new object, or something passed in via its arguments.
I think the current convention for class creation showcases the furthest limits of argument mutation and returning:</p>
<ul class="simple">
<li>The <tt class="docutils literal">M</tt> argument is not part of the return value, but an additional target for the return value to be stored in. The purpose of this behavior is to allow storing the class's name in itself, without resorting to repetition when it comes time to put it in the module. (Regardless of whether a module is passed, the class is returned; which allows the somewhat repetitive option of storing the class in both a module and a local.)</li>
<li>The <tt class="docutils literal">metatable</tt> argument is, by virtue of the preferred call syntax, assumed to be uniquely held by the constructor at the time, and therefore acceptable to mutate or return. (Inclusive or.) The purpose of this behavior is to concisely and quickly create metatables for use as classes. Creating copies of the passed-in metatable would have various issues, so I don't bother.</li>
</ul>
<p>This has been fun, but to make use of this, I need a project to go with it, and ideally to have Seed working.
The current hurdle with Seed is that I need to write code to extract the author config; if present, make "author" flags optional, otherwise required.
It's kind of fiddly, oh well.
I've got time, I'll try to get that done quick.
Okay, I'm generating the paths, probably.
From there, it shouldn't be hard to extract the author data, if it's present, and create a placeholder if it's not.</p>
<p>One bit of weirdness: the first record showed two diffs, and I recorded the first; the second record also showed two diffs, the second diffs together made up the first second diff.
I should probably ask about that.</p>
<p>Okay, definitely need to wrap up.
Good night.</p>
Diary 2019-07-242019-07-24T04:00:00-04:002019-07-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-24:/diary-2019-07-24<p class="first last">Classing the joint up</p>
<p>Rather than look into Seed stuff, I elected to implement the changes I wanted to make to the stuff I was messing around with in Lua.</p>
<p>(Since I mentioned it, I decided just now to take a look at how Pijul stores its global config.
Looks like it checks <tt class="docutils literal">$PIJUL_CONFIG_DIR/config.toml</tt> first, then <tt class="docutils literal">$XDG_DATA_HOME/pijul/config/config.toml</tt>, then <tt class="docutils literal"><span class="pre">~/.pijulconfig/config.toml</span></tt>.
Okay, I can do that too, seems easy enough once I put some time towards it.
I'll need to make sure I have those paths right, though.)</p>
<p>Anyway, I have another class system in Lua, since tiny class systems are really easy to put together in Lua.
I think I prefer the ergonomics of this attempt to my previous endeavors.
It's better suited to working with module tables, which is really what I should have been focusing on in the first place, in the context of Lua classes.
I am somewhat at a loss for how to document it, since I've forgotten the tricks I pulled to make LDoc work with the kinds of stuff I was putting in method signatures.
Having messed with this between the sentences, I think this is working, I just need to put in some effort.</p>
<p>Other stuff I'm doing: some reading, a tiny bit of writing, Nova Drift, silly movies from the early nineties, I don't remember what else and it's getting late.</p>
<p>Tomorrow, I'll try to improve the interaction between Seed and Pijul, and maybe put in another bug against Poetry asking for more functionality that I don't know that anyone else specifically wants.
Good night.</p>
Weekly Roundup 2019-07-232019-07-23T04:00:00-04:002019-07-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-23:/weekly-roundup-2019-07-23<p class="first last">More grinding away on Seed.</p>
<ul class="simple">
<li>Wednesday: A small amount of work on Seed.</li>
<li>Thursday: Another small amount of work on Seed.</li>
<li>Friday: Some more work on Seed.</li>
<li>Saturday: Yet more work on Seed.</li>
<li>Sunday: I messed with stuff besides Seed.</li>
<li>Monday: I made some more progress with Seed, and thought about the tools that it has to work with.</li>
</ul>
<p>Next week, I'm going to go over Pijul's capabilities some more, try actually using Seed, probably add some options, and then start working on other commands.</p>
Seed 2019-07-222019-07-22T04:00:00-04:002019-07-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-22:/seed-2019-07-22<p class="first last">Incremental progress</p>
<p>I messed a little with other stuff, but I mostly focused on getting progress on Seed.
The implementation for the fork command is almost done, I just haven't figured out how to implement specifying the developer name.
Maybe it can piggyback off of pijul's configuration.</p>
<p>In any case, once the last bits of that are ironed out, I'm going to start testing out the prototype by trying to create a self-hosting repository for Seed.
It won't get too far, but I'd rather find problems with it sooner than later.</p>
<p>Once I've ironed out any issues, though, I think I'd like to focus on the requirements that Seed will put on complementary tooling, because I don't want to be surprised by some missing functionality that is obvious only to me.
I've been sort of weighing in my head the possibility that I'll end up writing my own packaging system, but I really really hope it doesn't come to that, because that would be a huge pain. ... And said tools managed to end up in a broken state, so it's possible my hand is going to be forced unless I can fix it, which it looks like I just did, very heavy-handedly.
Somehow, the permissions were hosed on many, if not all of the <tt class="docutils literal">__pycache__</tt> folders, which put Poetry in an inconsistent state when I tried to upgrade it.</p>
<p>At least I can be confident that situation will never arise again, because, um... hm...
Computers!
Good night.</p>
Diary 2019-07-212019-07-21T04:00:00-04:002019-07-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-21:/diary-2019-07-21<p class="first last">Writing the same basic code again in a slightly different way... I should figure out how to reframe this as a "kata" so that when I do it it's "learning".</p>
<p>I needed a break from messing with Seed, so I did some stupid Lua tricks around trying to make a minimal class system again.
I came up with something interesting, but with some limitations and ergonomics issues that make me want to not show it off just yet.</p>
<p>It would be really excellent if I had any kind of project to try to use this stuff with; maybe once I get back to Seed I can try to put together something using Löve, since this code would be kind of wasteful in the context of a PICO-8 cartridge.</p>
<p>For now, this was a fun diversion that I'll try to polish up later; maybe it would benefit from having tests written for it, as well.</p>
<p>Anyway, wrapping up now would be excellent, so, good night.</p>
Seed 2019-07-202019-07-20T04:00:00-04:002019-07-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-20:/seed-2019-07-20<p class="first last">There's a lot of behavior to specify.</p>
<p>I took things easy today, whole bunch of reading and hanging out next to the AC.
But, I did get a bit more done with Seed.
This time, it was documenting the possible relationships and changes in relationships between different repositories.</p>
<p>I guess I don't have more to say on this and I'm really tired, so, another short entry.
Good night.</p>
Seed 2019-07-192019-07-19T04:00:00-04:002019-07-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-19:/seed-2019-07-19<p class="first last">Slowly getting things done.</p>
<p>I'm writing up the motivations for Seed, possibly for the first time, I don't really remember.</p>
<p>I really wanted to have something else to say here, but I ended up just staring off into space.
I guess I'm tired, oh well.
Good night.</p>
Seed 2019-07-182019-07-18T04:00:00-04:002019-07-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-18:/seed-2019-07-18<p class="first last">Uuuugh.</p>
<p>I'm sleepy and it's so hot.
I'm measuring my progress on Seed and other things right now in sentences, but I think that's how it has to be until I get energy back and somewhere cool to work.</p>
<p>I fell asleep writing this, so, yeah, I have to call it this soon.
Good night.</p>
Seed 2019-07-172019-07-17T04:00:00-04:002019-07-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-17:/seed-2019-07-17<p class="first last">So tired, can't attempt wittiness.</p>
<p>I'm way too sleepy to write a bunch.
I wanted to get something done today, so I started documenting the behavior that Seed is supposed to have.
The initial versions will not have all of the capabilities I plan to document, because some of those capabilities are unneeded for self-hosting.
I've written all I can muster for tonight.
Good night.</p>
Weekly Roundup 2019-07-162019-07-16T04:00:00-04:002019-07-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-16:/weekly-roundup-2019-07-16<p class="first last">Excited to be out of bed.</p>
<ul class="simple">
<li>Wednesday: I'd been reading, writing, and hacking a little.</li>
<li>Thursday: No post due to sickness.</li>
<li>Friday: No post due to sickness.</li>
<li>Saturday: Short post due to sickness.</li>
<li>Sunday: Short post due to sickness.</li>
<li>Monday: Short post due to sickness.</li>
</ul>
<p>Next week, I seem to have recovered, so I'll be able to actually work on stuff for posts.
I don't know yet what I want to work on, but I'm going to drop a teaser for something that's months out at best, and could easily change completely: gigerpunk luchadors.</p>
Diary 2019-07-152019-07-15T04:00:00-04:002019-07-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-15:/diary-2019-07-15<p class="first last">Incremental improvements...</p>
<p>I seem to be doing better, but I'm definitely not done with this, which kind of sucks, because it seems like my first reaction to "I'm capable of applying more effort to things" is to apply that effort to worrying about whether I'll keep getting better.
Next priority: "<em>How quickly</em> am I getting better?"</p>
<p>I was able to work on a few other things, like design stuff for one of my projects, and reading more.
Quoting one of my reactions: "This isn't the queer representation we need, but it's the queer representation we deserve".</p>
<p>I sat on this for a while in case I had anything else to say, but I guess I don't.
I really really really want to be clear of this whole "sickness" thing.
Good night.</p>
Diary 2019-07-142019-07-14T04:00:00-04:002019-07-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-14:/diary-2019-07-14<p class="first last">Why won't it be DONE already?</p>
<p>The fever hasn't gone away yet.
I'm generally more alert and able to move around, but I'm still not up to my usual levels of stamina.
I'm doing everything I can think of to get the fever down in a responsible manner, because I'm really tired of this.</p>
<p>In stuff not related to my health, I just recently today decided to replay Thomas Was Alone.
I'm not crying, you're crying.</p>
<p>And back to health, I'm going to try for "extremely aggressive hydration".
I'll document the success or failure of that tomorrow.
For now, I need to be wrapping things up.
Good night.</p>
Diary 2019-07-132019-07-13T04:00:00-04:002019-07-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-13:/diary-2019-07-13<p class="first last">Too hot to handle.</p>
<p>Having been sick again these last few days, I know have some advice about being sick: don't.</p>
<p>I've still got a killer headache, but there's a chance I can deal with that with enough water.</p>
<p>No posts the last few days because I was just lying in bed while my brain struggled not to cook.</p>
<p>Biggest thing I accomplished, I think, was noticing that the 2001 one-dollar coins of a small island nation were Pokémon-branded, which is more cyberpunk than my imagination can handle right now.
Like, imagine if the US issued the McDollar. ... Nobody give Trump any ideas.</p>
<p>Well, I'm not sick any more, just really dehydrated apparently, so here's looking forward to getting something accomplished.
Good night.</p>
Diary 2019-07-102019-07-10T04:00:00-04:002019-07-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-10:/diary-2019-07-10<p class="first last">Reading: great! Writing: eh.</p>
<p>I've been reading a bunch recently.
Either these books are really short, or I forgot how quickly I could read an engaging novel.
Either way, they're good.
The Quantum Thief trilogy.
I'm most of the way through it now.</p>
<p>I'm trying to do some writing, and that's a bit slower.
I basically ended up doing kind of a weird yak shave, where I'm either trying to develop a setting for a role-playing game, or the other way around, I kind of forget, but now to get an idea of the character archetypes I want to support, I'm trying to write a story in the setting.
I'm sure this will all make sense at some point.</p>
<p>So far as Seed goes, I think I'm going to need to ask for help or file documentation bugs, because it's not clear to me how to use some of the options to <tt class="docutils literal">pijul record</tt>.</p>
<p>I'll try to get on that soon, and write some more.
I don't know how quickly I can ramp back up now that I'm back in town; it feels like the travel messed me up in kind of subtle ways.</p>
<p>We'll see what I can do.
Good night.</p>
Weekly Roundup 2019-07-092019-07-09T04:00:00-04:002019-07-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-09:/weekly-roundup-2019-07-09<p class="first last">Vacation.</p>
<ul class="simple">
<li>Vacation: Vacation.</li>
</ul>
<p>More seriously, I poked at Seed a little.
But mostly vacation.</p>
<p>Next week, not vacation.
I've got a few ideas I want to work with.
Hopefully I'll be able to focus in this heat.</p>
Weekly Roundup 2019-07-022019-07-02T04:00:00-04:002019-07-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-02:/weekly-roundup-2019-07-02<p class="first last">A "Seedy" week. Eeey! I forget if I've used that joke, and I don't feel like looking it up.</p>
<ul class="simple">
<li>Wednesday: I tried to work out some details of how Seed should work.</li>
<li>Thursday: I made an effort to work through some of the logic underlying Seed's operations.</li>
<li>Friday: I played Nova Drift, stewed in the heat, and considered which features of Seed to de-prioritize.</li>
<li>Saturday: I did some quick work on Seed while I was writing the post, focusing on designing the "fork" command.</li>
<li>Sunday: I started implementing the "fork" command.</li>
<li>Monday: I wrote bit more code for Seed, and got back to the work on Jedi; I think it's mostly done, but the tests are failing in some configurations on Windows for reasons I don't understand yet.</li>
</ul>
<p>Next week, I'm going to take it easier because we're traveling again.
I've been thinking about where I want to take some projects.</p>
<p>Like, it's conceivable that Seed and pip could end up in a state where the negative space of the two of them working together could be filled by some other PEP 517/518 build system than Poetry.
It's not that I'm in a hurry to replace Poetry, but I have been noticing ways in which it's not a precise fit for my workflow.
And if Seed and pip are eventually going to implement some of the same features anyway...
Note that Seed isn't well-placed to compete with most Python packaging solutions, since it's a general-purpose tool for project lifecycle management, built on top of a <em>specific</em> revision control system.</p>
<p>I was also thinking about MonFree, and the role that grind should play in game design.</p>
Diary 2019-07-012019-07-01T04:00:00-04:002019-07-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-07-01:/diary-2019-07-01<p class="first last">Seed's code is about to get a bit more complicated.</p>
<p>Today was a little nicer.
I was able to get a little more done on Seed, kind of chipping away at my specification for what forking is.
It's pretty involved.
Just doing stuff like extracting lists from a DOT file so I can template them into a toml file which I then present to the user to edit, then parse it.
That operation involves every third-party library I'm using for this project.</p>
<p>I also got some more unlocks in Nova Drift.
The Courser is kind of hard to control, at least to start with, but Courser, Railgun, Barrage, Warp Strike combine to do some truly hilarious things to the screen.</p>
<p>I'm also working on Jedi again.
I think we're nearly there, but there's a mismatch between test and code, and it's not totally clear to me right now which one is right.
I've got my suspicions, but I'm still not terribly familiar with the code base, not like my own stuff.</p>
<p>It's getting late, got to wrap this up, um, it's over!
Good night.</p>
Seed 2019-06-302019-06-30T04:00:00-04:002019-06-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-30:/seed-2019-06-30<p class="first last">The library I'm using to parse DOT has kind of a weird interface.</p>
<p>The weather continues to be unpleasantly warm.
And humid.
And stagnant.</p>
<p>I was focusing on other stuff most of the day, but I was able to start working on Seed, a little.
I started implementing some of the stuff I wrote up yesterday.
Currently, the fork code does some basic validation, then creates a temporary clone, then reads and parses the dependency graph, gets the set of node names from the graph, and removes all non-leaf nodes from the set in a way that seems inefficient, but I don't want to focus on that right now.
Next, it sorts the set, and reads in the seed.toml file.</p>
<p>Then it fails because I'm not done implementing it, and therefore the next thing it executes is, more-or-less accurately, <tt class="docutils literal">raise NotImplementedError</tt>.</p>
<p>I'm glad I got something done for today just now, but getting more done is going to require getting into the details of how Jinja works, and I don't want to do that right now.</p>
<p>Good night.</p>
Seed 2019-06-292019-06-29T04:00:00-04:002019-06-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-29:/seed-2019-06-29<p class="first last">Nailing down functionality in grueling yet still somewhat high-level detail.</p>
<p>All right, here's the deal.
I spent all day doing other stuff like unlocking stuff in Nova Drift and rereading webcomics.
I'm going to try to write up working on Seed, live-ish.</p>
<p>I've got some electronic music playing, and my first priority is on writing up the feature list.
Okay, I did that.
I got just a few entries added, but I'll add more as I think of them.
For now, let's see about implementing some of this.</p>
<p>I took some time to drill into what the "fork" command needs to do, and how it might accomplish it.
The current design requires "src" and "dest" arguments, which are required, and currently must be local paths that are siblings.
Given those, there are many tasks that must then be done:</p>
<ul class="simple">
<li>The repository must be cloned to a temporary directory</li>
<li>The set of patches with no children must be extracted</li>
<li>Said set must be put in a canonical order, such as through alphabetization, and converted to a toml table containing a single key with an array of strings value</li>
<li>The seed.toml must be read from the clone, and the table substituted in</li>
<li>The substituted toml must be presented to the user for editing</li>
<li>The edited toml must be parsed, its data applied to the clone, and then overwritten on top of the clone's toml.</li>
<li>The clone must test green</li>
<li>Cut the 0.1.0 version</li>
<li>Make the clone available from dest</li>
<li>Fork a dev branch from master in dest, using global settings.</li>
</ul>
<p>I will surely be able to implement this stuff when I'm not busy roasting in the summer heat.
I'm struggling to stay awake now.
Good night.</p>
Diary 2019-06-282019-06-28T04:00:00-04:002019-06-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-28:/diary-2019-06-28<p class="first last">Everything is wet and sticky, it's terrible.</p>
<p>It is so incredibly hot right now.
I played a little Nova Drift today because the new update finally reached Itch.
I'm having trouble getting a consistent framerate; I'll have to report that I guess.</p>
<p>I planned out stuff for Seed and decided to defer some features that I don't personally need.
I'd like to have made progress on the prototype itself, but I guess instead today was a day for slowly melting.</p>
<p>I would very much like to get the following things done with Seed tomorrow:</p>
<ul class="simple">
<li>Draw up features in a roadmap.</li>
<li>Write the code needed to perform a fresh fork from a seed.</li>
</ul>
<p>Being awake in these conditions is really unpleasant.
Good night.</p>
Seed 2019-06-272019-06-27T04:00:00-04:002019-06-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-27:/seed-2019-06-27<p class="first last">I suspect I may be seeing a reason why the existing tools that I know of, do not work like this.</p>
<p>Here's the current thing that has me tripped up regarding Seed:</p>
<p>A seed repo is essentially a template that gets filled in to create a basic 0.1.0 version of a new repo.
In getting filled in, it has to have some kind of environment defined to map variable names to values.
What ultimately gets filled in should usually be a string, but more elaborate data structures might sometimes be called for, such as an array of strings to represent a list of authors.
The seed repo can use any set of variable names that the seed creator desires.
There are various possible features that we might prioritize in order to choose a workflow for passing in variable values:</p>
<ul class="simple">
<li>Constraining choices of value or specifying a default</li>
<li>Presenting the variables to the user in some defined order</li>
<li>Allowing the user to specify structured data</li>
</ul>
<p>Here's what I'm leaning towards for now, as an initial implementation at least:</p>
<p>The seed.toml file contains a "substitutions" table, where the keys are variable names.
Each key is documented in a comment that precedes it.
Keys may have a value already specified, or may be left blank.
Documentation should mention any restrictions on allowed values.
When the user performs an initial fork, the seed program should open the seed.toml file in an editor; after the user saves, the program should append a table containing just the relevant patches.</p>
<p>(The invariant of the "relevant" patches is that those patches should be the parents in the seed repo of the patch in the current repo.)</p>
<p>Updating the patches goes as follows:</p>
<p>Update the referenced patches, ideally to a tag for simplicity, and commit only the changes to seed.toml.
Submit that patch for updating.
In a new clone, that patch gets its own branch, and then the relevant patches are pulled from the seed.
The program attempts to apply the merged seed.toml to the seed repo; if it fails, it drops the user into an editor and prompts them to fix the variables.
Once the new version creates successfully, it gets tested green, then tested red if that fails.
I'm still not fully comfortable with this flow; there are possible avenues of failure that I'm not sure what the right way to recover from them is.
That said, I'd like to start prototyping these ideas when I have time, which is not right now, because I spent all day working this out in the first place, and doing other stuff.</p>
<p>Good night.</p>
Seed 2019-06-262019-06-26T04:00:00-04:002019-06-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-26:/seed-2019-06-26<p class="first last">A lot of my mental model of Seed seems to involve bits where I was like "And then we just do the thing." I'm working on dealing with that.</p>
<p>So, I'd been working out the details of how to fork from a seed repo, but before I could prototype it, I got distracted fixing up the numerous issues I discovered in the current seed repo, such as:</p>
<ul class="simple">
<li>I somehow had a table in it twice, which I'm pretty sure isn't valid TOML.</li>
<li>Due to pulling in several iterations of noxfile setup, I had stuff in the noxfile that belonged in the tasks file (basically, if it doesn't need the package installed, it's a candidate for the tasks file).</li>
<li>Some of my extras defintions were too specialized, and should have been handled in the noxfile by just installing multiple extras.</li>
</ul>
<p>Here's the plan for how to fork from a seed:</p>
<ul class="simple">
<li>Get substitutions from ??? (Take a <tt class="docutils literal">seed.toml</tt> file, copy it, optionally adding substitutions, then use the copy to determine the seed repo and substitutions, I guess?)</li>
<li>Clone the seed to a tmpdir, up to a given patch.</li>
<li>Recursively process substitutions in the tempdir: rewrite names, and after a file's name has been substituted (with the help of <tt class="docutils literal">pijul mv</tt>), process the files</li>
<li>(Copy over the <tt class="docutils literal">seed.toml</tt> file?)</li>
<li>Record the changes</li>
<li>For thoroughness, perform a green test run.</li>
</ul>
<p>From the new repo, either clone a fresh repo into the workspace, or attempt a merge with the following special logic:</p>
<ul class="simple">
<li>Unconditionally test green, even if the diff pattern would normally prohibit it</li>
<li>If the green test fails, do a red test, <em>I think</em> this needs to still check the diff pattern, I'm not sure.</li>
</ul>
<p>If things go wrong enough, this might need manual intervention unless I can work out really smart default behavior.</p>
<p>I think I had something else in mind to say, but I lost my train of thought and I have a headache, which is one of many ways circumstances can make me realize it's time to call it.
I'll try to actually prototype some of this tomorrow.
For now, good night.</p>
Weekly Roundup 2019-06-252019-06-25T04:00:00-04:002019-06-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-25:/weekly-roundup-2019-06-25<p class="first last">Time to start iterating?</p>
<ul class="simple">
<li>Wednesday: I played a bit of Nova Drift and thought about Seed.</li>
<li>Thursday: Mostly more Nova Drift.</li>
<li>Friday: I drew up more detail for how Seed should work.</li>
<li>Saturday: I was extremely tired; I believe I was lying down too much.</li>
<li>Sunday: I watched Barbarella, which was kind of like a children's book, but titillating by 60s standards. While I was recovering from that psychic onslaught, I started putting together the base repo for my Python projects using Seed.</li>
<li>Monday: I got more of the repo together. To properly develop it further, I'm going to need to develop Seed enough to be able to fork the base repo into a usable state.</li>
</ul>
<p>Next week, I'm going to try to make progress on Seed at a measured pace.
One thing I should do is start outlining features to aim for.</p>
Seed 2019-06-242019-06-24T04:00:00-04:002019-06-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-24:/seed-2019-06-24<p class="first last">Time flies when you're having fun.</p>
<p>Oops.
I got so into working on the data for Seed that I forgot to write up anything I did.</p>
<p>I'm basically trying to take files from my previous projects and cut out various bits of cruft and decisions I disagree with or don't need.</p>
<p>I ended up jumping the gun on adding in template substitutions, which means I'm going to need to develop some kind of basic functionality to be able to test out some of the new stuff.
I'll try to get that done soon, but not rush into it.</p>
<p>Anyway, nothing more to say in the next ten minutes.
Good night.</p>
Seed 2019-06-232019-06-23T04:00:00-04:002019-06-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-23:/seed-2019-06-23<p class="first last">I'm going to have to ask people sometime what the idiomatic way is to accomplish some of the stuff I'm trying to do.</p>
<p>We watched Barbarella today, which was frankly kind of mind-destroying, so I'm just counting myself lucky to have accomplished anything.</p>
<p>Yesterday, I put a few files into the seed folder for Python projects, and today I started putting stuff in them.
I"m planning to spider out from what I have, add configuration files related to the various commands.
At some point, I'm going to need something like Cookiecutter's substitutions.
I think I might try just swiping the implementation, since Seed is supposed to kind of be like, some of the things I thought Cookiecutter might have been like, but didn't seem to be.</p>
<p>Anyway, that's enough incremental progress for today.
Good night.</p>
Diary 2019-06-222019-06-22T04:00:00-04:002019-06-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-22:/diary-2019-06-22<p class="first last">I think I was lying down too much today.</p>
<p>I wanted to get more done today, but I'm feeling really tired now.
I started putting together the environment for Seed, but I'm too tired to think straight.</p>
<p>I'm not going to get anywhere in this state, so I'm going to have to call it right now.
Good night.</p>
Seed 2019-06-212019-06-21T04:00:00-04:002019-06-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-21:/seed-2019-06-21<p class="first last">I've made the barest of concessions to collaborative workflows with this design, so early versions of Seed will probably be really bad for multi-user scenarios.</p>
<p>I spent some time earlier today laying out the stuff I need Seed to do.
Either some of the recent things I thought of simplify the design, or I forgot something.
Or maybe a lot of the fancy/complicated stuff I came up with is transparent to the user in terms of common actions, which, if so, that's good.</p>
<p>I think next I'll try to put together the data required for Seed to manage its own repo state.
My plan is to develop the data and client code, write a first draft that appears compatible with it, and use the draft to manage the second version, and start using the second version on itself as soon as possible.</p>
<p>It's too hot to think any harder and I'm tired already.
Good night.</p>
Diary 2019-06-202019-06-20T04:00:00-04:002019-06-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-20:/diary-2019-06-20<p class="first last">I don't know what to put for this summary.</p>
<p>Messed around more in Nova Drift.
Did reasonably well with a build I kind of tossed together; I can't tell if this is putting together a good build, or doing better at the moment-to-moment gameplay.</p>
<p>That took up a bunch of time, and I'd like to move away from it.
My plan for tomorrow is to thoroughly document everything that I need Seed to do, on paper.
I think I've got everything worked out in my head, but I need to get it all down to be sure.</p>
<p>Anything else to say for tonight?
Nope, and it's late, again.
Good night.</p>
Diary 2019-06-192019-06-19T04:00:00-04:002019-06-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-19:/diary-2019-06-19<p class="first last">Feels like I'm turning a corner.</p>
<p>Tried out one of the Nova Drift builds I was working out.
It turned out to be not what I expected, because I misinterpreted the effect of Regression.
It looks like it banishes the mods on screen at the time, rather than all possible mods?
Either way, I feel like I got pretty far for the Research body running some basic constructs, so I might try redoing some of that build without the gimmicks.</p>
<p>I think I've also got the ideas for Seed mostly worked out, so now I just want to take some time to properly document them, get them in a more understandable form than scattered text.</p>
<p>It is unpleasantly warm and humid right now.
I'm going to try to wrap things up.
Good night.</p>
Weekly Roundup 2019-06-182019-06-18T04:00:00-04:002019-06-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-18:/weekly-roundup-2019-06-18<p class="first last">Trying to get my mental energy back...</p>
<ul class="simple">
<li>Wednesday: I made some progress in various indie games, and figured out where to go forward with Jedi stuff.</li>
<li>Thursday: Started working on fixing up the Jedi PR.</li>
<li>Friday: Converted the PR from draft, to not draft.</li>
<li>Saturday: Played games, and tried to figure out where to go next in terms of creative stuff.</li>
<li>Sunday: Did pretty well in Nova Drift.</li>
<li>Monday: I started having ideas, but didn't go into detail.</li>
</ul>
<p>Next week, I'm not really sure what I'll talk about.
Not the writing.
I'm trying to come up with some more builds for Nova Drift, but right now I'm focused on gimmicks like "be as small as possible".</p>
Diary 2019-06-172019-06-17T04:00:00-04:002019-06-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-17:/diary-2019-06-17<p class="first last">I think work is done with the all-day planning meetings, after what seems like a month.</p>
<p>A couple random things from today:</p>
<ul class="simple">
<li>Played more games</li>
<li>Had an idea for the Linked Seas setting</li>
<li>Had an idea that may or may not pan out for some writing I won't discuess here further.</li>
<li>Thought a little bit about Seed.</li>
</ul>
<p>I'd like to work on Seed before any other coding, but I'm also feeling a bit burnt out.
I'm going to make an effort to focus on non-coding stuff for the next week, like writing or game design.</p>
<p>But first, taking things easy starting... now!
Good night.</p>
Diary 2019-06-162019-06-16T04:00:00-04:002019-06-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-16:/diary-2019-06-16<p class="first last">While writing the first part of this entry, I had the adrenaline jitters from shmupping hard.</p>
<p>Solved some puzzles, and managed to get my second-highest high score (not terribly high) on the current version of Nova Drift, with a build that I didn't think <em>too</em> hard about.
It was pretty fun having a build where pretty much every eventuality besides "not interacting with enemies" gave a temporary damage boost.</p>
<p>We're out of town again, so that's my excuse this time for why I'm not trying too hard to work on anything else.</p>
<p>Thinking about how I've gotten back on top of things in the past, maybe it's time for me to try to work out some more Stupid Lua Tricks.</p>
<p>Anyway, nothing is happening now.
Good night.</p>
Diary 2019-06-152019-06-15T04:00:00-04:002019-06-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-15:/diary-2019-06-15<p class="first last">I got a haircut today. That's nice.</p>
<p>I mostly spent today lazing around and trying to figure out inspiration for writing stuff.</p>
<p>Making incremental progress in various games.</p>
<p>While I wait for feedback on the PR to Jedi, I'd also maybe like to come up with something flashy to make and show off.
Maybe try to port some of the higher-level libraries I wrote for Dennis to something that'll compile to web, so I can try making some kind of HTML5 demo thing.</p>
<p>Nothing concrete, just still trying to be taking things easy.
Good night.</p>
Diary 2019-06-142019-06-14T04:00:00-04:002019-06-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-14:/diary-2019-06-14<p class="first last">Test-*mumble*-development!</p>
<p>Hooray, the tests passed.
Now to take the PR off draft...
Eh, I'll wait for AppVeyor to finish as well.
In any case, things are looking up for NewType support in Jedi.
Not sure when to expect any of this to land in Anaconda (the Sublime Text package), since last I checked its version of Jedi was well behind the release at the time.</p>
<p>The plan now:
Take the PR off draft in the morning, and work on writing fiction later tomorrow.
The best way to help with this now is to wrap up as soon as possible.
Good night.</p>
Diary 2019-06-132019-06-13T04:00:00-04:002019-06-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-13:/diary-2019-06-13<p class="first last">"I was exhausted so I did like 0.5 things" entries aren't any more fun to write than they are to read...</p>
<p>I finally took a look at the third comment on the PR, and on the one hand, I think I understand it, and it looks like it provides a better answer than I had to the second comment (which means the test I wrote is almost certainly wrong).
But, I've got no stamina lately, so I'm just going to take "I understand the third comment" as pretty much good enough, then try applying it for kicks.
Okay, it's in, and I'll get a response from Travis at some point.
Open source software can be so confusing in ways I'd rather not think about.
Oh well.</p>
<p>I think I've been in the mood to do some writing recently, but been getting writer's block right out of the gate.
I'm going to need to try again later sometime, when it's not 11 PM.</p>
<p>Okay, I absolutely should not be on my laptop any more.
Good night.</p>
Diary 2019-06-122019-06-12T04:00:00-04:002019-06-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-12:/diary-2019-06-12<p class="first last">Still kind of in "break mode" I think.</p>
<p>Solving a rock isn't normal, but in Baba Is You, it is.
Oh no, I found more ridiculous hidden levels.</p>
<p>Anyway, the plan for Jedi is apparently "do a new PR".
That's fine, I just think the code isn't ready yet, and I'm not currently working on it, because I was finding more and more <em>stuff</em> inside Baba Is You.
The next thing for me to tackle with Jedi is to figure out the third comment, which goes in-depth into something that I didn't understand at the time, and apparently got wrong.</p>
<p>Other stuff I've been doing...
I've been playing Nova Drift, and got on the Discord to report some bug or other.
Being on there has exposed me to a group of players whose level I have definitely never been on.
I'm going to put together a collection of builds from the server to try out; I hadn't previously realized how ridiculous the Architect's mines were.</p>
<p>Also trying to put together more stuff for MonFree because that's where my interest is landing I guess.</p>
<p>That's all I've got fow now.
Good night.</p>
Weekly Roundup 2019-06-112019-06-11T04:00:00-04:002019-06-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-11:/weekly-roundup-2019-06-11<p class="first last">The meetings will continue... I mean, I hope not.</p>
<ul class="simple">
<li>Wednesday: I poked at chiptune stuff.</li>
<li>Thursday: I poked at chiptunes a little more, and said vague stuff about MonFree's direction.</li>
<li>Friday: I fixed the printer somewhat (it'd been kind of messed up for months) and said less vague stuff about MonFree's direction.</li>
<li>Saturday: I relaxed a lot following Friday's stuff. (I'm not sure I ever explained this, but I timestamp posts with midnight local time, the day after the activities they're about. So I was wiped out for the "Saturday" entry because of stuff I did for work on Friday.)</li>
<li>Sunday: I did some work on Jedi.</li>
<li>Monday: I did more work on Jedi, and mostly got really confused by GitHub's interface. I also tried to reconstruct a conlang, and got mildly frustrated with my past self.</li>
</ul>
<p>Next week, let's see...
Today, which is actually Monday, but I'd put it as "Tuesday" if I had Tuesday on the list above, I beat some things in Baba is You that it wasn't initially clear how to reach.
I've also got some GitHub comments to read on the Jedi stuff.</p>
Diary 2019-06-102019-06-10T04:00:00-04:002019-06-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-10:/diary-2019-06-10<p class="first last">When it comes to doing things in any particular order, do as I say, not as I do.</p>
<p>I'm working on some of the comments for Jedi.
GitHub's interface is confusing, at least if I don't use it for several months.
I made some changes, and then asked if the changes I made were the right ones to make.
That's not the right order at all.
Oh well.</p>
<p>After that, I started reconstructing the lexicon of the conlang I mentioned, and realized that I have some issues with the derivational morphology.
Even for a language where I wasn't trying too hard to differentiate from English, some of the correspondences are too exact.</p>
<p>And earlier today, I realized Seed was missing a specification for a workflow that it definitely needs.
Looks like I've got various bits of work, if not cut out for me, at least vaguely outlined.</p>
<p>I'm really sleepy now.
Good night.</p>
Diary 2019-06-092019-06-09T04:00:00-04:002019-06-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-09:/diary-2019-06-09<p class="first last">Some serious lying-around-for-hours today.</p>
<p>I mostly took it easy today, but I also did a little work on the Jedi stuff.
Like, very little.
A nonzero amount.</p>
<p>Other than that, we went shopping for new clothes.</p>
<p>I'd like to be up for more in-depth stuff on the weekends.
I'd also like work to ease off on all-day intensive stuff.
There may be a connection here.</p>
<p>Well, I can't think of anything else to write today, so I'm calling it.
Good night.</p>
Diary 2019-06-082019-06-08T04:00:00-04:002019-06-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-08:/diary-2019-06-08<p class="first last">Weekend, please be relaxing.</p>
<p>Yet another day of doing stuff I hadn't entirely planned to, thus ending up exhausted and playing various games to unwind.</p>
<p>Tomorrow, I think I'll finally try to get on the Jedi improvements.</p>
<p>Wow, this is some serious being-wiped-out.
Good night.</p>
Diary 2019-06-072019-06-07T04:00:00-04:002019-06-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-07:/diary-2019-06-07<p class="first last">I should put "and a pony" at the end of the design priority list.</p>
<p>Earlier today, I got the printer working a little better, which will be good for making templates and hard copies of rpg rulebooks.</p>
<p>Other than that, I think I mostly just spaced out, following five hours of meetings.</p>
<p>Also, I tried to do some design work for MonFree Retro, and decided that the other one should be renamed.
For now, I'm thinking "MonFree Tales".
My goal on this project right now is figuring out how to organize my priorities, and get them down, because I've got some high-level ideas that are in conflict.
Basically, I'm a big fan of flavorful "gimmick" monsters, but I don't want them to be counterproductive to use, or game-breaking, so I need to put some serious effort into balancing, but I want to have a lot of them.</p>
<p>Well, I'm done for tonight, having spaced out some more while writing this.
Good night.</p>
Diary 2019-06-062019-06-06T04:00:00-04:002019-06-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-06:/diary-2019-06-06<p class="first last">Headache blogging</p>
<p>I'm managing some kind of proto-migraine right now, so I'm going to try to actually write this post quickly.</p>
<p>Earlier today, I messed around a bit on the PICO-8, got some SFX/music stuff that's okay, I guess.
I'm thinking I'd like to switch for a while to a tracker that's more focused on imitating physical instruments.</p>
<p>Anyway, I'm reading articles on multiplayer game design in brief bursts, and seeing if I can apply them to MonFree, since Dennis was a prerequisite to MonFree.
Having heard about the directions that certain large franchises are taking, I've come to the conclusion that, rather than trying to copy shiny elements of other games, I should focus on what's appealing to me.
The result may end up being... mildly impenetrable.
I'll have to draw up a proper design later.</p>
Diary 2019-06-052019-06-05T04:00:00-04:002019-06-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-05:/diary-2019-06-05<p class="first last">A reasonable amount of work.</p>
<p>Taking it easy like I said.
Earlier, I went over my attempts to do chiptunes stuff.
The basic problem I'm seeing currently is that I don't have a good sense of instrumentation, so everything is sine waves or "organ".
I've got the somewhat reinforcing problems of not having a good sense of which instruments go to which part of the sheet music in the full arrangement, and not having a good sense of how to instrument for the PICO-8 in any case.
I'm thinking the best way forward with composition here would be to try to do some more minimal stuff.
If it fits in a single SFX, I can consider the whole thing at once.
This would lock me out of some of the tricks I used to implement triplets and weird measure lengths, but that's not a problem if the whole point is to do simple stuff.</p>
<p>I also took a look over the lexicon for the conlang I mentioned, and it looks like I actually am going to have to translate a bunch of the sample to recover portions of the lexicon.
Oops.</p>
<p>I don't have any kind of a summary here.
Um, take care of yourself and try to avoid burnout?
I don't know.
Good night.</p>
Weekly Roundup 2019-06-042019-06-04T04:00:00-04:002019-06-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-04:/weekly-roundup-2019-06-04<p class="first last">I swear I wasn't trying to make that last post an object lesson; the code is just genuinely bad.</p>
<ul class="simple">
<li>Wednesday: I motivated the Seed project, and started tossing out ideas.</li>
<li>Thursday: I tried to lay out requirements for Seed.</li>
<li>Friday: I put up the post-mortem for Dennis.</li>
<li>Saturday: I outlined a little more how Seed should work.</li>
<li>Sunday: I was tired.</li>
<li>Monday: I made some stubs for Seed, and posted some untested code that, on later inspection, turned out to be <em>extremely</em> wrong.</li>
</ul>
<p>Next week, I've got a bunch of stuff I want to cover, and I'm desperately in need of organization, so we'll see how that goes.
Maybe I should try taking it easy for a bit?</p>
Seed 2019-06-032019-06-03T04:00:00-04:002019-06-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-03:/seed-2019-06-03<p class="first last">Lots of stuff that I did not think through all the way.</p>
<p>I was focused on other stuff again today, and then I tried to write stubs for as many commands as I could think of.
I then forgot to do anything resembling TDD, and put together these monstrosities with no tests whatsoever:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">cast_out_different</span><span class="p">(</span>
<span class="n">left_list</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span> <span class="n">right_list</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterable</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="n">left_set</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">left_list</span><span class="p">)</span>
<span class="n">right_set</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">right_list</span><span class="p">)</span>
<span class="n">left_list</span><span class="p">[:]</span> <span class="o">=</span> <span class="n">right_list</span><span class="p">[:]</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">left_set</span><span class="o">.</span><span class="n">intersection</span><span class="p">(</span><span class="n">right_set</span><span class="p">))</span>
<span class="k">yield from</span> <span class="n">left_set</span><span class="o">.</span><span class="n">symmetric_difference</span><span class="p">(</span><span class="n">right_set</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">compare_trees</span><span class="p">(</span><span class="n">left</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">right</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterable</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="k">for</span> <span class="p">(</span>
<span class="p">(</span><span class="n">left_dirpath</span><span class="p">,</span> <span class="n">left_dirnames</span><span class="p">,</span> <span class="n">left_filenames</span><span class="p">),</span>
<span class="p">(</span><span class="n">right_dirpath</span><span class="p">,</span> <span class="n">right_dirnames</span><span class="p">,</span> <span class="n">right_filenames</span><span class="p">),</span>
<span class="p">)</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">left</span><span class="p">),</span> <span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">right</span><span class="p">)):</span>
<span class="k">yield from</span> <span class="n">cast_out_different</span><span class="p">(</span><span class="n">left_dirnames</span><span class="p">,</span> <span class="n">right_dirnames</span><span class="p">)</span>
<span class="k">yield from</span> <span class="n">cast_out_different</span><span class="p">(</span><span class="n">left_filenames</span><span class="p">,</span> <span class="n">right_filenames</span><span class="p">)</span>
<span class="k">for</span> <span class="n">fn</span> <span class="ow">in</span> <span class="n">left_filenames</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">filecmp</span><span class="o">.</span><span class="n">cmp</span><span class="p">(</span>
<span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">left_dirpath</span><span class="p">,</span> <span class="n">fn</span><span class="p">),</span>
<span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">right_dirpath</span><span class="p">,</span> <span class="n">fn</span><span class="p">),</span>
<span class="n">shallow</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="p">):</span>
<span class="k">yield</span> <span class="n">fn</span>
</pre></div>
<p>I'm not at all sure these work right, and I don't know if it's obvious what they're supposed to do.
In any case, I'm going to try later to get things set up a little more correctly.
Things to do include:</p>
<ul class="simple">
<li>Create a workspace for repos</li>
<li>Make a poetry project seed repo</li>
<li>Set up a local Python index (this is more for Dennis than Seed)</li>
<li>Convert the current repo for Seed into a Seed repo that's seeded from the poetry project repo.</li>
</ul>
<p>Misc other stuff from today:</p>
<ul class="simple">
<li>We're planning to go clothes shopping later on account of I shrank over the past year and a half.</li>
<li>I remembered some conlanging I did (I don't remember if I ever wrote it up here), and I'm like, I really hope I did the lexicon all the way, because otherwise I'm going to have to reverse-engineer any gaps from the fact that the language sample is Genesis 11. It'd be like doing Rosetta stone style analysis of a language I created, which is to say, somehow really cool and really stupid for basically the exact same reasons.</li>
</ul>
<p>I'd better wrap things up now so I have a chance to get on some of that tomorrow.
Good night.</p>
Diary 2019-06-022019-06-02T04:00:00-04:002019-06-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-02:/diary-2019-06-02<p class="first last">Doing things is old and busted, lying around totally exhausted is the new hotness.</p>
<p>Didn't get anything done today on any projects because we went out of town again, and came back exhausted.</p>
<p>So far as other projects, I think I'll officially take a break from drawing for a bit, rather than being all "I'll turn it around this week for sure!" and then... not doing that.</p>
<p>Good night.</p>
Seed 2019-06-012019-06-01T04:00:00-04:002019-06-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-06-01:/seed-2019-06-01<p class="first last">Test... gated development, maybe? It can't be "driven" because you can write the tests last, and it will accept it so long as the tests fail against the releasable code.</p>
<p>I've got enough diagrams, proofs-of-concept, and notes on Seed's design that I think I'll be ready to tackle it, once I have the energy.
I'll try to get on this tomorrow afternoon or so (probably by making a todo list first), but for now I'll try to lay out what I want to try to do with Seed.</p>
<p>The cloning model that gave Seed its name is relatively simple, but I ended up thinking, you know, while I'm thinking of workflows, why don't I see what I can come up with for the stuff that isn't cloning out new projects?</p>
<p>There were three basic areas I ended up trying to cover, more-or-less orthogonal, but with some dependencies:</p>
<ul class="simple">
<li>A workflow inspired by test-driven-development</li>
<li>Branches based on possible future semver versions</li>
<li>A way to have generated code be "tracked" without polluting the master or development branches.</li>
</ul>
<p>For the semver stuff, there's a "master" branch that can produce any of the "next" possible semvers after the highest release: a major, minor, or patch version.
Furthermore, there are branches for older major versions, which can produce new minor versions, and branches for older minor versions, which can produce new patch versions.
My current notes don't enforce any dependencies between these forked-out branches.</p>
<p>For TDD, I've got the following basic ideas:</p>
<ul class="simple">
<li>All potentially releasable branches must only ever test green.</li>
<li>There are "feature" branches which are associated with a release branch, test red, and only differ from their associated branch in test code.</li>
<li>There are transient "refactor" branches that involve changes to test code or code under test, not both. They must be green to be accepted, and merge to their corresponding releasable branch.</li>
<li>None of these kinds of branch should have conflicts.</li>
<li>"feature" branches can be modified with changes to test code or code under test, not both at once. Test code changes that maintain red are accepted; test code changes that convert to green prompt the user for whether it should be counted as a refactor; code-under-test changes that maintain red are rejected, and changes that convert to green are accepted.</li>
<li>Changes to the releasable code render other branches <em>stale</em> (they're missing patches). The condition has to be manually removed by a "freshen" command, which basically attempts to recreate the branch from the new releasable code, and the result is either "red" (replace), "green" (confirm merge), or "conflict" (abort freshen, prompt user to resolve manually).</li>
</ul>
<p>For builds, I haven't quite nailed it down.
There basically needs to be a branch that takes no patches and has different ignore behavior.
Another possibility would be to take patches, commit build artifacts on the branch, one branch per releasable branch.
In any case, the intermediate build is done from the releasable branch with the target directory in the build branch (there are a lot of clones), then the final build is done from the build branch and the artifacts propagated to the other directories.</p>
<p>I think all of this covers everything I'd like to do with this idea.
I'll have to write up a list tomorrow, like I said, and probably draw some tables.</p>
<p>It's super late.
Good night.</p>
Dennis 2019-05-31 (post-mortem)2019-05-31T04:00:00-04:002019-05-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-31:/dennis-2019-05-31<p class="first last">I don't know if this is good enough, but I wanted to get it over with for now. Much like Dennis!</p>
<p>Note: previous Dennis posts are in the <a class="reference external" href="https://mwchase.neocities.org/diary-2019-05-26">Diary</a> category.</p>
<p>So, I heaved the codebase over the finish line.
There are a few features missing, some ergonomic issues, and some code that should really be different.
Also, even with all of my tweaks, rewrites, and type annotations, it's still deficient in terms of quality, in some pretty serious ways.</p>
<p>Now that I'd like to take a break from touching this and reorient myself, it might be a good idea to provide some context for all of this.</p>
<p>Dennis is my second attempt to follow along with <a class="reference external" href="http://rogueliketutorials.com/tutorials/tcod/">TStand90's roguelike tutorial</a>.
The previous attempt, Homunculus, was done against an earlier version of the tutorial over a period of several months last year.
The two codebases are completely unrelated.
Homunculus ended up stalling out before reaching the end of the tutorial, because I didn't see a good way to implement certain functional programming concepts in Python that I <em>really wanted</em>, and I got distracted working on Structured Data in an attempt to develop implementations for them.
I've had trouble (very visibly so) giving the tutorial credit for providing a basic template of functionality; I've been really distracted by the way the tutorial ignores various good development practices, and the code samples are sometimes out of synch between boxes, within boxes, and with the code in the git repo.
<em>Nonetheless</em>, without some form of example code to look at for implementing the relevant functionality, Dennis would not have been possible.</p>
<p>All that said, let's break things down some.
Resources that went into Dennis:</p>
<ul class="simple">
<li>TStand90's tutorial</li>
<li><a class="reference external" href="https://poetry.eustace.io/">Poetry</a></li>
<li><a class="reference external" href="http://coconut-lang.org/">Coconut</a></li>
<li><a class="reference external" href="https://www.pyinvoke.org/">Invoke</a></li>
<li><a class="reference external" href="https://nox.thea.codes/">Nox</a></li>
<li><a class="reference external" href="https://github.com/pyenv/pyenv">pyenv</a> and <a class="reference external" href="https://github.com/pyenv/pyenv-virtualenv">pyenv-virtualenv</a></li>
<li>A few libraries and tools that I don't think I exercised to their fullest potential, such as <a class="reference external" href="http://www.structlog.org/">structlog</a> and <a class="reference external" href="https://www.pylint.org/">pyreverse</a></li>
<li>Various libraries and tools that I have more experience with so they didn't really register. (Mercurial, pytest, camel, coverage, mypy)</li>
</ul>
<p>At a high level, I've been trying out Poetry for several projects because I don't feel like it's worth writing and maintaining a setup.py file, and a MANIFEST.in and whatever else is supposed to be in there.
I've been using Poetry because it's the only alternative I know of that supports using <a class="reference external" href="https://hynek.me/articles/testing-packaging/#src">src layout</a>.</p>
<p>I've been trying out Nox recently because I've felt like, as opposed to <a class="reference external" href="https://tox.readthedocs.org/">tox</a>, it is worth using a general-purpose programming language to define the kinds of tasks I'm doing.
Nox's documentation mentions Invoke, and so I ended up using Invoke for tasks that don't logically fit into a virtual environment with a particular configuration of Dennis installed.</p>
<p>Homunculus stalled out because I felt like I didn't have a good way in Python to do destructuring with user-defined types, and so I made one, and ended up getting caught up in extending it and figuring out what functionality it "should" have.
Coconut provides the baseline required for what I wanted the features to accomplish, so it allowed me to put aside questions of how it should work, and just use it.
That said, there were a few hurdles:</p>
<ul class="simple">
<li>Where they overlap, Structured Data and Coconut have some key differences in behavior: Coconut's "data" classes don't override tuple-based truthiness logic, so I ended up hitting weird bugs until I remembered to explicitly check whether a value of a zero-length data type was <tt class="docutils literal">None</tt>. Also, Coconut's "match" statement places requirements on the pattern that don't exist in Structured Data; Structured Data "structures" are constructed at runtime, so any expression can evaluate to a structure, in theory. In contrast, Coconut's match seems to require the exact class name in scope, which goes against many Python style guides when it comes to defining a class in one module and matching against it in another.</li>
<li>I managed to get Coconut to compile, in strict mode with no warnings, to syntactically invalid Python.</li>
<li>For the Mypy integration, it seems like Mypy should be more able to reason about some of the constructs Coconut generates.</li>
<li>Coconut's tooling is not where I'd like it to be, in an ideal world. No equivalent to Jedi; the autocompletion was bizarre and weak, and it doesn't even complete stuff from the standard library, aside from builtins. I kept on tab-completing <tt class="docutils literal">typing.Call</tt> to <tt class="docutils literal">typing.callable</tt>, which isn't a thing. I haven't run across any formatters; I mainly reacted to this by often being lazy and writing <em>really</em> long lines.</li>
</ul>
<p>One thing that has me feeling a little iffy towards Poetry is that it doesn't currently have a documented way to interact with generated code like Coconut produces.
(See, I really don't want to commit the generated code—I tried it and gave up after a few days—so that means I'm ignoring it for convenience, which means that the only reason Poetry sees <em>anything</em> to build is that I'm not using Git.)
I haven't noticed any issues with it in the absence of generated code.
I really like the robust dependency resolution.
BUT Coconut was one of the absolutely essential bits of tooling for this project.</p>
<p>Taken together, this kind of makes my feeling on Coconut that I'd like to extract out the functionality I'd least like to rewrite in-place, and somehow take a mulligan on Structured Data focusing on just that functionality.
Maybe Python 3.8's features would be helpful for this kind of thing...</p>
<div class="highlight"><pre><span></span><span class="go">Python 3.8.0a4+ (heads/master:331a6a56e9, May 27 2019, 11:07:29)</span>
<span class="go">[Clang 10.0.0 (clang-1000.11.45.5)] on darwin</span>
<span class="go">Type "help", "copyright", "credits" or "license" for more information.</span>
<span class="gp">>>> </span><span class="n">abc</span> <span class="o">=</span> <span class="s2">"abc"</span>
<span class="gp">>>> </span><span class="k">if</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">)</span> <span class="o">:=</span> <span class="n">abc</span><span class="p">:</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">)</span>
<span class="gp">...</span>
File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>
<span class="gr">SyntaxError</span>: <span class="n">cannot use named assignment with tuple</span>
</pre></div>
<p>Nope.
Another possibility would be looking into libraries like <a class="reference external" href="https://attrs.readthedocs.io">attrs</a> to see if anything fits my use case particularly well.
A mix of approaches might make sense, as well.</p>
<p>Miscellaneous notes from development...
PEP 518 was only <a class="reference external" href="https://github.com/python/peps/commit/b5a4f071d5ef3bc0034a3a9a833d0d90faef8c5f">recently clarified</a>, and I'm pretty sure I saw people who interpreted the pre-clarification wording as the opposite of the clarification.</p>
<p>Anyway, that's what was on my mind once I got done with Dennis.
I'd like to do a few iterations of the "Seed" concept, then migrate the repo over somehow, and start iterating on factoring out libraries.</p>
<p>Note: previous Dennis posts are in the <a class="reference external" href="https://mwchase.neocities.org/diary-2019-05-26">Diary</a> category.</p>
Seed 2019-05-302019-05-30T04:00:00-04:002019-05-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-30:/seed-2019-05-30<p class="first last">Somewhat worried that I'm going to run across an article describing much the same ideas I'm having, and then it'll be all "The user experience was awful and everyone hated it."</p>
<p>I've refined my ideas for Seed a bit.
I currently have a bunch of interesting ideas for limitations of high-level concepts, that I'm going to need to see how it all shakes out in practice.</p>
<p>I just tossed together the very, very basics of the wrapper, just exposing all of the commands that I'm pretty sure need to be passed through as-is.
I don't want to try to push through this right now; I've been getting to bed earlier lately, which is probably a good thing.</p>
<p>Anyway, I'm thinking when I have the time to try to develop this stuff, I'll try to use the workflows I have in mind manually.</p>
<p>One idea that I think I might look into later, that wouldn't fit into the base workflows, would be making a repository that's some transformation applied to another one.
I'm not enthusiastic about this idea.
The intent is to have some kind of workaround in case tools like Poetry end up supporting many more repo formats, but the same set of use-cases.
(Specifically, not having an obvious way to deal with generated code.)
My intuition is that shoving a repo into this mold would on average cause more problems than it would solve.
Maybe instead there could be the possibility of creating a "build" branch that gets generated code added to auto-generated patches in a clone, then puts the artifacts back in the source repo.
This would be a somewhat involved process, but most of it could be automated.</p>
<p>Anyway, I really need to wrap up.
Good night.</p>
Seed 2019-05-292019-05-29T04:00:00-04:002019-05-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-29:/seed-2019-05-29<p class="first last">Thinking about experimental wrappers around pre-1.0 software...</p>
<p>One thing I noticed while working on Dennis was that I was dividing the code into different components, roughly per-module.
Some code is responsible for displaying graphics, some is a generic implementation of a high-level design pattern, some is for generating fake events for testing purposes, some code is for generating fake events for testing purposes.
It's hard for me to come up with a precise count, but nearly half of the source files would have general utility for game programming, in that I could imagine using them to make a game in a different "genre" than roguelike.
This makes me think of trying to use the same code in multiple distinct projects, and thus think "How would I like to do that?"</p>
<p>The standard dichotomy for this question of coordinating this kind of reusable code is "monorepo" vs "multirepo".
I don't want to rehash the pros and cons as applied to either an abstract repository that exists for rhetorical purposes, or a specific closed-source repository; there's plenty of both of those rundowns on the internet, as well as some open-source examples.</p>
<p>So, in Dennis, right now, there are several modules that have <em>no</em> in-project dependencies.
These are potential candidates for factoring out into their own projects.
Some of them are project-specific and just happen to not import stuff, so they shouldn't be broken out.
(And maybe this is an indicator that some of their interface should be broken out <em>within</em> the project?
I'm not sure.)</p>
<p>But suppose I go "You know what, this vector code seems pretty generic, and I'd rather not copy it around"...
I'd want to create a new project containing the vector code, and if it somehow has other code, remove that code.
Make sure the new project has a different name, and a fresh semver, get it working.
Then, add a dependency on the new project, and remove the old code, get it working, and cut a new release of the original project.</p>
<p>In an internet-approved monorepo, each project is a directory under the repository root, and near as I can tell, semver isn't really a thing in the relevant workflows.
I'm not sure anyone's laid out any "here's how you multirepo" guides in contrast to the "here's how you monorepo" ones, but here's something that occurred to me...
The biggest friction I've had, that projects like cookiecutter are meant to deal with, is in bringing a fresh repository from "nothing" to "valid configuration for building".
Doing that is a pain, it has a lot of busywork, so I would say that creating fresh repositories is hard.
<em>But</em>, in a distributed world, in a world of Mercurial and Pijul, Darcs, Fossil, Bazaar, and, yes, Git, if you have one repo in a valid configuration for building, you have as many repos in a valid configuration for building as you want.
Suppose the workflow for making a new project isn't based on <tt class="docutils literal">init</tt>, <tt class="docutils literal">cp</tt>, or <tt class="docutils literal">mkdir</tt>, but <tt class="docutils literal">clone</tt>?</p>
<p>What I'm visualizing is a collection of projects that all derive from a common "seed" repo that represents a minimal project.
The "seed" repo should be in the paths config for all other repositories.
In the event of collaboration, the "default" url should be the shared remote repo; I haven't thought too hard yet about how collaboration should actually work.
So, tasks involved in this layout:</p>
<ul class="simple">
<li>Fix bugs/add functionality: work within a single repo, cut a new version</li>
<li>Factor out functionality into new project: clone source, rename/update, publish (probably to local index), add dependency to source and remove old code</li>
<li>Add common tooling: update seed repo, and then, um... not sure when and how best to require repos to pull and merge. Do normal development on topic branches, only allow merge to master when tests are green, disallow merge to master when there's a diff with the seed repo, pull seed repo changes to topic branch and follow normal procedure for merging? Will need to take another look at this, that was all just spitballing.</li>
</ul>
<p>(Maybe I want to have a "seed" branch that is kept in synch between all repos, and merged into master?)
(I'm moderately tempted to see how much effort it would take to formalize this on top of Pijul.
Maybe avoid the topic-branch stuff.
Do this with Pijul, and there's a seed repo that holds the common set of patches.
Maybe use branches kind of like, okay, there's master, and release.
Pushes and development hit master, builds are from release, and hm, I haven't thought this all the way through.)</p>
<p>Since I'm thinking about this for personal projects that I might or might not open-source all or any of, I'm going to focus on stuff I can set up up on my laptop.</p>
<p>Okay, I looked into Pijul a little more, and here's what I think I want whatever script I write, working title "seed", to do:</p>
<ul class="simple">
<li><tt class="docutils literal">seed init</tt>: Create a Pijul repo with a default <tt class="docutils literal">seed.toml</tt> file in it.</li>
<li><tt class="docutils literal">seed fork <name></tt>: In a seed repo, creates a clone of the current repo, configured to use the current repo as the seed. In a non-seed repo, creates a clone of the current repo, configured to use the same seed as the current repo. Question: how to distringuish between seed and non-seed? The TOML file? Note: Seed repo should have just "master" branch. Non-seed should have "master" and "release". Clones should clone "master" from source, not sure about "release". Note: New repo should be next to source repo, fail if name exists.</li>
<li><tt class="docutils literal">seed pull</tt>: Pulls changes from the seed repo to "master".</li>
<li><tt class="docutils literal">seed pr <patches></tt>: Creates a pr branch with a unique name from "release", applies patches, runs tests. Need to figure out the rest of the flow.</li>
<li>Some kind of command for actually cutting a release, which should create a tag in the release branch.</li>
</ul>
<p>The high-level idea I have behind the configuration file is that, for a given task, such as "run tests", there should be a simple command to accomplish that.</p>
<p>Okay, this idea isn't all-the-way baked, but I think there's some potential in prototyping it.
I'll give it a shot later.</p>
Weekly Roundup 2019-05-282019-05-28T04:00:00-04:002019-05-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-28:/weekly-roundup-2019-05-28<p class="first last">A week that got a lot better once my muscles stopped hurting.</p>
<ul class="simple">
<li>Wednesday: I was still sort of sick, but I was able to do some work on Dennis. I left myself a note to work on Jedi later, which I did not do.</li>
<li>Thursday: I did more work on Dennis, and decided that versioning generated code was a bad time.</li>
<li>Friday: I did some refactors that weren't refactors, because they broke things.</li>
<li>Saturday: I fixed a variety of bugs that ended up in the code.</li>
<li>Sunday: I finished the tutorial. The code has definite potential for improvement, but I'd rather take a break.</li>
<li>Draw a Box: I got some work done, then ran into not having a good way to print out templates here. I'll see about rememdying that by this weekend.</li>
</ul>
<p>Next week, maybe I'll look over the PR.
Also, I'm trying to write a retrospective on Dennis.
(I just realized I got through the tutorial in just a month, wow.)</p>
<p>PS I updated my masto link(s).</p>
Draw a Box 2019-05-272019-05-27T04:00:00-04:002019-05-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-27:/draw-a-box-2019-05-27<p class="first last">Eh, could have been better, as usual.</p>
<p>In this post:</p>
<ul class="simple">
<li>A little bit of work, still not great momentum.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>More outlines on May 24. I think I'll try doing texture studies tomorrow. I don't yet have a plan for ramping back up, but I felt like at least trying to hit the previous levels of activity now.</li>
<li>I missed that texture studies has a template, so I ended up just getting more reference images on May 25. Oh well.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Diary 2019-05-262019-05-26T04:00:00-04:002019-05-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-26:/diary-2019-05-26<p class="first last">Tutorial complete. Now, the real challenge begins.</p>
<p>ETA: Dennis posts continue in the <a class="reference external" href="https://mwchase.neocities.org/dennis-2019-05-31">category</a>.</p>
<p>I'm up through part 13 of the tutorial.
It's done, modulo whichever crash bugs I've introduced, and not yet encountered, of which there could be many.
I've got a few things I'd like to add, but for the moment, I'd like to avoid adding features, in favor of improving the code quality.
Like, neither the tutorial code, nor my adaptation, currently has docstrings.
(I think I have like, one, copied from the itertools recipes.)
There are also some organizational questions that I kind of held off on answering, but I'd like to look into.
And code that works, but I know I wrote wrong, because it's really confusing and unintuitive.</p>
<p>Regardless, I can play through far enough to fill my inventory with healing potions and fireball scrolls.
Defense OP, should nerf.</p>
<p>Anyway, I also want to look into trying out some other tooling.
Like, there are bits of the codebase that could, in theory, be broken out into their own projects.
I'd be interested in making a tiny monorepo for this stuff, and adapting my current ad-hoc build stuff to Bazel or something.</p>
<p>Anyway, I'm ready to take a break from this stuff, at least for a few days.</p>
<p>And, it's getting late.
Good night.</p>
<p>ETA: Dennis posts continue in the <a class="reference external" href="https://mwchase.neocities.org/dennis-2019-05-31">category</a>.</p>
Diary 2019-05-252019-05-25T04:00:00-04:002019-05-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-25:/diary-2019-05-25<p class="first last">Having leveling break <em>sometimes</em> wasn't nice at all.</p>
<p>The rendering code makes a lot more sense now.
The stair code as I implemented it was broken in a way that the tutorial implied it might be, so I put in a workaround.
Leveling was mostly broken, as a consequence of how I wrote event handling; the details need to be better-specified so I can figure out how to avoid similar breakage in future.
I started implementing the weighted choice stuff, and as a prerequisite to using that, I've now got numpy's random implementation mostly wired in, though I suspect there's some undesirable behavior there that I'd also like to better specify.</p>
<p>Looking over the rest of part 12, finishing it up should be trivial.
It looks like part 13 shouldn't be much of a challenge either, so maybe there's a chance I can wrap up adding features tomorrow, and then focus on polish, and working out what specific directions to take the codebase.</p>
<p>Good night.</p>
Diary 2019-05-242019-05-24T04:00:00-04:002019-05-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-24:/diary-2019-05-24<p class="first last">Not running the code for an extended period: not a great idea!</p>
<p>Quick update: I completed part 11, but along the way, I attempted to make some improvements to rendering, which ended up regressing some old bugs.
When I attempted to reapply the fix, the other improvements caused entirely new bugs to manifest.
I'd like to fix this properly, and that's going to mean carefully redesigning the abstraction I made for the rendering logic.</p>
<p>I'm going to try to do that tomorrow, and try to smoke out any other bugs.
Then, it'll be time to get back into part 12.</p>
<p>Good night.</p>
Diary 2019-05-232019-05-23T04:00:00-04:002019-05-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-23:/diary-2019-05-23<p class="first last">I ran into <tt class="docutils literal">'Your battle skills grow stronger! You reached level <span class="pre">{0}'.format(player.level.current_level)</span> + '!'</tt> and I frankly don't know how to process that.</p>
<p>I did some work on the level-up stuff today. Made the View, and its associated method, and some minor tweaks to various areas.
Starting this post inspired me to do a bit more, but I didn't feel like implementing the menu yet, so I'm leaving it there for tonight and coming back to it tomorrow.</p>
<p>One thing that I don't want to force out late at night is representing the stat boosts from leveling up in a separate data structure that gets added into the Fighter component.
Or rather, I just now coded the data structure, but I'd like to wrap up early, so I won't add it in yet.
Wiring it in is more effort than writing it, because I'll need to add it to the component, the serialization code, and the three component initializations.
I'll also want to add processing of it to the properties for the stats associated with the modifications.</p>
<p>Everything that remains in part 11 should be pretty straightforward, except for the menu code, because I have to look up the deprecation chains every time.</p>
<p>Something else on my mind is how exactly I want to test some of this behavior.
Like, I don't actually care about replicating a sequence of behaviors with the Confused, AI, I just want to assert that it makes no illegal moves, and wears off in the proper timeframe.
Maybe if I have isolated tests for confusion and going down stairs, I can handle the rest more easily.</p>
<p>One other note: I fumbled a set of commits earlier today in terms of committing generated code in the right order, so I've now decided that I don't want to do that.
First thing tomorrow, when it comes time to work on this, I'm going to remove the generated code and the customizations that make it work, go back to ignoring it.
I've reopened the feature request relating to this use case.</p>
<p>That's enough (or too much) rambling for now.
Good night.</p>
Diary 2019-05-222019-05-22T04:00:00-04:002019-05-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-22:/diary-2019-05-22<p class="first last">I'm not pair programming this, but maybe I should get a rubber duck.</p>
<p>Sickness status: mostly just really sore.</p>
<p>I did a little work on Dennis today:</p>
<ul class="simple">
<li>Factored FOV recomputation out of the render code</li>
<li>Added dungeon floor printing to the stats section</li>
<li>First draft of the Level component.</li>
<li>A few iterations on the Level component.</li>
</ul>
<p>I haven't written the views for it, which is where the level-up logic is going to go.</p>
<p>Speaking of "views", I should try to get the tutorial wrapped up, the code polished, and to write up my architecture, because I just counted, and of the modules I have in the source currently, less than half of them have a directly corresponding module in the tutorial I'm looking at.</p>
<p>In other projects, I've got some improvements I have to make to the Jedi PR, but I don't want to try that yet.
I'll try to handle that over the weekend.</p>
Weekly Roundup 2019-05-212019-05-21T04:00:00-04:002019-05-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-21:/weekly-roundup-2019-05-21<p class="first last">I woke up this morning super-tired. Then things got worse.</p>
<ul class="simple">
<li>Wednesday: I did some debugging, and planned out roughly how things went for the rest of the week.</li>
<li>Thursday: I reorganized the code some, and put the planning from Wednesday into the actual todo list.</li>
<li>Friday: I finished the reorganization, and got ready to componentize the GameMap.</li>
<li>Saturday: I redid the handling of generated code so that it gets versioned with everything else. Not sure if that makes sense overall, but I did this as a precaution in case Poetry gets Mercurial support. I also started working on supporting replays.</li>
<li>Sunday: We drove into Boston and I decided against forcing myself to produce Content late at night.</li>
<li>Monday: Because of how the weekend went, rather than a drawing update, I did more code work and update.</li>
</ul>
<p>Next week, I'll take things easy until I stop being sick.</p>
Diary 2019-05-202019-05-20T04:00:00-04:002019-05-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-20:/diary-2019-05-20<p class="first last">The code type-checks, surely that's good enough! (Real talk: I'll have to be very lucky to get this code to work when I finally fire it up.)</p>
<p>No drawing today because I just didn't feel like it this weekend.
I'm getting really excited by all the work I've got done on Dennis.
Things are blurring together a little, but going by the items checked off on my to-do list today, I:</p>
<ul class="simple">
<li>Did some fundamental updates to the way the core game-step logic works</li>
<li>Consolidated the rendering code into a single (admittedly somewhat janky) class</li>
<li>Added several commands</li>
<li>Extended the GameMap component</li>
<li>Added stairs sprites, components, commands</li>
</ul>
<p>The main thing I need to move onto the other half of part 11 is to add the dungeon level display to the rendering.
The thing that's holding me back from that is the sense that there's more refactoring to be done that would make this more natural somehow.
If I can't figure it out by the end of the day tomorrow, I'll just push through.
I've got the feeling that I "should be" able to come up with some kind of abstraction like a scene graph, probably precalculate most of the layout because it probably shouldn't be dynamic.</p>
<p>I also, um, have not actually spun up the game in a while.
I mean, every time I add a component, it breaks the save format because I don't want to go to the trouble of writing deserializers for a format that only existed for a few days.
Pretty sure this is laziness, but I still feel justified.</p>
<p>Other stuff I did today: shuffle around accounts in my fedi client, queue up some other sites to look into getting accounts for later.
When I figure out what's what, I'll update my footer, which will be a fun site update.
(Cue briefly forgetting where that part of the footer is even defined.)
(It's in my <tt class="docutils literal">pelicanconf.py</tt>.)</p>
<p>Anyway, the buried lede on all of this is that through the simple measure of "writing down when I finished a thing", I can later look up <em>when I finished the thing</em>, so todo.txt is paying some serious dividends at this point.</p>
<p>Definitely will try to rearrange things some next week, scheduling-wise.</p>
Diary 2019-05-192019-05-19T04:00:00-04:002019-05-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-19:/diary-2019-05-19<p class="first last">I didn't do anything today that fits in the usual blog topics.</p>
<p>Nothing to say about today.
I was out of town for hours, so I didn't work on anything.</p>
<p>I'll try to do more in the next few days, but going through stuff now, trying to get into the zone, would be a bad idea.</p>
<p>Good night.</p>
Diary 2019-05-182019-05-18T04:00:00-04:002019-05-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-18:/diary-2019-05-18<p class="first last">So close to having things be completely reproducible...</p>
<p>Today, I was really tired all day, which wasn't great.
Anyway, I finished moving the GameMap into the ECS, and now it's only really awkward in the places that I haven't yet refactored, like the core game logic and the rendering code.
I also made some changes to how the repository is handled.
Instead of ignoring the generated source code, I added a pre-commit hook to update the generated code, and addremove the generated files.
I also added an alias to diff that excludes the generated files.
The hook implementation has me a little nervous, but I prefer it to the possibility of taking a build system update that just completely wipes out the build.</p>
<p>Anyway, my next priority is adding the RNG into the save files, which will allow me to get perfect replays.
My current plan for that is to allow saving numpy's Mersenne Twister data structure (already done), and incorporate it into the code that relies on randint.
Basically, the Game object would have one, and pass it into the generator code, and also use it to seed new ones to pass into the item use functions, where they could then be used by stuff like the Confused AI.
I'm kind of sad I don't have the ability to express Rust-style ownership here; I'd really like to be able to be all "pass it in here as a mutable borrow, and this class here needs to take it by owner, so you have to make a new one".
What it comes down to is, I haven't yet worked out the exact way I want this to look, so I can't make the change yet, because I don't know what change I want.
Maybe this would be more obvious if I put the replay stuff on hold, and went to following along with part 11.
I'll sleep on it and see what I think in the next few days.</p>
<p>For now, I'm going to try to wrap up sooner than I did last night.
Good night.</p>
Diary 2019-05-172019-05-17T04:00:00-04:002019-05-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-17:/diary-2019-05-17<p class="first last">Cutting down nicely on long-range dependencies.</p>
<p>I made some good progress today.
I finished moving the bulk of the serialization code into the relevant modules, made some much-needed simplifications to the ecs code, consolidated some other code into a relevant module, and then started work on one of the big improvements I've been eager to get to.</p>
<p>Previously, there was a single game map, so it was stored as a de-facto global on the Game object.
I'm laying the groundwork for having multiple dungeon floors, and it seems to me that "which map the coordinates apply to" should be an aspect of the position component, which means I need to pull the maps into the ecs.
I've done that, and fixed most but not all of the code that needs to change.
One of the things that interests me is what comes next, since the Game object won't need to track the map explicitly any more: the active map is just the map referred to by the player's position.
This means I get to get rid of a bunch of explicit handling of the game map.
It might also mean that some of the "can/cannot walk there" sanity checking might get to move into the "MappedView" component, which, again, reduces explicit handling.</p>
<p>Once this is done, my priorities are getting logging in everywhere and correctly, possibly tweaking some of the processing or output.
Then, reworking the usage of random numbers.
Then, I can try to put together replay support.
After that, I'm going to start looking at the tutorial again.</p>
<p>Well, however much of that happens soon, it happens <em>tomorrow</em>.
Good night.</p>
Diary 2019-05-162019-05-16T04:00:00-04:002019-05-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-16:/diary-2019-05-16<p class="first last">Hardcore organizational action</p>
<p>I didn't push too hard to get stuff done today.
I started moving the serialization registry definitions into the modules that defined the type in question, on the logic that, since the serialization code relies so heavily on the type's layout and constructor behavior.</p>
<p>For after that's done, I looked over yesterday's post, and incorporated the tasks and orderings into my todo file.
So, now I've got a really thorough list of things that need to happen, roughly in dependency order.
It's a little intimidating, but I'll just try to make progress on it every day.</p>
<p>Looking over the list is also making me think about what directions I want to take this code in after I reach the end of part 13.
My inclination is to figure out how to translate the code manually to Python, coming up with whatever library support I need.
From there, find collaborators, and work on polishing the code and expanding it into a tutorial series.
(I don't feel qualified to do a tutorial series on Coconut, and it seems like I'm using some of its features similarly to how my old boss's wife used Class Namespaces: as a stepping stone or temporary measure before or during a refactor.)
I'll also want to revisit the old idea I had of adapting the code into specific games that I'm more interested in.
Probably focus on trying to make non-code resources and concept stuff for them.</p>
<p>For now, though, the best thing to work on, is sleeping.
Good night.</p>
Diary 2019-05-152019-05-15T04:00:00-04:002019-05-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-15:/diary-2019-05-15<p class="first last">Great debugging moment of the day: realizing that, if my most-of-the-background-colored text isn't on top of the different-colored section of background, I won't see it.</p>
<p>So, the good news is, I came up with a bunch of simplifications that enhance correctness and type coverage, though probably not, like, speed.
The bad news is, when I was testing them out, I discovered that I somehow broke a completely unrelated code path.
I chose to focus on getting the code to work, which in this case meant replacing some math and a library function call with a different library function call.</p>
<p>Now that I've got those changes done, here's some high-priority ones:</p>
<ul class="simple">
<li>Use the GameMap component</li>
<li>Make the randomness controllable</li>
<li>Create a replay format</li>
<li>See if the replays can be used to work with tests</li>
</ul>
<p>I'll probably put other stuff above the last one, once I get to it.
In part because it'll allow me to do my own version of some of the part 11 stuff.
Let's see what that looks like:</p>
<ul class="simple">
<li>Use the GameMap component</li>
<li>Add game_map field to the Position component</li>
<li>Add integer dungeon_level to GameMap</li>
<li>Create Teleporter component, which has either a target entity, or a callback to create a target entity. (Maybe create TeleporterUp and TeleporterDown?)</li>
<li>Create Stairs sprites</li>
<li>Create events for stairs</li>
<li>Finally do the method-extraction rewrite of the Game class</li>
<li>Write handlers for stairs actions</li>
<li>Add stairs to RenderOrder</li>
<li>Various tweaks to rendering</li>
<li>Add wait command</li>
</ul>
<p>There's also level-related stuff, but I want to take care of this half of the part first.</p>
<p>Looking over the remaining tutorial, I believe I can finish things up relatively quickly, do some code polish, and then start figuring out what I want to adapt this code into.</p>
Weekly Roundup 2019-05-142019-05-14T04:00:00-04:002019-05-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-14:/weekly-roundup-2019-05-14<p class="first last">Had to, and have to, work on getting rid of some technical debt.</p>
<ul class="simple">
<li>Wednesday: I did some refactoring, and ran into parts of Coconut that <em>do not</em> act like Structured Data.</li>
<li>Thursday: I shifted focus to prioritize serialization, and addressing things blocking serialization.</li>
<li>Friday: Because I'm not using a service with an issue tracker for this, I started entering feature requests in a text file. More effective than it sounds!</li>
<li>Saturday: I tried to plan ahead for after serialization is done.</li>
<li>Sunday: I wrote most of the serialization code. According to the coverage metrics, the project is now more than 10% serialization code.</li>
<li>Draw a Box: Very little got done.</li>
</ul>
<p>Next week, I'm going to do a round of polish on Dennis before starting on part 11.</p>
Draw a Box 2019-05-132019-05-13T04:00:00-04:002019-05-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-13:/draw-a-box-2019-05-13<p class="first last">How to improve this situation... I'm not sure.</p>
<p>In this post:</p>
<ul class="simple">
<li>Scheduling conflicts.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>Outlines for dissection on May 10. I feel like these came out better than last week's. I'm going to have to figure out some way to ramp up drawing practice, since I think I'm feeling a little better in general. Unfortunately, it's not happening this week, since we're going to be out of town for the weekend.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same.
Because we're going out of town again.</p>
Diary 2019-05-122019-05-12T04:00:00-04:002019-05-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-12:/diary-2019-05-12<p class="first last">*vigorous typing throughout the day*</p>
<p>Well, my save/load module is like 500 lines long, but it's fine.
It's fine.
It's fine.
It's fine.
It's fine.</p>
<p>I do actually have some ideas for potentially removing bits of it, but there's also stuff to look into adding.
My plan is to get on with part 10 of the tutorial, but I need to take it easy for now, because most of that was today, according to the logs.</p>
<p>I'm trying to figure out what direction I want to take this game after I get through the tutorial.
Like, yes, the starting point the tutorial gives me seems fairly standard for traditional roguelikes, but the <tt class="docutils literal">tcod</tt> library doesn't really lock much down in terms of gameplay.
I had some ideas for a game I'd like to exist earlier, but I don't know if a sprites-on-grid turn-based game is the proper medium for the concept or not.
The basic idea I had is something inspired by the early Fallout games, but the apocalypse it takes place after is Lovecraft-inspired rather than nuclear.
There are multiple NPCs that all look suspiciously like Jeffrey Combs.
The player is presented with a dialogue option to comment on this, but the requirements for it are impossible to fulfill.
I mean, the early Fallout games were <em>very</em> turn- and tile-based, so it's not that I have a specific reason to doubt the idea would work, but more that I don't know if <em>I</em> can execute <em>the general idea</em> with <em>this technology</em>.</p>
<p>Anyway, I'm wiped out from traveling, and writing over 400 lines of code, so I'm just going to scout ahead a bit in the tutorial.
I don't actually remember how I wanted to prioritize the various tasks I came up with, but I'm inclined to push through the tutorial until I run across something that looks like it would interfere with them, because I'd like to get out of fitting my priorities around it.</p>
<p>I should probably describe what the heck is in all the serialization code that it's so long.
Basically, it currently has 23 pairs of "dumper" and "loader" functions, each associated with a single concrete type in the codebase:</p>
<ul class="simple">
<li>Seven types of component (ai, collision, display, fighter, inventory, item, position)</li>
<li>The map</li>
<li>One of the AI functions</li>
<li>The ecs "world"</li>
<li>The game</li>
<li>The messages and message log</li>
<li>The six current game states</li>
<li>Three of the item functions</li>
<li>2D coordinate pairs</li>
</ul>
<p>There are a number of <tt class="docutils literal">TypedDict</tt> classes to define the exact interface expected between loader and dumper.
Everything is type-annotated, though some of it needs to be fudged a little.
The public interface to the module is two functions that wrap up access to the serialization machinery; they accept and return <tt class="docutils literal">Game</tt> objects, which recursively include everything of interest.</p>
<p>Closing thoughts: I think I'll be able to finish part 10 pretty quickly.
Probably the most effort I'll have to put in will be tracking down the code that relies on functions that are or will be deprecated.
I've finally got actual test code running against this stuff, though I need to actually write tests of the core game logic; everything I need is there, pretty much, I just haven't put anything together.</p>
<p>Maybe what I ought to do is write code to log all of the events generated by normal play, and write functionality for "replays" with test code.
That probably doesn't quite make sense.
Oh well, it's late.
Good night.</p>
Diary 2019-05-112019-05-11T04:00:00-04:002019-05-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-11:/diary-2019-05-11<p class="first last">I mean this in the most neutral way possible: I legitimately <em>do not know</em> what "good coding practices" this tutorial I'm following is supposed to exhibit.</p>
<p>Once again, entry got pushed out because I was having too much fun messing with dennis.
Today, I addressed some of my concerns around serialization, wrote tests for edge cases because real-looking data is effort, and started writing serializers.
Doing this is going to be significantly more effort than just sticking everything in <tt class="docutils literal">shelve</tt>, but I'm not going to stick everything in <tt class="docutils literal">shelve</tt>.</p>
<p>Looking over the tutorial, I believe I want to take a hard line on refactoring once I get through part 10.
I should, at the very least, finally start breaking up the input processing function.
There's also wiring in the new logic I've written for handling sprites and fighters.
And converting the <tt class="docutils literal">GameMap</tt> to a component.</p>
<p>Thinking about adding multiple floors, that might call for more advanced queries for the world iterator.
I'll add that to the to-dos.</p>
<p>Once I've had my fun refactoring, I'm going to see if there's any more Mypy options I want to turn on.</p>
<p>It's late and I don't know how to end this post.
Good night.</p>
Diary 2019-05-102019-05-10T04:00:00-04:002019-05-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-10:/diary-2019-05-10<p class="first last">Wondering what else I'll gradually rediscover the need for</p>
<p>Today, I got tempted to use some kind of tooling to manage priorities for working on Dennis.
I poked at some fancy things, but then discovered <a class="reference external" href="http://todotxt.org/">todo.txt</a>, plopped a file for that into the repo, and got to work on it.</p>
<p>I put in some of the lower-priority refactors I want to do.
I put in and worked on stuff needed for testing, like convenience functions for making game objects.
I also put in a bunch of out-there feature ideas that may or may not pan out, but sound interesting to me.
So, I've got actual test code now, which is exciting.
I'm working on my coverage numbers, and some amount of improving coverage metrics will propbably come from working out which bits of code I can ignore.</p>
<p>I've decided I want to focus a bit next on serialization, and the big concern there is reworking how the code refers to colors.</p>
<p>Not much more to say for now, and I'm really sleepy, so I'm going to cut things off here.
Short entry again, oh well.
Good night.</p>
Diary 2019-05-092019-05-09T04:00:00-04:002019-05-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-09:/diary-2019-05-09<p class="first last">If you squint really hard, this resembles project management.</p>
<p>Thinking back on all of the refactoring I've been doing, I realized that a bunch of it wasn't really getting me closer to having serialization work nicely.
I therefore exercised a tiny bit of restraint and shifted focus towards addressing any issues I identified that would directly complicate serialization.
I wrote up everything I saw as an issue inline, and fixed a few of the issues, but not yet all of them.</p>
<p>The serialization issues I identified fit into two general categories:</p>
<ul class="simple">
<li>The type of an attribute would, if serialized directly, pull in data that exists elsewhere in the intended serialized structure, which would copy the state. But, if just the unique state gets serialized, then it's impossible to deserialize the object without access to information that the deserializer cannot express the need for. The solution to these issues was to rewrite the type to work with just the unique state, and rely on the consumers to provide the wider context.</li>
<li>The type of an attribute would, if serialized, preserve information from the source code of the current run. For example, if I stored some of the messages associated with an item on the associated component, then it would be very inconvenient to make sure the messages had any changes made to the source in future versions. My solution to this was to store the message directly on the class or function that handles the item's behavior.</li>
</ul>
<p>I believe I solved every instance I found of the first issue, but the second issue is somewhat more involved to solve, so I only fixed some of it.
The big issues remaining are the "Fighter" and "Display" components.
My basic inclination right now is to make a set of baseline things, and have ways of modifying them by nesting them inside other data structures.</p>
<p>I just put together the groundwork for that, which was pretty easy.
Actually adapting the rest of the code to use it is more effort, which I'll put off until tomorrow.
Tomorrow, I'll wire those in, and figure out how I want to handle colors, because I know I want to do something different than how I'm currently handling them.
Really excited to redo the core turn logic, but that's not a priority.
I'll let myself work on that when it looks like the code is ready for serialization.</p>
<p>I've put off finishing this post too long.
Good night.</p>
Diary 2019-05-082019-05-08T04:00:00-04:002019-05-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-08:/diary-2019-05-08<p class="first last">I've seen complaints about how the end goal of refactoring is a system that behaves the same, but this is honestly kind of soothing to me.</p>
<p>Slight issue I'm hitting: I got messed up from doing foolish stuff like "being outside", and in the state I'm in, I end up much more inclined to code, than to talk about the stuff I'm coding.
I'll try, though.</p>
<p>Basically, for the past few days, I've been refactoring code.
As before, just rearranging things and looking at them from a different perspective can yield shocking amounts of order that I feel the original presentation obscured.
What I'm currently trying to work up to is this:</p>
<ul class="simple">
<li>Given that the game-state controls the choice of input handler</li>
<li>Given that the choice of input handler controls the possible input events</li>
<li>Given that the act of processing the input events requires knowledge of both the game-state and the input event</li>
<li>The third given makes no sense, and we should instead be focusing on giving each behavior in the main function a distinct input event, so the relevant logic can be moved out of the function.</li>
</ul>
<p>Still more work to be done on this stuff, but I think it's possible now for me to start breaking out methods, and then look into moving them around more.</p>
<p>I got inspired by this post to do another related simplification, and that bugged the game up until I remembered one thing about Coconut that really bothers me: <tt class="docutils literal">data</tt> classes with no fields have falsy instances by default.
That kind of thing has me thinking that I'll want to revisit Structured Data later, because there are various ways that, after I've worked so long on Structured Data, Coconut violates the "Principle of Least Astonishment" for me.
(See also "I'm pretty sure you can't use dotted paths in a match".)</p>
<p>Hopefully, I'll make good progress on this big refactor, then figure out whether I want to make any changes to the storage and invocation for "Items", then I should be good to start on part 10, and wire in my own serialization logic.</p>
<p>For now, I extremely need to get to sleep.
Good night.</p>
Weekly Roundup 2019-05-072019-05-07T04:00:00-04:002019-05-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-07:/weekly-roundup-2019-05-07<p class="first last">A Very Software Development Week</p>
<ul class="simple">
<li>Wednesday: I wrote up my new "tab" behavior for Sublime Text in <em>excruciating</em> detail.</li>
<li>Thursday: I curled up in a ball and waited for the pain to stop. This summary is longer than the post.</li>
<li>Friday: I figured out what I wanted to try to do for the entity system in Dennis. I didn't follow exactly what I laid out, but the general idea is there.</li>
<li>Saturday: I mentioned working on Dennis, and tried to come up with something to say about <em>Prince of Darkness</em> to make the post a little longer.</li>
<li>Sunday: I got caught up in implementing changes, so I pushed out a really quick entry at the last minute.</li>
<li>Draw a Box: I had a bad day, and then didn't feel like working on it the rest of the weekend. Oh well.</li>
</ul>
<p>Next week, I refine Dennis even more.</p>
Draw a Box 2019-05-062019-05-06T04:00:00-04:002019-05-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-06:/draw-a-box-2019-05-06<p class="first last">I dunno, I didn't feel like it; working on dennis was more fun.</p>
<p>In this post:</p>
<ul class="simple">
<li>A lack of motivation</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>Some contour curves on May 3, and, like, what the heck? These came out <em>so bad</em>. My inclination is to shelve this for the moment, and draw dissections to texture later, because I remember the visualization coming much easier when I was drying slices, and therefore had a motivation for the contours.</li>
</ul>
<hr class="docutils" />
<p>Next week, I'll hopefully draw more than this.</p>
Diary 2019-05-052019-05-05T04:00:00-04:002019-05-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-05:/diary-2019-05-05<p class="first last">Did too much stuff to be able to write about what I did.</p>
<p>Thought of some really cool ways to rewrite the code and make it more reliable.
Unfortunately, this involves combing through all of the code, because I'm making fundamental changes that I can't see how to make "half-way".
It would be nice if I'd had tests first, but there's no obvious API <em>to</em> test yet, so nyeah.
Once I've updated everything, I'm going to try to add type annotations to all of this junk; the changes I'm making should make that all work much better than it did the way I was doing it before.</p>
<p>Once I've got this current rewrite, of the entity stuff, done, then I think I should work on breaking out the core loop into its own class.
I've also got vague ideas about refactoring the room generation, but nothing concrete there yet.
(Also, at some point I need to audit my usage of colors.
It's really ad-hoc and hard-to-read.)</p>
<p>It is way too late already, I guess I'm done.
Good night.</p>
Diary 2019-05-042019-05-04T04:00:00-04:002019-05-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-04:/diary-2019-05-04<p class="first last">Really excited to try actually writing tests for this stuff.</p>
<p>I've still kind of got a headache, so I'm going to try to be brief.</p>
<p>I worked through part 8 of the tutorial, and that's nearly done.
I don't have quite enough focus to finish up right now.
I think part 9 shouldn't be a big deal though, so after that I can get into refactoring things.</p>
<p>We watched <em>Prince of Darkness</em> today.
Cool visuals and concepts, not sure why most of the characters were assholes.</p>
<p>I guess I don't have anything else to say.
Don't get headaches, they suck.
Good night.</p>
Diary 2019-05-032019-05-03T04:00:00-04:002019-05-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-03:/diary-2019-05-03<p class="first last">Can write today. Less pain.</p>
<p>Hm.
Yes.
Wow.
I think I will try to avoid that in future.
I had an adverse reaction to medication, but I believe it's worn off by now.
I was still exhausted all day.</p>
<p>That said, I was able to plug away at the tutorial, currently midway through part 8.
I don't feel like I have anything specific to say about where I'm at.
I mean, I'm still rewriting stuff on the fly because the idea of using the code as presented offends me.
And there are some decisions I've made that I know aren't quite right.
And I haven't written tests.
I feel like that should come after I've broken the biggest function in the game into separate things.
Looking ahead in the tutorial, I think I'll finish part 9, and then, once again, go really off-the-rails for part 10.</p>
<p>Thoughts on tests...
The rendering functions look like excellent candidates for mocks.</p>
<p>Thoughts on serialization (the subject of part 10)...
I implemented inventories somewhat differently this time, and I kind of have to decide if I want to change my mind, or otherwise really commit to the particular way I'm doing ECS.
Or maybe I just need to have a post-processing step following deserialization.
Or...
Hm.
I think what I want is to have a registry of components.
That can be added to the unique objects, and serialized.
Move the "components" dict out of the entities, move the entity list into the registry, use WeakKeyDictionaries...
I'd say this idea is shaping up well, and I'll give it a go after part 9.</p>
<p>For now, I've been trying way too hard, and I think I'm not all the way to recovered.
I should stop.
Good night.</p>
Diary 2019-05-022019-05-02T04:00:00-04:002019-05-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-02:/diary-2019-05-02<p class="first last">Can't write today. Pain.</p>
<p>Can't write today.
Pain.</p>
Diary 2019-05-012019-05-01T04:00:00-04:002019-05-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-05-01:/diary-2019-05-01<p class="first last">On the one hand, this is really dry. On the other hand, I'm really invested in it.</p>
<p>One thing I ended up working on briefly over the weekend was an attempt to come up with an alternative to Sublime Text's default "reindent" command that is sometimes triggered by pressing tab.</p>
<p>The general problem of "I don't like what Sublime Text does here by default" is something that I've had cause to think about <a class="reference external" href="https://stackoverflow.com/questions/37752003/how-to-stop-sublime-text-from-indenting-by-multiple-tab-stops">for years</a>.
To recap that question, I asked "Hey, how do I make it only indent one tabstop?", got some discussion that I feel was... not helpful, figured out for myself how to get the behavior I wanted, and was happy with it, then blew back in a few days ago, <em>years later</em>, with a link to a Gist that does something completely different than what I was asking for.</p>
<p>Let's break this down:</p>
<ul class="simple">
<li>The "auto_indent" setting in Sublime Text has five associated key-bindings. Four of them are kind of two groups of two, and have to do with the enter key, but I don't think they're all of the functionality associated with the enter key when "auto_indent" is true? Doesn't matter. The last keybinding (first in the file) is as follows: when the cursor is on an empty line, with nothing selected, treat pressing "tab" as the "reindent" command.</li>
<li>The baseline functionality of the "reindent" command, applied to an empty line, is that it will find the previous non-indented line, and if it's indented, match that indentation, otherwise indent by one tab.</li>
<li>(It also detects characters that begin blocks, and will indent one tab more than an indented line that ends by beginning a block.)</li>
<li>This behavior, in a language that uses explicit delimiters, is fine. Perfectly acceptable.</li>
<li>This behavior, in Python, is agonizing.</li>
</ul>
<p>I'm going to try to systematize the issues I'm having here.
Let's suppose, given a blank line in front of a given user at a given moment, that there exists a "user-desired indentation" (UDI), a quantity of whitespace that that user at that moment, desires to be inserted, should they press the tab key.
What can we conclude?</p>
<ul>
<li><p class="first">The UDI must be non-zero; if they desired no tabs be inserted; they would not move their cursor there and press the key.</p>
</li>
<li><p class="first">It might not be possible for code analyzing the text buffer to determine the UDI; it must rely on fallible heuristics. In particular, there are text buffers where multiple UDIs are possible for the same arrangement of text, depending on user intent.</p>
</li>
<li><p class="first">Heuristics must be evaluated based on the consequences of failure. If a heuristic is wrong, there are two possibilities:</p>
<blockquote>
<ul class="simple">
<li>The heuristic over-estimated the UDI: the text is too indented and some of the whitespace must be deleted. Call this an <strong>excess</strong>.</li>
<li>The heuristic under-estimated the UDI: the text is insufficiently indented, and further tabs must be added. Call this a <strong>deficit</strong>.</li>
</ul>
</blockquote>
</li>
<li><p class="first">These two outcomes present a different workflow to the user to resolve them:</p>
<blockquote>
<ul class="simple">
<li>An excess is resolved by deleting text. Deleting too much text results in a blank line, and the user has expended effort to achieve nothing. Furthermore, the user must switch from using the left hand, to the right.</li>
<li>A deficit is resolved by adding text. Adding too much text results in nothing in particular. The user does not need to use any additional keys to resolve the deficit.</li>
</ul>
</blockquote>
</li>
<li><p class="first">Given a line that admits multiple possible UDIs, the quality of the behavior depends on the ease of resolution in the case that the behavior is incorrect. Because the workflow for resolving excess is more onerous, I feel that excess must be avoided, and therefore, the correct behavior is to choose the lowest indent among all possible UDIs.</p>
</li>
</ul>
<p>This, then, is what motivated my original question: if we assume that "one tab" is always a possible UDI, then "one tab" is the best choice of what to insert.
The resulting behavior was good enough for me for over two years.
So what changed?</p>
<p>Well, I'm actually sort of A/B testing myself, with the command I wrote active on one machine I use, but not the other.
That said, the idea came to me when I was following the roguelike tutorial I love to complain about, and realized that it would be nice—not essential, but <em>nice</em>—if pressing tab on a blank line between two blocks at the same indentation, brought it to that same level.
And then I considered the motivating case for the StackOverflow question: "Given a method that ends in a highly indented block, how do I write a new method after it without hitting the delete key a bunch?" and I thought "What if the class is in an indented block, itself? Supposing I'm inserting a method between two methods, I know I don't want to use any less indentation."
After years of being fine with the behavior I'd written, I realize that it was possible to get a higher lower bound on the desired indentation: to reduce deficits without risk of excess.</p>
<p>So anyway, that's what I was doing Sunday night instead of sleeping.
Whoops!</p>
Weekly Roundup 2019-04-302019-04-30T04:00:00-04:002019-04-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-30:/weekly-roundup-2019-04-30<p class="first last">Smashing my metaphorical face into things: the week.</p>
<ul class="simple">
<li>Wednesday: I simplified node-graph a bunch, removing the possibility of some classes of bug. Started thinking about interactive fiction.</li>
<li>Thursday: I kept on thinking about interactive fiction, and also node-graph architecture.</li>
<li>Friday: I got a better plan for interactive fiction, and started implementing my planned changes to node-graph. I also found out about a language that transpiles to Python, which gave me the urge to pick the Python/tcod roguelike tutorial back up. And also spent the day doing other stuff.</li>
<li>Saturday: I reinstalled my entire Python stack. I don't remember which <em>specific</em> thing pushed me over the edge, but this had pretty much no downside, so I'll take it. It doesn't hurt that I did this well before I tried to publish. I started trying to follow the roguelike tutorial again, and documented most of the commands I used.</li>
<li>Sunday: Between the maze of twisty little deprecations, all alike, the tutorial's impossible-to-apply diffs ("That seems a little extreme." It's telling me to delete lines that <em>didn't exist</em>.), and the fact that I wrote code in a very different style, like, a year ago or whatever, this is all sort of baffling. But I'm making my way through it.</li>
<li>Draw a Box: Shorter entry this week because shopping.</li>
</ul>
<p>Next week, let's see, I can write up new developments on an old StackOverflow question I asked (Ooh, exciting!), continue grinding through the tutorial, get back to grinding through node-graph, or try to work on the interactive fiction stuff.</p>
Draw a Box 2019-04-292019-04-29T04:00:00-04:002019-04-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-29:/draw-a-box-2019-04-29<p class="first last">Another slightly small weekend, just because.</p>
<p>In this post:</p>
<ul class="simple">
<li>I <em>finally</em> get new pens.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>More contour ellipses on April 26. I did not get a new pen yet. That, friends, was a mistake.</li>
<li>More contour ellipses on April 28. We got pens yesterday, and also new electronics, which we spent a good while setting up, because maintaining functionality in apps is for squares. Anyway, visualization wasn't as good today, I think I need to review that kind of stuff.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Diary 2019-04-282019-04-28T04:00:00-04:002019-04-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-28:/diary-2019-04-28<p class="first last">"Let's see you do better." Believe me, I'd like to; I intend to.</p>
<p>I continue to angrily follow a tutorial that seems to have somehow gotten worse since the last time I looked at it.
The diffs are just making less and less sense, it's ridiculous.</p>
<p>Anyway, that level of complaining in mind, I'm considering trying to make my own tutorial based on my efforts to rewrite and update this tutorial.</p>
<p>What I'm thinking of those efforts so far:</p>
<ul class="simple">
<li>invoke, pyenv, and pyenv-virtualenv are nice</li>
<li>I ended up wanting to do some stuff to nox that I'm not sure what the preferred way to do it is; or rather, I kind of don't want to do it the way I suspect is the preferred way.</li>
<li>I'm still getting my footing with Coconut. I don't think I've fully achieved a balance between "just type in Python code!", "it's got all these fancy extra features!", and "but you don't <em>have</em> to use them in any given situation". Also, it seems like sometimes the parser handles things so badly that it can only tell me that the error is <em>on a particular line</em>, and not anything about what's specifically wrong.</li>
</ul>
<p>Thinking about what my own take on any of this would probably look like:</p>
<ul class="simple">
<li>Pages on GitHub, probably</li>
<li>All diffs would be actual git-formatted diffs from actual repo state.</li>
<li>I'm actually kind of imagining that maybe this would be done through the medium of PRs and commits. All like "here's what it takes to get from this game to this, slightly more sophisticated, game". Probably not actually workable, though.</li>
<li>Not sure how I'd handle stuff like refactoring, since I'd be writing this for people like me, and a lot of my reactions I remember were along the lines of "Just write it correctly the first time, come on."</li>
</ul>
<p>What I really need before I can plan the idea in earnest is to go through things again, and try to get further.
(Part of the trick of this is that Coconut provides features comparable to Structured Data, more or less, so I've just, you know, got them, and I don't have to context-switch to developing them.)
Having worked through this stuff once before sort of helps, but nowhere near as much as I would have expected.
Not only has the tutorial been updated in ways that don't completely make sense, but the <a class="reference external" href="https://github.com/libtcod/python-tcod">tcod</a> library has been under active development, complete with deprecations, <em>and</em> my own code style has changed somewhat since I stepped away.
The overall effect is like a tripod with a pogo stick duct-taped to each leg.</p>
<p>Anyway, I'd better get on this.
I'm not even through Part 3 yet.
Get on this later; I'm tired now.
Good night.</p>
Diary 2019-04-272019-04-27T04:00:00-04:002019-04-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-27:/diary-2019-04-27<p class="first last">Stream-of-coding-ness</p>
<p>Working on this post a little early because I overhauled the publishing pipeline's dependencies as a side effect of fixing a bug I had that was breaking Poetry in weird ways.
I'm fairly confident it wasn't a Poetry bug, it's just that Poetry was able to reproduce it.
My solution may have been... somewhat drastic: I uninstalled the Pythons that Homebrew was providing, and replaced them with pyenv.
This had the unintentional effect of Marie-Kondo-ing my pip installation.
I should probably make a requirements file for this folder, and hardcode the theme path.</p>
<p>Oh man, this one aspect of my system is getting way more organized now.
This is exciting!
I could probably install Anaconda now without getting mad at it, but let's not go crazy.</p>
<p>Let's take stock:</p>
<ul class="simple">
<li>I've installed <a class="reference external" href="https://github.com/pyenv/pyenv">pyenv</a> and <a class="reference external" href="https://github.com/pyenv/pyenv-virtualenv">pyenv-virtualenv</a>.</li>
<li>I've used them to install Pythons 2.7.16, 3.7.3, and 3.8-dev.</li>
<li>I can't think of any reason to keep using 2.7 besides <a class="reference external" href="https://www.mercurial-scm.org/">Mercurial</a>, which is working on a Python 3-compatible release.</li>
<li>Oh yeah, whatever was keeping me from just pip-installing Mercurial before, is fixed now, so that let me uninstall it from Homebrew.</li>
<li>I've got completely empty output from <tt class="docutils literal">pip freeze</tt> currently, and I'd like to try to keep it that way by maintaining project-specific virtualenvs and requirements files.</li>
<li>Speaking of which, I made virtualenvs for my text editors, so I can manage their Python requirements separately.</li>
</ul>
<p>I'm not going to get too far on any projects now, but I want to try putting together one from scratch with this stuff.
Cross my fingers I'll do better at working through the tutorial, because I'm going to try to rewrite the Python 3 roguelike tutorial in Coconut.
And what better name to give to a vaguely medieval game in Python, than Dennis?
Let's get the basics together.</p>
<ul class="simple">
<li><tt class="docutils literal">poetry new <span class="pre">--src</span> dennis</tt></li>
<li><tt class="docutils literal">cd dennis</tt></li>
<li><tt class="docutils literal">pyenv virtualenv 3.7.3 dennis</tt></li>
<li><tt class="docutils literal">pyenv local dennis 2.7.16</tt> (Maybe I should give mercurial its own virtualenv so it's more obvious what's going on)</li>
<li><tt class="docutils literal">pip install <span class="pre">-U</span> pip</tt></li>
<li><tt class="docutils literal">hg init</tt></li>
<li><tt class="docutils literal">poetry add <span class="pre">--dev</span> coconut <span class="pre">-E</span> all</tt>, <tt class="docutils literal">poetry add <span class="pre">--dev</span> nox</tt>, <tt class="docutils literal">poetry add <span class="pre">--dev</span> invoke</tt>, <tt class="docutils literal">poetry add <span class="pre">--dev</span> bump2version</tt> (I'm thinking that I want things that interact with the source code, like transpilers, task runners, and helpers, to be dev dependencies, while things that interact with the installed package, like sphinx, hypothetically, would be optional dependencies)</li>
<li><tt class="docutils literal">poetry install <span class="pre">--no-root</span></tt> not merged yet, can't use that option, aww. For now, I'll just try to be careful.</li>
<li><tt class="docutils literal">mkdir <span class="pre">coconut-src</span></tt>, <tt class="docutils literal">mkdir <span class="pre">coconut-src/dennis</span></tt>, <tt class="docutils literal">mkdir src/dennis/data</tt></li>
<li>(Save the spritesheet to the data folder)</li>
<li><tt class="docutils literal">mv src/dennis/__init__.py <span class="pre">coconut-src/dennis/__init__.coco</span></tt></li>
<li>Ponder whether having hgignore ignore all python files under src would break things. Guess I'll have to try it out.</li>
<li><tt class="docutils literal">hg add</tt> everything, then commit</li>
<li>(Discover that blowing away pip failed to uninstall coconut properly, what a surprise. I'll probably have a bunch of files I'll have to delete, oh well.)</li>
<li><tt class="docutils literal">coconut <span class="pre">coconut-src/</span> src</tt></li>
<li><tt class="docutils literal">poetry build</tt></li>
<li>Hm, yes, it completely didn't work. Actually, wait, it worked perfectly I think, Quick Look is just a dirty liar sometimes.</li>
</ul>
<p>Okay, before I jump into anything else, I need to work out the tasks:</p>
<ul class="simple">
<li>Clean: delete stuff</li>
<li>Build-coco: <tt class="docutils literal">coconut <span class="pre">coconut-src/</span> src</tt>, probably with other options</li>
<li>Build: requires build-coco, <tt class="docutils literal">poetry build</tt></li>
<li>nox: requires build, does some checks, not sure what, pytest, mypy maybe, could make docs</li>
<li>bumpversion: takes parameter, let's say it passes the parameter to <tt class="docutils literal">bump2version</tt>, then passes the result to <tt class="docutils literal">poetry version</tt>. I dunno, it can do whatever, probably.</li>
<li><tt class="docutils literal">touch noxfile.py tasks.py</tt></li>
<li><tt class="docutils literal">poetry remove <span class="pre">-D</span> pytest</tt>, <tt class="docutils literal">poetry add <span class="pre">--optional</span> twine coverage pytest</tt></li>
<li>Add stuff to the noxfile and the tasks file.</li>
<li><tt class="docutils literal">inv nox</tt>. Hm, the output isn't colorized. I'll try to fix that. Also, I didn't add configuration for pytest or coverage, so that's all wrong. I'll get on that now.</li>
<li>Okay, I fixed the test and coverage configuration, got colors working, and added a "Private" trove classifier so I don't fumble-finger this onto anywhere. (I don't think it's that easy to accidentally upload to PyPI, but I don't really care.)</li>
</ul>
<p>And now it's midnight.
Tomorrow, I can try actually writing code.</p>
Diary 2019-04-262019-04-26T04:00:00-04:002019-04-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-26:/diary-2019-04-26<p class="first last">That was some distraction.</p>
<p>I'm working on reimplementing node-graph's differential methods as visitors.
It's sort of amazing what will typecheck.
For example: <tt class="docutils literal"><span class="pre">IntermediateDifferential(*map(sum,</span> <span class="pre">*zip(*node.nodes)))</span></tt>.
Mypy is fine with that.</p>
<p>In other news, I did enough hypothetical low-level design stuff that I got it out of my system, and my plan now for IF is to write up a transcript, and use that to evaluate authoring tools against.
If I come up with a criterion that doesn't reflect the transcript's requirements, I have to make myself ignore it.</p>
<p>And in other other news, I found out recently about <a class="reference external" href="http://coconut-lang.org/">Coconut</a>, and it has me wanting to revisit roguelike tutorial-y stuff, now that I know someone else has implemented the features I was approximating with Structured Data.
(In point of fact, even though I haven't tried it out really, just reading the documentation has me fairly confident that some of the equivalents to Structured Data functionality, are superior in Coconut.)</p>
<p>For a sec I couldn't remember what I spent most of today doing, and then I was like "Oh yeah, I was trying to justify my choice of classpect. An excellent use of literally anyone's time."</p>
<p>Um.
Good night.</p>
Diary 2019-04-252019-04-25T04:00:00-04:002019-04-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-25:/diary-2019-04-25<p class="first last">Trying desperately to only reinvent the wheel a little.</p>
<p>Didn't really touch node-graph today, might mess with it a bit during this post.</p>
<p>So far as trying to keep myself from badly reinventing existing technology, I've managed to talk myself into not doing a high-level implementation of low-level data structures, and instead try to put stuff together using existing libraries that—and this is excellent—I'm not responsible for maintaining.</p>
<p>Looking at node-graph, the thing I want to express is a constraint for the "visitor" type.
Probably I should just make a base class for all of the "visited" node types I made yesterday, and base it on that.
However, I also want it to be variadic, and uuuuugh.
Screw it.
Single-dispatch function of one argument that returns the real function.
Everything is curries.
Or, since the arguments are to be passed through to everything, maybe the arguments could be passed first, and return a single-dispatch function.
Or the arguments could be bundled up into an object that the single-dispatch function takes as another type parameter.
I think I'm going to have to take the "figure out what interface I want, then implement it" route.</p>
<p>Or I could try the "get a single-dispatch function from somewhere" route, since that seems most flexible and doesn't need as much scaffolding as some of the other ideas.</p>
<p>Hm.
I messed around some, and I've got something that seems promising, though there's probably something wrong with the variance.
I'll come back to it tomorrow, since it's almost midnight and I've got to get ready for tomorrow.
Good night.</p>
Diary 2019-04-242019-04-24T04:00:00-04:002019-04-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-24:/diary-2019-04-24<p class="first last">Stay on target...</p>
<p>Working on node-graph had me thinking "I feel like my design here was way too complicated. Surely this can be done more easily."
And thanks to the tests I wrote, I was able to start deleting code, until I'd excised most of the special cases that exist only to compensate for each other's existence.
The code got a lot shorter, and I got inspired to make other simplifications, that ended up removing a lot of weird logic, pushing checks out of internal loops, out to the top-level interface, mostly.
It's probably possible to remove more of the checks, but I don't care right now.</p>
<p>I'm sketching out ideas for a visitor system.
It's sort of complicated, because I'm thinking up front about how to avoid recursion.
Maybe I should sketch out how to avoid recursion, do an initial recursive design but with the non-recursive data types, then work on eliminating it.
Or maybe it'll be easy once I have the types put together.
Why don't I try that now...
Hmm...
Hard to say what I think about what's easy or hard, besides that "recursive but using the new classes" is probably easier than "recursive without the new classes" would be, because it means I don't need to go beyond the simple capabilities of <tt class="docutils literal">functools.singledispatch</tt>, I think.</p>
<p>I've also been thinking about interactive fiction, and roughing out some ideas.
I've got something that feels promising from an interaction perspective, but it's nowhere near being a rough draft yet.</p>
<p>One unfortunate aspect of my relationship with interactive fiction is that I haven't found an authoring tool that totally clicks with me, so I get this recurring itch to <em>just roll my own</em>, and the results of trying to design just a single low-level component have me intellectually convinced this is a bad idea, but that doesn't stop the urges.</p>
<p>I'm thinking I'll take some time later to just sketch out the logic of the visitor stuff, since this is actual new spec.
I guess I'll also do the IF-related stuff, just to see if I can make a better case for "come on, don't do this" on paper than in my head.</p>
Weekly Roundup 2019-04-232019-04-23T04:00:00-04:002019-04-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-23:/weekly-roundup-2019-04-23<p class="first last">Wait, that was all <em>this week</em>?</p>
<ul class="simple">
<li>Wednesday: I thought iterating on Node Graph was kind of slow, and laid out the things that didn't work yet. Like adding things together.</li>
<li>Thursday: I figured out how to make Poetry and Nox go fast. Not sure I can endorse my methods, but they <em>seem</em> to work. I also started implementing functionality in Node Graph.</li>
<li>Friday: I took a break from Node Graph, to rewrite some of the internals of Structured Data.</li>
<li>Saturday: I found a long-lived bug in Node Graph, as part of writing tests for multiplication, and worked out a plan to make the nodes less of a pain to work with.</li>
<li>Sunday: I put the "simplify use of caches" plan into action, and pondered what to focus on next.</li>
<li>Draw a Box: Drew arrows and contour ellipses.</li>
</ul>
<p>Next week, I'm feeling an inclination to try to do interactive fiction stuff, but also I've been drastically simplifying Node Graph.</p>
Draw a Box 2019-04-222019-04-22T04:00:00-04:002019-04-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-22:/draw-a-box-2019-04-22<p class="first last">I thought I was handling the pen so much better...</p>
<p>In this post:</p>
<ul class="simple">
<li>Redoing exercises, again.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>A page of organic arrows on April 19. I think I made some kind of improvement on visualization.</li>
<li>Another page of organic arrows on April 20. Glad to be not doing more of these immediately.</li>
<li>Contour ellipses on April 21. Two takeaways: my ellipses are embarrassingly rusty, perhaps I should be looking for ways to ramp up; and I'm pretty sure this pen is dying.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Diary 2019-04-212019-04-21T04:00:00-04:002019-04-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-21:/diary-2019-04-21<p class="first last">Progress continues</p>
<p>Status of node-graph:
Defined dunder methods, and also removed various other bits of noise.
Defined partial derivatives, and found yet another old bug, thanks to the assert I added earlier.</p>
<p>I think the next step is to work on visitor interfaces for this stuff, so I can start constructing networks.</p>
<p>On the other hand, this code is incredibly intimidating, and the fact that I've got some random magic numbers in here doesn't help.</p>
<p>There's something missing in terms of documenting the motivation for some of the code I've written recently.
I'm not sure I have anything concrete that I can point to as "not the way it should be".
Maybe the place to start rectifying this sensation is in documenting the actual format of the various data types I've defined.
It's definitely hard for me to grasp some of the things I've set up the code to do.
Like in the intervening years, I've lost the full weight of the aesthetics deriving the design, so I'm falling back somewhat on "eh, seems to work".</p>
<p>Hm.
On a whim, I ran pylint against node-graph.
Per usual when running pylint against my code, I ran across bugs in pylint the existence of which I never would have considered.</p>
<p>It occurs to me that maybe one issue I have with pylint is the idea of collapsing everything into a single numerical score.
Like, when it comes to code, you've got concerns like "that spacing is unreadable" or "that looks like it can't ever work".
But you've also got concerns like "do you actually need to use a metaclass there?".
I'm not sure that any pair of those is different only in degree.
Maybe it's just way too late at night, but it seems weird to me to put them all into a single one-dimensional score, such that one could in theory "trade" one for another and get "equivalent" code of a very different character.</p>
<p>But yeah, it's late.
Good night.</p>
Diary 2019-04-202019-04-20T04:00:00-04:002019-04-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-20:/diary-2019-04-20<p class="first last">Vintage bugs...</p>
<p>Status of node-graph: while adding tests for multiplication, I found a bug that appears to exist in every previous iteration of the code.
Oops.</p>
<p>Basically, multiplying certain arrangements of terms results in dropping a minus sign from the result.
Sort of disturbing that this code sort of worked, given that kind of issue.
I'm also looking at the constructors, and I'm not seeing some code in here that I remember thinking I wanted, so I think there are more bugs lurking in here.
However, when I <em>try</em> to trigger this bug, I can't get it to happen.
On further inspection, this actually is handled, it's just that this code is so bonkers that I forgot how I did it.
This logic should probably be moved out of where it is, and to a more common codepath. ... Except that trying to do that proved incredibly confusing.
I opted to add a precondition to one of the utility functions instead.</p>
<p>Anyway, the next bit of functionality to address would be partial derivatives, but writing tests for this code has made me realize that the ergonomics for it are... bad.
I'm implementing the basic math things visible at the top level as methods on or taking an "Environment" object.
The purpose of the environment object is to act as a limited-lifetime cache of node objects, in order to keep graphs from containing duplicate nodes.
I believe some form of this idea is necessary, but that other implementations are possible.</p>
<p>Going through the constraints I want to put on this:
Nodes need a reference to their cache;
Therefore cache keys must be weak references;
Therefore I need some kind of weak-referenceable wrapper type.</p>
<p>I think I've got the beginnings of this worked out...
Okay, I've switched the caches around to using weak references, and put a reference to the top-level cache into every node.
From there, I can cut down on Environment params, and I should eventually be able to turn the basic arithmetic operations into dunder-methods.
Get all that working, and <em>a lot</em> of visual noise falls away.</p>
<p>I'll have to try putting this into practice later.
Good night.</p>
Diary 2019-04-192019-04-19T04:00:00-04:002019-04-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-19:/diary-2019-04-19<p class="first last">Detour</p>
<p>Instead of working on node-graph more, I made some unimportant breakthroughs on internal code structure for Structured Data.</p>
<p>I then procrastinated writing this, so it's late now and I'll try to be brief:</p>
<p>One of the patterns I use a few places in Structured Data, and in other code, is to create a stack of items, and some means of processing those items, which can either pass them to code outside the scope of the stack, or create more items to put on the stack.
I usually implement this with a while loop, but it kind of seemed like it should be possible to represent the stack as an iterator, from the perspective of the out-of-scope code.
It took me until today to figure out how to do that.</p>
<p>The basic idea is that the processing function has to return one of two things: an instruction to yield a value, or a sequence of values to put on the stack.
I'm representing these as different types, because I can, and I have questionable habits around reducing cyclomatic complexity.
Basically, one type holds a value and yields it, the other holds a sequence, puts it on the stack, and yields nothing.
(I also added special-case support for None because it looks less cluttered that way.)</p>
<p>The way this shakes out, the stack and while-loop are still created, but they're confined to a single module.
Consumers just have to define the processing function, which only sees a single item, and use it in a for loop, where the body of the for loop is all of the stuff that the containing function actually cares about, like containers to get values accumulated in.</p>
<p>I razzed myself a little for lowering cyclomatic complexity so much, but there are some things about this that make me think it is probably actually better.
Chief among them is the fact that the high-level code has lower parameter counts in the function definition: less state has to be bundled together at a given level.</p>
<p>Anyway, that's what I did tonight.
Good night.</p>
Diary 2019-04-182019-04-18T04:00:00-04:002019-04-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-18:/diary-2019-04-18<p class="first last">It go faster now</p>
<p>Following some extended iterations, I got fed up with the flow of nox recreating the virtual environments every time, and Poetry doing a build for every environment, so I tried a bunch of things until I found something that seemed to work.
I'm not sure I can <em>recommend</em> the result, precisely, but I figured I'd explain what I did.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span></pre></div></td><td class="code"><div><pre><span></span><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">shutil</span>
<span class="kn">import</span> <span class="nn">nox</span>
<span class="n">nox</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">reuse_existing_virtualenvs</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">BUILD_LOCATION</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">def</span> <span class="nf">install</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">extras</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="k">if</span> <span class="n">BUILD_LOCATION</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">session</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"Need to run build first"</span><span class="p">)</span>
<span class="n">install_string</span> <span class="o">=</span> <span class="n">BUILD_LOCATION</span>
<span class="k">if</span> <span class="n">extras</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">install_string</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">"[</span><span class="si">{</span><span class="n">extras</span><span class="si">}</span><span class="s2">]"</span>
<span class="n">session</span><span class="o">.</span><span class="n">install</span><span class="p">(</span><span class="n">install_string</span><span class="p">)</span>
<span class="nd">@nox</span><span class="o">.</span><span class="n">session</span>
<span class="k">def</span> <span class="nf">build</span><span class="p">(</span><span class="n">session</span><span class="p">):</span>
<span class="n">shutil</span><span class="o">.</span><span class="n">rmtree</span><span class="p">(</span><span class="s2">"dist"</span><span class="p">,</span> <span class="n">ignore_errors</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">session</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="s2">"poetry"</span><span class="p">,</span> <span class="s2">"build"</span><span class="p">,</span> <span class="s2">"-vvv"</span><span class="p">,</span> <span class="n">external</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">global</span> <span class="n">BUILD_LOCATION</span>
<span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="s2">"dist"</span><span class="p">):</span>
<span class="k">if</span> <span class="n">filename</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">".whl"</span><span class="p">):</span>
<span class="n">BUILD_LOCATION</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">"dist"</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
<span class="nd">@nox</span><span class="o">.</span><span class="n">session</span>
<span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="n">session</span><span class="p">):</span>
<span class="n">install</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="s2">"coverage_only"</span><span class="p">)</span>
<span class="n">session</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="s2">"coverage"</span><span class="p">,</span> <span class="s2">"erase"</span><span class="p">)</span>
</pre></div></td></tr></table></div>
<p>This is the beginning of my noxfile.
I start off by importing some stdlib modules into the noxfile, which isn't a thing you <em>can't</em> do, but I don't know if you're not supposed to.
Then I import nox as normal, and set the reuse option to true because making the virtualenvs every time was pretty slow.
Then, I define a global variable that gets written to inside one of the sessions, which is, again, something that I can't tell whether it's a bad idea, but I <em>can</em> tell that it's possible and easy.
I then define a helper function to require it to be set before installing both the wheel and any extras.
Next, the session that has to come first, the session that does a release build of the library, which turns out to be pretty quick on its own.
It then scans the filesystem to determine what to tell pip to install later.
Then, one of the sessions that now rely on the wheel.
Installing the wheel is fast, I think because it doesn't need to hit the build system.
Doing it like this <em>should</em> be fine, I think.</p>
<p>Anyway, the point of all this is, now running nox (in a virtualenv because Poetry seems to interact oddly with nox's virtualenvs if I don't; not sure what's going on there) gets me results as I watch, instead of leaving me hanging for what feels like minutes.
Now that I've souped all this up, I can get back to implementing addition.</p>
<p>Hm.
Something weird.
I got my coverage all the way to full, and tried to do a refactor, and somehow this seems to have removed a random bit of branch coverage.</p>
<p>(Time passes)</p>
<p>Well, I recovered the coverage, even if I'm not sure why I lost it.</p>
<p>Next up, multiplication.
I am... not exactly looking forward to formulating tests for this stuff.
Good night.</p>
Diary 2019-04-172019-04-17T04:00:00-04:002019-04-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-17:/diary-2019-04-17<p class="first last">We're not talking "boffer duel on office chairs" quite yet, but it's still slower than I keep expecting</p>
<p>I've been working on Node Graph stuff, using Nox and Poetry.
I'm... honestly not sure I can recommend doing test-driven development with Poetry in its current state.
It's not that it doesn't work, it's that it feels like Poetry installs are really slow (a known issue).</p>
<p>In any case, I'm gradually adding functionality, and trying to take a slow and considered approach.
It's looking to me like basing things off of actual usage will streamline the interface considerably, even if the actual code is almost identical.
Basically, the things I actually want to do with this code are really restricted compared to "what's technically possible".</p>
<p>I haven't yet collected my thoughts on this, because I keep on looking back at the source code and seeing some conceptual improvement I can make.
I'm right now trying to work my way towards some constant folding techniques that will probably neither help nor hinder things, but are nice to have nonetheless.
These techniques would have been much more difficult in the context of the old interface, which is interesting.</p>
<p>In any case, I've gone through enough of the basics of all this that there are now just three things to implement for the baseline functionality of the module:</p>
<ul class="simple">
<li>addition</li>
<li>multiplication</li>
<li>partial derivative</li>
</ul>
<p>Because this is (hand-rolled, because not-invented-here syndrome) symbolic manipulation, those are all big tasks, actually.
And partial derivative is somewhat more straightforward than the others, insofar as it requires them, and it's a lot less daunting to go from addition and multiplication to partial derivative, than <em>to</em> addition and multiplication.</p>
<p>I'll see about those later, because it's already pretty late.
Good night.</p>
Weekly Roundup 2019-04-162019-04-16T04:00:00-04:002019-04-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-16:/weekly-roundup-2019-04-16<p class="first last">An evidently eventful week.</p>
<ul class="simple">
<li>Wednesday: I figured out what I wanted to do this week, and started with Jedi. There's a PR open! The ball is, at (very) long last, no longer in my court.</li>
<li>Thursday: I updated my Exercism stuff. Update from later: it was accepted. I got Poetry installed; the initial setup is great.</li>
<li>Friday: I was sleepy and looked over Poetry stuff.</li>
<li>Saturday: I made an effort to talk my way through configuring the Poetry version of things.</li>
<li>Sunday: I was on the road and apprehensive about Node Graph.</li>
<li>Draw a Box: I noticed that a bunch of the boxes were bad in identical ways.</li>
</ul>
<p>Next week, I'll probably talk about gradually adding code to the new Node Graph thing.</p>
Draw a Box 2019-04-152019-04-15T04:00:00-04:002019-04-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-15:/draw-a-box-2019-04-15<p class="first last">I am staring at a lot of boxes with wonky back faces.</p>
<p>In this post:</p>
<ul class="simple">
<li>A bit less than before.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>Some more of the 250 boxes on April 12. I'm getting gradually faster at this, which is interesting. Hopefully I'm getting fast at drawing this stuff <em>right</em>. Anyway, I probably won't be drawing for the rest of the weekend because we're going out of town.</li>
<li>Some more boxes on April 14. Probably going to take a break from this and consider this sheet finished. I'm seeing some common issues in the latest boxes especially. It looks like I'm failing to align one of the back corners properly, which causes the structure of the back faces to distort weirdly.</li>
</ul>
<hr class="docutils" />
<p>Next week, I'll get back to the normal flow of lessons.</p>
Diary 2019-04-142019-04-14T04:00:00-04:002019-04-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-14:/diary-2019-04-14<p class="first last">Bunch of things happened today that weren't working on this stuff.</p>
<p>Not much happened today.
It turns out I missed some bits of configuration when I ported stuff over to the new project, so I got those taken care of.</p>
<p>It's about ready to start taking the actual code in, which has me a little freaked out, since that's almost 500 lines of code with no tests, which is not ideal.
Like, should I be pretending to do test-driven-development with this, or should I just plop it all in and add tests until I get the coverage all the way up?</p>
<p>I should also work on the documentation, which is its own iffy thing, since Sphinx's advice for working with the conf file is "just generate it".
I'd really like to have some insight on why I might choose to lay any of this out one way and not another.</p>
<p>Oh well, something to look into next week.</p>
Diary 2019-04-132019-04-13T04:00:00-04:002019-04-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-13:/diary-2019-04-13<p class="first last">Intense copy-paste action</p>
<p>All right, let's look over the features that I'm hoping to replace with <a class="reference external" href="https://poetry.eustace.io/">Poetry</a> and <a class="reference external" href="https://nox.thea.codes/en/stable/">Nox</a>.</p>
<p>The big win I want to get from Nox is to avoid having the configuration file responsible for regenerating itself.
I managed to get a merge conflict in that for Structured Data, and it rubbed me the wrong way, because I had to kind of, like, fix it twice at the same time, in the same way.
So, my goal is to push all of such auto-manipulations to run-time metaprogramming, as needed.</p>
<p>I'm seeing Codecov/Coveralls support.
I haven't tried to do that yet; I'll keep it in mind once I get everything else together enough to set up on GitHub.</p>
<p>There's documentation using <a class="reference external" href="http://www.sphinx-doc.org/en/master/index.html">Sphinx</a>.
I need to look into that more closely, with a focus on looking into how Sphinx is actually supposed to be used.
(In that I haven't been looking into it very closely, and have basically just taken what the template gave me, though I did have to do some silly stuff to get PDF builds to work.)</p>
<p>There's <a class="reference external" href="https://github.com/timothycrosley/isort/">isort</a> and <a class="reference external" href="https://github.com/peritus/bumpversion">bumpversion</a>.
Poetry handles bumpversion's functionality.
isort will look for configuration in pyproject.toml, which sounds fine to me.</p>
<p>There's various checks that get run as part of <a class="reference external" href="https://tox.readthedocs.io/en/latest/">tox</a>.
Simple enough to port to Nox.</p>
<p>And C extensions, via <a class="reference external" href="https://cython.org/">Cython</a> or <a class="reference external" href="https://cffi.readthedocs.io/en/latest/">cffi</a>.
I'm going to have to put a pin in that, as well.</p>
<p>So, let's see what I'm comfortable trying to get working to start with:</p>
<ul class="simple">
<li>.coveragerc (DONE)</li>
<li>.editorconfig (DONE)</li>
<li>.gitignore</li>
<li>mypy.ini (DONE)</li>
<li>.flake8 (DONE)</li>
<li>pytest.ini (DONE)</li>
<li>isort can go in pyproject.toml (DONE)</li>
<li>Adding classifiers and such to pyproject.toml</li>
</ul>
<p>Now, let's see about some dependencies for checking.</p>
<p>I added dependencies.
Some of this feels a little heavy-handed, like maybe there's room for a tool that's like Poetry, but not quite?
I don't have a good problem statement in mind, so eh.</p>
<p>Anyway, there's just a few more dependencies to install and make use of, and then it's time to get code in.
My basic hope is that I'll soon be set up with enough tests that I can confidently rewrite some of this stuff.</p>
<p>Anyway, it's too late right now.
Good night.</p>
Diary 2019-04-122019-04-12T04:00:00-04:002019-04-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-12:/diary-2019-04-12<p class="first last">New and sort-of shiny</p>
<p>Very sleepy today.
I made a project with Poetry and I'm gradually getting the tooling around it to parity with my other projects.</p>
<p>Scattered thoughts on this:</p>
<ul class="simple">
<li>Poetry is showing its pre-1.0 status a little more than I expected it would at first. Features seem to be moving faster than documentation.</li>
<li>It looks like <a class="reference external" href="https://github.com/pypa/pip/issues/6170#issuecomment-471958075">I'm not alone in this impression</a>. Since I couldn't figure out how to work Poetry's "develop" mode, I'm experimenting with using stuff like <a class="reference external" href="https://hynek.me/articles/testing-packaging/#a-name-cc-a-combined-coverage">Hyneck Schlawack's advice</a> for getting the paths to work in coverage. It looks like it all has to be exactly right, but then it works perfectly.</li>
<li>You can't <em>prove beyond a shadow of a doubt</em> that Nox isn't using semver. That said, it's not using semver.</li>
<li>I should probably audit the version specifiers I put in later, when I'm more awake.</li>
</ul>
<p>Something I'd been thinking about, but didn't really get to: some people want to be able to use pyproject.toml as a configuration file for various non-build-system purposes, and I can't tell whether that was the intention.
In any case, it'll probably make me less sad than having various tools read from tox.ini and intepreting my fragment specifiers as their configuration sections.
That... wasn't fun.
Using poetry as a replacement for requirements.txt files is definitely great; I can imagine potentially getting into issues under very specific circumstances, but I think there's a way to address the edge cases I'm imagining.</p>
<p>Anyway, I'm barely awake at this point.
Cannot write anything else useful now.
Good night.</p>
Diary 2019-04-112019-04-11T04:00:00-04:002019-04-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-11:/diary-2019-04-11<p class="first last">If debugging is the process of removing software bugs, then programming must be the process of putting them in. - E. W. Dijkstra, maybe</p>
<p>Exercism status update: probably fast but definitely confusing state machine has been replaced with a few strategic calls to library functions.
I believe the resulting code is more correct for input not covered by the test cases, insofar as it now accepts <em>all</em> whitespace and <em>all</em> text that differentiates glyphs by case.
It might do something weird if you pass it German, or Turkish.
In other words, it's code that cares about case.</p>
<p>The key thing that I needed to grasp to kick off the refactor was, I managed to represent a binary output with three-value business logic that was modeled by two booleans.
So I just kind of... converted four to three, then three to two.
This simplified the core logic enough that I was able to separate out the different conditions to test, and, as I said, to replace them with library functions, thereby making the code, like, probably less than half as long.</p>
<p>That was a nice exercise in refactoring.
Might or might not be all the way done, but it should be much easier to make any further updates.</p>
<p>On a Python packaging note, I installed <a class="reference external" href="https://poetry.eustace.io/">Poetry</a> and configured it with my PyPI account.
This was super easy, very straightforward installation and configuration, great job.
I'm interested in Poetry because it's one of several tools that aim to, among other things, replace <tt class="docutils literal">setup.py</tt> when it comes to Python package development, but it's the only one I've found so far that supports the <tt class="docutils literal">src</tt> layout.</p>
<p>I'll get back into that tomorrow.
For now, good night.</p>
Diary 2019-04-102019-04-10T04:00:00-04:002019-04-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-10:/diary-2019-04-10<p class="first last">Computers: Extremely Confusing!</p>
<p>Okay, I'm done with the migraine for now, so let's lay out what I've got to work on, and try to address <em>some</em> of it.</p>
<ul class="simple">
<li>I never did fix up the stuff I was doing in Exercism.</li>
<li>I've got some guidance on the Jedi changes, so I'd like to try to get some of that working.</li>
<li>To the stack of tasks that has "actual machine learning" at the bottom, and "learn Nox" at the top, I have decided to add "review Python development tooling". It's a good thing I don't have a particular compelling use case in mind for the stuff deep in the stack, because this seems like it could be really irritating if I did.</li>
</ul>
<p>Little bit of choice paralysis right now, so I'm going to get up, do other stuff for half an hour, and come back.
It's cool, through the magic of editing you won't know I was gone.</p>
<p>Okay, I decided to first try to catch up on Jedi stuff.
The guidance I got, either the code changed when I wasn't looking, or it was done from memory, because it didn't match the API in front of me.
In any case, I'm not certain, but I think I got at least one of my new tests to pass.
I'm honestly just going to toss this up when the local test runs finish, and see if Travis can better explain what's still and/or newly going wrong.</p>
<p>I feel a little bad that my post for tonight is just "I copied some code out of a GitHub comment and edited it until it wasn't obviously (to me) wrong" but them's the breaks.
Actually, the breaks are slowly worse, because I can't seem to push.
Something broke in the last two weeks.</p>
<p>Update: I changed a bunch of settings, and then stuff started working.
It sure is great, knowing computers.
I'm such an expert.</p>
<p>Anyway, that soaked enough time up that now I'm definitely done.
I'm thinking tomorrow I'll revisit Exercism stuff.</p>
<p>Good night.</p>
<p>ETA: <a class="reference external" href="https://travis-ci.com/mwchase/jedi/builds/107728750">All tests pass</a>? I don't believe you.</p>
Weekly Roundup 2019-04-092019-04-09T04:00:00-04:002019-04-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-09:/weekly-roundup-2019-04-09<p class="first last">Avoid migraines if you can.</p>
<ul class="simple">
<li>Wednesday: Thought more about contributing to Jedi, and weakly dissed Anaconda (the scientific computing environment, not the Sublime Text plugin)</li>
<li>Thursday: Part 1: Went over the concepts behind a library I'm working on that is, at best, only useful for teaching purposes.</li>
<li>Friday: Part 2: Talked about different ways to make Python code (usually of a numerical nature) faster.</li>
<li>Saturday: Part 3: Started laying out goals for what to profile and try to optimize. Posted late because Pelican is <em>weird</em>.</li>
<li>Sunday: I figured out what Pelican was doing, and mentioned having a migraine.</li>
<li>Draw a Box: Working on the 250 box challenge.</li>
</ul>
<p>Next week, I can't just say I'm taking it easy, I have to put in serious effort to take it easy, because I still have a migraine.</p>
Draw a Box 2019-04-082019-04-08T04:00:00-04:002019-04-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-08:/draw-a-box-2019-04-08<p class="first last">I'm much preferring having a numerical target to "filling the page".</p>
<p>In this post:</p>
<ul class="simple">
<li>Like 10% done now.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>More boxes on April 5. I think I'm getting a better understanding of grip, but fixing up the basics has me feeling sloppy at the higher-level stuff again. Some lines kind of going off. Hopefully I'll get a solid base sometime soon.</li>
<li>More boxes on April 6. I think maybe sometime I should try to do a big push to get further along on this stuff, because otherwise I'll be at this quite a while. Not now, though.</li>
<li>More boxes on April 7. I think I'm making some breakthroughs in visualization. Hopefully those translate into improvements in composition next time around. And yes, I'm doing this with a migraine. I think it's messing with my impulse control.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Diary 2019-04-072019-04-07T04:00:00-04:002019-04-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-07:/diary-2019-04-07<p class="first last">Passive-aggressive jabs at my publishing toolchain</p>
<p>Yesterday's post goes up at the same time as this one because "page fails to render" evidently isn't a good enough reason to throw up an error that would halt compilation.
I don't <em>think</em> that behavior is my fault, but I'm not sure.</p>
<p>Anyway, I didn't get a successful run of anything together today, but I did try putting stuff together with Nox.
It's so far looking like a better fit for the cookiecutter-pylibrary workflow than tox is.</p>
<p>Anyway, I shouldn't have done as much as I did today, honestly, but I over-exerted myself because I have poor judgment.
It turns out the "head hurty" was a migraine.
It sucks!!!</p>
<p>Kind of amazed that I haven't managed to combine "intense stress" and "staring at a computer screen" like that before, to be honest, but now I have.</p>
<p>Wish me luck at taking it easy; it's evidently difficult for me right now!
Good night.</p>
<p>ETA: I had to add <tt class="docutils literal"><span class="pre">--fatal</span> errors</tt> to the command, to get the behavior I had been assuming I'd be getting all along.
Why...
Why is it not just <em>like that</em>?</p>
Diary 2019-04-062019-04-06T04:00:00-04:002019-04-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-06:/diary-2019-04-06<p class="first last">I meant to have more today, but head hurty.</p>
<p>There are a couple different factors to consider when profiling code.
For this, let's first go over the architecture.</p>
<p>There is an abstract representation of the network, which can be manipulated in various ways, including differentiation.
This network has to be built up initially.
The network has to be pair with a predefined evaluation strategy, and this will produce functions that operate on weights and data to produce either an output, or a training gradient.</p>
<p>We can conceptually separate this into two or three phases.</p>
<ul class="simple">
<li>First, we build the network using a series of loops.</li>
<li>Then, we combine an evaluator with the output nodes, to get functions.</li>
<li>Then, we evaluate those functions, many times.</li>
</ul>
<p>In terms of high-level usage, we can probably view the first two steps as a single step.</p>
<p>For the initial, say, "construction" phase, we want to make sure we're not outrageously slow, and if we use techniques like caching, we want to make sure we don't put ongoing memory pressure on the system, or spike "too high" during construction.</p>
<p>For the "main" phase, we want to go as fast as possible, and avoid increasing memory pressure with time.</p>
<p>I can't figure out just by thinking about it what kind of numbers I want to achieve here.
And, as I said, my laptop is probably not so great for this anyway.
So, I figure when it comes to learning by doing, I'll just try to get statistics for various versions and focus on quantifying the differences.</p>
<p>I'd like to get more done with all this, but I had a really rough day and I probably shouldn't be looking at my screen right now.</p>
<p>One thing I'm thinking about trying out with all of this is <a class="reference external" href="https://nox.thea.codes/en/stable/index.html">Nox</a>.
I've been using <a class="reference external" href="https://tox.readthedocs.io/en/latest/">tox</a> for my other Python projects, and while my hand-rolled <tt class="docutils literal">tox.ini</tt> files are reasonable, the stuff that <a class="reference external" href="https://github.com/ionelmc/cookiecutter-pylibrary">cookiecutter-pylibrary</a> does with Jinja... is not.
So, since I've got some new testing I want to do, I figured I'd try out Nox and see if it's a better fit, if I should migrate some of my projects over to it.</p>
<p>Tomorrow, though, because I am done.
Ugh.
Sorry to you and to me that today ended up like this.</p>
Diary 2019-04-052019-04-05T04:00:00-04:002019-04-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-05:/diary-2019-04-05<p class="first last">Writing cliffhangers is great because it lets me have shorter posts without having to come up with real endings.</p>
<p>So, I cut myself off yesterday, but I've got some ideas for how to make my numerical code, or code very like it, faster.</p>
<p>The basic premise of a variety of optimization libraries and frameworks for Python is that if your inner loop is hot enough, you don't want to have Python function calls inside it.
My own code does something more than one call per <em>edge</em> in its graph.
As ways to implement stacked matrix multiplication go, I'm not surprised such techniques haven't taken off.
We're talking like over a thousand function calls for a single evaluation of the network, easy.
Now, we need at least one function call to make things actually happen.
Can we reach one function call per error evaluation?
Per gradient calculation?
Per training step?
Per batch of training steps between diagnostic dumps?</p>
<p>I think I can get that far.
It probably won't be amazing on my machine—I don't have fancy GPUs to work with—but I expect I'll be able to get modest improvements, at least.</p>
<p>So, what does reducing the number of function calls look like?
Basically, you take some Python code with function calls, and transform it in some way to remove the Python function calls.</p>
<p>Possible ways to do this include:</p>
<ul class="simple">
<li>Try to rewrite everything in <a class="reference external" href="https://rpython.readthedocs.io/en/latest/faq.html#what-is-rpython">RPython</a>. I tried to do this. I now do not recommend RPython for things that aren't interpreters.</li>
<li>Rewrite parts of it in <a class="reference external" href="https://cython.org/">Cython</a>. I haven't personally used Cython directly myself; I don't know how well it does at optimizing the kind of tiny shrapnel functions my library here has.</li>
<li>Use an actual machine learning library/framework like <a class="reference external" href="http://www.deeplearning.net/software/theano/index.html">Theano</a> or <a class="reference external" href="https://www.tensorflow.org/">TensorFlow</a>. Theano says it compiles graphs to C, and TensorFlow appears to compile graphs to... something. I probably should use these, but I like feeling like I put every bit of the graph-level logic together myself.</li>
<li>Compile some functions using LLVM, via <a class="reference external" href="http://numba.pydata.org/">Numba</a>. I've experimented some with Numba, and while some of the advanced features aren't all the way there yet (I wanted to wrap a dataclass in a jitclass, and that just... doesn't work), I like how the interface works out. I haven't profiled this, so I'd like to do that before going all in on this idea, but I have <a class="reference external" href="http://www.calebjones.net/posts/2018/09/llvm-hearts-peano-addition/">reason to be optimistic</a> about LLVM's ability to handle tiny shrapnel functions.</li>
</ul>
<p>In any case, before I sink effort into any kind of optimization like that, I should first try to do some due diligence about timing and profiling my code.
The old code I wrote, I profiled in an ad-hoc manner, which isn't great so far as knowing which profile data even matters.</p>
<p>Let's see about working out what kind of patterns of usage to profile, and how...
Tomorrow.</p>
Diary 2019-04-042019-04-04T04:00:00-04:002019-04-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-04:/diary-2019-04-04<p class="first last">An attempt at a two-parter</p>
<p>I spent today being sleepy and trying to square some stuff away, so I'm going to try describing some old stuff I alluded to yesterday.</p>
<p>In my efforts to get a handle on neural nets, I rolled my own library for manipulating them.
Because I've never really approached optimization in a principled manner, it was pretty slow, no matter what crazy rewrites I did to it.
I believe part of the problem was that I had too much going on in the hot loops, basically as a result of including dynamic capabilities that I don't think were necessary in that context.</p>
<p>To be a little more concrete:</p>
<ul class="simple">
<li>The library consumer first constructs a directed acyclic graph where each node is some kind of mathematical operation.</li>
<li>A separate visitor class defines functions to evaluate arbitrary nodes within the DAG with respect to an invariant state. Note that, for nodes that don't just retrieve a value from the state, but rely on other nodes, the visitor has to be re-consulted to evaluate those values.</li>
<li>As such, I now believe the signature of <tt class="docutils literal">(cls, node, state)</tt> is one of the factors holding this code back, because it necessarily pulls a number of attribute lookups and method calls into the hottest loops in the code. When it comes to variation over time, the network structure is constant and the visitor classes should be irrelevant, leaving just the state. Ideally, from there, we'd have some way to bundle up a bunch of training iterations into a single call, in case it's still slow.</li>
</ul>
<p>Well, I've got all these ideas, but I should probably be collecting statistics on the code to be able to see if they're at all worth it.
In any case, the stuff I was talking about in the last bullet point sounds nice and all, but you may wonder how I intend to attempt it.</p>
<p>Gosh, it's late.
Good night.</p>
Diary 2019-04-032019-04-03T04:00:00-04:002019-04-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-03:/diary-2019-04-03<p class="first last">Anaconda? More like... I dunno.</p>
<p>I continue to not really be sure how best to get started developing Jedi.
Like, there's tests, so I can't break anything, but it's also not obvious to me how to correctly add functionality.</p>
<p>This kind of blockage is one possible explanation for why I'm circling back around to random old projects.
I've got some old machine learning code that I put together in an attempt to put the underlying techniques into terms I can understand.
It's really slow, but I think I've worked out a tolerable way to make it faster.
I'm kind of leery to write these ideas up, because I'm not at all confident that what I did is "correct" or "sensible", and the right answer to what I was trying to do is probably "use libraries".
I'm also following along with tutorials, and I'm kind of like, wow, Anaconda impresses me less and less the more I use and hear about it.
Like, is there some way to set it up so it won't break Homebrew packages that depend on Python?
I'm currently getting by with pip, because I really don't see how Anaconda is supposed to be worth it.</p>
<p>Oh well, that's it for today.
Good night.</p>
Weekly Roundup 2019-04-022019-04-02T04:00:00-04:002019-04-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-02:/weekly-roundup-2019-04-02<p class="first last">Maybe I should take a break again sometime...</p>
<ul class="simple">
<li>Wednesday: I linked to a bunch of commentary on literate programming.</li>
<li>Thursday: I concluded that what I want out of literate programming is basically the ability to have generated docs as thorough as rustdoc's.</li>
<li>Friday: I improved Structured Data's documentation a little.</li>
<li>Saturday: I outlined what I want Jedi to do.</li>
<li>Sunday: I got very distracted.</li>
<li>Draw a Box: I decided to move onto the 250 box challenge.</li>
</ul>
<p>Next week, I'm going to try to make some progress on Jedi, but I've got other stuff I'm interested in...</p>
Draw a Box 2019-04-012019-04-01T04:00:00-04:002019-04-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-04-01:/draw-a-box-2019-04-01<p class="first last">So many boxes...</p>
<p>In this post:</p>
<ul class="simple">
<li>This is probably going to get really boring, until I get bored myself.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>A bit more organic perspective on March 29. I got a laptop stand this week, and it makes probably the nicest drawing surface I've yet tried.</li>
<li>Finished the organic perspective sheet on March 30. I think next I'll try to 250 box challenge, which I didn't try the first time around.</li>
<li>I started the challenge on March 31. I've just got a few boxes so far, and some of them are real clunkers. Also, I can tell I need to work on my grip.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Diary 2019-03-312019-03-31T04:00:00-04:002019-03-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-31:/diary-2019-03-31<p class="first last">Pew pew! PEW PEW PEW!</p>
<p>Me yesterday: I sure would like to figure out more about developing Jedi.</p>
<p>Me today: It sure is fun coming up with a bunch of other projects, and playing Nova Drift.</p>
<p>Not much to talk about, really.
We watched a Troma fantasy movie that was well-reviewed on a bad-movies site.
While I take a little issue with the factual accuracy of parts of the review, all in all <em>Eye(s?) of the Serpent</em> was kind of amazing in the lengths it went to to try to conceal its lack of plot.
It's something about a windowless castle with like three rooms, and a secret warcamp with like five guys in it and kites flying above it at all times, and at the end, two characters sword-fight each other to death, but not in the way that sword fights usually cause death.
I think they exploded?</p>
<p>Trying to think about what to try to work on.
I'm thinking stepping away from tooling, and focusing on creating some content, and then maybe making stuff to present that content nicely.
We'll see.</p>
<p>Good night.</p>
Diary 2019-03-302019-03-30T04:00:00-04:002019-03-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-30:/diary-2019-03-30<p class="first last">Jedi mind whammy.</p>
<p>So, I don't remember explaining what it is that I'm trying to add to Jedi.
I don't remember a lot of things.
I also remember a lot of things. ...
Well then.
Anyway, Jedi is a Python library that provides auto-completion facilities for Python code; various text editors integrate with it.
Among its features are determing a value's expected type from context, and providing suggestions for field access based on that type.
For example, you could have a function parameter annotated as <tt class="docutils literal">int</tt>, and it would suggest methods from the <tt class="docutils literal">int</tt> type if you typed a dot after it.</p>
<p>Now, Python 3 has been adding various features around gradual typing, various ways to define types outside of just providing stuff like <tt class="docutils literal">str</tt> or <tt class="docutils literal">int</tt>.
Among the facilities offered by the <tt class="docutils literal">typing</tt> module, are the ability to statically define subclasses of types, that aren't visible dynamically.
In other words, at runtime, they are no-op functions, but according to static analysis, they are subclasses of a particular type.
This could be used to allow the type checker to reason about stuff like sanitized data, or restricted subsets of a type.</p>
<p>However, these features do not play nicely together.
Jedi sees the runtime nature of the <tt class="docutils literal">NewType</tt>, instead of treating it as a cast.
As such, the inferred type of the input is the inferred type of the output, and for function parameters, it infers no type at all.</p>
<p>I first found out about this behavior from a discussion on StackOverflow, where I was surprised to discover that things didn't work as I expected, and they were disappointed.
I entered an issue on the bug tracker, offered to help, and then got horribly distracted.
For so long, that the relevant development moved to a feature branch specifically devoted to improving integration with typing.</p>
<p>Looking over what there is right now, here's how I <em>think</em> I'm supposed to implement things:</p>
<p>A <tt class="docutils literal">NewType</tt> is a callable returned from a callable.
I think this means that I need to define two contexts: <tt class="docutils literal">NewTypeClass</tt> for <tt class="docutils literal">NewType</tt> itself, and <tt class="docutils literal">NewType</tt> for its return values.</p>
<p>As far as actually implementing this stuff...
I got started, then realized that this stuff is confusing to me because I lack context, so now I'm reading <a class="reference external" href="https://jedi.readthedocs.io/en/latest/docs/development.html">Jedi Development</a> to try and get filled in a little.
Um, oops, I feel like there was less there than I expected.</p>
<p>Here's where I'm at:</p>
<p>The first argument to <tt class="docutils literal">NewType</tt> is a <tt class="docutils literal">str</tt>, and the second argument is "anything that we consider equivalent to a class".
The result is a context that has a name given by the first argument, and acts like a class, where the constructor takes one argument, of the type of the second argument.</p>
<p>Oh well, I'll keep trying to understand this.
For now, good night.</p>
Diary 2019-03-292019-03-29T04:00:00-04:002019-03-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-29:/diary-2019-03-29<p class="first last">Was sleepy.</p>
<p>It's too late to do much.
I'm going to do some quick doc passes and describe them.</p>
<p>I basically described some of the "matcher" classes, but I think this is all missing a unified explanation.
The changes I made don't really fit into the ideas I was think about with "what is needed for literate programming in a modern language?" but I did end up noticing how anemic the documentation for Structured Data was, so that's helpful.</p>
<p>I think I'd like to make a serious effort with the Jedi stuff, now that I'm over the hump of "code is way out of date" and now have to consider the hump of "never quite worked out how to extend these systems".
I'll try to write that kind of stuff up tomorrow.
Good night.</p>
Diary 2019-03-282019-03-28T04:00:00-04:002019-03-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-28:/diary-2019-03-28<p class="first last">Unexpected obstacles suck.</p>
<p>Okay, so.
Yesterday, I was trying to describe what I felt would fit with my understanding of literate programming, and today, I realized that what I was describing is basically what <a class="reference external" href="https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html">rustdoc</a> does.
Regardless, let's see if it looks good if I try to impose a narrative on Structured Data's documentation.</p>
<p>So, here's where that ended up:</p>
<ul class="simple">
<li>Wrote up explanations of roughly how to use the <tt class="docutils literal">adt</tt> and <tt class="docutils literal">match</tt> modules.</li>
<li>Doctest in the <tt class="docutils literal">adt</tt> module.</li>
<li>Turns out Divide and Cover can't handle doctests.</li>
<li>Frantic merges.</li>
<li>Sedate Travis jobs.</li>
</ul>
<p>I think I'll need to try again later to improve the <tt class="docutils literal">match</tt>-related documentation, because that offers somewhat more elaborate capabilities than <tt class="docutils literal">adt</tt> does.</p>
<p>I'd also like to give the <tt class="docutils literal">match</tt> module its own doctest, but I'd like to give Travis a chance to catch up.</p>
<p>I definitely want to give this another try, because I ended up getting kind of distracted after my initial shot at improving the documentation.</p>
Diary 2019-03-272019-03-27T04:00:00-04:002019-03-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-27:/diary-2019-03-27<p class="first last">I read stuff pertinent to this entry but took no notes, then focused my effort on something not amenable to writing up. So it's a little scattershot.</p>
<p>A grab-bag of things, followed by a little more depth:</p>
<ul class="simple">
<li>I looked into literate programming. More on that in a moment.</li>
<li>I revisited some hobby code. It is now more correct, and less prone to stack overflows.</li>
<li>I did a bunch of merges with my Jedi fork to hopefully get ready to start actually developing.</li>
</ul>
<p>I let this entry go late, so I'm going to try to type quickly.</p>
<p><a class="reference external" href="http://www.literateprogramming.com/">Literate Programming</a> is a subject somewhere between obscure and contentious, except for <a class="reference external" href="https://wiki.haskell.org/Literate_programming">Haskell</a>, and <a class="reference external" href="https://coffeescript.org/#literate">CoffeeScript</a>, I guess.
I think I also read about it in R.
I guess what I should have said is, there seems to be widely scattered experimentation with the concept, but it hasn't really taken the world by storm in the course of 35 or so years.
I've mainly been exposed to the general through <a class="reference external" href="https://jupyter.org/">Jupyter</a> notebooks, which don't go as far as Knuth's CWEB tool, and also have... <a class="reference external" href="https://www.youtube.com/watch?v=7jiPeIFXb6U">issues</a>
(I haven't watched the recording, but I read the slides, and it seemed to jibe with my experiences. Hopefully things have changed since I last seriously tried to use Jupyter.)</p>
<p>Anyway, what is literate programming?
According to that website I linked:</p>
<blockquote>
Let us change our traditional attitude to the construction of programs: Instead of imagining that our main task is to instruct a computer what to do, let us concentrate rather on explaining to human beings what we want a computer to do.</blockquote>
<p>But <a class="reference external" href="http://akkartik.name/post/literate-programming">some people</a> feel that the original implementations of the idea (from Knuth!) falls short in various ways.</p>
<p>For my part, I've been refreshing my memory on what's out there, with a focus on Python, over the last few days.
I might do a survey of things later, but I don't have time to hunt down and describe all of the links.
Thinking over the way I want to see my own documentation improve, I think I don't need to learn a new tool for it.
What I need to do is focus on documenting the affordances and requirements of my public interfaces, and make sure that dependencies are hyperlinked.
The idea being, to make it easy, using the existing documentation infrastructure, for people to put together the narrative that tells them how to use the library, using fragments of hypertext.
("What?" "They need to be able to wiki-walk the documentation." "Oh.")</p>
<p>Examples of the kinds of information that should be included:</p>
<ul class="simple">
<li>Required types/interfaces ("What do I need to give it?")</li>
<li>Provided types/interfaces ("What can I do with what it gives me back?")</li>
<li>Known subclasses/implementations ("How can I satisfy this requirement?")</li>
</ul>
<p>I'll give it a shot tomorrow.
Good night for now!</p>
Weekly Roundup 2019-03-262019-03-26T04:00:00-04:002019-03-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-26:/weekly-roundup-2019-03-26<p class="first last">Improving code by writing about stuff I don't understand.</p>
<ul class="simple">
<li>Wednesday: I tried to adjust to a bit of the new schedule that surprised me, and plan ahead a little.</li>
<li>Thursday: I thought about revisiting Jedi, mentioned a problem I'd solved with my mypy plugin, and briefly described Baba is You.</li>
<li>Friday: I tried to write up my false starts with the plguin very thoroughly.</li>
<li>Saturday: I filed a bug against Rust, and started trying to work out how to move on with the plugin.</li>
<li>Sunday: I remembered that <tt class="docutils literal">adt</tt> is literally based on a module with a dedicated plugin, so I should look at the plugin. I then had so much trouble explaining some of my design decisions that I released two new versions over the course of the post. (Technically, the second one was a bugfix.)</li>
<li>Draw a Box: Holding steady, feeling good about this.</li>
</ul>
<p>Next week, I think I should try to start back up on Jedi for real, but for some reason I seem to be researching literate programming.</p>
Draw a Box 2019-03-252019-03-25T04:00:00-04:002019-03-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-25:/draw-a-box-2019-03-25<p class="first last">I'm glad this seems to be working.</p>
<p>In this post:</p>
<ul class="simple">
<li>Oh good, this is sustainable.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>More organic perspective on March 22. I think I'll keep at this until I can reliably use my shoulder for tiny boxes, or I get really bored.</li>
<li>More organic perspective on March 23. I'm trying to verify some of the vanishing points on these boxes, and they look off, so I'll try to focus on that for a bit.</li>
<li>More organic perspective on March 24. I drew a long curve this time, so it's not done.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Diary 2019-03-242019-03-24T04:00:00-04:002019-03-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-24:/diary-2019-03-24<p class="first last">Blogpost-driven development</p>
<p>I realized something about Structured Data and writing plugins for it: the <tt class="docutils literal">adt</tt> decorator is inspired heavily by the dataclasses module, so I should just... look at the plugin to figure out what's going on there.</p>
<p>What I've worked out so far is that I've changed things enough that a straight copy and paste is mostly not a good idea.
I'll try to summarize what's going on when the <tt class="docutils literal">adt</tt> decorator hits a class:</p>
<ul class="simple">
<li>The decorator takes three boolean options: <tt class="docutils literal">eq</tt>, <tt class="docutils literal">order</tt>, and <tt class="docutils literal">repr</tt>. <tt class="docutils literal">repr</tt> is irrelevant to the plugin.</li>
<li>If <tt class="docutils literal">eq</tt> is true, the decorator will attempt to add predefined equality methods to the class. It will not add them if the class itself defines them, but it ignores superclasses, and hm. Hm. I'm not sure that's right. In fact, I'm so weirded out by that behavior that I just now published a version where it takes superclasses into account. If the prewritten equality methods are added, it also attempts to add a prewritten hash method.</li>
<li>If <tt class="docutils literal">eq</tt> is false, the baseline behavior of equality methods is that of <tt class="docutils literal">object</tt>. Also, it is an error in these circumstances to pass <tt class="docutils literal">order=True</tt>.</li>
<li>If <tt class="docutils literal">order</tt> is false, the comparison methods bottom out at <tt class="docutils literal">None</tt>, which... might be wrong? I'm honestly not sure.</li>
<li>If <tt class="docutils literal">order</tt> is true, it is an error if the prewritten equality methods weren't added. If they were, then the decorator will attempt to add predefined comparison methods. If comparison methods are already defined, that is an error.</li>
</ul>
<p>For the methods mentioned here, the <tt class="docutils literal">self</tt> and <tt class="docutils literal">other</tt> parameters should be constrained, not to the same type as each other, but to subclasses of the decorated class.</p>
<p>Other things going on: annotations with a particular type indicate "constructors", which should be modeled as functions accessible only to the decorated class.
I don't know if there's a good way to represent that sort of thing.</p>
<p>It looks like I've got two main areas to cover, and I think the way to get started on them is to start adding pseudocode in comments and figure out how to implement them.
For now, it's late, and I should sleep.</p>
Diary 2019-03-232019-03-23T04:00:00-04:002019-03-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-23:/diary-2019-03-23<p class="first last">I should try writing normal typed code sometime.</p>
<p>State of the coding: I managed to break the Rust compiler in what I assume is a new way, involving doing really weird things to the type checker.
Besides that, I'm gradually making progress on the mypy plugin.
I've put together enough stuff to get the Ctor annotations to typecheck, and now I just have to figure out how to handle the adt decorator.
Ah, "just".
I basically need to access a representation of the underlying type, somewhere, and replace the above-modified type annotations with functions or something.
This is glossing over the fact that adt has helpers for various protocols.
It has these helpers, because, you know, why not?
I'm going to need to take those into account as well.
I'll have to see if anything is needed for the match module, but the key interfaces to that look like they're mostly ending up with <tt class="docutils literal">Any</tt>, anyway.</p>
<p>Anyway, I was so focused on getting the plugin to do stuff that I started this entry quite late, and now it's late, and it would be best for me if I finished this entry now.</p>
Writing a mypy Plugin 2019-03-222019-03-22T04:00:00-04:002019-03-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-22:/writing-a-mypy-plugin-2019-03-22<p class="first last">Here's how I messed up.</p>
<p>So, as I've mentioned, I'm working on a mypy plugin for Structured Data.
First, I'll quickly go over why this is needed to start with.
A typical ADT definition in Structured Data looks like this:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span></pre></div></td><td class="code"><div><pre><span></span><span class="kn">import</span> <span class="nn">typing</span>
<span class="kn">from</span> <span class="nn">structured_data</span> <span class="kn">import</span> <span class="n">adt</span>
<span class="n">T</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T"</span><span class="p">)</span>
<span class="nd">@adt</span><span class="o">.</span><span class="n">adt</span>
<span class="k">class</span> <span class="nc">BinaryTree</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span>
<span class="w"> </span><span class="sd">"""A data type that you probably don't want to actually use!"""</span>
<span class="n">Leaf</span><span class="p">:</span> <span class="n">adt</span><span class="o">.</span><span class="n">Ctor</span>
<span class="n">Node</span><span class="p">:</span> <span class="n">adt</span><span class="o">.</span><span class="n">Ctor</span><span class="p">[</span><span class="s2">"BinaryTree[T]"</span><span class="p">,</span> <span class="n">T</span><span class="p">,</span> <span class="s2">"BinaryTree[T]"</span><span class="p">]</span>
</pre></div></td></tr></table></div>
<p>To be honest, this is actually a little more advanced than the code I've tried to get it to accept.
Some of this might be outright wrong.
All the same, it has the issue of "indexing <tt class="docutils literal">Ctor</tt>", which makes mypy raise errors.
Variadic generic types exist, but they can't be user-defined currently.</p>
<p>This is exactly one of the use cases that the mypy documentation describes for one of the plugin hook methods.
Right at the top of the <a class="reference external" href="https://mypy.readthedocs.io/en/stable/extending_mypy.html#current-list-of-plugin-hooks">Current list of plugin hooks</a>.
So, I just need to define a custom hook to handle this stuff.
Simple, right?</p>
<p>Anyway, this is actually so far from simple so far, that I don't think I've actually changed the behavior yet.
This post is about what it took for me to get to, <em>maybe</em>, <a class="reference external" href="http://rampantgames.com/blog/?p=7745">black triangle</a>.</p>
<p>First, a bit of background: the implementation of Structured Data is <em>extremely</em> modularized.
Not in the sense that there are swappable components of some kind, but in the sense that there are <em>a lot</em> of Python modules, even though the public interface resides entirely in three modules: <tt class="docutils literal">adt</tt> (algebraic (actually sum) data types), <tt class="docutils literal">data</tt> (example data types), and <tt class="docutils literal">match</tt> (destructuring matches).
These modules rely on each other, and thirteen internal modules, some of which define just a single short class or function.
I forget what my exact thought process was, but it doesn't bother me enough to want to change it, so I'm leaving it be.
The relevant fact is that, while <tt class="docutils literal">Ctor</tt> is <em>exposed</em> through the <tt class="docutils literal">adt</tt> public module, it's defined in an internal module, and that internal module contains some significant statements, the nature of which I will temporarily conceal for the purpose of generating suspense.</p>
<p>Now, where this comes around to mypy plugins is, the hooks, at least the ones I've looked at, work by passing the hook a "fullname", which is a string, and getting back either <tt class="docutils literal">None</tt>, or a callback that takes a specialized object.
If there's a thorough explanation of the concepts involved, I've missed it, so I was experimenting, dropping in print statements and forcing failures to make pytest reveal the output.
(Oh yeah, I'm using <a class="reference external" href="https://github.com/mkurnikov/pytest-mypy-plugins">pytest-mypy-plugins</a> to handle the testing. It took a little poking at the source code for me to figure out how to configure everything in a way that seems to work.)
In any case, this revealed that mypy was asking the hooks for callbacks using a fullname that included the module in which <tt class="docutils literal">Ctor</tt> is actually defined.
I didn't want to make my plugin rely on the internal layout of Structured Data, so I looked for a way to fool mypy.
It seemed that my initial efforts were in vain: the <tt class="docutils literal">typing</tt> module defines a <tt class="docutils literal">TYPE_CHECKING</tt> constant that is false at runtime, but statically considered true.
In other words, by using this constant in a conditional, we can replace functionality with variants that have more desirable type-checking characteristics, such as being defined in a particular module.</p>
<p>Now, another point of confusion I had was, the <tt class="docutils literal">UnboundType</tt> objects that my code was getting to work with, have an <tt class="docutils literal">args</tt> attribute, but when I went to retrieve it, it was always empty, even though my test cases so far all use subscripting.
I had no idea what to expect mypy to do, no clear and strong mental model, so assumed I was getting the annotations in some kind of multiple-passes-of-a-single-location workflow, which seemed inconvenient, but whatever.</p>
<p>Things started to get confusing for me when I realized that I was still getting the "real" fullname, even though I was trying to use <tt class="docutils literal">TYPE_CHECKING</tt> to create a facade for mypy's benefit.
I decided to try to future-proof this stuff by writing code that works on the aspects of <tt class="docutils literal">Ctor</tt> that I consider unchanging:</p>
<ul class="simple">
<li>There is only one <tt class="docutils literal">Ctor</tt> class overall.</li>
<li>It is defined somewhere in the hierarchy under <tt class="docutils literal">structured_data</tt>.</li>
<li>It is called <tt class="docutils literal">Ctor</tt>.</li>
</ul>
<p>Anyway, still confused by the behavior of the plugin architecture, I added more and more diagnostic logging, until I realized something: I <em>was</em> seeing calls that had non-empty <tt class="docutils literal">args</tt> eventually, and they differed from the initial calls in such a way that they were almost certainly unrelated.
The later lines were the ones I wanted to analyze, and the earlier ones?
They weren't originating in the test data at all, not directly.
The test data was importing from <tt class="docutils literal">structured_data</tt> because it had to, and that was causing mypy to run on <tt class="docutils literal">structured_data</tt>, and process those significant, suspense generating statements I mentioned earlier.</p>
<p>Those statements are...
<tt class="docutils literal">structured_data</tt> has a few internal caches that relate to <tt class="docutils literal">Ctor</tt> objects, and those caches are defined alongside <tt class="docutils literal">Ctor</tt>, in the same module, and have to be annotated with it.
As such, because I had the facade in the public module, <em>the private module didn't know about it</em>, and its annotations, <em>the annotations that have to be processed before the test data</em>, included the fullname that corresponded to the runtime type.</p>
<p>So, if you're still following (this is kind of a mess...), the solution to my problems was to trust the code a little more: have the conditional import/dummy definition, and match the dummy fullname exactly, because mypy has no problem with the internal usage of <tt class="docutils literal">Ctor</tt>, and therefore <em>I don't want to analyze it myself</em>.
I missed that this was working in the first place, first because the internal usages were kicking up the internal name, and then because I thought I had to devise a fuzzy matching scheme, which concealed the fact that it was, in fact, matching two different strings.</p>
<p>Coding is hard, and as I said, I'm pretty sure this stuff doesn't really do anything yet.
Good luck in your own coding endeavors, and I hope this breakdown of my confusion has given you some ideas for how to approach whatever confusion you may be dealing with.</p>
Diary 2019-03-212019-03-21T04:00:00-04:002019-03-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-21:/diary-2019-03-21<p class="first last">Getting visibility into frameworks is confusing.</p>
<p>Collaboration tip: try to avoid saying you'll work on something, but then ghost it for like a year.
Anyway, I'm interested in getting back to improving Jedi, so I've been looking over my fork, and realizing it would probably be best to start fresh.
(Among other things, there's a new branch that it sounds like I should be targeting, maybe?)</p>
<p>I also figured out some of the reasons that my mypy plugin stuff was so incredibly confusing to me, so I've got improvements that should go in soon.
I'll try to write that up tomorrow, because it could be useful troubleshooting advice for people who write their modules like I do.
(I've already put up an abridged writeup in Gitter, which I hope came out a little more in-depth than "I fixed it".)</p>
<p>I also grabbed some new games.
Baba is You is... confusing.
A completely accurate description would run the risk of sounding like the <a class="reference external" href="https://www.destructoid.com/100-objective-review-final-fantasy-xiii-179178.phtml">100% Objective Review: Final Fantasy XIII</a>.
("You play as characters. The player characters are the characters you control. Your goal is to attain the goal.")
Anyway, that was interesting and distracting, so I'll also be playing that for a while.</p>
Diary 2019-03-202019-03-20T04:00:00-04:002019-03-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-20:/diary-2019-03-20<p class="first last">Ugh... sleepy...</p>
<p>Tuesday is a day for writing diary entries now.
Weird.</p>
<p>Anyway, I'm making slow progress on mypy plugin stuff.
I ended up finally asking some questions on the Gitter channel for typing, and hopefully I didn't fall too much into the X/Y problem in how I stated them.
I'll give that some time, and try to switch gears for now.</p>
<p>Let's see.
I can try to improve my Exercism stuff to be more comprehensible, and there's still the Amethyst tutorial to get on with.
For now, though, I just want to wrap things up.
I'm super tired.
Good night, sorry there wasn't much.</p>
Weekly Roundup 2019-03-192019-03-19T04:00:00-04:002019-03-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-19:/weekly-roundup-2019-03-19<p class="first last">Feeling a bit better, for sure.</p>
<ul class="simple">
<li>Wednesday: I revisited Structured Data, because polishing this stuff is fun, even if I'm not sure what I'm going to do with it.</li>
<li>Draw a Box (last in this slot): After another poor showing, I realized I needed to change things up.</li>
<li>Friday: I revisited my syntax definition, and thought about how best to recreate Divide and Cover for Coverage 5.</li>
<li>Saturday: I realized that some of the details of how Structured Data works are obscure even to me at this point.</li>
<li>Sunday: I started thinking about a mypy plugin for Structured Data, in a post which I... don't remember <em>not</em> publishing?</li>
<li>Draw a Box: Three days of practice instead of two! Whoo!</li>
</ul>
<p>Next week, let's see what catches my interest.</p>
Draw a Box 2019-03-182019-03-18T04:00:00-04:002019-03-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-18:/draw-a-box-2019-03-18<p class="first last">... Hooray.</p>
<p>In this post:</p>
<ul class="simple">
<li>I actually hit my weekly goal, now that I've revised it down to more than I was doing consistently.</li>
<li>I did, however, have to do some of these late because we were out of the house. I might need to revise my weekend scheduling to earlier in the day.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>The axes of the rotated boxes exercise on March 15. This is much better laid-out than my previous attempts, though there are a few issues: the vanishing points are deflected off the axis, I don't know if the backs of the ends are the right size, many of the lines are wobbly, and the back faces were too small for me to comfortably use my shoulder.</li>
<li>I didn't finish the rotated boxes exercise, per se, on March 16. It's just that it's too crowded and busy for me to place the last four boxes. I'm going to have to draw everything bigger next time.</li>
<li>Some organic perspective on March 17. It's really hard to keep on using my shoulder with the tiny boxes, still.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same.
Maybe.
Maybe not.
We'll see.</p>
Diary 2019-03-172019-03-17T04:00:00-04:002019-03-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-17:/diary-2019-03-17<p class="first last">Not terribly exciting, but necessary.</p>
<p>I did a little bit of documentation work, but I'd like to make the plugin, which means setting up a new project.
I'm not sure if Python got a better story for starting a project when I wasn't looking.
The Structured Data project is based off a cookiecutter, but I've customized it heavily beyond that, and I've never quite gotten how to use cookiecutters.
Like, I have a strong, sincere conviction that it should be possible to tweak the generation parameters for a cookiecutter and update an existing project, and no evidence whatsoever that there is any way to actually do this.
So, for the plugin, I'll be just directly copying the coverage5 branch of Structured Data and pulling stuff out of it.</p>
<p>Okay, some time later, I've updated a whole bunch of the support code.
It's not worth trying to fix up any more just yet, but I think I should soon be able to push, and from there, fix the rest of the badges.
I also need to update the requirements, have a proper test file tree, and actually write some code.
(And find any other bits I missed.)
Feeling good about getting this done in the next few days, though.</p>
<p>(Addendum: did I... forget to publish this? Weird.)</p>
Diary 2019-03-162019-03-16T04:00:00-04:002019-03-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-16:/diary-2019-03-16<p class="first last">A bunch of false starts, and a rabbit hole.</p>
<p>Finally heard back about the Erlang exercise stuff.
Needs work, but they were really diplomatic about it.</p>
<p>Anyway, I tried to understand reStructuredText Augmented, but I couldn't, so I looked into writing a mypy plugin for Structured Data, but it was late and I didn't feel like starting up a new repo, so I instead tried to increase the mypy coverage for Structured Data.
This was mostly straightforward until it really wasn't.
Calling the <tt class="docutils literal">adt</tt> decorator ultimately invokes a dense thicket of introspection and metaprogramming; I'm actually not sure what type mypy is inferring for some of these functions, if any.</p>
<p>Before I do any more of this fanciness, I should probably work on improving the documentation.
Most of the concepts exist basically completely within about a hundred test cases, which isn't a great way to read them, especially since they're not in the actual documentation.
I'll try to base stuff off the dataclasses documentation, to start with.</p>
<p>It's really late and I don't have a good way to end this post.</p>
Diary 2019-03-152019-03-15T04:00:00-04:002019-03-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-15:/diary-2019-03-15<p class="first last">Small but good-feeling progress.</p>
<p>Taking a fresh look at the syntax definition code revealed two things:</p>
<ul class="simple">
<li>sublime-syntax files are still really confusing to me.</li>
<li>I was able to accomplish a lot of what I wanted by just adding some scopes and deleting a few rules. The changes I've made are immensely helpful, but I'm not done just yet. (I may also be able to simplify my color scheme.)</li>
</ul>
<p>I'd like to now focus on creating a custom reporter for coverage collected using the function context.
(Ideally, there'd be a module-level context...)
There are a few things to check for/do:</p>
<ul class="simple">
<li>For each file in the src, its first statement was executed by the first context. (Warn if not, with an option to make this an error.)</li>
<li>It is possible to associate a list of contexts to each source file. (There should be some mechanism for overriding the default logic, using some kind of pragma, maybe?) (I just checked something, and it looks like munging this myself would be unreliable enough that I'm going to ask for a "test_module" context.)</li>
<li>Considering only the first context and the associated contexts, calculate the coverage for the file, and pass this result to the various reporters.</li>
<li>Possibly instead this would be a post-processing step on the coverage database, so everything that reads it just sees the munged data and is fine with it.</li>
</ul>
<p>Things are feeling nice from all of this.
(It's just too bad I can't figure out how to hook Sublime Text into my publishing pipeline so I can inflict my syntax definition and color scheme on the world.)</p>
<p>I'll try to write some of this stuff up tomorrow.
Good night.</p>
Draw a Box 2019-03-142019-03-14T04:00:00-04:002019-03-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-14:/draw-a-box-2019-03-14<p class="first last">It's about time, really.</p>
<p>In this post:</p>
<ul class="simple">
<li>Some drawing.</li>
<li>A mild pivot.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>Some more single-point perspective on March 8. I haven't done much of this sheet, but I think I'll move on for now. For fun, I tried sketching some mammals from reference. Initial results: it's pretty easy to draw an okay tiger, possible to draw a somewhat okay echidna, and frustrating to attempt to draw a pangolin.</li>
<li>I tried to redo the rotated box exercise on March 10. I gave up early when I accidentally drew one of the boxes as a pentagonal prism. I figured that was a sign.</li>
</ul>
<p>And that's it.
I've finally come to the conclusion that "drawing every day" isn't working any more, so I'm going to try changing things: fewer days to try drawing, but more structure about when in the day to do so.
I'll be specifically doing this in the afternoon, when I'm a bit more awake, on days where it's convenient for me to do this stuff in the afternoon.</p>
<hr class="docutils" />
<p>Next time, the entry will hopefully have <em>three</em> days of work recorded.</p>
Diary 2019-03-132019-03-13T04:00:00-04:002019-03-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-13:/diary-2019-03-13<p class="first last">Some of the issues that code analysis websites raise are like puzzles with no answers.</p>
<p>I kicked off the week doing various bits of housekeeping on the Structured Data repo.
This included:</p>
<ul class="simple">
<li>Getting docs to build, finally.</li>
<li>Adding a note to the README about namedtuple enhancements in Python 3.8.</li>
<li>Addressing some issues flagged by some of the many, many integrations the repo.</li>
<li>Adding type annotations to internal functions.</li>
</ul>
<p>I also made a branch for testing against the latest <a class="reference external" href="https://pypi.org/project/coverage/5.0a4/">coverage.py alpha</a>.
I'm not sure what kind of things I need to do to make coverage work as it did under divide-and-cover.
My big concern right now is making sure all imports of source files are accomplished by context 1.
My use of fixtures <em>may</em> make this work, but I'm not certain.</p>
<p>I'm going to have to ponder Coverage's documentation, look into making some kind of enhancements to reporting, and maybe focus on other things about this code for now.
For example, I haven't touched the syntax file, and it's still taunting me with its excessive lack of color.
I'll try to get back up to speed on that in the next few days, because I really want to make the Augmented syntax definitions the best they can be.</p>
<p>For now, the best I can be is ready for tomorrow and in bed.
Good night.</p>
Weekly Roundup 2019-03-122019-03-12T04:00:00-04:002019-03-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-12:/weekly-roundup-2019-03-12<p class="first last">It's fine.</p>
<ul class="simple">
<li>Wednesday: I started learning Amethyst, and submitted a solution to Exercism that I'm pretty sure they haven't gotten back to me about yet.</li>
<li>Draw a Box: More disappointing roundups on this. Oh well.</li>
<li>Friday: Cleaned up stuff on my laptop a little. Spitballed interpreter design; I do not have anything planned where I would <em>need</em> a custom interpreter.</li>
<li>Saturday: Complained about the Twitch app breaking after upgrade. (It was briefly not broken, but now is again.) More Amethyst, and thoughts on Halloween 6.</li>
<li>Sunday: Minecraft, Amethyst, rpgs.</li>
<li>Monday: I complained about how various programming tutorials tell you to change code, but don't give you proper diffs, so if you get errors it's like, did I mess something up? Do they fix this error later in the lesson? Did they just plain mess up the code in their not-diffs? And thought about revisiting development of my Python libraries.</li>
</ul>
<p>Next week, I think I should be making a deliberate effort towards better organization of all of this stuff.</p>
Diary 2019-03-112019-03-11T04:00:00-04:002019-03-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-11:/diary-2019-03-11<p class="first last">More quiet weekend stuff</p>
<p>Working my way through the Amethyst tutorial, and it's mostly fine, but it seems a little weird to me that I've now tried out two unrelated game dev tutorials that want you to hand-apply diffs that are, textually, not diffs.</p>
<p>Like, maybe that's a resolution I should make to myself if I ever make a programming tutorial: whenever I tell people to change a file on their computer, provide a complete working patch they could apply via command-line.</p>
<p>Anyway, other stuff: statted up some enemies for an attempt at an Anima Prime tutorial, and played a bunch of Minecraft.
(I don't know if I was supposed to notice that alloying is available as soon as basic Tinker's stuff is unlocked, but it is and I did.)</p>
<p>I was thinking about Rust and applying ideas from Rust to Python, and I just realized that I don't know how Class Namespaces handles variable annotations.
My guess is "poorly", but now I kind of want to dust it off and see.
For background, Class Namespaces is a Python 3 library I wrote, inspired by a blog post that I assume was about <a class="reference external" href="https://erezsh.wordpress.com/2008/06/27/namespaces-lets-do-more-of-those-python-hackery/">namespaces in Python 2</a> (based on the date of publication).
It does really fiddly stuff with metaclasses and custom dict subclasses to let you define nested namespaces within a class using context managers.
Some parts of it are over-complicated, but which specific parts those are, in my opinion, may surprise you!
I might try and revisit it, but while I'm thinking of Python libraries, I'll probably also go for my Structured Data library, a library that gives you completely different reasons to put a bunch of weird junk in your class definitions.</p>
<p>Thinking about that makes me think of trying again to write a mypy plugin for Structured Data, and how I'd version such a thing...
See, if I add a feature to the base library, that's a minor change, but I think it'd be a breaking change to the plugin, because it needs to be updated, but the updated version would have false negatives if it's used against code written for an earlier version.
Does this make any sense?
I don't know.
It's late.</p>
<p>I think I'd like to come up with a bit more structure for these posts, but that's not happening at this exact moment.
Good night.</p>
Diary 2019-03-102019-03-10T05:00:00-04:002019-03-10T05:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-10:/diary-2019-03-10<p class="first last">Maybe I should just try to accept that "a whole lot of Minecraft" is a thing that'll happen.</p>
<p>Twitch still isn't working right, so I've given up on it and switched to MultiMC.
That worked, and I spent a lot of today messing with Modern Skyblock 3.
I'm not sure if I was supposed to notice that there's alloying early-game, but I did, and that has thrown things way out of whack.</p>
<p>Anyway, I also got a little further in the Amethyst tutorial.
Nothing much to say about that; my plan is to go more in-depth after I finish it, and start tweaking it into different forms.</p>
<p>Also also, we talked some about Anima Prime, and the current plan is that I'll put together an example thing showcasing the various bits of the rules.
Not quite sure what to do there that the sourcebook doesn't already have.
Maybe I'll ask for a specific scenario to describe...</p>
<p>Other than that, today was pretty uneventful, which was nice.</p>
Diary 2019-03-092019-03-09T05:00:00-05:002019-03-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-09:/diary-2019-03-09<p class="first">I couldn't quickly figure out how best to cite the webpage I quoted.</p>
<p class="last">A variable-ratio schedule rewards a particular behavior but does so in an unpredictable fashion. The reinforcement may come after the 1st level press or the 15th, and then may follow immediately with the next press or perhaps not follow for another 10 presses. The unpredictable nature of a variable-ratio schedule can lead to a high frequency of behavior, as the animal (or human) may believe that the next press will “be the one” that delivers the reward.</p>
<p>(<a class="reference external" href="http://www.psychexamreview.com/schedules-of-reinforcement/">http://www.psychexamreview.com/schedules-of-reinforcement/</a>)</p>
<p>Anyway, the new Twitch launcher tends to be really glitchy about displaying the modpacks I have installed.
I haven't found a consistent fix yet.
For some reason, I've been in there <em>a lot</em> trying to get it to work.</p>
<p>I did a little bit of progress following the Amethyst tutorial.
Mostly, I got it set up with Pijul so I've got a safety net against accidentally trashing it.
I'm really interested in exploring the stuff about pushdown automata, because that's the kind of thing I was trying to do, badly, when I was following that Python roguelike tutorial.
(As I recall, the tutorial described an approximation to a PDA, and I <em>might</em> have tried to generalize it.)</p>
<p>Aside from that, we watched Halloween 6 (or "Vi"), and, um, wow.
That was some editing.
It's a good thing neither of us has photosensitive epilepsy.
I feel like there was a bunch of padding going on there:</p>
<ul class="simple">
<li>People get freaked out for no reason, and do things slowly as a result</li>
<li>Overuse of musical stings, to the point where they made me think that nothing surprising had happened even though it had.</li>
<li>Lingering shots of bladed tools.</li>
<li>Talking to people in one place about how they'd like to continue the conversation somewhere else.</li>
</ul>
<p>Like, points for trying to build on the thorn stuff from 5, but, oof.</p>
<p>And, it's late again.
I'll try to work harder on following the tutorial tomorrow.
Good night.</p>
Diary 2019-03-082019-03-08T05:00:00-05:002019-03-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-08:/diary-2019-03-08<p class="first last">I am very easily distracted.</p>
<p>Things I did today:</p>
<ul class="simple">
<li>Focused on cleaning up my giant mass of web browser tabs. My laptop should run a lot better now.</li>
<li>Minecraft after I told myself I wouldn't.</li>
</ul>
<p>I've also been thinking about implementing interpreters in Python, inspired by considering the tail-call elimination code I wrote, and pondering whether it has any real use.
Designing interpreters in general might be useful if I get into the position of both wanting to add scripting to something, and not seeing a good story for embedding an existing language's interpreter.</p>
<p>Considering the hypothetical language as statement-based, with various control flow forms.
The basic structure of organization is a "block", which the various control flow forms include.
Let's model this at a somewhat low level, and have the concept of a "function", which acts as the root of a tree of goto labels.
So, in terms of definition, there are various kinds of statement, each of which can be associated with some number of blocks.
Each block contains some number of statements.
(It'd probably be really hard to actually use, but I've got a mental image of something partway between Lua and Erlang.)
I'm imagining something that could be considered equivalent to a continuation, but it would actually just be pretty much a normal stack: each function call would be a new frame, and entering blocks would add scopes, but leave the frame intact.
So, there'd be a pointer within each relevant block of statements, and that would either advance or be replaced with a pointer to an accessible label.</p>
<p>That was fun to work out, but I don't think I have anything new to bring to the table here, so I'll shelve this as well for now, and pick back up game-making tutorials.
I think what I'd like to do when I come back to this kind of language messing-around thing is to be articulating hypotheses, and designing stuff to test them.
Talking about this reminded me of some old code, and I got distracted staring at it, because it's frankly kind of weird.
Oh well, best move on, get sleep.
Good night.</p>
Draw a Box 2019-03-072019-03-07T05:00:00-05:002019-03-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-07:/draw-a-box-2019-03-07<p class="first last">Oof, week after week of this sort of thing is a little rough.</p>
<p>In this post:</p>
<ul class="simple">
<li>A little bit of single-point perspective.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>Finally psyched myself up to do some single-point perspective on March 4. In terms of speed and accuracy, doing this with my shoulder leaves a lot to be desired.</li>
<li>More single-point perspective on March 6. Speed is better, dunno about accuracy. I'm going to have to start explicitly scheduling this stuff so I can get it done sooner, and therefore less sleepily.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will hopefully be more substantial.</p>
Diary 2019-03-062019-03-06T05:00:00-05:002019-03-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-06:/diary-2019-03-06<p class="first last">... Slow ramp, I guess.</p>
<p>Things I did today:</p>
<ul class="simple">
<li>Started reading the very beginning of the amethyst.rs documentation, and downloaded stuff. While writing this entry, I started up a project, and later I'll read over the documentation.</li>
<li>Got back into Exercism with a solution that feels like it's got around three iterations to go before we'll be satisfied with it. I'm at the same exercise on both tracks I'm doing actively, so I could try to port this solution from Erlang to Elm, but I probably shouldn't.</li>
<li>Minecraft skyblock stuff. It turns out I'd been doing squid spawning all wrong, and I managed to get it to work trivially with a few minor adjustments. Thus, I was able to get cactus. ... Expert packs can be <em>weird</em>. Anyway, I think I should back off from that until the weekend and focus on art; I've actually got stuff in mind to draw for fun! It'll be really cool until I try it, and all of my ambitions turn to dust.</li>
</ul>
Weekly Roundup 2019-03-052019-03-05T05:00:00-05:002019-03-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-05:/weekly-roundup-2019-03-05<p class="first last">Those were some really lean posts, eesh.</p>
<ul class="simple">
<li>Wednesday: I pasted an early draft of some frightening code that somebody is probably going to decide they like. I also showed off the output from the then-current version of my auto-rolling code for the RPG campaign we're trying to set up.</li>
<li>Draw a Box: I drew a little bit. (Spoiler, the low levels continue for a bit.)</li>
<li>Friday: I mostly thought about sequels, and what people "actually want" when they say they want a sequel, and didn't explicitly wonder "Does the weird dance the Halloween series is doing qualify as 'not being beholden to continuity'?"</li>
<li>Saturday, Sunday, Monday: I took it easy.</li>
</ul>
<p>Next week, I'm going to try to ramp back up again.</p>
Diary 2019-03-042019-03-04T05:00:00-05:002019-03-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-04:/diary-2019-03-04<p class="first last">I guess it was a lazy Sunday.</p>
<p>What did I do today?
Um...</p>
<p>Well, we've been watching more of the Halloween movies.
We're up through 5, so just one more and then the timeline starts getting all silly.</p>
<p>I'm going to wind down on the RPG stuff until we both think we have a good grasp on the rules.</p>
<p>I think for the future I'll try to get more into the other stuff I've been doing: learning new programming languages, reading trashy books, and getting back into drawing, which I haven't been doing much because I'm supposed to spend an equal amount of time doing stuff for fun, and I haven't had fun stuff to draw in mind.</p>
<p>All of that is in the future, however, and in today's immediate past is, um, a bunch of modded Minecraft, I guess.</p>
<p>Let's see about being a bit more active in the months to come, I guess.
Good night.</p>
Diary 2019-03-032019-03-03T05:00:00-05:002019-03-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-03:/diary-2019-03-03<p class="first last">Got to accomplish something each day.</p>
<p>I spent today being tired, and working on rpg stuff (including adding more capabilities to the auto-roller).
We designed our characters.
Now, I'm trying to write up the stuff we need to know for various situations so we have a quick reference.
It's not going well; I'm going to see if I can mark up the pdf on my e-reader any.
Maybe I'll just be like, okay, I'll act as the referee.</p>
<p>I don't know when we'll try to get started in earnest.
My wife seems to be having some kind of extended migraine of varying intensity.
We might need to put off doing things too intensely until the seasons change properly.</p>
<p>Looking ahead, I was thinking I wanted to take transcripts of this stuff, but I don't know how she'd feel about putting them online.</p>
<p>I'm going to wrap this up here, and try to test this rumor I've heard that "sleep" does something to alleviate "being tired".</p>
Diary 2019-03-022019-03-02T05:00:00-05:002019-03-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-02:/diary-2019-03-02<p class="first last">I dunno, it's short this time.</p>
<p>Haven't done the tab completion, but I've got it basically specified.
I made some other tweaks to the display code.</p>
<p>Aside from that, I decided to get unblocked on the secret project, and so I am.</p>
<p>Anyway, going to try to get the game going this weekend, I think.</p>
<p>Not much else to say, because today was a mix of polishing a command-line interface, secret project, and taking it easy.</p>
Diary 2019-03-012019-03-01T05:00:00-05:002019-03-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-03-01:/diary-2019-03-01<p class="first last">Sequels, and some coding progress.</p>
<p>I seem to recall pontificating about sequels and continuity and whether some movie series "really" share a continuity.
I feel like in talking about stuff along those lines, I'm playing a little fast and loose with various ideas and assumptions, such as:</p>
<ul class="simple">
<li>People should go out and do what I say with no further reflection. This is false.</li>
<li>It's bad if something isn't "really" a sequel. This is the result of somewhat muddled thinking on my part, which I'll get into in a sec.</li>
</ul>
<p>I think what ultimately bothers me about when a sequel isn't "really" in continuity is, we don't have a convenient way to distinguish between "An installment in an ongoing series with an overarching plan" and "A story that notionally takes place 'after' another, completed story".
This might not be a distinction that can be meaningfully drawn, necessarily.
I think it's possible for a piece of media to end up on a continuum between these, like newspaper comics that combine ongoing arcs and no plan whatsoever to end.
Furthermore, we probably want "installments in ongoing series" to <em>also</em> be "stories in their own right", if they're long enough compared to the time between installments.</p>
<p>I guess my issue with stuff like horror movie sequels is that "something in the same continuity" doesn't seem to be the best way to deliver a similar <em>experience</em> to the original, and most of the horror movie sequels I've seen don't really fit into the established continuity.
On the opposite extreme, stuff like trying to turn Halloween into an anthology... eesh.
I think what I'd prefer to see is something like Osamu Tezuka's "star system" applied to a franchise.
Basically, paratextually acknowledging that the characters in a story aren't going to act in a way that's totally consistent with their past appearances, but drawing roles, motifs, etc from those past appearances.</p>
<p>I think I haven't developed this to my satisfaction yet.
I don't have a good sense for applying this outside of, say, horror movies, where sequels are mostly bound to bring in unwitting victims from somewhere, or else just give everyone amnesia about stuff that should really be world-changing.
It maybe gets into "what do we mean by a sequel?" in various contexts.
Like, a "sequel" to a "work" is "more of" some aspect of the work, but it's not more of every aspect, because otherwise it would just be the original work.
So, if it's "more of" one aspect of the work, which aspect is that?
If someone is giving thought to the matter, it is whichever aspect they deem most important to the work's identity.
This could be thematic elements, characters, situations, probably more things.
My feeling is that the default assumption is that a sequel should be focused on constructing a direct continuation of the sequence of events in the original.
If this wasn't in some way the intent in the first place, things get awkward.</p>
<p>I don't think I've developed that to my satisfaction still, but I'm done for now.
Instead of more of that, I just tried to put together a quick command-line interpreter for driving the rpg functions I've been writing.
It is nice how quickly I can put together a basic interface using the <tt class="docutils literal">cmd</tt> module, and with just a bit more effort, I can put together the one bit of tab-completion that makes sense for this application.
Aesthetically, I'd prefer to work with something that doesn't use classes the way <tt class="docutils literal">cmd</tt> does, but something something purity something practicality something something.</p>
<p>Things seem to be going a little better for me.
Maybe work is doing better, maybe it's the increased levels of sunlight.
I don't know, but I hope it continues.
Here's hoping I get more on track still.
Good night.</p>
Draw a Box 2019-02-282019-02-28T05:00:00-05:002019-02-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-28:/draw-a-box-2019-02-28<p class="first last">I vaguely remember these exercises.</p>
<p>In this post:</p>
<ul class="simple">
<li>Not much, because I'm backsliding a bit on time management.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>Some funnels on February 22. These came out really rough, but the page looks filled enough, so I guess I'll move on.</li>
<li>Some plotted two point perspective on February 25.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will hopefully be better.</p>
Diary 2019-02-272019-02-27T05:00:00-05:002019-02-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-27:/diary-2019-02-27<p class="first last">If anything about this is a game of margins, then this post definitely loses. Heyo!</p>
<p>Before anything else, here is some code that I refuse to work with in any remotely professional capacity.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span>
<span class="normal">74</span>
<span class="normal">75</span>
<span class="normal">76</span>
<span class="normal">77</span>
<span class="normal">78</span>
<span class="normal">79</span>
<span class="normal">80</span></pre></div></td><td class="code"><div><pre><span></span><span class="kn">import</span> <span class="nn">inspect</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="k">class</span> <span class="nc">TailCall</span><span class="p">(</span><span class="ne">BaseException</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">function</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">,</span> <span class="n">exits</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">function</span> <span class="o">=</span> <span class="n">function</span>
<span class="bp">self</span><span class="o">.</span><span class="n">args</span> <span class="o">=</span> <span class="n">args</span>
<span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span> <span class="o">=</span> <span class="n">kwargs</span>
<span class="bp">self</span><span class="o">.</span><span class="n">exits</span> <span class="o">=</span> <span class="n">exits</span>
<span class="k">def</span> <span class="nf">process_exits</span><span class="p">(</span><span class="n">exits</span><span class="p">,</span> <span class="n">exc_type</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">exc_value</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">traceback</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="k">for</span> <span class="n">exit_group</span> <span class="ow">in</span> <span class="nb">reversed</span><span class="p">(</span><span class="n">exits</span><span class="p">):</span>
<span class="k">for</span> <span class="n">exit</span> <span class="ow">in</span> <span class="n">exit_group</span><span class="p">:</span>
<span class="k">if</span> <span class="n">exit</span><span class="p">(</span><span class="n">exc_type</span><span class="p">,</span> <span class="n">exc_value</span><span class="p">,</span> <span class="n">traceback</span><span class="p">):</span>
<span class="n">exc_type</span> <span class="o">=</span> <span class="n">exc_value</span> <span class="o">=</span> <span class="n">traceback</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">return</span> <span class="n">exc_type</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
<span class="k">class</span> <span class="nc">tail_call</span><span class="p">:</span>
<span class="n">__thing</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">thing</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_thing</span> <span class="o">=</span> <span class="n">thing</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">_thing</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">__thing</span>
<span class="nd">@_thing</span><span class="o">.</span><span class="n">setter</span>
<span class="k">def</span> <span class="nf">_thing</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__thing</span> <span class="o">=</span> <span class="n">value</span>
<span class="bp">self</span><span class="o">.</span><span class="vm">__doc__</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="vm">__doc__</span>
<span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">instance</span><span class="p">,</span> <span class="n">owner</span><span class="p">):</span>
<span class="k">return</span> <span class="n">tail_call</span><span class="p">(</span>
<span class="n">inspect</span><span class="o">.</span><span class="n">getattr_static</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_thing</span><span class="p">,</span> <span class="s2">"__get__"</span><span class="p">)(</span><span class="bp">self</span><span class="o">.</span><span class="n">_thing</span><span class="p">,</span> <span class="n">instance</span><span class="p">,</span> <span class="n">owner</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="n">frame</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">_getframe</span><span class="p">()</span>
<span class="n">function</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_thing</span>
<span class="k">if</span> <span class="p">(</span>
<span class="n">frame</span><span class="o">.</span><span class="n">f_back</span>
<span class="ow">and</span> <span class="n">frame</span><span class="o">.</span><span class="n">f_back</span><span class="o">.</span><span class="n">f_back</span>
<span class="ow">and</span> <span class="n">frame</span><span class="o">.</span><span class="n">f_back</span><span class="o">.</span><span class="n">f_back</span><span class="o">.</span><span class="n">f_code</span> <span class="o">==</span> <span class="n">frame</span><span class="o">.</span><span class="n">f_code</span>
<span class="p">):</span>
<span class="k">raise</span> <span class="n">TailCall</span><span class="p">(</span><span class="n">function</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">,</span> <span class="p">[])</span>
<span class="n">exits</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">raised</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">function</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">except</span> <span class="n">TailCall</span> <span class="k">as</span> <span class="n">tc</span><span class="p">:</span>
<span class="n">function</span> <span class="o">=</span> <span class="n">tc</span><span class="o">.</span><span class="n">function</span>
<span class="n">args</span> <span class="o">=</span> <span class="n">tc</span><span class="o">.</span><span class="n">args</span>
<span class="n">kwargs</span> <span class="o">=</span> <span class="n">tc</span><span class="o">.</span><span class="n">kwargs</span>
<span class="n">exits</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">tc</span><span class="o">.</span><span class="n">exits</span><span class="p">)</span>
<span class="k">except</span><span class="p">:</span>
<span class="n">raised</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">if</span> <span class="n">process_exits</span><span class="p">(</span><span class="n">exits</span><span class="p">,</span> <span class="o">*</span><span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">()):</span>
<span class="k">raise</span>
<span class="k">finally</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">raised</span><span class="p">:</span>
<span class="n">process_exits</span><span class="p">(</span><span class="n">exits</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_thing</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">def</span> <span class="fm">__enter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_thing</span><span class="o">.</span><span class="fm">__enter__</span><span class="p">()</span>
<span class="k">def</span> <span class="fm">__exit__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">exc_type</span><span class="p">,</span> <span class="n">exc_value</span><span class="p">,</span> <span class="n">traceback</span><span class="p">):</span>
<span class="n">exit_func</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_thing</span><span class="o">.</span><span class="fm">__exit__</span>
<span class="k">if</span> <span class="n">exc_type</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">TailCall</span><span class="p">:</span>
<span class="k">return</span> <span class="n">exit_func</span><span class="p">(</span><span class="n">exc_type</span><span class="p">,</span> <span class="n">exc_value</span><span class="p">,</span> <span class="n">traceback</span><span class="p">)</span>
<span class="n">exc_value</span><span class="o">.</span><span class="n">exits</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">exit_func</span><span class="p">)</span>
</pre></div></td></tr></table></div>
<p>Anyway, I'm going to try to go into a little more detail on the dice-rolling stuff.
It might be useful to people rolling their own.</p>
<p>First off, one of the most important things to me in writing code to simulate die rolls, is making sure the rolls are handled transparently.
While it's possible to consider simple rolls in terms of binomial distributions, turning rolls for a tabletop game into a black box doesn't really serve any purpose.
My feeling on this is, we want to have as easy of a time as possible checking the logic; ideally, the roller should surface all of the information required to replicate the results by hand, given the random inputs used.</p>
<p>My next priority was presenting this information in a way that makes sense.
To this end, I've got an object that effectively allows the construction of two parallel narratives.
The first details what was rolled, and for what purpose.
The second distills and interprets the results into high-level descriptions.
Let's use the current maneuver roller:</p>
<blockquote>
<pre class="doctest-block">
>>> rolls.maneuver(10) # Don't know if you can do this in normal play.
Rolling a maneuver die.
Rolled 3.
Rolling a maneuver die.
Rolled 3.
Rolling a maneuver die.
Rolled 2.
Rolling a maneuver die.
Rolled 2.
Rolling a maneuver die.
Rolled 5.
Rolling a maneuver die.
Rolled 6.
Rolling a maneuver die.
Rolled 6.
Rolling a maneuver die.
Rolled 5.
Rolling a maneuver die.
Rolled 3.
Rolling a maneuver die.
Rolled 6.
--------------------------------------------------------------------------------
Strike dice: 5.
Charge dice: 3.
Failed dice: 2.
Earned an Awesome Token.
</pre>
</blockquote>
<p>There are several aspects to this:</p>
<ul class="simple">
<li>The initial call</li>
<li>The die roll reports.</li>
<li>A bunch of dashes to separate the areas.</li>
<li>The high-level report, which turns (in this case) twenty lines of rolling into 4 (usually 3 for lower numbers of dice) lines of results.</li>
</ul>
<p>I'm going to try to wrap things up this week, but I'm right now thinking about writing an interface using the <tt class="docutils literal">cmd</tt> module to simplify things.
The big thing I'd add over the existing functionality is a top-level command for rolling arbitrary-sized dice, for how Mythic wants you to choose randomly out of lists sometimes.</p>
<p>I'll try to get that put together, and then show off the code later.
I promise it's less horrifying than the stuff up top.</p>
<p>(The joke in the summary is that the monospaced text is going way off to the right because it is long and cannot wrap.)</p>
Weekly Roundup 2019-02-262019-02-26T05:00:00-05:002019-02-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-26:/weekly-roundup-2019-02-26<p class="first last">It'd be nice to have a quiet week where work makes sense.</p>
<ul class="simple">
<li>Wednesday: I thought about RPGs, and jury duty.</li>
<li>Draw a Box: I drew ellipses in boxes</li>
<li>Friday: I mentioned having a good experience regarding another RPG, and continued to plan. Also, I complained vaguely about work.</li>
<li>Saturday: I spent much of the day indexing character options from different sourcebooks. Then thought about how best to adapt my wife's setting to Anima Prime.</li>
<li>Sunday: I wrote functions to simulate the odds and random event rolls from Mythic.</li>
<li>Monday: I wrote functions to simulate the maneuver and strike rolls from Anima Prime.</li>
</ul>
<p>Next week, I'm going to try to maybe get a campaign rolling.</p>
Diary 2019-02-252019-02-25T05:00:00-05:002019-02-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-25:/diary-2019-02-25<p class="first last">We kept on <em>doing stuff</em> this weekend, that wasn't blogging. What's up with that?</p>
<p>Slightly more in-depth info on the rolls stuff:</p>
<p>It looks like all of the edge cases work for the fate chart rolls for Mythic, which surprised me a little.
I'm going to have to come up with tests for this stuff.
I also wrote functions for the Anima Prime rolls, which was simple, given that all of the complexity is in resource management, and so far as actual rolls, there are, like, one and a half kinds of rolls in Anima Prime.
Then I tried to make the outputs look nicer; I'll need to actually use these some before I'm sure I did that right, but it's too late tonight for me to focus on that.
I also feel like it should be possible to take the print calls out of this code and turn it into some kind of message-building thing, but, again, it's late.</p>
<p>...</p>
<p>Me fifteen minutes ago, a fool: "I'm not going to do this now. I have restraint."</p>
<p>Me now: "I had better get ready for bed <em>right now</em>, because I did the thing I said I wasn't going to do."</p>
<p>I'll try to write some tests for this later so I'm sure it all works, then think about showing it off.</p>
<p>Good night.</p>
Diary 2019-02-242019-02-24T05:00:00-05:002019-02-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-24:/diary-2019-02-24<p class="first last">Wow I'm tired</p>
<p>Earlier today, I coded up simulators for the ten-sided and percentile dice stuff for Mythic.
I haven't decided how I want to package this up.
Kind of have to work out what flow we go for in terms of managing dice and character sheets, etc.</p>
<p>I didn't get much else done on the kind of stuff I blog about, because we went out for a while, and got back late, and we're really tired.</p>
<p>I have nothing else to write for now.
Good night.</p>
Diary 2019-02-232019-02-23T05:00:00-05:002019-02-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-23:/diary-2019-02-23<p class="first last">Maybe I can write some fanfiction with this stuff, I don't know.</p>
<p>Got distracted with more organizing rulebooks that I'm probably not going to use in the near future.
I'm going to assume this is therapeutic and keep on doing it.</p>
<p>In "more immediately usable news", I'm not feeling qualified to write up my wife's setting (which is reasonable), so I'm going to see if she's up for comparing it with the default Anima Prime setting and figuring out changes, adaptations, and writeups.
I think maybe what's needed here is physical copies of all of these books, and maybe that means getting a printer that doesn't arbitrarily scrunch and stretch lines of text.
Maybe just getting them away from a backlit screen would help.</p>
<p>Well, that's that.
It's late, better wrap up now rather than later.</p>
Diary 2019-02-222019-02-22T05:00:00-05:002019-02-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-22:/diary-2019-02-22<p class="first last">(Screams into the kanban board)</p>
<p>Before anything else, I'd like to thank the customer support at Monte Cook Games.
I sent in a reasonable request that was in response to unreasonable circumstances of my own making, and they were like "Yeah, that makes sense." and resolved everything to our satisfaction.
Good job.</p>
<p>Anyway, it's hella rough dealing with work.
I wish I could be setting priorities more; I feel like it would be more tolerable if I could just focus my energies where they'd be most effective; it feels like that's not what's happening.</p>
<p>Anyway, still working on RPG stuff, slowly.
My intention is to design an Anima Prime setting based on a concept my wife came up with recently, and strap the Mythic GME to it, so we can both play.
I'll try to make some proper progress on that this weekend.</p>
<p>Well, I'm writing slowly, so I'm not going to get much more written down at this rate.
Hope things turn out more prolific tomorrow.
Good night.</p>
Draw a Box 2019-02-212019-02-21T05:00:00-05:002019-02-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-21:/draw-a-box-2019-02-21<p class="first last">Eh.</p>
<p>In this post:</p>
<ul class="simple">
<li>Only a few days, due to a combination of in-hindsight unreasonable dread, and wanting to make sure I was up in time to get to jury duty.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>Finally did ellipses in planes on February 18. Got one page done. I was kind of dreading this, but either I wasn't engaging my shoulder (boo!) or it's toughened up a bit following the gridded ellipses (yay!).</li>
<li>I did the other page of ellipses in planes on February 20. These definitely need more practice, but I'll move on for now.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will hopefully have more going on.</p>
Diary 2019-02-202019-02-20T05:00:00-05:002019-02-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-20:/diary-2019-02-20<p class="first last">Tomorrow morning is going to suck.</p>
<p>I've got jury duty in the morning, so I'm going to try to wrap things up a little earlier.
I'm doing prep work for the rpg stuff I mentioned.
Said prep work basically amounts to making sure I have a decent grasp on all of the relevant rules, cross-referenced between three (and a half?) books.</p>
<p>I think what I need to make this work is to come up with a setting sketch, out to the level of some sample enemies, and working out the skills and powers we'll have.
After that, I want to have some kind of flowchart or something for synthesizing all of the rules into some gameplay loops, examples of the various kinds of things we'll want to note down, and probably tooling for handling a bunch of the rolls.
I'm fairly sure we don't have percentile dice handy.</p>
<p>Anyway, I'd better sleep so I can get up so I can get over there so I can probably not be selected.</p>
Weekly Roundup 2019-02-192019-02-19T05:00:00-05:002019-02-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-19:/weekly-roundup-2019-02-19<p class="first last">Maybe I should come up with Silly Code Things to do regularly, to break up the harder stuff.</p>
<ul class="simple">
<li>Wednesday: I mentioned some writing I've been thinking of doing, and pondered the shortcomings I was noticing in my approach.</li>
<li>Draw a Box: I drew ellipses. Now that I'm drawing them right for the first time, it hurt.</li>
<li>Friday: A quick entry on account of doing Silly Code Things all day.</li>
<li>Saturday: An explanation of the Silly Code Things, then a conclusion that I didn't have anything in mind for them, so there probably isn't much point. I did some other Code Things, like GUI framework tutorials.</li>
<li>Sunday: Grumbling about some GUI frameworks. And my decisions about how to spend my time.</li>
<li>Monday: I didn't think of anything to write all day, dashed out something in five minutes to have something.</li>
</ul>
<p>Next week, still need to manage stress.</p>
Diary 2019-02-182019-02-18T05:00:00-05:002019-02-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-18:/diary-2019-02-18<p class="first last">Extremely quick post</p>
<p>Took it easy for most of today, not much time to post.</p>
<p>I've been spending a lot of time lately researching tabletop RPG systems, looking for something that my wife and I can play together, just the two of us, because we don't want to even try to coordinate a larger group of people.
I've got an idea, but I'll have to run it by her.
If she goes for it, maybe I'll write something up.</p>
<p>I think I'm feeling a bit less stressed, but there's still a few things I need to take the time to just go and do.</p>
<p>Anyway, that's a few minutes of writing, before a night of sleeping.
Here's hoping for something more substantial in the week to come.</p>
Diary 2019-02-172019-02-17T05:00:00-05:002019-02-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-17:/diary-2019-02-17<p class="first last">I get interested in organization under very specific circumstances.</p>
<p>Oops, I botched yesterday's post.
It's up now, as in, now, when this goes up.</p>
<p>Anyway, another quiet day on the weekend.
I messed around with some learning to code stuff, exercises and tutorials.
I'm kind of leaning towards, if I want to do any text-heavy game stuff, doing it in the browser, because I feel like there I can sort of trust it to handle stuff that is admittedly, <em>in terms of the stuff I'll probably do</em>, an edge case, but is commonly encountered by other people.
Like text rendering at all more complicated than English.
Like, if I think to check that Arabic text renders sensibly, and it doesn't, that bothers me.</p>
<p>I also got distracted indexing character creation stuff for an RPG that has options spread over nine or ten books.
Am I ever going to make use of this index? ... No comment.</p>
<p>Anyway, I let things go late, so I'd better wrap up.
Good night.</p>
Diary 2019-02-162019-02-16T05:00:00-05:002019-02-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-16:/diary-2019-02-16<p class="first last">Explaining continuation passing style: an attempt was made.</p>
<p>Okay, yesterday I mentioned continuation passing style, and now I have some more time to try to explain it.</p>
<p>One way to think about continuations is, first, consider the "return" statement.
There is some sense in which we can imagine "returning" to be calling a function that never returns.
The function in question is "whatever the program does next", and is determined by the caller.</p>
<p>The next step is to go and write functions that actually work like that.
For what I'm doing, I wrote functions that don't mutate their inputs, and take other functions like themselves as arguments, as well as utility functions that create such functions from constant values.
These results of these functions then take a continuation as an argument and elaborate on it in various ways.
This is very hard to talk about completely abstractly, so have some code snippets:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span></pre></div></td><td class="code"><div><pre><span></span><span class="kd">local</span> <span class="kr">function</span> <span class="nf">k</span><span class="p">(</span><span class="n">const</span><span class="p">)</span>
<span class="kr">return</span> <span class="kr">function</span><span class="p">(</span><span class="n">ret</span><span class="p">)</span>
<span class="kr">return</span> <span class="n">ret</span><span class="p">(</span><span class="n">const</span><span class="p">)</span>
<span class="kr">end</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="kr">function</span> <span class="nf">binop</span><span class="p">(</span><span class="n">op</span><span class="p">)</span>
<span class="kr">return</span> <span class="kr">function</span> <span class="p">(</span><span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">)</span>
<span class="kr">return</span> <span class="kr">function</span><span class="p">(</span><span class="n">ret</span><span class="p">)</span>
<span class="kr">return</span> <span class="n">left</span><span class="p">(</span>
<span class="kr">function</span><span class="p">(</span><span class="n">r_left</span><span class="p">)</span>
<span class="kr">return</span> <span class="n">right</span><span class="p">(</span>
<span class="kr">function</span><span class="p">(</span><span class="n">r_right</span><span class="p">)</span>
<span class="kr">return</span> <span class="n">ret</span><span class="p">(</span><span class="n">op</span><span class="p">(</span><span class="n">r_left</span><span class="p">,</span> <span class="n">r_right</span><span class="p">))</span>
<span class="kr">end</span>
<span class="p">)</span>
<span class="kr">end</span>
<span class="p">)</span>
<span class="kr">end</span>
<span class="kr">end</span>
<span class="kr">end</span>
<span class="kd">local</span> <span class="n">add</span> <span class="o">=</span> <span class="n">binop</span><span class="p">(</span><span class="kr">function</span><span class="p">(</span><span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">)</span> <span class="kr">return</span> <span class="n">left</span> <span class="o">+</span> <span class="n">right</span> <span class="kr">end</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">sub</span> <span class="o">=</span> <span class="n">binop</span><span class="p">(</span><span class="kr">function</span><span class="p">(</span><span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">)</span> <span class="kr">return</span> <span class="n">left</span> <span class="o">-</span> <span class="n">right</span> <span class="kr">end</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">mul</span> <span class="o">=</span> <span class="n">binop</span><span class="p">(</span><span class="kr">function</span><span class="p">(</span><span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">)</span> <span class="kr">return</span> <span class="n">left</span> <span class="o">*</span> <span class="n">right</span> <span class="kr">end</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">div</span> <span class="o">=</span> <span class="n">binop</span><span class="p">(</span><span class="kr">function</span><span class="p">(</span><span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">)</span> <span class="kr">return</span> <span class="n">left</span> <span class="o">/</span> <span class="n">right</span> <span class="kr">end</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">eq</span> <span class="o">=</span> <span class="n">binop</span><span class="p">(</span><span class="kr">function</span><span class="p">(</span><span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">)</span> <span class="kr">return</span> <span class="n">left</span> <span class="o">==</span> <span class="n">right</span> <span class="kr">end</span><span class="p">)</span>
</pre></div></td></tr></table></div>
<p>Given an ordinary value, the function <tt class="docutils literal">k</tt> returns a function that takes a continuation, and returns the result of applying that continuation to the value.
Thus:</p>
<div class="highlight"><pre><span></span><span class="o">></span> <span class="n">cps</span> <span class="o">=</span> <span class="nb">require</span> <span class="s2">"cps"</span>
<span class="o">></span> <span class="n">cps_func</span> <span class="o">=</span> <span class="n">cps</span><span class="p">.</span><span class="n">k</span><span class="p">(</span><span class="s2">"Hello, World!"</span><span class="p">)</span>
<span class="o">></span> <span class="n">cps_func</span><span class="p">(</span><span class="nb">print</span><span class="p">)</span>
<span class="n">Hello</span><span class="p">,</span> <span class="n">World</span><span class="err">!</span>
</pre></div>
<p>The functions returned from <tt class="docutils literal">binop</tt> do a bit more.
Basically, given two functions that take a continuation, they apply <tt class="docutils literal">op</tt> to the results of those functions and pass the result of that to the continuation.
Furthermore, they're written to take advantage of Lua's tail-call optimizations, so the above logic is expressed in terms of "Given the input functions and the continuation, construct new continuations that can be passed to the input functions, in order to eventually pass the result to the original continuation".</p>
<p>I don't really have a solid motivation for implementing this stuff, as such.
I guess it's just kind of mindbending that this stuff can work at all.</p>
<p>There's more code than the stuff above, but it basically just amounts to an "if" expression, and code using the above to implement factorial.
The current implementation is based around using an accumulator, but I guess I could actually get rid of the accumulator-y stuff, since the tail-call optimizations are more baked into the libraries now.</p>
<p>Hm.
I just tried, and now I'm realizing that the time performance of this code is... confusing.
I think there might be performance cliffs or something.
Needs actual profiling.</p>
<p>One thing I want to figure out here is how best to represent state.</p>
<p>I was going to start this paragraph with the word "basically", and deleted it because it would have been a lie.
What I'm trying to figure out is how to add the idea of "this is the equivalent of a statement executing, and it will have an influence on the rest of the execution".
Have functions that when passed a continuation, do "read from this storage" or "write to this storage".
I think what those look like depend on the semantics I want to express with this stuff, which is kind of up in the air, and has no practical usage to constrain it, unfortunately.
So, I guess I'll step away from this for now, maybe try documenting it some at some point.</p>
<p>Other stuff I've been doing...
I've been trying out the tutorial for wxGlade, but the structure of the generated Python code bothers me enough (in a "if a human wrote this I wouldn't merge the PR" kind of way) that I've been sort of pondering writing my own generator based on the current one.
That's probably not a good idea before I grasp the full usage of wxLocale, though.
Because one thing that rubs me wrong is gettext.
I haven't actually used gettext or <a class="reference external" href="https://github.com/projectfluent/python-fluent">Fluent</a>, but the documentation for the former rubs me the wrong way, while the documentation for the latter doesn't.
But, I'm at least intellectually aware that I can't just say "I'm going to use the shiny new thing!" without understanding the integration with the old thing.
Maybe I end up not wanting to use wx, I don't know.
There are alternatives.</p>
<p>Anyway, that's enough of that for now.
I came up with a story idea that I want to try doing, so I'll work on that for a bit later.</p>
<p>And it's late, I'd better wrap up.
Good night.</p>
Diary 2019-02-152019-02-15T05:00:00-05:002019-02-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-15:/diary-2019-02-15<p class="first last">It's even worse than it sounds.</p>
<p>To get back into working on things, I have to follow my heart.
And today, my heart said to work on reimplementing basic flow control using CPS in Lua.</p>
<p>I'll try to give a more thorough accounting of this in the next entry.
There are some improvements I want to make to the code before I put it up, and I want to have a code sample handy besides "deeply worrying factorial implementation".</p>
<p>Sadly, I got distracted by other things, so this entry is both short and late.
I will now try to get enough sleep.
Good night.</p>
Draw a Box 2019-02-142019-02-14T05:00:00-05:002019-02-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-14:/draw-a-box-2019-02-14<p class="first last">This stuff is a lot harder when I do it as intended.</p>
<p>In this post:</p>
<ul class="simple">
<li>OW</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>The rest of the planes on February 7. These still aren't as good as I can draw with my wrist, but I think now I'm ready to take a break from these and have them in a rotation, once I start doing a rotation.</li>
<li>I ghosted some lines on February 10. I should get some grids and work on ellipses next.</li>
<li>Me several weeks ago, a fool: "People are talking about feeling sore from drawing from the shoulder, but it doesn't seem to have happened to me. Guess I got lucky somehow?" Me on February 11, after drawing 166 vaguely circular shapes from the shoulder "<strong>ow</strong>".</li>
<li>I did another sheet of ellipses on February 12. Kind of some tension right now, where I know I need to be trying to draw them quickly so I get a fluid motion, but they look kind of bad at any speed.</li>
</ul>
<hr class="docutils" />
<p>Next week, I'll change focus a little while I keep on revisiting exercises I did wrong the first time.</p>
Diary 2019-02-132019-02-13T05:00:00-05:002019-02-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-13:/diary-2019-02-13<p class="first last">Trying to take stock of my situation, whilst faintly buzzing.</p>
<p>I believe I did some more Erlang today.
Memory's a little fuzzy, and I can tell I'm feeling stressed.</p>
<p>Recently, I've been trying to come up with some crossover AU stuff between a few fandoms that Some People love to complain about.
I've come up with various Cool Things, but I'm having trouble fitting a lot of it together, and I believe one problem underlying this is a lack of theme.
Interesting character designs, but when I think about it, it currently kind of just amounts to bouncing action figures off each other inside my mind.
Maybe what I need in terms of writing is to figure out how to use themes in succinct writing, then gradually expand.</p>
<p>I'm not sure that makes sense.
I guess what I'm hoping to do is to write a bunch of rough drafts of micro-fiction, and try to figure out what works in terms of developing and conveying themes.
The idea of working with short stuff is to try to reduce the volume of text to produce and analyze for a single cycle of iteration.
Basically, I think I should be able to expend the minimum effort required to write a story, and then apply any further effort to making it shorter.</p>
<p>I'll try to get started on that kind of thing tomorrow, but if it's not in me then, it's not.
I think that's probably the way to deal with stress?
Make an honest effort at stuff, and accept whatever the outcome is?
I don't actually know.</p>
<p>Anyway, it's not incredibly late, but I'm still tired.
Good night.</p>
Weekly Roundup 2019-02-122019-02-12T05:00:00-05:002019-02-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-12:/weekly-roundup-2019-02-12<p class="first last">This was a banner weak in getting literally and metaphorically crushed.</p>
<ul class="simple">
<li>Wednesday: I recounted my foolish, foolish choice to have the hubris of thinking I could handle Boston sports victory crowds.</li>
<li>Draw a Box: I ramped back up, more or less.</li>
<li>Friday: I recounted the horrible, unpleasant results of following unambiguous directions for using Git.</li>
<li>Saturday: I thought about trying to do more ambitious things, possibly with a focus on accessibility.</li>
<li>Sunday: I mentioned that I've been doing stuff on Exercism, and also the ridiculous movie we watched.</li>
<li>Monday: Oh yeah, I wanted to mess with the PICO-8 some more.</li>
</ul>
<p>Next week, I think I should try to make sound effects, rather than music tracks, with the PICO-8.</p>
Diary 2019-02-112019-02-11T05:00:00-05:002019-02-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-11:/diary-2019-02-11<p class="first last">Another light day.</p>
<p>I just kind of hung out today.
I did some more work trying to learn Erlang.
I think so far as projects go, I'd like to revisit PICO-8 a bit, finally do the sound work, then find something else to work on.</p>
<p>I'm going to cut this off here because I made some bad time management choices, and I've got some drawing I want to do before midnight.</p>
Diary 2019-02-102019-02-10T05:00:00-05:002019-02-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-10:/diary-2019-02-10<p class="first last">It's hard to write much interesting about a day where I was mostly taking it easy. (redux)</p>
<p>Took things easy again today, did a little less.
I'm doing programming exercises on Exercism, and it's hard for me to say much about them, because I've mostly been doing the easy stuff.
I should probably ramp that up a bit.
And read more.</p>
<p>I ended up getting distracted by a game, though.</p>
<p>Also, we watched Samurai Cop, which is probably not the worst movie I've seen, but it's certainly up there in terms of confusion.
Representative reactions: "I wish I knew enough about cinematography to explain why this sequence is so confusing." and, after listening to some of the dialogue "Am I having a stroke?"
Also, I had really excellent timing when, during one of the movie's interminable sex scenes, I wondered aloud if it was going to abruptly cut to something else completely, at which point it did.
Sumarai Cop really loved abrupt, confusing cuts.</p>
<p>I'd better wrap this up, it's late.
Good night, and maybe I'll have something more substantial tomorrow.</p>
Diary 2019-02-092019-02-09T05:00:00-05:002019-02-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-09:/diary-2019-02-09<p class="first last">It's hard to write much interesting about a day where I was mostly taking it easy.</p>
<p>Things went well today.
Not much to talk about.
Read some.
Coded some.</p>
<p>I think I'd like to switch to a larger-scale project, whether that's picking back up the secret project (far less interesting than I'm making it sound), or something card-related.</p>
<p>I got inspired to try out VoiceOver today, and I ended up trying it on some truly awful webpages.
Sometime I should make sure that my blog isn't one of them.
I also wonder if it'd be good for testing out user interface designs.
What's it that I read where, that features that make something usable for people that need them, often prove helpful to people that don't?
And I think <a class="reference external" href="https://www.crummy.com/">Leonard Richardson</a>, among others, has pointed out that restrictions breed creativity.</p>
<p>Anyway, time to face the weekend head-on, by which I mean curled up in bed.</p>
Diary 2019-02-082019-02-08T05:00:00-05:002019-02-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-08:/diary-2019-02-08<p class="first last">The beginning of this post represents a brief break from attempting to be positive about the efforts of others.</p>
<p>Based on my experiences today, let me tell you a terrible joke.</p>
<p>Git.</p>
<p>A-hahaha.</p>
<p>Anyway, after spending <em>several hours</em> in a single hellish rebase, I got home, did my usual got-home things, and wrote some more Erlang.
There's really something to be said for the flexibility of the function definitions in Erlang and Prolog.</p>
<p>Anyway, I'm feeling like I'd like to get back to reading those novels I got.</p>
<p>It's late, so I'll turn in for now, and get to it tomorrow.
Good night.</p>
Draw a Box 2019-02-072019-02-07T05:00:00-05:002019-02-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-07:/draw-a-box-2019-02-07<p class="first last">Triumphant(?) return</p>
<p>In this post:</p>
<ul class="simple">
<li>A few days, and attempt to ramp up.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>Some planes on a new sheet on February 3. That was a long break, but now I'm feeling better-rested, and I feel like I was a little more observant about what was causing some of the lines to go wrong. I really should look into getting something a little more proper as a drawing surface.</li>
<li>Some more planes on February 4.</li>
<li>Some more planes on February 6. Skipped a day to recover from being crushed. Anyway, I should be done with redoing planes soon, and able to move on to redoing or at least revisiting other stuff.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be hopefully more active.</p>
Diary 2019-02-062019-02-06T05:00:00-05:002019-02-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-06:/diary-2019-02-06<p class="first last">Do not be near the Superb Owl celebrations</p>
<p>Going in to work was a mistake.
I returned from the general vicinity of the parade battered, cramped, and generally squeezed.
Also, an hour late.</p>
<p>Speaking as someone who has been to several crowded fan conventions, and been on more than a few overstuffed trains, I have <em>never</em> been packed into such a tight crowd.</p>
<p>I don't really have much else to talk about, because that was, just... ugh.</p>
<p>A little progress on the stuff I vaguely mentioned earlier, but nothing to speak of.</p>
<p>I'm going to get ready for tomorrow so I can curl up and try to feel better.
Good night.</p>
Weekly Roundup 2019-02-052019-02-05T05:00:00-05:002019-02-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-05:/weekly-roundup-2019-02-05<p class="first last">A thrilling week of taking steps to become less sleepy.</p>
<ul class="simple">
<li>Wednesday: I mentioned I was getting more sleep, and groused about weird consequences of Continuum's rules.</li>
<li>Draw a Box: I drew just a little, then started a break.</li>
<li>Friday: I started thinking about collectible card games.</li>
<li>Saturday: I started thinking about making a collectible card game, and also about the Hero's Journey.</li>
<li>Sunday: I detailed a pisstake of various attempts at a "monomyth".</li>
<li>Monday: I tried to reorient myself some, and decided to focus for now and Erlang, and existing card games.</li>
</ul>
<p>Next week, maybe I'll do some more Erlang.</p>
Diary 2019-02-042019-02-04T05:00:00-05:002019-02-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-04:/diary-2019-02-04<p class="first last">A week of determinedly taking it easy starts to pay off.</p>
<p>I feel like I'm not really hitting a coherent plan, currently, just kind of looking at what interests me.</p>
<p>I've been kind of focusing on:</p>
<ul class="simple">
<li>Making more effort to learn Erlang (I really should have been working alongside the book; my grasp on syntax is Pretty Bad, currently.)</li>
<li>Looking at comprehensive specifications for existing products and going "Hm, I bet I could implement this specification, then figure out how to generalize it". I might try to find, like, two more related but distinct specifications, and try to implement them in terms of common functionality and specializations for each one.</li>
</ul>
<p>Other than that ridiculously huge idea for an undertaking (the specification I'm looking at right now is 700 kb of plaintext), I should also get back into reading sometime.
Thinking over the situation at work, I'll try to avoid ramping up too hard until we get to pull other teams into the current project and do more interesting things.</p>
<p>I should make sure to keep getting enough sleep, though, and as part of that...
Good night.</p>
Diary 2019-02-032019-02-03T05:00:00-05:002019-02-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-03:/diary-2019-02-03<p class="first last">Spoilers, I guess</p>
<p>Okay, I made a vague statement yesterday about the only "legit" monomyth.
At some point after playing Bayonetta and watching Kill la Kill, my wife and I noticed:</p>
<ul class="simple">
<li>Character with black and red color scheme</li>
<li>Unaware at first of the broader conflict they figure into, operating for selfish or short-sighted reasons</li>
<li>A hybrid of different strains, one benevolent, one malevolent</li>
<li>Inspired to do right by a dead relative, pushed to do wrong by a living relative</li>
<li>Opposed by a character with a blue and/or white color scheme</li>
<li>By remembering more of their hidden past, they discover their duty, and hidden reserves of power</li>
<li>This involves fighting a hybrid similar to themselves</li>
<li>In space for some reason</li>
<li>After which they fall back into the atmosphere, like, straight down</li>
</ul>
<p>We call this the "Sonic Adventure 2 monomyth", after Shadow's character arc.
Except for the end of this, this also applies to Zuko from Avatar.</p>
<p>The whole joke here is that this seems like a superficially compelling mixture of specifics and broad ideas, that all apply to several unrelated stories, but (hopefully) nobody would try to teach this as an actual guide to storytelling.</p>
<p>I think there are, though, some instructive things to be gleaned from the details and nuance that have to be sanded off to fit into the given mold.</p>
<ul class="simple">
<li>Zuko wants honor, Shadow wants to avenge Maria, Ryūko wants to avenge her father, and Bayonetta is mostly focused on killing angels, but also wants to uncover the mystery of the Eyes of the World.</li>
<li>Zuko is the child of two different (human) families, Shadow is an artificial hybrid, Ryūko is (<abbr title="if I recall correctly">IIRC</abbr>) a human augmented with alien biology, and Bayonetta is a child of members of two different orders of magic users.</li>
<li>Zuko is inspired by his mother (and also his uncle, who is alive), and pushed by his father and sister, Shadow is inspired by Maria and pushed by Dr. Eggman (who are cousins, the grandchildren of his (human) creator), Ryūko is inspired by her father and pushed by her mother, and Bayonetta is inspired by her mother and pushed by her father.</li>
<li>Azula has blue fire, and no particular association with white; Jeanne has white hair and no particular association with blue. Further, Azula is a villain, Sonic is a hero, Satsuki is a hero disguised as a villain, and Jeanne is a hero brainwashed into being a villain (... I think)</li>
<li>Zuko fought his sister, Shadow fought his prototype, Ryūko fought her mother, and Bayonetta fought an angry god summoned by her magic combined with her father's.</li>
<li>So far as I know, Zuko has never been to space.</li>
</ul>
<p>In the end, the list above ends up as a mix of character design elements, gradually opening-up storytelling, common character concepts, straightforward character dynamics, and <a class="reference external" href="https://www.youtube.com/watch?v=BVn1oQL9sWg">SPAAaaaAAAaaaCE</a>.</p>
<p>None of this should be mistaken for a fair, reasoned critique of The Hero with a Thousand Faces, but I do think it's suggestive that I can put together something that very superficially resembles the form of the hero's journey, yet is obvious bs.
That does seem to indicate to me that focusing purely on form doesn't provide any ability to judge quality.</p>
<p>But yeah, there is some documentation of one of our dumb inside jokes.</p>
Diary 2019-02-022019-02-02T05:00:00-05:002019-02-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-02:/diary-2019-02-02<p class="first last">Vague attempt at a teaser.</p>
<p>Cards.
Cards cards cards.
Feeling like making a card game.
I could try to put something together command-line-wise.
Or try to learn how to use Unreal Engine with the stuff I just grabbed on their asset store.
Or see how much stuff I can shove into Ink logic.</p>
<p>Something else on my mind recently...
I was never into Kingdom Hearts directly, but all the noise around the release got me watching explainer videos, like the Polygon one that tried to explain things in terms of (ideas vaguely inspired by) the Hero's Journey.
I refreshed my memory on this stuff some, and mostly found out that nobody can agree on how many fundamental narrative building blocks there are.
And that trying to follow some of these outlines would probably make people think you were specifically referencing the Odyssey.
I brought this kind of thing up with my wife, and I was all "Well, I mean, we both know that there's only one legit monomyth..."
And it's getting late, so I'll have to explain the inside joke another time.</p>
Diary 2019-02-012019-02-01T05:00:00-05:002019-02-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-02-01:/diary-2019-02-01<p class="first last">The continuing adventures of: The Man Who Slept Too Little</p>
<p>Well, I'm working my way back to getting to be fully conscious, still.</p>
<p>As of today, I seem to be feeling the urge to play a collectible card game in the abstract, but no clear idea of which concrete game I would like to play.
I'll figure something out, I guess.
I'm going to take this as a sign that I'm getting some focus back, because I kind of didn't feel like doing much of anything when I was feeling this on Monday.</p>
<p>Still, no reason to get cocky.
It's almost midnight, better wrap up for now.
Good night.</p>
Draw a Box 2019-01-312019-01-31T05:00:00-05:002019-01-31T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-31:/draw-a-box-2019-01-31<p class="first last">This post is short, don't bother.</p>
<p>In this post:</p>
<ul class="simple">
<li>I focused on sleep instead of drawing, because I've got to pay off that sleep debt.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>Some more planes on January 24. These might be getting better or more consistent, I'm not sure.</li>
<li>Some more planes on January 25.</li>
</ul>
<hr class="docutils" />
<p>Next week, maybe I'll start back up? Maybe?</p>
Diary 2019-01-302019-01-30T05:00:00-05:002019-01-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-30:/diary-2019-01-30<p class="first last">Relaxing things: sleep, and flowcharts from hand-written dot files, apparently.</p>
<p>Sleep update: slept earlier, somewhat better rested.
I'm definitely not all better all at once, so I'll have to keep at this.</p>
<p>Besides working on my sleep habits, I also got some of Continuum's rules formalized into a flowchart.
There were some ambiguities that I had to make a judgment call on, or consult third-party clarifications in the Internet Archive (!!!).
Some things, I'm still not sure about.
Like, in a competitive action, suppose P1 is at N4 and rolls a 2, for a total roll of 2.
P2 is at A5 and rolls a 4, for a total of 1.
At this stage, P1 should beat P2.
But suppose we counterfactually add in P3, at J6, who rolls a 6, for a total roll of 0.
Adding a superior contestant with a worse roll causes the competion to favor, instead of P1... P2.
Time travel really is confusing.
Now, it's possible, maybe likely, that I'm coming to this conclusion as a result of a flawed reading of the rules, but I'm not exactly sure where I went wrong, if so.</p>
<p>If I had to house-rule this, I'd say that the superiority-style rules... no, I thought I had something, but there are always weird counterfactuals, I think.
My intuitive desires are that adding characters should not function as a kingmaker, and that something like the superiority rules remain intact, and I'm doubtful it's possible to have both at once, and the former is harder.</p>
<p>Another way to look at the problem is, in the above counterfactual, the individual matchups aren't transitive.
So there's no way to combine the matchups without reversing one or two of them.
For now, I choose to just not worry about this.</p>
<p>For now, I'd better wrap up, and work on the highest priority: resting.
Good night.</p>
Weekly Roundup 2019-01-292019-01-29T05:00:00-05:002019-01-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-29:/weekly-roundup-2019-01-29<p class="first last">I'm not any happier than anyone else with how focused these entries are on my mounting sleep debt.</p>
<ul class="simple">
<li>Wednesday: I started trying to take it easy.</li>
<li>Draw a Box: I drew only a few days, because I hadn't been taking it easy enough.</li>
<li>Friday: I continued trying to take it easy.</li>
<li>Saturday: I hadn't taken it easy.</li>
<li>Sunday: It looks like I took it easy a little?</li>
<li>Monday: I realized that I need to put more effort into taking it easy.</li>
</ul>
<p>Next week, I'm going to make a point of getting to bed earlier, so I can work on digging myself out of a sleep-deprivation hole.
Might just make the entries entirely about how well I feel like I'm doing at sleeping.</p>
Diary 2019-01-282019-01-28T05:00:00-05:002019-01-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-28:/diary-2019-01-28<p class="first last">I should actually plan to take things easy...</p>
<p>Instead of thinking I'm going to have an entry, and just not writing much, I'm going to resign myself to just doing basic diary entries for a bit, and try to take it easy.</p>
<p>Today, I started messing with two things.
One was taking a Python codebase that's been unmaintained since I was in high school, and trying to get it to, um, work.
Highlights include that fact that it exists entirely within a single file, and is thousands of lines long.
Other fun things include tab-based indentation, and seemingly random globals declarations; I've weeded out the uneccesary ones, but I'm not sure about the ones that are missing.
I haven't gotten around yet to the fact that WxPython has changed rather significantly since this code was last updated, and that's its own thing to deal with.
The other thing is attempting to write up the rules for Continuum in a way that makes a little more sense to me.
I've got a suspicion that it can be made to flow a little more linearly.</p>
<p>I don't know that I'll end up with anything to really discuss about either of these.</p>
<p>For now, though, I should be focusing on getting to bed earlier, and hopefully that'll eventually pay dividends in terms of accomplishing things.
Good night.</p>
Diary 2019-01-272019-01-27T05:00:00-05:002019-01-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-27:/diary-2019-01-27<p class="first last">Lean pickings again.</p>
<p>Today I mostly focused on the secret project, which, like, it's a secret, so that's a non-starter.</p>
<p>I've also been looking into and back over some role-playing games.
I've got the vague suspicion it's somehow possible to fuse a few dramatically different games into a ball of hilarious nonsense.
I also kind of want to try to turn some of these rulebooks into wikis so I'm not doing page number math and flipping back and forth, but I remember how weird things got the last time I tried to do that, and I'm still not totally sure what was actually happening there.
Probably if I want to do something like that, I should build it like one of the various SRD sites, and author it somewhat normally as compared to using TiddlyWiki, which seems to interact weirdly with a lot of things, last I checked, which was a while ago.</p>
<p>I guess what I'm trying to figure out is RPGs about time travel, specifically, and is it possible to represent the rules for them in an accessible fashion?
The Continuum pdfs aren't accessible out of the box because there's no obvious organizational aids, and the actual books aren't accessible because they require a lot of money in order to be accessed.
I'm wondering if it's possible to make something inspired by PbtA games or some other system; I don't really have a strong basis for choosing an inspiration.</p>
<p>I guess that's what I'm thinking about besides the secret project which is secret.</p>
Diary 2019-01-262019-01-26T05:00:00-05:002019-01-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-26:/diary-2019-01-26<p class="first last">Ugh</p>
<p>What even have these last few days been?
I'm so tired, and I haven't done anything today that I can write up, and I don't intend to in the next half hour or so.</p>
<p>I just want to not be tired...</p>
Diary 2019-01-252019-01-25T05:00:00-05:002019-01-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-25:/diary-2019-01-25<p class="first last">I'd like to be writing longer entries, but it's not in the cards, apparently.</p>
<p>I was just flat-out tired yesterday and today.
Falling asleep watching videos on the couch.
Not a great state to be in if one has an eye towards <em>accomplishing things</em>.</p>
<p>I was going to try to get this entry done quickly and get to sleep early, but I guess it's ended up short even though I'm up later than I want to be.
I'm going to have to figure out how to take things easy, I guess.</p>
<p>Good night.</p>
Draw a Box 2019-01-242019-01-24T05:00:00-05:002019-01-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-24:/draw-a-box-2019-01-24<p class="first last">This is a short one.</p>
<p>In this post:</p>
<ul class="simple">
<li>Some missed days due to bad time management, followed by a missed day for being <em>incredibly</em> sleepy.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>I drew some more planes on January 18. I <em>think</em> I was drawing these faster than last time, so that's a good sign. Hard for me to tell if anything is happening with the quality. For fun, I tried to come up with logo/signature stuff.</li>
<li>I drew some more planes on January 20, kind of late. Then I scribbled... stuff, after. One part was the logo I was messing with earlier; I think I'm liking it.</li>
<li>I drew some more planes on January 22. I think I want to switch back to ghosting lines for a bit, because the line quality seems really hit and miss for this one. Afterwards, I sketched out some base schematics for when I get back into Equivalent Skies.</li>
</ul>
<hr class="docutils" />
<p>Next week, I have no idea.</p>
Diary 2019-01-232019-01-23T05:00:00-05:002019-01-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-23:/diary-2019-01-23<p class="first last">Going outside was a mistake.</p>
<p>So far, I've spent a lot of this week on a secret project.
Sometimes, I see people talking about secret projects in the context of, they will release more detail, but that's not the plan here.
This paragraph constitutes everything I intend to make public about the project through this blog.</p>
<p>Aside from that, I'm taking it easy for now.
I don't want to stress myself out by feeling obligated to fit these various projects into a day, always, though it'd be nice if I could do it more regularly.</p>
<p>It snowed a few days ago, and the front steps of the house are a horrible adventure to navigate.
I basically need to hold various things in a deathgrip, and use that to stabilize myself, because so much of the area is covered in curved, sloping ice.</p>
<p>Well, that's it for today I guess, I'm super tired and bad at writing.
Good night.</p>
Weekly Roundup 2019-01-222019-01-22T05:00:00-05:002019-01-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-22:/weekly-roundup-2019-01-22<p class="first last">A weird mix of exhilarating and deeply frustrating.</p>
<ul class="simple">
<li>Wednesday: I made some vital progress on transcribing to PICO-8.</li>
<li>Draw a Box: Haha, turns out I hadn't noticed important things, and was teaching myself wrong. Need to review the basics, but right.</li>
<li>Friday: I got the notes of Stronger Than You, but not the volume or instrumentation.</li>
<li>Saturday: Miscellaneous stuff.</li>
<li>Sunday: VIDYA</li>
<li>Monday: MORE VIDYA</li>
</ul>
<p>Next week, I'm going to try throwing myself at whatever I feel like working on, and using some of the energy from that to work out better time management.</p>
Diary 2019-01-212019-01-21T05:00:00-05:002019-01-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-21:/diary-2019-01-21<p class="first last">This was a very disorganized day.</p>
<p>Another day, another series of time-management blunders.
(Also, I don't think I've previously run into the weirdness I just hit renaming a copied entry from the twentieth. How was <em>that</em> never a problem before?)</p>
<p>I decided to try adapting something shorter and more tractable to the PICO-8, so I've started transcribing the prelude to Sburb.
Because it's shorter than Stronger Than You, I'm doing strict one-measure-per-track until that bites me somehow, and because it was originally arranged for piano in the first place, I'm using the "organ" instrument.
This works for the chords, but I might want to switch to another instrument for the stuff that is not chords.</p>
<p>(I'll also probably end up hopelessly confused if I try to jump into transcribing the rest of Sburb, so I won't, for now.)</p>
<p>Played a bunch more Equivalent Skies.
I'm getting to empowerer crafting soon, which means I'm going to need to work out a better base build than "single massive floor, level with spawn".
Since Thaumcraft is telling me to go up, I'll probably try to build a tower opposite the mob farm, and relocate machines into it.
Probably want to base the design around a storage system.
Years ago now, I once tried to design a build around a kind of distributed spire, in which each mod I was working with had a "quadrant" to work with, and they connected up through either four or eight columns that went through the inner corner of each quadrant, with some kind of pavement between the quadrants to speed up travel.
It might be interesting to revisit that.
But I want to take a few days off, then try and set this stuff up.
Hm.
The pack just updated.
I might start fresh next weekend, and try to maybe do some kind of regular content with it.</p>
<p>For next week, though, I think I should be trying to manage my time more rigorously than simply writing stuff down in these blog posts.
So, that's the plan: plan better.</p>
Diary 2019-01-202019-01-20T05:00:00-05:002019-01-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-20:/diary-2019-01-20<p class="first last">... Eh.</p>
<p>Quick entry because I was out for a bunch of today, running into situations that were unpleasant but I don't want to vent about them here, and then I played video games for hours.</p>
<p>Um...
That's about the shape of today.
If you're familiar with commonly-used Minecraft mods, check out Equivalent Skies.
I think I'm still in the early game, might not be doing things super-effectively, but I'm having fun.
I probably ought to start doing the Thaumcraft quests; I've been procrastinating because I've been pretending I'll build any kind of base other than "just a big platform with stuff hovering above it because I used slabs".</p>
<p>Anyway, for tomorrow, I'm going to try to do more reading.
Nothing more to do today, since it's now tomorrow.</p>
Diary 2019-01-192019-01-19T05:00:00-05:002019-01-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-19:/diary-2019-01-19<p class="first last">Taking things easy.</p>
<p>PICO-8 update: I realized that one of the things I was doing to make the chords work wasn't exactly the same, so I used the last SFX slot on a slightly tweaked version.
I'm going to give this a few days, then start working on adjusting instruments and volume.
Next time I do something like this, I'm going to look for something rhythmically simpler, and with canonical sheet music more easily available.</p>
<p>I made better progress on everything else today.
Some reading, and I guess that was kind of it, but things seemed a lot less hectic to me.
I'll have to just remind myself to take things easy for most of the week, because I think I'm pushing myself too hard.</p>
<p>Over the weekend, I'm going to try to read a bit more about Erlang, and also write a reaction to <em>The Apple</em>, because hoo boy, that movie...</p>
<p>Anyway, I should wrap up for tonight.
I'm tired.</p>
Diary 2019-01-182019-01-18T05:00:00-05:002019-01-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-18:/diary-2019-01-18<p class="first last">Several hours of nerd snipe later...</p>
<p>Quick entry because I spent all the time I could have spent on other stuff, working on one thing.
And that thing was: an initial draft of a cover of Stronger Than You for the PICO-8.
I got <em>extremely</em> lucky here, in that I was able to fit the sheet music I was working with into 63 out of the 64 provided SFX.
(I had been thinking about trying to add accompanying sound effects, but HAHA NOPE)
The next step for this is to evaluate the instruments and effects to see if there's any improvement to be had over triangle waves with no effects except fade outs and fast arpeggios.</p>
<p>The next step for now is to sleep, and maybe later try to figure out how I want to organize things.</p>
Draw a Box 2019-01-172019-01-17T05:00:00-05:002019-01-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-17:/draw-a-box-2019-01-17<p class="first last">I'd really like to stop missing days, but I haven't.</p>
<p>In this post:</p>
<ul class="simple">
<li>Eeeeh.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>Sadly, I backslid on January 10. I just didn't want to use my fingers any more after the rest of today.</li>
<li>The website got redesigned, and I discovered this on January 11. I'll try to get a fresh start tomorrow.</li>
<li>I started reorienting myself on January 12. Reviewed the earlier lessons, and resolved to go back and watch the videos. The two big things I need to do are to make sure I'm drawing from my shoulder, and to get a better balance between exercises and messing around. I'm <em>way</em> behind on my messing-around quota. As a side effect, I need to be explicitly putting aside longer explicit blocks of time for doing this stuff. I also need to, if I'm going to mess with video footage, figure out how to do video footage that doesn't make me feel ill. I tried to get a handle on the drawing-from-the-shoulder thing, and I'm kind of feeling like I need something closer to a proper drawing surface, because it was like I couldn't really engage my shoulder without also engaging my waist. Anyway, time to go sleep off that video hangover.</li>
<li>I reviewed some basics on January 13. I think my highest priority right now is getting less pressure on my pens, because I think I've messed up two pens so far. So, I worked on ghosting, and discovered that I'd gotten a little rusty. Anyway, I did that, then, for fun, I tried drawing some Pokémon fusions. That... rapidly got less fun, on account of the fact that between my current skill level and the fact that they're unholy spritesmashes, the unholy spritesmash part was the less unsettling part of the final product. "Yeah, yeah, Startales, your face is a giant faceted gem, and <em>good lord</em> what is wrong with your legs?" I noticed relatively quickly that I ended up not drawing on the ideas of lesson 2, which is one of the reasons I had filed away in my subconscious for making sure I only use photo references, at least for now: I got focused on replicating the compositional details, went on autopilot treating it as a flat figure, and turned poor Magnedos into <a class="reference external" href="https://llvm.org/Logo.html">the LLVM dragon</a>. A shame, I think the design was promising, if vulnerable to immature jokes. All of Cuem looked good except for the skull, and the limbs... in other words, the pile-of-rocks aspect looked great, at least in comparison. I think next time I'm going to look for some rocks or something, try something a little more attainable first.</li>
<li>I waited too long to start on January 14. I'm going to jot down some ideas for later, and try to put aside a specific time every day.</li>
<li>I drew some planes on January 15. This went much slower than previous plane drawings, and had some line issues. I <em>believe</em> the problem is that my previous planes weren't drawn from the shoulder, so it's not properly conditioned to do what needs to be done. I think I'll stay on this until the sheet is reasonably full, maybe try to redo the homework because I was formerly using my wrist so much. For fun, I started sketching stuff out for a con-script.</li>
<li>I let things go too late on January 16. I think I'm going to have to accept that work is being hard on me right now, and I'll have to scale back my expectations for how much hobby stuff I do until it eases up a little.</li>
</ul>
<hr class="docutils" />
<p>Next week, I dunno.</p>
Diary 2019-01-162019-01-16T05:00:00-05:002019-01-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-16:/diary-2019-01-16<p class="first last">Rubber-ducking bizarre music hacks.</p>
<p>I ended up focusing on putting other songs into their own PICO-8 carts.
I'd really like it if I could decide to try this with a song that doesn't use triplets, because I think it would be easier if I could end playback early somehow.
Wait... if the desired measure length is a multiple of 32 ticks (and it is, as a matter of fact), then I can set it to loop at a later point, and have another track that actually handles the termination, by being the desired length.
This will require some weird sfx loops, but it was always going to.
I should really be writing this stuff down.</p>
<p>I'm going to try to get to bed earlier, and read a bit in bed, but we'll see.</p>
<p>We recently watched <em>The Apple</em>, and it is too late at night for me to do that movie justice.
Brief remarks: if you like <em>Shock Treatment</em>, it's worth checking out <em>The Apple</em>, but I prefer <em>Shock Treatment</em> for various reasons, such as that its jokes actually land.</p>
<p>ANyway, bed, getting there, yes, good night.</p>
Weekly Roundup 2019-01-152019-01-15T05:00:00-05:002019-01-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-15:/weekly-roundup-2019-01-15<p class="first last">Can't stop, won't stop, might slow down.</p>
<ul class="simple">
<li>Wednesday: Complained about blog software issues, and work. Read a novel some. Found some software to maybe mess with.</li>
<li>Draw a Box: I took a few days off because I was exhausted.</li>
<li>Friday: Not much happened because my hands were tired.</li>
<li>Saturday: Tic-tac-toe work, and an attempt at planning.</li>
<li>Sunday: The planning didn't work out, but I got some stuff done.</li>
<li>Monday: Looked into composing for the PICO-8, and realized it's more sophisticated than I thought.</li>
</ul>
<p>Next week, I'm going to keep on grinding stuff out, probably try to focus on reading.</p>
Diary 2019-01-142019-01-14T05:00:00-05:002019-01-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-14:/diary-2019-01-14<p class="first last">Getting back on my feet.</p>
<p>Did some reading, reoriented a little with drawing, played some games.</p>
<p>I found a tutorial on writing music for the PICO-8, followed along, and I think the result is passable.
I don't know if it makes sense as, like, background music for tic-tac-toe, but one step at a time.
There is way more depth to the PICO-8 composition tools than I realized at first.</p>
<p>Too bad I don't seem to have much to talk about regarding today, but I'm happy with how things went.</p>
<p>Moving forward, I'm going to try to have more focus.
Take a break from the PICO-8 stuff, except maybe to watch the tutorial series, then come back to it later.
Probably stay away from Minecraft for the near future.</p>
Diary 2019-01-132019-01-13T05:00:00-05:002019-01-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-13:/diary-2019-01-13<p class="first last">Uuugh</p>
<p>I'm glad I wasn't too wedded to those plans I made yesterday, because they didn't really pan out.</p>
<p>Status:</p>
<ul class="simple">
<li>Bounced off of reading just now, because it turns out I have issues with stuff like cooking in unfamiliar kitchens.</li>
<li>Watched the lesson 0 video, and made some plans. I'm going to try to check on some basic stuff after this entry posts. There are more videos to watch, and I didn't expect quite so much length.</li>
<li>Never got around to the PICO-8 stuff.</li>
<li>Spent <strong>a lot</strong> of time on the Minecraft video thing, collecting and condensing footage... that turned out to induce delayed nausea. Why are my videos all like this? Game footage, phone camera, doesn't matter.</li>
</ul>
<p>Anyway, we went shopping, and got some stuff we'll need, so that's good that we got that done.</p>
<p>I'm going to go try to make my head stop spinning.</p>
Diary 2019-01-122019-01-12T05:00:00-05:002019-01-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-12:/diary-2019-01-12<p class="first last">I did a thing today!</p>
<p>Just now, I implemented winline drawing in tic-tac-toe, then spaced out trying to understand the sound effects stuff.
I'm going to have to look at examples, I guess.</p>
<p>I otherwise didn't get much done today, so let's see what I want to get done tomorrow:</p>
<ul class="simple">
<li>A bunch of reading. Shouldn't be an issue once I get started. Slot this in around 4 PM.</li>
<li>Reorient myself on the drawing stuff. I haven't been doing everything I maybe should have, and the courses got redesigned, so I need to take some time to review old stuff and make more solid plans for myself. Watch videos in the morning, plan after lunch, exercises around 8 PM.</li>
<li>Review sound work for the PICO-8. I'll look into this stuff after dinner.</li>
<li>Try recording and messing with Minecraft video. Do this around 2 PM.</li>
</ul>
Diary 2019-01-112019-01-11T05:00:00-05:002019-01-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-11:/diary-2019-01-11<p class="first last">I really hope this isn't the new normal in workload.</p>
<p>Didn't get much done today.
I spent most of work auditing and upgrading systems.
Typing the same commands over and over was like semantic satiation for my fingers.
After that, I just wanted to take it easy.
So I listened to music, cleaned up my browser tabs, tried to track down a webcomic from the aughts, added type annotations to the publisher script, read about Erlang...
You know, relaxing things.</p>
<p>(The type annotations got a little less relaxing when I realized that a massive chunk of the logic is based around just, strings.
I wonder if I can make use of pathlib to make it a little richer.)</p>
<p>I've got PICO-8 open for tomorrow.
I want to stop talking about working on it, and work on it.</p>
<p>This year feels like kind of a mixed bag so far.
I feel like I'm making great progress on things... when I make progress at all.
Oh well, not helping anything by being up this late.
Better work on sleep first.</p>
Draw a Box 2019-01-102019-01-10T05:00:00-05:002019-01-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-10:/draw-a-box-2019-01-10<p class="first last">With hard work and dedication, you too can feel awful for at least a week.</p>
<p>In this post:</p>
<ul class="simple">
<li>I got really tired, then got slightly less tired over time.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>Just a little texturing on January 3, because I'm two days in to three all-day meetings and <em>exhausted</em>.</li>
<li>Nothing on January 4, because I'm so tired.</li>
<li>Nothing on January 5, because I'm still so tired.</li>
<li>I did some texturing on January 6, to ramp up slowly.</li>
<li>I did a little bit of texturing on January 7. I should start setting aside specific times for this stuff, so I don't let it go late and try to do things sleepy.</li>
<li>Ramped back up with texturing a little, shortly after January 8. Now that I look over the sheet again (yep, so little done that this is still the first texturing sheet), I am getting a sense of improvements and picking up techniques, but I don't know, I feel like I'm probably improving overall, but maybe randomly doing a little worse with some specific textures. I should maybe look into finding other resources that go into more detail with this stuff, because at this point I'm kind of saying stuff like "okay, stippling seems to generally work" and basically trying out different ways to make Fibonacci spirals emerge, on account of the various fruits and scales I chose to texture.</li>
<li>I did some more texturing on January 9. I decided to put little circled numbers indicating the order I mostly did these in, because I figured this is visually interesting enough that it could be a good accompaniment to a post, even if some of the early attempts fail to really resemble what they're supposed to be. The circled numbers are necessary because I don't naturally fill in an empty sheet of paper in an order that makes sense to other people. (I once did a math problem incorrectly, with work that snaked all over the page in a way that completely concealed the connections unless you're me. When I found the mistake, I propagated the changes "forward", making corrections all over the sheet. Judging from other people's reactions, it was a little disorienting to watch.)</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry had better be better, eesh.</p>
Diary 2019-01-092019-01-09T05:00:00-05:002019-01-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-09:/diary-2019-01-09<p class="first last">Computers: threat or menace?</p>
<p>Yesterday's entry went up an hour after I finished it, because somehow or other I ended up with Pelican upgraded through a major version, and Sass replaced with an entirely different implementation.
Fixing the fallout of this required editing my theme, my blog config, some of my posts, and the publisher script.
Besides the theme changes, which were for the Pelican upgrade, the majority of the changes focused around editing the blog config to disable or remove functionality from the webassets package that Sass no longer supported.
This was not a pleasant experience, and I did not take it well, or gracefully.
Two big complaints: webassets seemed really opaque, and I'm not clear how actively people are using it, since I couldn't find the issue I hit; and Pelican doesn't seem to emit tracebacks by default.
I should rework my publisher script to pass <tt class="docutils literal"><span class="pre">--debug</span></tt>, I think, and file the bug against webassets.
Later.</p>
<p>Work is, not great, but it hasn't gotten as bad as I worried it might.
I'm still an <a class="reference external" href="https://twitter.com/nickm_tor/status/860234274842324993">abyss domain expert</a>, which is a, ah, hole that I'd like to dig myself out of.</p>
<p>I did a little more reading.
I haven't totally stopped myself from analyzing things, so I'm noticing stuff like apparent callbacks to stuff that wasn't shown but seems like it would have been; not sure if intentional.
Also, a lot of the male lead's dialogue is way over the top.
It keeps reminding me of when my wife quotes meme remixes of gay porn.
However, I do keep losing track of the fact that I'm pretty sure these characters are supposed to be in their late teens and early(?) twenties, so I shouldn't really be expecting them to react to things more proportionately than I did in college. ... They're fine.
Stuff I'd want in my own writing: characters older and less wealthy than this.
This is useful data.
I do appreciate the fact that I haven't gotten any precise numbers or measurements; that kind of thing is clunky, and I should avoid it, or at least avoid frontloading it.</p>
<p>Oh also, I snagged a copy of <a class="reference external" href="https://hyperlapsepro.zendesk.com/hc/en-us/articles/115010695707-Hyperlapse-Pro-Key-Availability-Issues">Hyperlapse Pro</a>, and I'm thinking I'll try it out on Minecraft footage because I don't have meatspace footage that would work well with it.
That's a few days out because I'm not managing time well enough to play during the week any more.</p>
<p>I think I need to take inventory of all of the stuff I'm trying to work on, because it seems to have ballooned out of control.
For now, good night.</p>
Weekly Roundup 2019-01-082019-01-08T05:00:00-05:002019-01-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-08:/weekly-roundup-2019-01-08<p class="first last">All work and all play make the blog go off-topic.</p>
<ul class="simple">
<li>Wednesday: I did some planning for the year, and talked myself into finally starting on romance novels.</li>
<li>Draw a Box: Eh, not great, work-ethic-wise.</li>
<li>Friday: I optimized my PICO-8 code some, and gave an explanation that probably wasn't very helpful. I started reading a romance novel.</li>
<li>Saturday: I wrote this very short entry in the aftermath of the meetings.</li>
<li>Sunday: I reflected on what I've read so far, and what I feel I've learned from writing for the PICO-8.</li>
<li>Monday: I got horribly distracted by Minecraft. Going to have to dial that back a bit.</li>
</ul>
<p>Next week, let's see about establishing a better rhythm for the various things I'm trying to work on nearly simultaneously.</p>
Diary 2019-01-072019-01-07T05:00:00-05:002019-01-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-07:/diary-2019-01-07<p class="first last">I think I was slightly sick all weekend, but I seem to have recovered.</p>
<p>I am, shall we say, somewhat apprehensive about how this next week is going to be at work, because of some coordination stuff that I don't want to get into.
Allegedly, everything is taken care of, but I'm skeptical.</p>
<p>Anyway, I'm ramping up slowly.
I read another chapter.
I wasn't intending to analyze this, but I am noticing stuff, like, the narrative reveals how they feel about each other, and then later mentions why.
It's still pretty quick-feeling, but it's a lot better than how things went in, say, Maniac Cop 3, which is not a romance but does feature a romance-presenting occurrence.</p>
<p>So, I don't want to commit to working harder on these things until I see how things shake out at work. ... I say that, but also I'm having a good time in Minecraft.
I'm kind of trying to impose my own rules for getting through the pack I'm in, Enigmatica 2.
I'm basically not bothering with the quest rewards, just using them as a checklist.
Ideally, I'd have a non-Skyblock pack that has guide-only quests that explain each family of mods.
Enigmatica 2 is <em>almost</em> that, though I do seem to have found a magic mod with no associated quest tab, so there might be stuff I'm not seeing.
Idea that occurred to me after I stopped tonight: can I get Unbreakable and World Traveller on a shuriken, so I can just kind of hoover up mob drops into my base?
Probably want to add looting and beheading.</p>
<p>Minecraft TODO:</p>
<ul class="simple">
<li>Relocate base to an area with a higher concentration of Ember. (And dig down to bedrock, etc.)</li>
<li>Max out Luck on pickaxe.</li>
<li>Get a lot of lapis.</li>
<li>Make World Traveler shuriken so I don't have to "collect drops" or "be near monsters".</li>
<li>Farm tinker weapon XP on some spawners I found.</li>
<li>While I'm down at bedrock anyway, look into starting EnderIO.</li>
<li>Make a World Traveler mining tool at some point, probably?</li>
<li>World Traveler axe?</li>
<li>I'm pretty sure I can start on Psi easily enough now.</li>
</ul>
<p>I'm clearly pretty excited about this Minecraft stuff, but I'll get back to PICO-8 soon and keep up with everything else, I promise.</p>
Diary 2019-01-062019-01-06T05:00:00-05:002019-01-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-06:/diary-2019-01-06<p class="first last">Busy day, but not with this stuff.</p>
<p>I "didn't have a chance to read" today.
Quick thoughts on what I read yesterday.
I hadn't realized for a few chapters how much younger the leads are than I am.
Also, I mentally glossed over stuff like what kind of car they had (like how you have to ignore how big the apartments are in sitcoms), so good on the author for pretty much coming out and saying "yeah, they're all pretty rich".
Male lead has an adorable little brother to give himself someone else to better himself for. ... Who he nearly attacked.</p>
<p>None of this is a criticism of the writing; I think it's actually really effective so far.
I would have been all over today, except I was super tired and zoning out a bunch.</p>
<p>I also had some thoughts about game-making that I didn't have chance to articulate yesterday.
My experience working with the PICO-8 has me thinking that I need to be giving more wait to what the player sees and feels than to the underlying systems, at least initially.
Basically, I trust myself to make systems work, I <em>know</em> I can prop up any given pattern of usage I find convenient, so I have to make sure I prioritize UI and UX over fancy rulesets.
With more experience, I might be able to take shortcuts like "this target experience suggests rules like this, so I can just prototype it like that", but I don't have experience like that right now.</p>
<p>(By "didn't have a chance to read" I meant "used all chances to read to play Minecraft instead".)</p>
Diary 2019-01-052019-01-05T05:00:00-05:002019-01-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-05:/diary-2019-01-05<p class="first last">TIRED.</p>
<p>I read some today.
The early chapters seem bite-sized.</p>
<p>SO TIRED.
GOODNIGHT.</p>
Diary 2019-01-042019-01-04T05:00:00-05:002019-01-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-04:/diary-2019-01-04<p class="first last">Doing what I can while running on fumes.</p>
<p>I realized that I could simplify the PICO-8 code in a few ways:</p>
<ul class="simple">
<li>Because the grid lines are uniform, I can use <tt class="docutils literal">sspr</tt> to draw the middle bits all at once, which cuts down on draw calls and lets me get rid of the intersection sprite.</li>
<li>I don't have winline rendering yet, but I was dreading writing the code to handle diagonals, because it would have involved fiddly logic in which there's N internal bits but N+1 nubbins on either side, which is tricky to iterate over. I realized I could eliminate this by shifting the pieces over to the side by one pixel. This moves N nubbins into the internal section, eliminating the draws, expands N nubbins, which is fine, and the remaining 2 nubbins get absorbed into the end pieces. The end result is I still need to iterate <tt class="docutils literal">spr</tt> calls to make this work, but all of the iterations match and I only need two calls outside the iteration, which is nice aesthetically. I just need to remember to deflect the draws 1 pixel to the side, when I do the logic.</li>
</ul>
<p>I've been in all-day meetings at work, so I'm exhausted, and will continue to be so.
The main thing I accomplished earlier today was to notice that performance on my work laptop improved when I closed all the text editor windows I had open, so I cut down on the windows on this laptop as well, and it's... probably not worse?</p>
<p>Yesterday, before the exhaustion set in, I bought one of the books I was interested in.
Actually, I bought it, and the book it's apparently a sequel to, because they were in a two-pack for a dollar more.
As I said, I'm exhausted, so I gave myself a target of just the first chapter.
The first chapter is from the male character's viewpoint, and he's kind of a pompous ass, so I'm kind of hoping this takes the tack of "he's ignoring his capacity to be a good person and improves himself" rather than "the heroine reforms the bad boy".
My wife feels way stronger about that cliché than I do, I think, but I'm still, like, I hope the book I bought is, like, good.</p>
<p>It would be good for me, I think, if I could get more comfortable with extending trust to the author to start with, rather than watching for (or imagining) the slightest sign of weakness.
I try to avoid being antagonistic to other people because it was tearing me up inside, and being antagonistic towards media I'm consuming... doesn't feel as bad, but it mostly doesn't feel good.</p>
<p>I'd read more tonight, but I am (again) exhausted and I want to get ready for bed early.</p>
Draw a Box 2019-01-032019-01-03T05:00:00-05:002019-01-03T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-03:/draw-a-box-2019-01-03<p class="first last">Out of all the times this has had me going through an exercise for what feels like forever, this is one of them.</p>
<p>In this post:</p>
<ul class="simple">
<li>Slightly less work than usual.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>A few ellipses on December 27. I'm thinking about what kind of style I want to aim for. One thing that bothers me with my texturing attempts is that I can't figure out how to lighten things, so if I want something to be lighter I have to figure out where <em>not</em> to draw. I'd prefer to do texturing/fills with something that's not purely set up to darken things. I don't have a firm enough grasp of terminology to know if I can boil that down to something like "painting".</li>
<li>I took a break on December 28. I'll probably take a break tomorrow as well, then try to pick things back up on Sunday.</li>
<li>I drew some ellipses on December 30. I'd like to start ramping back up.</li>
<li>I don't remember what I did on December 31, but according to the dates I put on these sheets, I did some texturing and some random doodles.</li>
<li>More ellipses and texturing on January 1.</li>
<li>More texturing on January 2. I'll be really excited to move past these exercises.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Diary 2019-01-022019-01-02T05:00:00-05:002019-01-02T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-02:/diary-2019-01-02<p class="first last">New Year, done vacationing, let's do this.</p>
<p>I started laying the groundwork for winline rendering in tic-tac-toe.
This basically involved making a whole bunch of global constants and variables, the former to make some logic I haven't written yet easier, the latter because it makes things easier in terms of communication between methods.
That will require a global variable one way or another, but maybe I can look into making it cleaner when I have this actually all the way to what I want, in terms of behavior, and I can iterate on it.</p>
<p>I'm also looking over the giant pile of books I have on my Kindle, and a subsection of my Amazon wish list, and thinking about what I want to read, in which order.
I ended up grabbing anything that looked plausible for my "reading list" collection, because I figured it was easier to notice something that's there and shouldn't be, than that's not there and should be.
Some of the stuff in there is probably more on the side of "potentially interesting" than "useful for what I have in mind".
I'm reading one thing that seems analogically applicable, <em>ZERO to MAKER</em> by David Lang.
My various creative plans don't involve soldering or waterproofing, so far as I know, but I think this book will establish a useful cognitive toolbox in terms of accomplishing what I want to accomplish.</p>
<p>My plan for the rest of the books is to figure out which projects I want to plan for, and where any given book would fit in terms of "if I want to make progress on one of these <em>right now</em>, what knowledge do I need?"</p>
<p>The projects I want to do are:</p>
<ul class="simple">
<li>The Romance Instrumentality Project. First priority is reading some romance novels and figuring out which ones I like, and which ones to reread later for analysis. Next, reading about outlining, with an eye towards making a model of beat sheets. Once I've done that, I'm going to want to focus on the specific subject matter I'm going for, which is going to mean switching gears <em>a lot</em> and reading about various theories and their applications.</li>
<li>The OMICE short stories. I feel like before I get OMICE into it, I want to find some other thing to write short stories for, hopefully light-weight in terms of world-building or the urge to world-build.</li>
<li>Linked Seas. There are still some serious issues I have with characterization, so I'm not sure which angle I want to take with this project.</li>
</ul>
<p>The first bullet point started off shorter, but I came to realize that it was the best starting point, in terms of things I have a concrete project in mind for.
So that means that I'll first be purchasing stuff from that list I put together earlier (and also checking for new stuff), and then reading it, and then posting my reactions I suppose.</p>
<p>By a process of rational evaluation, I have determined that the most fruitful course of action for me is to engage with work that focuses on the interiority of individuals, often relatably flawed ones, and be emotionally honest in my reactions.
This is the kind of thing I made Three Dollar Quill for in the first place.
Also, I am terrified.</p>
<p>I like to think that I've built up an aura of detached coolness and disaffection.
I'm pretty sure I actually haven't, but I like to think that, and I need to stop.</p>
<p>I can stew in this some more, but I need to:</p>
<ul class="simple">
<li>Get to bed, wake up, go to work, come back, then:</li>
<li>Find which book I want to read first.</li>
<li>Read it.</li>
</ul>
<p>Better get started, hurry up and sleep.</p>
Weekly Roundup 2019-01-012019-01-01T05:00:00-05:002019-01-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2019-01-01:/weekly-roundup-2019-01-01<p class="first last">The week of 7 Billion Humans, apparently.</p>
<ul class="simple">
<li>Wednesday: I laboriously moved around a bunch of PICO-8 sprites, and read some of an ebook.</li>
<li>Draw a Box: Texturings and ellipses.</li>
<li>Friday: I played 7 Billion Humans some.</li>
<li>Saturday: I realized I'd been working with too big a spritesheet and collapsed it down, and I played 7 Billion Humans some more.</li>
<li>Sunday: I played 7 Billion Humans some more.</li>
<li>Monday: I tried to articulate some fair complaints about Maniac Cop 3, the worst of the Maniac Cops.</li>
</ul>
<p>Next week, I'm going to take an inventory of my ebooks, then work out a plan of action.
I don't know how much I'll get done past that, because the first thing we're doing at work in the new year is three straight days of meetings, and that sounds exhausting.</p>
Diary 2018-12-312018-12-31T05:00:00-05:002018-12-31T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-31:/diary-2018-12-31<p class="first last">Recovering from vacation</p>
<p>I'm <em>almost</em> done with the code for tic-tac-toe.
Here's what's left:</p>
<ul class="simple">
<li>Code the ability to draw winlines</li>
<li>Add sound effects and music, because I want to learn how to do those.</li>
</ul>
<p>We also watched the third Maniac Cop movie today, and, whew.
I preferred the first to the second, but the second is <em>way</em> better than the third.
Issues include:</p>
<ul class="simple">
<li>Front-loaded exposition so a character can die quickly.</li>
<li>Cordell doesn't kill much (in what we assumed would be <em>a slasher movie</em>), and it's not clear what his motivations are throughout the movie.</li>
<li>Out of the four kills (just barely more than the movie's hero) Cordell did that I can remember, one of them has no effect on anything at all.</li>
<li>It's a Maniac Cop movie with a message of "boo-hoo, poor cops".</li>
<li>Nothing that gets revealed to the characters changes the basis of Jessup's lawsuit, but then he goes on a shooting rampage and gets killed in self-defense. Makes it easy!</li>
<li>Like a lot of these goofy movies we've seen, there's an obligatory-feeling romance-like plot-like occurrence that displays the approximate emotional depth of the first few lines of Sk8er Boi. (Looking over the lyrics, since I didn't remember them clearly, I'm pretty sure most b-movie creators, if they listened to Sk8er Boi, it would blow their minds.)</li>
<li>It feels like the movie is there in service of a bunch of cool (or "kewl") scenes, which do nothing to impart any sort of weight.</li>
<li>Ultimately, the closest we got to feeling suspense was wondering when exactly the dumbass house of cards we'd seen constructed would come tumbling down. (On reflection, the movie might have worked <em>slightly</em> better if we hadn't seen Kate's final moments in the convenience store except through the news footage. That way it would only be obvious in retrospect that Kate is partially being framed.)</li>
<li>The timeline is a little confusing, meh, I dunno.</li>
</ul>
<p>Ultimately, compared to the first movie, I feel like the sequels don't really have anything worthwhile to say.</p>
<p>Anyway, post is running late, better turn in and try to get back in the swing of things later.</p>
Diary 2018-12-302018-12-30T05:00:00-05:002018-12-30T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-30:/diary-2018-12-30<p class="first last">I was tired all day, and I'm tired now.</p>
<p>Socialization.</p>
<p>So exhausting.</p>
<p>7 Billion Humans.</p>
<p>Oddly, given the name, less exhausting.</p>
<p>I'm still feeling like I'm often having trouble applying concepts from one level to later levels.
It's like, I'm getting more commands as time goes on, but I don't feel like I'm developing any but the most basic of higher-level patterns to apply to the assignments.
It's been a while since I played Human Resource Machine, but I think its progression was slightly more obvious.
I could be wrong, though.
The problem, either way, manifests as some levels taking much longer than the levels before and after them, but maybe it's more complicated than that.</p>
<p>It'd be cool if I'd done anything else to write about today, but it was mostly just hanging out with friends visiting from another timezone.</p>
<p>I did start trying to write up the islands I want to build.
There's a little bit of a chicken and egg thing going on where I can't really guess how much space the functional aspects will take up unless I build them, but I've got nowhere to build unless I make an island.
Maybe I'll aim to have "enough" horizontal space, and just build upward as needed.</p>
Diary 2018-12-292018-12-29T05:00:00-05:002018-12-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-29:/diary-2018-12-29<p class="first last">I would really like to have a bit more structure in my days, soon, please.</p>
<p>I finally read some more of the manual for the PICO-8, and was therefore able to cut down considerably on the size of the spritesheet, so that's good.
The next thing to do is to start working on the various update and draw functions, but those <em>should</em> be easy once I kick myself into actually working on them.</p>
<p>I also played games today.</p>
<p>The Minecraft I've been playing has been a skyblock pack focused around crops.
Since I've gotten most of the crops done (the obvious stuff missing is a lot of HarvestCraft stuff, and emerald, which relies on HarvestCraft stuff), I've started actually exploring the mods I went and got the resources for.
I've progressed a little way in Astral Sorcery and Immersive Engineering.
What I think would be a cool way forward with this would be to make independent "islands" associated with different mods, and connect them to the center island with steel cables so I can try out the skyhook for getting around.
One obstacle to this is that I'm not super-great at elaborate builds in general, especially not aesthetic builds, especially not in a skyblock context.
But I'd like to learn.
Maybe find some pictures of factories and such for the Immersive Engineering island.</p>
<p>I got through whichever bit of 7 Billion Humans was bothering me, and suddenly it's showing off how weird the variance in objectives can get.
Sometimes I'm leveraging pathfinding and general dynamism, and other times I'm basically writing one program per worker, and it kind of has no pattern I can discern so far?
It's really peculiar.
I feel like I'd somewhat prefer to have the ability to use later instructions on old puzzles.</p>
<p>I'm learning a bit more about Erlang, but I think I'd be served well to start looking into coding challenges to try to apply it to.
Maybe take a look at Advent of Code stuff, since I've been remembering that it exists.</p>
<p>It's late, and I have to do stuff in the morning.
Good night.</p>
Diary 2018-12-282018-12-28T05:00:00-05:002018-12-28T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-28:/diary-2018-12-28<p class="first last">I was outside while it was light out today. Barely.</p>
<p>My days have been getting less and less structure the more I'm on vacation.
Today so far:</p>
<ul class="simple">
<li>Read some of a book that doesn't feel like a good candidate for having posts about it.</li>
<li>A lot of Minecraft.</li>
<li>Read a little more about Erlang. It feels like I have a lot of points of comparison for it. I should maybe switch books in the hope of getting more pedagogical stuff.</li>
</ul>
<p>I also recently got 7 Billion Humans, and powered through it until it suddenly got a little harder and I stopped trying so hard because I wasn't getting through the levels super-quick.
I think it might be hard to make a level in that game that's only kind of hard?
On an aesthetic level, if you felt like Human Resource Machine was insufficiently Tomorrow Corporation-y, then 7 Billion Humans has you covered.</p>
<p>Moving forward, the two big things I want to focus on:</p>
<ul class="simple">
<li>Spritesheet rework for tic-tac-toe, followed by writing the various hooks.</li>
<li>Reading list for next year.</li>
</ul>
Draw a Box 2018-12-272018-12-27T05:00:00-05:002018-12-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-27:/draw-a-box-2018-12-27<p class="first last">Post delayed on account of Minecraft.</p>
<p>In this post:</p>
<ul class="simple">
<li>Post delayed on account of Minecraft.</li>
<li>I did some texturings, then returned to working on my ellipse techniques.</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>A few more texturings on dissections on December 20. So far, I'm feeling like the outside textures have been not terribly close to the reference image, but they look passably like the general category. My inside textures have been hit-or-miss at best. I think I'm missing something obvious in terms of how to lay stuff out inside the dissection.</li>
<li>I went too late to do good work on December 21, so I guess I'll just try harder tomorrow.</li>
<li>I did a few more texturings on December 22. I feel like some of the textures came out more properly evocative this time, but I'm not sure I had the spatial illusion working well. Also, some of them just came out badly. Guess I'll keep on practicing.</li>
<li>A few more texturings on December 23. I feel like these suffered some from being on a thinner form than the previous ones, and also the fact that I'm still not very good at this. I know I should be trying to challenge myself so I can improve, but I feel like I haven't yet improved enough to make stuff I'll be satisfied with for purposes besides practice.</li>
<li>A few more texturings on December 24. I think tomorrow I'll review the other exercises and take a break from texturing, maybe track down some more reference images.</li>
<li>I took a break from texturing and drew ellipses on December 25. I think I've figured out one of the things holding me back from drawing ellipses well under some circumstances, and started practicing the things I've been missing. I know I wasn't using my muscles this way before because now they hurt a lot.</li>
<li>I drew a few circles shortly after December 26. Delayed on account of Minecraft.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same, hopefully with less Minecraft-related delays.</p>
Diary 2018-12-262018-12-26T05:00:00-05:002018-12-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-26:/diary-2018-12-26<p class="first last">Computers are hard!!! when you don't plan things ahead.</p>
<p>A couple things I did today:</p>
<ul class="simple">
<li>Finished reading one book.</li>
<li>Started packing the tic-tac-toe sprites into an arrangement that cuts down on awful offset math. I've currently packed the marks and the board sprites, and my plan next is to move the cursor sprites to after the board sprites, make the missing cursor sprites, and pack the win-line sprites afterwards. I spent a lot of this packing process figuring out how best to move the sprites around. I think I found some nice workflows in Sublime Text for shunting around pixels in bulk, and I realized that moving around a single sprite in PICO-8 is sort of not that bad, sort of. Is there any spritesheet editor that lets you say "okay, permute these sprites in a straightforward fashion without shifting them around relative to their edges"? Like, pull a sprite up from one row, have the other sprites shift to the right, and the one on the end overflows to the next row? That's not applicable to this, but it seems handy in the context of using a png spritesheet or something.</li>
<li>Started reading a book on Erlang. I'm going to trial this for the idea of blogging about books.</li>
</ul>
<p>What I've got so far from the book, <em>Introducing Erlang</em>:</p>
<ul class="simple">
<li>Do not read this on a black-and-white display like most e-readers have. The fancy color highlighting will give you eye-strain.</li>
<li>The period acts as a statement delimiter, and also a decimal separator. I'm cool with this as long as I'm not the one writing a parser for it.</li>
<li>I haven't played around in the shell much, but I think I understand the basics so far.</li>
<li>I just got to explaining modules, and it's too late at night for me to process this stuff properly, so I'm stopping now.</li>
</ul>
Weekly Roundup 2018-12-252018-12-25T05:00:00-05:002018-12-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-25:/weekly-roundup-2018-12-25<p class="first last">I got stuff done, but it was still a rough week.</p>
<ul class="simple">
<li>Wednesday: I thought about how little confidence tumblr inspires.</li>
<li>Draw a Box: I tried to shore up my fundamentals some more, then moved on to the dissection exercise.</li>
<li>Friday: I thought about learning about Erlang, and started planning future topics.</li>
<li>Saturday: I started working on the PICO-8 tic-tac-toe.</li>
<li>Sunday: Sprite work, and listening to music.</li>
<li>Monday: I figured out more of what I need for this PICO-8 project, and looked into other fantasy consoles; I didn't find any of them compelling enough to justify switching right now.</li>
</ul>
<p>Next week, more vacation, and hopefully a bit more planning for next year.</p>
Diary 2018-12-242018-12-24T05:00:00-05:002018-12-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-24:/diary-2018-12-24<p class="first last">It feels nicer working with my own janky code than with other people's janky code.</p>
<p>Today, I made cursor sprites, of which I'll probably need more, and started working on the actual code to power the game.
I got code to take turns and determine the winner, if any.
Next up is cursor movement code.
From there, I think I "just" need all the input and drawing code, the latter of which really needs the sprite sheet to be laid out in a saner fashion.</p>
<p>My impression of developing for the PICO-8, rather than just reading over other people's projects, is kind of mixed so far.
I haven't done I/O, so I don't have any strong feelings there yet.
Between spriting and coding, the sprite creation stuff is fine so far.
The coding is kind of ehh.
It's mainly that I'm used to much longer lines, so I keep on overflowing the screen, and the result is confusing to navigate.
Out of the fantasy consoles out there, I wonder if any of them are more flexible about development environments.</p>
<p>I guess I'm thinking in terms of, to develop for some actual consoles, you can in theory use any source language that can target the console's chipset, and therefore any editor, and rely on the compilation toolchain to tell you if your executable will for whatever reason not fit or work.
I don't know if that's a reasonable angle to approach a fantasy console from, especially if I'm on-board with using Lua.
In any case, I just grabbed a few likely-looking consoles: ECoS, LIKO-12, neko8, and PX8.
I won't mess with them until I feel like the PICO-8 is seriously holding me back.
What I have right now is organizational issues on my end, and I need a serious plan if I'm to deal with them.
There's also the fact that, looking at these, I doubt they'll be silver bullets, and I'll need to weigh the pros and cons, and also maybe look into the ones that involve paying money for them.
Also just installed pyxel.</p>
<p>Did the cursor movement code.
It definitely feels like the bigger issue than tools is having a mental model that doesn't get tangled up in abstractions.
I do this thing sometimes where I kind of buy into the monad-and-related-typeclasses hype without, well, actually using Haskell, and I think that's overall a net negative to productivity.
I guess slightly more concretely, the problem is seeing the elegance of sbstraction, but missing the cost of specializing an abstraction to a specific instance, which is required in order to <em>actually ship a thing</em>.</p>
<p>Thinking about this current project, I think there's a chance I'll skip other fantasy consoles once I get a handle on doing stuff in the PICO-8, and just try to transfer whatever I learn into fancier equivalents of the various PICO-8 tools.</p>
<p>Well, none of that's happening right now.
Glad I'm getting a better picture of my limitations around development.
I'm feeling like taking a break, then focusing on the spritesheet.
For now, it's almost actually the timestamp on this post, so I'd like to be done now.
Good night.</p>
Diary 2018-12-232018-12-23T05:00:00-05:002018-12-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-23:/diary-2018-12-23<p class="first last">Maybe for Christmas Eve, I can give you a longer post</p>
<p>I banged out some more sprites for tic-tac-toe, without sketching things out beforehand, which was a bad idea because they ended up just really haphazardly placed.
I'm going to have to work out a more sensible placement later, and also I have like eight more sprites to make, at least.
UI work is a Whole Thing.
Rearranging the current sprites and adding cursor sprites should be enough for me to then start messing with code.
It's also possible that I'll end up completely reworking the win-line sprites, so maybe I should scrap those, or at least not use them yet.
Also, I've got the cartridge open in my text editor, and it could do with a squarer font for displaying the graphics section.
I wonder if I could write a syntax highlighter for these using the PICO-8 palette.
Oh wow, the syntax highlighting from the PICO-8 package is... interesting.
(I did at least find some stuff that sort of justifies the O mark, so I'm leaving it as-is for now.)</p>
<p>Other than that, I've been doing more of the stuff I said I wasn't going to blog about.
Also, listening to the, um, Mouth trilogy?
Some of these are so intensely weird that I have to stop doing anything else, which kind of slows things down.</p>
<p>I'm a little annoyed that these posts are so short.
I mean, I've got plenty of time all day to do stuff and think about stuff, but, well...
I dunno.</p>
Diary 2018-12-222018-12-22T05:00:00-05:002018-12-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-22:/diary-2018-12-22<p class="first last">"I thought this was going to be a quick post, and it's just short."</p>
<p>Nothing much to speak of today.
Being on the road for a bit over an hour kind of made me not want to do much, so I bought a bunch of indie games on sale on Steam (yes, I know, and I'll be looking for any other games on sale on itch and Humble), and beat a few of them.
While I'm thinking of doing things, I'll fire up PICO-8 so it's just there later.
While it was open, I sketched out the marks.
The X mark looks pretty good to me right now, and I'm not sure about the O mark yet.
Maybe find a circle generator to compare what I drew to something more mathematically based.</p>
<p>What's left to be done there is the different components of the grid lines and the win lines, which I'll need to sketch out separately probably, because I don't think I can get away with eyeballing them like I did the marks.</p>
<p>I got most of Lemon Demon's music earlier today, in addition to another artist who randomly sent me a download code for another album, so I was like, sounds good to me.</p>
<p>Besides that, I was mostly messing around with stuff not worth blogging about, so I'm not going to blog about it.</p>
<p>Ugh, I thought this was going to be a quick post, and it's just short.
I'm going to need to figure out how to kind of refresh myself.
Post over.</p>
Diary 2018-12-212018-12-21T05:00:00-05:002018-12-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-21:/diary-2018-12-21<p class="first last">So done with some things for the year.</p>
<p>I finished up my last workday of the year.
Time to unwind for a while, because that was exhausting.</p>
<p>I realized today that I'm mildly interested in learning more about Erlang, and I further realized that I have some Erlang books on my Kindle.
When one of the ridiculous number of digital artifacts I own happens to be something I get interested in at a later time, it... probably doesn't justify the ridiculous number, but it's nice, I guess.
Anyway, I ended up noticing that I'd failed to categorize a bunch of the books on there, so I went through my downloaded books and sorted them out.
I ran across a few books I'd like to check out further in the future: some programming books that might be interesting, and some books that I started reading and then got distracted from my Kindle.</p>
<p>My plans, now that I have free time:</p>
<ul class="simple">
<li>sketch out the sprites required for tic-tac-toe in PICO-8. I'm leaning towards 3x3 marks and one-wide gridlines.</li>
<li>finish reading the book about genetics</li>
<li>create a reading list from the books I have on the Kindle</li>
<li>also buy the books MacIver mentioned, and get them on my Kindle and in the list</li>
<li>also, while I'm buying things, I was thinking I'd like to have more Lemon Demon songs easily accessible, might try to use Bandcamp again. I remember I stopped because the flow for buying from a bunch of artists was, um, bad, and kept freezing my card, while some asshole used my card to buy as-seen-on-TV homeopathic wart cure and the bank went "Huh, seems legit". But, rants about fraud prevention aside, if I just buy from one artist, it shouldn't do that. I think.</li>
</ul>
<p>It'd be cool if I had a more concrete thing I'd done to talk about, but frankly I have been fried all week.
Good night.</p>
Draw a Box 2018-12-202018-12-20T05:00:00-05:002018-12-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-20:/draw-a-box-2018-12-20<p class="first last">Waah, acquiring skills that have multi-year programs devoted to teaching them is HARD.</p>
<p>In this post:</p>
<ul class="simple">
<li>Flailing</li>
</ul>
<hr class="docutils" />
<p>This week, I have drawn:</p>
<ul class="simple">
<li>Circles and ellipses on December 13. On a whim, I reversed the direction of the ellipse tilts, and thereby discovered that <em>that matters</em>. I'm going to have to practice ellipses tilted "the other way" a bunch. So many weird holes in the fundamentals that I can miss.</li>
<li>More tilted ellipses on December 14. They're gradually getting shaped less like capsules, I think.</li>
<li>I drew more ellipses on December 15. They still kind of look like capsules, so I got frustrated, and tried doing some of the basic exercises with my off-hand. That was... something. I wonder if I could get not-terrible with that hand, then use two identical pens to draw stuff in stereographic mode by drawing each half of the image simultaneously. Probably not, but it's an amusing thought.</li>
<li>I drew more ellipses on December 16. I'm not getting a sense of improvement from this, and also I have to move on because I used up this template.</li>
<li>I did some somewhat random doodles of various exercises on December 17. I'm going to try revisiting the Lesson 2 stuff, try to get the full scope of that, and then start branching out and applying the fundamentals to whatever catches my fancy.</li>
<li>I drew the base shapes for a page of dissections on December 18. It's late now, so I'll get textures tomorrow.</li>
<li>I got some textures and textured two sections on December 19. I'm not happy with how they came out, I think I needed to be paying closer attention to the texture references. I didn't get much done tonight, but I wanted to wrap things up for now, because tomorrow is the last workday of the year for me and I want to sleep so I can get to it faster so I can get it over with faster.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Diary 2018-12-192018-12-19T05:00:00-05:002018-12-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-19:/diary-2018-12-19<p class="first last">I don't have a good conclusion and it's time to hit the publish command.</p>
<p>I didn't have time yet to do a rough draft of the game; we watched Maniac Cop, which took a good chunk of time.
A lot of that movie was silly, but I guess between this and Zombie Nightmare, I'm down for more "zombie vs police" movies.</p>
<p>On Monday, I did the whole log out of tumblr and stay off for the day thing.
I came back the next morning to a relatively quiet dashboard (which is more because I've seriously cut down on my follows), with just a corporate account, which, fair, and a statement from staff regarding the rules changes, which was at best too little, and <em>extremely</em> late.
Now that a bunch of people have deleted their blogs in protest, they choose to state that things won't be as bad as everyone is assuming, on the strength of the text of the rules.</p>
<p>When tumblr tries to explain that the text of the rules means things won't be so bad, that doesn't fill me with confidence.
They seem to have this weird idea that they can expect people to react solely to what they say, when everyone is mentally correlating their past words and actions to extrapolate out future actions, and deciding that it's really time to be going.
NSFW blogs on tumblr were always operating under worry of being put through a capricious reporting system and suspended, only to have gross spambots squat the URL.</p>
<p>Many aspects of staff's statement were the most insulting aspect:</p>
<ul class="simple">
<li>Presuming that the community at large has any trust in them at this point</li>
<li>Mentioning that, yes, the (nonsensical) phrase "female presenting nipples" is widely hated, and committing to its continued use</li>
<li>Attempting to intimate that some group that includes tumblr staff and anybody else should be working together to improve the algorithm</li>
<li>Sticking to their guns so far as using the algorithm at all</li>
</ul>
<p>TL;DR: the scorpion is acting confused that all the frogs are staying away.</p>
Weekly Roundup 2018-12-182018-12-18T05:00:00-05:002018-12-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-18:/weekly-roundup-2018-12-18<p class="first last">Just constantly mentioning how much I miss the sun (except when it does show up, it's super low in the sky and catches me in the face)</p>
<ul class="simple">
<li>Wednesday: Tired</li>
<li>Draw a Box: Didn't do as much as usual</li>
<li>Friday: Got back into coding a little</li>
<li>Saturday: Thinking about various future projects</li>
<li>Sunday: Decided to put hard work off until I'm more reliably awake</li>
<li>Monday: Tired</li>
</ul>
<p>I also spent Monday, the day I'm writing this, the day before the date on these things (well, that's not confusing), pointedly not being on tumblr, which may or may not have accomplished anything.</p>
<p>Next week, I want to start trying out coding to see where the spec is falling short for me.</p>
Diary 2018-12-172018-12-17T05:00:00-05:002018-12-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-17:/diary-2018-12-17<p class="first last">Get a little bit done, then go fall asleep.</p>
<p>An approximate breakdown of today:</p>
<ul class="simple">
<li>Being tired</li>
<li>Playing Fez</li>
<li>Jotting down more ideas for later</li>
<li>Being somewhat ill</li>
<li>Finding books to read later</li>
</ul>
<p>When I get around to the books, I'll probably do one-off entries reflecting on things when I reach stopping points.
I think I have some bad, or at least counterproductive, habits around reading, and I think explicitly reflecting on things would curb some of the worst bits.
This is similar to something I think I mentioned a few months ago, where I was reading <em>Ficciones</em> in Spanish, for reasons, and I noticed I was doing much better at comprehension when I read it out loud, then realized this was also something to keep in mind for stuff like RPG rulebooks.</p>
<p>I just now tweaked the tic-tac-toe spec, and I'm kind of feeling like, why don't I try using it now, and see where it falls short?
Like, not <em>right now</em> now, but soon.</p>
<p>Super excited for not having such short days in a few weeks.
Good night everyone.</p>
Diary 2018-12-162018-12-16T05:00:00-05:002018-12-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-16:/diary-2018-12-16<p class="first last">'m tired...</p>
<p>I did a little more work on Cryptopals, and thought about the functional spec.
I think a lot of the stuff I'm trying to work on right now requires reading explanatory materials while I'm all the way awake, which is kind of hard to do this close to the solstice.</p>
<p>I think I'll pivot thus:</p>
<ul class="simple">
<li>Mostly write up ideas for my future self to draw or write.</li>
<li>Put together a reading list for when I'm more conscious; I'll see how I feel in the first weekend in January.</li>
<li>To the extent that I'm working on functional specs, switch to iterating on <em>Vislav Peterson and the Island of Gold</em>, because that's a much less demanding spec in terms of depth.</li>
</ul>
Diary 2018-12-152018-12-15T05:00:00-05:002018-12-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-15:/diary-2018-12-15<p class="first last">COMPUTERS! *jazz hands*</p>
<p>Yesterday, apparently, Firefox upgraded, removed the live bookmarks feature, and exported my live bookmarks so I could load them into something else.
I had a look in the file.
It was just my Google Reader feed.</p>
<p><em>OOF</em></p>
<p>Poking around videos, I remembered that <a class="reference external" href="https://www.idris-lang.org/">Idris</a> sounded sort of interesting, so let's throw that on the pile of technologies to investigate.
So far as other things to investigate, <a class="reference external" href="https://notebook.drmaciver.com/">David R. MacIver</a> makes some interesting reading recommendations that I think might be really important to informing my writing, when I work on stuff besides this diary-ing/journaling/whatever.</p>
<p>Did a little more to the functional spec.
I think I need to review the guides I found to writing functional specs, to get this into a better state, because it feels like I'm just tossing stuff into it at the moment.</p>
<p>I had more stuff I wanted to put in this entry, but I've forgotten it, because a single browser tab was bringing my computer to its knees.</p>
<p>Oh yeah, it was thinking about machine learning.
I started typing up what I'd had in mind for that topic, and then concluded that actually, I didn't have enough that I wanted to say about it, even by the standards of these blog posts.
Basically, it seems cool, but I don't know of any problems I have, to which it would be a solution.
I'd been thinking about it for image processing, but it seems like learning to draw would work better for the kind of stuff I had in mind.
I think the best thing to do for now would be to start writing down drawing ideas in my art reference folder, so I have something to work with when I get better at drawing.</p>
Diary 2018-12-142018-12-14T05:00:00-05:002018-12-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-14:/diary-2018-12-14<p class="first last">All sorts of coding and command-line stuff.</p>
<p>Ugh, I messed up my right arm somehow.
So I'm writing this while contorting in order to hopefully stretch out the tendons.</p>
<p>Anyway, I got Pijul working.
I'd like to find the source for the Pijul book, because I think it needs some updates.
Also, now that I've heard of <a class="reference external" href="https://linuxwit.ch/blog/2018/12/e98e/">e30e/e98e</a>, I kind of wonder what the Nest's policy is on that kind of boundary-pushing/art.</p>
<p>All that aside, I got a Pijul repo going, and since I have PICO-8 right here on my machine, I stuck an empty PICO-8 project in the repo, and committed it.
This was slightly tricky, since I don't know how to navigate outside of PICO-8's save location from within PICO-8, so I made a softlink in the save location, into the repo, and this seems to work.
Once I established that this works, I stopped touching the repo, and did some sketches yesterday.
It turns out that, even though it's easy to describe tic-tac-toe and set it up on paper, doing so relies a lot on human intuition and the physical properties of paper itself, so I need to formalize that.
I feel like the various people online saying "do tic-tac-toe to start with" are missing emphasizing that point: <strong>when making a video game, you need to, somehow or other, get the internal state of the game to show up on the screen in a way that the player can interact with; without this, there kind of isn't a game; thus, you might as well start with a ruleset that is relatively simple, and has a completely canonical form</strong>.
Once I've got the display working, I could look into making 4 by 4 by 4 by 4 draft misère version, or trying to implement other simple turn-based games on a grid.
Alternatively, look into things besides PICO-8 because I assume it's still hard to make big games on it, so I'd like experience with other systems.</p>
<p>Before any of that, I need to get the stuff I sketched off paper and into documentation.
That's something that I need to work on: making systems that actually work is about doing the paperwork needed to make sure I'm not breaking them, or creating a broken design.</p>
<p>That being said, I also got back into trying to solve <a class="reference external" href="http://cryptopals.com/">Cryptopals</a> challenges.
(Huh, no ssl. That feels ironic.)
I'd been away from them for apparently almost a year, because I'd hit a mental block on how to express the prerequisites they wanted me to write for one challenge.
See, I've been writing the solutions to different challenges as command-line tools, and that ceases to make sense in challenge 12, so I've been kind of stalled out for a while.
But, I changed up the interface, and now it's just a question of how to <em>consume</em> it.
For all that I was implying that I'm just doing whatever here, I think I'm going to need to sketch stuff out for this, as well, because the logic involved is complicated.</p>
<p>I've got nothing more for now, time to get back to getting through life, in this case by going to sleep.</p>
Draw a Box 2018-12-132018-12-13T05:00:00-05:002018-12-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-13:/draw-a-box-2018-12-13<p class="first last">The ghosting felt pretty cool, at least.</p>
<p>In this post:</p>
<ul class="simple">
<li>This was just not my week.</li>
</ul>
<hr class="docutils" />
<p>Since I stopped paying attention to sheets (and noticed I hadn't updated this in a while, so I went back and at least made it not wrong), I have drawn:</p>
<ul class="simple">
<li>A bunch of freehanded circles on December 6. I managed my time poorly, so I was too tired for proper practice. I seem to have mistreated the pen I was using enough that now the other one in the same size seems better. I guess I'll end up ping-ponging between these pens.</li>
<li>I did more ghosting on December 7. Because I've got experience now with the perspective exercises, I decided to make the exercise a little more elaborate: given a start point, an end point, and two other points such that the line through them intersects with the line <em>segment</em> through the start and end points, draw only the straight line between the start point and the intersection point. It's quicker to do than it is to deal with that explanation.</li>
<li>I packed up my art supplies for an out-of-town trip, then forgot to actually take them out the door with me, on December 8. Whoops. I'm going to track down references for later.</li>
<li>I got back on December 9, wiped out, and resolved to catch up for the weekend on Monday.</li>
<li>I freehanded a bunch of circles on December 10. I think I should make some templates to print out for the exercises that have a bunch of setup, since I don't see drawing the grid as part of the exercise, and I end up putting it off because I don't like it.</li>
<li>I did a little bit of organic forms on December 11. Apparently, even though convoluted shapes are fun, I've only really got the hang of portraying depth with relatively simple shapes. I made some templates also, like I said, but I have yet to get them to print cleanly, so they're not usable.</li>
<li>I got a template printed and did some circle and ellipse drawing on December 12. Then I started sketching UI stuff for tic-tac-toe. Having to actually think about how game objects get put in front of the player is something I haven't really done, having mostly fallen back on text-based layout. Sketching this stuff out is a good way to see the depth in creating a game that doesn't come from elaborate rule systems or fancy algorithms and data structures, which is where I'm drawn to if I'm not careful.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will hopefully be a bit better.</p>
Diary 2018-12-122018-12-12T05:00:00-05:002018-12-12T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-12:/diary-2018-12-12<p class="first last">With the way these are getting, I hope this is something I can blame on the seasons.</p>
<p>I was really tired today, so I didn't accomplish much.</p>
<p>I mentioned trying to put together a small spec, and I decided to just keep on implementing tic-tac-toe until I can control my scope creep.
I've got the beginning of a functional spec, but it needs to be properly sketched in.
Hopefully, I'll get it done soon, and then I can start messing with fantasy consoles, since I'd rather not roll my own UI yet.</p>
<p>That's about it.
Really sleepy.
Good night.</p>
Weekly Roundup 2018-12-112018-12-11T05:00:00-05:002018-12-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-11:/weekly-roundup-2018-12-11<p class="first last">It'd be nice to have a week that leaves me feeling like I can remain upright afterwards.</p>
<p>I didn't fill these out as I went because I am a fool.</p>
<ul class="simple">
<li>Wednesday: I rambled about functional specs and game news.</li>
<li>Draw a Box: I noticed I was doing things wrong, and started reviewing earlier exercises.</li>
<li>Friday: I rambled about the kind of culture the laws in America seem to be meant to cultivate.</li>
<li>Saturday: I rambled about game news, news in general, and functional specs.</li>
<li>Sunday: I rambled about a <em>Hellraiser</em> movie.</li>
<li>Monday: I listed software and libraries I'd like to do something with, provided I had a functional spec to work with so I'm not totally at a loss.</li>
</ul>
<p>Next week, I don't have anything in mind.
Maybe come up with something simpler than <em>Untitled Wagon Game</em>, and spec that.</p>
Diary 2018-12-102018-12-10T05:00:00-05:002018-12-10T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-10:/diary-2018-12-10<p class="first last">Notes to my future selves.</p>
<p>I had a packed day today, so I'm going to go even lower-effort!</p>
<p>I've run across various bits of software that sound interesting, but I haven't used, or haven't used them to their fullest potential.
Maybe it would be handy to have a list.</p>
<ul class="simple">
<li><a class="reference external" href="https://www.mindforger.com/">Mindforger</a>: I ran across this oddly Spider-man-themed notebook app reading someone's posts on Mastodon. Looking at my current horrifying pile of Sublime Text windows, and the fact that I moved most of my desktop items into a folder called "a lump under the carpet", I'm interested in more organized note-taking, which this sounds like it could maybe offer? I don't have a good idea yet of what kind of initial investment is required to get started.</li>
<li><a class="reference external" href="http://alloytools.org/">Alloy</a> and <a class="reference external" href="https://lamport.azurewebsites.net/tla/tla.html">TLA+</a>: I'm putting these together even though they're distinct software, because I don't intuitively grasp the differences between them on various axes. They're both tools for working with specifications of system behavior, and verifying that properties hold, and generating counterexamples if not.</li>
<li><a class="reference external" href="https://pijul.org/">pijul</a>: I've mentioned pijul before. It's a version control system that uses a different underlying model than git or mercurial, which has various claimed benefits. I've only been able to install it since the latest release came out, and I had problems using commands recommended by the documentation, so I kind of bounced off it for now.</li>
<li><a class="reference external" href="https://pybee.org/">BeeWare</a>, <a class="reference external" href="https://kivy.org/">Kivy</a>, and <a class="reference external" href="https://logicaldash.github.io/LiSE/">LiSE</a>: Another set of somewhat related things: BeeWare, I heard of recently, and Kivy, I heard of earlier. Both are cross-platform toolkits for user interfaces in Python. LiSE is a game engine built on top of Kivy. LiSE sort of sounds like it would be good for some of the game ideas I've had, but I'm not really sure.</li>
<li><a class="reference external" href="https://hypothesis.works/">Hypothesis</a>: I've used Hypothesis to generate tests some, but not enough for my tastes.</li>
<li><a class="reference external" href="https://cosmic-ray.readthedocs.io/en/latest/">Cosmic Ray</a>: I haven't used this any, but it sounds interesting. It's for mutation testing, which basically tests the usefulness of your test code.</li>
<li>While I'm mentioning tools for evaluating tests, the <a class="reference external" href="https://pypi.org/project/coverage/#history">Coverage alphas</a>, which provide the "who tests what" feature.</li>
<li>Machine learning libraries. Not listing any because there are so dang many, it seems like.</li>
<li><a class="reference external" href="https://www.puzzlescript.net/">PuzzleScript</a>: I've used it some; I created a set of thematically-motivated rules for a game, then never made any levels for it; dunno if that's still accessible, and I think I also made a tic-tac-toe game, which was great because previous attempts have fallen to feature creep.</li>
</ul>
<p>Probably other stuff I'm forgetting right now.</p>
<p>PS: I was forgetting <a class="reference external" href="https://github.com/paladin-t/fantasy">fantasy consoles</a>, in general.</p>
Diary 2018-12-092018-12-09T05:00:00-05:002018-12-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-09:/diary-2018-12-09<p class="first last">Horror movie nitpicking again</p>
<p>We watched <em>Hellraiser: Hellseeker</em> last night, and it's one of those movies where even though it's full of gore and mutilation and blood, I'd be hard-pressed to call it a horror movie, because it's overall just so absurd.
I can accept that they were trying to make a horror movie, and they wanted it to have a twist, it's just, I guess it came out kind of half-baked.</p>
<p>Before getting into talking about the details, it seems to me like maybe 2002 was the year of <a class="reference external" href="https://meninblack.fandom.com/wiki/Scrad">characters with CGI stalks somewhere that end in another head</a>.
Also, at a very high level, <em>Hellseeker</em> is like if <em>Inferno</em> tried to be more connected to the earlier movies, and also failed to make sense in different ways.</p>
<p>Ignoring "plot-hole" type complaints, I think the big things that get in the way of appreciating the movie as anything other than schlock are:</p>
<ul class="simple">
<li>The twist is certainly a revelation, but it doesn't really feel like a payoff.</li>
<li>It's nevertheless pretty easy to figure out about where they're going with the plot, and the movie is more tedious, the more knowledge you have that it thinks you don't. What I mean to say is, it doesn't really deliver on things from a dramatic irony perspective.</li>
</ul>
<p>The big twist is that the movie starts out as a story that the main character is telling himself about his life, using a mish-mash of memories from different times.
However, the fact that things don't really match up temporally doesn't really come through—it has to be worked out after the twist—and I feel like the movie could have done so much, in with the weird stuff that they did show (I don't know what the point of the surgery scene was (yes I do, it's because this movie wants to be <em>Jacob's Ladder</em>)), to hint at the fact that we're watching an unreliable narrator construct the events around him. I feel like there's a lot that could be done with that, and basically all we get is sometimes scenes look different in flashback.</p>
<p>Now I'm thinking about the comparison between <em>Jacob's Ladder</em> and these last two <em>Hellraiser</em> movies we watched.
<em>Inferno</em> and <em>Hellseeker</em> are pretty similar, in terms of wanting to be <em>Jacob's Ladder</em>, except the viewpoint character's arc ends on a down note.
It's like they decided that, they'd better have a downer ending, even if that's not what <em>Jacob's Ladder</em> did.</p>
<p>I was trying to take that further, and it kept on ending up at complaining about plot holes, so I'm going to try to take a broader perspective.
I feel like there's a particular kind of ambition in <em>Hellraiser</em> and <em>Hellbound</em>, that came through in the effects and the sets, that I feel is absent in the later entries I've seen, and that's kind of disappointing.
I'd hold out hope that later entries will reclaim it, but looking at plot summaries, that seems unlikely.
What it comes down to is, I get the feeling that the first two movies were much more about craft and visuals than the later movies.
While there are still depictions of weird, fantastical things in those movies, I feel like the camera takes a more passive role in depicting them as the series goes on.
Less "okay, let's move the viewpoint around in ways that should make no physical sense" and more "okay, the effect is here, let's point the camera at it and go".</p>
<p>When I think about these kinds of differences, the way we're watching open-ended series in release order is pretty arbitrary.
It's just like, there are a lot of movies out there, here's one way to organize them, let's go.</p>
<p>Hmm...
I'm not trained as a critic.
I do know when a horror movie trying to be serious makes me laugh.
All of this dissecting of movies has me thinking again, that I'd like to get better at creating.
It's late, but the bathroom is taken right now, so I'll get on researching creative pursuits.</p>
Diary 2018-12-082018-12-08T05:00:00-05:002018-12-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-08:/diary-2018-12-08<p class="first last">It takes real effort to be positive in this climate...</p>
<p>I kept on thinking I had an idea for a post today, and having it not come together.
Oh well!
Grab-bag time.</p>
<p>I'd been mostly unaware of what Epic is up to, so, having now seen some semi-recent Twitter output from Tim Sweeney, please assume until further notice, that my reaction to any game storefront being in the news for any reason is a pained grimace, half-heartedly twisted into an attempt at a neutral expression.
I want things to improve, but there's so much news that's really hard to read, and this isn't even all the stuff that isn't video games...</p>
<p>I'm kind of at a remove from world news, I guess as kind of a reaction to getting a small bit of news firehose from Twitter, which is part of the reason I'm not really on it any more.
But, like, it's obvious that there's so much horrible, stupidly horrible stuff going on in the world, and it seems like so much of it doesn't happen for any kind of a good reason.
So many events that seem completely contingent, adding up to senseless and unprovoked killings, and that's just the worst of it...</p>
<p>I don't like being a downer like that.
I want to find some way to turn things around, but I don't see how I could single-handedly do anything big, so I guess I need to look for big things I can help with, and little things I can do.</p>
<p>I need to find something, and as cool as doing stuff with code can be, I think I'm concluding once again that I have to look into the Romance Instrumentality project more.
I've got that all set to start commenting on the blog posts I copied.
Speaking of stuff in the functional specs, I've got I think all of the syntax-related stuff from the blog copied in, though I think there's more stuff that might be relevant, like the blog posts mention writeups, which I <em>think</em> are in the package itself.
I've got to find those, and then I can really get into these things.</p>
<p>But, for now, romance novels.</p>
Diary 2018-12-072018-12-07T05:00:00-05:002018-12-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-07:/diary-2018-12-07<p class="first last">Hashtag-TheGunIsGood</p>
<p>Diary because I don't want to try to get this to the rough-draft quality of my usual free-topic things...</p>
<p>On the heels of what is, according to an anonymous source, the culmination of months of effort on tumblr's part, to secure greater ad revenue by angering vocal segments of their userbase, now I'm hearing about new policies from Facebook.
Policies that sound like an attempt to program an old-timey expert system to hate sexuality.
Like someone trying to write ordinances using an uncooperative deck of old Magic: The Gathering cards.
Like a neural network read nothing but manifestos.</p>
<p>Okay, enough attempts at evocative dunks.
Point is, thinking about these various social media companies' track records with sexuality and violent ideologies, and some other dunks I made on Facebook's policies (which, maybe they're all like that, I wouldn't know), I realized what this is all reminding me of.</p>
<div class="youtube youtube-16x9"><iframe src="https://www.youtube.com/embed/YOROvO2fxTc" allowfullscreen seamless frameBorder="0"></iframe></div><p>I'm having a lot of trouble articulating exactly what I'm feeling here, but pretty much, this scene (I have not seen Zardoz, so I can't speak to the rest of it) feels like it's ended up way too relevant.
While the dichotomy from Zardoz is simpler than what we have out here in the real world, there's still a lot of related forces, against, like, bodily and emotional autonomy, and in favor of easy answers and the feeling of power.</p>
<p>My only answer to all of this, so far, is to get more voices out there, and for me, I guess that means continuing to practice art and prioritizing the Romance Instrumentality Project.
Why don't I start putting together reference materials for that now.
No synthesis yet, just turning them from random browser tabs into a document to improve.
Okay, that's the easiest stuff out of the way.</p>
<p>I don't know how much chance I'll have to work on stuff in the near future—this weekend sounds a little hectic—but I've got goals.
For now:</p>
<ul class="simple">
<li>Paste in my blog posts for Python Augmented and Structured Data</li>
<li>Add comments (in Drive, not on the blog) to the blog posts I copied into the new romance spec</li>
</ul>
Draw a Box 2018-12-062018-12-06T05:00:00-05:002018-12-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-06:/draw-a-box-2018-12-06<p class="first last">Oops.</p>
<p>In this post:</p>
<ul class="simple">
<li>I get corrected by the course.</li>
</ul>
<hr class="docutils" />
<p>Since I finished the <strong>???</strong> sheet, I have drawn:</p>
<ul class="simple">
<li>Finished the eighteenth sheet on November 29.</li>
<li>I've covered the nineteenth sheet in iffy attempts on November 30. Looking over the site in more detail, I've realized that, as was probably obvious to people more familiar with the intended usage of the Draw A Box lessons, I was doing this kind of wrong. Therefore, when I finish this sheet, I'm going to then go back to the beginning and review things. Not more sheets, but revisiting the exercises. Once I work my way back up to organic forms, and do two more full sheets of those only, I'll continue on in Lesson 2.</li>
<li>I filled the nineteenth sheet on December 1. I think I started doing better than yesterday, but I don't really know. Tomorrow, instead of moving on, it's time to refresh the basics.</li>
<li>I traced through lines and doodled organic forms on December 2. Contra the organic forms advice, it seems to me like somewhat complicated forms are the way to go, because the greater visual interest makes it easier for me to ascribe depth to them.</li>
<li>I freehanded lines on December 3, and forgot to write it up that day.</li>
<li>I drew planes, then put ellipses in them, on December 4. I'm going to have to revisit these exercises later; I think I can do better on both.</li>
<li>I drew some circles inside rectangles on December 5. I'm seeing a need to come back to this exercise and do more of the freehand circle stuff, so I guess that's where I'll be for a bit.</li>
</ul>
<hr class="docutils" />
<p>Next week, I keep on reviewing the basics.</p>
Diary 2018-12-052018-12-05T05:00:00-05:002018-12-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-05:/diary-2018-12-05<p class="first last">It's been a few days.</p>
<p>I've been gradually moving writeups and ideas into the functional specs.
According to the dates I put on these things, I copied all of the OMICE posts into the spec, so I can just drag stuff around in it later.
I also made some tweaks to a spec for a conlang focused around the interaction of some non-English features.
I think the quick hits to go to from here would be Python Augmented and Structured Data.</p>
<p>I'd like to think that I'd have gotten more done if I hadn't been distracted by the mass exodus from Tumblr.
I've got so many accounts on so many services to start following, and some people, like Prokopetz, don't even know where they're going yet!
It's a huge mess, and it sloshed out to me even though I don't post on tumblr any more, really.</p>
<p>Anyway, in other random news, I guess Epic is launching its own storefront.
I'm interested in seeing competition on revenue split.
I've heard confusing things about what games they will and won't allow, and the chart in their announcement story feels off; like I think I read someone interpreting it as "Epic will also cover Unity fees", which I'm fairly sure they didn't say they'd do.
Regardless, this should shake things up, hopefully in a good way.</p>
<p>In the end, thinking over the last few days, I guess I can't hold out for a totally serene week with no distractions, so I'll just focus on doing what I can in response to what happens.</p>
<p>PS: I tried to clean up my desktop, and that turned out to break my publishing pipeline, because I guess it's held together with spit and pipe cleaners.</p>
Weekly Roundup 2018-12-042018-12-04T05:00:00-05:002018-12-04T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-04:/weekly-roundup-2018-12-04<p class="first last">I don't like paperwork.</p>
<ul class="simple">
<li>Main project: I started doing functional specs, and felt so much promise that I'm redoing my schedule in response.</li>
<li>Draw a Box: I got up through the organic forms exercise.</li>
<li>Free-Topic: I ranted about B-movies and Victorian(?) poetry.</li>
</ul>
<p>Next week, I'm switching to free-topic/diary instead of projects, to devote more time to the functional specs.</p>
Functional Specifications - Retrospective 2018-12-032018-12-03T04:00:00-05:002018-12-03T04:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-03:/functional-specifications-retrospective-2018-12-03<p class="first last">I've decided to do this more.</p>
<p>In this post:</p>
<ul class="simple">
<li>My feelings on the last week.</li>
<li>How well I followed the plan.</li>
<li>Musings on long-term goals.</li>
</ul>
<hr class="docutils" />
<p>Since the last entry, I pulled more stuff into the <em>Untitled Wagon Game</em> spec, and added another spec, this time for a conlang.
I also got the bulk of the paperwork figured out; just need to ask a few questions, and I can work out what remains.
The worst bit was not having a decision.</p>
<p>I spent much of last week under way too much stress, but I did inch along with this functional specification stuff, so that's good.</p>
<p>My plan was just "write a bunch of these specifications" and I at least got started on a bunch of them, but I've got a lot more information to pull in.</p>
<p>I want to avoid taking on projects without a specification for now (though sometimes the specification kind of is the project), so I'm going to just keep on improving these specifications for now.</p>
<hr class="docutils" />
<p>Next week, I think I should switch into diary mode for the foreseeable future.</p>
Functional Specifications - Workflow 2018-12-022018-12-02T04:00:00-05:002018-12-02T04:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-02:/functional-specifications-workflow-2018-12-02<p class="first last">It's <em>like</em> progress</p>
<p>In this post:</p>
<ul class="simple">
<li>I didn't do much.</li>
<li>But it is in another platform now.</li>
</ul>
<hr class="docutils" />
<p>This is the third post in this category which was <em>definitely</em> always spelled correctly.</p>
<p>Anyway, I didn't make much progress because of two factors.
One is that I'm getting used to the idea of having a designated place to put stuff for a project.
This is more mindbending for me than I'd like it to be.
The other is that I'm stressing out about some paperwork.
I'll try to get that cleared up in the morning.</p>
<p>The big thing I did is not terribly interesting: I decided, by gosh, yes, Google Docs probably makes more sense as a platform for this than reStructuredText files.
So, I copied and reformatted the files, and added some design notes to the spec for <em>Vislav Peterson and the Island of Gold</em>.
I've got a window up right now with some disorganized notes that I should get into the spec for <em>Untitled Wagon Game</em>.</p>
<p>I think the fact that I'm kind of reluctant to read my notes says bad things about how much of a point there is to writing them in the first place.
I'll have to try to revise them to make them nicer on me somehow.</p>
<p>I'll try to shove in some more work before the retrospective.</p>
<hr class="docutils" />
<p>Next time, my thoughts on this week.</p>
Diary 2018-12-012018-12-01T05:00:00-05:002018-12-01T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-12-01:/diary-2018-12-01<p class="first last">I need to treat myself better.</p>
<p>Today, I was exposed to a bunch of media that didn't seem interested in respecting people's time.</p>
<p>One was, via MST3K, <em>The Day Time Ended</em>, which is all concepts and no stakes.
People interact with stop-motion aliens and vigorously drawn-on special effects, and the consequences of anything are pretty much opaque until they happen.
Things, that are notionally part of the threadbare thing this movie has instead of a plot, come to a state resembling resolution, without having the decency to involve the process of filming in the transition.
What it comes down to is, they didn't have to try to squeeze all of those ideas in one movie.</p>
<p>I also downloaded <em>The Gallery of Pigeons and Other Poems</em>, by Theo Marzials, a man <a class="reference external" href="https://interestingliterature.com/2018/11/30/the-worst-poem-ever-published-theo-marzials-a-tragedy-analysis/">put up for consideration to be part of the canon of terrible poetry</a>, because apparently I have thresholds where ease of acquisition overpowers taste.
Anyway, perhaps the quality varies enough that, if I were to read it over again, I might come to a more favorable opinion of the title poem than I did at first, but as I was reading about rods of Jupiter and threads of gold and words that I believe are supposed to represent the coos of pigeons, I just wanted to shout at this dead man, "Please! Have a point to the words that you write!"</p>
<p>On a lighter note, we watched Hellraiser: Inferno yesterday.
As some of the critics say, it's good, but it doesn't really seem much like previous movies in the series, even given that the series ended up kind of all over the place starting with 3.
On the other hand, the fact that it doesn't tie itself to the previous movies is a point in its favor; the previous four movies are all kind of their own thing, trying to claim to be consistent with each other.
(The rules set out in 2 are somewhat questionable in their application to 1, the motivations are weird in 3 and 4, and I cannot reconcile the implied character relationships in 4 with anything previous to that movie.)
(The previous parenthetical is giving me dark thoughts, wondering how much of the appeal of sequels is the opportunity to do exactly that kind of nitpicking.
Like, if people are arguing about what your character was doing in 1862 or whatever, offscreen, does that drive Positive Brand Engagement Metrics?
I don't think I'd be surprised if that's the case.)</p>
<p>Anyway, I need something that makes me feel better about myself, like sleep.</p>
Functional Specifications - Skeletons 2018-11-302018-11-30T04:00:00-05:002018-11-30T04:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-30:/functional-specifications-skeletons-2018-11-30<p class="first last">That was, um about it.</p>
<p>In this post:</p>
<ul class="simple">
<li>I was doing other stuff mostly.</li>
</ul>
<hr class="docutils" />
<p>Last post, I said that in addition to <em>Vislav Peterson and the Island of Gold</em> and the <em>Untitled Wagon Game</em>, I wanted to start specs for</p>
<ul class="simple">
<li>OMICE</li>
<li>Structured Data</li>
<li>Object system</li>
<li>Redoing college code in Rust</li>
<li>Python Augmented</li>
<li>Jedi improvements</li>
</ul>
<p>And that's about what I did.
I have a basic skeleton for functional specs, and I made drafts for all of those (and <em>Mirror Scrimmage</em>) that don't really go beyond the skeleton yet.</p>
<p>It'd be cool if I'd accomplished more in two days, but I didn't.
The next steps to take are to collate the data that mostly lives in Three Dollar Quill posts, and write it up in the relevant specs.
I know I have OMICE posts to go in, and I believe I have Structured Data stuff as well, and I'm pretty sure the object system and probably Python Augmented are in there.
I forget if I've ever talked about the Jedi PR I'm working on here, and I don't know if there's much to say about the college code.</p>
<p>Hopefully, I'll have more time to get this together over the weekend.</p>
<hr class="docutils" />
<p>Next time, I'll hopefully have at least associated the relevant long-form discussions to each spec, and beyond that started pulling information into them.</p>
Draw a Box 2018-11-292018-11-29T05:00:00-05:002018-11-29T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-29:/draw-a-box-2018-11-29<p class="first last">Progress</p>
<p>In this post:</p>
<ul class="simple">
<li>Boxes</li>
<li>Blobs</li>
</ul>
<hr class="docutils" />
<p>Since I finished the <strong>???</strong> sheet, I have drawn:</p>
<ul class="simple">
<li>Second quadrant of the fifteenth sheet on November 22. I feel like something's coming across better on the fifteenth sheet than the fourteenth.</li>
<li>Third quadrant on November 23. The little boxes are kind of iffy.</li>
<li>Finished the fifteenth sheet on November 24. On to lesson 2.</li>
<li>Did the sixteenth and seventeenth sheets, arrow exercises, on November 25. I notice these kind of look better to me from a distance, so I guess if I'm going to be doing stuff seriously I need to make sure to do stuff way zoomed in, so all of the wonky-looking stuff is small.</li>
<li>Started the eighteenth sheet, Organic Forms (with ellipses) on November 26. Didn't do much, on the basis of WOW I'm tired.</li>
<li>More on the eighteenth sheet on November 27.</li>
<li>More on the eighteenth sheet on November 28. It should be done soon.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same as the latter half.</p>
Functional Specifications - Planning 2018-11-282018-11-28T04:00:00-05:002018-11-28T04:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-28:/functional-specifications-planning-2018-11-28<p class="first last">I've kind of already started some of these, just not in a nice form.</p>
<p>In this post:</p>
<ul class="simple">
<li>I list out things I want to functionally specify.</li>
</ul>
<hr class="docutils" />
<p>I've written... <em>started writing</em> a few functional specifications for things recently, and I really like it compared to the ad-hoc kind of specifications I did before, and it felt a little nicer than outlines for <em>Vislav Peterson and the Island of Gold</em>.</p>
<p>As such, I want to revisit some old and new projects and start writing functional specifications for them.
For this post, I'm just going to list stuff, not get started, because there's a lot and it's late.</p>
<ul class="simple">
<li>OMICE</li>
<li>Structured Data</li>
<li>Homunculus</li>
<li>Mon Free Retro</li>
<li>Mon Free Journeys</li>
<li>The current Lua object system I'm hacking on</li>
<li>Trying to reimplement some code I wrote in college in Rust, to hopefully give it not-bad performance and design</li>
</ul>
<p>A few that I hadn't been thinking about:</p>
<ul class="simple">
<li>Python Augmented (desperately in need of a spec, oh wow)</li>
<li>Jedi improvements</li>
<li>Linked Seas as a setting document</li>
<li>Conworld Codex</li>
<li>RIP I guess, but I feel like I should get some reading done first</li>
<li>Something I don't think I've posted about, a game idea, working title of <em>Mirror Scrimmage</em></li>
<li>Demiurgent Business</li>
<li>Tiny Music</li>
<li>Shine Whave? Maybe?</li>
<li>The Cabin</li>
<li>Time Travel CCMWG</li>
</ul>
<p>I think the most interesting/useful to go for to start with would be:</p>
<ul class="simple">
<li><em>Vislav Peterson and the Island of Gold</em></li>
<li><em>Untitled Wagon Game</em></li>
<li>OMICE</li>
<li>Structured Data</li>
<li>Object system</li>
<li>Redoing college code in Rust</li>
<li>Python Augmented</li>
<li>Jedi improvements</li>
</ul>
<p>That seems like a fair amount to go on, even if I just end up making skeletons for all of the ones I haven't started, but if I somehow get through all this, I think doing <em>Mirror Scrimmage</em> next would be a nice treat.</p>
<p>I did my drafts for <em>Vislav Peterson and the Island of Gold</em> and <em>Untitled Wagon Game</em> as reStructuredText files, but I wonder if this whole endeavor wouldn't make more sense as Google Docs...</p>
<hr class="docutils" />
<p>Next time, I start making skeletons of these things.</p>
Weekly Roundup 2018-11-272018-11-27T05:00:00-05:002018-11-27T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-27:/weekly-roundup-2018-11-27<p class="first last">I needed a vacation from this vacation LOL.</p>
<ul class="simple">
<li>Main project: I started making puzzles in Opus Magnum, according to a framing story, and then tried writing a functional specification for all of this.</li>
<li>Draw a Box: More perspective exercises.</li>
<li>Free-Topic: We're watching MST3K, and I was tired and didn't want to write much.</li>
</ul>
<p>Next week, I'm not sure, but more functional specifications would be cool.</p>
Opus Magnum - Retrospective 2018-11-262018-11-26T05:00:00-05:002018-11-26T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-26:/opus-magnum-retrospective-2018-11-26<p class="first last">Lots of people take breaks for Thanksgiving. Not me. I put out really short posts, apparently.</p>
<p>In this post:</p>
<ul class="simple">
<li>My feelings on the last week.</li>
<li>How well I followed the plan.</li>
<li>Musings on long-term goals.</li>
</ul>
<hr class="docutils" />
<p>If last week had been any other week, it could have gone better, but that's because the week that it was, was Thanksgiving week, and I was thrown off any semblance of a normal schedule.
Like, hopefully, I actually make it in to work in the morning.
Anyway.
Progress felt incremental overall, but I started in some interesting directions I want to pursue.</p>
<p>This was another week without a clear plan, or an "exploratory" week if I want to feel better about it.
I ended up devising a solid foundation for coming up with puzzles, and applied the functional spec ideas to them.
This is not how I anticipated things going, but, again, it looks really promising.</p>
<p>I think right now I want to view working on the functional spec as important practice that I'll be applying to my constellation of game ideas, and also the Romance Instrumentality Project.
As I see it, there's nothing stopping me from translating a beat sheet into a functional spec, and this is, again again, an idea I think seems worth pursuing.</p>
<p>So far as <em>Vislav Peterson and the Island of Gold</em>, I want to iterate on the functional spec a bit, before I get back into writing.
Once that's done, I want to focus on fleshing out the first two parts.
What strikes me as the biggest potential problem point is the byproduct structures; I want to figure out how to keep them interesting, from a visual perspective, and a synthesis perspective.</p>
<hr class="docutils" />
<p>Next week, eesh, I dunno, maybe I should just functional spec all of the things, try to figure out the boundaries on what's a nail for this hammer.</p>
Opus Magnum 2018-11-252018-11-25T05:00:00-05:002018-11-25T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-25:/opus-magnum-2018-11-25<p class="first last">I did the thing I said I was going to do.</p>
<p>In this post:</p>
<ul class="simple">
<li>I'm writing another spec.</li>
<li>It's cool.</li>
<li>It points to some gaps in my plan.</li>
<li>It's late.</li>
</ul>
<hr class="docutils" />
<p>I just now put together a rough draft of a specification document for this "scenario", <em>Vislav Peterson and the Island of Gold</em>.
It has varying amounts of detail on the different puzzles that will appear in the different parts of the scenario.
It currently lays out times to introduce every glyph except, I think, triplex bonding, which is something I should have in the back of my head.</p>
<p>I think the big thing it's missing, though it doesn't come through in the puzzles, is some kind of arc for Vislav.
I know that I want the last puzzle in the scenario to be some kind of culmination of everything that came before, but I don't know what, in-story, it's supposed to accomplish.
What, in-story, is Vislav working towards?</p>
<p>It's nice that I know to ask these questions, at least.</p>
<p>The fact that it's late and I want to get to bed just won out over my feeling that this post should be longer.</p>
<hr class="docutils" />
<p>Next time, what I thought of this week.</p>
Diary 2018-11-242018-11-24T05:00:00-05:002018-11-24T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-24:/diary-2018-11-24<p class="first last">Is it still a grab-bag if it's mostly a movie reaction that's not substantial enough to merit being called a full entry?</p>
<p>I spent all day doing stuff that I mostly don't intend to write about here.</p>
<p>Scattered thoughts on the first episode of MST3K season 12:</p>
<ul class="simple">
<li>Nobody actually accuses Eric of doing the stuff MAC does. He just kind of assumes they do, for some reason, and nobody reacts to his protestations of innocence.</li>
<li>"You sucked him up into the vacuum cleaner?" Well, when you put it that way, it sounds <em>stupid</em>.</li>
<li>The Mike and Eric interactions are kind of like if <em>Stranger Things</em> possessed no energy of any kind, and you were watching it in Hell. (Is it crass for one Netflix show to directly mention another?)</li>
<li>White Diamond made some questionable career choices.</li>
<li>The strongest impression I have of the movie is that the main criterion for whether the script was done seems to have been, had they shoved in enough unconnected scenes to get the page count high enough?</li>
</ul>
<p>My wife sent me some online roleplaying rules that she wants to try to make into a tabletop thing, but we haven't really discussed them yet.</p>
Opus Magnum 2018-11-232018-11-23T05:00:00-05:002018-11-23T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-23:/opus-magnum-2018-11-23<p class="first last">I seem to have stumbled ass-backwards into a way to improve some skills I want to work on.</p>
<p>In this post:</p>
<ul class="simple">
<li>Guidelines I'm following for this puzzle series.</li>
<li>Puzzles I have so far.</li>
<li>Seat-of-pants planning.</li>
</ul>
<hr class="docutils" />
<p>I ended up coming up with a framing story for the puzzles I'm making, about a ship's alchemist who gets stranded on a mysterious island.
I'm aiming for a somewhat different feel compared to the official puzzles, in which there's a sense in which some reagents are processed into an explicitly "used-up" form.
The other idea I have, which I haven't really written down, or put into practice, is to focus on how certain transformations only go one way:</p>
<ul class="simple">
<li>There's no way to undo the glyph of animismus</li>
<li>There's no way to transmute higher metals to lower metals.</li>
</ul>
<p>So, this alchemist, Vislav Peterson, is going to be working to extract lower metals from gold alloys, and using reagents produced by previous reactions to create "gilded" versions of those reagents to dispose of the gold.</p>
<p>So far, I've done two puzzles, and started a third.</p>
<ul class="simple">
<li>The first is to convert "seawater" to distilled water. My choice for seawater was a water with three salts, evenly spaced. I thought I was making this too easy, but then it turned out to be fiddly, so I think this is a good basic puzzle.</li>
<li>Later on, when Vislav first discovers the gold, he uses an "elemental acid" to extract it from the ore and spin it into wire, creating two depleted byproducts.</li>
</ul>
<p>I've added a puzzle between these, for the synthesis of the elemental acid, but I don't yet have a good idea of what to put in.</p>
<p>I think for most of these puzzles, I want to avoid the glyph of disposal and Van Berlo's wheel.
Vislav does not have access to the last resort.</p>
<p>I was going to put up gifs of my solutions to my puzzles, but these files are big bois, and I don't want to put up images that are larger than every other image I've uploaded, combined.
Maybe I'll make this a GitHub project or something, since the actual puzzles are, in fact, encoded in tiny tiny text files.
Or maybe I'll start using Steam again, but this is the first time I've done anything vaguely like missing it since I stopped, so I'm not ready to go back yet.</p>
<p>Anyway, now that I've proved to myself that writing this framing stuff is good enough to produce puzzles from, I think the next step is to actually flesh it out and figure out where it's going.</p>
<hr class="docutils" />
<p>Next time, maybe I can put together a specification for this stuff like the one for UWG that I, um, started and didn't come back to.</p>
Draw a Box 2018-11-222018-11-22T05:00:00-05:002018-11-22T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-22:/draw-a-box-2018-11-22<p class="first last">It's getting a bit hard for me to perceive progress/needs improvement with this stuff.</p>
<p>In this post:</p>
<ul class="simple">
<li>Perspective practice</li>
</ul>
<hr class="docutils" />
<p>Since I finished the <strong>???</strong> sheet, I have drawn:</p>
<ul class="simple">
<li>Another quadrant on the thirteenth sheet on November 15. I keep on ending up with weird nonsense for these, oh well.</li>
<li>As much as I could of the last quadrant on the thirteenth sheet on November 16. I kind of want to come back to this, but not terribly soon.</li>
<li>One quadrant of Organic Perspective Boxes on the fourteenth sheet on November 17. I feel like I didn't draw enough, so I might come back to this.</li>
<li>Another quadrant on November 18. It's... fine. It's fine. It's fine.</li>
<li>Another quadrant on November 19. I feel like there's some quality in the example that I'm not capturing yet.</li>
<li>Finished the fourteenth sheet on November 20.</li>
<li>First quadrant of the fifteenth sheet on November 21.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same, until I move on to lesson 2.</p>
Opus Magnum - Introduction 2018-11-212018-11-21T05:00:00-05:002018-11-21T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-21:/opus-magnum-introduction-2018-11-21<p class="first last">It looks like I'm going to be coming up with a framing story for this stuff?</p>
<p>In this post:</p>
<ul class="simple">
<li>Opus Magnum Opus Magnum (Exapunks) Opus Magnum.</li>
<li>Some puzzles I made that I didn't like.</li>
<li>Ideas for stuff I want to try doing differently.</li>
</ul>
<hr class="docutils" />
<p>A couple weeks ago, I got back into Zachtronics games, and got Opus Magnum, then beat the main campaign, one of the post-game puzzles, and some of the side puzzles.
(SpaceChem and Opus Magnum have weird menus. I don't remember the other Zachtronics games having so many nooks and crannies.)
Anyway, after enough of that, I eventually started messing around with coming up with my own puzzles.
(I'd try out other people's puzzles, but I don't feel like launching Steam and I can't figure out how else to get them from the workshop, which is kind of annoying given how little it takes to specify an Opus Magnum puzzle.)</p>
<p>(... Like, come on, these things should fit into little badge image things or something, easy. The informational content is about, like, less than a kilobyte, I'm pretty sure.)</p>
<p>Anyway, I've come up with and solved two puzzles so far, and my intent is to design some better puzzles by the time the week is out.</p>
<p>Here's what I have so far:</p>
<ul class="simple">
<li>Given three fire atoms in a row, one bond normal, one bond triplex, create the following three products: two normal bonds of an equilateral triangle of three fire atoms, two triplex binds of an equilateral triangle of fire atoms, and an equilateral triangle of six fire atoms, bonded only on the perimeter, with alternating normal and triplex bonds.</li>
<li>Given a equilateral triangle of fire atoms all bonded normally, create the following product: a hexagon of fire atoms with alternating normal and triplex bonds, with a salt atom bonded to each, straight out.</li>
</ul>
<p>The first puzzle was interesting because I noticed a blind spot in my first solution to it, and was able to switch things around to be more efficient.
It was annoying because it was hard for me to reason about the bond arrangement in the big triangle, and there's no way to interconvert that product with its mirror image, so I had to rearrange things a lot just to make virtually the same thing.</p>
<p>Inspired by the mirror image bond thing, and benzene, I came up with the second puzzle's product, which can interconvert with its mirror image just by rotating.
That puzzle proved annoying because:</p>
<ul class="simple">
<li>I gave myself a three-atom reagent, but the solution I decided on ends up operating on atoms in groups of four, so the timing was really obnoxious.</li>
<li>There's no center atom, so it's confusing and time-consuming to rotate the radially symmetric product.</li>
</ul>
<p>I'd like to take things in a few different directions:</p>
<ul class="simple">
<li>Step away from triplex bonds for now; those things are fiddly.</li>
<li>Figure out something based on metal transmutation.</li>
<li>Possibly work with repeating products. I found that you can have multiple such products in one puzzle, so I've got this idea of having one such product with vitae atoms, and the other with mors atoms, using the glyph of animismus.</li>
<li>Try to draw the reagents from existing puzzles. I'd be interested in something along the lines of "make something with water, alcohol, and some kind of lead crystal"</li>
<li>I'm trying to figure out how to represent mundane substances like smoke, ash, wood, sugar, coal, bone, non-elemental salt. I guess that's leaning towards an aesthetic of "If someone were stuck in the wilderness with a transmutation engine, what would they have to work with, and what would they think to make?"</li>
<li>I need to separate "what capabilities the transmutation engine is supposed to have" from "things a player or puzzle designer can specify".</li>
</ul>
<hr class="docutils" />
<p>Next time, I'll try to come up with and solve something that feels different.</p>
Weekly Roundup 2018-11-202018-11-20T05:00:00-05:002018-11-20T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-20:/weekly-roundup-2018-11-20<p class="first last">I think I might need to re-evaluate things somehow or other.</p>
<ul class="simple">
<li>Main project: I bashed together the prototype of Yet Another Lua Object System (yalos is as good a name as any for it).</li>
<li>Draw a Box: I did more single-point perspective stuff, then started messing with rotated boxes.</li>
<li>Free-Topic: I didn't have much to talk about because I was too sleepy.</li>
</ul>
<p>Next week, I might try making Opus Magnum puzzles and discussing them.</p>
<p>PS I finally got pijul installed, whoo!</p>
Object Systems - Retrospective 2018-11-192018-11-19T05:00:00-05:002018-11-19T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-19:/object-systems-retrospective-2018-11-19<p class="first last">I didn't specify my objective well, but I still basically achieved it.</p>
<p>In this post:</p>
<ul class="simple">
<li>My feelings on the last week.</li>
<li>How well I followed the plan.</li>
<li>Musings on how to make the code better.</li>
</ul>
<hr class="docutils" />
<p>Last week was very finely divided between "hooray, I made good progress on the prototype and tried it out" and "how do I document this? How?!"</p>
<p>I didn't have an overarching plan beyond "get it done" and I just kind of filled things in from day to day, changing things around as I saw fit.
Process-wise, this has some issues, but I'm okay with the results this time.</p>
<p>The code has lots of bits that could be factored out into their own modules to make the main module shorter, but what I'm really feeling stuck on right now is how to document the higher-order functions I've written.
Like, I don't see a nice way to express "and the rest of the arguments are passed into the function which was <em>this</em> argument" or "this function returns whatever the function that was passed into it returns".
I also have yet to notice how to document functables, which is annoying because I'm hitting them hard this time.
I'm going to have to accept that I can't make the documentation much better without figuring out custom templates, because I'm seeing all sorts of potential ergonomic pitfalls in the code I wrote, that can only be handled by getting actual experience with this stuff.</p>
<p>Update: by complaining about this enough, I figured out how to get a good-enough support for types related to higher-order functions.
The result is kind of horrifyingly dense because I can't use spaces, but it seems to make things more obvious than cross-references like I was doing.
I still haven't worked out functables, but I've got a way forward on the other stuff, so that feels good.
(For functables, maybe just... put them next to each other in the doc? LDoc is weird.)</p>
<p>Once I'm happy with the documentation, I need to start writing tests.</p>
<hr class="docutils" />
<p>Next week, dunno yet.</p>
Object Systems 2018-11-182018-11-18T05:00:00-05:002018-11-18T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-18:/object-systems-2018-11-18<p class="first last">Everything about this code is prototypical except for the mental model.</p>
<p>In this post:</p>
<ul class="simple">
<li>It exists now</li>
</ul>
<hr class="docutils" />
<p>I put together most of the functionality I'd decided on, with the main missing bit being validation.
By referring back to a previous, more complicated system, I was able to get the tricky bits done, though I suspect there's some way to make it more parsimonious.
I then put together one of the examples of "things I want to try to do".</p>
<p>I started trying to document it, and that's kind of rocky.
It's a combination of "this file is big and messy and contains some things that should be their own modules", "I'm not sure how best to express the concepts in terms LDoc understands", and "I have so godawfully many tabs open that LDoc's documentation stutters nauseatingly when I scroll it".</p>
<p>Let's look at what I have:</p>
<ul class="simple">
<li><tt class="docutils literal">read</tt> is a utility function that could probably stand to have a better name. It's used to convert a method that takes <tt class="docutils literal">count</tt> wrapped values after <tt class="docutils literal">self</tt>, into one that takes a wrapper after <tt class="docutils literal">self</tt>.</li>
<li><tt class="docutils literal">singleton</tt> is a utility function that I haven't used yet, which creates singleton constants that hook into the object metamethod dispatch system.</li>
<li><tt class="docutils literal">type</tt> is a functable that takes a constructor, followed by a sort-of metatable, and returns a similar functable that uses the provided constructor to create objects with behavior controlled by the sort-of metatable.</li>
<li><tt class="docutils literal">typeof</tt> is a utility function that returns the type of a value, with respect to this object system. <tt class="docutils literal">typeof(type) == type</tt></li>
</ul>
<p>I added some more functions that I haven't tested out, and therefore I'm not really sure about.</p>
<p>Missing functionality:</p>
<ul class="simple">
<li>No validation around method return values</li>
<li>Actually, the method logic is half-implemented, at best (UPDATE: I did it)</li>
<li>singletons shouldn't be given their wrapped values, which conceptually do not exist</li>
<li>Actually, actually thinking about singletons has me thinking they need some special-case logic everywhere, which isn't really much of a hardship.</li>
<li>But I'll hold off on that until I actually try to use them. I mean, maybe the way to go is to just use <tt class="docutils literal">read(0, <span class="pre">...)</span></tt></li>
</ul>
<p>I think what I need to do is try to apply this library to basic code challenges.
And sleep.
I really need to sleep.</p>
<hr class="docutils" />
<p>Next time, what I thought of this week.</p>
Diary 2018-11-172018-11-17T05:00:00-05:002018-11-17T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-17:/diary-2018-11-17<p class="first last">I overextended myself, time to crash.</p>
<p>I tossed together a custom puzzle in Opus Magnum, and solved it two different ways.
This was pretty cool, but I could go for puzzles from other people, probably.</p>
<p>I ended up getting way too caught up in the object systems thing to write up much else tonight.</p>
<p>And besides that, I seem to be exhausted.
I'm going to just do the daily drawing exercise, then go sleep.</p>
Object Systems 2018-11-162018-11-16T05:00:00-05:002018-11-16T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-16:/object-systems-2018-11-16<p class="first last">Deciding not to do things is great, because it means suddenly I have less work to do.</p>
<p>In this post:</p>
<ul class="simple">
<li>Changing plans, cutting ideas</li>
<li>A grab-bag of desired features</li>
<li>Applications I have in mind</li>
</ul>
<hr class="docutils" />
<p>Another late Friday post...</p>
<p>On further reflection, it's a bad idea to attempt an "everything is an object" system in Lua without creating an entire runtime to deal with it.
As such, I'm going to restrict the scope of the current idea/project to dealing with wrapped values, basically putting forward composition as much as possible.
There are two special cases I want to account for in my current ideas on accmplishing this stuff.
One is that ideally there should be a fast path for objects that wrap a single value.
The other is that it should be possible to create singleton objects that don't have a constructor or track internal state.
It'd also be nice to memoize the wrapping functionality.
I'll see how far I can get without parametric types, but I'll probably be thinking about introducing them, we'll see.</p>
<p>So, I'm currently focused on generic wrapping, which means I'll relax the "everything is an object" stuff at least enough to mitigate the need for specific boxed types.</p>
<p>Here's what I have in mind for all of this stuff:</p>
<ul class="simple">
<li>All objects are empty tables with the same metatable.</li>
<li>objects are constructed by calling types, which are objects that wrap a table and optionally a constructor.</li>
<li>types with no constructor are singletons, and are considered to be instances of themselves (unless this doesn't work)</li>
<li>"methods" are vanilla functions that take two arguments from the system machinery: one that is just the self object, and one that is the accessor function for the wrapped values; there's a utility function that converts this into filling in a fixed number of wrapped values.</li>
<li>Wait, that means I probably can't do the "fast path" thing, oh well.</li>
<li>The constructor takes no extra arguments, and returns values to be wrapped.</li>
<li>It is an error for a method to return a mutable wrapped value.</li>
<li>Tables, functions, threads, and userdata are assumed to be mutable; booleans, strings and numbers are known not to be.</li>
<li>Can't wrap nil I guess.</li>
</ul>
<p>After the values are returned from the constructor and wrapped up, the wrapped value and the type are associated with the new object.</p>
<p>Let's look at the kind of stuff I want to prototype with this whole idea:</p>
<ul class="simple">
<li>Wrapped values representing absolute positions, relative positions, and scaling factors</li>
<li>Wrapped values representing dimensioned quantities</li>
<li>Wrapped values representing oriented quantities</li>
<li>Wrapped values representing vectors and matrices</li>
</ul>
<p>Basically, I want to prototype some of the stuff I've been trying to do in Rust, and try actually applying it to something before trying to optimize.</p>
<hr class="docutils" />
<p>Next time, I'll try to get the basics of all of this working.</p>
Draw a Box 2018-11-152018-11-15T05:00:00-05:002018-11-15T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-15:/draw-a-box-2018-11-15<p class="first last">I might be outstripping my training...</p>
<p>In this post:</p>
<ul class="simple">
<li>It all comes tumbling down tumbling down tumbling down...</li>
</ul>
<hr class="docutils" />
<p>Since I finished the <strong>???</strong> sheet, I have drawn:</p>
<ul class="simple">
<li>I finished the first quadrant of the second single-point exercise on November 8.</li>
<li>I did the second quadrant on November 9.</li>
<li>I did the third quadrant on November 10. I thought it'd be instructive to see how well the lines I'd drawn by eye line up, and, and... 😰</li>
<li>I finished the... twelfth sheet? on November 11. I kept on checking the lines, and I think I did a little better than yesterday? Tomorrow is going to be a Whole Thing.</li>
<li>I started on what is apparently the thirteenth sheet on November 12. My attempt at starting off this exercise, Rotated Boxes, is <em>turbo nonsense</em>, and I'm trying to work out if that's going to be a problem.</li>
<li>I filled in one quadrant on the thirteenth sheet on November 13. Quoting from the webpage: "If your drawing comes out terribly, but you learned a lot from the process, then I consider that a win." So maybe I can still salvage this...</li>
<li>I think I filled in another quadrant on the thirteenth sheet on November 14. It's hard to be sure, because I seem to be drawing non-euclidean vector puke, and there are confusing discontinuities.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same, I guess?</p>
Object Systems 2018-11-142018-11-14T05:00:00-05:002018-11-14T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-14:/object-systems-2018-11-14<p class="first last">Going back to the well of complicated stuff of probably-limited utility.</p>
<p>In this post:</p>
<ul class="simple">
<li>More code-related stuff!</li>
<li>I stretch the definition of "inheritance" beyond what anyone should recognize.</li>
</ul>
<hr class="docutils" />
<p>I've got an urge to mess with object libraries again.
I think I didn't write up the last time I did this, but the main challenges come around to design, again.</p>
<p>My goal this time is to set something up based around newtype wrappers and parametric types.
The idea is that a given underlying representation of an object can have different behavior in different contexts, mostly within that object's own methods.
The idea is that "inheritance" works very differently in this library, compared to most languages.
I'll also try going for "everything is (boxed) objects" within the context of the library, and see how that works out.
This requires a small collection of wrapper types.
The hierarchy will have multiple roots, so there'll be a special constructor for root classes around optimized ("optimized") representation, but the initial set of roots will just be, like, table, function, number, string, coroutine maybe.</p>
<p>A boxed value can have its underlying representation looked up, and it has an associated type, which is a subtype of functions, or possibly tables, or maybe specialized shapes.
Building this kind of self-referential hierarchy is fun.
I get to pretend it's like assembling an airplane around myself in midair, but it's not really, I guess.</p>
<p>Anyway, the idea is that each box type exposes the functions on its associated table as rewritten methods, but here's the key: "inheritance" is only structural, so method names don't propagate, so they can't conflict.
I'll maybe want some form of automated delegation, but that's an ergonomics concern, not a completeness concern.</p>
<p>A type is several fundamental things:</p>
<ul class="simple">
<li>A constructor function</li>
<li>Metamethod hooks</li>
</ul>
<p>In other words, a function that creates the underlying data, plus a table to be used in metamethod lookup.
It's not a metatable precisely, because I plan to have all objects use the same metatable, and just interact with the metamethod hooks.</p>
<p>Thinking about this, it seems problematic to wrap the table functions into table methods.
I guess to deal with it, it'd need, like, get and set methods instead of forwarding <tt class="docutils literal">__index</tt>.
Which is fine.</p>
<p>Since I cannot figure out how to do that "optimized representation" idea, I'm going to have to scrap it.</p>
<p>One thing that I'd really like to try out around Lua-related experimentation is Pijul, a new version-control system based on patch algebra.
It sounds really cool, but I wouldn't know, since the current release doesn't install, and I have no idea when the next release comes out.
The specific application I'd like to try out is taking the tiny Lua modules I always end up writing in projects, like a function to make ephemeron tables, and just merge it into any Lua project I do that needs it.</p>
<p>Last-minute thought: as I think about this more, I might want some way to do "multiple inheritance", and I think I see a way to pull it off.</p>
<hr class="docutils" />
<p>Next time, I'll sketch out some use cases and invocations</p>
Weekly Roundup 2018-11-132018-11-13T05:00:00-05:002018-11-13T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-13:/weekly-roundup-2018-11-13<p class="first last">I feel like maybe I didn't write much of substance...</p>
<ul class="simple">
<li>Main project: I tried to put together a design document in less than a week, which turns out to not be nearly enough time, for me at least.</li>
<li>Draw a Box: BOXES</li>
<li>Free-Topic: I made up for all of the time in college I didn't spend stoned off my ass in a dorm room.</li>
</ul>
<p>Next week, I haven't decided, but I want it to leave me time to work on the design document more.</p>
Game Design - Retrospective 2018-11-122018-11-12T04:00:00-05:002018-11-12T04:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-12:/game-design-retrospective-2018-11-12<p class="first last">A week was not enough time.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I think about this last week, all in all.</li>
<li>How well I followed the plan.</li>
<li>Reasonable near-term goals.</li>
<li>Thoughts on further-out improvements.</li>
</ul>
<hr class="docutils" />
<p>My biggest regret about the last week was that the goal I ended up settling on turned out to be too big.</p>
<p>There was no plan as such, but I ended up realizing I needed a design document for... *checks notes* "Untitled Wagon Game".
So I started writing up a design document, and in the course of a few days barely scratched the surface.
Making stuff that isn't just a goofy prototype is brutal.</p>
<p>Anyway, I guess I'll keep on doing that, and when I actually have a full document, I can start doing the thing I mentioned earlier about factoring out prototypes.</p>
<hr class="docutils" />
<p>Next week, I need to find something lower-effort for my posts.</p>
<p>(*Collective groan*</p>
<p>It's free!)</p>
Game Design 2018-11-112018-11-11T05:00:00-05:002018-11-11T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-11:/game-design-2018-11-11<p class="first last">Writing a spec is hard</p>
<p>In this post:</p>
<ul class="simple">
<li>I've started working on a design doc. You can't see it.</li>
</ul>
<hr class="docutils" />
<p>After, ahem, some experiences at work, I'd much rather work too hard on a design document than not hard enough, so I started drafting stuff for, uh, "Untitled Wagon Game".
It's frankly not in a state to show off.
It's got some ideas in it about the art style, the map layout, character creation, tutorial quests, and travel.
It's got some stuff I ought to research later.</p>
<p>What I'm getting from this is that I can't put together a finished design document in just a few hours, which is what I ended up trying to do.
I think if I want to make progress on this, I need to switch into diary mode, so I'm not trying to put out so much in a week.</p>
<p>I'm going to try and do other stuff to unwind now.</p>
<hr class="docutils" />
<p>Next time, what I thought of this week.</p>
Time Travel: Threat or Menace?2018-11-10T04:00:00-05:002018-11-10T04:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-10:/omice-planning-2018-11-10<p class="first last">Both?</p>
<p>In this post:</p>
<ul class="simple">
<li>I keep changing my mind about what should be in OMICE</li>
<li>I attempt to summarize <em>On the Notion of Cause</em></li>
<li>Trying to avoid causal language is <em>really hard</em></li>
<li>Let's tie this into the OMI via time travel</li>
<li>Even handwavier arguments than usual</li>
<li>Stuff that could be in a depressing time travel story</li>
</ul>
<hr class="docutils" />
<p>I'm reconsidering the stuff I'll put in OMICE whenever I get to it; I've currently written nothing, I don't mind admitting.
What brought this on is finally reading <em>On the Notion of Cause</em>, which is recommended by the fascinating blog <a class="reference external" href="https://graphicallinearalgebra.net/">Graphical Linear Algebra</a>.
In <em>On the Notion of Cause</em>, Bertrand Russell critiques a tendency in philosophy to evaluate the natural sciences in terms of their ability to derive statements about <em>cause</em> and <em>effect</em>.
Russell argues that "cause" and "effect" aren't sensible concepts applied to reality at large.
The fundamental nature of physical laws is one of <em>relations</em>, which can, in a sufficiently isolated system, provide a basis for indirect control of an output using an input.
Because it's easier to reason about causal-like systems, we engineer things to behave in a causal fashion.</p>
<p>For an example of a partially isolated system, consider a bubble under some wallpaper.
We expect that pushing down on the bubble in one place will cause the wallpaper to bubble elsewhere, but we usually can't predict where it will end up.
It is... extremely difficult for me to figure out how to describe this stuff without phrasing things in terms of causality.
In terms of predictive power, getting an accurate picture of what will happen in a situation requires close knowledge of the state of the local universe, and the more information you use in the prediction, the less generally applicable the prediction is.
Given a hundred bubbles on the wall, you'd have a rough time coming up with a general answer to questions like "which way will the bubble go".</p>
<p>Okay, that was my attempt to apply Russell's arguments to a different situation, now what does this mean for OMICE?
Well, I'd had some ideas along the lines of "reality behaves more like <em>this</em> than like <em>that</em>, so you should structure your stories more in the former way".
I suspect the consequent is still true, but rather than appealing to reality, I'm going to have to appeal to how people think about the world, which, usually it's hard to tell the difference.
Switching gears to thinking about time travel (the, like, original mission of the OMI), what does <em>On the Notion of Cause</em> mean for reasoning about time travel?
Most obviously, if "cause" and "effect" aren't fundamental to nature, then what can be meant, if anything, by the notion of an "uncaused cause"?</p>
<p>I'm going to try to avoid saying "because" when trying to reason about this, because it makes my head hurt.
When we think about time travel stories, they're normally people messing around in the past of their light cone.
Imagining that we observe this from outside the timeline, we see an unusual path that relations take.
The "obvious" behavior to expect from long-range correlation is some kind of interference pattern; boundary conditions constrain the configurations of matter within the boundary.
Think of it perhaps like a shadow falling on phase space, I dunno.
Yet another hurdle to thinking about this stuff is that closed timelike curves make it hard for me to reason about the symmetries related to conservation laws, probably because I don't actually know enough about Noether's theorem in the first place.
Thinking about it at a very high level, a CTC introduces topological features that reduce the symmetry of the universe, so it must inherently violate conservation laws.
That may have been complete bullshit; all available evidence points to, I am not qualified to make that determination in terms of truth value, so I guess in an <em>On Bullshit</em> sense, it definitely sort of is?
This is why I want to get editors.</p>
<p>Anyway, there was some stuff I wanted to say about a thing I read elsewhere, about the CTC allowing for an overwhelming resonance that disallows the CTC or at least prevents normal matter from entering it, but I can't find it right now, and I absolutely do not trust myself to rederive the argument.</p>
<p>If we pretend that kind of thing doesn't happen, for narrative purposes, then we end up with a situation where several things are at least arguable:</p>
<ul class="simple">
<li>The universe inside the future light cone of the beginning of time travel is a different regime than the outside.</li>
<li>In particular, macro-scale probability is now more tied to feedback loops.</li>
<li>Probability governs much of our lives, including evolution.</li>
<li>So whatever comes out of the portal or whatever, is going to be part of a self-perpetuating feedback loop that could have any kind of creepy relationship with humanity.</li>
<li>I just wanted to write adventure fiction with pretensions of cerebrality, dammit.</li>
<li>Most obviously, the idea of an "arrow of time" gets kind of iffy.</li>
</ul>
<p>Thinking about all of these things, I find myself wondering, in a poor man's poor man's Philip K. Dick kind of way, if the inside of the regime is habitable, what does it look like?
With the arrow of time breaking down, do people sometimes remember the future?
Is there just one self-creating temporal conspiracy or plague, or several competing?
Who's the sap that I, as the author, set up as smart enough to make this possible, and dumb enough to make it happen?</p>
<p>Well, I'll have to think about it later, because it's midnight now, time to publish.</p>
Game Design 2018-11-092018-11-09T05:00:00-05:002018-11-09T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-09:/game-design-2018-11-09<p class="first last">Using the advanced mind-mapping technology of (checks notes) paper.</p>
<p>In this post:</p>
<ul class="simple">
<li>Admitting I published this late.</li>
<li>A summary of my design sketch from last night.</li>
<li>Analysis, and future plans.</li>
<li>I wonder if it's possible to extract information from <em>a lot</em> of bitcoin wallets involved in similar illegal activity.</li>
</ul>
<hr class="docutils" />
<p>Okay, I meant to write this last night, but that wasn't how time shook out.
What I got done last night was to sketch up an idea of what the journey interface could be like.
It's a series of waypoints that represent resting for the night, connected by lines that represent a day's travel.
Each waypoint and connection, including the source and destination, are annotated with a short explanatory snippet.
The connections happen to be such that they'd fit on a hex grid, which might be an interesting way to take the map.</p>
<p>The annotations are short and to-the-point.
They include:</p>
<ul class="simple">
<li>A mundane event while traveling</li>
<li>Minor hardship while traveling</li>
<li>Several quest hooks to revisit later (I think the game should push the player towards completing the current quest before rushing off to fulfill other hooks)</li>
<li>Meeting other caravans on the road</li>
<li>Bandits</li>
<li>Mysterious events with no obvious course of action in response</li>
</ul>
<p>I don't know what's a good proportion of these in an actual game.
So far as length, I want to have what the player sees be short and to-the-point.
Perhaps there's some way to drill down, but I don't think I want to lean on that idea.</p>
<p>I think to build on this, I'd next need to translate this framework—GOD FUCKING DAMMIT I JUST GOT ANOTHER BITCOIN EXTORTION EMAIL (it's from about half an hour in the future)—to an Ink file where I have an approximate category for each step of a journey, and just start filling in stuff for the categories, see what makes sense.
That, and make more of these as I figure out which systems I want to flesh out.</p>
<hr class="docutils" />
<p>Next time, I should look over some actual design documents and figure out how hard to go with this stuff.</p>
Draw a Box 2018-11-082018-11-08T05:00:00-05:002018-11-08T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-08:/draw-a-box-2018-11-08<p class="first last">I'm losing track of this stuff a little bit.</p>
<p>In this post:</p>
<ul class="simple">
<li>A bunch of perspective exercises.</li>
</ul>
<hr class="docutils" />
<p>Since I finished the <strong>???</strong> sheet, I have drawn:</p>
<ul class="simple">
<li>I did a bit more of Plotted 2 Point Perspective on November 1. Sadly, my improvised straightedge is losing integrity, so I should probably switch to a closer-together pair of vanishing points. I also realized today that I was doing the single-point perspective exercise kind of wrong. I was ghosting the non-perspective lines, but I should have been ghosting all of the freehand lines. Doing that should improve the quality considerably.</li>
<li>A little more on November 2. I did some extreme perspective effects, and it's kind of instructive what these kinds of transformations will do to a rectangle. Got me staring confused at the corners of the walls, so that's something, I guess.</li>
<li>A little more on November 3. I'm trying to focus on not drawing extra line right now, just because when I do a thing enough, I start trying to reduce effort.</li>
<li>Finished the second Plotted 2 Point Perspective sheet, then switched back to the first single-point perspective sheet on November 4. The results on that sheet were kind of underwhelming to start with, so I'm going to come back to it later.</li>
<li>Did somewhat better in the third quadrant on November 5. Needs more practice, to be sure, and it'd be nice if I weren't dealing with the time change.</li>
<li>I finished whichever sheet that was, I've lost track, on November 6. I think I'm improving, but there's another sheet to go before I can move on.</li>
<li>I started on the next sheet on November 7, more single-point stuff. I got a late start, so I didn't get a full quadrant done, oh well.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Game Design 2018-11-072018-11-07T05:00:00-05:002018-11-07T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-07:/game-design-2018-11-07<p class="first last">Today came at me fast, so this post is pretty short.</p>
<p>In this post:</p>
<ul class="simple">
<li>The live election results are harrowing, think about games.</li>
<li>Trying to make an extra-fiddly Zachtronics-style game.</li>
<li>More details on the wagon game concept.</li>
</ul>
<hr class="docutils" />
<p>Ever since SpaceChem came out, I've wanted to have some kind of Zachtronics-style game that's more realistic in terms of its fake chemistry, but I haven't had a good idea of how to pull that off while having the result be a "game" instead of a "basically useless clone of Maple [I think]".</p>
<p>The big departure I guess such a thing would bring about is, the waldos can't be grasping arbitrary atoms, and can't have control over orientation.
Related issues include bringing in stuff like entropy and enthalpy, or establishing heat and pressure gradients.
Recycle streams.
Zooming in, there's also the question of process control.
Give players components like PIDs, and stick them on a little Shenzhen I/O-esque board.
I wonder if it would work to have concerns like temperature, but use really big bins to describe them.
How else can I apply discrete mathematics without having the player's machines micromanage each molecule?
I'd also like to develop some fictional chemistry so I don't have to worry about people like me pondering weird bond angles and suchlike.
Maybe try to base it off what I can glean of the Planiverse, and claim that chemistry is two-dimensional now because someone discovered a compactified spatial anti-dimension, and it turns out the resulting physics is nicer for engineering because reasons.</p>
<p>Anyway, I also want to sketch stuff out for the wagon game idea.</p>
<p>For an initial scenario, suppose the players have taken an order to deliver a shipment of furs to a town five days travel away.
The player studies the map, makes a budget, accepts the job, gives the quartermaster the shopping list, then picks up the furs and leaves.
For each of the five days on the road, it's possible they'll get some event related to the road.
For each of the four nights they're in the wilderness, it's possible they'll get a rest-related event.
Events are in mini-cyoa form, and can lead to stuff like changes in supply levels, loss of quest items, stat changes, or curses.</p>
<p>One thing I want is that the character progression is relatively flat, but they are able to get better equipment.
This makes intuitive sense to me.</p>
<hr class="docutils" />
<p>Next time, I'll hopefully have calmed down enough from the election to sketch stuff out on paper.</p>
Weekly Roundup 2018-11-062018-11-06T05:00:00-05:002018-11-06T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-06:/weekly-roundup-2018-11-06<p class="first last">I am not a fan of the DST changeover.</p>
<ul class="simple">
<li>Main project: I made some progress on my implementation of Crafting Interpreters.</li>
<li>Draw a Box: I did some Plotted Two Point Perspective, tried to skip the rest, then switched back.</li>
<li>Free-Topic: I tweaked the site's HTML and style sheets a little. The former is probably not noticeable, the latter, I dunno, it's probably done something?</li>
</ul>
<p>Next week, I sort of want to do some of that reading I worked out earlier, but I also sort of want to sketch out more game ideas...</p>
Crafting Interpreters - Retrospective 2018-11-052018-11-05T05:00:00-05:002018-11-05T05:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-05:/crafting-interpreters-retrospective-2018-11-05<p class="first last">A pretty good week, all in all.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I think about this last week, all in all.</li>
<li>How well I followed the plan.</li>
<li>Reasonable near-term goals.</li>
<li>Thoughts on further-out improvements.</li>
</ul>
<hr class="docutils" />
<p>I didn't precisely have a "plan" this week, the point was just to make some more progress on my Lua version of the Crafting Intepreters stuff.
I feel like this worked out.</p>
<p>I did that, and writing these posts was a helpful kick in the pants to get past some impediments.
There wasn't really a plan beyond that.</p>
<p>I've been reading ahead in Crafting Interpreters, on how the C version works, and it looks to me like, if I'm going to port that to anything, I'm porting it to Rust.
This would be a weird changeup, insofar as it replaces "Lua doesn't have more than a basic framework for exceptions, so I rolled my own" with "Well, I'm not writing <em>that</em> code, since it's in the standard library".
It might actually be quite a different experience, insofar as I'd have to teach myself about stuff that the book barely touches on, like arenas.</p>
<p><em>However</em>, before I do any of that, I want to finish up the AST-based interpreter, write up documentation and tests for it, and then start forking it and experimenting with it.
I might end up porting it to RPython and trying to optimize it that way.</p>
<hr class="docutils" />
<p>Next week, I think I should write about something other than coding.
Whether that's reading stuff, or writing stuff, I'll work that out later.</p>
Crafting Interpreters - Progress 2018-11-042018-11-04T04:00:00-05:002018-11-04T04:00:00-05:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-04:/crafting-interpreters-progress-2018-11-04<p class="first last">Making progress, yes.</p>
<p>As of this writing, I'm most of the way through Chapter 8, stopping just before actually implementing blocks.</p>
<p>Honestly, the biggest points of confusion for me were that I never stripped my "challenge" code out, so the syntax of the language I'm developing has some capabilities that aren't in the book.
I made the call to hold the values inside "cells" instead of storing them directly, because checking tables for <tt class="docutils literal">false</tt> and <tt class="docutils literal">nil</tt> is kind of fiddly in Lua, so it's easier to wrap them.</p>
<p>Right now, I'm reading ahead because it's late and I don't want to touch the code.
Looking at control flow, I see there's going to be C-style loops, which... does Java have those?
Does JavaScript have those?
Does Haxe?
I'm trying to figure out if I have any point of reference for those things.
Like, yeah, they're syntactic sugar, but they're not <em>that</em> sugary?
I'd rather duplicate Lua's paradigm, with only numeric for to start with, and iterator form later.
Although, there are probably a lot of things I'd like to tinker with.</p>
<p>One thing I've wanted to try in PL stuff is having an operator that applies to a function, an unevaluated expression, and a block, or something along those lines, with the idea that this would allow expressing control flow as library functions with syntactic sugar.
Alternatively, a syntax that would support calling functions in that way.</p>
<p>For now, I'm reading ahead, because I want to see what the bytecode interpreter is like, and get some idea of which language I want it to be in.
I'll try to get through reading about classes tomorrow, look at the next section, then circle back to chapter 8.
For now, it's late.</p>
<hr class="docutils" />
<p>Oh, hey, I stopped doing the horizontally ruled section dividing stuff for no compelling reason.
I'd like to bring those back, but I'm sleepy right now.</p>
<p>So, I'll just say that next time, I'll look back over this week.</p>
Site Design 2018-11-032018-11-03T04:00:00-04:002018-11-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-03:/site-design-2018-11-03<p class="first last">Tweaks</p>
<p>In this post:</p>
<ul class="simple">
<li>I trash Semantic UI's documentation a bunch.</li>
<li>I redid the theme.</li>
<li>Oh, huh, my site doesn't have valid HTML.</li>
</ul>
<hr class="docutils" />
<p>At work, the main project I'm on is using <a class="reference external" href="https://semantic-ui.com/">Semantic UI</a>.
This was not my decision.
I keep on bouncing off the documentation when I try to read it, though I <em>think</em> I basically understand the concepts now.
One barrier to my reading the documentation is its tendency to give examples like <tt class="docutils literal"><div <span class="pre">class="ui</span> button"></tt>, a construction that strikes me as akin to putting a sticky note that says "food" on a brick, and calling that cooking.
I think supporting UI automation code for years might have given me a hardline stance on this kind of thing.
Anyway, the other issue is that, while I'm bouncing off the documentation, I'm also rolling around in my head a quote from the front page: "Get the same benefits as BEM or SMACSS, but without the tedium." and thinking wistfully about working on this blog's theme.
I don't know what BEM-related tedium they're talking about.</p>
<p>All of this is to say that I was reading up background material on Semantic, and I ended up looking at the generated source for one of the pages on the site.
From reading up on Semantic, I came to the conclusion that I should probably be using <tt class="docutils literal">em</tt> or <tt class="docutils literal">rem</tt> in my theme, so that's why everything looks a little different as of earlier today.
The other thing I noticed was that my generated html had some errors, which I will sum up thus:</p>
<ul class="simple">
<li>The <tt class="docutils literal"><span></tt> tag does not work that way, apparently. I figured, since I had nothing to put in it, I could just self-close it, and, nope. Got to give it an open and a close.</li>
<li>Sublime Text decided to """help""" me by adding an extra quote mark after some template stuff that was generating an HTML attribute.</li>
</ul>
<p>While I'm thinking about this, I plugged the site into the W3C validator.
It tossed up some warnings.
I'll see about fixing those.</p>
<p>...</p>
<p>In the end, I was able to fix the <tt class="docutils literal">lang</tt> attribute being broken on most pages.
There's also some stuff about the contents of the <tt class="docutils literal"><header></tt> elements that I'm not sure is a problem <em>per se</em>, and also the generated code is using some obsolete HTML, which, goddammit, I trusted whichever component is messing this up. <strong>I trusted it!</strong></p>
<p>So, there's more work to be done on this stuff, but it's Friday night and I want to wind down.
Final thought on Semantic UI's front page: I really feel like bringing up BEM and SMACSS is a tactical misstep, because Semantic UI seems to me like a different <em>kind of thing</em> from BEM and probably SMACSS.
So, while I'm hitting the docs at random trying to find stuff, I keep on having to fend off the incorrect idea that I could just replace Semantic UI with BEM.
After all, <em>Semantic UI itself</em> set them up as competing technologies.
But this is absurd; Semantic UI is a framework, and BEM is a set of naming conventions.
Also, I still don't know when the tedium of using BEM is supposed to hit.</p>
<hr class="docutils" />
<p>Next post, I guess I should try to make some of those interpreter changes I mentioned.</p>
Crafting Interpreters - Progress 2018-11-022018-11-02T04:00:00-04:002018-11-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-02:/crafting-interpreters-progress-2018-11-02<p class="first last">Throwing all sorts of stuff at this.</p>
<p>Last time, I mentioned I wasn't sure how best to get through Chapter 7 of <em>Crafting Interpreters</em>.</p>
<p>Yesterday, I talked myself through it and got it into a mostly-working state.
This morning, I ironed out the really obvious bugs, took too long of a shower, and severely winded myself getting to the train.</p>
<p>Here's what the deal with the first part of that was.
Some of working on this is a blur, but it's a fact that, before I got started really laying the details of this stuff out for myself, I hadn't been sure what kind of exceptions I wanted to be passing around.
I think the source of my mental fuzziness was that I hadn't worked out all of the things that should be throwing errors usable by the interpreter.
Once I added validation to the majority of the functions, things began to fall into place.
Writing validators suggested shortcut functions, shortcut functions supported refactoring, and it became really pleasant after that.
I ended up something that could do math.
What I neglected to notice that night was that it didn't handle errors properly.</p>
<p>As I realized this morning, that was because I was changing a return value in the wrong part of the stack, so where I was trying to call the result with a bunch of handlers, I was instead calling the (boolean) status, so my error recovery code errored out.
This was a little annoying to fix, but doable.</p>
<p>I later took on the challenges, and decided that addition should not coerce its arguments (to be honest, I kind of want to split out addition and concatenation so it works like in Lua, but without coercion with addition; coercion on concatenation is probably fine though), that it's fine to compare strings, but not values of unlike type (I might add support for comparing booleans later), and that, rather than making zero division raise an error, I'll take <a class="reference external" href="https://www.hillelwayne.com/post/divide-by-zero/">Pony's approach</a> just to see what happens.</p>
<p>So, that was chapter 7.
Earlier today, I ported up through the end of 8.1, before realizing that I should read over the rest of chapter 8 before I did anything.
So I did.
The basic revelation I got from doing so was that I intend to undo some of my changes, and make deliberate fundamental design changes relative to the Java version.
Not just "this is a table instead of a switch statement, so things are a little weird", but "I want to rewrite the Lua code I have, so that it corresponds to some fundamentally different concepts, that would look like very different Java code".
I am, mysteriously, 100% sure this won't bite me later.
Here's the deal.
<em>Crafting Interpreters</em> adds an Environment object to the Interpreter object, to track the current execution scope.
This means that it needs a finally block after nested scopes to reset the global environment.
The equivalent of "finally" in Lua is undesirable to me for code that could be nested deep, because it means that <abbr title="tail-call optimization">TCO</abbr> is guaranteed impossible.
(Granted, I'd have to do some trampolining to get TCO to happen regularly with this code, but I don't want to make it impossible for me.)
It seemed a little weird to me, insofar as, we know that the environment should be the same before and after, we're shuffling it around inside a particular object.
Why not just pass the environment as a parameter, and define new ones as needed, to be passed in only to the functions that need them?
(Answer: because when I implemented the visitor pattern in Lua, I gave it the ability to take varargs, and I forgot that's not normal.)
Now, if the current environment is a function of dynamic state, and the global environment is consistent between runs, perhaps it should live in the <tt class="docutils literal">lox</tt> table instead, and because I have the visitor object taking the <tt class="docutils literal">lox</tt> table, perhaps the visitors should be converted from dynamic to static visitors, and passed the lox object as part of the varargs.
This leads in my mind to separating the statement and expression visitors into distinct objects, and collapsing the public interface to the intepreter module into a function.</p>
<p>Other things to look into doing eventually:</p>
<ul class="simple">
<li>Rely more on stacks for processing the source and running the code; I should ideally be able to bound all recursion depth to a relatively small limit, and avoid the <tt class="docutils literal">error</tt> and <tt class="docutils literal">pcall</tt> functions.</li>
<li>Convert environments to store variables array-style, with a separate table for mapping names to indices, and cache indices. Because variables in Lox are declared explicitly, it's possible to use static analysis to determine all variable names ahead of time, and assign them positions in an array, then redo the variable accesses to be by index. Not sure how this interacts with stacked environments, maybe it doesn't work, we'll see eventually.</li>
</ul>
<p>Next time, let's see what happens when I try to do the rewrites I laid out above.</p>
Draw a Box 2018-11-012018-11-01T04:00:00-04:002018-11-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-11-01:/draw-a-box-2018-11-01<p class="first last">SpooOOOooky technical exercises!</p>
<p>In this post:</p>
<ul class="simple">
<li>Switching between exercises.</li>
</ul>
<hr class="docutils" />
<p>Since I finished the <strong>???</strong> sheet, I have drawn:</p>
<ul class="simple">
<li>Some of the "Plotted 2 Point Perspective" exercise on October 25. I'm not feeling this one right now, and I hope it's mostly from trying to do straightedge stuff.</li>
<li>A little bit more of it on October 26. I should try and blow through this part, move onto the next thing as soon as I can.</li>
<li>I got most of the ninth sheet filled in around October 27. I'll probably fill things in a bit more later. I notice that I seem to be getting improving intuitions about where lines will meet, which I think is a good thing to get from all this?</li>
<li>The ninth sheet is just about filled, as of October 28. I'll skip to the other exercises for now.</li>
<li>The first quadrant on the tenth sheet is mostly filled, as of October 29. Lots of stuff in the lesson is ringing true.</li>
<li>The second quadrant is pretty much filled, as of October 30. I think I might want to switch back to Plotted 2 Point Perspective now, and revisit these exercises later.</li>
<li>I started the other Plotted 2 Point Perspective sheet on October 31. I did a few exercises, not much, because even if I know I need them, they're kind of a pain. That last bit might be because I'm using improvised straightedges for the longer lines, which is probably not necessary.</li>
</ul>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Crafting Interpreters - Reflections 2018-10-312018-10-31T04:00:00-04:002018-10-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-31:/crafting-interpreters-reflections-2018-10-31<p class="first last">CRIPES, they weren't meant to be called "Dairy"</p>
<p>I mentioned earlier, I think, that I'm going through <a class="reference external" href="http://craftinginterpreters.com">Crafting Interpreters</a>, but I'm too much of a <em>prima donna</em> to touch Java, so I've been converting from Java to Lua as needed.
(I will probably convert the other interpreter to Lua again, Python 3, RPython, or Rust, because C <em>terrifies</em> me.)
To start off this week, what's that been like?</p>
<p>Kind of a mixed bag, but all of the things being mixed together are basically fine.
Lua's treatment of different types of value is more uniform than Java's, and Lua's value semantics line up well with Lox's, to the point that the <tt class="docutils literal">is_truthy</tt> function is just the identity currently.
On the other hand, Lua is deliberately agnostic about a number of design decisions that object-oriented languages tend to make, such as:</p>
<ul class="simple">
<li>What are types?</li>
<li>How does inheritance work?</li>
<li>Is this a sequence or a hashmap?</li>
<li>Must exceptions be of some type?</li>
</ul>
<p>As it happens, I can get away dodging most of these questions; the code so far hasn't really relied on Java's implementation of particular language features in a detailed way.
Let's take a look at what I <em>did</em> have to hand-roll.</p>
<p>One of the more obvious divergences, to me, is that, because imports are at runtime, cycles are Pretty Bad.
(Python can sometimes handle import cycles better, but not always, and I don't know how to tell when it's going to go badly besides "It never seems to work right for me.")
As a result, instead of having things import my lox module, I have it construct a table, which the various parser objects require to be passed into their constructor.
Missed out on a golden opportunity to call it the LoxRuntimeDependencyInjector (... FacadeFactoryProxyAbstractSingletonVisitorBean[#]) or something.
Anyway, this means that I don't get to treat the class as a singleton by writing a bunch of static methods, since most of those concepts don't map cleanly onto Lua anyway.</p>
<p>My implementation of the visitor pattern might look a bit off.
Basically, instead of keying off of classes (which don't exist), I have visitable objects provide an <tt class="docutils literal">accept</tt> method that indexes the visitor with the object's constructor, to obtain a concrete visitor function.
Now, I couldn't decide whether to make the visitor function take the visitor as a first argument, so I made a "dynamic" version that does, and a "static" version that doesn't.
To simplify things, the <tt class="docutils literal">visit</tt> method handles the calling convention, and the <tt class="docutils literal">accept</tt> method just retrieves the function.</p>
<p>Other things going on:</p>
<ul class="simple">
<li>The implementation of enums is a one-off for token types.</li>
<li>I have a module that's just some utility functions for creating and manipulating hashsets.</li>
<li>The current "object" module is tiny, and has no dependencies. We'll see if that keeps up.</li>
<li>I wrote some "exception" stuff so I'd have something fancier than strings for my calls to <tt class="docutils literal">error</tt>, and a wrapper around <tt class="docutils literal">pcall</tt> to provide something like try-catch semantics.</li>
</ul>
<p>Where I need to go next is to look over chapter 7, and figure out how I want to finish implementing the various operators.
I had actually forgotten the differences that arose from not having a switch statement, but those are there, too.</p>
<p>I'll try to explain in detail why this is bringing me up short, next time.</p>
<p>..[#] I may as well note that this is unfair of me, since I've never used Spring and probably have no reason to care what it names its classes.</p>
Weekly Roundup 2018-10-302018-10-30T04:00:00-04:002018-10-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-30:/weekly-roundup-2018-10-30<p class="first last">Not a great week, output-wise. In my defense, the political climate right now fucking sucks.</p>
<ul class="simple">
<li>Diary: I spitballed ideas for (yet) a(nother) game.</li>
<li>Draw a Box: I finished up the basic ellipse exercises.</li>
</ul>
<p>Next week, I might talk about some interpreter coding I've been doing.</p>
Diary 2018-10-292018-10-29T04:00:00-04:002018-10-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-29:/diary-2018-10-29<p class="first last">I'm playing games more than thinking about blogging. OH WELL.</p>
<p>The main campaign in Opus Magnum felt a bit short, and I need some time to psych myself up for the post-game.
In the meantime, Exapunks, and waah, rewiring my heart is <em>hard</em>.
(Playing all this Zachtronics stuff has me wanting to check out KOHCTPYKTOP again. КОНСТРУКТОР? Anyway, turns out I need to update Flash to do that. Bummer.)</p>
<p>I had some thoughts on doing game stuff with Ink.
One possible way to do things with dynamic increases would be to have "template" stories, that the game can create multiple copies of, and pass aggregate values into the main story.
Like, there could be any number of instances of a "wagon" story active at once, and the player would interact with them separately, propagating changes to values into stuff like sums in the main story.
I don't want that kind of thing to be my first resort, but it's a definite possibility if things get really elaborate.</p>
<p>To figure out what kind of tech stuff I should be working on, I need to take the stuff I was listing out yesterday, and really put the squeeze to myself in terms of what each part will look like, and whether I'm missing anything.</p>
<p>I think I might end up trying to spec this game out some using Ink, which is confusing to me, so then again, maybe I won't.</p>
<p>I need to look over my plans for future work, but for now I think I'll talk about the Lua stuff I'm working on, for next week.</p>
Diary 2018-10-282018-10-28T04:00:00-04:002018-10-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-28:/diary-2018-10-28<p class="first last">Opus Magnum, but also game design thoughts.</p>
<p>I may have played too much Opus Magnum to focus on much else.</p>
<p>Thinking about the kinds of things this game could include:</p>
<ul class="simple">
<li>Recruiting randomly generated NPCs.</li>
<li>Work assignments.</li>
<li>Random encounters.</li>
<li>Known geographical hazards.</li>
<li>Stealing things.</li>
<li>Having things stolen.</li>
<li>Relationship meters.</li>
<li>Starvation.</li>
<li>Autosaves between zones.</li>
<li>Manual saving.</li>
<li>Diseases and curses.</li>
<li>Alchemy.</li>
<li>No lockpicking minigame.</li>
<li>Dungeoneering.</li>
<li>Carrying capacity.</li>
<li>Land speed determinations.</li>
<li>Rations and meal planning.</li>
<li>Haggling, but abstracted.</li>
</ul>
<p>One thing to note is that I probably want to limit the party size, and the number of NPCs that can be present in a given scene.</p>
<p>Basically, in a settlement, you have the following jobs you can assign:</p>
<ul class="simple">
<li>Given a budget and a shopping list, send a party member to buy as many supplies from the list as possible, and sell any goods.</li>
<li>Pickpocket passersby.</li>
<li>Case out a building.</li>
<li>Rob a cased building. Optionally, bring stuff in and leave it behind. With a sufficiently bad thief, this is neither optional nor visible in the UI.</li>
<li>Ask around for odd jobs.</li>
<li>Get the rewards for completed tasks.</li>
<li>Seek treatment for diseases or curses.</li>
<li>Recruit.</li>
<li>Leave.</li>
</ul>
<p>These can have the following outcomes:</p>
<ul class="simple">
<li>Some or all of the party is arrested.</li>
<li>Get a job that can be completed within the settlement.</li>
<li>Get a job that requires traveling.</li>
<li>New party members, possibly a choice of them.</li>
<li>Now on the road.</li>
</ul>
<p>On the road, the following things can happen:</p>
<ul class="simple">
<li>Get arrested.</li>
<li>Held up.</li>
<li>Attacked by wild animals.</li>
<li>Encounter a navigational hazard.</li>
<li>Find an unmapped dungeon.</li>
<li>Find a known dungeon.</li>
<li>Run low on supplies.</li>
<li>Reach the destination.</li>
</ul>
<p>The following actions are available:</p>
<ul class="simple">
<li>Adjust rationing.</li>
<li>Hunt.</li>
</ul>
<p>If arrested, the player can:</p>
<ul class="simple">
<li>Resist arrest.</li>
<li>Give up.</li>
</ul>
<p>If held up, the player can:</p>
<ul class="simple">
<li>Fight.</li>
<li>Negotiate.</li>
<li>Give up.</li>
</ul>
<p>If attacked by animals, the player can:</p>
<ul class="simple">
<li>Try to pacify the animals.</li>
<li>Go all-out against the animals.</li>
<li>Give up???</li>
</ul>
<p>When the player encounters a known navigational hazard:</p>
<ul class="simple">
<li>There may be a dedicated service that allows them to get past it.</li>
<li>There may be some way to deal with it themselves.</li>
</ul>
<p>When the player encounters a dungeon:</p>
<ul class="simple">
<li>They can note it for later.</li>
<li>Or go in.</li>
</ul>
<p>In a dungeon, they can assign jobs, and redo assignments as needed:</p>
<ul class="simple">
<li>Look for and disarm traps.</li>
<li>Take point.</li>
<li>I need to think about this part more.</li>
</ul>
<p>They can encounter dungeon-related things, like:</p>
<ul class="simple">
<li>Locked doors.</li>
<li>Blocked passages.</li>
<li>I need to think about this more.</li>
</ul>
<p>Various things can inflict diseases and curses, which:</p>
<ul class="simple">
<li>Often require treatment.</li>
<li>May add or remove various survival-related meters.</li>
</ul>
<p>I think when it comes to navigating between settlements, I want to give the trip a maximum length, and load it into the story to set up traversal.
Potentially it could instead use some form of linked-list-style traversal, allowing for arbitrary length.</p>
Diary 2018-10-272018-10-27T04:00:00-04:002018-10-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-27:/diary-2018-10-27<p class="first last">Opus Magnum</p>
<p>Opus Magnum.
Opus Magnum.
Opus Magnum Opus Magnum.
Opus Magnum?
Opus Magnum Opus Magnum!
Opus Magnum.</p>
<p>(Exapunks.)</p>
<p>Opus Magnum Opus Magnum Opus Magnum.</p>
<p>(I'm a fan of Zachtronics games.
Is it any wonder, after I said "I'm porting the code to Lua as I read.
This is an interesting exercise, and I'd recommend it to people familiar with Lua and the source language of whatever they choose to port.
It basically forces you to consider, when the source leans on some language feature, which part of it is actually necessary to accomplish the goal."?)</p>
<p>Do I have anything else to say about today?
Not really.
We watched some episodes of Baywatching ("That was the weirdest version of Rosemary's Baby") and then Sleepaway Camp ("... Hi").
And then <tt class="docutils literal">GOTO 1</tt></p>
Diary 2018-10-262018-10-26T04:00:00-04:002018-10-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-26:/diary-2018-10-26<p class="first last">I can't ever just copy down tutorial code, no, I have to rewrite it on the fly...</p>
<p>My inclination for this untitled game, is to sketch out the kind of interface I want for it, and sketch out even simpler "games" that basically just need that bit of interface.</p>
<p>From a UI perspective, a shop interface needs the ability to input numbers in various places.</p>
<p>Because it needs many numbers, I believe I shouldn't try to have the "shopping" logic handled in Ink.
I'm leaning towards the idea of an Ink-based setup that uses no external functions, it's just driven by the host application in a somewhat odd way.
So, instead of Ink running comparisons based on user input, the "shopping" logic would run outside of Ink, then give back control, possibly after updating some variables, possibly not.</p>
<p>It seems to me that one of the things I want to nail down early is whether to hold most of the data in Ink, or not.
One approach I could take would be to base conditionals in Ink on external functions with a default implementation of always returning true.
That way, the data can be arbitrarily complex, I can try to avoid state in the story json, and only my stuff can break on saving and updating.
But it's clear to me that I need some kind of design sketch if I'm going to figure this out.
Maybe the right solution is to work my way up to a prototype that stores all data in the story, and I just see how far I can get.
But, again, this needs a design to work towards.</p>
<p>Since this is a diary entry, and I didn't get much towards that part of thing, I'll mention one of the other things I've been doing that I kind of alluded to.
I've been messing around with <a class="reference external" href="http://craftinginterpreters.com/">Crafting Interpreters</a>; I've gotten up through chapter 6.
The catch is, I'm so burned out on Java, I'm porting the code to Lua as I read.
This is an interesting exercise, and I'd recommend it to people familiar with Lua and the source language of whatever they choose to port.
It basically forces you to consider, when the source leans on some language feature, which part of it is actually necessary to accomplish the goal.
I have yet to actually define anything that acts like a concrete superclass, so that's cool.
I'm kind of slowing down for chapter 7, because it's becoming clear that I need to take a step back and define something similar to exception types, and an equivalent of catch blocks.</p>
<p>Thinking about it in detail, something that looks good would be, like, there's a function that takes <tt class="docutils literal">pcall</tt> arguments, but instead of returning the result, it returns a function that takes a message type and a function.
If the message matches the type, then pass it to the function and return the result, otherwise propagate the error.
If, shock of shocks, everything actually works, pass the result.
Now, should it be possible for the calling code to easily tell that an error occurred?
I don't see any reason having the information would hurt code quality, except that it would always have to be handled if it were present.
I could try defining it both ways and see which one I use.
That was quick to throw together; I'll try it out tomorrow.</p>
Draw a Box 2018-10-252018-10-25T04:00:00-04:002018-10-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-25:/draw-a-box-2018-10-25<p class="first last">Ellipses all over the place.</p>
<p>In this post:</p>
<ul class="simple">
<li>I'm almost ready to draw a box.</li>
</ul>
<hr class="docutils" />
<p>Since I finished the seventh sheet, I have drawn:</p>
<ul class="simple">
<li>More freehanded ellipses as of October 18. I don't count these among the sheets. My big revelation doing this was that I get good results if I end the ellipse a little after the point where I start it, instead of trying to loop exactly.</li>
<li>About 50 ellipses on the fourth sheet on October 19. On the one hand, it's nice to see that I've come so far in a month; I just need to keep practicing these basics and I'll get them. On the other hand, this is a callout post for my past self, for drawing so many weird quadrilaterals.</li>
<li>The other ~50 ellipses on the fourth sheet shortly after October 20. Looking at these now, I see that I kind of messed up the perspective lines for all but the simplest ones. I kind of want to look into perspective techniques or math, and do a third sheet of planes later.</li>
<li>50 ellipses on the fifth sheet on October 21.</li>
<li>About 50 ellipses on the fifth sheet on October 22.</li>
<li>Counting is a pain, so I just got, the rest, on October 23.</li>
<li>The eighth sheet on October 24. I'm seeing definite patterns of undesired lumpiness in my ellipses. For this exercise, it looked a little better when I started on the funnel, usually.</li>
</ul>
<hr class="docutils" />
<p>Next week, DRAWING BOXES?!?!</p>
Diary 2018-10-242018-10-24T04:00:00-04:002018-10-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-24:/diary-2018-10-24<p class="first last">If that was "just a hashtag" then this is "just a finger"</p>
<p>This week is going to be in diary format because I don't want to do project format.</p>
<p>Ugh.
Steam is a nightmare, GoG has its own problems, I have trouble remembering Itch and Humble.
I want to try and make a game happen, as some kind of catharsis; it might end up on Itch.</p>
<p>I'm going to try and do some pre-planning, make sure I understand what I'm trying to do up-front.
My inclination is to try to do something text-based, without a lot of reading required at any one time.
I want to make as much of it as I can using Ink.
If I end up severely exceeding Ink + <a class="reference external" href="https://nedbatchelder.com/code/cog/">Cog</a>, I'll try to prototype something in Python, then attempt to move to Rust.</p>
<p>Instead of the kind of big loops I have in mind for MonFree, I want to try to work out a nice little gameplay loop, then elaborate on it.
Something with dungeon-diving.
Exactly how much Oregon Trail can you put in a vaguely Diablo-inspired game before it gets obnxious?
Or vice-versa?</p>
<p>What I'm basically thinking is, I want to start from a vague aspiration, and a tiny subset that I think I can implement, then iterate on it.
So, the vision is "somewhere between Oregon Trail with magic, and Diablo-likes with hunger".
I don't want to do combat to start with, because I think too hard about that, so I think my starting point should be "trip planning simulator".</p>
<p>Basically, the first iteration is:</p>
<ul class="simple">
<li>The player is given a task to transport goods between two cities.</li>
<li>They have a wagon.</li>
<li>They have to stock up on supplies.</li>
<li>Supplies include rations, weapons, and replacement parts.</li>
<li>They have several "turns", which are a day each, and currently don't have much happening.</li>
</ul>
<p>I have some ideas for what to add:</p>
<ul class="simple">
<li>Hunting</li>
<li>Random events</li>
<li>Magic</li>
<li>More locations</li>
<li>Loans</li>
<li>Having to buy your wagon to start with</li>
<li>Dungeons</li>
<li>Arbitrage</li>
<li>Curses</li>
</ul>
<p>One thing I need to work out is, when the scale is bigger than a single journey, what's the organizational conceit?
I guess I hope that journeys can be a decent way of organizing things, even if there are many.</p>
Weekly Roundup 2018-10-232018-10-23T04:00:00-04:002018-10-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-23:/weekly-roundup-2018-10-23<p class="first last">The events summarized in this entry end with the 21st. I'm missing then.</p>
<ul class="simple">
<li>Main project: I started laying out the details of what OMICE articles should be like.</li>
<li>Draw a Box: I drew the sixth and seventh sheets, which are rows of ellipses. I think I need more practice here.</li>
<li>Free-Topic: Kind of an unfocused ramble, mostly about non-standard code editing setups I'm trying out.</li>
</ul>
<p>Next week, I either take things easy, or try to lose myself in something, I don't know.</p>
OMICE Planning - Retrospective 2018-10-222018-10-22T04:00:00-04:002018-10-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-22:/omice-planning-retrospective-2018-10-22<p class="first last">It's fine.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I think about this last week, all in all.</li>
<li>How well I followed the plan.</li>
<li>Reasonable near-term goals.</li>
<li>Thoughts on further-out improvements.</li>
</ul>
<hr class="docutils" />
<p>This week, I wanted to lay out some guidelines for myself, for when I start writing articles for the One-Man Institute of Counterfactual Experimentalism, which is a ways out for now, I think.
This went okay.</p>
<p>I was able to lay out three broad categories of article, and some subdivisions within them.
Then, I started figuring out what each kind of article would need for me to consider it ready for publication.
I think that part still needs some work and thought.
One thing I wanted to do was have my wife look over them; I sent a version of them over to her, but I don't think she's had time to look at them yet, so I'll ask again later.</p>
<p>I don't think I'm really planning to do anything on this directly in the near-term, so my basic plan is: maybe start doing stuff for the Romance Instrumentality Project, so I can eventually do some structured writing that I will, for now, try to avoid excessive worldbuilding with, then later I can actually apply these guidelines I came up with.</p>
<hr class="docutils" />
<p>Next week, I'm not sure right now.</p>
OMICE Planning - Articles 2018-10-212018-10-21T04:00:00-04:002018-10-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-21:/omice-planning-articles-2018-10-21<p class="first last">Also, all kinds of article need to have more effort put into them than this post.</p>
<p>In this post:</p>
<ul class="simple">
<li>Standards for each kind of article.</li>
<li>A rough idea of the structure of each kind of article.</li>
</ul>
<hr class="docutils" />
<p>Last time, I went over the topics I want to cover for OMICE.
This time, let's figure out what kind of standards I want to cover for each kind of article I can write for them.</p>
<p>All articles need someone besides me to edit them before they're "done".</p>
<p>In no particular order:</p>
<ul class="simple">
<li><dl class="first docutils">
<dt>Survey articles, summing up the history of a particular idea, need some level (unsure) of good-quality sources. Ideally, a few people in the relevant field would take a look at it.</dt>
<dd><ul class="first last">
<li>Articles on general principles should give several qualitatively different examples of the principle in action, say around three.</li>
<li>Accounts of scientific discoveries should explain how things closer to human experience were used to observe things further away, what common phenomena made more sense in light of the discovery, and what practical implications or applications the discovery had.</li>
<li>Accounts of overturned ideas should explain how the idea was arrived at, and why it was convincing, as well as what evidence ended up weighing against it.</li>
</ul>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt>For the worked examples of worldbuilding, there should be some accompanying fiction that takes advantage of the final product, and directly deals with around a quarter of the worldbuilding details. Not sure where I want the fiction to go. The worldbuilding articles should have links to survey and philosophy articles, where appropriate.</dt>
<dd><ul class="first last">
<li>The worldbuilding, even when grounded in "describing fictional physics" should have a cultural component.</li>
<li>Relatedly, some worldbuilding should be focused on alien situations, but with no "fictional physics"; for example, a planet that could exist somewhere in this universe.</li>
<li>I don't want it to be a core focus, but one aspect of the worldbuilding examples could be "here's this high-profile worldbuilding; how would I do it differently?"</li>
</ul>
</dd>
</dl>
</li>
<li>For the philosophy "how" articles, after I feel like it's developed enough, I attempt to apply it, and revise it in light of any challenges I encounter.</li>
<li>For "when" articles, I guess I have to do some worked examples and make sure the recommendations make sense.</li>
</ul>
<p>Structurally, an article will consist of a title (which includes its categorization), and then:</p>
<ul class="simple">
<li>Philosophy articles will open with a profile of the intended audience. Next, they'll develop the article's argument. (I'm not sure I'm thinking about this well. "Write the rest of the damn article.")</li>
<li>Worldbuilding articles will open with a "what-if" question, and explore its implications.</li>
<li>Survey articles of discoveries or overturnings will maybe be based around a timeline with collapsible sections. Before that, a brief description of what was believed before the discovery, and when exactly that was.</li>
<li>Survey articles of discoveries will follow the timeline with an "in practice" section.</li>
<li>Survey articles of principles will, when feasible, open with an example of something the reader can do to observe the principle. Then, a timeline of development and applications.</li>
</ul>
<p>I'm rushing this out a bit because I got distracted playing video games.
I'm going to try to run these ideas past other people, and see if they can suggest any changes or refinements.</p>
<hr class="docutils" />
<p>Next time, how this week went.</p>
Diary 2018-10-202018-10-20T04:00:00-04:002018-10-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-20:/diary-2018-10-20<p class="first last">I woke up this morning feeling like a lump of silly putty that had been hurled at a wall.</p>
<p>I had a rough few days, so another diary entry.
At work, we had a big whole-company meetup.
Then, the day after, I barely got out of bed until I was done telecommuting.
Maybe some of the people who went managed to have enough fun after to get a hangover, but for my part, I was just exhausted.
And the CEO was talking about doing these <em>more often than annually</em>...</p>
<p>*screams internally*</p>
<p>Anyway, I started using GitHub Desktop at work, and it was fine, which is good for it, since its a whole integrated thing, and so it had better fit their default workflows.</p>
<p>I've also been messing around with some hobby code I haven't been writing about, and trying out an editor that supports elastic tabstops.
I'm not sure yet, after a week, whether I can recommend them as anything other than a novelty.
One use case for them is having function arguments aligned under the function call, rather than off to the left, if the line is long and has to wrap.
But in the code I've used them with, I've often found that, in such lines, the length comes from the code up to the call, so bringing the left margin over squishes everything, and potentially pushes it over anyway.
The other thing I notice is that it manages to really strongly distinguish tabular and "almost-tabular" data, in that data that suggests, but does not entirely conform to, a tab-based structure, will look like garbage if you try to apply that structure.
It almost suggests to me a desire for some kind of control character that makes the following tab align to "the next stop", but doesn't affect the position of the "skipped" stop.
Maybe it would be handy to have a language that defined non-escaped tabs as not included in the string literals that contain them.</p>
<p>Ultimately, it was aggravating enough that I just rewrote all of the tab characters, and am now getting my novelty for this project by writing it in a proportional font.
Since I literally just now made the change, I can't speak to how well it'll sit with me—come back in a week for that, I guess—but it looks cool and I'm sure the editor supports it better.</p>
<p>Anyway, maybe I'll write about that project itself next week, maybe not.</p>
<p>Went back to modded Minecraft briefly, and tried out the beginning of a skyblock pack based on recent GregTech.
That was something.
It's not that I don't want to come back to it, it's just that I want to wait until I am well-rested and feeling <em>extremely</em> patient.
Anyway, I should get ready for bed, because I'm still/once more tired.</p>
OMICE Planning - Topics 2018-10-192018-10-19T04:00:00-04:002018-10-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-19:/omice-planning-topics-2018-10-19<p class="first last">I hope I didn't miss any.</p>
<p>In this post:</p>
<ul class="simple">
<li>What topics do I want to cover, in general?</li>
<li>What topics do I want to cover, in specific?</li>
</ul>
<hr class="docutils" />
<p>(HAHA Whoops the slug for the last post was wrong. It's fixed now.)</p>
<p>So, I forget if I ever really explained the OMI on this blog.
Beyond the jokey name ("One-Man Institute"), the general idea has been to provide guides for worldbuilding, focused on worlds in which some natural laws are replaced by alternatives.
I further ended up trying to to derive some principles of writing from an admittedly shaky understanding of quantum physics; I want to try to divorce the principles from said shaky understanding, since they're worth more in their own right than an analogy that I can't vouch for.
Because it's hard to reason about a world with completely alien physics, most worldbuilders that could make use of anything I have to say in the OMI, could also do with pop-sci introductions to general principles, and, in particular, how those principles were developed or discovered.</p>
<p>Putting that in terms of some high-level summaries:</p>
<ul class="simple">
<li><dl class="first docutils">
<dt>Philosophical pieces, more explicitly opinionated, that lay out the ethos of the OMI.</dt>
<dd><ul class="first last">
<li>How should we write?</li>
<li>When should we worldbuild?</li>
<li>How should we worldbuild?</li>
</ul>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt>Surveys of real-world science. These will have to be extremely focused, because there's <em>a lot</em> of science out there.</dt>
<dd><ul class="first last">
<li>General principles that are likely to apply to a fictional world, or that require care to violate.</li>
<li>Accounts of particularly subtle scientific discoveries.</li>
<li>Accounts of the adoption and overturning of obsolete ideas and concepts.</li>
</ul>
</dd>
</dl>
</li>
<li>Worked examples of world-building according to the above philosophies and principles.</li>
<li>Whatever that <em>Tom Swifty</em> thing I did was, that was gold.</li>
</ul>
<p>I think that does it for now; I had an exhausting day and I can't think of anything else.</p>
<hr class="docutils" />
<p>Next time, the types of article, and what each will take to be "done".</p>
Draw a Box 2018-10-182018-10-18T04:00:00-04:002018-10-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-18:/draw-a-box-2018-10-18<p class="first last">Scribbly and scrawly...</p>
<p>In this post:</p>
<ul class="simple">
<li>I drew a bunch of ellipses, and was only happy with, like, at most two dozen of them.</li>
</ul>
<hr class="docutils" />
<p>Since I started the sixth sheet, I have drawn:</p>
<ul class="simple">
<li>3/18 rows as of October 11. Early ellipses look bad, guess that's why I'm drawing a bunch.</li>
<li>6/18 rows as of October 12. I hope I get a sense of approaching this differently at some point, because it feels like so far I've made the same mistakes two days in a row. If I don't have something solid when I'm done with this sheet, I'm going to try shaking things up.</li>
<li>12/18 rows as of October 13. I did extra today to try to get more practice at once. Not sure it helped.</li>
<li>18/18 rows as of October 14. That's one sheet done, and I think I want to practice a little differently before I start the next one. I want to try doodling general spirals for a bit, try to get better at coordinating symmetric curves.</li>
<li>A bunch of freehanded circles and ellipses on October 15. I traced a few, freehanded some more, and now I'm feeling good to go back to the exercises.</li>
<li>9/18 rows as of October 16. I'm certainly doing these with more ease, but I don't know if they're improving. I might need to intersperse these ellipse exercises with later ones when I get past them.</li>
<li>18/18 rows as of October 17. I did these faster, and on the back of my laptop. I'm interested in going further with drawing circles fast. I'm not interested in drawing anything else using the back of my laptop.</li>
</ul>
<hr class="docutils" />
<p>Next week, I'm not sure what I'll be doing, but it won't be what I just did.</p>
OMICE Planning - Planning 2018-10-172018-10-17T04:00:00-04:002018-10-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-17:/omice-planning-planning-2018-10-17<p class="first last">Actually, "Inception" was the name of the doctor.</p>
<p>In this post:</p>
<ul class="simple">
<li>I decided to think really hard about the OMICE.</li>
<li>I want to nail down a set of topics.</li>
<li>And work out what each kind of article entails before it's "done".</li>
</ul>
<hr class="docutils" />
<p>I've got a few hectic days ahead, so I'm trying to take it a little easy this week, by focusing all of the project solely on scoping out a future project.
"What is the OMICE?" is basically the question I want to answer for this week.
In broad terms, it's a collection of essays, held to different editorial standards according to their type.
"Editorial standards" might sound weird, given that the whole gimmick of OMICE is that it's just me.
For now, my plan is to keep the title, the whole point of which is that it doesn't really make literal sense.</p>
<p>Ugh, I didn't plan the planning of the planning, so I'm not exactly sure how to get two entries out of this.</p>
<p>I basically want some kind of taxonomy of different types of article, as well as the standards that I'll hold them to before I consider them ready for publication.</p>
<p>It also wouldn't be a bad idea to sketch out a rough idea of the "lifecycle" of an article.</p>
<p>Maybe I should talk about why I decided I should have editorial standards for this passion project.
Simply put, I was reading someone else's more-or-less passion project, and I had some issues with it.
I had also been thinking about how it would probably make sense to make sure my arguments are valid.</p>
<p>On the side of "articles like would have appeared on the OMIIP", I want to run my arguments by someone who knows what I'm talking about.
On the side of "writing about techniques", I want to try to apply them exactly as I say, before I commit to them.
If I do any media analysis, I want to make sure that my analysis has various properties in the eyes of other people, such as: cohesiveness, motivation, adequate levels of citation, elementarity where not citing, and persuasiveness.</p>
<p>In addition to "kinds of article", I also need to put some thought into topics, like, what range of things do I want to cover for the OMICE?</p>
<p>I think that'll do for this week.</p>
<hr class="docutils" />
<p>Next time, I'll lay out topics first, because I think that makes it easier to reason about what kinds of articles I can write about the topics.</p>
Weekly Roundup 2018-10-162018-10-16T04:00:00-04:002018-10-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-16:/weekly-roundup-2018-10-16<p class="first last">Individual bits fell short, but I like how this week went, overall.</p>
<ul class="simple">
<li>Main project: I retired Divide and Cover, and messed around with SWI Prolog's libraries.</li>
<li>Draw a Box: I finished the planes exercise.</li>
<li>Free-Topic: We watched a Golden Film, and I had a lot of trouble finding anything to say about it.</li>
</ul>
<p>Next week, I'm thinking I might try planning for the OMICE.</p>
Logical Numbers? - Retrospective 2018-10-152018-10-15T04:00:00-04:002018-10-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-15:/logical-numbers-retrospective-2018-10-15<p class="first last">It was okay.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I think about this last week, all in all.</li>
<li>How well I followed the plan.</li>
<li>Reasonable near-term goals.</li>
<li>Thoughts on further-out improvements.</li>
</ul>
<hr class="docutils" />
<p>This week, I gave myself a bunch of goals, and I wasn't sure how many of them I was going to hit.</p>
<p>I gave myself the goal of retiring Divide and Cover, and I more-or-less got that done.
I'll have to look into finessing the reporting in the Coverage prereleases.</p>
<p>I also had goals of trying out PlUnit, GitHub Desktop, and Bors.
Bors is cool, though I'd make better use of it on a project with better tests than what I've done so far.
PlUnit is fine, minimal without feeling like it's missing anything, though I'm not sure I'm using it as expected right now.
I'm going to have to try out GitHub Desktop at work, because I don't have a sense, from working on my own, how it compares to the various command-line utilities I've tried.
I hit most of the goals I set for myself, except for the stuff related to finding bugs.</p>
<p>To make any progress on the bug/improved behavior front, I'll have to write up the algorithmic properties of the various predicates, maybe do some experimentation.</p>
<p>Long-term, I don't know how far I'll go with this, since it takes a fair bit of effort to get this to "as functional as the built-in stuff".
I'll probably keep at this as a way to learn more about Prolog's ecosystem.</p>
<hr class="docutils" />
<p>Next week, perhaps I'll pull out the other thing I did this weekend.</p>
Logical Numbers? - Iteration 2018-10-142018-10-14T04:00:00-04:002018-10-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-14:/logical-numbers-iteration-2018-10-14<p class="first last">This stuff is cool. And my part in all of this is useless. But this is still cool overall.</p>
<p>In this post:</p>
<ul class="simple">
<li>Getting the basics set up.</li>
<li>Status of the initial iterations.</li>
</ul>
<hr class="docutils" />
<p>Since last time, I wrote tests, and set up Travis and Bors with the repository.
Bors doesn't allow merges with failing tests, which, as it turns out, <a class="reference external" href="https://github.com/mwchase/logical-numbers/pull/1#issuecomment-429506497">instantly paid off</a>.
After that, I looked into various improvements.
It looks like Prolog's coverage story isn't as good as I made myself think, at first.</p>
<p>The tests are pretty minimal, but I started making changes anyway.
I started replacing short variable names with words, and the result seems a lot less obnoxious so far.</p>
<p>I ended up getting distracted by other stuff I might write up later, so there's not much more to say on this.</p>
<hr class="docutils" />
<p>Next time, what I thought of this week.</p>
Golden Films: The Jungle King2018-10-13T04:00:00-04:002018-10-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-13:/golden-films-the-jungle-king<p class="first last">Golden Films's The Jungle King is a Golden Films by Golden Films</p>
<p>Recently, my wife and I have been watching <a class="reference external" href="https://www.youtube.com/channel/UCUp4yFAjgOA11a4h568vnrA">Phelous</a> make fun of low-budget (and occasionally weirdly high-budget) animated movies.
Eventually, this turned into "Hey, let's track down movies he hasn't done, and get our kicks that way".
So, on Amazon, we watched (a VHS rip of) The Jungle King, from Golden Films.</p>
<p>After seeing so many of these movies made fun of, it's kind of hard for me to get a handle on this.
There are some of the usual suspects for a movie like this:</p>
<ul class="simple">
<li>The animation is incredibly choppy</li>
<li>The soundtrack just blasts public domain music</li>
</ul>
<p>With a few special confusing bits:</p>
<ul class="simple">
<li>According to the Chancellor's map, the whole movie is taking place on an island. So why is the Raj so insistent about trying to get ocean-front property? Seriously, he's so insistent.</li>
<li>Why are the peasant lions Jewish?</li>
<li>Why is the gorilla Jamaican-or-thereabouts when he sings, and seesawing wildly between Irish and Indian otherwise?</li>
<li>The animals have constructed a well-developed, if corrupt, civilization, with extensive architecture, agriculture, clothing, trade, and time-keeping. Why, then, are humans hunting them to put in zoos, and why do they let them keep jewellery and bathtowels when they do catch them?</li>
<li>Why was he wearing a bathtowel? It's not like he wears pants normally.</li>
<li>Why does he have a throne out in the middle of nowhere?</li>
</ul>
<p>Even with all of these questions, I have to say, this wasn't, like, transcendantly bad.
I'd say it's half-baked, on the mediocre side of things.
It's very Golden Films, is what it is.</p>
<p>I'm like, on the one hand, people should be reviewing this, because it's right there, but on the other hand, what is there to say?
It's not an adaptation of any existing story or event, so there's no question of fidelity to address.
It is what it is, and what it is, is... hard-to-follow story-telling, distracting animation, and jokes that they didn't trust the audience to get.</p>
Logical Numbers? - Documentation 2018-10-122018-10-12T04:00:00-04:002018-10-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-12:/logical-numbers-documentation-2018-10-12<p class="first last">There doesn't seem to be a cookiecutter for Prolog. Oh well.</p>
<p>In this post:</p>
<ul class="simple">
<li>Divide and Cover retirement update.</li>
<li>Turning the Prolog file I was constantly editing and re-editing into a legit project.</li>
</ul>
<hr class="docutils" />
<p>Before anything else, I got Divide and Cover squared away.
This had no real relevance to the rest of this, I just really didn't want to keep it around.
For whatever reason, the badges aren't showing up right in PyPI; I cut a new version to try to address this, and it didn't help.
I choose to interpret the weird state this leaves the repo in relative to the index as a meta-commentary on how I don't want to focus on these any more.
I forgot to say to use Coverage 5.
Maybe I'll come back to this sometime and add a message.
Not right now.</p>
<p>Anyway, I found some <a class="reference external" href="https://arxiv.org/abs/0911.2899v3">Coding Guidelines for Prolog</a> that I want to try to use to inform my style.
I've already got some idiosyncratic conventions that I don't intend to give up, but maybe I can add more.
I've got a repo made, and tracked using GitHub Desktop instead of Mercurial, the file added, and the things that I think should be public, have preliminary documentation.</p>
<p>No tests yet, but some of the documentation should be a good guide for writing tests.</p>
<hr class="docutils" />
<p>Next time, I want to have gotten at least through setting up CI.</p>
Draw a Box 2018-10-112018-10-11T04:00:00-04:002018-10-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-11:/draw-a-box-2018-10-11<p class="first last">Well, at least I'm doing these faster now.</p>
<p>In this post:</p>
<ul class="simple">
<li>I get bored of the fifth sheet.</li>
</ul>
<hr class="docutils" />
<p>Since I started the fifth sheet, I have drawn:</p>
<ul class="simple">
<li>15 planes on October 4. A bunch of bad ones. I think I need to be using the table again.</li>
<li>15 planes on October 5. A few bad ones. The table helped, maybe I should stop drawing such tiny squares.</li>
<li>15 planes on October 6. A bad one. I ought to switch back to drawing bigger ones, for sure. Next time.</li>
<li>15 planes on October 7. Bigger now, yay!</li>
<li>15 planes on October 8.</li>
<li>15 planes on October 9. Almost done.</li>
<li>15 planes on October 10. A bad one. I could technically fill up more of the sheet, but consider this: I don't want to.</li>
</ul>
<p>For a total of 840 lines this week,
and 1680 lines on the fifth sheet.</p>
<hr class="docutils" />
<p>Next week, intentional curves, I think!</p>
Logical Numbers? - Planning 2018-10-102018-10-10T04:00:00-04:002018-10-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-10:/logical-numbers-planning-2018-10-10<p class="first last">... Simple!</p>
<p>In this post:</p>
<ul class="simple">
<li>Coverage is trialing Who Tests What, which means I should be able to retire Divide and Cover.</li>
<li>I've got an ambitious project idea, not in terms of what the code accomplishes, but in terms of tooling and process. My hope is that the disruption of learning each new bit will be localized.</li>
</ul>
<hr class="docutils" />
<p>There are a few things I want to look into this week.</p>
<p>One is retiring the Divide and Cover repository.
My plan there is to set the development status to 7 (I think), add a no maintenance intended badge to both, publish new versions of each on PyPI, and archive the repository.
Have a message in there about, moving forward, want to be using Coverage 5+.</p>
<p>Later, I can look into how the Coverage prereleases actually work, I just... really don't want to deal with this code more than I have to, after all of the contortions I've gone through with it.</p>
<p>The big thing I want to do this week is use the arbitrary-sized integer functions I've been messing with, to get a handle on testing and documentation in Prolog, and potentially setting up a Prolog project with continuous integration and workflow bots.
For this, I also want to try out the GitHub Desktop app again, see if it handles GitHub's workflows better than non-opinionated tooling.</p>
<p>So, for that part of things, I need to:</p>
<ul class="simple">
<li>Create a new project, and manage it through the app.</li>
<li>Look at Prolog project layouts.</li>
<li>Create a directory tree in the project, in accordance with the previous bullet point.</li>
<li>Copy my current file into the tree. For now, do not make any changes to the code's behavior.</li>
<li>Document the intended behavior of the various predicates.</li>
<li>Write tests against the documented behavior, file bugs against the failures.</li>
<li>Set up CI, probably with Travis.</li>
<li>Mark the failures as expected to fail.</li>
<li>Figure out which services will usefully interact with this. I don't know if anything consumes the coverage data that Prolog can produce.</li>
<li>Set up bors.</li>
<li>Stop committing to master.</li>
<li>Start fixing bugs, on temporary branches.</li>
</ul>
<p>I'm not certain I couldn't do all of that this week by going flat out and ignoring all of my other obligations, but I'm certain I can't do it all if I don't do foolish things.
As such, I'll just make some amount of progress on the above, and that will be that.
I don't have strict day divisions in mind, but I'd at least like to get up through documenting code by the next entry.</p>
<p>The overall goal is to get some experience with tooling in Prolog, using basically a toy problem, but one that admits sophisticated solutions.</p>
<hr class="docutils" />
<p>Next time, I'll hopefully have cleared away the Divide and Cover repository, and gotten started on, I don't know what to call this, Logical Numbers?</p>
Weekly Roundup 2018-10-092018-10-09T04:00:00-04:002018-10-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-09:/weekly-roundup-2018-10-09<p class="first last">DON'T PAY CRIMINALS!</p>
<ul class="simple">
<li>Diary: I thought about programming in Prolog and maybe Lua, and then I got distracted for a bit agonizing over how a sextortion scammer managed to get a bit over a dozen paydays.</li>
<li>Draw a Box: I didn't fill up as much of the sheet as I thought I would, because I drew tiny, tiny boxes.</li>
</ul>
<p>Next week, I want to try applying good design principles to my probably-needless Prolog code.</p>
Diary 2018-10-082018-10-08T04:00:00-04:002018-10-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-08:/diary-2018-10-08<p class="first last">Stop doing it, guys...</p>
<p>Another one paid the money.
This is kind of depressing and annoying, because I can't see any way around this, short of mass-mailing every email address in a data breach, which sounds super annoying to do or be on the receiving end of.</p>
<p>Anyway, I was mostly taking it easy today.
I played CrossCode a little.
The second boss was substantially easier once I started applying actual thought to it.
I'm sort of confused about how much of the scenario being presented is supposed to be true within the game's fiction, and how much is fictional.
Hopefully, that gets clearer later.</p>
<p>Thinking about stuff to do later, I'm kind of interested in <a class="reference external" href="https://bors.tech/">bors</a>, so maybe I'll do a project next week focusing on getting bors working on a new project, even if it is a one-person deal.
If I'm doing that, maybe I want to try using a gui for Git again, because the various frontends and adapters I've used so far aren't obviously suited to the whole "the branch is done, you can delete it now" model.
(Actually, are there issues with deleting a tag in mercurial? I don't even know.)
GitHub Desktop seemed like the obvious choice, but opening it up reminded me of what a horrible mess my repositories are.
Well, I'll play around with it later, and see if it offers a better experience than "use Gitless as training wheels, then drop into Git for any remotely complicated operation."</p>
Diary 2018-10-072018-10-07T04:00:00-04:002018-10-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-07:/diary-2018-10-07<p class="first last">Please don't do it, guys...</p>
<p>Entry is short and early today because I'm out of town for a bit, shortly after I put this up.</p>
<p>Three more people paid into the scam.
That's twelve people who've established themselves as "scared enough of blackmail to pay money given vague claims".</p>
<p>I wonder if it's possible to analyze payment patterns and track these down automatically.
Like, here we've got a wallet with a small initial inlay, then repeated payments into it of a consistent USD amount, from wallets with no-to-minimal transaction history, and no outstanding balance.</p>
<p>I don't know if there's anything doing blockchain analytics, but that pattern of transactions seems like it should be a red flag.</p>
<p>Anyway, I'll be back later.</p>
Diary 2018-10-062018-10-06T04:00:00-04:002018-10-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-06:/diary-2018-10-06<p class="first last">An annoying distraction.</p>
<p>I'd kind of been assuming that I'd have something more substantial to write about today, but one of the things I decided to do was to make an actual dent in my email, and I discovered that there was a data breach.</p>
<p>Some script kiddie with typical delusions of grandeur found a password dump, and decided to try to intimidate me with the specter of videos that I <em>could have</em> been given any reason whatsoever to believe exist, but <em>wasn't</em>.
I'm working my way through my old terrible passwords right now, because "your passwords are leaked, yo" was the only credible part of the message.</p>
<p>I'm sad to say that, going by publicly available information, the script kiddie has made $7200 off of this scam so far.</p>
<p>In any case, reading the email (which, as near as I can tell, doesn't have a tracking image in it, but that's an amateur non-expert opinion) <em>allegedly</em> triggered a 48-hour countdown, so I'll let y'all know in two days if "[my] intimate one" gets sent any videos; I'm honestly looking at this thinking, like, bring it on.</p>
<p>Fortunately, more people reported this scam than paid up, at least with that particular wallet.</p>
Diary 2018-10-052018-10-05T04:00:00-04:002018-10-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-05:/diary-2018-10-05<p class="first last">It's nice to relax my focus a little in terms of doing coding things.</p>
<p>I was looking more into writing stuff in Prolog.
It's got some good tools that I ought to look into, like the testing facilities in SWI-Prolog sound like they're pretty good.</p>
<p>I also started sketching out some of the things I want to do with Linked Seas.
I should look into techniques for handling unreliable narrators.</p>
<p>One thing I've been doing since the year started, and not really mentioning, is regular exercise.
These past few days, I realized that it was possible for me to exert myself more on the treadmill, than I had been.
The result is presumably good in terms of exercise, but I'm wiped out right now.</p>
<p>Earlier today, I was messing around with other text editors.
I write this blog in Sublime Text, but there's nothing really specialized relating Sublime Text to my publishing workflow.
I was trying out <a class="reference external" href="https://foicica.com/textadept/">Textadept</a>, because that supports <a class="reference external" href="http://nickgravgaard.com/elastic-tabstops/">elastic tabstops</a>, and I'm trying to decide what I think of them.
One thing I think is, I don't like the way <tt class="docutils literal">etst</tt> works.
It happens to produce correct output for some of the example code, but it behaves very differently from the described mental model on certain arrangements of code.</p>
<p>Anyway, I'd like to try it out on some Lua code or something, if I ever come up with a project in Lua that isn't just meditating on PL design stuff.
Those projects are kind of frustrating when they get too rarefied for me to <em>pretend</em> I'm going to do something with them.
Ideally, I'd come up with something that isn't feature envy of another language.
Maybe something in <a class="reference external" href="https://love2d.org/">LÖVE</a>.</p>
<p>Anyway, going to try and take it easy and get my strength back.
I'll keep on posting these as regularly as I can.</p>
Draw a Box 2018-10-042018-10-04T04:00:00-04:002018-10-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-04:/draw-a-box-2018-10-04<p class="first last">Little squares...</p>
<p>In this post:</p>
<ul class="simple">
<li>I thought I was going to fill more of the page, but I started drawing tiny.</li>
</ul>
<hr class="docutils" />
<p>Since I started the fifth sheet, I have drawn:</p>
<ul class="simple">
<li>15 planes on September 27.</li>
<li>15 planes on September 28, plus two I'm not counting because they were iffy.</li>
<li>15 planes on September 29, plus a few that seemed iffy.</li>
<li>15 planes on September 30.</li>
<li>15 planes on October 1.</li>
<li>15 planes on October 2. They're kind of smaller right now, so the paper's going to have a lot more of them.</li>
<li>15 planes on October 3. Somehow, these went from columns of ten to columns of twenty.</li>
</ul>
<p>For a total of 840 lines this week,
and 840 lines on the fifth sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same, for a while, then hopefully I can start another sheet.</p>
Diary 2018-10-032018-10-03T04:00:00-04:002018-10-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-03:/diary-2018-10-03<p class="first last">The programming is working out easier than the reading.</p>
<p>I'm mostly messing around in Prolog right now.
I'm implementing super-basic types inside the predicate system, in pretty much the exact way I'm pretty sure I'm not supposed to for any serious code.
Doing this leads to all sorts of infinite-loop-blow-the-stack failure modes.
I think to deal with those, I need to start differentiating between "predicates that confirm and possibly desugar data" and "predicates that match in a specific progression".
If I can write more of the latter, and start them off in the various clauses I've written, that should give it more well-behaved semantics for progression along free variables.
This seems like an extremely "procedural" angle to take on the details, but it should allow me to construct higher-level predicates that "just work" in a variety of configurations.</p>
<p>This did give me an interesting thought.
One objection I've seen raised to writing code in tail-call or continuation-passing style is that the onus shouldn't be on the humans writing and maintaining code to express its high-level code in a particular way to take advantage performance optimizations provided by the compiler or run-time, if the required style is "unnatural".
I'm not going to talk about what's "natural", because my only real anecdote there is being traumatized by a WYSIWYG interface in college.
But, supposing we have particular criteria for what's natural, and compilation/interpretation facilities to transform "natural" code to "efficient" form, possibly with some kind of metadata constraints to request particular optimizations and complain when they're not possible.
Given all of that, it might be interesting to be able to say "let me call the tail-recursive function this loop body got translated into" or something like that.</p>
<p>What else has been happening lately...
I'm pretty tired, which is why I decided to take a break from projects this week.
Encoding arbitrary-length two's complement arithmetic in Prolog is for fun.</p>
<p>I got the fourth edition of Calendrical Caluculations as an e-book, which I'm kind of regretting now.
The Kindle edition is full of distracting errors.
I've reported enough that I feel like Amazon should be paying me for it.</p>
Weekly Roundup 2018-10-022018-10-02T04:00:00-04:002018-10-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-02:/weekly-roundup-2018-10-02<p class="first last">I'd like to wind down for a bit.</p>
<ul class="simple">
<li>Main project: I started thinking about stories and setting in Linked Seas, which, when you get right down to it, is where I should have been focusing anyway.</li>
<li>Draw a Box: I finished the fourth sheet.</li>
<li>Free-Topic: I made a tic-tac-toe game with a not-great interface.</li>
</ul>
<p>Next week, rather than have a main project, I think I'll take it easy and do diary-style entries.</p>
Conworld Codex - Retrospective 2018-10-012018-10-01T04:00:00-04:002018-10-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-10-01:/conworld-codex-retrospective-2018-10-01<p class="first last">It was okay.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I think about this last week, all in all.</li>
<li>How well I followed the plan.</li>
<li>Reasonable near-term goals.</li>
<li>Thoughts on further-out improvements.</li>
</ul>
<hr class="docutils" />
<p>This last week feels kind of so-so.
I think it's because I'm pushing myself a bit outside my comfort zone, so I can't move at the same rate that I'm used to.
Nevertheless, I did move a little forward.</p>
<p>I didn't plan this week well, kind of gave myself the directive to do things by the seat of my pants, and I did, so that technically worked right, but I'm not eager to do it again.</p>
<p>In the near term, I want to avoid framing this stuff as an accesory to worldbuilding, and start writing actual stories in the setting, so I can discover the setting through the stories.</p>
<p>In the long term, I want to have facilities for date manipulation and temporal logic in the code.
Right now I'm messing with code that could conceivably be used for supporting that stuff later, but it's hitting some issues that make me skeptical.
It might need to look even weirder than it already does to work well.</p>
<hr class="docutils" />
<p>Next week, I think I need to take it easy.</p>
Conworld Codex - Modeling 2018-09-302018-09-30T04:00:00-04:002018-09-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-30:/conworld-codex-modeling-2018-09-30<p class="first last">Quick post on how I haven't done much here.</p>
<p>In this post:</p>
<ul class="simple">
<li>There's not much, I'm tired, that's how it is.</li>
<li>What I did do in terms of predicates.</li>
</ul>
<hr class="docutils" />
<p>I ended up not doing too much work on the "what predicates do I actually need" problem.</p>
<p>I figured it makes sense to model narrator-ness, parentage, the location of significant events, and affiliation, among other things.
I don't have a good handle on how to represent them, though, and I also want some way to bring temporal logic of some kind into it.
One thing I need to add to my current very-rough draft is marking things <em>with</em> the narrator, so it works out to statements.
Perhaps that's how I want to model it: pairs of "narrator" and "what they said, possibly in some kind of structured format."</p>
<p>For now, the things I'm going to focus on are:</p>
<ul class="simple">
<li>Writing up the life of the first narrator I decided to go with.</li>
<li>Looking into modeling calendars, because that's something I've always wanted to have with my conworlding efforts, and I've had trouble getting it together properly when I've tried before.</li>
</ul>
<p>The more I think about the structure of the codex files, the more I think, the narratives should be given as raw <em>facts</em>, and the <em>rules</em> should be non-diegetic commentary.</p>
<p>Stuff like, the narrator here, Bwatts'a, would say stuff like "I hunt with the help of my bvejj, Fol'ze." and I'd add a separate commentary clause to the effect of "'Bvejj' is the Gwacha word for a boar-like creature with horns. They are omnivorous and understand simple commands. Under favorable conditions, one can take down a target the size of a large deer."</p>
<p>(How far can I exceed <a class="reference external" href="https://xkcd.com/483/">these limits</a> while still writing stuff that's recognizably English...)</p>
<hr class="docutils" />
<p>Next time, how this week went.</p>
Prolog 2018-09-292018-09-29T04:00:00-04:002018-09-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-29:/prolog-2018-09-29<p class="first last">While looking over the site, I realized that my custom theme doesn't render tag information at all??? Also, I wrote a thing.</p>
<p>In this post:</p>
<ul class="simple">
<li>This code will be the one going to nationals!</li>
</ul>
<hr class="docutils" />
<p>When it comes to writing software, there are really hard problems, really intellectually distracting problems, problems with canonical solutions, problems that just take a bit of effort to get past, and stuff kind of in between all of that.
The biggest problem I seem to hit, though, is the problem of avoiding scope creep.
It's just so easy to look at a problem statement, and see the underlying generalities that it could be expressed in terms of.
Why, with the right framework, the entire system could be expressed with just a handful of numbers! ...
Is what I think right before everything goes off the rails and I'm left with a useless hunk of over-engineered nothing.
But at long last, actual years of perseverance have paid off, and I've managed to avoid scope creep and built an engine that expresses the core logic and nothing more.</p>
<p>Some of you out there may have sensed a punchline coming.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span>
<span class="normal">102</span>
<span class="normal">103</span>
<span class="normal">104</span>
<span class="normal">105</span>
<span class="normal">106</span>
<span class="normal">107</span>
<span class="normal">108</span>
<span class="normal">109</span>
<span class="normal">110</span>
<span class="normal">111</span>
<span class="normal">112</span>
<span class="normal">113</span>
<span class="normal">114</span>
<span class="normal">115</span>
<span class="normal">116</span>
<span class="normal">117</span></pre></div></td><td class="code"><div><pre><span></span><span class="p">:-</span> <span class="s s-Atom">dynamic</span>
<span class="s s-Atom">board</span><span class="o">/</span><span class="mi">1</span>
<span class="p">.</span>
<span class="nf">board</span><span class="p">(</span><span class="s s-Atom">no</span><span class="p">).</span>
<span class="nf">player</span><span class="p">(</span><span class="s s-Atom">x</span><span class="p">).</span>
<span class="nf">player</span><span class="p">(</span><span class="s s-Atom">o</span><span class="p">).</span>
<span class="nf">turn</span><span class="p">(</span><span class="nv">B</span><span class="p">,</span><span class="s s-Atom">x</span><span class="p">)</span> <span class="p">:-</span>
<span class="nf">count</span><span class="p">(</span><span class="nv">B</span><span class="p">,</span><span class="s s-Atom">x</span><span class="p">,</span><span class="nv">C</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">count</span><span class="p">(</span><span class="nv">B</span><span class="p">,</span><span class="s s-Atom">o</span><span class="p">,</span><span class="nv">C</span><span class="p">)</span>
<span class="p">.</span>
<span class="nf">turn</span><span class="p">(</span><span class="nv">B</span><span class="p">,</span><span class="s s-Atom">o</span><span class="p">)</span> <span class="p">:-</span>
<span class="nf">count</span><span class="p">(</span><span class="nv">B</span><span class="p">,</span><span class="s s-Atom">x</span><span class="p">,</span><span class="nv">Cx</span><span class="p">)</span>
<span class="p">,</span> <span class="nv">Co</span> <span class="o">is</span> <span class="nv">Cx</span> <span class="o">-</span> <span class="mi">1</span>
<span class="p">,</span> <span class="nf">count</span><span class="p">(</span><span class="nv">B</span><span class="p">,</span><span class="s s-Atom">o</span><span class="p">,</span><span class="nv">Co</span><span class="p">)</span>
<span class="p">.</span>
<span class="nf">win</span><span class="p">(</span><span class="nv">B</span><span class="p">,</span><span class="nv">P</span><span class="p">)</span> <span class="p">:-</span>
<span class="nf">player</span><span class="p">(</span><span class="nv">P</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">row</span><span class="p">(</span><span class="nv">B</span><span class="p">,(</span><span class="nv">P</span><span class="p">,</span><span class="nv">P</span><span class="p">,</span><span class="nv">P</span><span class="p">))</span>
<span class="p">.</span>
<span class="nf">subscript</span><span class="p">((</span><span class="nv">Item</span><span class="p">,</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">),</span><span class="mi">0</span><span class="p">,</span><span class="nv">Item</span><span class="p">,(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">)).</span>
<span class="nf">subscript</span><span class="p">((</span><span class="nv">Y</span><span class="p">,</span><span class="nv">Item</span><span class="p">,</span><span class="nv">X</span><span class="p">),</span><span class="mi">1</span><span class="p">,</span><span class="nv">Item</span><span class="p">,(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">)).</span>
<span class="nf">subscript</span><span class="p">((</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="nv">Item</span><span class="p">),</span><span class="mi">2</span><span class="p">,</span><span class="nv">Item</span><span class="p">,(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">)).</span>
<span class="nf">count</span><span class="p">((</span><span class="nv">R1</span><span class="p">,</span><span class="nv">R2</span><span class="p">,</span><span class="nv">R3</span><span class="p">),</span><span class="nv">P</span><span class="p">,</span><span class="nv">C</span><span class="p">)</span> <span class="p">:-</span>
<span class="nf">tuple_count</span><span class="p">(</span><span class="nv">R1</span><span class="p">,</span> <span class="nv">P</span><span class="p">,</span> <span class="nv">C1</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">tuple_count</span><span class="p">(</span><span class="nv">R2</span><span class="p">,</span> <span class="nv">P</span><span class="p">,</span> <span class="nv">C2</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">tuple_count</span><span class="p">(</span><span class="nv">R3</span><span class="p">,</span> <span class="nv">P</span><span class="p">,</span> <span class="nv">C3</span><span class="p">)</span>
<span class="p">,</span> <span class="nv">C</span> <span class="o">is</span> <span class="nv">C1</span> <span class="o">+</span> <span class="nv">C2</span> <span class="o">+</span> <span class="nv">C3</span>
<span class="p">,</span> <span class="p">!</span>
<span class="p">.</span>
<span class="nf">print_winner</span><span class="p">(</span><span class="nv">B</span><span class="p">)</span> <span class="p">:-</span>
<span class="nf">win</span><span class="p">(</span><span class="nv">B</span><span class="p">,</span> <span class="nv">P</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">write</span><span class="p">(</span><span class="nv">P</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">write</span><span class="p">(</span><span class="s s-Atom">' wins!'</span><span class="p">)</span>
<span class="p">,!</span>
<span class="p">.</span>
<span class="nf">print_winner</span><span class="p">(</span><span class="k">_</span><span class="p">).</span>
<span class="nf">print_row</span><span class="p">((</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="nv">Z</span><span class="p">))</span> <span class="p">:-</span>
<span class="nf">write</span><span class="p">(</span><span class="nv">X</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">write</span><span class="p">(</span><span class="s s-Atom">'|'</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">write</span><span class="p">(</span><span class="nv">Y</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">write</span><span class="p">(</span><span class="s s-Atom">'|'</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">write</span><span class="p">(</span><span class="nv">Z</span><span class="p">)</span>
<span class="p">,</span> <span class="s s-Atom">nl</span>
<span class="p">.</span>
<span class="nf">print_board</span><span class="p">((</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="nv">Z</span><span class="p">))</span> <span class="p">:-</span>
<span class="nf">print_row</span><span class="p">(</span><span class="nv">X</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">write</span><span class="p">(</span><span class="s s-Atom">'-+-+-'</span><span class="p">)</span>
<span class="p">,</span> <span class="s s-Atom">nl</span>
<span class="p">,</span> <span class="nf">print_row</span><span class="p">(</span><span class="nv">Y</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">write</span><span class="p">(</span><span class="s s-Atom">'-+-+-'</span><span class="p">)</span>
<span class="p">,</span> <span class="s s-Atom">nl</span>
<span class="p">,</span> <span class="nf">print_row</span><span class="p">(</span><span class="nv">Z</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">print_winner</span><span class="p">((</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="nv">Z</span><span class="p">))</span>
<span class="p">.</span>
<span class="nf">tuple_count</span><span class="p">((</span><span class="nv">P</span><span class="p">,</span><span class="nv">P</span><span class="p">,</span><span class="nv">P</span><span class="p">),</span> <span class="nv">P</span><span class="p">,</span> <span class="mi">3</span><span class="p">).</span>
<span class="nf">tuple_count</span><span class="p">((</span><span class="nv">P</span><span class="p">,</span><span class="nv">P</span><span class="p">,</span><span class="k">_</span><span class="p">),</span> <span class="nv">P</span><span class="p">,</span> <span class="mi">2</span><span class="p">).</span>
<span class="nf">tuple_count</span><span class="p">((</span><span class="nv">P</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">P</span><span class="p">),</span> <span class="nv">P</span><span class="p">,</span> <span class="mi">2</span><span class="p">).</span>
<span class="nf">tuple_count</span><span class="p">((</span><span class="k">_</span><span class="p">,</span><span class="nv">P</span><span class="p">,</span><span class="nv">P</span><span class="p">),</span> <span class="nv">P</span><span class="p">,</span> <span class="mi">2</span><span class="p">).</span>
<span class="nf">tuple_count</span><span class="p">((</span><span class="nv">P</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">),</span> <span class="nv">P</span><span class="p">,</span> <span class="mi">1</span><span class="p">).</span>
<span class="nf">tuple_count</span><span class="p">((</span><span class="k">_</span><span class="p">,</span><span class="nv">P</span><span class="p">,</span><span class="k">_</span><span class="p">),</span> <span class="nv">P</span><span class="p">,</span> <span class="mi">1</span><span class="p">).</span>
<span class="nf">tuple_count</span><span class="p">((</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">P</span><span class="p">),</span> <span class="nv">P</span><span class="p">,</span> <span class="mi">1</span><span class="p">).</span>
<span class="nf">tuple_count</span><span class="p">(</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="mi">0</span><span class="p">).</span>
<span class="nf">row</span><span class="p">((</span><span class="nv">Fst</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">),</span><span class="nv">Fst</span><span class="p">).</span>
<span class="nf">row</span><span class="p">((</span><span class="k">_</span><span class="p">,</span><span class="nv">Snd</span><span class="p">,</span><span class="k">_</span><span class="p">),</span><span class="nv">Snd</span><span class="p">).</span>
<span class="nf">row</span><span class="p">((</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">Thd</span><span class="p">),</span><span class="nv">Thd</span><span class="p">).</span>
<span class="nf">row</span><span class="p">(((</span><span class="nv">X</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">),(</span><span class="nv">Y</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">),(</span><span class="nv">Z</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">)),(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="nv">Z</span><span class="p">)).</span>
<span class="nf">row</span><span class="p">(((</span><span class="k">_</span><span class="p">,</span><span class="nv">X</span><span class="p">,</span><span class="k">_</span><span class="p">),(</span><span class="k">_</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="k">_</span><span class="p">),(</span><span class="k">_</span><span class="p">,</span><span class="nv">Z</span><span class="p">,</span><span class="k">_</span><span class="p">)),(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="nv">Z</span><span class="p">)).</span>
<span class="nf">row</span><span class="p">(((</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">X</span><span class="p">),(</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">Y</span><span class="p">),(</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">Z</span><span class="p">)),(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="nv">Z</span><span class="p">)).</span>
<span class="nf">row</span><span class="p">(((</span><span class="nv">X</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">),(</span><span class="k">_</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="k">_</span><span class="p">),(</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">Z</span><span class="p">)),(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="nv">Z</span><span class="p">)).</span>
<span class="nf">row</span><span class="p">(((</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">X</span><span class="p">),(</span><span class="k">_</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="k">_</span><span class="p">),(</span><span class="nv">Z</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">)),(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="nv">Z</span><span class="p">)).</span>
<span class="nf">can_move</span><span class="p">(</span><span class="nv">B</span><span class="p">,(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">))</span> <span class="p">:-</span>
<span class="s s-Atom">\+</span> <span class="nf">win</span><span class="p">(</span><span class="nv">B</span><span class="p">,</span><span class="k">_</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">subscript</span><span class="p">(</span><span class="nv">B</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="nv">R</span><span class="p">,</span><span class="k">_</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">subscript</span><span class="p">(</span><span class="nv">R</span><span class="p">,</span><span class="nv">X</span><span class="p">,</span><span class="s s-Atom">' '</span><span class="p">,</span><span class="k">_</span><span class="p">)</span>
<span class="p">.</span>
<span class="nf">do_move</span><span class="p">(</span><span class="nv">B1</span><span class="p">,(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">),</span><span class="nv">B2</span><span class="p">)</span> <span class="p">:-</span>
<span class="nf">turn</span><span class="p">(</span><span class="nv">B1</span><span class="p">,</span><span class="nv">P</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">subscript</span><span class="p">(</span><span class="nv">B1</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="nv">R1</span><span class="p">,</span><span class="nv">Rows</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">subscript</span><span class="p">(</span><span class="nv">R1</span><span class="p">,</span><span class="nv">X</span><span class="p">,</span><span class="s s-Atom">' '</span><span class="p">,</span><span class="nv">Items</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">subscript</span><span class="p">(</span><span class="nv">R2</span><span class="p">,</span><span class="nv">X</span><span class="p">,</span><span class="nv">P</span><span class="p">,</span><span class="nv">Items</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">subscript</span><span class="p">(</span><span class="nv">B2</span><span class="p">,</span><span class="nv">Y</span><span class="p">,</span><span class="nv">R2</span><span class="p">,</span><span class="nv">Rows</span><span class="p">)</span>
<span class="p">.</span>
<span class="nf">move</span><span class="p">(</span><span class="nv">B1</span><span class="p">,(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">),</span><span class="s s-Atom">''</span><span class="p">,</span><span class="nv">B2</span><span class="p">)</span> <span class="p">:-</span>
<span class="nf">can_move</span><span class="p">(</span><span class="nv">B1</span><span class="p">,</span> <span class="p">(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">))</span>
<span class="p">,</span> <span class="nf">do_move</span><span class="p">(</span><span class="nv">B1</span><span class="p">,(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">),</span><span class="nv">B2</span><span class="p">)</span>
<span class="p">,</span> <span class="p">!</span>
<span class="p">.</span>
<span class="nf">move</span><span class="p">(</span><span class="nv">B</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="s s-Atom">'cannot move there'</span><span class="p">,</span><span class="nv">B</span><span class="p">).</span>
<span class="nf">start_game</span> <span class="o">:-</span>
<span class="nv">B</span> <span class="o">=</span> <span class="p">((</span><span class="s s-Atom">' '</span><span class="p">,</span> <span class="s s-Atom">' '</span><span class="p">,</span> <span class="s s-Atom">' '</span><span class="p">),(</span><span class="s s-Atom">' '</span><span class="p">,</span> <span class="s s-Atom">' '</span><span class="p">,</span> <span class="s s-Atom">' '</span><span class="p">),(</span><span class="s s-Atom">' '</span><span class="p">,</span> <span class="s s-Atom">' '</span><span class="p">,</span> <span class="s s-Atom">' '</span><span class="p">))</span>
<span class="p">,</span> <span class="nf">retract</span><span class="p">(</span><span class="nf">board</span><span class="p">(</span><span class="k">_</span><span class="p">))</span>
<span class="p">,</span> <span class="nf">asserta</span><span class="p">(</span><span class="nf">board</span><span class="p">(</span><span class="nv">B</span><span class="p">))</span>
<span class="p">,</span> <span class="nf">print_board</span><span class="p">(</span><span class="nv">B</span><span class="p">)</span>
<span class="p">.</span>
<span class="nf">move</span><span class="p">(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">)</span> <span class="p">:-</span>
<span class="nf">board</span><span class="p">(</span><span class="nv">B1</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">move</span><span class="p">(</span><span class="nv">B1</span><span class="p">,(</span><span class="nv">X</span><span class="p">,</span><span class="nv">Y</span><span class="p">),</span><span class="nv">M</span><span class="p">,</span><span class="nv">B2</span><span class="p">)</span>
<span class="p">,</span> <span class="nf">write</span><span class="p">(</span><span class="nv">M</span><span class="p">)</span>
<span class="p">,</span> <span class="s s-Atom">nl</span>
<span class="p">,</span> <span class="nf">retract</span><span class="p">(</span><span class="nf">board</span><span class="p">(</span><span class="k">_</span><span class="p">))</span>
<span class="p">,</span> <span class="nf">asserta</span><span class="p">(</span><span class="nf">board</span><span class="p">(</span><span class="nv">B2</span><span class="p">))</span>
<span class="p">,</span> <span class="nf">print_board</span><span class="p">(</span><span class="nv">B2</span><span class="p">)</span>
<span class="p">.</span>
</pre></div></td></tr></table></div>
<p>It's tic-tac-toe.
The joke is, I'm proud of writing the core logic of tic-tac-toe, and managing to avoid adding stuff to the spec like extra dimensions or larger boards or extra players or nested boards or drafting rules or <em>crafting mechanics and a sixty-hour story mode</em>.
(Things I haven't seen done are in italics.)
(I also didn't write an AI, but the core logic is without side effects, so it should be totally doable.)</p>
<p>Point is, using Prolog, I've finally managed to prototype out the full core logic of a game, which is huge to me.
For now, I want to focus on taking this logic more or less exactly, and using it with GUI code, so I can try to teach myself GUIs without things going off the rails again.</p>
<p>While I'm here, I should probably talk about my... interesting use of whitespace.
Turns out Prolog doesn't seem to like trailing commas, so I decided to move the delimiters to the following line.
This will come in handy when I'm diffing this code, or extending it.
It gives things a very distinctive shape, which means that syntax errors should be pretty obvious.</p>
<p>And a little bit about the actual design.
I put all of the state into a single data structure, so changes to it are as close to atomic as I know how.
I want to keep up the setup of writing game rules as mappings between game states, try to compose different systems.
Maybe sometime I can try to put these ideas into my own tutorial concept.
For now, I have to prove to myself that they can work.</p>
<p>But yeah, this needs a GUI, because typing the move commands in the REPL is... not great.</p>
Conworld Codex - Data Structures 2018-09-282018-09-28T04:00:00-04:002018-09-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-28:/conworld-codex-data-structures-2018-09-28<p class="first last">I seem to have worked out some of the things I DON'T want to do...</p>
<p>In this post:</p>
<ul class="simple">
<li>Working through what I need for aping historical methods, and whether I want to ape historical methods.</li>
<li>On balance, I don't.</li>
<li>I try to work out what I should be doing instead.</li>
<li>And allude to experimenting with fiddly concepts.</li>
</ul>
<hr class="docutils" />
<p>History deals with relics and narratives, and those both seem like good things to try to model.
Given a representative of a relic, we could have predicates for things like "made of such-and-such material".
We also want to have some way of considering "changes that already happened", like "the relic acquired this notch after event X but no later than event Y".</p>
<p>One thing that I feel I haven't settled on properly at this point is whether I want it to be possible for Conworld Codex to permit making statements about reasonable applications of the historic method at a particular time point.
My inclination is to say, I want the primary data of Conworld Codex to be the accounts given at particular points in time.
For systems with different goals, maybe the priorities work out differently.</p>
<p>This means, I think, that I want predicates <em>something</em> like "within this arbitrary space-time interval, someone with this identity set forth this narrative", related with ideas of causation and modal logic of belief.
Or maybe not.
The tension here is, I'm making statements entirely about a fictional world, and I'm trying to avoid privileging any narrative as "objective" when it comes to setting down what happened within that world, <strong>but</strong> I also have this idea of trying to put these narratives in a form where they can be reasoned about, and had concordances between them, more or less.
But saying "this story-teller existed" is itself an assertion with narrative consequences.</p>
<p>I might need to revisit an idea that I had of framing (not necessarily in the sense of a <em>framing device</em>) the narratives that make up the Linked Seas chronology as originating from notional "direct communication" between the fictional world and the real one.
I guess that ends up equating to "the author of the database posits the that the existence of these narrators and their narratives is axiomatic".
It seems to me that in that context, the value of designing and populating such a database would be in modeling and noting contradiction.</p>
<p>I mean, if the whole thing is supposed to represent an "objective timeline", then basically all I need is a predicate wrapped around a list of relatively simple terms that just put all of the relevant data in strings.
Maybe put something like that together in Python or Lua, because there's no need for logic programming in that context, and I'd get stuff like "variable scopes that I'm used to the behavior of".
But instead, I want to try to put together something that expressly does not try to conform to a single objective narrative.</p>
<p>What I'd need for what I'm describing here skews a little more into psychology than history, maybe sociology...
I'm not terribly sure of more than that, I know I'm out of my depth, and I'm trying to challenge myself.
Basically, given a narrator, work outward to create a biographical sketch.
Relate "objective" elements to more than one sketch, so that different biographies incorporate different perspectives and beliefs about an element.
Make the elements themselves opaque; details are only "visible" by how they relate to the narrators.</p>
<p>This seems reasonable as a means of organizing my notes, if nothing else.
I think I've mentioned this before, but I've wanted something like logic programming for a while, without quite realizing it.</p>
<p>Since I wrote up the bulk of this post, I've been trying out more tutorials and experimenting with data structures.
I think the big takeaway from my experiments is that I shouldn't mess too much with heavily recursive processing unless I'm ready to really commit to posing myself really hairy logic puzzles.
The procedural behavior of recursive goals can sometimes lead in really strange places.</p>
<p>The way I feel like taking this is to write up background notes for Kena'o, pick a few narrators to discuss the life of, write up notes on them, and figure out how to fit them in.</p>
<hr class="docutils" />
<p>Next time, disordered setting notes, and the predicates I derive from them.</p>
Draw a Box 2018-09-272018-09-27T04:00:00-04:002018-09-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-27:/draw-a-box-2018-09-27<p class="first last">More planes.</p>
<p>In this post:</p>
<ul class="simple">
<li>Planes woo.</li>
</ul>
<hr class="docutils" />
<p>Since I started the fourth sheet, I have drawn:</p>
<ul class="simple">
<li>10 planes on September 20.</li>
<li>10 planes on September 21.</li>
<li>10 planes on September 22.</li>
<li>10 planes on September 23.</li>
<li>10 planes on September 24, plus one I'm not counting because it was bad.</li>
<li>10 planes on September 25.</li>
<li>10 planes on September 26, finishing out the sheet.</li>
</ul>
<p>For a total of 560 lines this week,
and 800 lines on the fourth sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Conworld Codex - Planning 2018-09-262018-09-26T04:00:00-04:002018-09-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-26:/conworld-codex-planning-2018-09-26<p class="first last">Uncharted waters...</p>
<p>In this post:</p>
<ul class="simple">
<li>What I'm going to do in each post this week.</li>
<li>General ideas for the two central posts this week.</li>
</ul>
<hr class="docutils" />
<p>Things went late today, so I'm going to try to be quick about this whole "planning" thing.
I'm reading over some Prolog tutorials now, and it really is seeming like something that I was missing before, and trying and failing to recreate in other languages.
Since I want to try using it with Conworld Codex, that means I need to figure out what the relevant representation should actually look like, and what kind of operations it should support.</p>
<p>My plan for "attempt to actually do stuff" Conworld Codex is to attempt to draw inspiration from the historical method, and make the "codex" be more of a catalog of objects, texts, etc.
This will probably end up needing some form of temporal logic, maybe?</p>
<p>So, for my two project entries this week, I want to:</p>
<ul class="simple">
<li>Specify the data structures and predicates that I think will be needed.</li>
<li>Try out the relevant features in toy examples, because I think I'll need to give this more thought.</li>
</ul>
<p>I'd think more about stretch goals and stuff but it's late and I want to wrap this up.</p>
<hr class="docutils" />
<p>Next time, I try to work out what the domain I intend to model looks like.</p>
Weekly Roundup 2018-09-252018-09-25T04:00:00-04:002018-09-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-25:/weekly-roundup-2018-09-25<p class="first last">A Prolog of things to come? ... Nah...</p>
<ul class="simple">
<li>Main project: I read the beginning of a book, and mostly whined about it.</li>
<li>Draw a Box: I started drawing planes, oOOoooh.</li>
<li>Free-Topic: I tried to get back into Conworld Codex using Prolog, and rapidly discovered that, while Prolog is a powerful tool for what I'm trying to do, I don't really understand it yet, or the historical method(s).</li>
</ul>
<p>Next week, I'm going to try to sketch out what it would take to use Prolog for constructed history.
(On the logic that I don't want to keep jamming stuff in a flat file, and Prolog is significantly more powerful than the "not-a-flat-file" stuff I was attempting before.)</p>
Reading Retrospective 2018-09-242018-09-24T04:00:00-04:002018-09-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-24:/reading-retrospective-2018-09-24<p class="first last">A week of reading.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I think about this last week, all in all.</li>
<li>How well I followed the plan.</li>
<li>Thoughts on the future.</li>
</ul>
<hr class="docutils" />
<p>Over the past week, I accomplished my overall goal, so that's good.</p>
<p>I mentioned a lot of the stuff that's going to come up in this post during last week, but I'm putting it here anyway.</p>
<p>I ended up following a more aggressive schedule for reading than I originally intended, which ended up working out well because it was completely achievable.</p>
<p>The point of all of this was to read the latest draft of the beginning of my wife's novel, and as I said, I did that.
The next logical thing to do is obvious, since there are, of course, more books to look at.
I don't know if or when I'm up for that, though...
One possibility is, something we discussed but didn't follow up on, was having some kind of soundtrack for me to put on while reading the drafts.
That sounds like it could make things a bit better.</p>
<p>Either way, I did it.
It's been done.
I hope I don't need to use a weekly project for it if I do this again, because I think my posts this week were... underwhelming.
But whatever, it's done.
It's done.</p>
<hr class="docutils" />
<p>Next week, I'm going to take a different tack on Conworld Codex.</p>
Reading 2018-09-232018-09-23T04:00:00-04:002018-09-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-23:/reading-2018-09-23<p class="first last">Well, I did it.</p>
<p>In this post:</p>
<ul class="simple">
<li>Progress report.</li>
<li>I could feel less enthusiastic about this, I guess.</li>
</ul>
<hr class="docutils" />
<p>Because of the chapter-a-day thing, I finished the first book last night, and have today to reflect on it.
Handy!
Anyway, it's done.</p>
<p>There's some stuff toward the end that I'm fairly sure I don't remember from last time.
After some rough going in chapter six, chapter seven did feel like it was reversing course in terms of stuff that takes me out of the story.</p>
<p>I remember talking to my wife about how the story felt last time around, and how it seemed like I was doing a bad job of conveying stuff, so whatever.
It's like, the old version made it feel like I couldn't imagine things going forward for the protagonist.
I don't know what the new version of that section is like, but, like... am I excited to find out?</p>
<p>Like, I feel kind of bad that I'm not hyped for my wife's writing, but the last draft I looked at didn't really seem to be "for me" in some sense, and I'm not really sure about this one.
I felt a similar way about a book she recommended to me.
Maybe I should take another look...</p>
<hr class="docutils" />
<p>Next time, what I thought of this week.</p>
<p>PS Working with Prolog is melting my brain, and I've barely accomplished anything.</p>
Conworld Codex 2018-09-222018-09-22T04:00:00-04:002018-09-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-22:/conworld-codex-2018-09-22<p class="first last">It turns out logic programming is a lot easier if you're not trying to implement it from scratch in terms of an entirely different declarative framework.</p>
<p>In this post:</p>
<ul class="simple">
<li>Prolog exists!</li>
<li>Prolog is... <em>extremely</em> suited to Conworld Codex.</li>
<li>Turns out I was so distracted with stuff that was <em>not</em> "modeling my domain information", that I didn't... model... my domain information.</li>
</ul>
<hr class="docutils" />
<p>I recently remembered that I've occasionally tried to get into logic programming with Prolog, and it occurred to me that using Prolog might allow me to have Conworld Codex functionality without messing with GUI code.</p>
<p>So, let's try porting the bits of Conworld Codex I care about to <a class="reference external" href="http://www.swi-prolog.org/">SWI-Prolog</a>...</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span>
<span class="normal">74</span>
<span class="normal">75</span>
<span class="normal">76</span>
<span class="normal">77</span>
<span class="normal">78</span>
<span class="normal">79</span>
<span class="normal">80</span>
<span class="normal">81</span>
<span class="normal">82</span>
<span class="normal">83</span>
<span class="normal">84</span></pre></div></td><td class="code"><div><pre><span></span><span class="nf">event</span><span class="p">(</span><span class="nv">Cause</span><span class="p">)</span> <span class="p">:-</span> <span class="nf">causes</span><span class="p">(</span><span class="nv">Cause</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">).</span>
<span class="nf">event</span><span class="p">(</span><span class="nv">Effect</span><span class="p">)</span> <span class="p">:-</span> <span class="nf">causes</span><span class="p">(</span><span class="k">_</span><span class="p">,</span><span class="nv">Effect</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">).</span>
<span class="nf">event</span><span class="p">(</span><span class="nv">Part</span><span class="p">)</span> <span class="p">:-</span> <span class="nf">makes_up</span><span class="p">(</span><span class="nv">Part</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">).</span>
<span class="nf">event</span><span class="p">(</span><span class="nv">Whole</span><span class="p">)</span> <span class="p">:-</span> <span class="nf">makes_up</span><span class="p">(</span><span class="k">_</span><span class="p">,</span><span class="nv">Whole</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">).</span>
<span class="nf">event</span><span class="p">(</span><span class="nv">Event</span><span class="p">)</span> <span class="p">:-</span> <span class="nf">topic_of</span><span class="p">(</span><span class="nv">Event</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">).</span>
<span class="nf">topic</span><span class="p">(</span><span class="nv">Topic</span><span class="p">)</span> <span class="p">:-</span> <span class="nf">topic_of</span><span class="p">(</span><span class="k">_</span><span class="p">,</span><span class="nv">Topic</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">).</span>
<span class="nf">teller</span><span class="p">(</span><span class="nv">Teller</span><span class="p">)</span> <span class="p">:-</span> <span class="nf">causes</span><span class="p">(</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">Teller</span><span class="p">,</span><span class="k">_</span><span class="p">).</span>
<span class="nf">teller</span><span class="p">(</span><span class="nv">Teller</span><span class="p">)</span> <span class="p">:-</span> <span class="nf">makes_up</span><span class="p">(</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">Teller</span><span class="p">,</span><span class="k">_</span><span class="p">).</span>
<span class="nf">teller</span><span class="p">(</span><span class="nv">Teller</span><span class="p">)</span> <span class="p">:-</span> <span class="nf">topic_of</span><span class="p">(</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">Teller</span><span class="p">,</span><span class="k">_</span><span class="p">).</span>
<span class="nf">commentary</span><span class="p">(</span><span class="nv">Commentary</span><span class="p">)</span> <span class="p">:-</span> <span class="nf">causes</span><span class="p">(</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">Commentary</span><span class="p">).</span>
<span class="nf">commentary</span><span class="p">(</span><span class="nv">Commentary</span><span class="p">)</span> <span class="p">:-</span> <span class="nf">makes_up</span><span class="p">(</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">Commentary</span><span class="p">).</span>
<span class="nf">commentary</span><span class="p">(</span><span class="nv">Commentary</span><span class="p">)</span> <span class="p">:-</span> <span class="nf">topic_of</span><span class="p">(</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="k">_</span><span class="p">,</span><span class="nv">Commentary</span><span class="p">).</span>
<span class="nf">topic_of</span><span class="p">(</span>
<span class="s s-Atom">salt_mill_critiqued</span><span class="p">,</span>
<span class="s s-Atom">salt</span><span class="p">,</span>
<span class="s s-Atom">the_omniscient_narrator_from_the_lua_version</span><span class="p">,</span>
<span class="s2">"Deoshen Aternabel's salt mill \c</span>
<span class="s2"> design was intended to use sun, \c</span>
<span class="s2"> wind, etc, to extract salt from \c</span>
<span class="s2"> the ocean."</span><span class="p">).</span>
<span class="nf">topic_of</span><span class="p">(</span>
<span class="s s-Atom">salt_mill_critiqued</span><span class="p">,</span>
<span class="s s-Atom">deoshen_aternabel</span><span class="p">,</span>
<span class="s s-Atom">the_omniscient_narrator_from_the_lua_version</span><span class="p">,</span>
<span class="s2">"Deoshen Aternabel designed a \c</span>
<span class="s2"> 'salt mill'. Despite the care he \c</span>
<span class="s2"> put into its architecture, he \c</span>
<span class="s2"> never addressed the fact that \c</span>
<span class="s2"> his design was impractical in \c</span>
<span class="s2"> the cool, moist climate of Gaewon."</span><span class="p">).</span>
<span class="nf">topic_of</span><span class="p">(</span>
<span class="s s-Atom">aternabel_at_spansen</span><span class="p">,</span>
<span class="s s-Atom">atsimats_aternabel</span><span class="p">,</span>
<span class="s s-Atom">the_omniscient_narrator_from_the_lua_version</span><span class="p">,</span>
<span class="s2">"Admiral Atsimats Aternabel saw \c</span>
<span class="s2"> Gaewon's victory over Bilus as a \c</span>
<span class="s2"> chance to bring glory to his \c</span>
<span class="s2"> family by realizing Deoshen's \c</span>
<span class="s2"> design. He framed it in terms of \c</span>
<span class="s2"> the glory of Gaewon."</span><span class="p">).</span>
<span class="nf">causes</span><span class="p">(</span>
<span class="s s-Atom">bilusic_population_boom</span><span class="p">,</span>
<span class="s s-Atom">bilusic_expansion</span><span class="p">,</span>
<span class="s s-Atom">the_omniscient_narrator_from_the_lua_version</span><span class="p">,</span>
<span class="s2">"The reigning belief in Bilus's \c</span>
<span class="s2"> government was that war would \c</span>
<span class="s2"> address the crowding, either \c</span>
<span class="s2"> through colonization or attrition"</span><span class="p">).</span>
<span class="nf">causes</span><span class="p">(</span>
<span class="s s-Atom">salt_mill_critiqued</span><span class="p">,</span>
<span class="s s-Atom">aternabel_at_spansen</span><span class="p">,</span>
<span class="s s-Atom">the_omniscient_narrator_from_the_lua_version</span><span class="p">,</span>
<span class="s2">"Admiral Atsimats Aternabel \c</span>
<span class="s2"> wishes to realize the designs of \c</span>
<span class="s2"> his grandfather(?)"</span><span class="p">).</span>
<span class="nf">causes</span><span class="p">(</span>
<span class="s s-Atom">bilusic_expansion</span><span class="p">,</span>
<span class="s s-Atom">gaewom_empire</span><span class="p">,</span>
<span class="s s-Atom">the_omniscient_narrator_from_the_lua_version</span><span class="p">,</span>
<span class="s2">"The defeat of the Bilusic navy \c</span>
<span class="s2"> gives Gaewon the confidence to \c</span>
<span class="s2"> expand, itself"</span><span class="p">).</span>
<span class="nf">makes_up</span><span class="p">(</span>
<span class="s s-Atom">aternabel_at_spansen</span><span class="p">,</span>
<span class="s s-Atom">gaewon_empire</span><span class="p">,</span>
<span class="s s-Atom">the_omniscient_narrator_from_the_lua_version</span><span class="p">,</span>
<span class="s2">"Admiral Atsimats Aternabel's \c</span>
<span class="s2"> speech was part of a general \c</span>
<span class="s2"> sentiment that Gaewon had \c</span>
<span class="s2"> 'proven itself' by defeating Bilus"</span><span class="p">).</span>
<span class="nf">makes_up</span><span class="p">(</span>
<span class="s s-Atom">plague_of_gaewon</span><span class="p">,</span>
<span class="s s-Atom">gaewon_empire</span><span class="p">,</span>
<span class="s s-Atom">the_omniscient_narrator_from_the_lua_version</span><span class="p">,</span>
<span class="s2">"The Plague threw the island of \c</span>
<span class="s2"> Gaewon into chaos, severing \c</span>
<span class="s2"> administrative ties with the colonies"</span><span class="p">).</span>
</pre></div></td></tr></table></div>
<p>... Well.
That was insultingly easy compared to trying to role the detailed relational stuff myself.
The first twelve clauses are, as near as I can tell, everything I cared about from the Python version.
I'm not certain, because I went a few months I think, without looking at the code, so it's not obvious to me what I was doing back then.
The other issue is that the Lua version predates my big idea of "It should focus on collating in-universe perspectives", so the data doesn't make any sense.
I'm going to try redoing it with the text version.</p>
<p>I have a rough draft of the text version in Prolog now.
It turns out it's somehow even less suited to the above format, so I'm going to need to think long and hard about what I actually want to represent, and how.
Fortunately, expressing this stuff in Prolog appears to be extremely low-friction, so I'm really happy I finally thought to try this out.</p>
Reading 2018-09-212018-09-21T04:00:00-04:002018-09-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-21:/reading-2018-09-21<p class="first last">Starting to feel a little reluctant, again.</p>
<p>In this post:</p>
<ul class="simple">
<li>Progress report</li>
<li>Reading this is... difficult.</li>
</ul>
<hr class="docutils" />
<p>I ended up trying for a chapter a day rather than a chapter a post, so that's two chapters since the last post, and one left in the part.</p>
<p>The most recent chapter is pretty much as I remember it, and I kind of feel like it's getting into the same tonal area that got me fatigued with the previous version of this I read.</p>
<p>I've tried explaining this before, and I think I must have done a really bad job...
It's hard for me to take in such a depressing sequence of events and feel hooked, like I want to see more.
Clearly this is a matter of individual taste, since other people have read much more of these drafts.
Like, I think the air of hopelessness is intentional, but it's just not working for me.</p>
<p>Or maybe it's not intentional; like I alluded to, I tried explaining this earlier, and it seems like my wife wasn't seeing the same things in her work that I was.</p>
<p>I just wish I could get this to make a bit more sense, because it really feels like she didn't get why this was so hard for me.</p>
<p>I mean, I know I'm not making too clear of a case here, because I'm not going into any specifics at all.</p>
<hr class="docutils" />
<p>Next time, the last chapter in this part.</p>
Draw a Box 2018-09-202018-09-20T04:00:00-04:002018-09-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-20:/draw-a-box-2018-09-20<p class="first last">Aw yeah, moving on through the first lesson.</p>
<p>In this post:</p>
<ul class="simple">
<li>Strange figures of greater dimension</li>
</ul>
<hr class="docutils" />
<p>Since I started the third sheet, I have drawn:</p>
<ul class="simple">
<li>30 lines on September 13. I'll be surprised if I can fit on more than a day more.</li>
<li>31 lines on September 14. Done.</li>
<li>30 lines on September 15, on the supplemental sheet. This is filling up fast, because I'm trying to avoid closely-spaced parallel lines.</li>
<li>30 lines on September 16, on the supplemental sheet. I think I should move on to the next sheet for now.</li>
<li>10 planes on September 17, on the fourth sheet.</li>
<li>10 planes on September 18, on the fourth sheet.</li>
<li>10 planes on September 19, on the fourth sheet.</li>
</ul>
<p>For a total of 361 lines this week,
481 lines on the third sheet,
60 lines on the supplemental sheet,
and 240 lines on the fourth sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.
Although I guess I was wrong last week.
Whoops.</p>
Reading 2018-09-192018-09-19T04:00:00-04:002018-09-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-19:/reading-2018-09-19<p class="first last">No tag?!</p>
<p>In this post:</p>
<ul class="simple">
<li>Background information</li>
<li>Progress report</li>
</ul>
<hr class="docutils" />
<p>Okay, here's the deal.
My wife has done a lot more than I have, so far as "put together a coherent, sensible, long-form story" goes, and she's asked me to read her draft.
The last time I tried to read a draft of this story, it was too miserable for me and I gave up.
But she gave me a new draft, and it's definitely different.
Different names, different framing, some different decisions on tone...</p>
<p>Thing is, to be honest, I'm still not sure if it's my cup of tea.
I've had this feeling before about other things, that were really engaging once I put the effort in...
But to see if that'll happen, I have to put the effort in.</p>
<p>Hence this series.</p>
<p>The novel is broken into multiple "books".
My goal for this week is to finish the first "book".
By page count, I'm about halfway through.
(I had gotten a few chapters in, and my basic plan is to go about a chapter at a time.)</p>
<p>Okay, so, the reservation I had on doing this like this is, I have no idea how to talk about what I'm reading.
I believe I'd read past the end of book 1 previously, so everything I'm going to read is going to fit into a context of revised content.
(That was a lot of tenses.)</p>
<p>I guess all I have to say right now is, I did the reading for this entry, so I'm on track.</p>
<hr class="docutils" />
<p>Next time, another chapter.</p>
Weekly Roundup 2018-09-182018-09-18T04:00:00-04:002018-09-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-18:/weekly-roundup-2018-09-18<p class="first last">Just taking it easy.</p>
<ul class="simple">
<li>Main project: I fixed code blocks a little, and thought about where I'm going next.</li>
<li>Draw a Box: I almost finished the third sheet.</li>
<li>Free-Topic: More horror-movie thoughts.</li>
</ul>
<p>Next week, I try to read some unreleased writing.</p>
Site Design Retrospective 2018-09-172018-09-17T04:00:00-04:002018-09-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-17:/site-design-retrospective-2018-09-17<p class="first last">That was over with quite fast.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I think about this last week, all in all.</li>
<li>How well I followed the plan.</li>
<li>Reasonable near-term goals.</li>
<li>Thoughts on further-out improvements.</li>
</ul>
<hr class="docutils" />
<p>The plan this week was kind of deliberately looser.
I gave myself one goal that I hadn't figured out ahead of time, and figured I could just do speculation or diary-style stuff for the rest.</p>
<p>That's about what I did, and I'm okay with that.
I figured out how to solve the issue I noticed, by putting words together and remembering that HTML attributes have names for reasons, and then I rambled about stuff I want to do in the future.</p>
<p>I don't really have any more thoughts on changes to make to the site design.
It would be nice, to be sure, if more fit inside the code blocks without scrolling, but that's not how things are right now.</p>
<p>One thing that I've come to realize is that I'll get a lot further with most of my non-coding projects if I can get past a self-imposed limitation I've chosen.
Devoting a week to these things seems to help, so that's what I want to do next.</p>
<p>In the last few days, I also messed around with a thing for OMI that might end up becoming its own project...</p>
<p><img alt="Drafts of logos for the OMI, in head-on and perspective form" src="https://mwchase.neocities.org/images/draft_omi_logos.png" /></p>
<hr class="docutils" />
<p>Next week, I don't know how I'm going to write about it, but I have some reading to do.</p>
Site Design More Planning 2018-09-162018-09-16T04:00:00-04:002018-09-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-16:/site-design-more-planning-2018-09-16<p class="first last">Ramble ramble</p>
<p>In this post:</p>
<ul class="simple">
<li>OMI thoughts</li>
</ul>
<hr class="docutils" />
<p>I put down "more planning", but I don't know what I'm going to plan, really.
Maybe think about the OMI.</p>
<p>The idea of the One Man Institute is that it's a collection of resources for realistic world-building, with some advice on how much of the rest to actually apply, and how much to show your work, but the bulk of it being real scientific principles, and explorations of hypothetical situations in which something fundamental is changed or introduced, allowing the appearance of a physical law being "bent" or "broken".</p>
<p>For an example of the latter, in a setting with some kind of size-change technology that alters the matter making stuff up rather than changing the composition, we can expect that, if light works similarly to real light, then shrinking something would change its colors, and alter its passage of time.
This is something that's not intuitively obvious if you don't know the physical principles, but the effects can be presented in a systematic fashion without requiring an explanation of the underlying mechanics.</p>
<p>So, that's the kind of thing I'd want for some of the content, but also stuff like counterfactuals in human evolution and social development.
Ways of presenting evolutionary phenomena that didn't affect humans, affecting an intelligent species, but in a less ridiculous way than some high-profile franchises have done.</p>
<p>I'd really like to finish some long-form writing before acting like I have stuff to say here, though, so for the moment I just want to focus on planning the design and layout.</p>
<p>I've been a fan of <a class="reference external" href="https://tiddlywiki.com/">TiddlyWiki</a> for over a decade.
It's what the original One-Man Institute of Inapplicable Physics (offline, but backed up) is written in, and it's probably what I'll use for the One-Man Institute of Counterfactual Experimentalism.</p>
<p>My plan, completely untested, is to try dropping a TiddlyWiki file into the source tree, and have Pelican rewrite it.
The result should be a TiddlyWiki that lives inside the Three Dollar Quill formatting.</p>
<p>Unlike the rest of Three Dollar Quill, TiddlyWiki leans heavily on Javascript to present content.
It's basically a single-page-app that doesn't load anything extra from the server.
The user just clicks links to show more data that was pre-loaded.</p>
<p>In terms of content, I want to, before I put anything up, write up my ideas on How To Write Good, and try to apply them to my writing, after I've completed the Romance Instrumentality Project and rewritten more specific advice from other people.
(The rewritten advice will be entirely for my own benefit; instead of posting it, I'll just link to the source material, because I have no plans to say anything that isn't already <em>in</em> the source material.)</p>
<p>After that, I want to see if I can build out the worldbuilding recommendations from the writing advice, somehow.
Have a chain of justification, so that all worldbuilding advice from the OMI is expressed in terms of how it serves the writing, because I want to take the position that worldbuilding should serve writing.</p>
<p>Anyway, this post is late already, let's pack it in.</p>
<hr class="docutils" />
<p>Next time, I look over this week.</p>
Horror Movie Reflections: The Redeemer: Son of Satan2018-09-14T04:00:00-04:002018-09-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-14:/horror-movie-reflections-the-redeemer-son-of-satan<p class="first last">If you're making horror, don't make this.</p>
<p>In this post:</p>
<ul class="simple">
<li>A look at why I found this movie pretty disappointing, and what lessons we can take from that.</li>
</ul>
<hr class="docutils" />
<p>Recently-ish, we watched <em>The Redeemer: Son of Satan</em>.
This is a horror movie about a group of people who get lured into their old school (I think), for a fake reunion, that is actually a means of trapping them so a preacher who is possessed by a demon (or something) can pick them off one by one.</p>
<p>The effort of trying to articulate how badly this movie missed the mark of effective horror, I think helped me to better understand how horror is supposed to work.
So, from all of my trash-talking of this movie, here's how I think horror is supposed to work.</p>
<p>Horror stories are part of a literary tradition, that, like all literary traditions, has its roots in human experience.
An invocation of supernatural elements represents a way to try to comprehend forces, whether natural, statistical, or societal, that are not immediately obvious to understand.
To be really punchy in its representation of such forces, then, I think it should be possible to interpret supernatural elements as a metaphor for a more naturalistic situation, even if the text is unequivocal about the supernatural aspects.</p>
<p>For example, a killer ghost can be interpreted as fitting into anxieties about persistent social ills, copycat killers, etc, without having to chart out or explain what could be happening naturalistically.
We can interpret "What if killing the criminal isn't enough to stop the crimes?" through the lines of considering punitive and capital punishment, the role of spectacle, the forces that give rise to crime, or we can watch killer ghosts catch fire and make wisecracks.
I feel like I'm not quite articulating this right.
It's not that I have any position on whether horror movies contribute to dialogues about complex issues, or whether they have any moral duties in terms of what questions to raise or positions to take.
This is purely a question of whether there's proper emotional weight.
I will even accept "Hey, here's a thing that's generally regarded as creepy."</p>
<p>Contrasting with <em>The Redeemer</em>, a movie about a preacher who makes up stuff from the bible during his sermon and nobody calls him on it, and also kills a bunch of people because... sin?
He's maybe possessed by a demon, which definitely gives him an extra thumb, seems to give him off-camera teleportation abilities, and somehow or other allows him to successfully use extremely avoidable-seeming deathtraps.</p>
<p>Like, I don't have anything with which to relate "people are dying because they stand in the exact spot required for the deathtrap to even touch them".
The somewhat more credible kills are done with guns and drowning, which raises the question of "why did they bring in a supernatural element?"
The big thing the barely-explained supernatural elements seem to bring in is a license to not think too hard about editing or continuity.</p>
<p>Like, the killer suddenly appears in the bathroom that two women ducked into, which appears to have urinals (?), chases one out of what appears to be the only door, kills the other, then vanishes from the room, to appear in the library with a completely different appearance.
I suppose if I were dealing with a serial killer, I'd prefer one that didn't have such abilities, but "teleporting quick-change artist with precognition" doesn't have emotional heft.
Objectively, it's a worse situation, but when it comes to things that connect with us emotionally, people aren't applying rational objectivity.</p>
<p>I feel like I should have some kind of encapsulation of all of my ideas here, but frankly I did all that already.
Read the beginning again if you feel like that would be nice; I'm not typing it up again.</p>
Site Design Accidentally Done 2018-09-142018-09-14T04:00:00-04:002018-09-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-14:/site-design-accidentally-done-2018-09-14<p class="first last">Faster than I expected.</p>
<p>In this post:</p>
<ul class="simple">
<li>... Whoops.</li>
</ul>
<hr class="docutils" />
<p>"Hm, the problem is that there's a bunch of vertical space to fill evenly, and the scrollbar adds extra stuff on one, which throws off the alignment."</p>
<p>"..."</p>
<div class="highlight"><pre><span></span><span class="gh">diff --git a/static/css/main.scss b/static/css/main.scss</span>
<span class="gd">--- a/static/css/main.scss</span>
<span class="gi">+++ b/static/css/main.scss</span>
<span class="gu">@@ -196,6 +196,10 @@</span>
<span class="w"> </span> max-width: 600px;
<span class="w"> </span>}
<span class="gi">+.code, .linenos {</span>
<span class="gi">+ vertical-align: top;</span>
<span class="gi">+}</span>
<span class="gi">+</span>
<span class="w"> </span>.highlight pre {
<span class="w"> </span> background-color: $base03;
<span class="w"> </span> color: $base0;
</pre></div>
<p>"... Oh."</p>
<p>Turns out these problems are a lot easier when you come at them from the right angle.</p>
<p>While I'm in here, I'm going to drop that max-width a little to let the right-hand side breathe, or at least not be covered up.
I pulled it in 9 pixels, which is a sign to me that I should be trying to put more math in these, because that's an arbitrary amount.
Actually, even further.
Also, if I keep the widths and font sizes like this, I'm going to have to start rewrapping code samples at slightly ridiculous line widths.
Really tempted to just drop the code block font size way down.
Like, to 10px.
I think that still looks readable.
Or not, if I employ the advanced technique of "switch tabs, switch tabs back, squint"</p>
<p>Current plan going forward: rewrap code samples at line 40.</p>
<hr class="docutils" />
<p>Next time, I just relax, I don't know.</p>
<hr class="docutils" />
<p>I've come to the conclusion that it'd do me some good to kind of modulate how intensely I work in a given week.
Basically, have some weeks without projects.</p>
<p>In any case, I was thinking more about Ghosts of Departed Proofs, and I'm asking myself enough questions about how I actually want it to be used, that I think I'm best served by switching to a more concrete project.</p>
<p>Until I get into that, though, I found myself thinking about various newtype and newtype-adjacent things I've attempted in Rust.</p>
<p>(I think I should put effort into getting my thoughts down as I have them, somehow.
I had various thoughts earlier today that I thought, "Oh, that should go in the blog" and now I don't remember them.)</p>
<p>Probably the best thing for me to be working on is that "other reading" I think I mentioned.
Get that done, and then look into ebooks to grab, or ebooks I already have.</p>
<p>Oh yeah, one thing I was thinking about earlier was a cool logo for the OMI, and how I'd like to scope out getting back into writing it.
Probably going to be a completely fresh version of it, since I want to have a different focus, and also redo the theming in line with the rest of the blog.</p>
<p>One thing that would really make the OMI credible is <em>other writing</em>, probably in the vein of Linked Seas, so I figure I can plan soon, but putting the rubber to the road is blocked on, I really need to do that reading, so I don't feel bad doing other reading.</p>
<p>... This post failed to publish, apparently because there's too many files to upload at once.
(This is post-fixing-the-stylesheet.)</p>
Draw a Box 2018-09-132018-09-13T04:00:00-04:002018-09-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-13:/draw-a-box-2018-09-13<p class="first last">WHOO</p>
<p>In this post:</p>
<ul class="simple">
<li>WHOO</li>
</ul>
<hr class="docutils" />
<p>Since I started the third sheet, I have drawn:</p>
<ul class="simple">
<li>30 lines on September 6.</li>
<li>30 lines on September 7.</li>
<li>30 lines on September 8.</li>
<li>30 lines on September 9.</li>
<li>30 lines on September 10.</li>
<li>30 lines on September 11.</li>
<li>30 lines on September 12. Like one or two days left.</li>
</ul>
<p>For a total of 210 lines this week,
and 420 lines on the third sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Site Design Planning 2018-09-122018-09-12T04:00:00-04:002018-09-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-12:/site-design-planning-2018-09-12<p class="first last">The devil is in the details</p>
<p>In this post:</p>
<ul class="simple">
<li>One specific aspect of the theme rendering bothers me. I will fix it.</li>
<li>GDP thoughts.</li>
</ul>
<hr class="docutils" />
<p>So, I'm trying out this week something along the lines of "a small project, plus idle speculation about other things".</p>
<p>For the little project, I'm trying to fix an issue I noticed with the code block rendering.</p>
<p>Basically, I expect that the line numbers next to code blocks should line up with the code.</p>
<p>Currently, the line numbers and the code have a vertical offset between them, at least in Firefox and I think Safari.</p>
<p>It appears that this offset derives in some way from the presence of a horizontal scrollbar at the bottom of the code block, that is only present for the code and not the line numbers.</p>
<p>I'm not sure exactly how I'm going to stop the offset from happening, but that's what I want to get done this week.
Nice, simple, small-scope goal.</p>
<p>What I know is, the code block is a table, with I believe two cells.
One for the line numbers, one for the code.
The cells are supposed to be the same height, but they are less the same height than I want them to be.</p>
<hr class="docutils" />
<p>Next time, I try to figure out "what must I do to cause 'this cell needs horizontal scrolling' to affect both cells the same way?"</p>
<p>("Max, this sounds like a quick project."</p>
<p>If it were truly quick, I would have just done it.
The preliminary research for this was super obnoxious.)</p>
<hr class="docutils" />
<p>In the idle musings/speculation side of things, I haven't stopped messing with Ghosts of Departed Types.</p>
<p>I've implemented enough of the stuff from the first three sections to understand the motivation at the beginning of the fourth.
So, what I want to have, and do not have currently, is a means of associating type-level information to particular values in a program, and type-level proofs constructed from those values, that can be required by functions in order to compile.</p>
<p>Now, the ability to define named struct alternatives was useful.
What I'm leaning towards saying is, the newtypes need trait implementations, and to get the trait implementations you want, you need to control the newtype.
But, what if the newtype is a simple wrapper around a core Named value, so interconversion is just a matter of adding or removing the newtype.
So, instead of a custom parallel to Named, there'd be more invocations of named, and sorting a named vector with a named comparator would produce the type-level assertion "this list was sorted by this comparator"... well, the name would have to be associated with the sorting, actually...
At first, I didn't see the utility in wrapping another phantom type around data, when the point of the types in question is to refer to type-level data that doesn't necessarily relate to the actual value; I'm not sure whether "Oh yeah, data in Rust usually has to support mutability" is a justification.</p>
<p>I feel like I might be leaning towards a design where there's just a massive closure-onion thing.
Like, there doesn't seem to be a way to "leak" names out of their associated closures, so I'd better use one approximately every time I'd use a let-binding?
Write a sort function that only guarantees the value is sorted inside its closure.</p>
<p>Would library authors want to expose their newtypes?
The way I'm thinking about it, it shouldn't hurt.</p>
<p>What I don't have a clear mental image of is how the proof types are introduced and processed.
From skimming that part of the paper, it looks like it's possible to hand-unify the types, but there's also talk of type-system extensions.
My inclination for now is to start with hand-unification and try to improve the ergonomics within the confines of the language.
Applying type transformations in Rust suggests to me a trait for "apply this rule" where the input is a restricted domain built up from how the trait is implemented for the rule, and the result is held in an associated type.
It would be possible to cut down on the syntactic clutter some by defining type aliases.</p>
<p>Also, with only one "true" NamedStruct, just expose nice interfaces to everything with inherent methods, drop the macro.
(This code is so pre-1.0, it's not released in any form.)</p>
<p>Overall this looks like a promising idea, but I sense I should step back from it for a while.</p>
Weekly Roundup 2018-09-112018-09-11T04:00:00-04:002018-09-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-11:/weekly-roundup-2018-09-11<p class="first last">I would not recommend Rust macros for recreational coding.</p>
<ul class="simple">
<li>Main project: I worked on improving my port of GDP; the retrospective post includes a code box that indicates that the style sheet is sort of broken. Also, since I wrote it, I realized the macros were also kind of wrong, but it was more or less a simple fix.</li>
<li>Draw a Box: WHOO GHOSTING WHOO</li>
<li>Free-Topic: I wrote up the state of the various categories, because something I'm doing right now isn't working right, and I need to take stock.</li>
</ul>
<p>Next week, I'm going to take it easy.
I'm thinking just really looking into fixing up that issue with the style sheet, because it's bothering me so.</p>
GDP Rust Retrospective 2018-09-102018-09-10T04:00:00-04:002018-09-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-10:/gdp-rust-retrospective-2018-09-10<p class="first last">Really excited for the ability to write macros that don't look like this.</p>
<p>In this post:</p>
<ul class="simple">
<li>CODE</li>
<li>How the week went</li>
<li>Future goals</li>
</ul>
<hr class="docutils" />
<p>After the last post, I read over <a class="reference external" href="https://danielkeep.github.io/tlborm/book/index.html">The Little Book of Rust Macros</a> some more, and figured out what I was doing wrong and how to make the macros properly expressive.
Then, I re-did the documentation, and added examples.
The result is... lengthy.
I'm not sure I can properly convey it, so here's the file:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span>
<span class="normal">102</span>
<span class="normal">103</span>
<span class="normal">104</span>
<span class="normal">105</span>
<span class="normal">106</span>
<span class="normal">107</span>
<span class="normal">108</span>
<span class="normal">109</span>
<span class="normal">110</span>
<span class="normal">111</span>
<span class="normal">112</span>
<span class="normal">113</span>
<span class="normal">114</span>
<span class="normal">115</span>
<span class="normal">116</span>
<span class="normal">117</span>
<span class="normal">118</span>
<span class="normal">119</span>
<span class="normal">120</span>
<span class="normal">121</span>
<span class="normal">122</span>
<span class="normal">123</span>
<span class="normal">124</span>
<span class="normal">125</span>
<span class="normal">126</span>
<span class="normal">127</span>
<span class="normal">128</span>
<span class="normal">129</span>
<span class="normal">130</span>
<span class="normal">131</span>
<span class="normal">132</span>
<span class="normal">133</span>
<span class="normal">134</span>
<span class="normal">135</span>
<span class="normal">136</span>
<span class="normal">137</span>
<span class="normal">138</span>
<span class="normal">139</span>
<span class="normal">140</span>
<span class="normal">141</span>
<span class="normal">142</span>
<span class="normal">143</span>
<span class="normal">144</span>
<span class="normal">145</span>
<span class="normal">146</span>
<span class="normal">147</span>
<span class="normal">148</span>
<span class="normal">149</span>
<span class="normal">150</span>
<span class="normal">151</span>
<span class="normal">152</span>
<span class="normal">153</span>
<span class="normal">154</span>
<span class="normal">155</span>
<span class="normal">156</span>
<span class="normal">157</span>
<span class="normal">158</span>
<span class="normal">159</span>
<span class="normal">160</span>
<span class="normal">161</span>
<span class="normal">162</span>
<span class="normal">163</span>
<span class="normal">164</span>
<span class="normal">165</span>
<span class="normal">166</span>
<span class="normal">167</span>
<span class="normal">168</span>
<span class="normal">169</span>
<span class="normal">170</span>
<span class="normal">171</span>
<span class="normal">172</span>
<span class="normal">173</span>
<span class="normal">174</span>
<span class="normal">175</span>
<span class="normal">176</span>
<span class="normal">177</span>
<span class="normal">178</span>
<span class="normal">179</span>
<span class="normal">180</span>
<span class="normal">181</span>
<span class="normal">182</span>
<span class="normal">183</span>
<span class="normal">184</span>
<span class="normal">185</span>
<span class="normal">186</span>
<span class="normal">187</span>
<span class="normal">188</span>
<span class="normal">189</span>
<span class="normal">190</span>
<span class="normal">191</span>
<span class="normal">192</span>
<span class="normal">193</span>
<span class="normal">194</span>
<span class="normal">195</span>
<span class="normal">196</span>
<span class="normal">197</span>
<span class="normal">198</span>
<span class="normal">199</span>
<span class="normal">200</span>
<span class="normal">201</span>
<span class="normal">202</span>
<span class="normal">203</span>
<span class="normal">204</span>
<span class="normal">205</span>
<span class="normal">206</span>
<span class="normal">207</span>
<span class="normal">208</span>
<span class="normal">209</span>
<span class="normal">210</span>
<span class="normal">211</span>
<span class="normal">212</span>
<span class="normal">213</span>
<span class="normal">214</span>
<span class="normal">215</span>
<span class="normal">216</span>
<span class="normal">217</span>
<span class="normal">218</span>
<span class="normal">219</span>
<span class="normal">220</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">/// Create a named struct—that is, a struct that associates a Name to data.</span>
<span class="sd">/// This macro is invoked on any number of "items".</span>
<span class="sd">/// For the purposes of this macro, an "item" is one of:</span>
<span class="sd">/// a struct definition, or an impl block.</span>
<span class="sd">///</span>
<span class="sd">/// A struct definition consists of zero or more attributes,</span>
<span class="sd">/// followed by an optional visibility specifier,</span>
<span class="sd">/// followed by `struct`,</span>
<span class="sd">/// followed by a name,</span>
<span class="sd">/// followed by two type parameters with no bounds,</span>
<span class="sd">/// followed by a semicolon.</span>
<span class="sd">///</span>
<span class="sd">/// Note: the macro adds many derived trait impls.</span>
<span class="sd">/// `Default` is not one of them, and implementing `Default` is not recommended.</span>
<span class="sd">///</span>
<span class="sd">/// An impl block consists of `impl`,</span>
<span class="sd">/// followed by two type parameters,</span>
<span class="sd">/// still with no bounds,</span>
<span class="sd">/// followed by a name,</span>
<span class="sd">/// followed by two type parameters,</span>
<span class="sd">/// followed by a block.</span>
<span class="sd">/// The block contains method stubs.</span>
<span class="sd">///</span>
<span class="sd">/// Method stubs consist of a visibility specifier</span>
<span class="sd">/// (with allowable values constrained by the method name),</span>
<span class="sd">/// followed by `fn`,</span>
<span class="sd">/// followed by the name (one of a predefined set of choices),</span>
<span class="sd">/// followed by any required type parameters,</span>
<span class="sd">/// followed by a semicolon.</span>
<span class="sd">///</span>
<span class="sd">/// The allowed method names are:</span>
<span class="sd">///</span>
<span class="sd">/// * `new`: cannot have bare `pub` for visibility,</span>
<span class="sd">/// `pub(crate)` recommended,</span>
<span class="sd">/// takes no type parameters.</span>
<span class="sd">/// `new(value)` constructs a value of type `Self`, wrapping `value`.</span>
<span class="sd">/// * `as_mut`: cannot have bare `pub` for visibility,</span>
<span class="sd">/// `pub(crate)` recommended,</span>
<span class="sd">/// takes no type parameters.</span>
<span class="sd">/// `self.as_mut()` returns a mutable reference to the wrapped value.</span>
<span class="sd">/// * `into_inner`: can have any visibility,</span>
<span class="sd">/// `pub` recommended,</span>
<span class="sd">/// takes no type parameters.</span>
<span class="sd">/// `self.into_inner()` consumes `self` and returns the wrapped value.</span>
<span class="sd">/// * `as_ref`: can have any visibility,</span>
<span class="sd">/// `pub` recommended,</span>
<span class="sd">/// takes no type parameters.</span>
<span class="sd">/// `self.as_ref()` returns an immutable reference to the wrapped value.</span>
<span class="sd">///</span>
<span class="sd">/// # Examples</span>
<span class="sd">///</span>
<span class="sd">/// ```rust</span>
<span class="sd">/// # #[macro_use]</span>
<span class="sd">/// # extern crate gdp;</span>
<span class="sd">/// # fn main() {</span>
<span class="sd">/// named_struct! {</span>
<span class="sd">/// struct MyNamed<N, T>;</span>
<span class="sd">///</span>
<span class="sd">/// impl<N, T> MyNamed<N, T> {</span>
<span class="sd">/// pub(crate) fn new; // Define as needed.</span>
<span class="sd">///</span>
<span class="sd">/// pub(crate) fn as_mut; // Define as needed.</span>
<span class="sd">///</span>
<span class="sd">/// pub fn into_inner; // Definition recommended.</span>
<span class="sd">///</span>
<span class="sd">/// pub fn as_ref; // Definition recommended.</span>
<span class="sd">/// }</span>
<span class="sd">/// }</span>
<span class="sd">/// # }</span>
<span class="sd">/// ```</span>
<span class="cp">#[macro_export]</span>
<span class="fm">macro_rules!</span><span class="w"> </span><span class="n">named_struct</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">(</span><span class="cp">$vis</span>:<span class="nc">vis</span><span class="w"> </span><span class="k">struct</span> <span class="cp">$name</span>:<span class="nc">ident</span><span class="o"><</span><span class="cp">$N</span>:<span class="nc">ident</span><span class="p">,</span><span class="w"> </span><span class="cp">$T</span>:<span class="nc">ident</span><span class="w"> </span><span class="cp">$(,</span><span class="p">)</span><span class="o">*></span><span class="p">;</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cp">#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]</span>
<span class="w"> </span><span class="cp">$vis</span><span class="w"> </span><span class="k">struct</span> <span class="cp">$name</span><span class="o"><</span><span class="cp">$N</span><span class="p">,</span><span class="w"> </span><span class="cp">$T</span><span class="o">></span><span class="p">(</span><span class="cp">$crate</span>::<span class="n">pd_wrapper</span>::<span class="n">PDWrapper</span><span class="o"><</span><span class="cp">$N</span><span class="o">></span><span class="p">,</span><span class="w"> </span><span class="cp">$T</span><span class="p">);</span>
<span class="w"> </span><span class="n">named_struct</span><span class="o">!</span><span class="p">{</span><span class="cp">$($tail</span><span class="p">)</span><span class="o">*</span><span class="p">}</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="c1">// Method block</span>
<span class="w"> </span><span class="p">(</span><span class="o">@</span><span class="cp">$param</span>:<span class="nc">ident</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">new</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="fm">compile_error!</span><span class="p">(</span><span class="s">"Generated `new` method cannot be public"</span><span class="p">);</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="p">(</span><span class="o">@</span><span class="cp">$param</span>:<span class="nc">ident</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">as_mut</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="fm">compile_error!</span><span class="p">(</span><span class="s">"Generated `as_mut` method cannot be public"</span><span class="p">);</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="p">(</span><span class="o">@</span><span class="cp">$param</span>:<span class="nc">ident</span><span class="w"> </span><span class="cp">$vis</span>:<span class="nc">vis</span><span class="w"> </span><span class="k">fn</span> <span class="nf">new</span><span class="p">;</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cp">$vis</span><span class="w"> </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">t</span>: <span class="cp">$param</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Self</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="bp">Self</span><span class="p">{</span><span class="mi">0</span>: <span class="cp">$crate</span>::<span class="n">pd_wrapper</span>::<span class="n">PDWrapper</span>::<span class="n">new</span><span class="p">(),</span><span class="w"> </span><span class="mi">1</span>: <span class="nc">t</span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">named_struct</span><span class="o">!</span><span class="p">{</span><span class="o">@</span><span class="cp">$param</span><span class="w"> </span><span class="cp">$($tail</span><span class="p">)</span><span class="o">*</span><span class="p">}</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="p">(</span><span class="o">@</span><span class="cp">$param</span>:<span class="nc">ident</span><span class="w"> </span><span class="cp">$vis</span>:<span class="nc">vis</span><span class="w"> </span><span class="k">fn</span> <span class="nf">into_inner</span><span class="p">;</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cp">$vis</span><span class="w"> </span><span class="k">fn</span> <span class="nf">into_inner</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-> <span class="cp">$param</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="mi">1</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">named_struct</span><span class="o">!</span><span class="p">{</span><span class="o">@</span><span class="cp">$param</span><span class="w"> </span><span class="cp">$($tail</span><span class="p">)</span><span class="o">*</span><span class="p">}</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="p">(</span><span class="o">@</span><span class="cp">$param</span>:<span class="nc">ident</span><span class="w"> </span><span class="cp">$vis</span>:<span class="nc">vis</span><span class="w"> </span><span class="k">fn</span> <span class="nf">as_ref</span><span class="p">;</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cp">$vis</span><span class="w"> </span><span class="k">fn</span> <span class="nf">as_ref</span><span class="p">(</span><span class="o">&</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-> <span class="kp">&</span><span class="cp">$param</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="o">&</span><span class="bp">self</span><span class="p">.</span><span class="mi">1</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">named_struct</span><span class="o">!</span><span class="p">{</span><span class="o">@</span><span class="cp">$param</span><span class="w"> </span><span class="cp">$($tail</span><span class="p">)</span><span class="o">*</span><span class="p">}</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="p">(</span><span class="o">@</span><span class="cp">$param</span>:<span class="nc">ident</span><span class="w"> </span><span class="cp">$vis</span>:<span class="nc">vis</span><span class="w"> </span><span class="k">fn</span> <span class="nf">as_mut</span><span class="p">;</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cp">$vis</span><span class="w"> </span><span class="k">fn</span> <span class="nf">as_mut</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-> <span class="kp">&</span><span class="nc">mut</span><span class="w"> </span><span class="cp">$param</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="mi">1</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">named_struct</span><span class="o">!</span><span class="p">{</span><span class="o">@</span><span class="cp">$param</span><span class="w"> </span><span class="cp">$($tail</span><span class="p">)</span><span class="o">*</span><span class="p">}</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="c1">// End method block</span>
<span class="w"> </span><span class="p">(</span><span class="k">impl</span><span class="o"><</span><span class="cp">$N1</span>:<span class="nc">ident</span><span class="p">,</span><span class="w"> </span><span class="cp">$T1</span>:<span class="nc">ident</span><span class="w"> </span><span class="cp">$(,</span><span class="p">)</span><span class="o">*></span><span class="w"> </span><span class="cp">$name</span>:<span class="nc">ident</span><span class="o"><</span><span class="cp">$N2</span>:<span class="nc">ident</span><span class="p">,</span><span class="w"> </span><span class="cp">$T2</span>:<span class="nc">ident</span><span class="w"> </span><span class="cp">$(,</span><span class="p">)</span><span class="o">*></span><span class="w"> </span><span class="p">{</span><span class="cp">$($tail1</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">}</span><span class="w"> </span><span class="cp">$($tail2</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">impl</span><span class="o"><</span><span class="cp">$N1</span><span class="p">,</span><span class="w"> </span><span class="cp">$T1</span><span class="o">></span><span class="w"> </span><span class="cp">$name</span><span class="o"><</span><span class="cp">$N2</span><span class="p">,</span><span class="w"> </span><span class="cp">$T2</span><span class="o">></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">named_struct</span><span class="o">!</span><span class="p">{</span><span class="o">@</span><span class="cp">$T2</span><span class="w"> </span><span class="cp">$($tail1</span><span class="p">)</span><span class="o">*</span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">named_struct</span><span class="o">!</span><span class="p">{</span><span class="cp">$($tail2</span><span class="p">)</span><span class="o">*</span><span class="p">}</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="p">(</span><span class="cp">$(#[$outer:meta]</span><span class="p">)</span><span class="o">+</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span><span class="cp">$(#[$outer]</span><span class="p">)</span><span class="o">*</span><span class="w"> </span><span class="n">named_struct</span><span class="o">!</span><span class="p">{</span><span class="cp">$($tail</span><span class="p">)</span><span class="o">*</span><span class="p">}};</span>
<span class="w"> </span><span class="p">(</span><span class="o">@</span><span class="cp">$param</span>:<span class="nc">ident</span><span class="w"> </span><span class="cp">$(#[$outer:meta]</span><span class="p">)</span><span class="o">+</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span><span class="cp">$(#[$outer]</span><span class="p">)</span><span class="o">*</span><span class="w"> </span><span class="n">named_struct</span><span class="o">!</span><span class="p">{</span><span class="o">@</span><span class="cp">$param</span><span class="w"> </span><span class="cp">$($tail</span><span class="p">)</span><span class="o">*</span><span class="p">}};</span>
<span class="w"> </span><span class="p">(</span><span class="o">@</span><span class="cp">$_</span>:<span class="nc">ident</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{};</span>
<span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{};</span>
<span class="p">}</span>
<span class="sd">/// Create a name struct—that is, a struct that implements the `Name` trait.</span>
<span class="sd">/// This macro is invoked on any number of "items".</span>
<span class="sd">/// For the purposes of this macro, an "item" is one of:</span>
<span class="sd">/// a struct definition, or an impl block.</span>
<span class="sd">///</span>
<span class="sd">/// A struct definition consists of zero or more attributes,</span>
<span class="sd">/// followed by an optional visibility specifier,</span>
<span class="sd">/// followed by `struct`,</span>
<span class="sd">/// followed by a name,</span>
<span class="sd">/// followed by optional type parameters with no bounds,</span>
<span class="sd">/// followed by a semicolon.</span>
<span class="sd">///</span>
<span class="sd">/// Note: the macro adds many derived trait impls.</span>
<span class="sd">/// `Default` is not one of them, and implementing `Default` is not recommended.</span>
<span class="sd">///</span>
<span class="sd">/// An impl block consists of `impl`,</span>
<span class="sd">/// followed by the appropriate number of type parameters,</span>
<span class="sd">/// still with no bounds,</span>
<span class="sd">/// followed by a name,</span>
<span class="sd">/// followed by the appropriate number of type parameters,</span>
<span class="sd">/// followed by a block.</span>
<span class="sd">/// The block contains method stubs.</span>
<span class="sd">///</span>
<span class="sd">/// Method stubs consist of a visibility specifier</span>
<span class="sd">/// (with allowable values constrained by the method name),</span>
<span class="sd">/// followed by `fn`,</span>
<span class="sd">/// followed by the name (one of a predefined set of choices),</span>
<span class="sd">/// followed by any required type parameters,</span>
<span class="sd">/// followed by a semicolon.</span>
<span class="sd">///</span>
<span class="sd">/// The allowed method names are:</span>
<span class="sd">///</span>
<span class="sd">/// * `defn`: cannot have bare `pub` for visibility,</span>
<span class="sd">/// `pub(crate)` recommended,</span>
<span class="sd">/// takes one unbounded type parameter,</span>
<span class="sd">/// does not introduce bounds.</span>
<span class="sd">/// `defn<T>(value: T)` constructs an instance of `Named<Self, T>`,</span>
<span class="sd">/// wrapping `value`.</span>
<span class="sd">///</span>
<span class="sd">/// Note: all generated `impl`s, including the `Name` impl,</span>
<span class="sd">/// insert a bound of `Name` for `impl`-level type parameters.</span>
<span class="sd">///</span>
<span class="sd">/// # Examples</span>
<span class="sd">///</span>
<span class="sd">/// ```rust</span>
<span class="sd">/// # #[macro_use]</span>
<span class="sd">/// # extern crate gdp;</span>
<span class="sd">/// # fn main() {</span>
<span class="sd">/// name! {</span>
<span class="sd">/// struct Nullary;</span>
<span class="sd">///</span>
<span class="sd">/// impl Nullary {</span>
<span class="sd">/// pub(crate) fn defn<T>; // Define as needed.</span>
<span class="sd">/// }</span>
<span class="sd">///</span>
<span class="sd">/// struct Unary<A>;</span>
<span class="sd">///</span>
<span class="sd">/// impl<A> Unary<A> {</span>
<span class="sd">/// pub(crate) fn defn<T>; // Define as needed.</span>
<span class="sd">/// }</span>
<span class="sd">///</span>
<span class="sd">/// struct Binary<A, B>;</span>
<span class="sd">///</span>
<span class="sd">/// impl<A, B> Binary<A, B> {</span>
<span class="sd">/// pub(crate) fn defn<T>; // Define as needed.</span>
<span class="sd">/// }</span>
<span class="sd">/// }</span>
<span class="sd">/// # }</span>
<span class="sd">/// ```</span>
<span class="cp">#[macro_export]</span>
<span class="fm">macro_rules!</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">(</span><span class="cp">$vis</span>:<span class="nc">vis</span><span class="w"> </span><span class="k">struct</span> <span class="cp">$name</span>:<span class="nc">ident</span><span class="o"><</span><span class="cp">$($param</span>:<span class="nc">ident</span><span class="p">),</span><span class="o">*</span><span class="w"> </span><span class="cp">$(,</span><span class="p">)</span><span class="o">*></span><span class="p">;</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cp">#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]</span>
<span class="w"> </span><span class="cp">$vis</span><span class="w"> </span><span class="k">struct</span> <span class="cp">$name</span><span class="o"><</span><span class="cp">$($param</span><span class="p">,)</span><span class="o">*></span><span class="p">(</span><span class="cp">$crate</span>::<span class="n">pd_wrapper</span>::<span class="n">PDWrapper</span><span class="o"><</span><span class="p">(</span><span class="cp">$($param</span><span class="p">,)</span><span class="o">*</span><span class="p">)</span><span class="o">></span><span class="p">);</span>
<span class="w"> </span><span class="k">impl</span><span class="o"><</span><span class="cp">$($param</span>: <span class="cp">$crate</span>::<span class="n">named</span>::<span class="n">Name</span><span class="p">,)</span><span class="o">*></span><span class="w"> </span><span class="cp">$crate</span>::<span class="n">named</span>::<span class="n">Name</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="cp">$name</span><span class="o"><</span><span class="cp">$($param</span><span class="p">,)</span><span class="o">*></span><span class="w"> </span><span class="p">{}</span>
<span class="w"> </span><span class="n">name</span><span class="o">!</span><span class="p">{</span><span class="cp">$($tail</span><span class="p">)</span><span class="o">*</span><span class="p">}</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="p">(</span><span class="cp">$vis</span>:<span class="nc">vis</span><span class="w"> </span><span class="k">struct</span> <span class="cp">$name</span>:<span class="nc">ident</span><span class="p">;</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span><span class="n">name</span><span class="o">!</span><span class="p">{</span><span class="cp">$vis</span><span class="w"> </span><span class="k">struct</span> <span class="cp">$name</span><span class="o"><></span><span class="p">;</span><span class="w"> </span><span class="cp">$($tail</span><span class="p">)</span><span class="o">*</span><span class="p">}};</span>
<span class="w"> </span><span class="c1">// Method block</span>
<span class="w"> </span><span class="p">(</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">defn</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="fm">compile_error!</span><span class="p">(</span><span class="s">"Generated `defn` method cannot be public"</span><span class="p">);</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="p">(</span><span class="cp">$vis</span>:<span class="nc">vis</span><span class="w"> </span><span class="k">fn</span> <span class="nf">defn</span><span class="o"><</span><span class="cp">$param</span>:<span class="nc">ident</span><span class="o">></span><span class="p">;</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cp">$vis</span><span class="w"> </span><span class="k">fn</span> <span class="nf">defn</span><span class="o"><</span><span class="cp">$param</span><span class="o">></span><span class="p">(</span><span class="n">t</span>: <span class="cp">$param</span><span class="p">)</span><span class="w"> </span>-> <span class="cp">$crate</span>::<span class="n">named</span>::<span class="n">Named</span><span class="o"><</span><span class="bp">Self</span><span class="p">,</span><span class="w"> </span><span class="cp">$param</span><span class="o">></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cp">$crate</span>::<span class="n">named</span>::<span class="n">defn</span><span class="p">(</span><span class="bp">Self</span><span class="p">{</span><span class="mi">0</span>: <span class="cp">$crate</span>::<span class="n">pd_wrapper</span>::<span class="n">PDWrapper</span>::<span class="n">new</span><span class="p">()},</span><span class="w"> </span><span class="n">t</span><span class="p">)</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="c1">// End method block</span>
<span class="w"> </span><span class="p">(</span><span class="k">impl</span><span class="o"><</span><span class="cp">$($param1</span>:<span class="nc">ident</span><span class="p">),</span><span class="o">*</span><span class="w"> </span><span class="cp">$(,</span><span class="p">)</span><span class="o">*></span><span class="w"> </span><span class="cp">$name</span>:<span class="nc">ident</span><span class="o"><</span><span class="cp">$($param2</span>:<span class="nc">ident</span><span class="p">),</span><span class="o">*</span><span class="w"> </span><span class="cp">$(,</span><span class="p">)</span><span class="o">*></span><span class="w"> </span><span class="p">{</span><span class="cp">$($tail1</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">}</span><span class="w"> </span><span class="cp">$($tail2</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">impl</span><span class="o"><</span><span class="cp">$($param1</span>: <span class="cp">$crate</span>::<span class="n">named</span>::<span class="n">Name</span><span class="p">),</span><span class="o">*></span><span class="w"> </span><span class="cp">$name</span><span class="o"><</span><span class="cp">$($param2</span><span class="p">),</span><span class="o">*></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">name</span><span class="o">!</span><span class="p">{</span><span class="cp">$($tail1</span><span class="p">)</span><span class="o">*</span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">name</span><span class="o">!</span><span class="p">{</span><span class="cp">$($tail2</span><span class="p">)</span><span class="o">*</span><span class="p">}</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="p">(</span><span class="k">impl</span><span class="o"><</span><span class="cp">$($param1</span>:<span class="nc">ident</span><span class="p">),</span><span class="o">*</span><span class="w"> </span><span class="cp">$(,</span><span class="p">)</span><span class="o">*></span><span class="w"> </span><span class="cp">$name</span>:<span class="nc">ident</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span><span class="n">name</span><span class="o">!</span><span class="p">{</span><span class="k">impl</span><span class="o"><</span><span class="cp">$($param1</span><span class="p">),</span><span class="o">*></span><span class="w"> </span><span class="cp">$name</span><span class="o"><></span><span class="w"> </span><span class="cp">$($tail</span><span class="p">)</span><span class="o">*</span><span class="p">}};</span>
<span class="w"> </span><span class="p">(</span><span class="k">impl</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span><span class="n">name</span><span class="o">!</span><span class="p">{</span><span class="k">impl</span><span class="o"><></span><span class="w"> </span><span class="cp">$($tail</span><span class="p">)</span><span class="o">*</span><span class="p">}};</span>
<span class="w"> </span><span class="p">(</span><span class="cp">$(#[$outer:meta]</span><span class="p">)</span><span class="o">+</span><span class="w"> </span><span class="cp">$($tail</span>:<span class="nc">tt</span><span class="p">)</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span><span class="cp">$(#[$outer]</span><span class="p">)</span><span class="o">*</span><span class="w"> </span><span class="n">name</span><span class="o">!</span><span class="p">{</span><span class="cp">$($tail</span><span class="p">)</span><span class="o">*</span><span class="p">}};</span>
<span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{};</span>
<span class="p">}</span>
</pre></div></td></tr></table></div>
<p>EDIT: Ugh, something is wrong with the style sheet, I want to fix it...</p>
<p>I don't know how much of this length is How Macros Are, and how much is that these are the first big macros I've written, so of course it's probably longer than it could be.</p>
<p>Regardless, I'm past the big scary thing.
Now I can focus on documenting everything else, made possible by following the API guidelines.</p>
<p>Anyway, so far as what I accomplished this week, I got these macros written with their cool input format, and documented them.
Once I'd realized how bad my initial macro formats were, that was about all I could hope for.</p>
<p>Moving forward, I want to get the rest of the base crate up to standards, then go over sorted-by some more.
Once I've hit the basic implementation goals for sorted-by, I want to see what kind of code it's generating.
When I was messing around with a much earlier version of this code, it didn't look to me like the output was structured in a zero-cost way, relative to equivalent code.</p>
<hr class="docutils" />
<p>Next week, I'm going to try to take it easy.</p>
GDP Rust Development 2018-09-092018-09-09T04:00:00-04:002018-09-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-09:/gdp-rust-development-2018-09-09<p class="first last">It's a start</p>
<p>In this post:</p>
<ul class="simple">
<li>Macros are hard. And tedious.</li>
</ul>
<hr class="docutils" />
<p>To be honest, I kind of took things easy today, but I did improve things somewhat.</p>
<p>I took the <tt class="docutils literal">name</tt> macro from processing <tt class="docutils literal">pub DefaultCmp</tt> to <tt class="docutils literal">pub struct DefaultCmp;</tt> which is a little more verbose, but also communicates intent more clearly, without requiring an intuitive knowledge of what the macro does.</p>
<p>While I was working on that, I realized even moreso how brittle the current macros are, and tried to improve on it.
Sadly, the result is broken when it tries to actually evaluate.
I think if I want to keep developing this, I'm going to have to switch to nightly until 1.30 lands, because I want to stop messing around with weird brittle hacks.
1.30 stabilizes the <tt class="docutils literal">macro_vis_matcher</tt> feature, which should allow me to seriously reduce the size and redundancy of these macros.</p>
<p>... Huh. That didn't help as much as I thought it would.
I think I'm going to have to ask the forums for help, because the macro_rules implementation is overall a huge pain so far.</p>
<hr class="docutils" />
<p>Next time, I go over this week.</p>
Process Refinements 2018-09-082018-09-08T04:00:00-04:002018-09-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-08:/process-refinements-2018-09-08<p class="first last">That is a lot of projects I've started.</p>
<p>In this post:</p>
<ul class="simple">
<li>Ideas for changing up the blogging process.</li>
<li>A giant list off started projects, and my feelings on them.</li>
<li>An attempt to sort all of that by dependencies, and rough interest on my part.</li>
</ul>
<hr class="docutils" />
<p>Earlier, I mentioned possibly bringing in more agile process to these weekly things I'm doing.
Something like, try and bring back the trello (which was making less sense when I moved to a more restricted set of weekly topics), and start trying to scope stuff for the various projects.</p>
<p>I'd basically divide things into:</p>
<ul class="simple">
<li>Quick hit</li>
<li>Not too bad</li>
<li>Challenging</li>
<li>Formidable</li>
<li>Theme (Complicated enough to build a week around)</li>
<li>Week (Complicated enough to take up a week on its own)</li>
<li>Out-of-scope</li>
</ul>
<p>And note projects thus:</p>
<ul class="simple">
<li>Structured Data: shelved for now</li>
<li>Conworld Codex: oh geez, I left off trying to find a UI library I liked... Focus on that at some point, I guess</li>
<li>Demiurgent Business: I could come back to this, but I don't currently feel like it</li>
<li>GDP Rust: active development</li>
<li>Homunculus: I would approach this from the angle of improving Rust's TDL bindings</li>
<li>Linked Seas: I want to focus on the RIP first</li>
<li>Mon Free: explicitly blocked on Homunculus progress</li>
<li>Tiny Music: I want to get better at API stuff from the core of GDP first, then I'll look over this</li>
<li>Romance Instrumentality Project: I've got other stuff I want to read first</li>
<li>The Cabin: oh man, this is from when I was trying to put in accurate timestamps. Anyway, I can work on this, I just don't have any ideas currently</li>
<li>Python Augmented: going to have to psych myself up to stick this in a vcs and just start hacking on it</li>
<li>Time Travel CCMWG: this is amazing and I have no idea how to make it a thing</li>
<li>Shine Whave: pffft</li>
<li>Revisiting the "online media affordances" stuff. I want to take a different tack on this.</li>
</ul>
<p>And some things I don't have posts on:</p>
<ul class="simple">
<li>Thoughts on effective horror, inspired by a movie that was very... ineffective</li>
<li>The One-Man Institute, no longer of Inapplicable Physics, but now of Counterfactual Experimentalism. I believe the institute's goals are served, not by pretending to understand General Relativity and Quantum Mechanics, but by pretending to understand <em>lots of things</em></li>
<li>Trying to write libraries for nicer newtypes in Rust</li>
<li>An unnamed board game idea: not really fleshed out, chain of inspiration goes back to Jumanji, which, huh, they made another Jumanji movie last year, how about that, I was unaware</li>
<li>Jedi improvements: I should give this a week sometime, I don't know really</li>
</ul>
<p>So, stuff to do:</p>
<ul class="simple">
<li><dl class="first docutils">
<dt>GDP</dt>
<dd><ul class="first last">
<li>Tiny Music</li>
<li><dl class="first docutils">
<dt>Try to help bind TDL</dt>
<dd><ul class="first last">
<li><dl class="first docutils">
<dt>Homunculus</dt>
<dd><ul class="first last">
<li>Mon Free</li>
</ul>
</dd>
</dl>
</li>
</ul>
</dd>
</dl>
</li>
<li>Newtypes</li>
</ul>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt>Reading that doesn't get a post</dt>
<dd><ul class="first last">
<li>RIP</li>
</ul>
</dd>
</dl>
</li>
<li>Python Augmented</li>
<li>Jedi</li>
<li>Effective horror</li>
<li>Online media</li>
<li>OMICE</li>
<li>Demiurgent Business</li>
<li><dl class="first docutils">
<dt>???</dt>
<dd><ul class="first last">
<li><dl class="first docutils">
<dt>Conworld Codex</dt>
<dd><ul class="first last">
<li>Linked Seas (also depends on RIP)</li>
</ul>
</dd>
</dl>
</li>
</ul>
</dd>
</dl>
</li>
<li>The Cabin</li>
<li>Shine Whave I guess</li>
<li>CCMWG</li>
<li>Untitled Game</li>
</ul>
<p>With so many things to look into, I kind of want to take a week sometime to just scope things out and spec them into tasks within each project.</p>
GDP Rust Goals 2018-09-072018-09-07T04:00:00-04:002018-09-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-07:/gdp-rust-goals-2018-09-07<p class="first last">At first, I thought the documentation needed improvement. Then, I realized the stuff I was documenting also needed improvement.</p>
<p>In this post:</p>
<ul class="simple">
<li>"This code just needs some doc improvements."</li>
<li>"Wow, no, it's a good thing I haven't published this."</li>
<li>"Here's what I can do to make it better."</li>
</ul>
<hr class="docutils" />
<p>When I started sketching out stuff for this post, I was focused on how the documentation was obviously lacking.
Then I went looking for advice on writing better documentation, and I found the <a class="reference external" href="https://rust-lang-nursery.github.io/api-guidelines/about.html">Rust API Guidelines</a>.
While I'd happened to internalize some of the ideas it presented, from other sources, there were some areas where my code fell particularly short, particularly in terms of the macro design.</p>
<p>Here's how the interface stacked up when I started looking through the list:</p>
<hr class="docutils" />
<p>There is one public module, <tt class="docutils literal">named</tt>, and four macros: <tt class="docutils literal">name</tt>, <tt class="docutils literal">name_impls</tt>, <tt class="docutils literal">named_struct</tt>, and <tt class="docutils literal">named_struct_impls</tt>.
The "impls" macros are only public because it seemed to break consumers if they were private; they're just helpers for their corresponding macro.
In <tt class="docutils literal">named</tt>, we have three structs, <tt class="docutils literal">Id</tt>, <tt class="docutils literal">Named</tt>, <tt class="docutils literal">PDWrapper</tt>, a trait, <tt class="docutils literal">Name</tt>, and two functions, <tt class="docutils literal">defn</tt> and <tt class="docutils literal">name</tt>.
<tt class="docutils literal">Name</tt> is a marker trait for name types.
Types so marked can fit into the first slot of any name-based struct, such as <tt class="docutils literal">Named</tt>, but also any consumer can define its own structs.
<tt class="docutils literal">defn</tt> is a helper function used in the macro-generated definition of <tt class="docutils literal">Name</tt> implementors.
It is somewhat obnoxious to call on its own.
<tt class="docutils literal">name</tt> is a pretty direct port from the Haskell; evidently Rust imposes some similar constraints on implementation.
It basically takes an arbitrary value, and a closure that operates on a named value, then gives the value a unique name, and passes it into the closure, then returns the result.
<tt class="docutils literal">Id</tt> is visible only because I can't figure out how to give <tt class="docutils literal">name</tt> the bounds I want, and <tt class="docutils literal">Id</tt> is what it actually uses in practice.
<tt class="docutils literal">PDWrapper</tt> is a little convenience newtype that someone else has probably already written, but I didn't look for it.</p>
<p>There's more to go over inside the macros, but I know the macros need an overhaul.
Let's look through the API Guidelines.</p>
<ul class="simple">
<li>The only names I'm worried about right now are <tt class="docutils literal">Id</tt> and <tt class="docutils literal">PDWrapper</tt>, aka "the things I didn't want to foreground in my documentation anyway".</li>
<li><tt class="docutils literal">Named</tt> and <tt class="docutils literal">PDWrapper</tt> are missing <tt class="docutils literal">Display</tt> impls. <tt class="docutils literal">PDWrapper</tt> should probably impl <tt class="docutils literal">Default</tt>, <tt class="docutils literal">Named</tt> definitely should not.</li>
<li>I should look into supporting Serde.</li>
<li><tt class="docutils literal">Named<N, T></tt> inherits <tt class="docutils literal">Send</tt> and <tt class="docutils literal">Sync</tt> impls from <tt class="docutils literal">T</tt> <em>exactly</em>, which is what I want.</li>
<li>The macros need to be rewritten, and the documentation needs a few more passes.</li>
</ul>
<p>To make things better, I'm going to:</p>
<ul class="simple">
<li>Move <tt class="docutils literal">PDWrapper</tt> to its own module.</li>
<li><tt class="docutils literal">impl Display</tt> for <tt class="docutils literal">PDWrapper</tt> and ideally all named structs.</li>
<li><tt class="docutils literal">#[derive(Default)]</tt> for <tt class="docutils literal">PDWrapper</tt>.</li>
<li>Start breaking down the macros.</li>
</ul>
<p>There are a number of layers of problems with the macros.
It's basically variations on "too terse", but manifesting in various ways:</p>
<ul class="simple">
<li>The syntax is so abbreviated that it doesn't resemble Rust.</li>
<li>All convenience methods are defined, whether you want them or not.</li>
</ul>
<p>My gut feeling is that each definition where the user has some input should be its own item, which, similarly to non-default <tt class="docutils literal">fn</tt> declarations in trait definitions, should end in a semicolon.
The grammar works out to something like <tt class="docutils literal">($attribute)* <span class="pre">[pub[\($scope\)]]</span> struct <span class="pre">$name[<($param)*>];</span></tt> for <tt class="docutils literal">name</tt> and <tt class="docutils literal">($attribute)* <span class="pre">[pub[\($scope\)]]</span> struct $name(nothing, or maybe require a pair of type parameters)</tt> for <tt class="docutils literal">named_struct</tt>.
The "impl" versions should now need to be invoked explicitly, and work something like: <tt class="docutils literal"><span class="pre">impl<$N,</span> $T> <span class="pre">$name<$N,</span> $T> { $named_struct_impls* }</tt> for <tt class="docutils literal">named_struct</tt>, <tt class="docutils literal"><span class="pre">impl<($param1)*></span></tt> for <tt class="docutils literal"><span class="pre">name<($param2)*></span> { $name_impls* }</tt>.
For reasons, I don't think it'd work to have the bounds in the macro invocation, so just document that the macro needs them not there, and will add them.
Anyway, the insides would have to look something like <tt class="docutils literal">($attribute)* <span class="pre">[pub\($scope\)]</span> fn $name $rest*</tt>, dispatch on pub/scope to specialized item macros that get something like <tt class="docutils literal">($attribute)* $overall_scope fn $name (type parameters as appropriate) <span class="pre">\((params</span> as expected for the <span class="pre">function)\)</span> <span class="pre">-></span> $type;</tt> or something.
The intermediate stuff depends on what's convenient.</p>
<hr class="docutils" />
<p>Notes: all visibility modifiers that involve parentheses are stricter than without, and "crate" is the least strict.
Therefore, if <tt class="docutils literal">pub(crate)</tt> is acceptable, then any other parenthesized modifier is acceptable.</p>
<p>The core of the library was stripped-down enough that it was hard to be "a little wrong" in an absolute sense, without being "almost entirely wrong" in a relative sense.
As such, my concerns are around ergonomics and legibility in the helper code.</p>
<p>I was working on this before in my free time, and I'll probably continue to do so.
What these weekly projects get me is the impetus to work through some big, unpleasant part of a task.
This week, that gets to be Making The Macros Work Good.</p>
<hr class="docutils" />
<p>Next time, I try to improve the macro implementation.</p>
Draw a Box 2018-09-062018-09-06T04:00:00-04:002018-09-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-06:/draw-a-box-2018-09-06<p class="first last">It's spooky how much less boring this is.</p>
<p>In this post:</p>
<ul class="simple">
<li>I'm enjoying this.</li>
</ul>
<hr class="docutils" />
<p>Since I started the third sheet, I have drawn:</p>
<ul class="simple">
<li>30 lines on August 30. It's nice to be doing the ghosting exercise now, though <em>for some reason</em> I'm pretty rusty.</li>
<li>30 lines on August 31.</li>
<li>30 lines on September 1.</li>
<li>30 lines on September 2.</li>
<li>30 lines on September 3. I did some long lines, so they're kind of wobbly. I guess this kind of gives a sense of how far is too far to freehand.</li>
<li>30 lines on September 4.</li>
<li>30 lines on September 5. Looking at how I'm doing these, I think I want to do an extra sheet, with an eye towards long, non-adjacent-and-parallel lines. That constraint means it should fill up fast, so the extra sheet isn't a big deal.</li>
</ul>
<p>For a total of 210 lines this week,
and 210 lines on the third sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
GDP Rust Planning 2018-09-052018-09-05T04:00:00-04:002018-09-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-05:/gdp-rust-planning-2018-09-05<p class="first last">... No biggie.</p>
<p>In this post:</p>
<ul class="simple">
<li>What this all is</li>
<li>My long-term goals</li>
<li>Short-term avenues of improvement</li>
<li>While discussing an irritating limitation, I get so irritated that I go deal with it</li>
<li>A formidable breakdown of short-term goals</li>
<li>Which of those goals I feel are in scope for this week</li>
<li>The plan</li>
</ul>
<hr class="docutils" />
<p>So, last weekend, I started working on attempting to port Ghosts of Departed Proofs from Haskell to Rust.
It appears that, by now, I've got the core mostly working, and I'm focusing on proving this out by trying to implement Ghosts functionality for sorted Vec and Iterator.</p>
<p>So far as that, my plan there is to implement functionality for every kind of stdlib iterator that makes sense in the context of "preserving a sorted invariant", then create a <tt class="docutils literal">Merged</tt> iterator struct.
Thinking over how I'd implement such a thing earlier, I concluded that the implementation would actually be kind of obnoxious, so I'll content myself with just laying the groundwork for now.</p>
<p>In terms of the quality of the code right now, there are a few issues and open questions:</p>
<ul class="simple">
<li>I've just started documenting things; I want to have some really thorough documentation in there.</li>
<li>There are some things I'm not sure about with the macro matches I'm doing. Like, should there by optional trailing semicolons?</li>
<li>I can't point at anything that I know I could do better, but the macros I've written look kind of janky. One of them has nine match arms, and three of them are just so a different three get triggered with or without a trailing comma.</li>
</ul>
<p>In terms of stdlib code to write special handling for:</p>
<ul class="simple">
<li>I've already written a conversion for <tt class="docutils literal">Cloned</tt>.</li>
<li><dl class="first docutils">
<dt>Several structures need unconditional conversions:</dt>
<dd><ul class="first last">
<li><tt class="docutils literal">Empty</tt></li>
<li><tt class="docutils literal">Once</tt></li>
<li><tt class="docutils literal">Repeat</tt></li>
</ul>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt>Some have straightforward conversions:</dt>
<dd><ul class="first last">
<li><tt class="docutils literal">Filter</tt></li>
<li><tt class="docutils literal">Fuse</tt></li>
<li><tt class="docutils literal">Inspect</tt></li>
<li><tt class="docutils literal">Peekable</tt></li>
<li><tt class="docutils literal">Skip</tt></li>
<li><tt class="docutils literal">SkipWhile</tt></li>
<li><tt class="docutils literal">StepBy</tt></li>
<li><tt class="docutils literal">Take</tt></li>
<li><tt class="docutils literal">TakeWhile</tt></li>
</ul>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt>Some have somewhat more elaborate conversions:</dt>
<dd><ul class="first last">
<li><tt class="docutils literal">Enumerate</tt> (products the name with <tt class="docutils literal">DefaultCmp</tt>.)</li>
<li><tt class="docutils literal">Rev</tt> (wraps the Name in a <tt class="docutils literal">Reverse</tt>. Double <tt class="docutils literal">Reverse</tt> should allow for cancellation. <tt class="docutils literal">Reverse</tt> should propagate inward through products.)</li>
<li><tt class="docutils literal">Zip</tt> (given two arbitrary names, uses their product, which is also a name.)</li>
</ul>
</dd>
</dl>
</li>
</ul>
<p>There are also a bunch of traits.
The way I'm doing things currently, I can't have blanket impls, but I might change that.
The basic issue is that, until I changed it literally as I was writing this, I was using a single structure for every role in this code, which turns out not to work all that well in terms of blanket impls.
The impls stop conflicting, though, if I have different container types for different kinds of object, so that turns out to be okay.
Now, I can't do a blanket implementation of <tt class="docutils literal">FromIterator</tt> because not all containers preserve insertion order, so that's going to be a piecemeal kind of thing.</p>
<p>I might also want to change the way I do products of names; I'll have to see if there are any disadvantages to using simple tuples.</p>
<p>I mentioned earlier that the implementation of <tt class="docutils literal">Merged</tt> seemed obnoxious.
Basically, it's a pair of peekable, potentially double-ended, fused iterators, along with a function.
If either iterator is exhausted, it must be discarded and not consulted again.</p>
<p>I just realized that <tt class="docutils literal">Enumerate</tt>, <tt class="docutils literal">Rev</tt>, and <tt class="docutils literal">Zip</tt> have some more issues: <tt class="docutils literal">Enumerate</tt> and <tt class="docutils literal">Zip</tt> need to have a corresponding set of function combinators, as does <tt class="docutils literal">Rev</tt>.</p>
<p>The stuff I feel like doing goes roughly in order of:</p>
<ul class="simple">
<li>Document existing code</li>
<li>Implement the combinators mentioned above</li>
<li>Implement the unconditional conversations</li>
<li>Implement blanket traits</li>
<li>Implement the straightforward conversions</li>
<li>Design <tt class="docutils literal">Merged</tt></li>
<li>Make decisions about what to accept in the macros</li>
<li>Streamline the macro definitions</li>
<li>Implement <tt class="docutils literal">Merged</tt></li>
</ul>
<p>This is probably not entirely honest, in that I've got a good idea of how I want <tt class="docutils literal">Merged</tt> to look, but I'd rather have more experience with the code before I commit to it.</p>
<p>I think I'll break down the tasks for the two middle posts in this week thus:</p>
<ul class="simple">
<li>First, document as much as I can, and summarize the stuff I documented.</li>
<li>Second, implement whatever. There are probably some dependencies I glossed over up there, so I'll really tackle those in whatever order ends up making sense. Probably do the blanket traits early, because those don't really rely on anything else that I can think of.</li>
</ul>
<hr class="docutils" />
<p>Next time, <strong>EDIT: WHOOPS I DIDN'T FILL THIS IN FOR TWO DAYS</strong> I look into improving the documentation, and then the overall API.</p>
Weekly Roundup 2018-09-042018-09-04T04:00:00-04:002018-09-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-04:/weekly-roundup-2018-09-04<p class="first last">In some ways disappointing, in some ways excellent.</p>
<ul class="simple">
<li>Main project: I started porting tiny_music to Rust. I ended up feeling like I didn't say much interesting, and I suspect that's due to bad planning.</li>
<li>Draw a Box: I FINISHED THE SHEET! YAY!</li>
<li>Free-Topic: I started trying to port Ghosts of Departed Proofs to Rust.</li>
</ul>
<p>Next week, I've been having fun (... the kind of fun where I swear at the compiler for a while...) with the gdp port, so how about I keep on that?</p>
Music Theory - Retrospective 2018-09-032018-09-03T04:00:00-04:002018-09-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-03:/music-theory-retrospective-2018-09-03<p class="first last">This retrospective feels wonky. I might need a break.</p>
<p>In this post:</p>
<ul class="simple">
<li>My feelings on the last week.</li>
<li>How well I followed the plan.</li>
<li>Musings on how to make the code better.</li>
<li>Thoughts on how to improve the planning process for these weekly projects.</li>
</ul>
<hr class="docutils" />
<p>Huh, I think I kind of scoped out this week weird and kind of did the retrospective yesterday, sort of?
Note for the future, don't do that.</p>
<p>The goal of this week was to go back into a codebase I hadn't touched in months, and port it to Rust so I could make some progress on it.
I ended up discovering that there were a lot of aspects of the design that I hadn't fully thought out, and I'll have to change/think about as things go on.
I got most of the way through implementing code to approximate feature parity.</p>
<p>The big concern I have with the way I'm implementing things now is, there are a few places I'm using mutation where I think actually maybe I shouldn't.
Or maybe the correct answer is to keep using mutation, but make a clone and mutate the clone.</p>
<p>I'm getting kind of dissatisfied with the way my current weekly schedule works out.
I might have to start doing planning poker or something for these things.
I guess my problem with this week was that the process of implementation wasn't very interesting to write about, so the third project post felt a little tepid.
I might be able to recoup my good feelings on this by writing up tiny_music_rs after it's in a better state.</p>
<hr class="docutils" />
<p>Next week, I'm having fun with gdp, so maybe I'll just be on a Rust kick for a bit longer.</p>
Music Theory - Implementation 2018-09-022018-09-02T04:00:00-04:002018-09-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-02:/music-theory-implementation-2018-09-02<p class="first last">Just kind of slop some code in there at random.</p>
<p>In this post:</p>
<ul class="simple">
<li>How starting to code was.</li>
<li>Plans of various scopes.</li>
</ul>
<hr class="docutils" />
<p>I spent Saturday reading about crate organization, partly for this, mostly for gdp, and then just started implementing types and functions from the last post.
It's not all implemented yet, and I keep changing the interfaces, but it shouldn't take long for me to get things the rest of the way ported, and start adding functionality.</p>
<p>The biggest obstacle I've hit so far is not having a good sense of when code with weird ergonomics is Just How Rust Is Right Now, and when it's "Oh, yeah, that was a compelling use case, so we stabilized a feature that helps with that <a class="reference external" href="https://blog.rust-lang.org/2017/08/31/Rust-1.20.html">literally a year ago</a>."
So, with generally not knowing how best to express things, I feel like I haven't really hit my stride, but all the same I'm translating code into a nice, mostly-concise form.
A bunch of my re-expressions were around converting from tuple returns to mutable arguments.</p>
<p>For ease of "just throwing code in there and making sure it typechecks" I've been just writing absolutely everything into a single file.
To move forward, I think I ought to start separating things into modules.
Maybe first do it within the file, then pull out modules into their own files as possible.
Once that's done, I can look over the various types, and, without the noise of the entire rest of the file, figure out what derives and such to stick on them.</p>
<p>One thing I should figure out before I do too much more is, what exactly is this library supposed to expose?
I guess, probably, all of the types I noted up, but I'm not really sure.
Also, I probably want to bite the bullet and make <tt class="docutils literal">Duration</tt> a newtype, because I do want it to be distinct from "a fraction that is the same shape".</p>
<hr class="docutils" />
<p>Next time, I look over this last week.</p>
GDP Rust 2018-09-012018-09-01T04:00:00-04:002018-09-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-09-01:/gdp-rust-2018-09-01<p class="first last">This week is a little Rust-heavy.</p>
<p>In this post:</p>
<ul class="simple">
<li>Other people's weird type-level code.</li>
<li>My thoughts on synthesizing said weird type-level codes together.</li>
</ul>
<hr class="docutils" />
<p>Main topic <em>and</em> free topic as code?
That seems a little off.
Oh well.</p>
<p>One thing I do for fun is attempt to implement various bits of PL theory from the context of one language, in another.
During the last few months, I've been reading and re-reading a paper on a technique, developed in Haskell, called <a class="reference external" href="https://github.com/matt-noonan/gdp-paper">Ghosts of Departed Proofs</a>.
I figured, when I do static stuff to mess around in, I do it in Rust, so can these techniques be applied to Rust code?</p>
<p>My answer, from repeatedly fumbling around and compiling little toy examples, is: Probably?</p>
<p>A key thing I needed to understand this all was a point of comparison: Ghosts of Departed Proofs is inspired by the ST monad, which also inspired/is related to <a class="reference external" href="https://play.rust-lang.org/?gist=21a00b0e181a918f8ca4&version=stable">Sound Unchecked Indexing</a>.
I probably wouldn't have gotten as far as I have, without that code.
Be that as it may, I don't think I'm far enough along to paste up code samples.
I keep on changing my mind about what makes sense, because I was doing this to mess around, and hence, didn't plan.</p>
<p>So, for plans, here's a rough outline of the crates I want to make (all names subject to change):</p>
<ul class="simple">
<li>gdp. This should be a small crate, in line with the small size of the core Haskell module.</li>
<li>sorted_by. This should probably be a little bigger. The idea is, this would exercise the various parts of the gdp crate.</li>
<li>some test module. This would be as big as it has to be; the idea here would be to try to break the guarantees that gdp and sorted_by need to work.</li>
<li>There are other modules in here that I kind of skimmed over because my attention span is shot, I guess. The description of "gdp" above is based on the <tt class="docutils literal">Named</tt> module, so actually gdp might be somewhat bigger, or maybe there are a bunch more crates that I haven't really looked into yet.</li>
</ul>
<p>As to what goes in them, I need to go over the original Haskell.</p>
<p>The <tt class="docutils literal">Named</tt> module exports several definitions:</p>
<ul class="simple">
<li><tt class="docutils literal">Named</tt> associates an extra type parameter to a normal newtype. The equivalent in Rust is to have a tuple struct where one element is a <tt class="docutils literal">PhantomData<_></tt>.</li>
<li><tt class="docutils literal"><span class="pre">(~~)</span></tt> is syntactic sugar for <tt class="docutils literal">Named</tt>.</li>
<li><tt class="docutils literal">name</tt> takes a value, a function that operates on all "named" versions of that value, and associates a unique named type to that value, then returns the overall result. I tried to avoid porting this directly, but then I saw that Sound Unchecked Indexing worked much the same, so, heck, that's what we're doing.</li>
<li><tt class="docutils literal">Defn</tt> is a singleton data type.</li>
<li><tt class="docutils literal">defn</tt> is a function that I believe is meant to allow library authors to explicitly name a value outside the context of the <tt class="docutils literal">name</tt> function.</li>
<li><tt class="docutils literal">Defining</tt> is a type...class(?) that's required for the implementation of <tt class="docutils literal">defn</tt>. It can't be implemented in Rust with precisely equivalent semantics, so far as I know. I've seen forum threads and such asking for <tt class="docutils literal">Coercible</tt>, and it doesn't seem to be in Rust.</li>
</ul>
<p>So, let's see what we need to translate these.</p>
<p><tt class="docutils literal">Named</tt> needs a tuple struct that wraps a type parameter and some manner of zero-sized-type, such as PhantomData.
Sound Unchecked Indexing creates a type with the required properties using an invariant lifetime.
I believe I want to ultimately do this using some kind of trait, which is implemented by Index (which can be private to the crate), and open to implementation by library authors, which could be a bit tricky to get right.</p>
<p><tt class="docutils literal">name</tt> creates a name, that only seems to last as long as the call, using lifetimes.
In my current iteration on this, the second argument to <tt class="docutils literal">name</tt> is required to accept at least a subset of all trait implementors, but because that subset can be private, the functions in question <em>must</em> accept the trait, which is the correct behavior.</p>
<p>I've set up a trait, as I said, and I'm trying to figure out the proper way to handle implementing it, so that only library authors can assign names they create.</p>
<p>Looking at the use of <tt class="docutils literal">defn</tt>, I see that it's attaching names defined by the library author.
Since the library author can write an arbitrary association, it is fine if it's possible for the author to write a function that is basically the identity function, but this behavior must be opt-in.</p>
<p>Having a function that attaches the name to a value seems fine.
Having a name initially attached to a particular closure seems tricky.
I believe the way to go is to just return the named form from a nullary function.
That way, the type parameters get filled in properly and such.</p>
<p>I haven't looked over everything that's needed here.
For the proofs from part of the paper I skimmed over, I think the equivalent in Rust must be some kind of trait implementation.</p>
<p>Given that name types are not very interesting, in terms of implementation details, it would probably be handy to provide a macro to make them given just a name.
To actually carry out the attachment, there must be a requirement that only the crate author can fulfill.
This would be creating an instance of the name using a private constructor.
If the downstream crate is responsible for the name instantiation, then that means the upstream must provide a constructor function that takes a name instance as an argument, but it only needs the instance as proof of authority, so it can then drop it and use a phantom type.
The default instance should be a struct with a private ZST and a public constructor, that is thus accessible only within the crate.
The type itself is public, but it cannot be instantiated outside its crate.</p>
<p>It might be desirable to define the Named struct as taking the PhantomData explicitly, and define a trait to implement internally to extract out the wrapped type, for the purposes of the public constructor.
This would make auto-derives less annoying, but I'm not sure it wouldn't expose something annoying somewhere else.
Maybe use a type alias instead.
That's probably less aggravating, in that it seems to provide about the same functionality as the trait idea, but it doesn't involve traits as much.
It's probably a bad idea to use traits where they're not absolutely needed.
Which, to be fair, they are absolutely needed in a lot of places.</p>
<p>Something that just clicked for me: the library-defined names in the example are actually polymorphic, taking another name.
This shouldn't be too problematic to implement, but it is a wrinkle to be aware of.</p>
<p>In terms of the "sorted_by" stuff, I want to work on iterator stuff.
Linear-time guaranteed sorted merges sounds cool.</p>
<p>I think where I want to go next with this is to sketch out plans on paper, think about this stuff visually.</p>
Music Theory - Research 2018-08-312018-08-31T04:00:00-04:002018-08-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-31:/music-theory-research-2018-08-31<p class="first last">Galling as the time away was in retrospect, it does seem to have given me some useful insights.</p>
<p>In this post:</p>
<ul class="simple">
<li>A list of types.</li>
<li>Some concerns I have, now that I'm looking at this with fresh eyes.</li>
<li>Ideas for directions to take this, when I'm not feeling blocked by language choice.</li>
<li>The plan for how to do the initial implementation.</li>
</ul>
<hr class="docutils" />
<p>Tiny Music is currently rather small, even for what it's meant to accomplish.</p>
<p>It defines several types:</p>
<ul class="simple">
<li>Duration, which is functionally a wrapper around positive rationals (which, practically speaking, could be based on u8, and work fine)</li>
<li>NoteType, which is currently START, TIED, and REST, and will soon swap out START for stuff like literal pitches and applying an interval to the preceding pitch. On reflection, the use of TIED, while probably necessary, enforces some surprising behavior.</li>
<li>Note, which combines Duration and NoteType, and also allows for 0 or more augmentation dots.</li>
<li>BeatType, which appears to be unused. It's the start of an attempt to apply concepts from a previous entry, and consists of PRIMARY_ON_BEAT, SECONDARY_ON_BEAT, TERTIARY_ON_BEAT, PRIMARY_OFF_BEAT, and SECONDARY_OFF_BEAT.</li>
<li>BeatStructure, which combines a Duration with a sequence of sequences of positive integer beat lengths. It seems like this should have provided a means of iterating out BeatTypes, but I guess I never did that.</li>
<li>Measure combines a sequence of Notes with a BeatStructure, and validates at runtime that they actually match in length.</li>
<li>MultiMeasure is a sequence of Measures. Along with Duration, this is going to be a newtype in Rust.</li>
</ul>
<p>Something that hadn't occurred to me before is that the way I'm representing Notes means that simultaneous notes must be accomplished via simultaneous measures.
In terms of what the code sees, this means that intervals need to be able to look "across" voices.
In terms of what the input looks like, this means that stuff like music for stringed instruments will require some serious conversion before it's in a state that makes sense.</p>
<p>Because of the wide variety of things that can be done in a rhythmic fashion, it seems like I should aim to parameterize NoteType by the type of actions that can be taken.
Doing that, it may then be possible to represent the same stretch of music at different levels of abstraction: convert a set of chords made up of abstract notes into a set of interlinked intervals realized through four voices, then render as concrete pitches.</p>
<p>To get the implementation done, I'll want to introduce types in approximately the order they're in up there.</p>
<hr class="docutils" />
<p>Next time, I start work on a tiny_music crate.</p>
Draw a Box 2018-08-302018-08-30T04:00:00-04:002018-08-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-30:/draw-a-box-2018-08-30<p class="first last">IT'S DONE!</p>
<p>In this post:</p>
<ul class="simple">
<li>IT'S DONE!</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>30 lines on August 23.</li>
<li>30 lines on August 24.</li>
<li>30 lines on August 25.</li>
<li>30 lines on August 26.</li>
<li>30 lines on August 27, of somewhat lower quality, perhaps due to reckless shmup-playing beforehand. It feels like my hand was under a couch...</li>
<li>30 lines on August 28.</li>
<li>36 lines on August 29, finishing the sheet.</li>
</ul>
<p>For a total of 216 lines this week,
390 lines on the first sheet since I started counting,
and <em>a lot</em> of lines on the second sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be a little different.</p>
Music Theory - Planning 2018-08-292018-08-29T04:00:00-04:002018-08-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-29:/music-theory-planning-2018-08-29<p class="first last">Enough dawdling.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I want to do this week overall.</li>
<li>How I'll break it down.</li>
</ul>
<hr class="docutils" />
<p>As I consider Structured Data more and more, I've come to the decision that I want to put that all on hold and try using Rust instead.
To try this out, I'm going to try to adapt Tiny Music, because it has no external dependencies.</p>
<p>In line with my usual thought process of "don't rush into things so much", my two project days this week will be:</p>
<ul class="simple">
<li>Document the current state of Tiny Music, and then plans I had going forward.</li>
<li>Start converting the code, with an eye on tests.</li>
</ul>
<p>My overall hope is that I'll be able to move forward expanding the definition of types of note, once I've finished the conversion.</p>
<hr class="docutils" />
<p>Next time, a full writeup of the current state of Tiny Music.</p>
Weekly Roundup 2018-08-282018-08-28T04:00:00-04:002018-08-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-28:/weekly-roundup-2018-08-28<p class="first last">Subsequent to all of this, I played some bullet hell games, and now my hand feels funny.</p>
<ul class="simple">
<li>Main project: I got ready to learn about romance novels in a somewhat methodical fashion.</li>
<li>Draw a Box: More lines. Closing in on the home stretch of this sheet, for real.</li>
<li>Free-Topic: I did kind of a grab-bag of several topics, since I didn't have an entire post about any of them.</li>
</ul>
<p>Next week, I attempt to convert Tiny Music to Rust so I'm not considering myself blocked on pattern matching.</p>
Romance Instrumentality Project - Retrospective 2018-08-272018-08-27T04:00:00-04:002018-08-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-27:/romance-instrumentality-project-retrospective-2018-08-27<p class="first last">Did everything I said, not everything I wanted.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I think about this last week, all in all.</li>
<li>How well I followed the plan.</li>
<li>Reasonable near-term goals.</li>
<li>Thoughts on further-out improvements.</li>
</ul>
<hr class="docutils" />
<p>This week, I planned to scope out some romance publishers and have a look through their catalogues.
I did that, but there were a few subgoals that didn't work out, so I had to abandon them.</p>
<p>The big stumbling block I had this week was around having some slightly off assumptions about how things work.
I assumed that all publishers would have as detailed guidelines as it sounds like Rutskarn ran into, and that doesn't seem to be the case for the ones I found.
So, lacking the training wheels I expected, I had to recalibrate my expectations.
I'm not sure it really affected my short-term plans, but it definitely scrapped some of my long-term plans.</p>
<p>Basically, once I have more exposure to the genre, I'm going to have to kind of be self-directed to develop at it, since I'm not seeing the aforementioned training wheels.</p>
<p>On balance, this means more work than I wanted to put in to developing an outline, but probably not much more work.</p>
<p>So far as the reading list I put together, I'll probably have to go over the individual titles again.
There are some that I'm somewhat skeptical as to whether they fit into the strict romance novel framework; some of them are very short.</p>
<p>Ultimately, this week doesn't seem too impressive to me in terms of the artifacts I got out, but I went over all of the excerpts for nearly every book I put on the list, so it's not like I didn't put in effort.
Where I fell short was down to bad assumptions on my part, and issues with website navigation.</p>
<p>Going forward with the project, I want to hold off on reading for now.
I'd like to take some time at some point to go over resources I've found, in a less skim-y fashion.</p>
<hr class="docutils" />
<p>Next week, it occurs to me that my Python projects are kind of foundering due to my feature envy of Rust.
It might make sense to try porting Tiny Music to Rust and see how that goes, since that doesn't have any dependencies that I remember.</p>
Romance Instrumentality Project - Initial Reading List 2018-08-262018-08-26T04:00:00-04:002018-08-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-26:/romance-instrumentality-project-initial-reading-list-2018-08-26<p class="first last">These tags are getting a little recherché.</p>
<p>In this post:</p>
<ul class="simple">
<li>I had a list (below), then I tried to come up with a sampling of books (ahead of the next post), and things went a little off the rails.</li>
</ul>
<hr class="docutils" />
<p>So, I binged on samples and catalogs.
Here's what I came up with:</p>
<ul class="simple">
<li><dl class="first docutils">
<dt>SMP Swerve</dt>
<dd><ul class="first last">
<li>Until It's Right</li>
</ul>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt>Bold Strokes Books, I ended up not getting grabbed by their Romance section for now, but unrelated to the overall project, I like the sound of:</dt>
<dd><ul class="first last">
<li>The Maverick Heart Cycle</li>
<li>The Godfall Novels</li>
</ul>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt>Carina Press</dt>
<dd><ul class="first last">
<li>The Cascadia Wolves miniseries</li>
<li>The Magic Born Miniseries</li>
<li>The Triton Experiment Miniseries (assuming I can find book one)</li>
</ul>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt>Less Than Three Press</dt>
<dd><ul class="first last">
<li>Alchemy</li>
<li>The Zhakieve Chronicles</li>
<li>The Exile series</li>
<li>The Shadows of Melbourne series</li>
<li>Choice</li>
<li>Crystal Cage</li>
<li>Cursed with Claws</li>
<li>Dragon Magic</li>
<li>Dragonspire</li>
<li>Dreamsnare</li>
<li>Empty Vessels</li>
<li>Equilibrium</li>
<li>Evergreen</li>
<li>For the Clan</li>
<li>The Strange Happenings in Saxtain series</li>
<li>Gatekeepers and Dreamweavers</li>
<li>Glove of Satin, Glove of Bone</li>
<li>Goblet's Edge</li>
<li>Green Toes</li>
<li>Hold Fast the Knight</li>
<li>Homeplanet</li>
<li>If Lost, Please Return To</li>
<li>Losing Ground</li>
<li>Matters of Heart</li>
<li>The Night Spirit series</li>
<li>One More Ride</li>
<li>Opalescence</li>
<li>The Kitten & Witch series</li>
<li>Pyre at the Eyreholme Trust</li>
<li>Rescues and the Rhyssa</li>
<li>Rule of Three</li>
<li>Sand Raiders</li>
<li>Skeletons in the Closet</li>
<li>Smoke Signals</li>
<li>The Broken Forest</li>
<li>The Night Watch</li>
<li>The Shock of Survival</li>
<li>Werebears and Water</li>
<li>The Visions series</li>
</ul>
</dd>
</dl>
</li>
</ul>
<p>I had trouble navigating ImaJinn's site, and Less Than Three gave me plenty to work with, so I'm not looking at ImaJinn for now.</p>
<p>I'm thinking once I've taken care of some other obligations, I'll look into the Cascadia Wolves books (although it is a little distracting that one character happens to have the same name as a character in a certain high-profile video game), and pick and choose from the huge list of Less Than Three stuff up there.</p>
<p>I didn't have time to try to write up and synthesize guides.
I'll try that later.</p>
<hr class="docutils" />
<p>Next time, I go over this last week of work.</p>
Checking In 2018-08-252018-08-25T04:00:00-04:002018-08-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-25:/checking-in-2018-08-25<p class="first last">I didn't have a singular thing to go over today.</p>
<p>In this post:</p>
<ul class="simple">
<li>Update on Gitless.</li>
<li>Thinking about syntax files.</li>
<li>Thinking about Structured Data.</li>
<li>Thinking about the romance stuff, as well.</li>
</ul>
<hr class="docutils" />
<p>This week was a little intense, so I didn't have anything lined up for this post.
I do have a grab-bag of not-big-enough-for-a-post things.</p>
<p>Continuing on with trying to use Gitless, it seems entirely adequate for my usage so far.
I'm still hitting rough patches using it, but they're not caused by Gitless, and it has no way to notice the ways I'm messing up.
(Various permutations of "changing a file over <em>there</em>, and doing repo operations over <em>here</em>". I'm a little disorganized, and a CLI can't just magically fix that.)
Meanwhile, one of our development machines (which I'm not shoving random bits of software on, because that would be rude) got into detached HEAD state, which isn't supposed to be possible with pure Gitless.</p>
<p>I'm trying to wrap my head around designing rules for syntax files.
I've got this idea at an intellectual level that the syntax files don't need to perfectly capture the tree structure of the underlying code.
They need to parse out some of the information inherent in syntactically correct code, and it's nice if they can detect some forms of syntactically incorrect code.</p>
<p>The issue is being able to make judgment calls on what to model and what not to.
It's necessary to parse strings correctly, because they can contain patterns of text indistinguishable from source code except by context.</p>
<p>I think I want to think about this in terms of constraints.
Function calls, indexing, and collection literals introduce a constraint through matching brackets.
Attribute access constrains the right-hand side to be a user-defineable identifier.</p>
<p>I think I'll try using that principle to get back on the syntax file.</p>
<p>And speaking of Python stuff, I still haven't been touching Structured Data.
I need to take a few hours some time to go over what I want to do, because it's a little confused.
I believe I've mentioned before, the idea of writing optimization code to improve the performance characteristics of match-based functions?
I've only thought about that enough to ponder a few issues I hadn't entirely noticed in the first place:</p>
<ul class="simple">
<li>How to represent a "forward declaration" of a match-based function, so that it's possible to reason about recursive functions in some way.</li>
<li>Where to put the ADT representations of match structures. This is kind of an aesthetics thing; if you look at the history of the repository, it's probably fairly obvious that I'm often reorganizing code on a whim. I'm trying to keep from having a single monolithic file, but there are various dependencies. I was able to make some progress with the idea of "minimal modules" that don't import anything, or only import modules that don't import anything, but if I put ADT definitions next to their corresponding match classes (which seems a natural place to put them), then suddenly that introduces dependencies imported from the public interface.</li>
</ul>
<p>It's probably appropriate that "Project: Feature Envy of Rust" is giving me more feature envy of Rust.</p>
<p>Regardless, this reveals some shortcomings in my organizational scheme.
I've noticed I've had issues with this before, and tried to find advice, but I feel like I didn't find anything really concrete.
Either I'm using the wrong search terms, or nobody thinking about this the way I am has any answers.</p>
<p>I jotted down some romance-related ideas, but my presumptuous opinion as an arrogant STEM dude is that it doesn't make any sense to try to put anything together until I've read some professionally-published stuff and know what I like.
Some things that I'm going to have to meditate on are, if I end up writing and publishing something, what name would it be under?
would I talk about it in any detail here?
exactly who's supposed to be seeing this blog, anyway?</p>
<p>Nothing really specific; I haven't been focusing enough for that, I guess.
I think the weather's making me a bit loopy; it's just so humid and unpleasant.
Here's to next week.</p>
Romance Instrumentality Project - Broad Strokes 2018-08-242018-08-24T04:00:00-04:002018-08-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-24:/romance-instrumentality-project-broad-strokes-2018-08-24<p class="first last">I still feel the need to emphasize that this is all more wholesome than the slasher movies we've been watching.</p>
<p>In this post:</p>
<ul class="simple">
<li>I had a list (below), then I tried to come up with a sampling of books (ahead of the next post), and things went a little off the rails.</li>
</ul>
<hr class="docutils" />
<p>There are a few things I want to see guaranteed by the publisher:</p>
<ul class="simple">
<li>queer-positive</li>
<li>feminist</li>
</ul>
<p>In terms of subject matter, I have various areas of interest I could look into, and a few things I don't want to read.</p>
<ul class="simple">
<li>supernatural or aliens, particularly if it avoids garishly hued space women</li>
<li>polyamory, especially mmf</li>
<li>realistic bdsm</li>
<li>mindplay? (I admit I'm not sure what this would look like; like I'm pretty sure <em>something</em> would have to give in terms of realism, probably telepathy would be involved?)</li>
<li>probably not a lot of guns and violence</li>
<li>amazon?</li>
<li>avoid blackmail</li>
<li>I think I'd rather not read stuff with vampires right now</li>
<li>Now that I think about it, if there's any serious amounts of alien lesbian pirate romance, that'd definitely be a thing to look into</li>
</ul>
<p>I had a look at some recommended novels, looked at the publisher, and there's other books there I might look into, but they don't have their submission guidelines up, which means I also need to look into other publishers if I don't want to be caught off-guard.</p>
<p>An initial sampling of publishers to look for books from:</p>
<ul class="simple">
<li>SMP Swerve</li>
<li>Bold Strokes Books</li>
<li>Carina Press</li>
<li>ImaJinn Books</li>
<li>Less Than Three Press</li>
</ul>
<p>Looking over the submission guidelines, where applicable, I see that I haven't happened to stumble across the same publisher Rutskarn submitted to, because these submission guidelines are focused way more on themes than on structure.
I'm going to still try to put together a reading list from these next post, but I think I'm going to have to synthesize stuff from how-to guides for outlining, rather than just find some handy submission guidelines.
(The submission guidelines <em>were</em> useful for picking which publishers/imprints to look at.)</p>
<hr class="docutils" />
<p>Next time, in addition to setting myself a reading list, I'm going to try to pull together some guides, so I'll have something to look over when I've got more experience with the genre.</p>
<p>One other thing I want when I try to apply this, is to set myself some expectations for content ahead of time.
If I find myself deviating from those expectations, instead of discarding the expectations, I will back-burner the current attempt to satisfy them, and start over.
I want to see what happens when I'm focused on satisfying some conditions, rather than just Following My Muse™.
Nothing personal against My Muse, but I'd rather follow some guidelines, try to accomplish specific objectives; this is something I haven't really been doing as a writer.</p>
Draw a Box 2018-08-232018-08-23T04:00:00-04:002018-08-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-23:/draw-a-box-2018-08-23<p class="first last">Speeding up as I fill in more of the edges.</p>
<p>In this post:</p>
<ul class="simple">
<li>I'm getting close to the end of this sheet, really.</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>30 lines on August 16.</li>
<li>30 lines on August 17.</li>
<li>30 lines on August 18.</li>
<li>30 lines on August 19.</li>
<li>30 lines on August 20.</li>
<li>30 lines on August 21.</li>
<li>30 lines on August 22.</li>
</ul>
<p>For a total of 210 lines this week,
390 lines on the first sheet since I started counting,
and at least 1290 lines on the second sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Romance Instrumentality Project - Planning 2018-08-222018-08-22T04:00:00-04:002018-08-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-22:/romance-instrumentality-project-planning-2018-08-22<p class="first last">Get it? Because the initials... Ahem.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I'm going to do in each post this week.</li>
<li>Why I'm doing this.</li>
<li>Some reservations I have, and my feeling that they don't make logical sense.</li>
</ul>
<hr class="docutils" />
<p>Recently, I've been having trouble finding prose that I like.
So, I tried writing stuff that worked for me.
I ended up with an overdone backstory that distracted from the core ideas and was basically a mess of nonsense.</p>
<p>I suspect part of the issue there is that I had some form of plans for various things that would happen, but no disciplined outline.
It occurs to me that I could probably really improve my writing if I got practice writing with an outline, as opposed to writing without.
However, outlining seems to me to have been mostly presented as a distinct skill, so it kind of looks like I'd have to do even more work before seeing results.</p>
<p>Except... mostly, not fully.
There is some fiction that takes a much more "predefined guard-rails" approach to outlines.
And the last NaNoWriMo I remember attempting, I found myself genuinely affected by the emotionally fraught relationship drama I attempted to inject into the gonzo sci-fi I was writing, before the whole thing turned into a flabby mess and fell apart.
Bit of a theme, that.
Inspired by Rutskarn's recent Quest for Romance, I think I'll try to get into this whole romance genre.
My priorities will be somewhat different than his:</p>
<ul class="simple">
<li>I'm not interested in getting published; on the off-chance that I create a book-like artifact, I'll be looking into self-publishing, probably.</li>
<li>I'm not necessarily looking to write anything at all, but I judge there to be a good chance I won't find something that exactly works for me, so I'm definitely not ruling it out.</li>
<li>With that in mind, rather than trying to jump right into writing with a little research, I'm going to focus first on drawing up a list of novels, and make actually reading them a separate project, probably tackled after I've read more of my wife's adventure novel.</li>
<li>Instead of attempting a broad survey from just a few books, my plan is to draw up as large a list as I can of books that look like they'd appeal to me, and also include some other information for cross-referencing purposes.</li>
</ul>
<p>My plan for converting whatever books I find into a framework for advancing my own writing is to principally rate the <em>publishers</em> based on how I feel about what they publish.
From there, look over their submission guidelines, and draw up a set of requirements for my own project, and especially the outline.</p>
<p>Before I lay out my plans for this week specifically, there's something I need to talk about.</p>
<p>Like most people, I've got a variety of things I feel uncomfortable talking about.
And sometimes I compare the stuff I'm comfortable talking about, and the stuff I'm not, and I can pull out examples from each that make no sense next to each other.
Like, I have no issue talking about the horror movies I watch with my wife, some of which are ridiculous sleaze, and some of which are merely gory.
But I feel like I'm not comfortable talking about what kind of equally fictional relationships I'd like to see in media, and I think, on balance, that doesn't make sense to me.
Like, polyamory is way more wholesome than Warwick Davis cutting a man's torso open with his hideous leprechaun claws.
That is a statement that I can find no fault with, but I'm still working my way through accepting on an intuitive level.</p>
<p>So, I'm going to try to talk frankly about what kinds of themes and situations I want to see, because romance is an incredibly broad genre, and it doesn't pay, I don't think, to be vague about what I want.
And I want be more open to talking about myself.</p>
<p>In any case, this week, I have two goals I want to accomplish.</p>
<ul class="simple">
<li>The first goal is to put together a list of things I'd like to see, ideally broken down into must-haves and nice-to-haves.</li>
<li>The second goal is to get a spread of publishers, authors, and books, according to those criteria. I basically want to have a reading list for later, in spreadsheet form or something like it, so I can rate books as I finish them, and analyze the results to figure out what works for me.</li>
</ul>
<hr class="docutils" />
<p>Next time, I'm going to post the list of what I want to read about.</p>
Weekly Roundup 2018-08-212018-08-21T04:00:00-04:002018-08-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-21:/weekly-roundup-2018-08-21<p class="first last">It was a slow week, I think, but I still did stuff.</p>
<ul class="simple">
<li>Main project: I started writing tests and refining my modified Python syntax for Sublime Text. I didn't come up with a new name during the project, but I came up with one after, which was, um, taken. Okay, got a new one: [name of language] Augmented.</li>
<li>Draw a Box: I started stepping up my lines per day to try to close out <em>only my second sheet</em> and have some momentum for the more interesting exercises.</li>
<li>Free-Topic: I rambled about the two different command-line tools I'm using to try to avoid dealing with Git directly. I couldn't, and can't, recommend either hg-git or Gitless unreservedly, but I still trust my ability with either more than I trust my ability with Git.</li>
</ul>
<p>Next week, I take a different tack than I have before to developing as a writer.</p>
Syntax Highighting - Retrospective 2018-08-202018-08-20T04:00:00-04:002018-08-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-20:/syntax-highlighting-retrospecive-2018-08-20<p class="first last">The auto-completion for syntax test files was a pleasant surprise.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I think about this week.</li>
<li>How well I followed the plan.</li>
<li>Reasonable near-term goals.</li>
<li>Thoughts on further-out improvements.</li>
</ul>
<hr class="docutils" />
<p>This week, having finally gotten tired of looking at the awful highlighting I was getting out of my custom color scheme, I decided to start learning the ropes of properly developing a syntax file.</p>
<p>I determined that the big gap in my knowledge was in writing and using syntax test files, since I'm already quite capable of tossing together yaml to try to get behavior I want.
I also decided I wanted a better name for the family of syntax files I'm working on than "Edge".</p>
<p>My plan for the week was to write up some syntax requirements based on the Python language reference, and then write tests based on those requirements.</p>
<p>I was able to write up several subsections, but when it came to the subsections on identifiers, I instead wrote up over 400 words detailing my issues with how the syntax is now, and how I want to try to change it.
Since I want to have the syntax solid in the less contentious aspects before I mess with it in a big way, I elected to skip specifying those tests for now.
I was able to write tests for a few basic areas, though, and make fixes to the syntax file when some of those tests failed.
For most areas, it seems to be pretty quick to write up a set of tests.</p>
<p>I never did come up with a better name.
I'll have to keep on that on and off.</p>
<p>I wonder if it's possible to define syntax tests at a meta level, like in a pytest file, then use Hypothesis to try to generate edge cases.
Probably not worth it.</p>
<p>I decided I will be plugging away at the language reference and several other sections of the documentation, getting solid test coverage, before I try to make the syntax behave like I want.
What I discovered from specifying comments is that I can feel pretty confident in messing with code that I have tests for, and the thing about redoing the identifier stuff is, that would potentially touch most of the code.
So it needs tests everywhere.</p>
<hr class="docutils" />
<p>Next week, I haven't decided.
There is one thing I have in mind that would mainly be research, with the heavy lifting, such as it is, to come later.
Alternatively, I could put another week towards Structured Data and see what that gets me.</p>
Syntax Highighting - Tests 2018-08-192018-08-19T04:00:00-04:002018-08-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-19:/syntax-highlighting-tests-2018-08-19<p class="first last">This is a little nicer than I expected. Good job, Sublime Text developers.</p>
<p>In this post:</p>
<ul class="simple">
<li>The tests I've written.</li>
<li>How that's working out so far.</li>
</ul>
<hr class="docutils" />
<p>I've made three test files from the writeups I've done so far.
One test file is focused around comments, and various extensions to them.
One test file is focused specifically on encoding declarations.
And the last test file is basically some sanity checks around line continuations.</p>
<p>Writing these test files was much less fiddly than the documentation made it look like it might be.
Turns out there's all sorts of auto-completion for syntax tests.
The bit that I'm least sure about is, it kind of looks like the tests are sensitive to the order that the scopes apply in?
I wasn't expecting that, but, okay, tests on a single line are order-sensitive.</p>
<p>Having the tests is nice, because it makes it super simple to tweak the syntax file and be sure I didn't break everything.
I made some tweaks to the comments handling, but I'll probably hold off on further changes for now.</p>
<p>Looking forward, I want to say, okay, every day, I either write up a section or convert a writeup into tests.
Just kind of methodically grind through the syntax documentation.
Then, when I have enough coverage, I can get to work on redoing the name handling, without worrying about hosing the rest of it.</p>
<hr class="docutils" />
<p>Next time, I look over all of this.</p>
Syntax Highighting - Testplan 2018-08-172018-08-17T04:00:00-04:002018-08-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-17:/syntax-highlighting-testplan-2018-08-17<p class="first last">It turns out that disagreeing about how syntax definitions should be is something I can do at length. Hooray?</p>
<p>In this post:</p>
<ul class="simple">
<li>I try to keep my frustration with existing syntax options factually based.</li>
<li>The sections that I got good writeups for.</li>
</ul>
<hr class="docutils" />
<p>So, I started writing up test plans, had a few good ideas, and then I hit a snag.
See, section 2.3 of the Python language reference is <a class="reference external" href="https://docs.python.org/3/reference/lexical_analysis.html#identifiers">Identifiers and keywords</a>, and in my opinion, the highlighter I have to work with handles them shamefully.</p>
<p>No, no, try to be positive.</p>
<p>...</p>
<p>I'm <em>positive</em> that—</p>
<p>Okay, calm down, try to present this rationally.</p>
<p>The sense I get from the page on <a class="reference external" href="http://www.sublimetext.com/docs/3/scope_naming.html">Scope Naming</a> is that some of the ideas for what to highlight, like the name of something that falls under excessively narrow criteria to be considered a function call, came from working with languages where different kinds of thing have their own namespace, and which kind/namespace applies depends on how the thing is used.
But with languages like Python and Lua, there's nothing like that, there's just values with names, and you can do stuff to the values, such as use them as function calls.
Or add two values together, surround them with parentheses, and call <em>that</em>.</p>
<p>I got a little carried away trying to reconcile the mental model encoded in the scope naming recommendations with the documented behavior of Python.
The end result is that about three-quarters of the section on <a class="reference external" href="https://docs.python.org/3/reference/lexical_analysis.html#reserved-classes-of-identifiers">Reserved classes of identifiers</a> is about how I <em>think</em> the syntax should work.
The other quarter is also about how I think the syntax should work.</p>
<p>Before my little rant there, I got three good section writeups, three that were just variations on "This section is about whitespace, I probably don't want to call it out", and the section on <a class="reference external" href="https://docs.python.org/3/reference/lexical_analysis.html#whitespace-between-tokens">Whitespace between tokens</a>, which doesn't merit tests of its own, but does suggest other tests down the line.</p>
<p>My plan for turning these test plans into tests is to write the tests I'm confident the syntax has a chance with, which are <a class="reference external" href="https://docs.python.org/3/reference/lexical_analysis.html#comments">Comments</a>, <a class="reference external" href="https://docs.python.org/3/reference/lexical_analysis.html#encoding-declarations">Encoding declarations</a>, and <a class="reference external" href="https://docs.python.org/3/reference/lexical_analysis.html#explicit-line-joining">Explicit line joining</a>.
After that, instead of working with keywords and identifiers, I'll start writing up and testing literals, because, again, I'm more confident that I mostly agree with the syntax on those.</p>
<p>On the name front, I've been tossing out all sorts of names.
Like "Python Forward".
I don't know, I need something that properly conveys the core philosophy here, which, on reflection, is probably something like "Well, I like it".</p>
<hr class="docutils" />
<p>Next time, I start writing tests.</p>
Tools I've Used to Avoid Using Git Directly2018-08-17T04:00:00-04:002018-08-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-17:/tools-ive-used-to-avoid-using-git-directly<p class="first last">I'm honestly kind of surprised that "using git indirectly" doesn't seem to be a bigger thing</p>
<p>In this post:</p>
<ul class="simple">
<li>I namedrop a bunch of <abbr title="Version Control Systems">VCSs</abbr>, but somehow <em>not all</em> of the ones I've heard of.</li>
<li>I describe two non-Git tools for interacting with Git repositories, and try to list the pros and cons of each.</li>
</ul>
<hr class="docutils" />
<p>I've used a few different version control systems over the years, like <a class="reference external" href="http://bazaar.canonical.com/en/">Bazaar</a>, possibly <a class="reference external" href="https://www.fossil-scm.org/index.html/doc/trunk/www/index.wiki">Fossil</a> (I don't actually remember), probably not <a class="reference external" href="http://darcs.net/">Darcs</a> but I'm not sure, <a class="reference external" href="https://subversion.apache.org/">SVN</a> for I know not what reason, mostly <a class="reference external" href="https://www.mercurial-scm.org/">Mercurial</a>, and a little bit of <a class="reference external" href="https://git-scm.com/">Git</a>.</p>
<p>All in all, this doesn't add up to much cross-cutting expertise.
I'll sum up the stuff I remember quickly:</p>
<ul class="simple">
<li>I cannot remember anything about using Bazaar that differentiates it from Mercurial</li>
<li>Mercurial has some rough edges that I've mostly learned to deal with; I mostly remember having a bad time untracking stuff I didn't want to commit</li>
<li>Git is terrifying and confusing</li>
</ul>
<p>However, it's also becoming more and more prominent; I kind of forget that software projects can be places besides GitHub, sometimes.
Which is kind of a bad thing, but also a true thing.
A truly bad thing.</p>
<p>So, what am I to do if I want to use GitHub, but not Git?
Well, I've found two solutions so far.
Neither one entirely satisfies.</p>
<p>For my own projects, I've been using <a class="reference external" href="http://hg-git.github.io/">Hg-Git</a>.
At work, I had been using Hg-Git, but I'm attempting to switch to <a class="reference external" href="http://gitless.com/">Gitless</a>, for reasons that will become clear later.</p>
<p>Hg-Git works on the principle of converting between Git and Mercurial repositories.
In terms of workflow, all that's required compared to my normal usage habits is to ignore branches in favor of tags.
There are some caveats here that make me reluctant to recommend it generally, though.
In some ways, Hg-Git is a cobbled-together shim on top of a set of unstable interfaces, and speaking as the developer and maintainer of a cobbled-together shim on top of a set of unstable interfaces, I know maintaining those can be pretty thankless.
Hg-Git has got to be even less pleasant to support than Divide and Cover, because some of the distribution networks for Mercurial seem to aggressively disappear old versions.
Old versions that actually support the current release.
The other issue I hit was that it was kind of confusing to figure out which way to invoke clone.
What worked for me, I think, was to follow all of GitHub's instructions for setting up an ssh key, and clone <tt class="docutils literal"><span class="pre">git+ssh://git@github.com/username/some-repo.git</span></tt>
Basically, if you like Mercurial, and you can install a working combination of Mercurial and Hg-Git, there's only one reason I'd recommend anything else.
And that's if you're collaborating with people using Git-specific tooling.</p>
<p>At my job, we are developing Git-specific tooling, so I can't just throw it at a repository converted to Mercurial and expect anything useful to happen.
To run our scripts, and later, potentially, our pre-commit hooks, I need to be working with actual Git repositories.
Enter Gitless.
Gitless is an attempt to give Git, the underlying revision history system, a different, better-designed interface than Git, the command-line tooling.
I'd read the papers describing it months ago, and hadn't had a compelling reason to try it out before now.
I've only been using it for a few days, so my impressions aren't fully formed, but I want this post done now, so that's the way it goes.
As I understand the papers, Gitless is a proof-of-concept for some design principles: can these principles be applied to a notoriously complicated tool, and deliver equivalent functionality with a simpler interface?
The paper lays out several criticisms of Git that Gitless is supposed to handle better.
The thing that's confused me thus far about the reactions I've read to these criticisms is, I've seen people say that some of them don't apply to Mercurial, but I don't think I've seen anyone mention that some of them do.
So, that was one of the things that pushed me away from trying out Gitless on my own.
It's not that I think good design has to look like the current state of Mercurial, but I knew that Gitless wouldn't fit into what I was used to.</p>
<p>The direction of things at work changed the balance, though.
If the tooling needs a Git repository, I have to give it a Git repository.
And Gitless let me do that.
As I said, I've only been using it a few days, so I haven't dug into the really advanced features.
Point in its favor, though: all of the worst issues I had were down to getting confused between two similarly-named repositories, and resulted in no bad commits.
There isn't much documentation, but I haven't really needed much more than there is, so I think that's good.</p>
<p>Gitless was also kind of tricky to install, in that there were many ways to try to install it, and some of them took a long time to not work.
On Mac, I found my best bet was to install all of it via <a class="reference external" href="https://brew.sh/">Homebrew</a>.
There are instructions for installing just the dependencies via Hombrew, but that had various issues, and it Just Worked when I installed the whole thing through Homebrew.</p>
<p>I wish I had some kind of snappy conclusion to this, something really satisfying, but all I've got is the truth of my lived experience.
And the truth of my lived experience is, I like Hg-Git, but it's hard to set up and maintain a working install, and it looks like Gitless fulfills the stuff I need for work, but I don't actually know yet.
I'll probably keep on using Hg-Git for my own stuff, and for work, we'll see how things work out.</p>
Draw a Box 2018-08-162018-08-16T04:00:00-04:002018-08-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-16:/draw-a-box-2018-08-16<p class="first last">I really hope the way I've done this has built anything beyond "character".</p>
<p>In this post:</p>
<ul class="simple">
<li>I'm still drawing the lines.</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>15 lines on August 10.</li>
<li>15 lines on August 11.</li>
<li>15 lines on August 12.</li>
<li>15 lines on August 13.</li>
<li>15 lines mostly on August 14.</li>
<li>30 lines on August 15.</li>
</ul>
<p>For a total of 105 lines this week,
390 lines on the first sheet since I started counting,
and at least 1080 lines on the second sheet.</p>
<hr class="docutils" />
<p>Next week, I'm thinking I should start ramping up, get a little bit more done in a sitting.</p>
Syntax Highighting - Planning 2018-08-152018-08-15T04:00:00-04:002018-08-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-15:/syntax-highlighting-planning-2018-08-15<p class="first last">I need a name I'm happy with.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I'm going to do in each post this week.</li>
<li>My two overall goals.</li>
</ul>
<hr class="docutils" />
<p>I'm able to kind of muddle through with basic syntax changes by just tweaking small areas until they work right, but I've got some changes I want to make to my "Edge" syntaxes that are much bigger and riskier.
Since I want to make "Edge" actually capable of highlighting the stuff I want, that means I need a safety net in the form of tests.
I <em>also</em> need a better name than "Edge", seriously.</p>
<p>Because I don't have hands-on experience with writing syntax tests, and I don't know how Sublime Text specifically behaves with them, for my next post I just want to create some writeups of different test cases that I can then actually create for the next post after that.</p>
<p>To get stuff for tests, I want to first focus on the language specification, then on the documentation of built-in functions and classes, then on standard library code that defines behavior for reserved method names not covered by the previous areas.</p>
<p>For each test, I want to get a minimal syntactically valid snippet of code, followed by more elaborate constructions that bear more resemblance to code "in the wild".
For example, numeric literals should be tested on their own, then in the context of stuff like top-level constants, default function arguments, and literals within a function.
Each subsection of documentation should have its own writeup of what tests it suggests, if any, and if there are tests, each subsection gets its own test file.
These ideas might change as I get more hands-on experience, but I hope they're solid.</p>
<p>I don't know how much I'll get to this week, but one thing I want in the future is to make an effort to support subsets of old functionality; for example, Python 2 reserves a different set of method names than Python 3.</p>
<hr class="docutils" />
<p>Next time, I write up syntax test specifications based on the Python documentation.</p>
Weekly Roundup 2018-08-142018-08-14T04:00:00-04:002018-08-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-14:/weekly-roundup-2018-08-14<p class="first last">I'm finally just about back to decent energy levels.</p>
<ul class="simple">
<li>Main project: Planned for next week.</li>
<li>Draw a Box: Started drawing, but not in time for last week's post.</li>
<li>Free-Topic: Didn't do it this time.</li>
</ul>
<p>Next week, having finally recovered enough, I'm going to try to improve my Python and reST syntax files in a methodical fashion.</p>
Checking In 2018-08-122018-08-12T04:00:00-04:002018-08-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-12:/checking-in-2018-08-12<p class="first last">Still taking it easy before the roundup.</p>
<p>In this post:</p>
<ul class="simple">
<li>The stuff I was messing with earlier, which doesn't really merit a writeup.</li>
<li>Solidifying the plans for next week.</li>
</ul>
<hr class="docutils" />
<p>Yesterday, I was working on Python code with an eye towards modeling a Mutants & Masterminds character sheet.
I had the idea that perhaps I could convert it into syntax tests.
In the end, I instead got a somewhat improved understanding of how it all fits together, and I was able to get the crunch on the sheet filled out.</p>
<p>So, if we define what I was trying to do as "Write Python code to make it easier for me to create a Mutants & Masterminds character", then I technically succeeded, even though the code is not, as such, syntactically valid, currently.</p>
<p>Anyway, my plan is to get the snippets to use for testing from the Python documentation.
That's a lot more stable, and it covers more edges than I hit normally, like different integer representations and complex numbers.</p>
<p>I think basically I want to be converting each sub-heading within some parts of the <a class="reference external" href="https://docs.python.org/3/reference/index.html">Python Language Reference</a> into a writeup of what tests, if any, should be derived from that section, and a plan for doing so.
Stick the writeups in a folder in the package, which should really go up on GitHub once I think of a better naming convention than just sticking "Edge" after the names of the syntax files I grabbed and tinkered with.</p>
<p>(I was slightly more worried about the ramifications of doing that in the first place, before I checked the repo, and realized that these syntax bundles appear to be licensed under what I think could best be described as "The MIT license in a hurry")</p>
Planning Ahead 2018-08-112018-08-11T04:00:00-04:002018-08-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-11:/planning-ahead-2018-08-11<p class="first last">Easing back into doing stuff.</p>
<p>In this post:</p>
<ul class="simple">
<li>Going over the three things I thought of earlier, and trying to prioritize them.</li>
</ul>
<hr class="docutils" />
<p>So, I did some drawing today; that sheet is very close to being done.</p>
<p>The other thing I need in order to ramp up is a project for next week.
Yesterday, I mentioned three choices:</p>
<ul class="simple">
<li>Get the syntax files to work better. This would be focused around creating test files for them, since it's very hard for me to make any further changes with any confidence. Just enumerating various cases sounds simple enough. <a class="reference external" href="https://www.sublimetext.com/docs/3/syntax.html#testing">Basic syntax testing documentation</a></li>
<li>I'm very leery of rushing ahead to implement the changes I want to Structured Data, because every time I think about it I come up with another nuance. <a class="reference external" href="https://github.com/mwchase/python-structured-data/issues/12">Match transformation issue</a>, <a class="reference external" href="https://github.com/mwchase/python-structured-data/issues/16">Disjunctive structure issue</a></li>
<li>I evidently don't have a solid enough grasp on Jedi's internals to just toss together the changes I want. Probably I want to take some time to just go over things a few times. <a class="reference external" href="https://github.com/davidhalter/jedi/issues/1015">Jedi issue</a></li>
</ul>
<p>I think my plan for next week is to ruminate about the Structured Data changes, find sample Python code to annotate for syntax tests, and write about Jedi for the free topic post.</p>
Checking In 2018-08-102018-08-10T04:00:00-04:002018-08-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-10:/checking-in-2018-08-10<p class="first last">I want to start doing more, not sure if I'm up for it.</p>
<p>In this post:</p>
<ul class="simple">
<li>How am I doing?</li>
<li>What am I going to do?</li>
</ul>
<hr class="docutils" />
<p>It feels like I'm recovering from all of the stuff we did last weekend, but I'm still not feeling up to the normal workload I was pulling off before.</p>
<p>My hope is that I can work my way up to that.</p>
<p>The next step, I think, is to start practicing drawing again tomorrow.
After that, I want to try getting back into weekly projects next week.
I have a few options there:</p>
<ul class="simple">
<li>Improving the syntax file(s) has the slight disadvantage that it's <em>incredibly complicated</em>. I think my best bet would be to focus solely on writing up test files so I can enumerate what I expect and get some test-driven stuff into all of this.</li>
<li>There are just two things I want to add to Structured Data in terms of base features: transformer structure nodes, and callable multi-match wrappers. Put together, these would then allow me to implement optimizing transformations of pure multi-matches, so I can write stuff, in my DSL, to make my DSL faster, which is obviously a sensible use of resources.</li>
<li>Maybe my best bet would just be to write up the changes to Jedi that I still want to make.</li>
</ul>
Checking In 2018-08-092018-08-09T04:00:00-04:002018-08-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-09:/checking-in-2018-08-09<p class="first last">Believe me, I'm still alive.</p>
<p>In this post:</p>
<ul class="simple">
<li>What's been up since I got back?</li>
</ul>
<hr class="docutils" />
<p>Last weekend, I went down to Florida with the rest of my family to celebrate various events in my grandparents' life.
It was really amazing to see what had happened to all of my cousins, and good to catch up with my relatives, but also.</p>
<p>Also.</p>
<p>I'm still super exhausted and burned out from taking 8+ hours to travel between Belmont and St. Augustine, both ways, in the space of a little over two days.</p>
<p>I want to get back into writing and drawing regularly again, but I don't know if I'll be up for it until I've taken this next weekend to finish recovering.</p>
Weekly Roundup 2018-08-072018-08-07T04:00:00-04:002018-08-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-07:/weekly-roundup-2018-08-07<p class="first last">I took it easy last week to be able to handle a massive family gathering. That only went so far.</p>
<ul class="simple">
<li>Draw a Box: Finished up drawing for the week.</li>
<li>Other: Vented.</li>
</ul>
<p>Next week, I haven't even decided on anything.
No matter what, I still need to take it easy.</p>
Draw a Box 2018-08-022018-08-02T04:00:00-04:002018-08-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-02:/draw-a-box-2018-08-02<p class="first last">Yep, still drawing the lines.</p>
<p>In this post:</p>
<ul class="simple">
<li>Schedule slipping, a little.</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>15 lines on July 26.</li>
<li>15 lines on July 27.</li>
<li>15 lines on approximately July 28.</li>
<li>15 lines on approximately July 29.</li>
<li>15 lines on July 30.</li>
<li>15 lines on approximately July 31.</li>
<li>15 lines on August 1.</li>
</ul>
<p>For a total of 105 lines this week,
390 lines on the first sheet since I started counting,
and at least 975 lines on the second sheet.</p>
<hr class="docutils" />
<p>Next week, I'm taking a break.</p>
Vacation Quick Post 2018-08-012018-08-01T04:00:00-04:002018-08-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-08-01:/vacation-quick-post-2018-08-01<p class="first last">Industrial-Strength Vague</p>
<p>I figured I'd try making tiny posts during the vacation to keep posting something.
I usually have the idea that I'm writing my posts in a way that is persuasive or informative, in the sense of having something to do with the relevant techniques.
Not this time.
This post is, in fact, shorter than this preface.</p>
<hr class="docutils" />
<p>When is it right that one person acts as the arbiter of another person's gender identity or pronouns?</p>
<p>I ask because I see some people out there who have clearly decided that it sometimes is.</p>
Weekly Roundup 2018-07-312018-07-31T04:00:00-04:002018-07-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-31:/weekly-roundup-2018-07-31<p class="first last">I'm so tired.</p>
<ul class="simple">
<li>Main project: I started trying to use Structured Data in earnest, and came up with a simple set of feature requests that edge dangerously close to converting it into some kind of esoteric inner platform.</li>
<li>Draw a Box: LINES.</li>
<li>Free-Topic: I wrote a rambling shitpost about indie game intros in under an hour because I've failed to learn time management.</li>
</ul>
<p>Next week, I take a break, because I'm going to Florida, and I don't want to blog while dehydrated or overheated.</p>
Algebraic Data Types - Retrospective 2018-07-302018-07-30T04:00:00-04:002018-07-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-30:/algebraic-data-types-retrospective-2018-07-30<p class="first last">Going in unpredictable directions.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I think about this last week, all in all.</li>
<li>How well I followed the plan.</li>
<li>Reasonable near-term goals.</li>
<li>Thoughts on further-out improvements.</li>
</ul>
<hr class="docutils" />
<p>So, this week, I figured I had Structured Data in a sensible enough form to start using it in my other projects.</p>
<p>I promptly generated a deluge of feature requests for myself.</p>
<p>And rewrote the syntax.</p>
<p>I kind of tried to stay on track, but I did end up on an awful lot of digressions related to getting more advanced logic into the matching facilities.
There's a chance I'll end up with a full <abbr title="Domain Specific Language">DSL</abbr> into which I just rewrite most of Homunculus.</p>
<p>Speaking as an engineer of some kind, I like how this week turned out because it was fun to hack on this stuff.
Like, it would have been nice to get a little further, but I got Structured Data into a nicer condition, and I'm happy with that.</p>
<p>My plan is to move forward is to wait a bit, think things over, implement transformers, and then try to use them.</p>
<hr class="docutils" />
<p>Next week, I go on vacation, because I'd rather not try to get this to fit around a trip.</p>
Algebraic Data Types - Iteration 2018-07-292018-07-29T04:00:00-04:002018-07-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-29:/algebraic-data-types-iteration-2018-07-29<p class="first last">Really, really unstable.</p>
<p>In this post:</p>
<ul class="simple">
<li>A stream of consciousness about changes to Structured Data inspired by real-world use.</li>
<li>A roundup.</li>
</ul>
<hr class="docutils" />
<p>So, I tried to use Structured Data in Homunculus, and I was at first focused on redoing the input handling routines to be parsing some kind of data structure rather than a bunch of nested functions.</p>
<p>Needless to say, I'll be toning down the undertone of "obviously <em>this</em> is how it should be" when I revisit this for a post, because the direction I'm taking this is diverging radically from any kind of normal Python code.</p>
<p>Regardless, I have some feature requests I wrote for myself, that I'll be discussing for this post:</p>
<ul class="simple">
<li>Guards. A unary function whose result is interpreted as a boolean. They don't inherently bind anything, but they can be given a structure to match if they succeed. If they fail, the match fails. As a special case, there should be guards for truthiness and falsiness provided by the library.</li>
<li>Binds. Top-level associations between an overall structure, a binding, and a value. If the overall match succeeds, the value is placed in the binding.</li>
<li>Transformers. Pairs of an unary function and a structure. The function is applied to the value to match, and its result is matched by the structure.</li>
</ul>
<p>Thinking about these, I'm coming to the conclusion that I want to rework some of the syntax/calling conventions.</p>
<p>Instead of overloading the matrix multiplication operator, I want to give patterns a <tt class="docutils literal">__call__</tt> implementation to allow for as-patterns.</p>
<p>Binds should be a method of patterns, where the first argument is the structure and the second is the value.
Alternatively, a library function that puts the pattern and value together.</p>
<p>Guards should have a one-argument and two-argument form, different classes, where the one-argument version can convert to the two-argument version somehow.</p>
<p>Transformers could potentially have a one-argument version, but it shouldn't be valid for matches.</p>
<p>The first thing I want to change is to switch from <tt class="docutils literal">__matmul__</tt> to <tt class="docutils literal">__call__</tt>.
Let's see how that goes.
I concluded that I want to use indexing, to avoid the hassle of having a bunch of parentheses.
We'll see how that works out for me.</p>
<p>While I'm thinking about ergonomics, it'd be cool if there were some way to get the <tt class="docutils literal">dict</tt> stuff out of <tt class="docutils literal">DictPattern</tt> and <tt class="docutils literal">AttrPattern</tt>.</p>
<p>Like if there a "base" and a "decorated" version of the patterns, where the "base" can just take arbitrary kwargs, but there's some way to get the "decorated" version, which is going to have non-default attributes.
I went and did this a different way, probably simpler.
And then I realized that I simplified <tt class="docutils literal">DictPattern</tt> too much, reverted it, and stopped trying to have the classes have sort of the same interface.</p>
<p>I've decided that binds should be a specific kind of object, that take a single anonymous argument and arbitrary named arguments, so a single bind can bind many names.</p>
<p>I've got binds done, next to do (later!) would be guards, then transformers.
I also have to be ready to redo what I currently have in Homunculus for the next release, which will be a minor version, because I went and redid some APIs on account of this isn't stable yet and I didn't like them.</p>
<p>I know that transformers have to be two-argument because there's no point in applying a function if you're not going to destructure the result.
(Shhh. I <em>want</em> there to be no reason to do so.)
I'm not sure how they should combine with other things, given that I sort-of care about the order that bindings happen in.
Perhaps transformers should extend themselves via repeated calls, and those calls handle one-argument and two-argument differently.
One-argument just takes a pattern, two-argument is function, then pattern.
Then people can do the matches in whatever order they want.</p>
<p>Guards are one-argument and use indexing to add in structure for if they pass.</p>
<p>These are certainly some ideas, but I'm not feeling terribly sure of them, so I'm going to sleep on this.</p>
<p>For sure, though, this is an exciting time to follow Structured Data, in that my response to attempting to use this stuff once is to aggressively rewrite the constructors.</p>
<hr class="docutils" />
<p>Okay, here's exactly where things ended up:</p>
<ul class="simple">
<li>As-patterns are now formed with indexing instead of matrix multiplication.</li>
<li><tt class="docutils literal">AttrPattern</tt> now takes keyword arguments directly.</li>
<li>New <tt class="docutils literal">Bind</tt> class defines matches that are applied after an overall match succeeds.</li>
</ul>
<hr class="docutils" />
<p>Next time, I go over this last week of work.</p>
Coming Up With An Indie RPG's Opening Cinematic Based Solely On Some Slasher Movie Music I Pretended Was Game Soundtrack2018-07-28T04:00:00-04:002018-07-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-28:/coming-up-with-an-indie-rpgs-opening-cinematic-based-solely-on-some-slasher-movie-music-i-pretended-was-game-soundtrack<p class="first last">I've got some.</p>
<p>In this post:</p>
<ul class="simple">
<li>Background information.</li>
<li>A rough sketch.</li>
<li>The whole thing.</li>
</ul>
<hr class="docutils" />
<p>So, we're watching horror movies, still.
The last few we saw, I noticed the music in them.
Most of my commentary on the music in <a class="reference external" href="https://www.imdb.com/title/tt0100156/">Mirror, Mirror</a> was some variation on <a class="reference external" href="https://www.imdb.com/name/nm0509864/">Jimmy</a>, take it down a notch, but before that...
We have seen all of the <a class="reference external" href="https://www.imdb.com/title/tt0081383/">Prom Night</a> movies, although, thanks to a beat up DVD, not <em>all</em> of all of them.
Anyway, when the action in <a class="reference external" href="https://www.imdb.com/title/tt0105179/">Prom Night IV</a> shifted from "inexplicable happenings" (Why was the brother out there? Who goes around stealing freezers?) to "killing off teenagers for their sins", the music suddenly took a weird direction.</p>
<p>It kind of sounded like the soundtrack of some kind of indie RPG in the vein of Undertale.
So, I'm going to try to sketch out the opening narration to this game I made up in my head.</p>
<hr class="docutils" />
<p>So, the opening cinematic is going to end with a meteor streaking down the center of the screen, and the narration says "I heard that wishes come down to Earth on falling stars. I wonder whose wish that is. Could it be mine?"</p>
<p>Backing up, there's some kind of establishing thing laying things out at a high level, like in Undertale, but here, the narrator exists within the cinematic.
The narrator is somehow oppressed, enslaved, possibly chained.
Aesthetically, I don't want <em>exactly</em> the Mimigas from Cave Story, but something in that general design area.
With monstery characters like this, there's the question of how they relate to humans.
I think, rather than oppression or war, the humans in this setting are unaware of the narrator's plight, and perhaps the narrator's race altogether.
Perhaps the humans used to know of them, and have forgotten, and one of the themes of the game is "remembrance".</p>
<p>So, there's some other group involved, that I'm having trouble figuring out the aesthetics for.
Maybe some kind of shadowy, spindly figures.</p>
<p>I'm going to say for now that the narrator's race is aesthetically based off of deer, but they're short and somewhat humanoid.</p>
<hr class="docutils" />
<p>Shot of a human figure, a small horned figure, and a tall figure, tightly wrapped in a tattered cloak.</p>
<p>"We saabin didn't always work for the spindlecloaks. We used to live in harmony with the humans, who protected us. Then, one day, the spindlecloaks cast a terrible spell. The humans lost their memories of us, and couldn't see us! The spindlecloaks captured us, and the humans did nothing."</p>
<p>The shot fades to black.</p>
<p>"... At least, that's what my grandmother says."</p>
<p>Shot of the narrator breaking rocks with a small pick-axe.
The narrator's right side is facing the camera, and they're missing that eye.
It's just an X.</p>
<p>"I don't know what it's like outside the fences. I can only imagine."</p>
<p>Shot of the narrator's left side.
The moon is out now, and the narrator looks fatigued.</p>
<p>"I used to imagine that one of the humans would realize we were here, and come to our rescue."</p>
<p>The narrator closes their eye.</p>
<p>"But those fantasies grew bitter over time. Thinking about the freedom I should have hurts, and it's easier not to think about freedom at all."</p>
<p>A shot of the narrator from behind, with a forest in the background.</p>
<p>"Every once in a while, though,"</p>
<p>The sky flashes.</p>
<p>"Something happens that wakes up those feelings, and I wonder if things could be about to change."</p>
<p>A shooting star streaks down the middle of the screen, towards the forest.</p>
<p>"I heard that wishes come down to Earth on falling stars. I wonder whose wish that is. Could it be mine?"</p>
<p>Cut to the crash site.
The title of the game is superimposed on the meteorite.
A crack appears in the meteorite, and shifts apart and open.
The title fades out, as the player character climbs out of the meteorite.</p>
<hr class="docutils" />
<p>Needless to say, imagining this general kind of thing (I specifically came up with the idea of people watching a falling star, that happened to contain the player character, during the movie.) during a slasher movie was... bad for the mood.
Anyway, maybe I'll do something with this later.</p>
Algebraic Data Types - Targets 2018-07-272018-07-27T04:00:00-04:002018-07-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-27:/algebraic-data-types-targets-2018-07-27<p class="first last">I'm glad I didn't pursue the false lead too far.</p>
<p>In this post:</p>
<ul class="simple">
<li>A brief explanation of the stuff I was doing <em>instead of</em> documenting refactor targets.</li>
<li>The refactor targets.</li>
</ul>
<hr class="docutils" />
<p>When I was going over the Homunculus code for this post, I realized I wanted to use the matching system in more ways than was possible at the time, in order to replace the "Visitor" classes I'd written, and ideally get rid of some explicit branches in favor of constant data in an iterable form.</p>
<p>At first, I approached this "match extension" concept from the perspective of creating a custom matcher that can specially deal with tdl input events, but as I started working on implementing an API for that, I realized I could get most of the functionality I needed simply by creating a Pattern type that destructures objects by attribute.
While I was at it, I designed one for destructuring dictionaries.</p>
<p>In the morning, I'll cut a new minor version, but for now, I slept terribly last night, so I'm going to try to speed through the rest of this post.</p>
<p>I still want to provide an API for custom destructuring logic, but that's not a priority currently.</p>
<p>In tiny music, the initial use would be to convert the <tt class="docutils literal">NoteType</tt> enum to an ADT.
Although this is relatively straightforward, I'm going to hold off on doin it because I have type-checking etc happening on that project, and I haven't yet tried to make a mypy plugin to make anything at all involving ADTs typecheck.</p>
<p>On Homunculus, I thought I was going to cover GameStates first, but I think I'm going to go for replacing some of the uses of the <tt class="docutils literal">Visitor</tt> class first.
Then GameStates, then the Template concept.</p>
<p>I ought to write up the match semantics of all of this stuff.
There are some subtleties that I might potentially forget.
Perhaps sometime I should do a documentation pass on Structured Data for a week, but that's not this week.</p>
<hr class="docutils" />
<p>Next time, I start trying to use this stuff.</p>
Draw a Box 2018-07-262018-07-26T04:00:00-04:002018-07-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-26:/draw-a-box-2018-07-26<p class="first last">Make up for lost time, lose count of the lines...</p>
<p>In this post:</p>
<ul class="simple">
<li>I got a late start, and possibly drew five extra lines.</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>45 (or possibly fifty) lines on July 21.</li>
<li>15 lines on July 22.</li>
<li>15 lines on July 23.</li>
<li>15 lines on July 24. I think the pen is in bad shape again.</li>
<li>15 lines on July 25. Perhaps the pen is suffering from the clawlike grip I have it in.</li>
</ul>
<p>For a total of at least 105 lines this week,
390 lines on the first sheet since I started counting,
and at least 870 lines on the second sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Algebraic Data Types - Planning 2018-07-252018-07-25T04:00:00-04:002018-07-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-25:/algebraic-data-types-planning-2018-07-25<p class="first last">Actually using the code I write, what a concept.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I'm going to do in each post this week.</li>
<li>The target areas for using Structured Data.</li>
<li>The 1.0 roadmap, which is implicitly mostly just "known unknowns"</li>
</ul>
<hr class="docutils" />
<p>Okay, here's the deal: over the past week, I made some serious improvements to Structured Data.
I've thought of some further features I could add, but for now I want to focus on getting it to 1.0, and that means trying to use it in the projects I wrote it for.</p>
<p>There are two projects that really need it right now:</p>
<ul class="simple">
<li>Homunculus needs it to pull some variables into the GameState structure, and to represent "higher-order" templates within the "templates" system I want to implement.</li>
<li>tiny music needs it to implement providing a frequency to a note.</li>
</ul>
<p>I feel like the first thing I'll need to work out is a good path for refactoring, so rather than specifically writing tests, I'll be spending the next entry documenting what each project currently does in the areas I want to change, what I think it should look like, and stepwise changes to get from the first to the second.</p>
<p>After that, I'm going to have to do some tight iteration cycles, to figure out what I need to change to make the library usable.
I anticipate releasing several minor versions, but I don't think I'll be comfortable with releasing a major version until someone else is interested enough to offer feedback.</p>
<p>So, the road to 1.0 goes:</p>
<ul class="simple">
<li>0.5.0: we are here, API is much improved from earlier iterations</li>
<li>0.6+: I make any changes I need this week</li>
<li>pre-1.0: someone else tries to use this code</li>
</ul>
<hr class="docutils" />
<p>Next time, I document the target areas for introducing this code.</p>
Weekly Roundup 2018-07-242018-07-24T04:00:00-04:002018-07-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-24:/weekly-roundup-2018-07-24<p class="first last">I need to figure out how to take it easier.</p>
<ul class="simple">
<li>Main project: I started working on a conlang from a grammatical perspective, made some interesting progress, and overextended myself.</li>
<li>Draw a Box: DRAWING. I'm thinking of switching to another sheet, doing the other exercises, and coming back to this one later.</li>
<li>Free-Topic: I pondered evaluating software quality metrics in terms of what happens when you optimize for them.</li>
</ul>
<p>Next week, I try to get some proper use out of Structured Data.</p>
Conlanging - Retrospective 2018-07-232018-07-23T04:00:00-04:002018-07-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-23:/conlanging-retrospective-2018-07-23<p class="first last">This week went from really cool to OH GOD NO, and I'm not sure I fully grasp why yet.</p>
<p>In this post:</p>
<ul class="simple">
<li>I think about burnout, mostly.</li>
</ul>
<hr class="docutils" />
<p>So, this week I wanted to make an unspecified amount of progress on a brand-new conlang, subject to the restriction that I wasn't going to think about phonology at all.</p>
<p>I accomplished this by using nothing but deliberately-imprecise glosses with grammatical features glommed on.
To get example sentences, I used a list of sentences from "<a class="reference external" href="https://cofl.github.io/conlang/resources/games/syntax-testing.html">Syntax Testing Game</a>".
I aimed for translating ten sentences a day.</p>
<p>I made good progress for a few days, then I got burnt out and bailed.
There are several factors that could have contributed:</p>
<ul class="simple">
<li>Last week was somewhat stressful for unrelated reasons.</li>
<li>The sentences get somewhat more sophisticated though the days, so working out a translation gets harder.</li>
<li>Just typing the translations into a text file may be a non-scalable workflow.</li>
</ul>
<p>For now, I'm happy with what I accomplished, though I need a break from it for now.</p>
<p>At the moment, I just really want a good idea of those causes.
I believe a better workflow might be helpful if I pick this back up.
I think I should try to find some conlanging software that works well with what I've done so far.
The other thing that would help would be some way of moderating the amount of work I try to do in a day.</p>
<p>So, I think what I need to do when I come back to this, is take some time to figure out if there's any software or better organizational system that my existing work can slot into.
Then, maybe set up some kind of fakey agile thing so I can measure my "velocity" with new translations, or something.</p>
<hr class="docutils" />
<p>So, while I was working on this stuff, I was also getting Structured Data into a better shape.
The API is way better, and I'm now curious how it shakes out in practice.</p>
<p>With that in mind, next week, I'll focus on using Structured Data in some of my projects.
This may veer into writing plugins for it.</p>
Conlanging - Grammar 2018-07-222018-07-22T04:00:00-04:002018-07-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-22:/conlanging-grammar-2018-07-22<p class="first last">There's a lot of it.</p>
<p>In this post:</p>
<ul class="simple">
<li>Just a giant spew of made-up grammar facts.</li>
</ul>
<hr class="docutils" />
<p>I'm making a judgment call, and stopping the daily sentence quota.
I'm just slipping a lot, and it's hard to deal with.</p>
<p>Anyway, let's see how this works.</p>
<p>There are several categories of word, which each have different requirements for the associated information:</p>
<ul class="simple">
<li>verbs mark person, then number, then aspect</li>
<li>nouns and adjectives mark number, then case</li>
<li>names and pronouns mark person, then number, then case</li>
<li>conjunctions between nouns mark case</li>
</ul>
<p>Persons are:</p>
<ul class="simple">
<li>first</li>
<li>second</li>
<li>proximate</li>
<li>obviative</li>
</ul>
<p>The obviative is used to mark a distinct third person from the proximate, which is the default, except in certain sentences.</p>
<p>Numbers are:</p>
<ul class="simple">
<li>singular</li>
<li>dual</li>
<li>plural</li>
</ul>
<p>The plural number is used for mass nouns and some abstract concepts.</p>
<p>Aspects are:</p>
<ul class="simple">
<li>imperfective: sets up the verb as a background action</li>
<li>perfective: sets up the verb as an event, possibly in the context of a background action</li>
<li>inchoative: indicates that the verb is beginning</li>
<li>cessative: indicates that the verb is ending</li>
</ul>
<p>The latter two can be used to distinguish meaning where some languages would use different verbs.</p>
<p>So far, there have been two basic sentence structures.</p>
<p>A typical sentence starts with a verb, and follows it with noun phrases with an associated case, which generally go in order:</p>
<ul class="simple">
<li>nominative</li>
<li>accusative</li>
<li>dative</li>
<li>intrative, comparative, privative, adessive, instrumental (these have never appeared in a sentence together)</li>
<li>inessive</li>
</ul>
<p>There is also a genitive case, which doesn't appear on its own at the noun phrase level, but does appear within certain constructions.</p>
<p>There was also, until about five minutes ago as I write this, a "reflexive" case in the lexicon.
It functioned as a combination of nominative and accusative.</p>
<p>Looking over this, I'm probably going to get rid of the privative case.
I think it can be replaced with something like "[ala (adj)].number.genitive [thing].number.genitive'[wan (adj)]".</p>
<p>Anyway, the other major sentence structure just puts the accusative noun phrase before the verb, and makes the nominative noun phrase optional; it's sort of a passive construction.</p>
<p>Notes on specific cases:</p>
<ul class="simple">
<li>Dative can often mean "for", as in a benefactive, or possibly a causative. It also signifies the indirect object. And, in some contexts, the destination. ... I just realized I used it wrong for all sentences with [pana (v)]. Aw, they're now less bonkers. Although, I did have to introduce a nonce indirect object into one, for reasons.</li>
<li>Inessive is used with time periods to indicate tense, purely lexically.</li>
<li>The comparative is used a lot to translate adverbs modifying verbs. It's possible that I'll change out the "like a fast thing" constructions with stuff like "like a cheetah". Taking about the manner of a verb with nouns rather than adjectives.</li>
</ul>
<p>The genitive case is used to form possessives, superlatives, and comitatives, and can probably do other things.</p>
<p>To use the genitive:</p>
<ul>
<li><p class="first">Start with a noun phrase in genitive case.</p>
</li>
<li><p class="first">Move the head from the beginning to the end.</p>
</li>
<li><p class="first">Convert the end of the head to a contraction.</p>
</li>
<li><p class="first">Suffix it with an adjective that agrees with the noun before the genitive phrase.</p>
<blockquote>
<ul class="simple">
<li>If the adjective is [jo (adj)], then this expresses that the referent of the modified noun phrase is <em>owned by</em> the referent of the genitive phrase.</li>
<li>If the adjective is [wan (adj)], then this expresses that the referent of the modified noun phrase is <em>accompanied by</em> the referent of the genitive phrase.</li>
<li>For most other adjectives thus far, the referent of the modified noun phrase is <em>exemplary within the context of</em> the genitive phrase, in terms of the adjective.</li>
</ul>
</blockquote>
</li>
</ul>
<p>Adjectives normally follow the noun they modify.
I currently have determiners under the "adjective" umbrella.</p>
<p>It's possible for a sentence to have multiple verbs, and the mechanics of this were deliberately chosen to confuse:</p>
<p>There is no infinitive form.
Each verb has a subject.
The subjects MAY be equivalent noun phrases.
If they are, the subjects after the first (... I think) can be omitted.
If they are not, the verbs after the first agree with the first verb, and <em>not</em> their subject, in terms of person and number.
The verbs are not required to agree in terms of aspect, because trying aspect agreement took it from "pretty confusing" to "way too confusing".</p>
<p>Usually, the first verb has a special meaning when used like this:</p>
<ul class="simple">
<li>[sin (v)] again</li>
<li>[tu (v)] twice</li>
<li>[mute (v)] often, usually</li>
<li>[wile (v)] want, hope, should</li>
<li>[o (v)] imperative</li>
<li>[jo (v)] to have something as a result of</li>
<li>[sama (v)] probably</li>
<li>[ken (v)] can</li>
<li>[toki (v)] converts the rest of the sentence to a yes or no question</li>
</ul>
<p>When I combined multiple verbs with the passive form, I concluded that the first verb has to include a nonce indirect object, if it doesn't already have a direct object or later case.</p>
<p>So far as verbs of motion, the language is mostly "verb-framed", and encodes the manner of motion using the instrumental case.</p>
<p>There is no specific equivalent of "to be".
So far, I've used [lon (v)] to talk about location, and [sama (v)] to talk about appearance.</p>
<p>I haven't explored this in the example sentences, but I want the "prestige dialect" to favor "name-like" noun phrases over pronouns.
Basically, the way this would work is that there are certain "name-like" nouns that encode person in addition to number and case, and these would be used both to conclude each part of a name, but to construct "name-like" versions of phrases along the lines of "humble servant" or "most merciful".</p>
<p>One thing that I haven't really thought about hard with these sort-of glosses I'm doing is the "indefinite deteminer", [sin (adj)], the equivalent of "a(n)".
It exists to introduce new ideas, and there's no definite counterpart; things are assumed definite by default.</p>
<p>I think that's everything I've worked out so far.</p>
<p>I think what I want to do is take a break, then come back to this and try to use <a class="reference external" href="https://www.amazon.com/Describing-Morphosyntax-Guide-Field-Linguists-ebook/dp/B01LWYY885/">Describing Morphosyntax</a> on it.</p>
<hr class="docutils" />
<p>Next time, I wrap this up for now.</p>
The Software Quality Study I Want To See, Which May Already Exist2018-07-21T04:00:00-04:002018-07-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-21:/the-software-quality-study-i-want-to-see-which-may-already-exist<p class="first last">I slightly question my definition of "breezy", but this was a quick write, which may be obvious.</p>
<p>In this post:</p>
<ul class="simple">
<li>Anecdotes about software metrics gone wrong.</li>
<li>Software quality studies should embrace subjective measures, and for all I know, they already have.</li>
</ul>
<hr class="docutils" />
<p>Okay, this is going to be an especially quick and breezy post even by this blog's standards, because I had a really exhausting week, and I need to ease off on myself to avoid schedule slip.</p>
<p>In my tinkering with Structured Data, I hooked the repository up to some code quality measuring services, and started optimizing.
(Granted, some of those scores went up because I looked at the issues they brought up, and went "it's fine" to varying degrees of "would persuade another human". From "those variables are too defined, what's wrong with you" on one end to "anyone who owns themselves with this line of code deserves it" at the other.)</p>
<p>Anyway, rewriting my code to deal with these metrics reminded me of a quote or statement that I can't track down, saying that explicitly trying to optimize for particular metrics runs the risk of decoupling the metrics from whatever they're supposed to be a proxy for.</p>
<p>I've heard stories of companies trying to measure progress in terms of lines of code, which is a pretty bad idea.
But there are other measures that can go awry.
I remember back in college, I used pylint on some of my code, had it notice some pretty bad code, and promptly rewrote the code in a dynamic enough fashion to defeat static analysis.
That's... not how you're supposed to get rid of code smells.</p>
<p>Cyclomatic complexity is too high?
Rewrite the function as a bunch of smaller functions!</p>
<p>Statement count is too high?
Use method chaining to cram more computation into a single logical line!</p>
<p>Pylint complains about too few public methods?
Do <em>anything at all</em> besides disable the check globally.</p>
<p>What I'm getting at is, it's certainly possible to reason about connections between topological measures and system brittleness, but the real measure of a metric's worth is what the code looks like if you optimize it.
I'm actually not sure I'm against how my code ended up after I started trying to force the complexity down, but it definitely went in some surprising directions.</p>
<p>I could imagine a study in which developers with varying levels of experience are instructed to optimize a small but useful codebase of some kind according to some metric or other.
The results could then be rated by some subjective measures, and this would then produce a distribution for each metric.
From that, it would be possible to say, which metrics impose a ceiling on quality, and what kind of floor on quality does each metric have?</p>
<p>It might sound weird to focus on subjective measures, but it's harder to maintain code you don't like looking at, so subjective appraisals of the code are actually an extremely important measure.
The code could also be run through benchmarking, but my intuition is that most metrics are only slightly correlated with characteristics that affect performance.
I'm not so sure that stuff like defect rates is a useful measure.
I mean, in any compiled language, including Python, you'd much rather inspect the source than the compiled code, but they have in some sense identical defects reported against them.
Since defects are all but inevitable, it's much more important that the code empower the maintenance programmer.</p>
<p>I don't have the resources to pull something like this off.
Someone please run a study using these ideas, thanks in advance.</p>
Conlanging - Inventory 2018-07-202018-07-20T04:00:00-04:002018-07-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-20:/conlanging-inventory-2018-07-20<p class="first last">Ugh, I needed that break. Anyway, here's half of part of a lexicon.</p>
<p>In this post:</p>
<ul class="simple">
<li>What words I came up with.</li>
</ul>
<hr class="docutils" />
<p>I've been grabbing fragmented bits of Toki Pona to convert into placeholders for my lexicon.
Let's see what I've collected.</p>
<p>(I'll be honest, I forget what I meant when I wrote up last post's "next time", and the post itself isn't helping.)</p>
<ul class="simple">
<li>[ale (adj)] all</li>
<li>[ale (n)] "everywhere"</li>
<li>[ale (v)] to live</li>
<li>[ale ala (adj)] some</li>
<li>[anpa (v)] to travel down/below</li>
<li>[ante (n)] "the other side"</li>
<li>[awen (n)] visit</li>
<li>[awen (v)] to wait/stay/visit/sit</li>
<li>[en (conj)] and, between noun phrases</li>
<li>[ike (adj)] Used for "too", could mean "to any unacceptable degree", more generally means "bad" or "complicated", really needs more specific glosses</li>
<li>[ilo pi wawa ala (n)] "slow thing"</li>
<li>[ilo pona (n)] good thing</li>
<li>[ilo suno (n)] a bright thing (may be derive from [suno (adj)])</li>
<li>[ilo wawa ala (n)] a slow thing, AND a quiet thing, which feels off.</li>
<li>[jan (n)] person</li>
<li>[jan lili (n)] baby/child</li>
<li>[jan sama (n)] sibling/cousin?</li>
<li>[jan tawa (n)] camper, traveler</li>
<li>[jo (adj)] owned by</li>
<li>[jo (v)] to have</li>
<li>[jump (n)] jump. Toki Pona is hard sometimes.</li>
<li>[kama (n)] the future</li>
<li>[kama lili (n)] the near future, 'soon'</li>
<li>[kama suli (v)] to grow (could probably have just glossed it suli, but also it doesn't matter)</li>
<li>[kasi (n)] plants (flowers)</li>
<li>[ken (v)] to be able to</li>
<li>[kiwen jan (n)] ... doll</li>
<li>[kon telo (n)] mist/cloud</li>
<li>[lape (v)] to sleep</li>
<li>[lili (adj)] little</li>
<li>[lon (n)] here</li>
<li>[lon (v)] to stand, to be located</li>
<li>[lukin (v)] to look</li>
<li>[lupa (n)] door</li>
<li>[ma tomo lili (n)] village</li>
<li>[mama (n)] parent</li>
<li>[meli lili (n)] girl</li>
<li>[mije lili (n)] boy</li>
<li>[moku (v)] to eat</li>
<li>[moku telo (v)] to drink</li>
<li>[musi (v)] to play</li>
<li>[mute (adj)] many/very</li>
<li>[mute (v)] to do often</li>
<li>[ni (adj)] this</li>
<li>[o (v)] a verb of command</li>
<li>[pali (v)] to work</li>
<li>[pana (v)] to give</li>
<li>[pilin pona (adj)] happy</li>
<li>[pilin pona (n)] happiness</li>
<li>[pimeja (n)] blackness</li>
<li>[pini (n)] the past</li>
<li>[poki (n)] glass (okay, container)</li>
<li>[pona (adj)] good ("lovely") This one needs more work for sure</li>
<li>[pona mute (adj)] very good/wonderful</li>
<li>[pronoun] This is standing in for a more complicated idea that needs concultural support, but the grammatic behavior is presumed identical</li>
<li>[run (n)] run</li>
<li>[sama (v)] to be likely to, to seem/appear</li>
<li>[seli (n)] fire</li>
<li>[sewi (v)] to travel above/up</li>
<li>[sike (n)] around. In context, it's translating "around". This may change.</li>
<li>[sike (n)] ball. I am entirely aware this is on the list twice</li>
<li>[sike (v)] to roll; this seems like the verb so far most likely to involve something like ergativity, so I probably don't fully have a handle on it. In fact, I just changed it so the relevant example sentence is in the passive form, and the destination is therefore dative instead of accusative.</li>
<li>[sin (adj)] a</li>
<li>[sin (v)] to do again</li>
<li>[sitelen (v)] to write</li>
<li>[sona (n)] knowledge</li>
<li>[soweli (adj)] wild</li>
<li>[soweli (n)] animal, including dog, cat</li>
<li>[soweli lili (n)] kitten/puppy</li>
<li>[suli (adj)] old/large/big</li>
<li>[suno (adj)] bright</li>
<li>[suno (n)] the sun</li>
<li>[suno (v)] to shine</li>
<li>[supa (n)] table</li>
<li>[tawa (v)] to travel</li>
<li>[tawa musi (v)] dance</li>
<li>[telo (n)] water</li>
<li>[telo sewi (n)] rain</li>
<li>[telo tawa (n)] river</li>
<li>[tenpo kama (n)] a specific part of the future</li>
<li>[tenpo ni (n)] now</li>
<li>[tenpo suno kama (n)] tomorrow</li>
<li>[tenpo suno pini (n)] yesterday</li>
<li>[toki (v)] to say, can be used to form yes-or-no questions</li>
<li>[toki wawa (v)] to shout</li>
<li>[tomo sona (n)] school</li>
<li>[tomo suli (n)] "palace"</li>
<li>[tu (adj)] two</li>
<li>[tu (v)] to do twice (this must derive from the numerals somehow; probably the lower numbers have some "irregular" formulation, also shared by select higher numbers, like 40 or 108)</li>
<li>[walk (n)] walk</li>
<li>[wan (adj)] together</li>
<li>[wan (n)] together</li>
<li>[wan (v)] to be united/together/whole (in theory there should be a word for "once" that currently would gloss the same)</li>
<li>[weka (n)] some other place, "away"</li>
<li>[wile (v)] to want, to hope, should, this is probably overloaded</li>
</ul>
<p>Ninety something words.
That's certainly something.
My hope is that I can turn that big list there into some smaller lists of words that should be related.</p>
<hr class="docutils" />
<p>Next time, I discuss the grammar.</p>
<hr class="docutils" />
<p>July 18</p>
<p>So, before I do the sentences, I want to take the person marking off all of the nouns, and collapse the "pronoun" placeholders into one.
I also want to avoid using "kama" as a verb of motion.
Instead use "tawa" more as "to journey".</p>
<dl class="docutils">
<dt>Lovely flowers are growing everywhere.</dt>
<dd>[kama suli (v)].proximate.plural.imperfective [kasi (n)].plural.nominative [pona (adj)].plural.nominative [ale (n)].plural.inessive</dd>
<dt>We should eat more slowly.</dt>
<dd>[wile (v)].first.plural.imperfective [moku (v)].first.plural.imperfective [pronoun].first.plural.nominative [ilo pi wawa ala (n)].plural.comparative [mute (adj)].plural.comparative</dd>
<dt>You have come too soon.</dt>
<dd>[tawa (v)].second.singular.cessative [pronoun].second.singular.nominative [kama lili (n)].plural.inessive [ike (adj)].plural.inessive</dd>
<dt>You must write more neatly.</dt>
<dd>[wile (v)].second.singular.imperfective [sitelen (v)].second.singular.imperfective [pronoun].second.singular.nominative [ilo pona (n)].plural.comparative</dd>
<dt>Directly opposite stands a wonderful palace.</dt>
<dd>[lon (v)].proximate.singular.imperfective [tomo suli (n)].singular.nominative [pona mute (adj)].singular.nominative [sin (adj)].singular.nominative [ante (n)].singular.inessive [mute (adj)].singular.inessive</dd>
<dt>Henry's dog is lost.</dt>
<dd>[tawa (v)].proximate.singular.imperfective [soweli (n)].singular.nominative [jan Enwi (name)].obviative.singular.genitive'[jo (adj)].singular.nominative [sona (n)].plural.privative</dd>
</dl>
<p>I don't know if I'll actually go with privative case, but I like it for now.
Another way would be to represent "lose" as the cessative of "have". "To lose one's way"</p>
<dl class="docutils">
<dt>My cat is black.</dt>
<dd>[sama (v)].proximate.singular.imperfective [soweli (n)].singular.nominative [pronoun].first.singular.genitive'[jo (adj)].singular.nominative [pimeja (n)].plural.accusative</dd>
<dt>The little girl's doll is broken.</dt>
<dd>[wan (v)].proximate.singular.cessative [kiwen jan (n)].singular.nominative [lili (adj)].singular.genitive [meli lili (n)].singular.genitive'[jo (adj)].singular.nominative</dd>
</dl>
<p>The head of a phrase in genitive moves to the end.</p>
<dl class="docutils">
<dt>I usually sleep soundly.</dt>
<dd>[mute (v)].first.singular.imperfective [lape (v)].first.singular.imperfective [pronoun].first.singular.nominative [ilo wawa ala (n)].plural.comparative</dd>
</dl>
<p>I'm using the same gloss for "quiet" and "slow".
I need to decide what to do about that.
(Also "cat" and "dog", but whatever.)</p>
<dl class="docutils">
<dt>The children ran after Jack.</dt>
<dd>[tawa (v)].proximate.plural.imperfective [jan lili (n)].plural.nominative [jan Sa (name)].obviative.singular.accusative [run (n)].plural.instrumental [pini (n)].plural.inessive</dd>
</dl>
<p>July 19</p>
<dl class="docutils">
<dt>I can play after school.</dt>
<dd>[ken (v)].first.singular.inchoative [musi (v)].first.singular.inchoative [pronoun].first.singular.nominative [tenpo kama (n)].singular.inessive [tomo sona (n)].singular.genitive'[jo (adj)].singular.inessive</dd>
<dt>We went to the village for a visit.</dt>
<dd>[tawa (v)].first.plural.perfective [pronoun].first.plural.nominative [ma tomo lili (n)].singular.accusative [awen (n)].singular.dative ([sin (adj)].singular.dative) [pini (n)].plural.inessive</dd>
</dl>
<p>Dative for benefactive</p>
<dl class="docutils">
<dt>We arrived at the river.</dt>
<dd>[tawa (v)].first.plural.cessative [pronoun].first.plural.nominative [telo tawa (n)].singular.accusative [pini (n)].plural.inessive</dd>
<dt>I have been waiting for you.</dt>
<dd>[awen (v)].first.singular.perfective [pronoun].first.singular.nominative [pronoun].second.singular.accusative</dd>
</dl>
<p>I'm confused.</p>
<dl class="docutils">
<dt>The campers sat around the fire.</dt>
<dd>[awen (v)].proximate.plural.perfective [jan tawa (n)].plural.nominative [pini (n)].plural.inessive. [lon (v)].obviative.singular.perfective [seli (n)].singular.nominative [pronoun].proximate.plural.inessive</dd>
</dl>
<p>I figured "traveler" and "camper" were close enough.</p>
<dl class="docutils">
<dt>A little girl with a kitten sat near me.</dt>
<dd>[awen (v)].proximate.singular.perfective [meli lili (n)].singular.nominative [lili (adj)].singular.nominative [sin (adj)].singular.nominative [soweli lili (n)].singular.genitive'[wan (adj)].singular.nominative [pronoun].first.singular.adessive [pini (n)].plural.inessive</dd>
</dl>
<p>I've decided that genitive can glom onto other adjectives, like "together"</p>
<dl class="docutils">
<dt>The child waited at the door for her father.</dt>
<dd>[awen (v)].proximate.singular.perfective [jan lili (n)].singular.nominative [mama (n)].singular.accusative [pronoun].proximate.singular.genitive'[jo (adj)].singular.accusative [lupa (n)].singular.adessive [pini (n)].plural.inessive</dd>
<dt>Yesterday the oldest girl in the village lost her kitten.</dt>
<dd>[jo (v)].proximate.singular.cessative [meli lili (n)].singular.nominative [ma tomo lili (n)].singular.genitive'[suli (adj)].singular.nominative (oldest) [soweli lili (n)].singular.accusative [pronoun].proximate.singular.genitive'[jo (adj)].singular.accusative [tenpo suno pini (n)].singular.inessive</dd>
</dl>
<p>I don't know if I want to do it like this.
Basically, for adjectives that can be used normally, I guess the genitive sets up a superlative, with the genitive noun describing the set with respect to which the described noun is superlative, and the adjective the way in which it is superlative.</p>
<dl class="docutils">
<dt>Were you born in this village?</dt>
<dd>[toki (v)].second.singular.inchoative [ale (v)].second.singular.inchoative [pronoun].second.singular.nominative [ma tomo lili (n)].singular.inessive [ni (adj)].singular.inessive</dd>
<dt>Can your brother dance well?</dt>
<dd>[toki (v)].second.singular.inchoative [ken (v)].second.singular.perfective [tawa musi (v)].second.singular.perfective [jan sama (n)].singular.nominative [pronoun].second.singular.genitive'[jo (adj)].singular.nominative [ilo pona (n)].plural.comparative</dd>
</dl>
Late Post 2018-07-202018-07-20T03:59:00-04:002018-07-20T03:59:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-20:/late-post-2018-07-20<p class="first last">So sore and tired.</p>
<p>I'll level: I feel utterly awful right now, and the prospect of forcing my way through writing up a post in the next hour fills me with dread.</p>
<p>So I won't.</p>
<p>I'll half-ass the translation exercises for now, and in the morning, ass them the rest of the way, write up the status, and draw 30 lines.</p>
Draw a Box 2018-07-192018-07-19T04:00:00-04:002018-07-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-19:/draw-a-box-2018-07-19<p class="first last">It can't go on forever. I think.</p>
<p>In this post:</p>
<ul class="simple">
<li>I keep extremely careful track of when midnight was, for some reason.</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>15 lines on July 12.</li>
<li>15 lines on July 13.</li>
<li>15 lines just after midnight on July 15.</li>
<li>15 lines just <em>before</em> midnight on July 15.</li>
<li>15 lines on July 16.</li>
<li>15 lines on July 17.</li>
<li>15 lines on July 18.</li>
</ul>
<p>For a total of 105 lines this week,
390 lines on the first sheet since I started counting,
and 765 lines on the second sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Conlanging - Planning 2018-07-182018-07-18T04:00:00-04:002018-07-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-18:/conlanging-planning-2018-07-18<p class="first last">More daily activities!</p>
<p>In this post:</p>
<ul class="simple">
<li>What I'm going to do in each post this week.</li>
<li>General ideas for the two central posts this week.</li>
</ul>
<hr class="docutils" />
<p>So, for this week, I had the idea that I'd do things kind of like how it is now in Draw a Box, with daily goals that don't explicitly build on each other.
Since it's a weekly project, I can just dump in the current status of things each entry.</p>
<p>I don't know what I'll feel comfortable doing by the end of this week, but I want to try to approach this language from a perspective of successive refinement.
Like, right now, I'm seeing what I have in terms of building blocks for the grammar, and I can note stuff like, oh, these bound morphemes should interact in such and such a way.</p>
<p>Basically, the big artifact I want to have at the end of this is some kind of list of all of the grammatical concepts I pulled in to make things work, like the inessive case.</p>
<p>I also want to put together a rough sketch of the sounds that might be involved, and an explanation for the morphemes in terms of a hypothetical proto-language.
I want the latter because I already have some idea of how this went from isolating to agglutinative to fusional.
(Perhaps I could propagate structure through multiple layers of ancestry, then start working on sounds and bringing them forward.)</p>
<hr class="docutils" />
<p>Next time, I start writing up the assumptions I've made.</p>
<p>(By the way, I'm still hacking on Structured Data. It's at a point now where it would probably be interesting if I tried to use it...)</p>
<hr class="docutils" />
<p>July 16</p>
<dl class="docutils">
<dt>Many of the people shouted twice.</dt>
<dd>[tu (v)].proximate.plural.perfective [toki wawa (v)].proximate.plural.perfective [jan (n)].proximate.plural.nominative [mute (adj)].plural.nominative [pini (n)].obviative.plural.inessive</dd>
<dt>Happy people often shout.</dt>
<dd>[mute (v)].proximate.plural.imperfective [toki wawa (v)].proximate.plural.imperfective [jan (n)].proximate.plural.nominative [pilin pona (adj)].plural.nominative</dd>
<dt>The kitten jumped up.</dt>
<dd>[sewi (v)].proximate.singular.perfective [soweli lili (n)].proximate.singular.nominative [jump (n)].obviative.singular.instrumental [pini (n)].obviative.plural.inessive</dd>
</dl>
<p>I didn't feel like glossing "jump" in Toki Pona</p>
<dl class="docutils">
<dt>The kitten jumped onto the table.</dt>
<dd>[tawa (v)].proximate.singular.perfective [soweli lili (n)].proximate.singular.nominative [supa (n)].obviative.singular.accusative [jump (n)].obviative.singular.instrumental [pini (n)].obviative.plural.inessive</dd>
<dt>My little kitten walked away.</dt>
<dd>[tawa (v)].proximate.singular.perfective [soweli lili (n)].proximate.singular.nominative [lili (adj)].singular.nominative [mi (n)].first.singular.genitive'[jo (adj)].singular.accusative [weka (n)].obviative.plural.accusative [walk (n)].obviative.plural.instrumental [pini (n)].obviative.plural.inessive</dd>
<dt>The rain came down.</dt>
<dd>[anpa (v)].proximate.plural.perfective [telo sewi (n)].proximate.plural.nominative</dd>
<dt>The kitten is playing in the rain.</dt>
<dd>[musi (v)].proximate.singular.imperfective [soweli lili (n)].proximate.singular.nominative [telo sewi (n)].obviative.plural.intrative</dd>
<dt>The rain has stopped.</dt>
<dd>[mi (n)].first.singular.accusative [pana (v)].obviative.plural.cessative [telo sewi (n)].proximate.plural.dative</dd>
<dt>Soon the rain will stop.</dt>
<dd>[mi (n)].first.singular.accusative [pana (v)].obviative.plural.cessative [telo sewi (n)].proximate.plural.dative [kama lili (n)].obviative.plural.inessive</dd>
<dt>I hope the rain stops soon.</dt>
<dd>[wile (v)].first.singular.imperfective [mi (n)].first.singular.reflexive [pana (v)].first.singular.cessative [telo sewi (n)].proximate.plural.dative [kama lili (n)].obviative.plural.inessive</dd>
</dl>
<p>Conclusion: verbs don't agree with aspect. The aspect mark does come at the end, and it should interact somehow with the person/plural suffix.</p>
<p>July 17</p>
<dl class="docutils">
<dt>Once wild animals lived here.</dt>
<dd>[ale (v)].proximate.plural.perfective [soweli (n)].proximate.plural.nominative [soweli (adj)].plural.nominative [lon (n)].obviative.singular.inessive [en (conj)].inessive [pini (n)].obviative.plural.inessive</dd>
<dt>Slowly she looked around.</dt>
<dd>[lukin (v)].proximate.singular.perfective [ona (n)].proximate.singular.nominative [sike (n)].obviative.plural.accusative [ilo wawa ala (n)].obviative.plural.comparative</dd>
<dt>Go away!</dt>
<dd>[o (v)].second.singular.imperfective [sina (n)].second.singular.nominative [tawa (v)].second.singular.inchoative [weka (n)].obviative.plural.accusative</dd>
<dt>Let's go!</dt>
<dd>[o (v)].first.plural.imperfective [mi (n)].first.plural.nominative [tawa (v)].first.plural.inchoative</dd>
</dl>
<p>Could also use dual instead of plural.</p>
<dl class="docutils">
<dt>You should go.</dt>
<dd>[wile (v)].second.singular.imperfective [sina (n)].second.singular.nominative [tawa (v)].second.singular.inchoative</dd>
<dt>I will be happy to go.</dt>
<dd>[jo (v)].first.singular.inchoative [mi (n)].first.singular.nominative [pilin pona (n)].proximate.plural.accusative [kama (n)].obviative.plural.inessive [tawa (v)].first.singular.inchoative</dd>
</dl>
<p>I've decided here that in this language you "have happiness", which makes you a "happy person".
I guess I'm trying to see what it'll take to decide I want a copula.</p>
<dl class="docutils">
<dt>He will arrive soon.</dt>
<dd>[kama (v)].proximate.singular.cessative [ona (n)].proximate.singular.nominative [kama lili (n)].obviative.plural.inessive</dd>
<dt>The baby's ball has rolled away.</dt>
<dd>[sike (v)].proximate.singular.perfective [sike (n)].proximate.singular.nominative [jan lili (n)].obviative.singular.genitive'[jo (adj)].singular.nominative [weka (n)].obviative.plural.accusative</dd>
</dl>
<p>Two things occur to me here.
One is that I'm not sure if all of the stuff I've done so far is how proximate/obviative actually works.
The other is that I'll have to think more about this, because the verb "to roll" can easily involve ergativity, and I haven't really accounted for that.</p>
<dl class="docutils">
<dt>The two boys are working together.</dt>
<dd>[pali (v)].proximate.dual.imperfective [mije lili (n)].proximate.dual.nominative [tu (adj)].plural.nominative [wan (n)].obviative.plural.comparative</dd>
</dl>
<p>I used dual!
*toot*</p>
<dl class="docutils">
<dt>This mist will probably clear away.</dt>
<dd>[mi (n)].first.singular.accusative [sama (v)].obviative.plural.imperfective [pana (v)].obviative.plural.cessative [kon telo (n)].proximate.plural.dative [ni (adj)].plural.dative [kama (n)].obviative.plural.inessive</dd>
</dl>
<p>"To me it is likely that 'it' will cease to give this mist."</p>
Weekly Roundup 2018-07-172018-07-17T04:00:00-04:002018-07-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-17:/weekly-roundup-2018-07-17<p class="first last">I feel a little better about this week than I did yesterday, but I still want to actually finish the first stage of Homunculus.</p>
<ul class="simple">
<li>Main project: I wanted to work on Homunculus, and I drew up a plan, but I ended up getting distracted by Structured Data. On the plus side, since yesterday's post, I've gotten Structured Data close enough to 1.0 that I'm okay using it in my own stuff. Amazingly, sketching out functional data structures with no obvious practical application in Python code had identifiable benefits! (I figured out a good way to extract values from a match.)</li>
<li>Draw a Box: ... It's going.</li>
<li>Free-Topic: I tried conlanging using glosses written in not-exactly-Toki-Pona, rather than English or attempting to come up with words off the bat. It was a nice change of pace. So nice, in fact, that...</li>
</ul>
<p>Next week, I work on extending the unnamed conlang I started on last weekend.</p>
Homunculus - Retrospective 2018-07-162018-07-16T04:00:00-04:002018-07-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-16:/homunculus-retrospective-2018-07-16<p class="first last">I keep on finding new-feeling failure modes.</p>
<p>In this post:</p>
<ul class="simple">
<li>This was a frustrating yak shave, because I hadn't specified beforehand what was "shaved enough".</li>
</ul>
<hr class="docutils" />
<p>This week, I came up with some good plans that I can come back to later, but I only got so far on them by now.
I think what slowed me down was, I decided I needed Structured Data to proceed with Homunculus, but I didn't lay out what features Homunculus needed from Structured Data, specifically, so I kind of ended up spinning my wheels a bit, polishing Structured Data at random.</p>
<p>In the end, some of the particulars of Structured Data are much improved, but it can't get into a 1.0-worthy state until I actually attempt to use it in my projects, like Homunculus or tiny_music.
I wouldn't exactly recommend using it to anyone else right now, but if anyone wants to work with me on this, and doesn't mind code that <em>will</em> change its interface, check out the <a class="reference external" href="https://github.com/mwchase/python-structured-data">project page</a>.</p>
<p>Homunculus needs Structured Data, and Structured Data needs some kind of checklist to get to 1.0.
For now, I'll just note the need.</p>
<p>I think what I need to do going forward, is figure out exactly what Structured Data needs to get to 1.0, then figure out a complementary project to pair it with, like last week's blog publisher + syntax file.</p>
<p>I really liked having two somewhat unrelated projects I could switch between based on priority and blockage.
It felt a lot better than trying to work on one project so I could get another working. ... Which is why I have a different plan for next week.
I'll show it off in a few days, but it's different, for sure.</p>
<hr class="docutils" />
<p>Next week, let's dive into conlanging.</p>
Homunculus - 2018-07-132018-07-15T04:00:00-04:002018-07-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-15:/homunculus-2018-07-15<p class="first last">... Geez.</p>
<p>In this post:</p>
<ul class="simple">
<li>I don't think there's much exciting to write about.</li>
<li>But I tried.</li>
<li>I made some improvements to Structured Data.</li>
<li>But it can be better.</li>
<li>And maybe it just needs me to try to actually use it.</li>
</ul>
<hr class="docutils" />
<p>So, I spent all day noodling around with Structured Data.
I think I have to just try to use it now, and start opening bugs against myself.
But it turns out that sometimes, stuff that's satisfying to code, doesn't provide a good angle for writing about.
I mean I can try.</p>
<p>My basic goal with the changes I was making was to break the single big module I had everything in before, into several smaller modules with a tighter focus in each.
One thing that happened as a result of this goal was that I created a bunch of internal modules, some of them quite small, to implement functionality that didn't convincingly belong to one public module or the other.
I think separating the modules helped the code, because it made it more obvious which helper code applied to which publicly visible code, and reduced the clutter in the modules.</p>
<p>I think one thing that would improve things further is, each module, even the internal ones, has a value for <tt class="docutils literal">__all__</tt> that has the notional interface of the module.
I should make sure that everything in those <tt class="docutils literal">__all__</tt> lists is documented, so it's clear what the exported functions and such are for.</p>
<p>Let's see about getting these issues in, so I don't forget about them, on account of it's almost midnight now.</p>
<hr class="docutils" />
<p>Next time, I wrap this week up.</p>
Conlanging With Toki Pona2018-07-14T04:00:00-04:002018-07-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-14:/conlanging-with-toki-pona<p class="first last">Avoiding boiling the ocean</p>
<p>In this post:</p>
<ul class="simple">
<li>I've been looking into Toki Pona</li>
<li>It might offer me a way to do conlanging without getting bogged down in words and phonology right away.</li>
<li>How it should probably be handled...</li>
<li>Heck, let's try it out.</li>
</ul>
<hr class="docutils" />
<p>Over the past week or so, I went over some <a class="reference external" href="http://tokipona.org/">Toki Pona</a> tutorials.
From looking over several sources, it kind of seems like people using Toki Pona just have to decide what makes sense, in that there's community drift, changes from Sonja Lang, reform proposals, and people accidentally(?) codifying their own weird quirks in reference documents.</p>
<p>All that said, it occurs to me that Toki Pona could be an interesting tool for conlanging.
Suppose there's some linguistic feature you want to try using in a conlang, and you're like me, and don't have anything fleshed out enough to use as a base.
If I'm going to make up a language from scratch, I'm going to reach for a word list and a sentence list, and build things up until I can try to incorporate whatever feature I was making it for in the first place.</p>
<p>But it looks to me like Toki Pona could function as a sufficiently fleshed-out base, to apply changes to.
Just define the feature in question, figure out ways in which Toki Pona does not exhibit it, and what changes would be needed to get it.</p>
<p>I haven't gotten too far with trying this out, because I was doing stuff like obsessively refreshing ReadTheDocs to see when they'll roll out Python 3.7 support.</p>
<p>Anyway, ideas for features to try out, and details of how to notate the attempts...</p>
<ul class="simple">
<li>I'd want some kind of bracketing to represent "transformed words" from Toki Pona. Like [], maybe. Part of speech in parentheses inside the brackets, for clarity.</li>
<li>Affix bound morphemes to the root. Like maybe, now verbs are prefixed with number and suffixed with aspect, like paucal.[kama (v)].perfective, for "a few have come" (with the caveat that English doesn't express aspect well)</li>
<li>Generally try to hold off on redoing sentence structure until there's more marking architecture built up, to indicate what the re-done structure is supposed to indicate.</li>
</ul>
<p>I'm thinking when I get back to Linked Seas, I'll try to take this approach to create a proto-language, and do diachronic stuff.
I believe the requirements for getting a language like this into a state where it's usable as an ancestor language, include redoing all of the roots.
Basically, the commonly-used words in a typical language should occupy much narrower semantic fields than words in Toki Pona, so taking a language past the "syntax experimentation" stage requires interrogating the choice of semantic fields.
But fortunately, there aren't many of them, so it's feasible to kind of refactor things on the fly.</p>
<p>I'm going to throw out a bunch of features I'd like to try building a language around, and I'll do this for a weekly project some time:</p>
<ul class="simple">
<li>The equivalent of "o" is a verb.</li>
<li>There are serial verbs.</li>
<li>Typical sentences are VSO, but there's an equivalent to passivation that's in OV order.</li>
<li>Instead of prepositions, there's a case system that applies to nouns and adjectives, and relatively many cases.</li>
<li>Consonant clusters are acceptable, but are normally only present in contractions and loan-words.</li>
<li>Personal pronouns are contractions of noun phrases</li>
<li>Verbs inflect for number (single, dual, plural) and aspect. There are four aspects: perfective, imperfective, inchoative, cessative. (Thus, a single verb covers "ride", "mount", and "dismount".) The equivalent of tense is communicated through the inessive case.</li>
<li>Generally head-initial.</li>
<li>Idea had while working on the below: the equivalent of mass nouns are grammatically plural. "A glass of waters."</li>
<li>Idea had while working on the below: direction is encoded on verbs of motion/position rather than in adpositions.</li>
<li>Idea had while working on the below: there's an equivalent to indefinite articles, but not definite articles.</li>
</ul>
<p>I've got some time.
Let's see if I can put some sample sentences into that form.</p>
<dl class="docutils">
<dt>The sun shines.</dt>
<dd>[suno (v)].singular.perfective [suno (n)].singular.nominative</dd>
<dt>The sun is shining.</dt>
<dd>[suno (v)].singular.imperfective [suno (n)].singular.nominative</dd>
<dt>The sun shone.</dt>
<dd>[suno (v)].singular.perfective [suno (n)].singular.nominative [pini (n)].plural.inessive</dd>
<dt>The sun will shine.</dt>
<dd>[suno (v)].singular.perfective [suno (n)].singular.nominative [kama (n)].plural.inessive</dd>
<dt>The sun has been shining.</dt>
<dd>[suno (v)].singular.imperfective [suno (n)].singular.nominative [pini (n)].plural.inessive</dd>
<dt>The sun is shining again.</dt>
<dd>[sin (v)].singular.imperfective [suno (v)].singular.imperfective [suno (n)].singular.nominative</dd>
<dt>The sun will shine tomorrow.</dt>
<dd>[suno (v)].singular.perfective [suno (n)].singular.nominative [tenpo suno kama (n)].singular.inessive</dd>
<dt>The sun shines brightly.</dt>
<dd>[suno (v)].singular.perfective [suno (n)].singular.nominative [ilo suno (n)].plural.comparative
("The sun shines like bright things.")</dd>
<dt>The bright sun shines.</dt>
<dd>[suno (v)].singular.perfective [suno (n)].singular.nominative [suno (adj)].singular.nominative</dd>
<dt>The sun is rising now.</dt>
<dd>[sewi (v)].singular.inchoative [suno (n)].singular.nominative [tenpo ni (n)].singular.inessive</dd>
<dt>All the people shouted.</dt>
<dd>[toki wawa (v)].plural.perfective [jan (n)].plural.nominative [ale (adj)].plural.nominative [pini (n)].plural.inessive
(I believe I'm having "ale" function as a determiner here.)</dd>
<dt>Some of the people shouted.</dt>
<dd>[toki wawa (v)].plural.perfective [jan (n)].plural.nominative [ale ala (adj)].plural.nominative [pini (n)].plural.inessive</dd>
</dl>
<p>I don't know how the whole list would go over like this, but this seems promising.
I'm really liking the unfinished feeling that I got from just kind of putting some vague words together.
One thing I hadn't anticipated was that I started building up phrases in some of those, to create necessary high-level concepts, or narrow down meaning preemptively.</p>
<p>I'd like to try just one not on the sentence list before I wrap this up, because I anticipate it could give me some problems.</p>
<dl class="docutils">
<dt>I drink a glass of water.</dt>
<dd>[moku telo (v)].singular.perfective [mi (n)].singular.nominative [poki (n)].singular.accusative [telo (n)].plural.genitive'[jo (adj)].singular.accusative</dd>
</dl>
<p>The basic idea is that possessive constructions, including quantifying a mass noun, <em>require</em> contractions: the possessing noun is put in plural genetive, then the vowels are removed, and the appropriate ending is added with [jo (adj)].</p>
<p>Also, [mi (n)] is probably actually something like '[wan ni (n)], but that's an implementation detail.</p>
<p>One more:</p>
<dl class="docutils">
<dt>It's raining.</dt>
<dd>[mi (n)].singular.accusative [pana (v)].plural.imperfective [telo sewi (n)].plural.dative
"I am given rains."</dd>
</dl>
<p>I'm liking this, this is really nice.
I'll have to pick this back up later.</p>
Homunculus - Rewriting 2018-07-132018-07-13T04:00:00-04:002018-07-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-13:/homunculus-rewriting-2018-07-13<p class="first last">This one is entirely on me, oh well.</p>
<p>In this post:</p>
<ul class="simple">
<li>A list of entities created in the game.</li>
<li>A list of serializers that need to work differently.</li>
<li>A description of some prototyping.</li>
<li>Which suddenly loops back into Structured Data.</li>
</ul>
<hr class="docutils" />
<p>To start with, I focused on redoing entities.
I drew up the following list of entities defined in the code:</p>
<ul>
<li><p class="first">Fighters:</p>
<blockquote>
<ul class="simple">
<li>The player</li>
<li>orc</li>
<li>troll</li>
</ul>
</blockquote>
</li>
<li><p class="first">Items:</p>
<blockquote>
<ul>
<li><p class="first">healing potion</p>
</li>
<li><p class="first">fireball scroll</p>
</li>
<li><p class="first">confusion scroll</p>
</li>
<li><p class="first">lightning scroll</p>
</li>
<li><p class="first">equipment (pending):</p>
<blockquote>
<ul class="simple">
<li>sword</li>
<li>shield</li>
<li>dagger</li>
</ul>
</blockquote>
</li>
</ul>
</blockquote>
</li>
<li><p class="first">Stairs:</p>
<blockquote>
<ul class="simple">
<li>stairs</li>
</ul>
</blockquote>
</li>
</ul>
<p>(Wait for it...)</p>
<p>The big concern I have with this rewrite is factoring game definition stuff out of the serialized data.
For example, suppose I decided to change the color of the orcs.
(Work with me here.)
I'm currently writing the color data into the save file, which means that only <em>newly-generated</em> orcs would get the new color.</p>
<p>I wrote up the basic issues or lack thereof with each serializer, and found that the following needed to change:</p>
<ul class="simple">
<li>Fighter</li>
<li>Item</li>
<li>Entity</li>
</ul>
<p>(<em>Wait for it...</em>)</p>
<p>Because I'm too lazy to write code to reverse-engineer templates from instantiated values, I just added some failing assertions to the save and load paths, and deleted the current data.</p>
<p>Next, I wasn't really sure where in the project these "templates" should live, so I made a new file in my text editor.
Making templates for the Fighter component wasn't hard.
But then...
Then I got to work on Entity templates, and...
(There it is.)
There's an entity missing from the list above.
Three, nearly-identical entities, in fact.
Every entity with a Fighter component can convert into a "corpse" form.
The quick, easy, and relatively supported way to handle this would be to have some kind of flag on the entity that mediates access to its template.
The thing I want to do is to get Structured Data working, so I can include it in this project and use it all over the place.</p>
<p>So, I had a look at getting Structured Data to work with Python 3.7.
Getting Appveyor and Travis working was simple.
Unfortunately, it turns out you can't make ReadTheDocs build with Python 3.7 currently, so my online docs went from "Built wrong but 'passing'" to "Totally broken on RTD, but at least it's honest about it."
I can't figure out where to look for a roadmap on "building with 3.7 on RTD", so I have no idea when that'll work.
But everything else works, so I'll just press on and focus on my local copy.</p>
<p>I think I'd like to iterate on Structured Data for a bit, get something worthy of another release.
It also needs proper documentation, even if it's annoying to try to read, currently.</p>
<hr class="docutils" />
<p>Next time, stuff from Structured Data's change log, I guess.</p>
<hr class="docutils" />
<p>Note from writing this post: my reStructuredText theme, which is not interestingly different from the one in Sublime's GitHub, doesn't seem to detect italics inside parentheses.
Need to figure out what's up with that.</p>
Draw a Box 2018-07-122018-07-12T04:00:00-04:002018-07-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-12:/draw-a-box-2018-07-12<p class="first last">I should mix this up somehow, but I haven't yet.</p>
<p>In this post:</p>
<ul class="simple">
<li>I don't think I'm less than half done with this. That's nice.</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>15 lines on July 5.</li>
<li>15 lines <em>almost</em> on July 6.</li>
<li>15 lines on July 7.</li>
<li>15 lines... I marked the date on July 8, so it counts.</li>
<li>15 lines on July 9.</li>
<li>15 lines on July 10.</li>
<li>15 lines on July 11.</li>
</ul>
<p>For a total of 105 lines this week,
390 lines on the first sheet since I started counting,
and 660 lines on the second sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Homunculus - Planning 2018-07-112018-07-11T04:00:00-04:002018-07-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-11:/homunculus-planning-2018-07-11<p class="first last">Let's make a push to get through the tutorial!</p>
<p>In this post:</p>
<ul class="simple">
<li>What I need to implement to be done with the tutorial.</li>
<li>Notes on things that could be especially tricky since I went and editorialized all over the design.</li>
<li>Thoughts on things I want to do differently, and tasks that will go before getting back into the tutorial.</li>
<li>An overall plan.</li>
</ul>
<hr class="docutils" />
<p>Here's a quick overview of features from the tutorial I haven't implemented yet:</p>
<ul class="simple">
<li>Monsters granting xp</li>
<li>The player gaining xp</li>
<li>The player leveling up</li>
<li>The character screen</li>
<li>The wait button (This completes part 11)</li>
<li>Weighted random choice</li>
<li>Generating the entities in a level based on weighted random choice</li>
<li>Weights generated from the dungeon level</li>
<li>Stat rebalancing (This completes part 12)</li>
<li>Equippable items</li>
<li>The "Equipment" component, including equipping items</li>
<li>We see in the changes to <tt class="docutils literal">Entity.__init__</tt>, the cost of my hubris. In my code, there's no obvious way to get the equivalent of "if Equippable, but no Item, create Item". On the other hand, do we want empty Item components? ... Hm. I could have sworn the Item component did something more, but no, an empty Item component is entirely adequate for typical equipment.</li>
<li>Equipped items provide bonuses</li>
<li>Place equipment in the map</li>
<li>Start the player with basic equipment</li>
<li>Display equipment information in the inventory screen (This completes the tutorial)</li>
</ul>
<p>Thoughts on these goals:</p>
<ul class="simple">
<li>It seems wrong to me that the Equippable component requires the Item component to work correctly. I feel like that means it should be an extension to the Item component, instead of sort of its own thing.</li>
<li>With the adding statistics and rebalancing existing ones, I want to get away from holding stat values on the components, and turn them into references to a structure that contains the information.</li>
<li>This would push things towards defining a "base" player, and having level bonuses on the Fighter component.</li>
<li>I want to bring in Structured Data, but that's not happening without having a version of Structured Data that's worth using, so I'll be leaving some TODOs in, probably. <em>However</em>, Appveyor is ready to go now, so I can get on updating things whenever.</li>
</ul>
<p>So, here's the plan:</p>
<ul>
<li><p class="first">Write up a list of every kind of entity the game can currently create.</p>
</li>
<li><p class="first">Move the values out of the Component constructors into several Enums, which are themselves based on NamedTuples.</p>
</li>
<li><p class="first">Maybe just ignore handling serialized data correctly, and start over?</p>
</li>
<li><p class="first">Get up through the end of Part 12.</p>
</li>
<li><p class="first">Switch gears to getting Structured Data in better shape:</p>
<blockquote>
<ul class="simple">
<li>Set up travis builds inside docker</li>
<li>Just do Appveyor builds as normal</li>
<li>Update, document, remove old code, etc.</li>
</ul>
</blockquote>
</li>
<li><p class="first">Start on part 13.</p>
</li>
</ul>
<p>I don't know if I'll get all of that done inside a week, and I'm not planning to push myself to, but that's about the order I think things should go in: fix up component structures, re-do saving, do one and a half parts of the tutorial, and switch to Structured Data.</p>
<p>Getting Structured Data working could be huge, so if I don't get it done this week, I'll definitely focus on it next week.</p>
<hr class="docutils" />
<p>Next time, I document in detail all of the stuff that I want to rewrite.</p>
Weekly Roundup 2018-07-102018-07-10T04:00:00-04:002018-07-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-10:/weekly-roundup-2018-07-10<p class="first last">I have added some rainbows to this, but NOT ENOUGH rainbows.</p>
<ul class="simple">
<li>Main project: I gave myself two quality-of-life improvement projects: make the blog poster better, and make my syntax highlighting more like how I want it. Just from actually putting some time into it, I breezed through the former, and the latter turned out to be tricky.</li>
<li>Draw a Box: I swear, I'm getting a significant amount of the way through this sheet. Stuff will get interesting in... some number of weeks. I don't think I'm supposed to be taking it this slowly, but this pace works for me so far.</li>
<li>Free-Topic: I thought about trying to tone down some of my language here—not the fucking swearing, that's fine—being more humble about my work and my opinions on other people's work, and easing off on trying to always use or promote particular tools, in every context.</li>
</ul>
<p>Next week, I'm going to try to sprint on Homunculus. It's relatively close to completion, and I'd like to just get it done, so I can start messing with it.</p>
Blog Setup - Retrospective 2018-07-092018-07-09T04:00:00-04:002018-07-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-09:/blog-setup-retrospective-2018-07-09<p class="first last">Another weekly project down.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I think about this last week, all in all.</li>
<li>How well I followed the plan.</li>
<li>Reasonable near-term goals.</li>
<li>Thoughts on further-out improvements.</li>
</ul>
<hr class="docutils" />
<p>One thing I'm seeing so far, is a lack of any kind of "standard" week, when I let myself really get into this stuff.
Maybe that'll change once I have access to Python 3.7 on CI (chop chop, Appveyor; and it looks like the answer on Travis is "just use a docker image", which... does exist, I guess, so I just need to learn how to use it...)
But for now, I just have to take each week as it comes.</p>
<p>When it comes to last week in particular, I gave myself a few goals, blew most of the way through one of them, and kind of plinked away at the other.
No matter how I feel about the whole "syntax definition" question, it's undeniable that the blog publisher script is in a much better place.</p>
<p>In terms of following the plan, I ended up realizing that most of the big improvements I wanted were such low-hanging fruit that I just had to, like, decide to do them.
And so I did.
I'd had the good fortune to have several things in mind, so I was able to give myself other stuff to focus on, of a higher priority.
Maybe that's something I could do with these projects.
Come up with a few things that appeal to me, and switch off by priority.</p>
<p>Also, now that I really look at what the reST syntax does, some of these matches look weirdly restrictive?
Like what's the deal with how the raw html block is specified?
Anyway, for now, I just switched on the syntaxes as default, so I get the full force of the not-quite-bakedness.
Give me some incentive to fill these in.</p>
<p>I kind of wonder how far out coming up with new syntax files is going to go.
I kind of want to say, anything beyond what I need for Python, I'd like to open things up as some kind of community project, but I'm pretty sure I'm not in a position where that makes sense now.
I don't really have any greater ambition for these projects, I just want something that works for me.</p>
<hr class="docutils" />
<p>Next week...
mi sona ala.
mi ken sona e ijo kepeken toki pona?
Or not, I don't know.
Maybe I'll write up what the heck the Python syntax file does for a Free Topic day sometime.</p>
Blog Setup - Implementation 2018-07-082018-07-08T04:00:00-04:002018-07-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-08:/blog-setup-implementation-2018-07-08<p class="first last">How will you highlight, when you have no scope?</p>
<p>In this post:</p>
<ul class="simple">
<li>Fixes to the publisher.</li>
<li>Things about the publisher that I didn't fix.</li>
<li>What I accomplished with my custom syntax file.</li>
<li>What I've yet to accomplish.</li>
</ul>
<hr class="docutils" />
<p>Okay, I should summarize what I did before the <em>last</em> post.</p>
<ul class="simple">
<li>I put checks for error conditions all through the blog publisher script.</li>
<li>I added a <tt class="docutils literal">__main__.py</tt> file next to it, and made a dumb, probably somewhat mis-written script to invoke it from anywhere. (I judged it to be Too Much Effort right now to turn this into a pip-installable package with command-line entry points.)</li>
<li>I created a <a class="reference external" href="http://click.pocoo.org/6/">click</a> command group to act as the frontend, registered the "draft" and "publish" tasks with it, and invoked the command group from the module runner.</li>
<li>I copied some code from Stack Overflow to pop up notifications, then wrote a wrapper around that function to pop up failure notifications on error, and another to pop up success notifications when the command succeeds. (This could possibly be done more compactly-ish with decorators, but it doesn't matter right now.)</li>
</ul>
<p>There were some things that I want to do sometime, but it wasn't a big deal currently:</p>
<ul class="simple">
<li>All of the different kinds of directory manipulator are still defined in the same file, and therefore shove the associated globals inside the class definition as a form of namespacing.</li>
<li>Various aspects of the Three Dollar Quill project are still hardcoded. In the long term, I think I want to have some kind of configuration file at the top level of the blog repository, but there's no particular reason to do this right now.</li>
</ul>
<p>I also started hacking on copies of the syntax files for Python and reStructuredText.
(I can't... find the latter in my syntax picker, not from Sublime? Where did the file go?)
I made varying amounts of progress on various areas, and some observations:</p>
<ul class="simple">
<li>One thing I did was strip out Python 2 compatibility syntax; I tend not to write Python 2 on my own time, and I don't want to deal with maintaining it until after the rest of the syntax does what I want it to.</li>
<li>I managed to get more metadata and some mini-languages into comments.</li>
<li>In particular, I managed to get some forms of type annotation comment implementated; this wouldn't normally by of interest for the way I develop, but I'm mildly interested in supporting the 2-3 polyglot, and, indeed, older versions of Python 3, so I'll come back to this later and try to improve on this.</li>
<li>I managed to delegate the syntax handling for docstrings to a reStructuredText handler, which I had to modify slightly to get syntax handling on the first line of the docstring. I feel like I've gone way beyond the documented features to get this to work.</li>
</ul>
<p>For some reason, I'm testing the syntax file and the highlighting on the blog publisher script.
I guess it's just because it's there.</p>
<p>One thing I haven't looked into is assigning expression scopes to the inside of type annotation strings.</p>
<p>The big thing I haven't gotten working, and the whole reason I went down this rabbit hole in the first place, is assigning a scope to every identifier so I can highlight them.
One thing I noticed while figuring out what's needed (basically, identifiers can be divided into some that are only legal at the top level in an expression context, and everything else, which is also legal at the top level, but can also appear in the top level at the left-hand side of an assignment statement, as a class or function name, as a named parameter or argument, and as the target of an <tt class="docutils literal">as</tt> keyword.) is that, even though functions are supposed to have a particular scope when they're called, this isn't actually possible to accomplish in all circumstances.
In a multi-line expression, you can put a line break before the open parenthesis, and, near as I can tell, the syntax highlighter is powerless to handle this scenario.
This doesn't matter in most practical circumstances, and it doesn't matter for what I want to do, but it's kind of bothersome that the recommended scoping behavior seemingly cannot be guaranteed using the scoping engine.</p>
<p>Looking at how this does, I think I'll just try to preserve the existing behavior as much as possible, on the logic that it's good enough for the official syntax, and do the stuff I want on top of it.</p>
<p>That basically consists of:</p>
<ul class="simple">
<li>Defining scopes for every kind of identifier that can exist in a program, including the language-provided identifiers, and those provided by the standard library.</li>
<li>In particular, categorize all identifiers by their use of underscores, and attach the <tt class="docutils literal">punctuation.definition.variable</tt> scope to all relevant underscores.</li>
</ul>
<p>The main obstacle I have is, I feel like I need to better understand the 50+ contexts defined in the syntax file before I can figure out how to pervasively insert my proposed categorization of names.
I think I'll take a break for now, and come back to this later.</p>
<p>(One other tweak that just occurred to me is to have the docstring contexts in the reStructuredText syntax delegate inline literals back to Python.
Also, I'm not sure that this syntax has scopes for doctests.
I think it should.
Need to go over the reStructuredText syntax definition and compare it to what this syntax provides.)</p>
<hr class="docutils" />
<p>Next time, I wrap this project up.</p>
Blind Spots2018-07-07T04:00:00-04:002018-07-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-07:/blind-spots<p class="first last">I've got some.</p>
<p>In this post:</p>
<ul class="simple">
<li>I want to work on being more humble in the things I assert.</li>
<li>When do we want to test? When don't we want to?</li>
<li>divide-and-cover's repository should be in better shape than it is.</li>
</ul>
<hr class="docutils" />
<p>Something I've been thinking about some is how I've been presenting refactoring and commentary on code on this blog.
I feel like it's been too easy for me to get into a mode where I'm negative about other people's hard work that, to some extent or another, they did for themselves first.</p>
<p>I need to be more careful to present my opinions here as <em>opinions</em>, and make it clear that there's no objective thing here.
(Also, by the standards I've alluded to in some of these posts, the very script I wrote to <em>publish</em> this blog is pretty heinous.
It has avenues of improvement I can take it down, but until then, the uploader software I want and the uploader software I have seem pretty different to me.)</p>
<p>In the past, I've tried to be pretty extreme about metrics that seem sensible to me.
One way to describe the way I tend to push coverage metrics on projects is "more 100% than 100%", from divide-and-cover.
And I think taking the responsibility for covering a module's API surface, and putting it <em>specifically</em> on the tests explicitly associated with that module, I think that's a powerful tool.
But it's time I admitted to myself that a tool's power is insufficient to justify its use.
The only thing that justifies using a tool is having a problem that that tool can solve.
Testing in general is a form of insurance, a way of constraining the changes that the code can undergo.
I'm starting to think that testing is more valuable the more colloborative the development process is—noting well that development can be collaborative even if only one person is actually editing the code.
Think of a test as a way of saying "It's important to me that this behavior holds. In fact, it's so important that I've instructed the computer to say so for me."</p>
<p>Reiterating on the aside about collaboration, I feel like when I release some software into the world, it should be ready for collaboration.
I have not really lived up to this; aside from any issues of wounded pride I'm expressing here, projects like divide-and-cover should... have... tests...
I went to all the trouble of composition and dependency injection and stuff, and then didn't write anything for them.
Cleaning up divide-and-cover should be a project soon.</p>
<p>I guess the big takeaway is that I have some blind spots I should be working on.
They seem like they don't make any sense; probably that's a part of why they're blind spots.</p>
Blog Setup - Research 2018-07-062018-07-06T04:00:00-04:002018-07-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-06:/blog-setup-research-2018-07-06<p class="first last">I accidentally part of the implementation.</p>
<p>In this post:</p>
<ul class="simple">
<li>I research by going beyond research.</li>
<li>I do end up figuring out which bits are difficult, though.</li>
<li>And get a plan specifically for the next time.</li>
</ul>
<hr class="docutils" />
<p>Here's where the blog publisher is now:</p>
<ul class="simple">
<li>A single, awkwardly-named python script with no <tt class="docutils literal">if __name__ == '__main__':</tt> stanza, that I "use" by invoking it in interactive mode and calling functions.</li>
<li>Many functions call subprocesses, but do not check the result.</li>
<li>The script is supposed to be a <a class="reference external" href="http://click.pocoo.org/6/">click</a> frontend to a bunch of libraries for manipulating different kinds of directory trees, but it only depends on click, without helpfully using it, and is a single script.</li>
<li>Various paths specific to my current setup are hardcoded into the script.</li>
<li>The invocation is not instantaneous, and if something goes wrong, I have to <em>look at the output like a savage</em> to know that it didn't work.</li>
</ul>
<p>It turns out that handling the first three of these was pretty easy.
And the last one wasn't a big deal either, though my solution could use some refinement.
"Research" here seems to mean "just try stuff".
Experimentation is a kind of research, right?</p>
<p>In that vein, let's see what happens if I just try to put together my ideas for a syntax definition...</p>
<p>Here's what happens:</p>
<ul class="simple">
<li>Formatting string literals, control flow, access modifiers, and builtin constants were all easy.</li>
<li>Getting hashed syntax highlighting as I want it looks like it needs a different syntax definition. Yaaaay.</li>
<li>For some reason, the hashed syntax highlighting <em>did</em> turn some of the source to these blog posts into rainbow goop.</li>
</ul>
<p>Therefore, the hard problems, currently, are addressing the hardcoded constants in the blog publisher (hard because I don't have any other users to get feedback on how this should work from), writing a python syntax file worthy of my syntax highlighting, and finding a more robust way to call AppleScript from Python.</p>
<p>The syntax file is the highest priority, so I guess I'll be looking into that.</p>
<p>So far, I've mostly copied the current Python syntax definition from Sublime Text, stripped out Python-2-specific syntax, and left myself notes on a few things I want to work differently.</p>
<p>Basically, aside from giving all names a handy scope, I want to:</p>
<ul class="simple">
<li>Consider the different kinds of name somewhat differently. (It seems to me that it makes some kind of sense to distinguish between "names reserved by the language" (and perhaps distinguish between known and unknown versions of such names), "names scoped to a class", "names private by convention", and "names public by convention")</li>
<li>Consider docstrings as embedded reStructuredText instead of comments. (Also, get or make a new reStructuredText syntax definition.)</li>
<li>Parse comments somewhat, and highlight directives. (So, call out in some way, the shebang line, the encoding specification, notes, typing directives, and possibly other tools.)</li>
</ul>
<hr class="docutils" />
<p>Next time, I try to get some of these specific things done, in the custom package I made to test this stuff out.</p>
Draw a Box 2018-07-052018-07-05T04:00:00-04:002018-07-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-05:/draw-a-box-2018-07-05<p class="first last">I'll actually scan in the stuff I draw once it gets interesting. For now, muscle memory.</p>
<p>In this post:</p>
<ul class="simple">
<li>LINES</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>15 lines on June 28.</li>
<li>15 lines on June 29.</li>
<li>15 lines on June 30.</li>
<li>15 lines on July 1.</li>
<li>15 lines on July 2.</li>
<li>15 lines on July 3.</li>
<li>15 lines on July 4.</li>
</ul>
<p>For a total of 105 lines this week,
390 lines on the first sheet since I started counting,
and 555 lines on the second sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Blog Setup - Planning 2018-07-042018-07-04T04:00:00-04:002018-07-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-04:/blog-setup-planning-2018-07-04<p class="first last">It's been long enough, let's try to improve this experience.</p>
<p>In this post:</p>
<ul class="simple">
<li>I lay out a bunch of tasks I want to accomplish.</li>
<li>I think about areas I'll need to research.</li>
<li>I summarize what I've done so far.</li>
<li>I list some goals for the end of the week.</li>
</ul>
<hr class="docutils" />
<p>Here are specific things I want to have working with the blog publisher:</p>
<ul class="simple">
<li>The blog publisher should be a proper command-line app.</li>
<li>The blog publisher should have a proper "create local draft" mode again. (It turns out this actually works; I'd simply forgotten about it.)</li>
<li>The blog publisher should be more responsive to non-zero error codes from subprocesses.</li>
<li>The blog publisher should notify me when posting fails.</li>
</ul>
<p>Here are specific things I want to have working with Sublime Text, some of which may not be possible with the current syntax definition:</p>
<ul class="simple">
<li>I want to update my custom <a class="reference external" href="http://ethanschoonover.com/solarized">solarized</a> color scheme to a <a class="reference external" href="http://www.sublimetext.com/docs/3/color_schemes.html">Sublime Color Scheme</a>.</li>
<li>The custom color scheme should have <a class="reference external" href="http://www.sublimetext.com/docs/3/color_schemes.html#hashed_syntax_highlighting">hashed syntax highlighting</a> for identifiers.</li>
<li>Constants and variables should have separate slices of the solarized space for their hashed highlighting. (Due to the way <a class="reference external" href="https://github.com/MattDMo/PythonImproved">PythonImproved</a> works, I probably won't do this, actually.)</li>
<li>The inside of a string literal should be highlighted but not otherwise formatted or colored, while the quotes should be <em>not</em> highlighted, and formatted or colored.</li>
<li>Comments should be highlighted and bold.</li>
<li>If possible, the <tt class="docutils literal">async</tt>, <tt class="docutils literal">await</tt>, and <tt class="docutils literal">yield (from)</tt> keywords should be called out especially.</li>
<li><tt class="docutils literal">global</tt> should be very emphasized.</li>
<li><tt class="docutils literal">self</tt> and <tt class="docutils literal">cls</tt> should be highlighted specially and given a fixed color.</li>
<li>Look into highlighting parentheses in a more extreme fashion.</li>
<li>Do <em>not</em> especially emphasize most keywords.</li>
<li>Builtin constants should have a different range of colors for hashed highlighting.</li>
<li>It's a little bit at the point where I kind of want to hack on PythonImproved. Try to get good stuff like highlighting enum members as constants under all circumstances, if I can figure out how.</li>
<li>Selected text should reverse the background color, and be emphasized when the window is focused.</li>
</ul>
<p>Here are specific things I want to have working with my blog theme:</p>
<ul class="simple">
<li>Instead of using my hand-rolled solarized syntax theme on the blog, find someone else's to just drop in.</li>
</ul>
<p>I actually went and just did that one, using a modification of <a class="reference external" href="https://gist.github.com/nicolashery/5765395#file-solarized-dark-css">Nicolas Hery's solarized dark css for pygments</a>.
The result has more styling in it, and better documentation of the token types, but it probably needs some work.</p>
<p>So, the important thing in all of this is that I should have a nicer system for publishing to this blog.
The nice thing to have when all of this is done, is a syntax highlighting scheme that incorporates a variety of ideas I've been exposed to over time, all in one package.</p>
<hr class="docutils" />
<p>Next time, I figure out what of the above I can and can't do.</p>
Weekly Roundup 2018-07-032018-07-03T04:00:00-04:002018-07-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-03:/weekly-roundup-2018-07-03<p class="first last">Rough week. Rough, incredibly hot week.</p>
<ul class="simple">
<li>Main project: I got started on designing MonFree Kalazia, an audiovisual gamelike experience for any computer I can get it to run on, inspired by a popular, long-running multimedia franchise.</li>
<li>Draw a Box: The paper is getting gradually filled up. Closer and closer to drawing boxes.</li>
<li>Free-Topic: I speculated about setting up static analysis of Python code to enforce worst-case algorithmic bounds, with an eye towards making informed performance tradeoffs with design by contract. I assumed while I was writing the post that the relevant functionality could just be crowbarred into mypy, but that looks to not be the case.</li>
</ul>
<p>Next week, inspired by some embarrassing failures-to-actually-post in the past week, I'm going to touch up the uploader script, and, while I'm at it, redo my syntax highlighting for Sublime Text, and possibly revisit the syntax highlighting on this blog.</p>
MonFree - Retrospective 2018-07-022018-07-02T04:00:00-04:002018-07-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-02:/mon-free-retrospective-2018-07-02<p class="first last">I need to get my groove back.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I learned.</li>
<li>What I accomplished.</li>
<li>What's next.</li>
</ul>
<hr class="docutils" />
<p>So, what have I learned from trying to put together a design for MonFree?
Well, designing stuff is hard, which I knew.
I'm well acquainted with the rabbit holes that form around specification.
I just hope I get my momentum back at some point, and can look back at one of these feeling like I accomplished what I meant to, rather than merely(?) "something".</p>
<p>Anyway, I did end up with a much clearer picture of the directions I could take the UI, which I need to sketch out sometime.</p>
<p>What I think I really need for the next week I do is to make sure I have a good baseline first.</p>
<p>This week, I started putting together a specification of how a hypothetical monster training game would differ from the not-yet-done basic roguelike I'm sometimes working on, and came up with a list of things that have to be implemented.</p>
<p>Next, I started working out rough dependencies between them, to have a plan of attack for converting one to the other.</p>
<p>I'm not sure if it's the heat this week, or moving out of my comfort zone in terms of what to work on (if it's not obvious, I do very little design up front most of the time), or if the new schedule isn't working right, but I'm not feeling like going for another week of this.
I think next week I'll try something like, I don't know, Project Euler problems in Rust.
One thing pointing to external factors is that I've been kind of messing up the task of actually publishing these entries lately.
Actually, maybe that's something I could do. Touch up the publishing script, because there must be some way to improve this workflow.</p>
<hr class="docutils" />
<p>Next week, I want to find something a little easier, to cope with this miserable heat.</p>
MonFree - Design 2018-07-012018-07-01T04:00:00-04:002018-07-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-07-01:/mon-free-design-2018-07-01<p class="first last">This is going to take a lot of work.</p>
<p>In this post:</p>
<ul class="simple">
<li>Musings on the control scheme.</li>
<li>Tasks to look into to extend Homunculus into MonFree.</li>
<li>Not ready to make big changes to the map handling yet.</li>
</ul>
<hr class="docutils" />
<p>I realized that I want to think a little about control scheme.</p>
<p>I'm inclined to say that the basic control scheme should be:</p>
<ul class="simple">
<li>number keys: use item/ability from hotbar</li>
<li>some choice of keys, such as wasd: up, down, left, right</li>
<li>going to need to think a little, maybe have dialogue controls differ some between Retro and Journeys. Basically, I have the idea that it should be possible to cut off conversation in Journeys, so it might need more buttons. But Retro just needs start/continue and continue/cancel.</li>
<li>Might as well have buttons that just go like "Ztart, eXit, Continue". Stick with that for now.</li>
<li>Something to bring out the menu, like tab maybe.</li>
</ul>
<p>So, with everything I'm thinking about, I need to figure out a way to iterate.
Easy things to change:</p>
<ul class="simple">
<li>Model player facing.</li>
<li>Switch from generated rooms to fixed rooms. Then, make the staircases come down in a specific location and add staircases up. Replace walking up/down a staircase button with the interact button, and have it be done from adjacent tiles. I may change this idea later. It's inspired in part by trying to use the stairs in the Gen 1 Celadon buildings. Work on implementing buildings.</li>
<li>Remove the combat mechanics. Switch all AI to wandering randomly. Pop up a simple dialogue message on interacting with an NPC.</li>
<li>Implement <abbr title="quality-based narrative">QBN</abbr> mechanics, and re-implement the inventory in terms of QBN. Add a "money" quality. Ensure that qualities are scoped to entities. Kind of like special components that just contain a number or an enumeration. Or a formula for one or the other? Qualities should be one of a specific set of types, but with a <tt class="docutils literal">component_type</tt> based on the quality type.</li>
<li>Mark some tiles as randomly triggering events. For now, just pop up different dialogue boxes.</li>
</ul>
<p>I'm going to need to think some more about how to accomplish the map transitions, because it seems like I don't have a fully fleshed-out and consistent idea of how the maps work in the games I'm trying to imitate here.
Like, I'm pretty sure the maps in gen 1 at least were like, beyond certain boundaries on the maps, you triggered a map transition, but no other character did.
This had the side effect that NPCs could wander out to a point where they'd suddenly vanish if you followed them.
My issue thinking about this is that the playable area in the maps comes together to form a more-or-less contiguous thing, and there's no jarring transition, so either there's an underlying coordinate system that the maps are defining subsets of, or there's some data that's specific to pairs of maps that gets them aligned.
The fact there I don't yet see an obvious solution to all this is a sign to me that I need to step away from this part and think about it more later.</p>
<p>Anyway, once the above changes are done, then I think I want to start getting a battle system in, and shops.
Shops would basically be a place where you find an NPC who'll exchange around your qualities.
For the battle system, that needs a <tt class="docutils literal">Roster</tt> component, and <tt class="docutils literal">Monster</tt> entities.</p>
<p>Thinking about qualities scoped to entities, stuff like stats definitely needs to distinguish between "not present" and "zero".</p>
<p>This week turned out really hard, but I guess I made some progress.</p>
<hr class="docutils" />
<p>Next time, wrapping this week up.</p>
Guard Rails for Design by Contract2018-06-30T04:00:00-04:002018-06-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-30:/guard-rails-for-design-by-contract<p class="first last">Determine your runtime at compile-time, in order to contract your properties</p>
<p>In this post:</p>
<ul class="simple">
<li>It's hard to strike a good balance in writing contracts to verify software, because you don't want to slow down the program too much.</li>
<li>... And we don't know offhand how much a given contract slows things down.</li>
<li>... But what if we could annotate things so that a static analysis tool could figure it out?</li>
<li>Approximately 1.5 bad jokes that I don't have the decency to explain.</li>
</ul>
<hr class="docutils" />
<p>While I wait for all of the infrastructure I need for Python 3.7 CI to get set up, I'm thinking about other projects I could look into.
I was thinking about something <a class="reference external" href="https://www.hillelwayne.com/">Hillel Wayne</a> has talked about a few times, which is combining property-based testing and design-by-contract.
One tension that arises in design-by-contract, is which contracts to be checking in production:</p>
<blockquote>
<p>I have mixed feelings on this. On one hand, if you have control over your production environment, it’s better to fail fast than let an error propagate. On the other hand, contracts are a runtime overhead. On the other other hand, if you’re concerned about runtime overheads you really should be profiling your code instead of just turning off consistency checks and hoping that’s where the slowdown is.</p>
<p>On the other other other hand, many of the “full specification”-style contracts involve coming up with a “definition” of the function that’s more “obviously correct” than whatever implementation you have. In practice this usually means brute forcing the solution, which probably would be a source of slowdown in prod. So my personal rule is “some contracts stay up, some get turned off.”</p>
</blockquote>
<p>It looks to me like one perspective to take on this, is to suppose that algorithmic characteristics are part of the code's interface, and therefore, in production, you don't want to be running any checks with worse asymptotic performance.
So all we need to do is get everyone using <a class="reference external" href="https://en.wikipedia.org/wiki/Big_O_notation">big O notation</a>, and they can verify the correctness of it all by hand.</p>
<p>... Wait.</p>
<p>It'd be really convenient if we could have some form of static analysis tool that took care of this stuff for us, to an extent.
And, it turns out that type systems can encode some pretty sophisticated annotations of type values, via "<a class="reference external" href="https://github.com/matt-noonan/gdp-paper">Ghosts of Departed Proofs</a>".
I'm a little interested in trying to apply those techniques to Python, but what I have in mind here is kind of adjacent to it, and would rely on different behavior than a typical type checker has.
I'll try to sketch something out, since it'll get really vague if I don't have something to point to.</p>
<div class="highlight"><pre><span></span>T = typing.TypeVar('T')
U = typing.TypeVar('U')
def my_product(a: typing.List[T], b: typing.List[U]) -> typing.List[typing.Tuple[T, U]]:
results = []
for elem_a in a:
for elem_b in b:
results.append((elem_a, elem_b))
return results
</pre></div>
<p>We want to somehow express the idea that the runtime of <tt class="docutils literal">my_product</tt> is dependent on the sizes of <tt class="docutils literal">a</tt> and <tt class="docutils literal">b</tt>, specifically, on their product.
Something like...</p>
<div class="highlight"><pre><span></span>import roger_smith
T = typing.TypeVar('T')
U = typing.TypeVar('U')
M = typing.TypeVar('M')
N = typing.TypeVar('N')
def my_product(a: roger_smith.Bind[typing.List[T], roger_smith.Binding[roger_smith.Len, M]], b: roger_smith.Bind[typing.List[U], roger_smith.Binding[roger_smith.Len, N]]) -> roger_smith.Bound[typing.List[typing.Tuple[T, U]], roger_smith.Product[M, N]]:
results = []
for elem_a in a:
for elem_b in b:
results.append((elem_a, elem_b))
return results
</pre></div>
<p>This is obviously extremely un-ergonomic, and the name is a joke that I'm a louse for making, but hopefully the basic idea comes across: it's possible to generate one or more bindings from each argument to a type variable (TODO, check whether mypy has any objections to this that, like most of mypy's objections to writing my own type syntax, I did not foresee), and combine the bound variables into an expression in the output type that expresses the complexity bounds on the function.
The time complexity should probably be worst case; it is, after all, the long tail that causes a lot of the trouble.
To verify the complexities provided, the checker basically has to add up every line's algorithmic complexity within a suite, and multiply loops by the algorithmic bounds on the number of iterations.
Ideally, the checker should be able to request further bindings in order to calculate such things, and to generate a complexity for the result.</p>
<p>To work with Python specifically, there are some further features needed.
For example, methods should be annotated both with the algorithmic complexity of the specific implementation, and with the maximum algorithmic complexity that is acceptable in a subclass.
Also, some except blocks should be excluded from the calculations, but I think that has to be an explicit annotation of some kind.</p>
<p>I feel like this is a little obnoxious because it makes you still do the work (unless it has all of the fill-in features and you just iterate over it), but at least it can handle checking and verification.</p>
<p>Anyway, a miracle occurs, and we have a mypy plugin for this.
For the purpose of run-time type checkers, the "binding" functions should probably just return their first argument, because I can't think of any useful way to do the analysis at runtime.</p>
<p>Now that we have the ability to generate and verify algorithmic bounds, the next step is to have a contracts library that operates within the bounds.</p>
<p>It's late an I'm tired, so I'm just going to handwave my way through this idea: add to an existing or new contracts library the concept of "oracle" contracts, which are not checked at runtime, but are somehow signalled to run under test.
Annotate the contracts using the <tt class="docutils literal">Cast</tt> function to confirm that the complexity is as expected.
Then, there you go: oracle contracts that (probably) don't slow down performance unacceptably at runtime.</p>
<p>I feel like if I tried to do this, I'd either get a useful tool, or learn about some really deep stuff.
Maybe both.
So, I think this is a good candidate for several weeks' worth of project sometime.</p>
MonFree - Goals 2018-06-292018-06-29T04:00:00-04:002018-06-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-29:/mon-free-goals-2018-06-29<p class="first last">Not a bad start on speccing things out at a high level</p>
<p>In this post:</p>
<ul class="simple">
<li>What is "Homunculus"? I'm not sure I've actually said before.</li>
<li>What should Retro and Journeys be?</li>
<li>What common factors do the Kalazia games have?</li>
<li>What differentiates them?</li>
</ul>
<hr class="docutils" />
<p>So, there are several things to describe.</p>
<p>Homunculus is my name for a roguelike game/engine I'm writing, based on a tutorial for writing a roguelike using <a class="reference external" href="https://pypi.org/project/tdl/">tdl</a>.
When it's done, the gameplay loop will be:</p>
<ul class="simple">
<li>Start a new game.</li>
<li>Spawn in a randomly generated dungeon, surrounded by orcs, trolls, potions, scrolls, swords, and shields.</li>
<li>Kill enemies to level up.</li>
<li>Find the staircase down to move to a tougher level, and get healed a little.</li>
<li>Eventually die.</li>
</ul>
<p>It has autosave functionality.
Movement is turn- and grid-based; there's no diagonal movement because I didn't want to implement vimkeys, and I didn't think of anything better.</p>
<p>I hope to extract out the content assumptions, and extend the core functionality, to create engines and assets for games set in a region I made up, called Kalazia.
For convenience, the two things I'm trying to put together, MonFree Retro and MonFree Journeys, I'll call the common code and assets MonFree Kalazia.
I'm thinking about both Retro and Journeys, in part, to have some idea of which concepts I feel like pulling out into a library first.</p>
<p>When I was thinking about MonFree, I first thought about the ideas that went into Journeys, which came from reading the <abbr title="Pokémon Tabletop United">PTU</abbr> rulebooks.
I thought it'd be cool to have a video game that incorporated some of the ideas from the books, such as "type bends", and battling on a grid.
I also think it'd be interesting to have the ability to customize the player character, from a gameplay perspective.</p>
<p>However, since some of that is pretty ambitious, I'd also be okay with something that packed ideas like "type bends" into a more old-school presentation.
Hence, MonFree Retro.</p>
<p>I want the overall gameplay of MonFree Retro to be:</p>
<ul class="simple">
<li>Start the game in the southwest corner of Kalazia, and work your way around it in several clockwise loops.</li>
<li>Start the game with a single monster, capture and train more.</li>
<li>Prove yourself against powerful trainers that each specialize in a different element.</li>
<li>Finally, go up against "the best" trainers, and thereby unlock the postgame content.</li>
<li>Along the way, deal with a criminal organization that is <em>definitely</em> not inspired by current events.</li>
</ul>
<p>Where Retro has a fixed overarching plot with short sideplots that open up as the game continues, I want Journeys to be more of a quality-based narrative setup, maybe with waypoint-based conversations.
(Terminology swiped from <a class="reference external" href="https://emshort.blog/2016/04/12/beyond-branching-quality-based-and-salience-based-narrative-structures/">Beyond Branching: Quality-Based, Salience-Based, and Waypoint Narrative Structures</a>)
I don't have a specific vision for Journeys, so I'm first going to throw out some questions:</p>
<ul>
<li><p class="first">Can the player form a party with other humans?</p>
</li>
<li><p class="first">Can a single game world support the player in a range of activities such as:</p>
<blockquote>
<ul class="simple">
<li>Opening a shop</li>
<li>Becoming an archeologist</li>
<li>Wielding godly power</li>
<li>Getting tangled up in the criminal underworld</li>
<li>Entering the various competitions</li>
<li>SCIENCE!</li>
<li>MAGIC!</li>
</ul>
</blockquote>
</li>
</ul>
<p>What I'm kind of imagining is an overall structure of story hooks that hint at different styles of narrative, and slot into a small set of predefined structures, which the player then moves between to define what their character is like.
Kind of a hybrid of <a class="reference external" href="http://fallenlondon.storynexus.com/">Fallen London</a> and <a class="reference external" href="https://www.drivethrurpg.com/product/134196/Chuubos-Marvelous-WishGranting-Engine">Chuubo's Marvelous Wish-Granting Engine</a>.</p>
<p>So, overall gameplay of Journeys would be:</p>
<ul class="simple">
<li>Start the game, ideally anywhere in Kalazia, with a single monster.</li>
<li>Develop your character and their team, following intriguing story hooks</li>
<li>Hopefully, have a satisfying experience, however you decide to develop your character.</li>
</ul>
<p>With those thoughts down, let's see what the ideas have in common:</p>
<ul>
<li><p class="first">The player is collecting a team of monsters to act as traveling companions</p>
</li>
<li><p class="first">Those monsters have various elemental affinities</p>
</li>
<li><p class="first">They have abilities that key into those affinities</p>
</li>
<li><p class="first">The interactions between those affinities determine how effective attacks against a monster are</p>
</li>
<li><p class="first">The monsters gain power from combat experience, which is one way they learn new abilities</p>
</li>
<li><p class="first">Various factors allow the monsters to change into more powerful forms; new forms have the potential to learn different abilities, and may have different elemental affinities</p>
</li>
<li><p class="first">Some monsters have abilities that can alter their affinities, combat characteristics, appearance, etc.</p>
</li>
<li><p class="first">The combat statistics are the following:</p>
<blockquote>
<ul class="simple">
<li>Maximum hit points; this number does not change during the course of combat</li>
<li>Physical/Special Attack/Defense: different moves are considered "physical" or "special"; the distinction is basically whether they have "heft"</li>
<li>Speed</li>
<li>Accuracy/evasion/and such</li>
<li>I want to break evasion into various kinds of armor class, maybe</li>
</ul>
</blockquote>
</li>
<li><p class="first">I want to have an idea of size classes, that apply modifiers to the statistics, and can be switched between using abilities or items. Basically, I don't want ants to be giant by default, but the player should be able to make their ant be giant</p>
</li>
<li><p class="first">There are unique monsters with connections to the lore of Kalazia. They can be encountered and spoken to, gotten quests or boons from, but not captured.</p>
</li>
<li><p class="first">Rather than "trading" monsters, players should be somehow able to "lend" a monster to friends while they are both online, and this should have various effects</p>
</li>
<li><p class="first">Various factors should be able to influence a monster's appearance</p>
</li>
<li><p class="first">Monsters are recruited by weakening them in battle, then using an item of some kind</p>
</li>
<li><p class="first">Monsters can be bred to raise new monsters from a low level; breeding compatibility relies on various factors including relative size, and relative size also influences the species distribution of the child; like, potentially anything should be able to have a panda baby, or a kangaroo baby. Kiwis may have some trouble having a kiwi baby.</p>
</li>
<li><p class="first">Updates are queued, and applied to a running game when the player consults specific NPCs; this should put the game in a sufficiently predictable state</p>
</li>
<li><p class="first">There should eventually be mod support, which should use the same facilities as in-place updates</p>
</li>
<li><p class="first">No external time-gated events; the game should run on its own clock, possibly allow for waiting/sleeping. Some in-game events may be sensitive to in-game time.</p>
</li>
<li><p class="first">Besides directly attacking an opponent's hit points, a monster can also inflict various status effects, which make combat harder in various ways</p>
</li>
<li><p class="first">Players should have access to manual saves under most circumstances, auto-saves at scene transitions, and auto-saves on game close</p>
</li>
<li><p class="first">There are NPCs that serve various functions; players can have simple conversations with them</p>
</li>
<li><p class="first">The player has access to monsters that are unique or rare, but not intimately tied to lore</p>
</li>
<li><p class="first">There are various ways to teach monsters moves that they would not learn "naturally", including passing the move down through breeding.</p>
</li>
<li><p class="first">I want some kinds of monster to have unique breeding mechanics</p>
</li>
<li><p class="first">There are shops and healers at various locations. Healing is free (possibly only in Retro).</p>
</li>
<li><p class="first">Only some of the game map is caves. The rest is roads, buildings, rivers, the sea, forest/jungle, maybe a canyon...</p>
</li>
<li><p class="first">Most things that take you to a different location can be followed back the other way.</p>
</li>
<li><p class="first">Though some terrain features can forbid certain kinds of movement.</p>
</li>
<li><p class="first">Map regions are connected at their north, south, east, and west sides.</p>
</li>
<li><p class="first">In-game text that the player can read.</p>
</li>
<li><p class="first">Monsters not being used for battle can be held in reserve somewhere.</p>
</li>
</ul>
<p>Distinctions between Retro and Journeys:</p>
<ul class="simple">
<li>In Retro, time passes and NPCs move in real time. Journeys waits on player input.</li>
<li>In Retro, battles take place in an abstract space disconnected from the surroundings and the flow of time. In Journeys, battles are physically located in the world, and turns to game ticks</li>
<li>In Retro, trainers do not influence the battle beyond commands and items. In Journeys, trainers have combat statistics and special abilities.</li>
<li>In Retro, the player moves forward through a plot with minor reactivity. <em>Hopefully</em>, in Journeys the player is presented with a selection of algorithmically-filtered plot hooks, and follows the ones that appeal to them.</li>
<li>I would <em>like</em> Journeys to have some form of modeling of events not influenced by the player.</li>
</ul>
<p>This represents a good initial sketch of what the Kalazia games will be like.
It's probably going to need a lot of expansion and refinement.</p>
<hr class="docutils" />
<p>Next time, I try to organize these, and devise a sequence of iterative steps from Homunculus to Kalazia.</p>
Draw a Box 2018-06-282018-06-28T04:00:00-04:002018-06-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-28:/draw-a-box-2018-06-28<p class="first last">Continued progress</p>
<p>In this post:</p>
<ul class="simple">
<li>LINES</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>15 lines on June 21.</li>
<li>15 lines on June 22.</li>
<li>15 lines on June 23.</li>
<li>15 lines on June 24.</li>
<li>15 lines on June 25.</li>
<li>15 lines on June 26.</li>
<li>15 lines on June 27.</li>
</ul>
<p>For a total of 105 lines this week,
390 lines on the first sheet since I started counting,
and 450 lines on the second sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
MonFree - Planning 2018-06-272018-06-27T04:00:00-04:002018-06-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-27:/mon-free-planning-2018-06-27<p class="first last">Hopefully-Legally-Distinct-From-Established-Intellectual-Property... mon.</p>
<p>In this post:</p>
<ul class="simple">
<li>The motivation for MonFree.</li>
<li>My relatively high-level goals for this week, in speccing it out.</li>
<li>The specific things I want to have for myself in a week's time.</li>
</ul>
<hr class="docutils" />
<p>I don't want to get into <em>why</em> I'm not really into the Pokémon video games any more.
Suffice it to say that I'd rather play games at my own pace, without getting time-gated content dangled in my face.
I want to be playing a game because I want to play it, not because failing to play over a specific interval will leave me with a constant memory of the stuff I missed out on.
(If your response to this is "but the event Pokémon aren't even that good", then I'm going to assume that this week of posts is Not For You.)</p>
<p>So, I've got a little itch for a monster collecting game with all kinds of fancy bells and whistles, and no event stuff, and playing old games on an emulator, That Would Be Wrong 😇.
(Yes, my solution to "I've been losing interest in the series since gen 3" is "try to make my own".
My scoping estimates for this are made out of denial and fairy dust.)</p>
<p>Anyway, once I finish that roguelike tutorial and polish the code to a beautiful shine, I want to take the grid-based movement engine and start extending it in all kinds of ways.
I see two directions I could take the code to start with, and I'd kind of like to explore both, build them as extensions of some kind on top of a core that I extract out of Homunculus.</p>
<p>The first direction is something in line with the first 4 generations or so, grid-based but real-time, with distinct modes for battling, dialogue, etc.
The second direction would be kind of a combination of the mechanics in the Pokémon Tabletop fangames, with the turn-based all-the-time elements of how the engine is right now.</p>
<p>Needless to say, I'm not intending to include anyone else's intellectual property in this.
It'd be great if I could work out how far intellectual property goes, but I'm going to do the next-best thing, and declare that I'm basically clueless about the things that I haven't had explicitly spelled out for me, but I don't intend to misrepresent the provenance of the stuff I'm working on.
Starting with the name, this is going to be "MonFree" instead of anything nearer to the stuff I know is trademarked.</p>
<p>With that in mind, I'm going to spend this week trying to figure out what these two versions, MonFree Retro and MonFree Journeys, would look like.
I wouldn't say no to some kind of MonFree Card thing, but that's not what I want to think about just this moment.
(I also have this idea that I'd like to support games in the mold of other monster-raising franchises, but I have very limited familiarity with other franchises, so I don't really want to plan it out right now.)</p>
<p>I thought about doing this earlier, and I sketched out some high-level ideas, so I'm going to try to draw from those ideas.
One such idea is the setting of "Kalazia", a coastal region that surrounds a large bay.</p>
<p>So, as to what specific goals I want to try to do this week:</p>
<ul class="simple">
<li>Baseline behavior of Homunculus, after I finish the tutorial. (Note that this will differ somewhat from the behavior of the tutorial code.)</li>
<li>Behavior common to MonFree Retro and MonFree Journeys</li>
<li>Behavior specific to MonFree Retro</li>
<li>Behavior specific to MonFree Journeys</li>
</ul>
<p>I want to create designs for:</p>
<ul class="simple">
<li>Components that need to be implemented, under "Common", "Retro", and "Journeys" projects, in order to provide those behaviors.</li>
</ul>
<p>When the week is done, I should have:</p>
<ul class="simple">
<li>A document with preliminary design notes for setting-agnostic components, components required for the "Kalazia" setting, and components required specifically for Retro and Journeys.</li>
<li>A draft of a roadmap for getting from Homunculus 1.0 (which does not currently exist) to Retro and Journeys.</li>
</ul>
<hr class="docutils" />
<p>Next time, I start figuring out what differentiates MonFree Retro and MonFree Journeys from Homunculus, and from each other.</p>
Weekly Roundup 2018-06-262018-06-26T04:00:00-04:002018-06-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-26:/weekly-roundup-2018-06-26<p class="first last">Still getting my bearings with this new schedule idea.</p>
<p>So, I realized that the new schedule doesn't make sense to be broken up by day...</p>
<ul class="simple">
<li>Main project: I made some improvements to Structured Data, my attempt to bring fancy sum types into Python. It's still not ready for even me to use. Soon...</li>
<li>Draw a Box: It continues apace.</li>
<li>Free-Topic: I speculated about time travel game mechanics, and after a few false starts, came up with something diabolically over-complicated that I'm pretty sure I didn't explain properly.</li>
</ul>
<p>Next week, I'm going to think about some of the long-term directions I might take the Homunculus codebase, in Project MonFree.</p>
Algebraic Data Types - Retrospective 2018-06-252018-06-25T04:00:00-04:002018-06-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-25:/algebraic-data-types-retrospective-2018-06-25<p class="first last">It was really hard to work on this without a bugfixed Python version to run CI against.</p>
<p>In this post:</p>
<ul class="simple">
<li>What I think about this last week, all in all.</li>
<li>How well I followed the plan.</li>
<li>Reasonable near-term goals.</li>
<li>Thoughts on further-out improvements.</li>
</ul>
<hr class="docutils" />
<p>So, how did this first week on the new schedule go?
Well, it seems like it's probably not the best idea to get into coding a project before its dependencies are officially released; I think Structured Data could have gotten by just fine with more design before coding.
In my defense, I had not realized that <tt class="docutils literal">typing.Generic</tt> is kind of broken until 3.6.6.
Like, that was an issue that I could not have anticipated without just writing some dang code.</p>
<p>So far as the plan, I intended to write tests for various happy and error paths; I think I got more error paths than happy paths, and so there's a big hole in coverage around all of the different permissible syntaxes for type annotations, some of which I'll need to experiment with in 3.7 before I feel comfortable writing tests for them.
I also wanted to improve the documentation.
I didn't get so far there because I managed to break <a class="reference external" href="https://readthedocs.org/">Read the Docs</a> in what appears to be an obscure fashion, and it's hard to be excited about updating documentation when it's not going to show up on the website.
I should be able to fix that without breaking CI soon.</p>
<p>Once I have the CI switched to 3.7, I want to do a big push on ergonomic considerations.
Stuff like making it easy to create an extract pattern bindings, probably using a lot of <tt class="docutils literal">__getattribute__</tt> overrides to deal with names rather than strings.
I also want to shrink down and separate modules.
I should also focus on the generated documentation for the Constructors.</p>
<p>Other future directions I could take include looking into support for type checkers besides <a class="reference external" href="http://mypy-lang.org/">mypy</a>, though that'd be lower priority, since for now I only plan to use it with mypy.
There are also some open questions on how the generated <tt class="docutils literal">__new__</tt> function for the Constructors should look, since there are a fixed number of arguments of known type, but no name, which is really hard for me to wrap my head around documenting.
I could try using numbered arguments instead? Like, 0, 1, 2, 3...</p>
<p>Hopefully, I'll be able to get some good thinking time in, do a little tweaking on the side, and make a lot more progress the next time around.</p>
<hr class="docutils" />
<p>Next week, I want to try switching away from coding for a bit.
Haven't yet decided what to do instead.</p>
Algebraic Data Types - Development 2018-06-242018-06-24T04:00:00-04:002018-06-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-24:/algebraic-data-types-development-2018-06-24<p class="first last">I spent most of this tracking down a bug, but it was a REALLY WEIRD bug.</p>
<p>In this post:</p>
<ul class="simple">
<li>I made some documentation improvments.</li>
<li>I mostly ended up trouble-shooting an issue with generating docs against newer versions of Python, which I'm not sure anyone has explicitly mentioned?</li>
</ul>
<hr class="docutils" />
<p>So, I was mostly focused on the documentation for now, but I made a few changes to the code.</p>
<p>The most obvious improvement to me was the removal of the coverage append instructions.
Those are incorrect, and mostly irrelevant until there's more than one supported version.
Currently, there's sort of <em>zero</em> supported versions, because 3.7 isn't out yet.</p>
<p>Fixing up the versions will make a lot of things work better, and it's a little frustrating waiting for the release.
The online docs are broken in a way that I found extremely non-obvious: because <a class="reference external" href="https://readthedocs.org/">Read the Docs</a> tried to build the docs using Python 2.7, importing the package failed with a syntax error against the metaclass syntax.
That's all well and good, as far as failures go, but the error <em>didn't fail the build</em>???
Anyway, that's why the "reference" section is empty: because my annotation extension library doesn't import cleanly under Python 2.
Again, I'll try to address this when 3.7 releases.</p>
<p>I don't have "usage" filled out.
I kind of want to work out the dependencies between the different components, and factor them into their own modules.
One idea I want to consider on its own, though, is giving the modules short names, or recommending a short name to import <tt class="docutils literal">structured_data</tt> under, such as <tt class="docutils literal">s_d</tt>.
There are two obvious sets of features provided by <tt class="docutils literal">structured_data</tt>: sum type definitions, and pattern matching capabilities.
However, they can't just be cleanly split in two, because that structure leads to a bunch of circular dependencies.
Unless some of the dependencies I have are wrong.
They may very well be.</p>
<p>One thing that had me uncertain about documenting things was the fact that I'm not at all sure that the way I'm doing things right now, against a version that outright does not work in various ways, is how I want to do things.</p>
<p>Once I had the other changes basically done, I edited the changelog to look a little more like what <a class="reference external" href="https://keepachangelog.com/en/1.0.0/">Keep a Changelog</a> recommends.</p>
<p>I didn't make quite as much progress as I would have liked; I'll try to fit in some extra development on Wednesday-ish.</p>
<hr class="docutils" />
<p>Next time, wrapping this week up.</p>
Thoughts On Time Travel Game Mechanics2018-06-23T04:00:00-04:002018-06-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-23:/thoughts-on-time-travel-game-mechanics<p class="first last">"Hmm. Hmm... Hmm? Hmm! $$$$"</p>
<p>In this post:</p>
<ul class="simple">
<li>I consider time travel in RPG rules, and try to tweak an existing system.</li>
<li>I get hopelessly bogged down in edge cases, then start wildly handwaving.</li>
<li>My rambling crystallizes into a game concept which I can only think of as an act of war against bank accounts.</li>
</ul>
<hr class="docutils" />
<p>I was reading over an attempt to devise RPG rules for generic time travel shenanigans, and I ended up thinking about how to formalize the rules that Homestuck has.
(This is ignoring the retcon abilities.)</p>
<p>This is probably not going into Demiurgent Business, unless I can generalize the ideas away from strictly time travel shenanigans.</p>
<p>Characters have a Primary Dharma and a Secondary Dharma.
The Primary Dharma is the core of a character's identity, and influences how they can shape their Secondary Dharma, which is the details of how they relate to the world.</p>
<p>A character with access to time travel can react to unacceptable events by Rejecting the Secondary Dharma associated with the events.
This is accomplished by traveling back in time and interacting with their past self.
From the perspective of the past self, they can see Future Dharma from their future selves, and Accept them by becoming that future self, or Reject them by not becoming the future self.</p>
<p>Rejected Dharma leads to a swift death, or some form of fundamental transformation, to acquire a new Primary Dharma.</p>
<p>Setting things up to rely on personal paradox like this kind of implies that the resolution to the grandfather paradox is "sometimes angry futurebabies pop in out of nowhere".
Either that, or it's impossible to travel to before you were born, because that would deny your past self agency in reacting to your actions.</p>
<p>So, if you hire a time traveling assassin who is older than your grandfather, then the assassin ends up with a choice to make about Dharma, but you still never existed.
But if the assassin took the job from you, then they must Reject the Dharma, because they are incapable of Accepting it.
Or, I guess they could try, and that would form a closed loop that doesn't involve you.</p>
<p>Maybe I need to consider some way of thinking about Dharma entanglements.
Like, time travel on someone's behalf, and you're pulling their Secondary Dharma with you.
Which could act as a tether of some kind.</p>
<p>I think I may have been missing the fact that this stuff relies on the quality of self-interaction.
Like, if you travel back in time and hide, that doesn't change your Secondary Dharma, because there's no contradiction.</p>
<p>So, moving away from looking at the broader timeline, and focusing on the Age and the Yet.
We want to consider techniques that allow Yet Dharma to interact with Age Dharma.
In typical "linear" causality, Yet Dharma is a function of Age Dharma, but if they interact, then it becomes a more elaborate system.</p>
<p>Two means of change are through true time travel, which influences Age Dharma with a concrete Yet Dharma, and precognition, which allows a selection of Age Dharma based on Yet Dharma.</p>
<p>In game-mechanical terms, the latter corresponds to choosing from a set of Yets, and the former two having two abilities: to sacrifice the current Yet to undo an event from the Age, gaining a new Yet, and to place an arbitrary event in the Yet, and then later pay it off.</p>
<p>Thinking about that puts me in mind of, like, a deck of cards, where each card has some kind of associated resource, and associated costs.
So, a Seer can choose from a set of target cards that somehow have different costs associated, while a Traveler can discard their hand, using the discarded cards to somehow pay to undo a move, or tutor a card that they then have access to when they can pay for it.
So, each player's Yet would be their Hand, and the players are all constructing some kind of Age structure on the board, out of cards.
To have these varied distances of interaction, I'm kind of imagining now a card-based wargame.</p>
<p>So, if what's on the table is the Age, then to attack someone at a point in time, you have to declare the attack right after the card goes down, then figure out in subsequent turns how to accomplish it.
Cards could come into play with resources on them, and any left over would be available to claim later.
Possibly some resources would only go on the next card.
It should probably also be possible to "steal" declared attacks, converting them into feints of some kind.</p>
<p>I'm going to have to put this overall concept of "collectible card miniatures wargame about time battles" on the back burner because I have no idea how to design it.
But it's undeniably a heck of an idea.</p>
Algebraic Data Types - Testing 2018-06-222018-06-22T04:00:00-04:002018-06-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-22:/algebraic-data-types-testing-2018-06-22<p class="first last">Writing a few tests for too much code.</p>
<p>In this post:</p>
<ul class="simple">
<li>I wrote a few tests. Possibly, I could have written more, but this week wiped me out.</li>
<li>The tests give me some ideas for breaking up the 500+ line source file into manageable chunks.</li>
</ul>
<hr class="docutils" />
<p>This week had a lot going on, so I didn't test as thoroughly as I would have liked, but I did test a good portion of the error paths in the code, and I got the coverage above 50%, though just barely.</p>
<p>My initial testing focused on confirming the behavior of the Ctor type (which I may be able to simplify somewhat if I switch entirely to Python 3.7 semantics; can't do that yet though), with such things as:</p>
<ul class="simple">
<li>Indexing with the empty tuple is the same as the base class. I may want to relax this in the future, depending on how much I care about having a single representation of Ctor stuff (especially since the size of the index is the only thing that's supposed to matter at runtime).</li>
<li>Indexing with a non-tuple is the same as indexing with a 1-tuple that contains the non-tuple. Currently, this is by object identity, but, again, there are many possibilities. (I mean, in 3.7, indexing could be instance creation, and Ctor a subclass of int! I think.)</li>
<li>Can't subclass Ctor freely. I'd rather we weren't subclassing it at all. Next week, oh well.</li>
<li>Can't index an already-indexed Ctor. I'll be really happy to see the end of these metaclasses.</li>
<li>An exercise of most of the pattern-matching machinery. Some of the ergonomics here are bad, and I'm trying to figure out how to improve them. The test is dense enough that I'm going to include it here.</li>
</ul>
<div class="highlight"><pre><span></span> @structured_data.enum
class TestClass:
StrPair: structured_data.Ctor[str, str]
matcher = structured_data.ValueMatcher(
((1, 2), TestClass.StrPair('a', 'b')))
assert not matcher.match((
(structured_data.Pattern('_'), 4),
structured_data.Pattern('_')))
assert matcher.matches is None
assert matcher.match((
structured_data.Pattern('tup') @ (1, structured_data.Pattern('a')),
TestClass.StrPair(
structured_data.Pattern('b'), structured_data.Pattern('c'))))
assert matcher.matches == dict(tup=(1, 2), a=2, b='a', c='b')
</pre></div>
<p>This test is perhaps too big, in that it tests matching against tuple literals, against sum types, using at patterns, using discards...
Given my wish to separate things, perhaps the if-statements that ultimately power the match function should be converted into a loop that acts on (predicate, generator) pairs.
When the predicate matches, extend the work list from the generator, then do the next iteration.
Anyway, then they could be put into their own little modules, and be given little test cases.</p>
<p>The next big win for testing would be creating custom modules to import, to test the logic at the top level.
I'll have to see if divide-and-cover is okay with putting random non-discoverable files in the test tree, because that pattern of organization did not occur to me until this week.</p>
<p>(Also, it seriously bothers me that the cookiecutter's linting settings aren't generating <em>something</em> for that test code up there.
I'm using to having pretty strict lints on all of the code, including, at minimum, requiring docstrings everywhere.)</p>
<hr class="docutils" />
<p>Next time, I get into the documentation.
What's incorrect?
What should be added?
What should I do to the changelog?</p>
Draw a Box 2018-06-212018-06-21T04:00:00-04:002018-06-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-21:/draw-a-box-2018-06-21<p class="first last">The (second?) easiest category to deal with the new schedule.</p>
<p>In this post:</p>
<ul class="simple">
<li>Slightly short week this time, because of the schedule shift.</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>15 lines on June 15.</li>
<li>15 lines on June 16.</li>
<li>15 lines on June 17.</li>
<li>15 lines on June 18.</li>
<li>15 lines on June 19.</li>
<li>15 lines on June 20.</li>
</ul>
<p>For a total of 90 lines this week,
390 lines on the first sheet since I started counting,
and 345 lines on the second sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.
A little longer.</p>
Algebraic Data Types - Planning 2018-06-202018-06-20T04:00:00-04:002018-06-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-20:/algebraic-data-types-planning-2018-06-20<p class="first last">Not quite sure what I'm doing here, but I'm hopeful.</p>
<p>In this post:</p>
<ul class="simple">
<li>I lay out a bunch of tasks I want to accomplish.</li>
<li>I specify what the tests I write should cover.</li>
<li>I mention what I've accomplished so far, iterating on this.</li>
<li>I list some goals for the end of the week.</li>
</ul>
<hr class="docutils" />
<p>I'm still figuring out exactly what these new posts entail, but here's what I've decided to do this week for Structured Data:</p>
<ul class="simple">
<li>Get it ready for Python 3.7, which comes out in a week.</li>
<li>Ergonomics tweaks to the code.</li>
<li>As far as the documentation, figure out which bits of it are out of date, and update them. This definitely includes the documentation on how testing works.</li>
<li>Update the changelog according to <a class="reference external" href="https://keepachangelog.com/en/1.0.0/">Keep a Changelog</a>.</li>
<li>As I work on the documentation, figure out which bits of the code need to be documented, or can be moved around. I don't want to touch behavior, but the code "organization" right now is a whole... big... thing.</li>
<li>Add whatever tests I think of, for purposes of increasing coverage.</li>
</ul>
<p>Tests needed:</p>
<ul class="simple">
<li>Various permutations of type annotation syntaxes. Should these be in some kind of dedicated module (to provide proper access to globals)? Need to handle various styles of deferred annotation.</li>
<li>Error paths.</li>
</ul>
<p>So far:</p>
<ul class="simple">
<li>Got <a class="reference external" href="https://codecov.io/">Codecov</a> working properly with <a class="reference external" href="https://www.appveyor.com/">Appveyor</a>.</li>
<li>Fixed an error in coercing constructor instances to bool.</li>
<li>Discovered that there really isn't much point in supporting Python 3.5.</li>
<li>Removed the necessity of using some awkward syntax.</li>
</ul>
<p>When the week is done:</p>
<ul class="simple">
<li>The documentation should be ready for version 0.2.0, out next week.</li>
<li>Coverage should be at at least 50%, easily.</li>
</ul>
<hr class="docutils" />
<p>Next time, I start writing tests, so that there's basic functionality, verifying error paths, and generally improved coverage.
<a class="reference external" href="https://www.hillelwayne.com/post/a-bunch-of-tests/">Hillel Wayne</a> calls these "automanual" tests, and I'm interested in trying out the other ideas he mentions, but I need a baseline of tests first.</p>
Weekly Roundup 2018-06-192018-06-19T04:00:00-04:002018-06-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-19:/weekly-roundup-2018-06-19<p class="first last">A weird nub of a roundup.</p>
<ul class="simple">
<li>Schedule Change: The schedule changed, so this awkward update is here to kick things off.</li>
</ul>
Schedule Change 2018-06-182018-06-18T04:00:00-04:002018-06-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-18:/schedule-change-2018-06-18<p class="first last">Changing the weekly schedule around.</p>
<p>In this post:</p>
<ul class="simple">
<li>I lay out the pros and cons of the old schedule.</li>
<li>I explain the new schedule I'll be using going forward.</li>
</ul>
<hr class="docutils" />
<p>Giving this blog a schedule was kind of an experiment, and I think it's time to change the parameters.</p>
<p>Pros of the current system include:</p>
<ul class="simple">
<li>Daily content</li>
<li>Planning-ahead using the "next week" blurbs</li>
</ul>
<p>Cons include:</p>
<ul class="simple">
<li>Required effort is distributed badly</li>
<li>Inflexible regarding what can be done over several weeks</li>
</ul>
<p>I'm currently leaning towards designing some "week-long schedule" concepts, so I can devote a single week to mostly a single project.
Fixtures of all schedules would include the weekly roundup, the free-topic day, and art practice roundup.
I want these all to go on consistent days in every schedule, and I should note that the roundups take almost no concentrated effort.</p>
<p>In the context of working on a software project, I could perhaps allot the remaining four days to:</p>
<ul class="simple">
<li>Planning</li>
<li>Tests</li>
<li>Development</li>
<li>Retrospective</li>
</ul>
<p>To figure out where everything should go, I note that I want the roundup between Retrospective and Planning, and something before each of Tests and Development</p>
<p>Suppose I put the roundup on Tuesday?
That puts the Retrospective on Monday, which is great, and the Planning on Wednesday, which is fine.
Development would be Sunday, which sounds decent from here.
Let's say, Free Topic on Saturday, Tests on Friday, Art Roundup Thursday.</p>
<p>Okay, the plan then is to finish out this week, then make this post on Monday, follow it with a short roundup, and then start... probably Structured Data Week.</p>
<p>Anyway, my basic plan for other topics is to handle stuff like Demiurgent Business as:</p>
<ul class="simple">
<li>Planning</li>
<li>Goals</li>
<li>Writing/Editing</li>
<li>Retrospective</li>
</ul>
<p>And actually have a separate place to write all the stuff down, rather than just making a bunch of posts.</p>
Weekly Roundup 2018-06-172018-06-17T04:00:00-04:002018-06-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-17:/weekly-roundup-2018-06-17<p class="first last">Last roundup before the next one.</p>
<ul class="simple">
<li>Algebraic Data Types Monday: After one day of frantic effort, I can say that this codebase is truly worthy of the semver "0.1.0".</li>
<li>Free-Topic Tuesday: I took stock of all of the various projects I have going to various degrees, and came up with rough priorities.</li>
<li>Demiurgent Business Wednesday: I designed players and player characters, then realized I needed to think more about how the NPCs work.</li>
<li>Conworld Codex Thursday: I feel like I'm getting really good at the beginning of this whole "write a GUI application backed by SQLite" idea.</li>
<li>Draw a Box Friday: More lines, as usual.</li>
<li>Homunculus Saturday: I got halfway through part eleven of the tutorial, and teased... something. OooOOooo...</li>
</ul>
Homunculus Devlog 2018-06-162018-06-16T04:00:00-04:002018-06-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-16:/homunculus-devlog-2018-06-16<p class="first last">The dunker becomes the dunkee.</p>
<p>In this post:</p>
<ul class="simple">
<li>I throw yet more shade at the tutorial. I'm starting to feel a little bad about doing this, but evidently not bad enough to retract the shade, or particularly feel like stopping.</li>
<li>I throw some more fancy techniques at the code, to improve extensibility.</li>
<li>I start adapting more tutorial code to my altered codebase, and gloss over a bunch of bug fixes.</li>
<li>I have to work around my design a little, because certain types of changes are less obvious in the context of my code.</li>
<li>Ultimately, I get about halfway through this part of the tutorial.</li>
<li>There's no "Next week" blurb? I wonder what that could be about...</li>
</ul>
<hr class="docutils" />
<p>Okay, part eleven of thirteen.
Let's do this.
This tutorial starts off reworking the map and adding more components, which means adding more parameter to the entity initializer, and, um...</p>
<blockquote>
<p>If you have a procedure with ten parameters, you probably missed some.</p>
<p class="attribution">—Alan J. Perlis</p>
</blockquote>
<p>So, before we get into the meat of the tutorial, let's make some changes I'd wanted to do before.
The basic idea is to stop accessing components as attributes.</p>
<p>So, I converted it to using a dictionary of components, instead of fixed attributes.
Then, I made a chained method to stick components on an entity.
This gets the arguments off the initializer, and happens to be somewhat cleaner for setting components in general, because it has the logic that must Always Fire in it.</p>
<p>To really take advantage of this, I next need to rev the serialization functions, so I can just dump the components dict directly.
The main concern with revving is getting the test code updated... except I'll need to generate a new test file anyway to get stairs, so I can cheat.
Except, cheating is effort, so I'll just rev the functions legitimately, then get to work on the tutorial.
I can probably get rid of the old dumpers, but for now, I'll focus on following the tutorial.</p>
<p>Let's see, make a Stairs component, write serializer functions for it...
Skip over the changes to Entity because I just future-proofed it...
Basically follow along with what the tutorial says, though in a slightly different order, because I'm sick and tired of writing usage before definition, because auto-complete can't possibly work when you do that.</p>
<p>Hm.
I'm at the new floor creation function, and it feels slightly suspicious that it's duplicating the logic from the "new game" code.
Oh well, I'll leave that for later.</p>
<p>Oh no, the function whose organization I've been down on now has access to a variable that my rewritten version does not.
Have I been owned?
Let's see.
It's actually kind of hard for me to tell what is and isn't going on here.</p>
<p>Okay, I appear to be owned in several ways.
Let's see about fixing this up.
The two issues I'm currently aware of are, message spam from trying to go down the stairs, and I really do need the conn.clear().
The former was easy, I just had an else-block at the wrong level of indentation.
For the latter, I want to try leveraging the Event "system".
For the former, for now I'm just putting in a quick hack of my own, and adding a new temporary flag attribute to the Game object, to tell it to clear the screen at the start of rendering.</p>
<p>The way is now clear to move on to the second half of this part, but I'm pretty sleepy, so I'll have to put it off until later.</p>
Draw a Box 2018-06-152018-06-15T04:00:00-04:002018-06-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-15:/draw-a-box-2018-06-15<p class="first last">Just keep drawing...</p>
<p>In this post:</p>
<ul class="simple">
<li>LINES.</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>15 lines on June 8. The paper wilted again.</li>
<li>15 lines on June 9. Summer is not kind to this paper.</li>
<li>15 lines on June 10.</li>
<li>15 lines on June 11.</li>
<li>15 lines on June 12.</li>
<li>15 lines on June 13. It's hard to think in all this pollen.</li>
<li>15 lines on June 14.</li>
</ul>
<p>For a total of 105 lines this week,
390 lines on the first sheet since I started counting,
and 255 lines on the second sheet.</p>
<hr class="docutils" />
<p>Next week, I've got a slight shakeup planned.
It won't affect this too much, but it will affect it a little.</p>
Conworld Codex 2018-06-142018-06-14T04:00:00-04:002018-06-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-14:/conworld-codex-2018-06-14<p class="first last">Staggering back and forth in terms of specifying stuff up front.</p>
<p>In this post:</p>
<ul class="simple">
<li>I try to nail down the interface concepts.</li>
<li>Then rework the backend a bunch of times.</li>
</ul>
<hr class="docutils" />
<p>My basic idea of how I want to structure Conworld Codex is slowly shaping up.</p>
<p>A "Codex" is a SQLite database.
It's handled in memory normally, and written to disk all at once, possibly in some kind of versioned format.</p>
<p>Through SQLAlchemy, each in-memory database has a corresponding session.
Therefore, I can say that a loaded Codex has an associated session.</p>
<p>The sessions have associated models, which are currently data-only.
I suspect that "fat models" in Django come from trying to put the business logic near the parts of the code responsible for persistence.</p>
<p>For the other levels of code, access to the Codex data is mediated through an "App" (should be "Codex") object, which functions as a root to a tree-based interface, and maintains canonical copies of everything visible to consumers of that interface.
Taking some terminology from Wx, we have ideas like:</p>
<ul class="simple">
<li>There can be arbitrarily many Frames, but this current idea allows only one Frame pointing to a particular top-level resource. This could be changed if the Abstract Widgets were converted from NamedTuples to dataclasses, and given weakrefs to their parent objects.</li>
<li>I think what I actually want is that each Frame handles all of its descendants, so possibly the change I want to make for now is to move the canonicalization dict onto the Frame... but then the Codex would still be responsible for synchronizing the model objects, if SQLAlchemy can't handle that. And SQLAlchemy doesn't know what I'm doing here.</li>
</ul>
<p>Okay, this train of thought is unpleasant enough that I'm going to just start searching for stuff like "declarative GUI" and see if I find anything applicable to this.</p>
<p>Enaml looks interesting, though parts of the docs do seem worryingly anemic.</p>
<p>What's got me down right now is, I'm trying to teach myself how to put together UIs, and the corollary there is, I don't know what I'm doing.
I think it would be easier with a completely fixed, single-window setup... which is not what I'm doing.</p>
<p>I think what I need to do if I want to get anywhere with this is, step away from the higher levels of code, and explicitly write out every transformation of data I want to model.
They all need to be handled, so I should have a checklist made.</p>
<p>First, the data:</p>
<ul class="simple">
<li>Events (name)</li>
<li>Tellers (name)</li>
<li>Topics (name)</li>
</ul>
<p>and relationships:</p>
<ul class="simple">
<li>Let us say for now that every Teller is a Topic. But any kind of relation there implies that perhaps there should be an overall list of Topic/Teller names, and the Topic and Teller tables just foreign key into them?</li>
<li>A Teller can have commentary relating an Event to a Topic, and my feeling is that the Topic-Event relation is closer than the other relations (what Events a Teller has commented on in relation to a Topic, and what Topics a Teller has commented on in relation to an Event)</li>
<li>There are two relations that can hold between events: contribution and composition. These are binary relations between two Events, and are associated with commentary by a Teller.</li>
</ul>
<p>It occurs to me that a database in which the tables were sum types and the indexes were explictly of functions, would be able to express these ideas in a very concise way.
But, since I don't feel like digging up the relevant old projects (... maybe if I ever feel like getting better with profiling), I'll look into joined table inheritance.</p>
<p>I went and rewrote all the models underlying this with all the stuff I just said in mind.
Somehow, the tests all pass after I did that.
I think it might be because there's no <tt class="docutils literal">__slots__</tt> attribute on any of the classes I wrote?
Anyway.</p>
<p>I may have rewritten things a few more times.</p>
<p>For now, the most primitive types are Events, Topics, and secondarily Tellers.</p>
<p>To create an Event, provide its name, which must be unique.</p>
<p>To create a Topic, provide its name, which must be unique.</p>
<p>To create a Teller, provide either the name of a Topic which is <em>not</em> already associated with a Teller, or a name for a new Topic.</p>
<p>I believe relations are made just with the appropriate constructor, and then Commentary composes a Relation and a Teller.</p>
<p>To generalize this, I think I need a big matrix, where one side is <abbr title="create, read, update, delete">CRUD</abbr> and the other side is Event, Topic, Teller, EventRelation, EventTopic, EventContribution, EventConstitution, and Commentary.</p>
<p>Have a code dump:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span>
<span class="normal">102</span>
<span class="normal">103</span>
<span class="normal">104</span>
<span class="normal">105</span>
<span class="normal">106</span>
<span class="normal">107</span>
<span class="normal">108</span>
<span class="normal">109</span>
<span class="normal">110</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""SQLAlchemy ORM classes for modeling codex data."""</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">Column</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">String</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">,</span> <span class="n">UniqueConstraint</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.ext.declarative</span> <span class="kn">import</span> <span class="n">declarative_base</span>
<span class="n">Base</span> <span class="o">=</span> <span class="n">declarative_base</span><span class="p">()</span> <span class="c1"># pylint: disable=invalid-name</span>
<span class="k">class</span> <span class="nc">Event</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""The events within the history of the codex."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'event'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Topic</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""A person, place, or thing."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'topic'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Teller</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""The people talking about the events."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'teller'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'topic.id'</span><span class="p">),</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">EventRelation</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""Base class for relations."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'event_relation'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="nb">type</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">(</span><span class="mi">50</span><span class="p">))</span>
<span class="n">__mapper_args__</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">'polymorphic_identity'</span><span class="p">:</span> <span class="s1">'event_relation'</span><span class="p">,</span>
<span class="s1">'polymorphic_on'</span><span class="p">:</span> <span class="nb">type</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">class</span> <span class="nc">EventTopic</span><span class="p">(</span><span class="n">EventRelation</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""How a topic relates to an event."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'event_topic'</span>
<span class="n">__table_args__</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">UniqueConstraint</span><span class="p">(</span><span class="s1">'topic_id'</span><span class="p">,</span> <span class="s1">'event_id'</span><span class="p">),</span>
<span class="p">)</span>
<span class="n">__mapper_args__</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">'polymorphic_identity'</span><span class="p">:</span> <span class="s1">'event_topic'</span><span class="p">,</span>
<span class="p">}</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'event_relation.id'</span><span class="p">),</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">topic_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'topic.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">event_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'event.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">EventContribution</span><span class="p">(</span><span class="n">EventRelation</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""How one event contributed to another."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'event_contribution'</span>
<span class="n">__table_args__</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">UniqueConstraint</span><span class="p">(</span><span class="s1">'cause'</span><span class="p">,</span> <span class="s1">'effect'</span><span class="p">),</span>
<span class="p">)</span>
<span class="n">__mapper_args__</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">'polymorphic_identity'</span><span class="p">:</span> <span class="s1">'event_contribution'</span><span class="p">,</span>
<span class="p">}</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'event_relation.id'</span><span class="p">),</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">cause</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'event.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">effect</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'event.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">EventConstitution</span><span class="p">(</span><span class="n">EventRelation</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""How one event was part of another."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'event_constitution'</span>
<span class="n">__table_args__</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">UniqueConstraint</span><span class="p">(</span><span class="s1">'part'</span><span class="p">,</span> <span class="s1">'whole'</span><span class="p">),</span>
<span class="p">)</span>
<span class="n">__mapper_args__</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">'polymorphic_identity'</span><span class="p">:</span> <span class="s1">'event_constitution'</span>
<span class="p">}</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'event_relation.id'</span><span class="p">),</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">part</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'event.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">whole</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'event.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Commentary</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Commentary on a relation by a Teller."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'commentary'</span>
<span class="n">__table_args__</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">UniqueConstraint</span><span class="p">(</span><span class="s1">'event_relation_id'</span><span class="p">,</span> <span class="s1">'teller_id'</span><span class="p">),</span>
<span class="p">)</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">event_relation_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'event_relation.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">teller_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'teller.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">)</span>
</pre></div></td></tr></table></div>
<p>I'm very unsure whether some of this makes sense, but I'm feeling a little better about using inheritance rather than manually monomorphizing relationships like I was before.</p>
<p>PS: You know what category of feature would be great to think about with all of this stuff? Robust undo/redo support.</p>
<hr class="docutils" />
<p>Next week, I get that matrix filled in.</p>
Demiurgent Business 2018-06-132018-06-13T04:00:00-04:002018-06-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-13:/demiurgent-business-2018-06-13<p class="first last">"Okay, enough preparation, time to jump in! ... I needed more preparation."</p>
<p>In this post:</p>
<ul class="simple">
<li>Instead of sketching out all of play, I try to design the players, characters, and scenario.</li>
</ul>
<hr class="docutils" />
<p>There are four players, and for this sketch of play, each will only have one role.</p>
<p>I was thinking I'd get to the sketch this week, but that looks unlikely, so I'll just set the stage for now.</p>
<p>Hiro is the Spotlight, Dowd is the Stage-fright, Manny is Chaos, and Wonko is Order.
Counter-clockwise from Hiro, the players sit: Manny, Dowd, Wonko</p>
<p>Hiro and Dowd are controlling the confidence and self-doubt, respectively, of Iarat Harshleaf, an Elf Rock-Star.
Wonko and Manny are controlling the skepticism and interest in the supernatural, respectively, of Sammy L., the campaign's Demiurge.
In addition, Wonko is responsible for playing side characters from the conspiracy and supernatural world, while Manny plays side characters from the mundane world.</p>
<p>Furthermore, Manny, Dowd and Wonko are also playing as:</p>
<ul class="simple">
<li>Byra Moor, a Dragon Survivalist. Manny altered/replaced Byra's "cook a decent meal from anything" class ability based on her "iron stomach" racial ability, to get a "lethal chef" ability instead. I have no idea how to implement this, that's future me's job.</li>
<li>Andrea Hyde, an Orc Ninja. Andrea is in the theatre program, and uses her stealth in service of her role as stagehand.</li>
<li>Rocky "Lawrence" Hill, a Ghost Shaman. It says on the brainstorming document that Undead characters have to swap a class feature, but I don't have a good picture yet of what kind of stuff Ghosts and Shamans <em>do</em>.</li>
</ul>
<p>But these characters are not the focus, and therefore are not subject to the conflict resolution mechanics.</p>
<p>Sammy L. is the campaign's Demiurge, and I don't have a good sense of how he was designed.
Possibly, it's something along the lines of Durance.
Like, there are six facts about the Demiurge, and six about the Conspiracy (or maybe different counts).
Point is, there's some ideal set of attributes for the Demiurge and the Conspiracy, and some of them fail to hold.
My current challenge is identifying those attributes.</p>
<p>I was thinking of stuff like "can't see without their glasses" or something.</p>
<p>The goal I should have in putting this stuff together is to determine what "false assessments" would lend themselves to complicating player success, rather than opposing it.</p>
<p>Notes:</p>
<ul class="simple">
<li>Race and class names should have no spaces or punctuation, and use dashes to separate words.</li>
</ul>
<hr class="docutils" />
<p>Next week, I think I'd like to take a break.
I'll have to think about what I choose to do instead.</p>
State of Development2018-06-12T04:00:00-04:002018-06-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-12:/state-of-development<p class="first last">Well, that's, like, between seven and eight projects I'm interested in.</p>
<p>In this post:</p>
<ul class="simple">
<li>I look at all of my GitHub repositories from the last few years, and try to cut down on the cruft.</li>
</ul>
<hr class="docutils" />
<p>After working on composition software suddenly got me to release a reworked version of an old hobby project on GitHub, and do three releases of some other code in the space of a day, it occurred to me that I should write up all the software that I'm actually vaguely willing to take responsibility for.</p>
<p>On GitHub right now, I have:</p>
<ul>
<li><p class="first">Stuff I want to develop more in the near future:</p>
<blockquote>
<ul class="simple">
<li>python-structured-data: the code that I spent all of Sunday getting into a state of "no tests whatsoever, and what documentation exists is somehow outdated in places". Because it would improve some of my code right now, I'm really interested in getting it into a usable state, and writing mypy and pylint plugins so I can use it without having tox fail. In terms of supported versions, it should be able to offer partial functionality from 3.5.?-3.6.5, and full functionality from 3.6.6+.</li>
<li>divide-and-cover: should really be two repositories, probably. divide-and-cover is a wrapper around <a class="reference external" href="https://coverage.readthedocs.io/en/coverage-4.5.1/">Coverage.py</a> that exposes hooks to switch between multiple command-line executors, which is useful because it lets you define one executor per module, designate tests as applying to a particular module (with auto-discovery), and only collect coverage data in the source tree during an initial import step, and when you're running tests that target a particular module. This has the effect of localizing the coverage from a test module, so it's relatively straightforward to tell which test covered which line, and encouraging modules to have well-defined interfaces that can exercise all of their internals. The actual logic of what to create and when to switch is handled by plugins to test frameworks; currently there's a pytest plugin. It would be nice if the code, now that it's testable, could be tested on all supported versions of Python, or at least every version supported by Coverage.</li>
<li>class-namespaces: Inspired by <a class="reference external" href="https://erezsh.wordpress.com/2008/06/27/namespaces-lets-do-more-of-those-python-hackery/">a blog post</a> that I believe was targeted at Python 2, a Python 3 library that allows you to divide a class namespace into more namespaces, to represent situations where one class has multiple responsibilities. This is some pretty cool code, although nobody uses it that I know of. I've been meaning to remove some unneeded code, update the testing matrix, and look into using divide-and-cover. I want to look into writing plugins for static analysis tools so they don't get confused. It would be good to test this against all supported versions of Python 3.</li>
<li>jedi: I forked this to work on a <abbr title="pull request">PR</abbr> to add support for typing.NewType, and I keep on not working on that. But I want to do it, because it would be <em>really</em> useful.</li>
</ul>
</blockquote>
</li>
<li><p class="first">Stuff that I could potentially get back to developing...</p>
<blockquote>
<ul class="simple">
<li>log4l: "This branch is 72 commits ahead of Neopallium:master." ... Wow. I forked lualogging because it had all sorts of outstanding bugs and pull requests (protip: If you interact with an interface in version X, and it gets removed in version X+1, the null hypothesis is that it won't be back in version X+2. Just saying.), used it a little, and promptly stopped using it. I wouldn't say no to updating it if it ever has any active users, including me, but right now, I don't have any issues or pull requests to deal with on it. (Although someone did file an issue against lualogging the day after my most recent commit to log4l.)</li>
<li>lua-lineread: Did I ever push this? I guess not. The code on my laptop appears to have been adapted from <a class="reference external" href="https://github.com/luvit/lit/blob/master/deps/readline.lua">a module from the Luvit Invention Toolkit</a>.</li>
<li>lua-cmd: An attempt to port the Python stdlib cmd module to Lua. I ended up not pursuing whatever project I was writing this for, so it's in limbo right now.</li>
</ul>
</blockquote>
</li>
<li><p class="first">Stuff that I'm <em>definitely</em> not going to do anything with in the foreseeable future. (I archived all of these repositories after I made this list.)</p>
<blockquote>
<ul class="simple">
<li>cpython: I forked it to make a PR for some bug or other, then never actually got to the "writing a PR" part</li>
<li>Psi: forked over a year ago in an effort to investigate a crash that I kind of hope is fixed by now</li>
<li>ink: I think I forked it to make a PR for a bug fix?</li>
<li>test-box: the ideas behind this later went on to become divide-and-cover</li>
<li>super-duper-adventure: I played GitHub roulette two years ago, and tried (not very hard) to make some interactive fiction</li>
<li>unrest-tooling and project-incipience: I assume the whole "let's try to make a Mass-Effect-like in <a class="reference external" href="http://pyrodactyl.com/">Unrest</a>'s engine" idea isn't a thing right now, but I wouldn't say no to helping out with a completely fresh effort helmed by someone better than I am at project management, which seems like a low bar.</li>
<li>unrpyc: I think this was also a fork for a bug report.</li>
<li>md-haxebinding: I think I was trying to fix a bug???</li>
<li>haxe-titanium-api: I don't remember why I forked this, except that I never do as much mobile development as I have thought, at times, that I might potentially do.</li>
</ul>
</blockquote>
</li>
</ul>
<p>Just on my laptop, I've got a bunch of repositories, but the stuff I want to work on in the near future is:</p>
<ul class="simple">
<li>Conworld Codex: I've got a good feeling about its direction, and unlike the other two, it doesn't have a pressing need for Structured Data.</li>
<li>Homunculus: would benefit from Structured Data, but it's not super necessary.</li>
<li>Tiny Music: on hold until Structured Data has had a few more updates.</li>
</ul>
<p>And not yet made, I have plans to do a mixture of forks and PRs for <a class="reference external" href="https://github.com/ionelmc/cookiecutter-pylibrary">cookiecutter-pylibrary</a>.</p>
Algebraic Data Types 2018-06-112018-06-11T04:00:00-04:002018-06-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-11:/algebraic-data-types-2018-06-11<p class="first last">Don't you just love it how you can look away from automatically generated code for like five minutes, and all the dependencies rev and break it at once?</p>
<p>In this post:</p>
<ul class="simple">
<li>I release three new versions of my test coverage code so I can later write tests against it so I can make sure that parallel execution works so I can potentially restore it to the project .coveragerc, without breaking the continuous integration builds for the library that I'm writing to be able to express note values and rests etc. as a single data type.</li>
<li>This was one <em>heck</em> of a day.</li>
</ul>
<hr class="docutils" />
<p>Hi, I'm Max Chase, and welcome to Algebraic Data Types.
Things get a little silly around here with all these fancy class decorators, but one thing we all know is that the initial design was perfectly fine, and nothing will ever change tha—</p>
<p>Everything's changed...
It's been one week since mypy rejected my initial design as complete nonsense, and forced me to rewrite it using metaclasses.
The status is now red, because I have to care about "correctness" now, in Algebraic Data Types: Rewrite That Shit</p>
<p>... Ahem, anyway.</p>
<p>Looking at the code for what I'm now calling "Structured Data", it's obvious to me that I'm going to need plugins to get the various static analysis tools to trust what I've done.
And to have plugins, I need to publish it as a package.
I figured I'd have a look at what other people are doing for package layouts, and I decided to start with Ionel Cristian Maries's <a class="reference external" href="https://github.com/ionelmc/cookiecutter-pylibrary">cookiecutter-pylibrary</a>.
A lot of my ideas in my current layout are based on his blog post: <a class="reference external" href="https://blog.ionelmc.ro/2014/05/25/python-packaging/">Packaging a python library</a>.
So, rather than implement his suggestions manually, why not try using the template he put together?</p>
<p>After a little wrangling, and clicking through of defaults that I didn't entirely understand, and search-and-replace-based rewriting, I've converted the initial skeleton into something that works with my toolchain so far.
Let's take a look at it.
Starting with tox.ini, I see that there are various changes I'm going to want to make.</p>
<p>One is that... hm.
I think I actually do want the matrix, which is one of the things that defaulted to "no", because I want separate coverage and no-coverage runs.
... Oh.
There was a much easier way to do the thing I just did.
I'm learning things!
(For the record, I attempted to regenerate the project by deleting everything and fixing diffs I didn't want, when I should have just edited the .cookiecutterrc file, and done... something.)</p>
<p>Anyway, tox.ini.
For the purposes of <em>this</em> project, the code can only fully support Python 3.6.6+, and partially support 3.5.?+, and therefore partially support PyPy 3.
I don't know right now what that exact logic will look like in the code, but it does mean I need to drop a bunch of environments.
... I can't help but notice that the generated tox.ini doesn't set usedevelop for py36-cover.
Anyway, next up is the setenv.
Because I want to use my custom coverage runner, I'm removing the PYTHONPATH assignment.
To compensate, it needs a <tt class="docutils literal">__init__.py</tt> file in the tests directory.
My tests shouldn't need passenv, so I'm taking it out.
Now we're at dependencies.
Since Structured Data doesn't rely on any libraries, my concerns about requirements are right here.
I don't know for sure, so I'm going to hold off, but I've got a hunch that tracking requirements in pip requirements files rather than in tox.ini would be more maintainable.
Okay, the test commands are a big one.
It's invoking coverage through a test runner plugin, despite <a class="reference external" href="https://stackoverflow.com/questions/38237057/running-tests-from-coverage-py-vs-running-coverage-from-test-runner">that not being the recommended practice</a>.
For general use, I'd want to switch it to invoking coverage.
For my use, it's going to be the custom runner.
Let's see, nothing egregious, looks good, we get to the "check" section, and I think I'm going to want to expand on this later, but I don't feel like it right now.
Then I get to the <abbr title="continuous integration">CI</abbr> sections, which understandably don't get invoked by the default environments, but that implies that the CI config files must invoke them, which then implies that the environment config I was just tweaking has to be specified in the CI config files as well, which...</p>
<blockquote>
If you don't have a huge number of test environments then probably you don't need this.</blockquote>
<p>Is it shitty of me to argue that this might <em>also</em> come in handy if one wants to test <em>fewer</em> targets?
Looks like I'm going to need to regenerate the project <em>again</em>.</p>
<p>... Someday, I'll figure out how to do this stuff gracefully. Today is not that day.</p>
<p>Okay, I think I want to commit the changes to .cookiecutterrc, the ci directory (except that I need to back-propagate the changes I made to tox.ini).</p>
<p>So, I want to first cut down the matrix in setup.cfg.
Then apply the changes to the tox.ini file.
Then regenerate the config files.</p>
<p>I HOPE I'm done messing with this.
The next step now is to actually add the code.</p>
<p>I added the code.
Current status: just <em>incredibly</em> broken.
I'm going to give it a github project page first.</p>
<p>Getting ssh working right was a hassle (http(s) wasn't working), but things went a lot smoother when I discovered that I somehow actually remember the passphrase for an ssh key I generated over five years ago, and have never used since.</p>
<p>And now, I make various tiny code changes until the CI services stop yelling at me.</p>
<p>Looks like one problem is that coverage combine doesn't do anything useful under CI?
So I got rid of it.
Let's see what happens.</p>
<p>Travis <em>almost</em> works now.</p>
<p>Looks like having releases tagged on GitHub helps.
That one's on me.</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>It works <em>even better</em> when you do the release in the correct project!
(Addendum: and <strong>even better still</strong> when you call the release by the proper name.)</p>
<p>Okay, now my problem is that, I'd somehow failed to commit my .coveragerc file, and as a result, when I fixed that (so my local "check" runs would pass) that broke CI.
I'm going to assume that something's wrong with where divide-and-cover is putting results.</p>
<p>Okay, I actually don't really remember what happened between that paragraph and this one, but I've got a lot of green now, in spite of the fact that Appveyor continues to fail to upload coverage.
I've got an idea of what needs to change, but I want to think carefully about it before I rush into it.</p>
<p>Summary of big changes:</p>
<ul class="simple">
<li>Convert tests directory to module, remove PYTHONPATH. (Easy)</li>
<li>Use coverage runner instead of pytest plugin. (Trickier for me to get right)</li>
<li>Probably remove report step from CI config. (Did this a: ever do anything? and b: work at any point since Coverage 4.3? On the other hand, it's possible the divide-and-cover breaks this.)</li>
<li>I <em>think</em> codecov needs to be split up by platform. Not sure.</li>
</ul>
<hr class="docutils" />
<p>Next week, I try to get Appveyor working right, and update the documentation, which blithely assumes that its recommended tox invocations do remotely what they used to do.</p>
Weekly Roundup 2018-06-102018-06-10T04:00:00-04:002018-06-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-10:/weekly-roundup-2018-06-10<p class="first last">Bouncing to new topics again.</p>
<ul class="simple">
<li>Algebraic Data Types Monday: I started shaving another yak.</li>
<li>Free-Topic Tuesday: I talked about how <em>Candyman</em>'s sequel isn't a rehash, but also isn't especially compelling.</li>
<li>Demiurgent Business Wednesday: I rolled around roles for rolling in my mind, and got conflicted about conflict.</li>
<li>Conworld Codex Thursday: I created ludicrous yet useful software personas to guide development.</li>
<li>Draw a Box Friday: I drew the heck out of some lines. Still no boxes.</li>
<li>Homunculus Saturday: I finished part 10 of the tutorial. Three more parts to go!</li>
</ul>
Homunculus Devlog 2018-06-092018-06-09T04:00:00-04:002018-06-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-09:/homunculus-devlog-2018-06-09<p class="first last">You could probably make a very slow drinking game out of my complaints that this code has no tests.</p>
<p>In this post:</p>
<ul class="simple">
<li>I return to the tutorial, and discover that it's not a big deal to finish part 10 up.</li>
</ul>
<hr class="docutils" />
<p>Okay everyone, let's crack open part 10 of the <a class="reference external" href="http://rogueliketutorials.com/tdl/10">roguelike tutorial</a> and see if I wrote myself into any corners with my extensive rewrites.</p>
<p>I left off around "Now let's change our main loop. It'll display the main menu, and depending on the player's choice, it will either start a new game, load an existing one, or exit the program."</p>
<p>The main functions start off the same, but the tutorial is still setting up individual variables instead of initializing an object.
I'll add in these <tt class="docutils literal">show_*</tt> variables and see where it goes with this.
And the background image.
I'll try to splice in the rest of the logic after my "game = None" line; I sense things could get a little dicier now.
So, the rest of the tutorial main function is in a loop.
I'm going to make it "while True" until I work out how I want to apportion the responsibility for checking on the windows.
I notice that some of the names collide with stuff I've defined, so I'm going to prefix the tutorial variables with underscores for now.</p>
<p>Actually, I probably didn't need to do that.
Anyway, I got all the way to the end of the chapter, fired up the runner, and—</p>
<p>... Well, it didn't throw any exceptions, so technically it all works, right?</p>
<p>Right?
Yes, um, I should figure out why it didn't seem to enter the loop.
I have some ideas.</p>
<p>Okay, it turns out I left off a "not" when I was copying a conditional, which is a pretty big deal!
That doesn't explain why the input handling is flaky.
I'll check again and see what I find.</p>
<p>"AttributeError: 'NoneType' object has no attribute 'play'"
Yeah, this is my fault somehow.
Found the issue.
I'd been messing around with the logic, attempting "clever" stuff, and I clevered myself out of actually keeping the game loaded.</p>
<p>... Eh. Something's still wrong with the logic.
I want to get that fixed, then call it a week.</p>
<p>Time to stick print statements in places.
Okay, it's reading the load-game branch.
So the logic must be faulty.</p>
<p>Got it.
I'd glazed over one of the bits where "show_main_menu" gets set to False.
I would like to reiterate that this tutorial has no tests.</p>
<p>Here's where the main function stands now:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span>
<span class="normal">74</span>
<span class="normal">75</span>
<span class="normal">76</span>
<span class="normal">77</span>
<span class="normal">78</span>
<span class="normal">79</span>
<span class="normal">80</span>
<span class="normal">81</span>
<span class="normal">82</span>
<span class="normal">83</span>
<span class="normal">84</span>
<span class="normal">85</span>
<span class="normal">86</span>
<span class="normal">87</span>
<span class="normal">88</span>
<span class="normal">89</span></pre></div></td><td class="code"><div><pre><span></span><span class="c1"># To test: ... augh</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">tcod</span> <span class="kn">import</span> <span class="n">image_load</span>
<span class="kn">import</span> <span class="nn">tdl</span>
<span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">RESOURCES_DIR</span>
<span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">constants</span>
<span class="kn">from</span> <span class="nn">.input_handlers</span> <span class="kn">import</span> <span class="n">handle_main_menu</span>
<span class="kn">from</span> <span class="nn">.menus</span> <span class="kn">import</span> <span class="n">main_menu</span><span class="p">,</span> <span class="n">message_box</span>
<span class="kn">from</span> <span class="nn">.new_game</span> <span class="kn">import</span> <span class="n">new_game</span>
<span class="kn">from</span> <span class="nn">.save_load</span> <span class="kn">import</span> <span class="n">load_game</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">tdl</span><span class="o">.</span><span class="n">set_font</span><span class="p">(</span>
<span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">RESOURCES_DIR</span><span class="p">,</span> <span class="s1">'arial10x10.png'</span><span class="p">),</span>
<span class="n">greyscale</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">altLayout</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">root_console</span> <span class="o">=</span> <span class="n">tdl</span><span class="o">.</span><span class="n">init</span><span class="p">(</span>
<span class="n">constants</span><span class="o">.</span><span class="n">SCREEN_WIDTH</span><span class="p">,</span>
<span class="n">constants</span><span class="o">.</span><span class="n">SCREEN_HEIGHT</span><span class="p">,</span>
<span class="n">title</span><span class="o">=</span><span class="n">constants</span><span class="o">.</span><span class="n">WINDOW_TITLE</span><span class="p">)</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">tdl</span><span class="o">.</span><span class="n">Console</span><span class="p">(</span><span class="n">constants</span><span class="o">.</span><span class="n">SCREEN_WIDTH</span><span class="p">,</span> <span class="n">constants</span><span class="o">.</span><span class="n">SCREEN_HEIGHT</span><span class="p">)</span>
<span class="n">panel</span> <span class="o">=</span> <span class="n">tdl</span><span class="o">.</span><span class="n">Console</span><span class="p">(</span><span class="n">constants</span><span class="o">.</span><span class="n">SCREEN_WIDTH</span><span class="p">,</span> <span class="n">constants</span><span class="o">.</span><span class="n">PANEL_HEIGHT</span><span class="p">)</span>
<span class="n">show_main_menu</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">show_load_error_message</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">main_menu_background_image</span> <span class="o">=</span> <span class="n">image_load</span><span class="p">(</span>
<span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">RESOURCES_DIR</span><span class="p">,</span> <span class="s1">'menu_background.png'</span><span class="p">))</span>
<span class="n">game</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">while</span> <span class="ow">not</span> <span class="n">tdl</span><span class="o">.</span><span class="n">event</span><span class="o">.</span><span class="n">is_window_closed</span><span class="p">():</span>
<span class="n">user_input</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">for</span> <span class="n">event</span> <span class="ow">in</span> <span class="n">tdl</span><span class="o">.</span><span class="n">event</span><span class="o">.</span><span class="n">get</span><span class="p">():</span>
<span class="k">if</span> <span class="n">event</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="s1">'KEYDOWN'</span><span class="p">:</span>
<span class="n">user_input</span> <span class="o">=</span> <span class="n">event</span>
<span class="k">break</span>
<span class="k">if</span> <span class="n">show_main_menu</span><span class="p">:</span>
<span class="n">main_menu</span><span class="p">(</span>
<span class="n">root_console</span><span class="p">,</span>
<span class="n">main_menu_background_image</span><span class="p">,</span>
<span class="n">constants</span><span class="o">.</span><span class="n">SCREEN_WIDTH</span><span class="p">,</span>
<span class="n">constants</span><span class="o">.</span><span class="n">SCREEN_HEIGHT</span><span class="p">,</span>
<span class="n">constants</span><span class="o">.</span><span class="n">COLORS</span><span class="p">)</span>
<span class="k">if</span> <span class="n">show_load_error_message</span><span class="p">:</span>
<span class="n">message_box</span><span class="p">(</span>
<span class="n">root_console</span><span class="p">,</span>
<span class="s1">'No save game to load'</span><span class="p">,</span>
<span class="mi">50</span><span class="p">,</span>
<span class="n">constants</span><span class="o">.</span><span class="n">SCREEN_WIDTH</span><span class="p">,</span>
<span class="n">constants</span><span class="o">.</span><span class="n">SCREEN_HEIGHT</span><span class="p">)</span>
<span class="n">tdl</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
<span class="n">action</span> <span class="o">=</span> <span class="n">handle_main_menu</span><span class="p">(</span><span class="n">user_input</span><span class="p">)</span>
<span class="k">if</span> <span class="n">show_load_error_message</span> <span class="ow">and</span> <span class="n">action</span><span class="p">:</span>
<span class="n">show_load_error_message</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">elif</span> <span class="n">action</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'new_game'</span><span class="p">):</span>
<span class="n">game</span> <span class="o">=</span> <span class="n">new_game</span><span class="p">()</span>
<span class="k">elif</span> <span class="n">action</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'load_saved_game'</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">constants</span><span class="o">.</span><span class="n">SAVE_FILE</span><span class="p">)</span> <span class="k">as</span> <span class="n">save_data</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">save_data</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="k">if</span> <span class="n">data</span><span class="p">:</span>
<span class="n">game</span> <span class="o">=</span> <span class="n">load_game</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">FileNotFoundError</span><span class="p">:</span>
<span class="k">pass</span>
<span class="n">show_load_error_message</span> <span class="o">=</span> <span class="ow">not</span> <span class="n">game</span>
<span class="k">elif</span> <span class="n">action</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'exit_game'</span><span class="p">):</span>
<span class="k">break</span>
<span class="n">show_main_menu</span> <span class="o">=</span> <span class="ow">not</span> <span class="n">game</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">root_console</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
<span class="n">con</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
<span class="n">panel</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
<span class="n">game</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="n">root_console</span><span class="p">,</span> <span class="n">con</span><span class="p">,</span> <span class="n">panel</span><span class="p">)</span>
<span class="n">game</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">show_main_menu</span> <span class="o">=</span> <span class="kc">True</span>
</pre></div></td></tr></table></div>
<hr class="docutils" />
<p>Next week, new functionality on several levels!
Also, I think I want to redo the component system.</p>
Draw a Box 2018-06-082018-06-08T04:00:00-04:002018-06-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-08:/draw-a-box-2018-06-08<p class="first last">Swirly.</p>
<p>In this post:</p>
<ul class="simple">
<li>Making good progress. Hopefully this is in fact training my muscle memory.</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>15 lines on June 1. OH GOD THE PAPER IS LIMP FROM THE HUMIDITY.</li>
<li>15 lines on June 2. Doing better.</li>
<li>15 lines on June 3.</li>
<li>15 lines on June 4.</li>
<li>15 lines on June 5, very short and quickly.</li>
<li>15 lines on June 6.</li>
<li>15 lines on June 7. The pen seems to be somewhat better at putting ink on my skin, than on paper...</li>
</ul>
<p>For a total of 105 lines this week,
390 lines on the first sheet since I started counting,
and 150 lines on the second sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Conworld Codex 2018-06-072018-06-07T04:00:00-04:002018-06-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-07:/conworld-codex-2018-06-07<p class="first last">I'd blame allergies, allergy medication, or lack of sleep for some of this post, but honestly, I'm just like that.</p>
<p>In this post:</p>
<ul class="simple">
<li>I make a test that is not very good.</li>
<li>I start using software personas as a medium for shitposting.</li>
<li>I derive useful tests and design insights from my deliberately absurd simulacra.</li>
</ul>
<hr class="docutils" />
<p>I'll be honest, the details of what I was working on kind of fell out of my head, because I was so into algebraic data type stuff.
But fortunately, I can just look at last week's post, and, oh yeah, the idea was to start writing tests to prove out the workflows for this app.</p>
<p>I added a basic test.</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">test_app</span><span class="p">(</span><span class="n">main</span><span class="p">,</span> <span class="n">models</span><span class="p">,</span> <span class="n">db_session</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Test app functionality."""</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">main</span><span class="o">.</span><span class="n">App</span><span class="p">(</span><span class="n">db_session</span><span class="p">)</span>
<span class="n">event</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'test'</span><span class="p">)</span>
<span class="n">db_session</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>
<span class="n">event_window</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">canonicalize</span><span class="p">(</span><span class="n">main</span><span class="o">.</span><span class="n">EventWindow</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="n">event</span><span class="p">))</span>
<span class="k">assert</span> <span class="n">event_window</span><span class="o">.</span><span class="n">contained_by</span>
<span class="k">assert</span> <span class="n">event_window</span><span class="o">.</span><span class="n">preceded_by</span>
<span class="k">assert</span> <span class="n">event_window</span><span class="o">.</span><span class="n">followed_by</span>
<span class="k">assert</span> <span class="n">event_window</span><span class="o">.</span><span class="n">contains</span>
<span class="k">assert</span> <span class="n">event_window</span><span class="o">.</span><span class="n">topics</span>
</pre></div>
<p>The big win from writing this test was realizing that I had the fields on EventWindow the wrong way around, so I switched them to have app first.
That way, every one of these classes is parent, then relevant database object(s).</p>
<p>I tried to write more tests, but thinking about content-free names, like I was at first, was a total drag.
I need to have something that resembles real data.
I don't feel like using Linked Seas (remember that?) stuff in the test code, so I'm going to do some user persona-y stuff.</p>
<p>Brian is a numinous data-being perfectly in harmony with whatever interface I happen to have slapped together this week, and xie wishes to write up the background of the various bardic songs that will be written out in full in xer upcoming fantasy pentadecalogy, <em>The Lost Secrets of the Hidden Kingdom of the Seven Songs of Um</em>.
Brian decides to first create a Teller, Friodemus the Wise.
The astute reader of the project's source code (I actually can't remember if I've pasted the relevant bits) will realize that there's no interface for managing Tellers, specifically.</p>
<p>I also have no specific idea how to organize the creation functionality within the interface.
Let's make a persona with different priorities.
Ace Slipstream is a time-displaced refugee from a future dystopia.
She uses Conworld Codex version 99.8.7rc18 to chronicle the confusing tangle of events leading to the mysterious Omicron Inception, which converted most of Cymerica to computronium slag, and also to write her weekly shopping list.
Let's have a look at her incredibly polished interface.
It must somehow reflect the underlying database model, in which there are three basic types, that relate to each other in various ways:</p>
<ul class="simple">
<li>Events are the simplest, consisting of just a name.</li>
<li>Topics and Tellers are almost as simple, consisting of a name, but also an optional one-to-one connection between the two.</li>
<li>In other words, some Tellers are Topics, and some Tellers are not Topics, and some Topics are Tellers, and some Topics are not Tellers, but no Teller is more than one Topic, and no Topic is more than one Teller.</li>
</ul>
<p>Looking at this, I kind of wonder if the Topic-Teller relation should be instead represented in a table with a pair of unique <abbr title="foreign key">FKs</abbr>, but I'll have to put that on the back burner until I have a better idea what difference it would make.</p>
<p>I'll try to address the Events first, because that should be a strict subset of the issues that Tellers and Topics will present.
Without applying some form of heuristic to the connecting data, there's no obvious way to organize Events beyond key functions of the numeric id and the name.</p>
<p>One possible way that Ace's GUI could look is something like current MediaWiki, with a front page and a search box.
I'm not quite sure what the front page should look like, but it seems to me there should be some way to represent or visualize the scope of a codex.
Statistics, perhaps?
Do I want, in Wx terminology, multiple Frames, or do I want to have one Frame per open Codex?</p>
<p>Thinking over this, it is clear that, for now, I want to put the functionality at the level of the App (which I might rename to Codex).
So, let's add a test for Brian's functionality.
Given an App (constructed by the test), Brian creates Friodemus the Wise, and gets back a TellerWindow that describes Friodemus.</p>
<p>Here's the flow I went with: there's a new_window method on the App object (which probably should be Codex), which creates a TellerWindow with no associated name.
The write only gets queued after the name gets set by a method on the TellerWindow.</p>
<p>I'm really, really liking how SQLAlchemy is designed.
I'm not doing great at navigating the documentation all the time, but it seems like there's a good chance I can get things to work, pretty much just by thinking really hard about what would make sense.</p>
<p>Brian's and Ace's personas gave me a good way forward for designing the App/Codex, but before I get too far, I want to think about how to handle the lifetimes of these auxiliary classes I'm tossing around.</p>
<hr class="docutils" />
<p>Next week, I revisit the logic of when the support classes are live and reachable, and then start working on growing the interfaces outwards.</p>
Demiurgent Business 2018-06-062018-06-06T04:00:00-04:002018-06-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-06:/demiurgent-business-2018-06-06<p class="first last">In a mildy cruel turn of fate, I'm feeling a little conflicted about some of this.</p>
<p>In this post:</p>
<ul class="simple">
<li>I lay out some important questions to address for conflict resolution systems.</li>
<li>I start answering them, lean a little on Polaris, then start differentiating the idea from Polaris.</li>
<li>I ponder some possible changes to this, like making every roll opposed.</li>
</ul>
<hr class="docutils" />
<p>Haha, I let this post go <em>way</em> too late.</p>
<p>Here's what I worked out last week: I think that conflict resolution with a dice pool that you can grow by invoking relationships sounds interesting.
There are a number of questions that need to be answered to make sure I'm using it in a way that makes sense:</p>
<ul class="simple">
<li>What contexts is conflict resolution likely to come up in?</li>
<li>What are the consequences of success?</li>
<li>What are the consequences of failure?</li>
<li>What decides whether a player can use a relationship to improve their chances?</li>
<li>Are there any caps on bonuses?</li>
<li>Can anything impose a penalty?</li>
<li>Are there degrees of success?</li>
</ul>
<p>I think that bonds should be temporarily used up when they grant a bonus, and refreshed by some ritual phrase.</p>
<p>The bonus concept represents the character motivating themselves to greater heights, so it's almost like conflict resolution should come into play when the character's strength of ... character ... is in question.
Like the opposing force to the player is a questioning of their commitment/determination/whatever.
Like they're testing the player character, instead of strictly trying to defeat them.
I like the idea of <a class="reference external" href="http://www.tao-games.com/polaris/">Polaris</a>'s four player roles, but I wonder if they could be shifted around.
Like, the current player and the Adversary, and the equivalent of the Moons somehow jointly control the Demiurge.</p>
<p>Confidence versus self-doubt, with the background detail of the Demiurge influencing the struggle.</p>
<p>I have this idea that the Demiurge somehow sets the scenario to start with, by proposing a surface-level mission for the club.
Based on this, the player characters then have some true mission they're trying to accomplish at the same time.
This can be to sabotage the surface mission, to ensure it goes easily, to slow it down, to cover up something that it would uncover, to mitigate the inevitable fallout...</p>
<p>If we have the assumption that success is inevitable, and what's in question is whether it's dignified or embarrassing, then the player and the adversary can represent those two forms of resolution.</p>
<p>In Polaris, the Moons represent all background characters not directly part of the conflict (and their player's protagonist), dividing up the characters by relationship to the Heart's character, and then by gender.
Now, if the Confidence and Doubt are two opposed forces within a character, can the other players be opposed forces within the Demiurge?
Interest in supernatural vs belief in rationality?
Holding out hope for miracles in the face of mundanity, vs clinging to an ordered world in the face of absurdity.</p>
<p>Anyway, these ideas cast the outcome of conflicts as a particular force predominating, so the answer of what the success/failure means is, that the narrative will go towards that as a result.</p>
<p>I wonder if the division of roles means that the Doubt can level up neuroses or something.
There are a couple directions to go in, if that's under consideration.</p>
<p>I think I don't want degrees of success.
One player or the other gets what they want, and that's the outcome.</p>
<p>I think at this point, I've got some interesting ideas, but I don't know how well they fit the overall diraction I want to take things.</p>
<hr class="docutils" />
<p>Next week, I attempt to do some example play, and extrapolate rules from the transcript.</p>
Horror Movie Reflections: Candyman & Candyman: Farewell to the Flesh2018-06-05T04:00:00-04:002018-06-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-05:/horror-movie-reflections-candyman-candyman-farewell-to-the-flesh<p class="first last">If Candyman was going to have a sequel, it deserved a better one.</p>
<p>In this post:</p>
<ul class="simple">
<li>I contrast <em>Candyman</em> and <em>Candyman: Farewell to the Flesh</em>, and am generally sad that <em>Candyman</em> got such an... unexceptional movie for a sequel.</li>
</ul>
<hr class="docutils" />
<p>My wife and I have been watching a bunch of horror movies lately, and some of those horror movies have been sequels.
Now, it's kind of trite to point out when a piecemeal franchise, like a lot of horror series, ends up with continuity glitches.
(There's also what happened with Friday the 13th, a series that had so many time skips, a fan timeline puts a movie released before I was born, as taking place when I was in middle school.)</p>
<p>But that's not what I want to talk about now.
We saw <em>Candyman</em>, and just recently saw <em>Candyman: Farewell to the Flesh</em>, and I was really struck by how, there was nothing egregious going on with narrative continuity, but in terms of continuity of style, it was amazingly different.
It's as if it's a sequel in terms of story, but not a spiritual successor.</p>
<p><em>Candyman</em> focuses on a graduate student who investigates an urban legend, gets repeatedly in over her head, has strained relationships with her husband and the people she interviews, reversals, betrayals, problems outside of the supernatural elements, and for most of the movie, it would not be inconsistent to suppose that she's actually just hallucinating everything that happens.
In terms of cinematography, <em>Candyman</em> also has establishing shots from high up, which is perhaps an obvious thing to do when Philip Glass is doing your soundtrack, but it works.</p>
<p><em>Candyman: Farewell to the Flesh</em> is about a schoolteacher who has a great life, except for having to deal with her brother, who is seemingly crazy, but only because the Candyman keeps killing people.
Sometimes people aren't happy to see her, but then someone else shows up and smooths things over.
Instead of aerial shots, we get parades, because it's Mardi Gras, because it's in New Orleans.
Pretty much every problem in Anne's life traces back to the Candyman in some way.
While Helen never really convinced anyone who didn't already believe in the Candyman, Anne gets bailed out at one point because he killed a man on camera, very obviously.
When the Candyman was doing stuff while not showing up on camera in <em>Candyman</em>, he was making Helen look crazy.
When the Candyman did stuff while not showing up on camera in <em>Farewell to the Flesh</em>, it's just like, well, I guess ghosts are real.
Anne still gets blamed for some of the murders, but given that some of them obviously involved supernatural strength, it's not entirely clear why.</p>
<p>I'm not sure about this, but I also feel like <em>Farewell to the Flesh</em> was way more willing to move away from Anne than <em>Candyman</em> was Helen.
<em>Candyman</em> was mostly Helen doing something, or people reacting to Helen.
<em>Farewell to the Flesh</em> flashed back to the death of Daniel Robitaille, seemingly whenever it felt like it.
It kind of felt like <em>Farewell to the Flesh</em> was treating the mythos as an end rather than a means.</p>
<p>All in all, I'm just wondering what happened here, exactly.
Did the fact that the production staff differed some between movies mean that the idea of what made the first movie really interesting was lost, and so the style of the sequel was in some sense uncorrelated with the first movie?
I think that seems likely, and mostly I just think that's kind of a shame.</p>
<p>(I should maybe figure out a topic schedule that would let me develop ideas like this a bit more, maybe decide later to not post at such a breakneck pace, but the problem is, I still <em>want</em> to go this fast.)</p>
Algebraic Data Types 2018-06-042018-06-04T04:00:00-04:002018-06-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-04:/algebraic-data-types-2018-06-04<p class="first last">Surprise! New category.</p>
<p>In this post:</p>
<ul class="simple">
<li>I start thinking about music theory, composition, synthesis, then veer off into some hobby work from months ago.</li>
</ul>
<hr class="docutils" />
<p>I'm going to try to speed through setting up intervals and such a little, because I want to try scraping together a prototype for writing MIDI files.
Long term, I'd like to try doing my own synthesis because that seems cool, but it's easier to synthesize a note when you've decided just how a note is represented.</p>
<p>Ugh, thinking about how to do this, I feel like I'm getting bitten by the fact that I never did get my <abbr title="algebraic data type">ADT</abbr> code into a workable state.
I think I'll switch gears a little, to getting that working.
I've come to the conclusion that I want to try using dataclasses-style class decorators, because attempting to use metaclasses was really unpleasant.
I'd like to paste some old code to help make sense of all the stuff I'm saying, but the old code I have doesn't really make sense.
Instead, I'll sketch out how I'd like to use the new thing.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span></pre></div></td><td class="code"><div><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Generic</span><span class="p">,</span> <span class="n">TypeVar</span>
<span class="kn">from</span> <span class="nn">wherever</span> <span class="kn">import</span> <span class="n">algebraic</span>
<span class="n">R</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">TypeVar</span><span class="p">(</span><span class="s1">'R'</span><span class="p">)</span>
<span class="n">E</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">TypeVar</span><span class="p">(</span><span class="s1">'E'</span><span class="p">)</span>
<span class="nd">@algebraic</span>
<span class="k">class</span> <span class="nc">Result</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">R</span><span class="p">,</span> <span class="n">E</span><span class="p">]):</span>
<span class="n">Ok</span><span class="p">:</span> <span class="n">R</span>
<span class="n">Err</span><span class="p">:</span> <span class="n">E</span>
</pre></div></td></tr></table></div>
<p>The decorator should do most of the same work as the dataclass decorator, but with some differences:</p>
<ul class="simple">
<li>The instances are always immutable, and backed by tuples.</li>
<li>The generated <tt class="docutils literal">__new__</tt> method is a factory, which creates instances of generated classes that are a subclass of the decorated class.</li>
<li>No field customization; the types are the types.</li>
<li>No subclassing.</li>
</ul>
<p>Let's see what methods I want to generate:</p>
<ul class="simple">
<li><tt class="docutils literal">__new__</tt></li>
<li><tt class="docutils literal">__repr__</tt> (if not present)</li>
<li>comparison methods, with similar logic to dataclasses</li>
<li>hashing, with a cut-down version of the logic</li>
<li>probably an <tt class="docutils literal">__init_subclass__</tt></li>
<li>something with docstrings</li>
</ul>
<p>Let's get started on this.</p>
<p>Okay, I've got code that resembles a stripped-down version of dataclasses, but because the layout is more constrained, there's less generated code.
I think for now, I'm going to avoid flexibility until I discover I need it, so all algebraic classes will be comparable, orderable, and hashable with no control.
Consumers will be able to tweak the repr logic, because that's not a big deal.</p>
<p>Actually, I really should put the customization in, but I want to consider carefully how this is going to work.
If the algebraic code defines equality, then it "might as well" define hashing.
If the algebraic code does not define equality, then it should not define hashing.
I'm currently using equality in some pattern-matching code, but I could just use the functions directly...
Except actually, it should be fine.
What I'm going to do differently is, I'm going to say that the methods get added in bundles.</p>
<p>Except I just realized that my implementation of ordering is very wrong.
When I get this into a repository, I'm going to strip it out.</p>
<p>Regardless, aside from that hiccup, I'm sure the code I wrote over the course of two days is perfect in every way.</p>
<p>... Okay, so I need to use the descriptor protocol to get at the name of wrapped methods.
Fine.</p>
<p>... Okay, it coughs up bizarre errors if I attempt to actually instantiate generic classes.
It looks like this is a result of some kind of optimization attempt that bypasses the normal <abbr title="method resolution order">MRO</abbr>.
The problem appears to be that I'm creating subclasses of a generic class, that add a built-in class as a superclass.
I believe I can hack around this by looking for an attribute, and changing it if it exists.</p>
<p>I was incorrect.
The problem was that I wasn't explicitly delegating <tt class="docutils literal">__new__</tt> calls through a base class, which I think confused things more than it should have?
Anyway, next I removed the <tt class="docutils literal">__init_subclass__</tt> stuff, because I forgot that specializing a generic class in Python subclasses it.
... Actually, I can keep that in, I just need to restrict the scope.</p>
<p>All right, here's where things ended up.
My main issue right now is, I made this in part to work well with typing information, and mypy reacts to my carefully crafted annotations like I threw garbage in its face.
I can't actually use this in my projects until I work out how to alter mypy's interpretation of it.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span>
<span class="normal">102</span>
<span class="normal">103</span>
<span class="normal">104</span>
<span class="normal">105</span>
<span class="normal">106</span>
<span class="normal">107</span>
<span class="normal">108</span>
<span class="normal">109</span>
<span class="normal">110</span>
<span class="normal">111</span>
<span class="normal">112</span>
<span class="normal">113</span>
<span class="normal">114</span>
<span class="normal">115</span>
<span class="normal">116</span>
<span class="normal">117</span>
<span class="normal">118</span>
<span class="normal">119</span>
<span class="normal">120</span>
<span class="normal">121</span>
<span class="normal">122</span>
<span class="normal">123</span>
<span class="normal">124</span>
<span class="normal">125</span>
<span class="normal">126</span>
<span class="normal">127</span>
<span class="normal">128</span>
<span class="normal">129</span>
<span class="normal">130</span>
<span class="normal">131</span>
<span class="normal">132</span>
<span class="normal">133</span>
<span class="normal">134</span>
<span class="normal">135</span>
<span class="normal">136</span>
<span class="normal">137</span>
<span class="normal">138</span>
<span class="normal">139</span>
<span class="normal">140</span>
<span class="normal">141</span>
<span class="normal">142</span>
<span class="normal">143</span>
<span class="normal">144</span>
<span class="normal">145</span>
<span class="normal">146</span>
<span class="normal">147</span>
<span class="normal">148</span>
<span class="normal">149</span>
<span class="normal">150</span>
<span class="normal">151</span>
<span class="normal">152</span>
<span class="normal">153</span>
<span class="normal">154</span>
<span class="normal">155</span>
<span class="normal">156</span>
<span class="normal">157</span>
<span class="normal">158</span>
<span class="normal">159</span>
<span class="normal">160</span>
<span class="normal">161</span>
<span class="normal">162</span>
<span class="normal">163</span>
<span class="normal">164</span>
<span class="normal">165</span>
<span class="normal">166</span>
<span class="normal">167</span>
<span class="normal">168</span>
<span class="normal">169</span>
<span class="normal">170</span>
<span class="normal">171</span>
<span class="normal">172</span>
<span class="normal">173</span>
<span class="normal">174</span>
<span class="normal">175</span>
<span class="normal">176</span>
<span class="normal">177</span>
<span class="normal">178</span>
<span class="normal">179</span>
<span class="normal">180</span>
<span class="normal">181</span>
<span class="normal">182</span>
<span class="normal">183</span>
<span class="normal">184</span>
<span class="normal">185</span>
<span class="normal">186</span>
<span class="normal">187</span>
<span class="normal">188</span>
<span class="normal">189</span>
<span class="normal">190</span>
<span class="normal">191</span>
<span class="normal">192</span>
<span class="normal">193</span>
<span class="normal">194</span>
<span class="normal">195</span>
<span class="normal">196</span>
<span class="normal">197</span>
<span class="normal">198</span>
<span class="normal">199</span>
<span class="normal">200</span>
<span class="normal">201</span>
<span class="normal">202</span>
<span class="normal">203</span>
<span class="normal">204</span>
<span class="normal">205</span>
<span class="normal">206</span>
<span class="normal">207</span>
<span class="normal">208</span>
<span class="normal">209</span>
<span class="normal">210</span>
<span class="normal">211</span>
<span class="normal">212</span>
<span class="normal">213</span>
<span class="normal">214</span>
<span class="normal">215</span>
<span class="normal">216</span>
<span class="normal">217</span>
<span class="normal">218</span>
<span class="normal">219</span>
<span class="normal">220</span>
<span class="normal">221</span>
<span class="normal">222</span>
<span class="normal">223</span>
<span class="normal">224</span>
<span class="normal">225</span>
<span class="normal">226</span>
<span class="normal">227</span>
<span class="normal">228</span>
<span class="normal">229</span>
<span class="normal">230</span>
<span class="normal">231</span>
<span class="normal">232</span>
<span class="normal">233</span>
<span class="normal">234</span>
<span class="normal">235</span>
<span class="normal">236</span>
<span class="normal">237</span>
<span class="normal">238</span>
<span class="normal">239</span>
<span class="normal">240</span>
<span class="normal">241</span>
<span class="normal">242</span>
<span class="normal">243</span>
<span class="normal">244</span>
<span class="normal">245</span>
<span class="normal">246</span>
<span class="normal">247</span>
<span class="normal">248</span>
<span class="normal">249</span>
<span class="normal">250</span>
<span class="normal">251</span>
<span class="normal">252</span>
<span class="normal">253</span>
<span class="normal">254</span>
<span class="normal">255</span>
<span class="normal">256</span>
<span class="normal">257</span>
<span class="normal">258</span>
<span class="normal">259</span>
<span class="normal">260</span>
<span class="normal">261</span>
<span class="normal">262</span>
<span class="normal">263</span>
<span class="normal">264</span>
<span class="normal">265</span>
<span class="normal">266</span>
<span class="normal">267</span>
<span class="normal">268</span>
<span class="normal">269</span>
<span class="normal">270</span>
<span class="normal">271</span>
<span class="normal">272</span>
<span class="normal">273</span>
<span class="normal">274</span>
<span class="normal">275</span>
<span class="normal">276</span>
<span class="normal">277</span>
<span class="normal">278</span>
<span class="normal">279</span>
<span class="normal">280</span>
<span class="normal">281</span>
<span class="normal">282</span>
<span class="normal">283</span>
<span class="normal">284</span>
<span class="normal">285</span>
<span class="normal">286</span>
<span class="normal">287</span>
<span class="normal">288</span>
<span class="normal">289</span>
<span class="normal">290</span>
<span class="normal">291</span>
<span class="normal">292</span>
<span class="normal">293</span>
<span class="normal">294</span>
<span class="normal">295</span>
<span class="normal">296</span>
<span class="normal">297</span>
<span class="normal">298</span>
<span class="normal">299</span>
<span class="normal">300</span>
<span class="normal">301</span>
<span class="normal">302</span>
<span class="normal">303</span>
<span class="normal">304</span>
<span class="normal">305</span>
<span class="normal">306</span>
<span class="normal">307</span>
<span class="normal">308</span>
<span class="normal">309</span>
<span class="normal">310</span>
<span class="normal">311</span>
<span class="normal">312</span>
<span class="normal">313</span>
<span class="normal">314</span>
<span class="normal">315</span>
<span class="normal">316</span>
<span class="normal">317</span>
<span class="normal">318</span>
<span class="normal">319</span>
<span class="normal">320</span>
<span class="normal">321</span>
<span class="normal">322</span>
<span class="normal">323</span>
<span class="normal">324</span>
<span class="normal">325</span>
<span class="normal">326</span>
<span class="normal">327</span>
<span class="normal">328</span>
<span class="normal">329</span>
<span class="normal">330</span>
<span class="normal">331</span>
<span class="normal">332</span>
<span class="normal">333</span>
<span class="normal">334</span>
<span class="normal">335</span>
<span class="normal">336</span>
<span class="normal">337</span>
<span class="normal">338</span>
<span class="normal">339</span>
<span class="normal">340</span>
<span class="normal">341</span>
<span class="normal">342</span>
<span class="normal">343</span>
<span class="normal">344</span>
<span class="normal">345</span>
<span class="normal">346</span>
<span class="normal">347</span>
<span class="normal">348</span>
<span class="normal">349</span>
<span class="normal">350</span>
<span class="normal">351</span>
<span class="normal">352</span>
<span class="normal">353</span>
<span class="normal">354</span>
<span class="normal">355</span>
<span class="normal">356</span>
<span class="normal">357</span>
<span class="normal">358</span>
<span class="normal">359</span>
<span class="normal">360</span>
<span class="normal">361</span>
<span class="normal">362</span>
<span class="normal">363</span>
<span class="normal">364</span>
<span class="normal">365</span>
<span class="normal">366</span>
<span class="normal">367</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""Class decorator for defining abstract data types."""</span>
<span class="kn">import</span> <span class="nn">collections</span>
<span class="kn">import</span> <span class="nn">keyword</span>
<span class="kn">import</span> <span class="nn">typing</span>
<span class="k">def</span> <span class="nf">_as_tuple</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="o">-></span> <span class="nb">tuple</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Convert non-tuple values to a 1-tuple, return tuples unchanged."""</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
<span class="n">value</span> <span class="o">=</span> <span class="p">(</span><span class="n">value</span><span class="p">,)</span>
<span class="k">return</span> <span class="n">value</span>
<span class="k">def</span> <span class="nf">_name</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">function</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the name of a function accessed through a descriptor."""</span>
<span class="k">return</span> <span class="n">function</span><span class="o">.</span><span class="fm">__get__</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="bp">cls</span><span class="p">)</span><span class="o">.</span><span class="vm">__name__</span>
<span class="k">def</span> <span class="nf">_set_new_functions</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">*</span><span class="n">functions</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Attempt to set the attributes corresponding to the functions on cls.</span>
<span class="sd"> If any attributes are already defined, fail before setting, and return the</span>
<span class="sd"> already-defined name.</span>
<span class="sd"> """</span>
<span class="k">for</span> <span class="n">function</span> <span class="ow">in</span> <span class="n">functions</span><span class="p">:</span>
<span class="k">if</span> <span class="n">_name</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">function</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">:</span>
<span class="k">return</span> <span class="n">_name</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">function</span><span class="p">)</span>
<span class="k">for</span> <span class="n">function</span> <span class="ow">in</span> <span class="n">functions</span><span class="p">:</span>
<span class="nb">setattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">_name</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">function</span><span class="p">),</span> <span class="n">function</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">class</span> <span class="nc">MatchFailure</span><span class="p">(</span><span class="ne">BaseException</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""An exception that signals a failure in ADT matching."""</span>
<span class="k">def</span> <span class="nf">desugar</span><span class="p">(</span><span class="n">constructor</span><span class="p">:</span> <span class="nb">type</span><span class="p">,</span> <span class="n">instance</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">)</span> <span class="o">-></span> <span class="nb">tuple</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the inside of an ADT instance, given its constructor."""</span>
<span class="c1"># I really do want to match exactly, I swear.</span>
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">instance</span><span class="p">)</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">constructor</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">MatchFailure</span>
<span class="k">return</span> <span class="nb">tuple</span><span class="o">.</span><span class="fm">__getitem__</span><span class="p">(</span><span class="n">instance</span><span class="p">,</span> <span class="nb">slice</span><span class="p">(</span><span class="kc">None</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_unpack</span><span class="p">(</span><span class="n">instance</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">)</span> <span class="o">-></span> <span class="nb">tuple</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the inside of any ADT instance.</span>
<span class="sd"> This function is not meant for general use.</span>
<span class="sd"> """</span>
<span class="k">return</span> <span class="n">desugar</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">instance</span><span class="p">),</span> <span class="n">instance</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_algebraic_base</span><span class="p">(</span><span class="n">obj</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="vm">__class__</span><span class="p">,</span> <span class="s1">'__algebraic_base__'</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">AlgebraicConstructor</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Base class for ADT Constructor classes."""</span>
<span class="vm">__slots__</span> <span class="o">=</span> <span class="p">()</span>
<span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Explicitly forward to base class."""</span>
<span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__qualname__</span> <span class="o">+</span> <span class="p">(</span>
<span class="sa">f</span><span class="s1">'(</span><span class="si">{</span><span class="s2">", "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">repr</span><span class="p">(</span><span class="n">item</span><span class="p">)</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">item</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">_unpack</span><span class="p">(</span><span class="bp">self</span><span class="p">))</span><span class="si">}</span><span class="s1">)'</span><span class="p">)</span>
<span class="k">def</span> <span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">if</span> <span class="n">other</span><span class="o">.</span><span class="vm">__class__</span> <span class="ow">is</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">:</span>
<span class="k">return</span> <span class="n">_unpack</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">==</span> <span class="n">_unpack</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="k">if</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="ow">is</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">return</span> <span class="bp">NotImplemented</span>
<span class="k">def</span> <span class="fm">__ne__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">if</span> <span class="n">other</span><span class="o">.</span><span class="vm">__class__</span> <span class="ow">is</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">:</span>
<span class="k">return</span> <span class="n">_unpack</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">!=</span> <span class="n">_unpack</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="k">if</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="ow">is</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">return</span> <span class="bp">NotImplemented</span>
<span class="k">def</span> <span class="fm">__lt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">if</span> <span class="n">other</span><span class="o">.</span><span class="vm">__class__</span> <span class="ow">is</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">:</span>
<span class="k">return</span> <span class="n">_unpack</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o"><</span> <span class="n">_unpack</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="k">if</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="ow">is</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">order</span> <span class="o">=</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__subclass_order__</span>
<span class="n">self_index</span> <span class="o">=</span> <span class="n">order</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">)</span>
<span class="n">other_index</span> <span class="o">=</span> <span class="n">order</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="vm">__class__</span><span class="p">)</span>
<span class="k">return</span> <span class="n">self_index</span> <span class="o"><</span> <span class="n">other_index</span>
<span class="k">return</span> <span class="bp">NotImplemented</span>
<span class="k">def</span> <span class="fm">__le__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">if</span> <span class="n">other</span><span class="o">.</span><span class="vm">__class__</span> <span class="ow">is</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">:</span>
<span class="k">return</span> <span class="n">_unpack</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o"><=</span> <span class="n">_unpack</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="k">if</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="ow">is</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">order</span> <span class="o">=</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__subclass_order__</span>
<span class="n">self_index</span> <span class="o">=</span> <span class="n">order</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">)</span>
<span class="n">other_index</span> <span class="o">=</span> <span class="n">order</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="vm">__class__</span><span class="p">)</span>
<span class="k">return</span> <span class="n">self_index</span> <span class="o"><=</span> <span class="n">other_index</span>
<span class="k">return</span> <span class="bp">NotImplemented</span>
<span class="k">def</span> <span class="fm">__gt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">if</span> <span class="n">other</span><span class="o">.</span><span class="vm">__class__</span> <span class="ow">is</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">:</span>
<span class="k">return</span> <span class="n">_unpack</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">></span> <span class="n">_unpack</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="k">if</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="ow">is</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">order</span> <span class="o">=</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__subclass_order__</span>
<span class="n">self_index</span> <span class="o">=</span> <span class="n">order</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">)</span>
<span class="n">other_index</span> <span class="o">=</span> <span class="n">order</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="vm">__class__</span><span class="p">)</span>
<span class="k">return</span> <span class="n">self_index</span> <span class="o">></span> <span class="n">other_index</span>
<span class="k">return</span> <span class="bp">NotImplemented</span>
<span class="k">def</span> <span class="fm">__ge__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">if</span> <span class="n">other</span><span class="o">.</span><span class="vm">__class__</span> <span class="ow">is</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">:</span>
<span class="k">return</span> <span class="n">_unpack</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">>=</span> <span class="n">_unpack</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="k">if</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="ow">is</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">order</span> <span class="o">=</span> <span class="n">_algebraic_base</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__subclass_order__</span>
<span class="n">self_index</span> <span class="o">=</span> <span class="n">order</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">)</span>
<span class="n">other_index</span> <span class="o">=</span> <span class="n">order</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="vm">__class__</span><span class="p">)</span>
<span class="k">return</span> <span class="n">self_index</span> <span class="o">>=</span> <span class="n">other_index</span>
<span class="k">return</span> <span class="bp">NotImplemented</span>
<span class="k">def</span> <span class="fm">__hash__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">hash</span><span class="p">(</span><span class="n">_unpack</span><span class="p">(</span><span class="bp">self</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_make_constructor</span><span class="p">(</span><span class="n">_cls</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">length</span><span class="p">,</span> <span class="n">subclasses</span><span class="p">,</span> <span class="n">subclass_order</span><span class="p">):</span>
<span class="k">class</span> <span class="nc">Constructor</span><span class="p">(</span><span class="n">_cls</span><span class="p">,</span> <span class="n">AlgebraicConstructor</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Auto-generated subclass of an ADT."""</span>
<span class="vm">__slots__</span> <span class="o">=</span> <span class="p">()</span>
<span class="n">__algebraic_base__</span> <span class="o">=</span> <span class="n">_cls</span>
<span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">!=</span> <span class="n">length</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span>
<span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span>
<span class="n">Constructor</span><span class="o">.</span><span class="vm">__name__</span> <span class="o">=</span> <span class="n">name</span>
<span class="n">Constructor</span><span class="o">.</span><span class="vm">__qualname__</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">_cls</span><span class="o">.</span><span class="vm">__qualname__</span><span class="si">}</span><span class="s1">.</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s1">'</span>
<span class="n">subclasses</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Constructor</span><span class="p">)</span>
<span class="nb">setattr</span><span class="p">(</span><span class="n">_cls</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">Constructor</span><span class="p">)</span>
<span class="n">subclass_order</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">Constructor</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_process_class</span><span class="p">(</span><span class="n">_cls</span><span class="p">,</span> <span class="n">_repr</span><span class="p">,</span> <span class="n">eq</span><span class="p">,</span> <span class="n">order</span><span class="p">):</span>
<span class="k">if</span> <span class="n">order</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">eq</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">'eq must be true if order is true'</span><span class="p">)</span>
<span class="n">lengths</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">subclasses</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
<span class="n">subclass_order</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="bp">cls</span> <span class="ow">in</span> <span class="nb">reversed</span><span class="p">(</span><span class="n">_cls</span><span class="o">.</span><span class="vm">__mro__</span><span class="p">):</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="s1">'__annotations__'</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">lengths</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">_as_tuple</span><span class="p">(</span><span class="n">value</span><span class="p">))</span>
<span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">length</span> <span class="ow">in</span> <span class="n">lengths</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">_make_constructor</span><span class="p">(</span><span class="n">_cls</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">length</span><span class="p">,</span> <span class="n">subclasses</span><span class="p">,</span> <span class="n">subclass_order</span><span class="p">)</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">__init_subclass__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">issubclass</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">subclasses</span><span class="p">)):</span>
<span class="k">raise</span> <span class="ne">TypeError</span>
<span class="c1"># Allow it to go through otherwise, because Generic.</span>
<span class="k">return</span> <span class="nb">super</span><span class="p">(</span><span class="n">_cls</span><span class="p">,</span> <span class="bp">cls</span><span class="p">)</span><span class="o">.</span><span class="n">__init_subclass__</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="n">_cls</span><span class="o">.</span><span class="n">__init_subclass__</span> <span class="o">=</span> <span class="n">__init_subclass__</span>
<span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">args</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">cls</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">subclasses</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">TypeError</span>
<span class="k">return</span> <span class="nb">super</span><span class="p">(</span><span class="n">_cls</span><span class="p">,</span> <span class="bp">cls</span><span class="p">)</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span>
<span class="k">if</span> <span class="n">_set_new_functions</span><span class="p">(</span><span class="n">_cls</span><span class="p">,</span> <span class="fm">__new__</span><span class="p">):</span>
<span class="n">base__new__</span> <span class="o">=</span> <span class="n">_cls</span><span class="o">.</span><span class="fm">__new__</span>
<span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">args</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">cls</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">subclasses</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">TypeError</span>
<span class="k">return</span> <span class="n">base__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span>
<span class="n">_cls</span><span class="o">.</span><span class="fm">__new__</span> <span class="o">=</span> <span class="fm">__new__</span>
<span class="k">if</span> <span class="n">_repr</span><span class="p">:</span>
<span class="n">_set_new_functions</span><span class="p">(</span><span class="n">_cls</span><span class="p">,</span> <span class="fm">__repr__</span><span class="p">)</span>
<span class="n">equality_methods_were_set</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">if</span> <span class="n">eq</span><span class="p">:</span>
<span class="n">equality_methods_were_set</span> <span class="o">=</span> <span class="ow">not</span> <span class="n">_set_new_functions</span><span class="p">(</span>
<span class="n">_cls</span><span class="p">,</span> <span class="fm">__eq__</span><span class="p">,</span> <span class="fm">__ne__</span><span class="p">)</span>
<span class="k">if</span> <span class="n">equality_methods_were_set</span><span class="p">:</span>
<span class="n">_cls</span><span class="o">.</span><span class="fm">__hash__</span> <span class="o">=</span> <span class="fm">__hash__</span>
<span class="k">if</span> <span class="n">order</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">equality_methods_were_set</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
<span class="s2">"Can't add ordering methods if equality methods are provided."</span><span class="p">)</span>
<span class="n">collision</span> <span class="o">=</span> <span class="n">_set_new_functions</span><span class="p">(</span><span class="n">_cls</span><span class="p">,</span> <span class="fm">__lt__</span><span class="p">,</span> <span class="fm">__le__</span><span class="p">,</span> <span class="fm">__gt__</span><span class="p">,</span> <span class="fm">__ge__</span><span class="p">)</span>
<span class="k">if</span> <span class="n">collision</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s1">'Cannot overwrite attribute </span><span class="si">{</span><span class="n">collision</span><span class="si">}</span><span class="s1"> '</span>
<span class="sa">f</span><span class="s1">'in class </span><span class="si">{</span><span class="n">_cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s1">. Consider using '</span>
<span class="s1">'functools.total_ordering'</span><span class="p">)</span>
<span class="n">_cls</span><span class="o">.</span><span class="n">__subclass_order__</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">subclass_order</span><span class="p">)</span>
<span class="k">return</span> <span class="n">_cls</span>
<span class="k">def</span> <span class="nf">algebraic</span><span class="p">(</span><span class="n">_cls</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="nb">repr</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">eq</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Decorate a class to be an algebraic data type."""</span>
<span class="k">def</span> <span class="nf">wrap</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return the processed class."""</span>
<span class="k">return</span> <span class="n">_process_class</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="nb">repr</span><span class="p">,</span> <span class="n">eq</span><span class="p">,</span> <span class="n">order</span><span class="p">)</span>
<span class="k">if</span> <span class="n">_cls</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="n">wrap</span>
<span class="k">return</span> <span class="n">wrap</span><span class="p">(</span><span class="n">_cls</span><span class="p">)</span>
<span class="n">DISCARD</span> <span class="o">=</span> <span class="nb">object</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">Matcher</span><span class="p">(</span><span class="nb">tuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""A matcher that binds a value to a name."""</span>
<span class="vm">__slots__</span> <span class="o">=</span> <span class="p">()</span>
<span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="k">if</span> <span class="n">name</span> <span class="o">==</span> <span class="s1">'_'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">DISCARD</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">name</span><span class="o">.</span><span class="n">isidentifier</span><span class="p">():</span>
<span class="k">raise</span> <span class="ne">ValueError</span>
<span class="k">if</span> <span class="n">keyword</span><span class="o">.</span><span class="n">iskeyword</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">ValueError</span>
<span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="p">(</span><span class="n">name</span><span class="p">,))</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return the name of the matcher."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">def</span> <span class="fm">__matmul__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">return</span> <span class="n">AsMatcher</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">AsMatcher</span><span class="p">(</span><span class="nb">tuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""A matcher that contains further bindings."""</span>
<span class="vm">__slots__</span> <span class="o">=</span> <span class="p">()</span>
<span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">matcher</span><span class="p">:</span> <span class="n">Matcher</span><span class="p">,</span> <span class="n">match</span><span class="p">):</span>
<span class="k">if</span> <span class="n">matcher</span> <span class="ow">is</span> <span class="n">DISCARD</span><span class="p">:</span>
<span class="k">return</span> <span class="n">match</span>
<span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="p">(</span><span class="n">matcher</span><span class="p">,</span> <span class="n">match</span><span class="p">))</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">matcher</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return the left-hand-side of the as-match."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">match</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return the right-hand-side of the as-match."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">names</span><span class="p">(</span><span class="n">target</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return every name bound by a target."""</span>
<span class="n">name_list</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">names_seen</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
<span class="n">to_process</span> <span class="o">=</span> <span class="p">[</span><span class="n">target</span><span class="p">]</span>
<span class="k">while</span> <span class="n">to_process</span><span class="p">:</span>
<span class="n">item</span> <span class="o">=</span> <span class="n">to_process</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">Matcher</span><span class="p">):</span>
<span class="k">if</span> <span class="n">item</span><span class="o">.</span><span class="n">name</span> <span class="ow">in</span> <span class="n">names_seen</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span>
<span class="n">names_seen</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="n">name_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">AsMatcher</span><span class="p">):</span>
<span class="n">to_process</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">match</span><span class="p">)</span>
<span class="n">to_process</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">matcher</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">AlgebraicConstructor</span><span class="p">):</span>
<span class="n">to_process</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="n">_unpack</span><span class="p">(</span><span class="n">item</span><span class="p">)))</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
<span class="n">to_process</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="n">item</span><span class="p">))</span>
<span class="k">yield from</span> <span class="n">name_list</span>
<span class="k">def</span> <span class="nf">_match</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
<span class="n">match_dict</span> <span class="o">=</span> <span class="n">collections</span><span class="o">.</span><span class="n">OrderedDict</span><span class="p">()</span>
<span class="n">to_process</span> <span class="o">=</span> <span class="p">[(</span><span class="n">target</span><span class="p">,</span> <span class="n">value</span><span class="p">)]</span>
<span class="k">while</span> <span class="n">to_process</span><span class="p">:</span>
<span class="n">target</span><span class="p">,</span> <span class="n">value</span> <span class="o">=</span> <span class="n">to_process</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
<span class="k">if</span> <span class="n">target</span> <span class="ow">is</span> <span class="n">DISCARD</span><span class="p">:</span>
<span class="k">pass</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="n">Matcher</span><span class="p">):</span>
<span class="k">if</span> <span class="n">target</span><span class="o">.</span><span class="n">name</span> <span class="ow">in</span> <span class="n">match_dict</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span>
<span class="n">match_dict</span><span class="p">[</span><span class="n">target</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="n">AsMatcher</span><span class="p">):</span>
<span class="n">to_process</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">target</span><span class="o">.</span><span class="n">match</span><span class="p">,</span> <span class="n">value</span><span class="p">))</span>
<span class="n">to_process</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">target</span><span class="o">.</span><span class="n">matcher</span><span class="p">,</span> <span class="n">value</span><span class="p">))</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="n">AlgebraicConstructor</span><span class="p">):</span>
<span class="n">to_process</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="n">_unpack</span><span class="p">(</span><span class="n">target</span><span class="p">)),</span>
<span class="nb">reversed</span><span class="p">(</span><span class="n">desugar</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">target</span><span class="p">),</span> <span class="n">value</span><span class="p">))))</span>
<span class="k">elif</span> <span class="p">(</span><span class="nb">isinstance</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">)</span> <span class="ow">and</span>
<span class="n">target</span><span class="o">.</span><span class="vm">__class__</span> <span class="ow">is</span> <span class="n">value</span><span class="o">.</span><span class="vm">__class__</span> <span class="ow">and</span>
<span class="nb">len</span><span class="p">(</span><span class="n">target</span><span class="p">)</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="n">value</span><span class="p">)):</span>
<span class="n">to_process</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="n">target</span><span class="p">),</span> <span class="nb">reversed</span><span class="p">(</span><span class="n">value</span><span class="p">)))</span>
<span class="k">elif</span> <span class="n">target</span> <span class="o">!=</span> <span class="n">value</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">MatchFailure</span>
<span class="k">return</span> <span class="n">match_dict</span>
<span class="k">def</span> <span class="nf">get_values</span><span class="p">(</span><span class="n">dct</span><span class="p">,</span> <span class="n">keys</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Unpack a dict, in order."""</span>
<span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">keys</span><span class="p">:</span>
<span class="k">yield</span> <span class="n">dct</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
<span class="k">class</span> <span class="nc">ValueMatcher</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Given a value, attempt to match against a target."""</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">value</span>
<span class="bp">self</span><span class="o">.</span><span class="n">matches</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">def</span> <span class="nf">match</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">target</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Match against target, generating a set of bindings."""</span>
<span class="k">try</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">matches</span> <span class="o">=</span> <span class="n">_match</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">)</span>
<span class="k">except</span> <span class="n">MatchFailure</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">matches</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">matches</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">R</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">TypeVar</span><span class="p">(</span><span class="s1">'R'</span><span class="p">)</span>
<span class="n">E</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">TypeVar</span><span class="p">(</span><span class="s1">'E'</span><span class="p">)</span>
<span class="nd">@algebraic</span>
<span class="k">class</span> <span class="nc">Result</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">Generic</span><span class="p">[</span><span class="n">R</span><span class="p">,</span> <span class="n">E</span><span class="p">]):</span>
<span class="w"> </span><span class="sd">"""Experimental generic ADT."""</span>
<span class="n">Ok</span><span class="p">:</span> <span class="n">R</span>
<span class="n">Err</span><span class="p">:</span> <span class="n">E</span>
<span class="n">my_result</span><span class="p">:</span> <span class="n">Result</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="n">Result</span><span class="o">.</span><span class="n">Ok</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
</pre></div></td></tr></table></div>
<hr class="docutils" />
<p>Next week, or possibly sooner, I try to figure out how to write a mypy plugin.</p>
Weekly Roundup 2018-06-032018-06-03T04:00:00-04:002018-06-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-03:/weekly-roundup-2018-06-03<p class="first last">I dunno man, it's a roundup. I'm tired.</p>
<ul class="simple">
<li>Music Theory Monday: I rewrote the BeatStructure code, then swapped it for the "time_signature" field.</li>
<li>Free-Topic Tuesday: I started working on an NFA-based regex engine. It should probably have ∞% more tests than it actually does.</li>
<li>Demiurgent Business Wednesday: I read an RPG about conspiracy theories, and things... started to fall into place.</li>
<li>Conworld Codex Thursday: I wrote a test for basic SQLAlchemy behavior, and explained some of the libraries I've written for myself.</li>
<li>Draw a Box Friday: More lines...</li>
<li>Homunculus Saturday: I converted from an enum to classes, and made various other improvements.</li>
</ul>
Homunculus Devlog 2018-06-022018-06-02T04:00:00-04:002018-06-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-02:/homunculus-devlog-2018-06-02<p class="first last">More incremental progress.</p>
<p>In this post:</p>
<ul class="simple">
<li>I remove the magic methods shenanigans from the Visitor class.</li>
<li>I rewrite the GameStates enum into several classes.</li>
<li>I replace instance equality with isinstance checks.</li>
<li>I remove the GameStates class.</li>
<li>I complain about the weather.</li>
</ul>
<hr class="docutils" />
<p>I've decided on a course of action to take with the Visitor code: pull back from dependency injection stuff, and see how far I can get with, like, distinct ClassVisitor and ValueVisitor subclasses of an abstract Visitor class.</p>
<p>Okay, implementing that part was easy.
Next up, redoing the GameStates stuff.
Okay, first, rewrite the deserializer to use getattr.
Then: redo every enum state as NamedTuples with a single "name" field, and stick an instance in the enum class, which should no longer be an enum class.</p>
<p>It's late and intolerably muggy, so I'll just go that far for now.
... And I broke serialization, because now the different states are no longer instances of GameStates.
I think I'll just get this over with and make a separate serializer for each, each targeting its own yaml field.
And then I realized that I only ever actually serialize one GameState, because you can't save while it's not your turn, you're dead, or you're in a menu.
So that's sort of convenient for me.</p>
<p>Okay, time to try converting the Visitors.
Wasn't too big a deal; I just had to be on my toes.</p>
<p>And then I went and replaced the equality checks with isinstance checks, and got the instances using the constructor (complete with default values) instead of the holder class, which is enough to let me remove the holder class and not worry about that.
Now, each isinstance, and some of the Visitors, represent possible methods I'd want to define on the classes.</p>
<p>However, I need to take a break from this rewrite, because I need to think about how I'm going to handle inheritance.
typing.NamedTuple is a little obnoxious when it comes to integrating with Python's type system.
I'm really tempted to break out dataclasses, which are coming up in the soon-to-be-released Python 3.7, but have an earlier-versions-of-Python-3 package on PyPI.</p>
<p>Anyway, thinking about using preview versions of stuff that hits general release in a few weeks is probably a sign that I should break here.
Let's take a look at the new Visitor classes.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span></pre></div></td><td class="code"><div><pre><span></span><span class="c1"># To test: just import.</span>
<span class="kn">import</span> <span class="nn">abc</span>
<span class="kn">import</span> <span class="nn">typing</span>
<span class="k">class</span> <span class="nc">Visitor</span><span class="p">(</span><span class="n">abc</span><span class="o">.</span><span class="n">ABC</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">state_methods</span> <span class="o">=</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">default</span> <span class="o">=</span> <span class="n">default</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_default</span>
<span class="nd">@abc</span><span class="o">.</span><span class="n">abstractmethod</span>
<span class="k">def</span> <span class="nf">matches</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
<span class="k">def</span> <span class="nf">_default</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span><span class="sa">f</span><span class="s1">'Not implemented for </span><span class="si">{</span><span class="n">state</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">bind</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">inner_bind</span><span class="p">(</span><span class="n">function</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">state_methods</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="n">function</span>
<span class="k">return</span> <span class="n">function</span>
<span class="k">return</span> <span class="n">inner_bind</span>
<span class="k">def</span> <span class="nf">visit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">for</span> <span class="n">match</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">matches</span><span class="p">(</span><span class="n">state</span><span class="p">):</span>
<span class="k">if</span> <span class="n">match</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">state_methods</span><span class="p">:</span>
<span class="n">visitor</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">state_methods</span><span class="p">[</span><span class="n">match</span><span class="p">]</span>
<span class="k">break</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">visitor</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">default</span>
<span class="k">return</span> <span class="n">visitor</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">ClassVisitor</span><span class="p">(</span><span class="n">Visitor</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">matches</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">):</span>
<span class="k">yield from</span> <span class="n">state</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__mro__</span>
<span class="k">class</span> <span class="nc">ValueVisitor</span><span class="p">(</span><span class="n">Visitor</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">matches</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">):</span>
<span class="k">yield</span> <span class="n">state</span>
</pre></div></td></tr></table></div>
<p>This is probably better than last week.
I'll have to think about it more.</p>
<hr class="docutils" />
<p>Next week, I take stock of the current state of things, and see where I can do myself the most good with rewrites.
Looking over the tutorial, I see that it might make sense to start following it again, especially since I seem to have done some similar things as it, independently.</p>
Draw a Box 2018-06-012018-06-01T04:00:00-04:002018-06-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-06-01:/draw-a-box-2018-06-01<p class="first last">Slow and steady. More slow than steady...</p>
<p>In this post:</p>
<ul class="simple">
<li>Starting the second sheet. Hopefully this one takes like a month, tops.</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>15 lines on May 25</li>
<li>15 lines on May 26. I got a new set of pens, and the one I tried promptly went flaky. I'll be so glad to try some other type of pen later.</li>
<li>15 lines on May 27.</li>
<li>15 lines on May 28. This completes the first sheet of paper.</li>
<li>15 lines on May 29. New sheet of paper, curved lines, and somewhat inauspiciously, I started this after a shower I took to deal with the heat, so now the paper is wet. The ink is supposed to be okay with this, but I don't think the paper is.</li>
<li>15 lines on May 30. The paper is pretty beat up already, but it's still taking ink, so that's good enough for me.</li>
<li>15 lines on May 31.</li>
</ul>
<p>For a total of 105 lines this week,
390 lines on the first sheet since I started counting,
and 45 lines on the second sheet.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Conworld Codex 2018-05-312018-05-31T04:00:00-04:002018-05-31T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-31:/conworld-codex-2018-05-31<p class="first last">The important thing is I accomplished something.</p>
<p>In this post:</p>
<ul class="simple">
<li>I set a modest goal for testing SQLAlchemy's functionality.</li>
<li>I achieve that goal.</li>
<li>I explain a weird bit that has nothing to do with SQLAlchemy.</li>
</ul>
<hr class="docutils" />
<p>As of last week, I should be able to construct <abbr title="Object Relational Mapping">ORM</abbr> instances for test purposes.
One thing I do when coming to grips with a new library, is to write tests for really obvious things to test my understanding of the library.</p>
<p>Currently, a lot of my design rests on the assumption that ORM instances obtained from different calls will compare equal if they refer to the same row, and generally be in synch with each other.</p>
<p>I've got a test that <em>appears</em> to demonstrate this well enough.
I put the test in a "dependencies" testing subdirectory, and moved the fixtures from last week to the top level so the tests would have access to them.
Here's how it looks in the test proper.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""Tests of the understanding of SQLAlchemy."""</span>
<span class="n">DIVIDE_AND_COVER_CONFIG</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span>
<span class="n">auto_detect</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">test_create_session</span><span class="p">(</span><span class="n">db_session</span><span class="p">,</span> <span class="n">models</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Make sure I understand how this stuff works."""</span>
<span class="n">test_event</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'test'</span><span class="p">)</span>
<span class="n">db_session</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">test_event</span><span class="p">)</span>
<span class="n">query_result</span><span class="p">,</span> <span class="o">=</span> <span class="n">db_session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Event</span><span class="p">)</span><span class="o">.</span><span class="n">filter_by</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'test'</span><span class="p">)</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="k">assert</span> <span class="n">test_event</span> <span class="o">==</span> <span class="n">query_result</span>
<span class="k">assert</span> <span class="nb">hash</span><span class="p">(</span><span class="n">test_event</span><span class="p">)</span> <span class="o">==</span> <span class="nb">hash</span><span class="p">(</span><span class="n">query_result</span><span class="p">)</span>
</pre></div></td></tr></table></div>
<p>Having basic tests like this is helpful for debugging, because it gives me a baseline for saying "okay, that assumption I made about how this works, is probably true".</p>
<p>The way SQLAlchemy works is definitely intriguing, after working with Django for so long.
Instead of save methods and query managers on the model classes, everything gets routed through the session object, which has a straightforward interface, so far.
Feels less template-y.</p>
<p>If you're one of the approximately seven billion people who haven't used my coverage runner library and plugin <a class="footnote-reference" href="#footnote-1" id="footnote-reference-1">[1]</a>, "Divide and Cover", you're probably wondering what the deal is with the global dictionary up there.
The basic idea of Divide and Cover is that each test module, with a few exceptions, should test a single source module, and vice versa.
As a consequence of this idea (in other words, if you don't agree with the premise, that's a sign you shouldn't use the library), I wish that the coverage from a given test module should only count toward the associated source module.
Divide and Cover delivers on this idea using a custom coverage runner and a pytest plugin <a class="footnote-reference" href="#footnote-2" id="footnote-reference-2">[2]</a>, to create and switch between multiple coverage objects.
For various reasons, a test writer might want to add coverage of multiple modules (straightforward generated code, for instance), or disable source module discovery (as here, where the test is essentially just an experiment about the behavior of a third-party library).
This is implemented using a dictionary with named keys, because I wanted to avoid requiring an import, since it's supposed to be possible to run the tests without installing Divide and Cover.</p>
<hr class="docutils" />
<p>Next week, now that I understand the basics of writing SQLAlchemy code, I start writing tests in the UI coordination... layer... thing.</p>
<table class="docutils footnote" frame="void" id="footnote-1" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-1">[1]</a></td><td>I'm not blaming anyone. There's no documentation, and the implementation has some shortcomings that I haven't gotten around to remedying.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="footnote-2" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-2">[2]</a></td><td>There shouldn't be a dependency on pytest itself; any sufficiently expressive test runner plugin framework should work.</td></tr>
</tbody>
</table>
Demiurgent Business 2018-05-302018-05-30T04:00:00-04:002018-05-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-30:/demiurgent-business-2018-05-30<p class="first last">It's cool, "THEY", I haven't actually played most of the games I've looked at.</p>
<p>In this post:</p>
<ul class="simple">
<li>I go over Conspiracist, and analyze it a little.</li>
<li>I start trying to put ideas into practice.</li>
</ul>
<hr class="docutils" />
<p>I'm going to try to run through Conspiracist, then start thinking about structure of play, where randomness should figure into this, stuff like that.</p>
<div class="section" id="conspiracist">
<h2>Conspiracist</h2>
<ul class="simple">
<li>Conspiracist has a simple character creation process that allows the players to quickly design their low-level underling character. (Conspiracist is geared toward one-shot play.)</li>
<li>Characters are a race, which can provide special abilities, advantages, and disadvantages; some specialties, which provide the ability to always succeed on certain actions; occupations, which represent the character's "day job" and gives them special abilities; and a motivation, which explains why the character is working for a vast conspiracy.</li>
<li>The Mission is the overall unit of organization in play. A Mission is divided into the Planning state, and the Execution.</li>
<li>In the Planning state, the players receive a cryptic clue from the Controller, and brainstorm what it could mean. When they have come to agreement over the nature of their mission, they conclude the Mission Briefing with the ritual phrase "Illuminati confirmed". After this, the Controller decides how correct they are.</li>
<li>The Execution is "the rest of the game". Working from a rough outline devised in the Mission Briefing, the players attempt to reach their goals, while the Controller runs the NPCs, and introduces escalating levels of weirdness into the overall scenario.</li>
<li>Conspiracist allows for player characters to oppose each other, though there probably needs to be several plot twists executed before that makes sense, to oppose NPCs, and adverse circumstances.</li>
<li>These actions are resolved by one die roll per player (2 dice pick highest, if the player is meaningfully aided in the attempt). There are no frameworks for modifiers, though some of the occupations and one race provide +/-1 to some rolls. Instead, if the player can justify applying a specialty, they succeed without complications instead of rolling.</li>
<li>Failing a roll results in a Complication, which should be some meaningful obstacle that changes things for the players in some way. (The examples of play also indicate that "and weird stuff happens" is also acceptable on a success, so long as it doesn't interfere with the fact that the player achieved their immediate objective.)</li>
</ul>
<p>Because the die rolls typically are even odds, the overall effect is that the player characters have narrow areas of specialization, and in most other circumstances are wildly out of their depth.</p>
<p>While the Mission Briefing is patterned on wild free-association in the service of working out conspiracies, I'm kind of flip-flopping on the question of whether "conspiracies" has particular thematic support in the bulk of gameplay.
On the one hand, there are no rules whatsoever for dealing with characters who know too much, but on the other hand, the action resolution rules are designed to bring in unexpected wrinkles at least half the time.
It's kind of like, there's so much gonzo weirdness, that some kind of super-science occult conspiracy is the best possible framing device to contextualize it.</p>
<hr class="docutils" />
<p>Thinking about cooperative actions gives me some ideas for how to handle advancement in Demiurgent Business.
Two characters can share any number of Bonds, based on some shared experience, and if that bond is relevant, the other character can add one die to a dice pool, if they aid in an action, or if that action is meant to benefit them.</p>
<p>So, we might have something like "Ame-san saved me from the sea monster that attacked the hot springs. <a class="footnote-reference" href="#footnote-1" id="footnote-reference-1">[1]</a> I'll give it my all to protect her from this Micro-Alien attack!" and that gives J. Doe there an extra die in his roll to fend off the Micro-Aliens.</p>
<p>I need to think more about how I want to actually <em>use</em> dice pools, particularly since I want to make determining the target number very simple, perhaps a constant.</p>
<hr class="docutils" />
<p>Next week, I stop, or at least take a break from, reading and trying to analyze existing games, and try to apply my analysis to designing Demiurgent Business.</p>
<table class="docutils footnote" frame="void" id="footnote-1" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-1">[1]</a></td><td>It was a very small sea monster, clearly, and probably made up for it by being extra-monstrous.</td></tr>
</tbody>
</table>
</div>
re-Inventing The Wheel2018-05-29T04:00:00-04:002018-05-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-29:/re-inventing-the-wheel<p class="first last">There's a certain amount of irregularity.</p>
<p>In this post:</p>
<ul class="simple">
<li>I talk about some somewhat advanced topics (regular expression parsing, arena-based allocation, unicode segmentation), then butcher them with code.</li>
</ul>
<hr class="docutils" />
<p>Every once in a while, I implement data structures or algorithms from scratch, as kind of a relaxation thing.
Sometimes, the results are pretty useless, but I still enjoy working through it.</p>
<p>This time around, I want to try implementing the regex data structures and algorithms from <a class="reference external" href="https://swtch.com/~rsc/regexp/regexp1.html">Regular Expression Matching Can Be Simple And Fast</a>.
While it's in Python, it's probably not going to be terribly fast in general, compared to lower-level implementations, but again, working through it.</p>
<p>There are some divergences I'm putting in from the article.
One is that I want to look at <a class="reference external" href="http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries">extended grapheme clusters</a> instead of individual bytes.
And, related to that, I want to shape the data in a different way; proper polymorphism, and arena-based access.</p>
<p>Arenas are something I learned about from reading Rust blogs, but I'm pretty sure they're a pre-existing concept.
The basic idea is that, in something like a graph data structure, instead of having individual nodes point to each other, have them refer to an index within an underlying structure.
I think there are varying degrees of sophistication that can be employed here, but I just used indices.
Anyway, doing this solves a few issues.
One is that stuff like Python's tuples aren't "supposed" to be able to do self-reference.
(I believe there's some kind of hacky thing that can be done with the C API, but I'm pretty sure it's a bad idea.)
Another issue is limiting the scope of what a node points to.
Arena-based graphs don't make it any more obvious, given a node, just how big a subgraph that node points to, but seeing the arena does place an upper bound, which is something.</p>
<p>The idea I have behind using graphemes is, I want to mess around with unicode-aware regular expressions, and how that works out in practice.
Might be an interesting use of this, to, like, parse a unicode-aware programming language.</p>
<p>For now, my major concern is figuring out how to address the glaring edge case in the code.</p>
<p>I might come back to this later, but for now, I'm just going to paste in the full source code, complete with obnoxious unhandled edge case.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span>
<span class="normal">102</span>
<span class="normal">103</span>
<span class="normal">104</span>
<span class="normal">105</span>
<span class="normal">106</span>
<span class="normal">107</span>
<span class="normal">108</span>
<span class="normal">109</span>
<span class="normal">110</span>
<span class="normal">111</span>
<span class="normal">112</span>
<span class="normal">113</span>
<span class="normal">114</span>
<span class="normal">115</span>
<span class="normal">116</span>
<span class="normal">117</span>
<span class="normal">118</span>
<span class="normal">119</span>
<span class="normal">120</span>
<span class="normal">121</span>
<span class="normal">122</span>
<span class="normal">123</span>
<span class="normal">124</span>
<span class="normal">125</span>
<span class="normal">126</span>
<span class="normal">127</span>
<span class="normal">128</span>
<span class="normal">129</span>
<span class="normal">130</span>
<span class="normal">131</span>
<span class="normal">132</span>
<span class="normal">133</span>
<span class="normal">134</span>
<span class="normal">135</span>
<span class="normal">136</span>
<span class="normal">137</span>
<span class="normal">138</span>
<span class="normal">139</span>
<span class="normal">140</span>
<span class="normal">141</span>
<span class="normal">142</span>
<span class="normal">143</span>
<span class="normal">144</span>
<span class="normal">145</span>
<span class="normal">146</span>
<span class="normal">147</span>
<span class="normal">148</span>
<span class="normal">149</span>
<span class="normal">150</span>
<span class="normal">151</span>
<span class="normal">152</span>
<span class="normal">153</span>
<span class="normal">154</span>
<span class="normal">155</span>
<span class="normal">156</span>
<span class="normal">157</span>
<span class="normal">158</span>
<span class="normal">159</span>
<span class="normal">160</span>
<span class="normal">161</span>
<span class="normal">162</span>
<span class="normal">163</span>
<span class="normal">164</span>
<span class="normal">165</span>
<span class="normal">166</span>
<span class="normal">167</span>
<span class="normal">168</span>
<span class="normal">169</span>
<span class="normal">170</span>
<span class="normal">171</span>
<span class="normal">172</span>
<span class="normal">173</span>
<span class="normal">174</span>
<span class="normal">175</span>
<span class="normal">176</span>
<span class="normal">177</span>
<span class="normal">178</span>
<span class="normal">179</span>
<span class="normal">180</span>
<span class="normal">181</span>
<span class="normal">182</span>
<span class="normal">183</span>
<span class="normal">184</span>
<span class="normal">185</span>
<span class="normal">186</span>
<span class="normal">187</span>
<span class="normal">188</span>
<span class="normal">189</span>
<span class="normal">190</span>
<span class="normal">191</span>
<span class="normal">192</span>
<span class="normal">193</span>
<span class="normal">194</span>
<span class="normal">195</span>
<span class="normal">196</span>
<span class="normal">197</span>
<span class="normal">198</span>
<span class="normal">199</span>
<span class="normal">200</span>
<span class="normal">201</span>
<span class="normal">202</span>
<span class="normal">203</span>
<span class="normal">204</span>
<span class="normal">205</span>
<span class="normal">206</span>
<span class="normal">207</span>
<span class="normal">208</span>
<span class="normal">209</span>
<span class="normal">210</span>
<span class="normal">211</span>
<span class="normal">212</span>
<span class="normal">213</span>
<span class="normal">214</span>
<span class="normal">215</span>
<span class="normal">216</span>
<span class="normal">217</span>
<span class="normal">218</span>
<span class="normal">219</span>
<span class="normal">220</span>
<span class="normal">221</span>
<span class="normal">222</span>
<span class="normal">223</span>
<span class="normal">224</span>
<span class="normal">225</span>
<span class="normal">226</span>
<span class="normal">227</span>
<span class="normal">228</span>
<span class="normal">229</span>
<span class="normal">230</span>
<span class="normal">231</span>
<span class="normal">232</span>
<span class="normal">233</span>
<span class="normal">234</span>
<span class="normal">235</span>
<span class="normal">236</span>
<span class="normal">237</span>
<span class="normal">238</span>
<span class="normal">239</span>
<span class="normal">240</span>
<span class="normal">241</span>
<span class="normal">242</span>
<span class="normal">243</span>
<span class="normal">244</span>
<span class="normal">245</span>
<span class="normal">246</span>
<span class="normal">247</span>
<span class="normal">248</span>
<span class="normal">249</span>
<span class="normal">250</span>
<span class="normal">251</span>
<span class="normal">252</span>
<span class="normal">253</span>
<span class="normal">254</span>
<span class="normal">255</span>
<span class="normal">256</span>
<span class="normal">257</span>
<span class="normal">258</span>
<span class="normal">259</span>
<span class="normal">260</span>
<span class="normal">261</span>
<span class="normal">262</span>
<span class="normal">263</span>
<span class="normal">264</span>
<span class="normal">265</span>
<span class="normal">266</span>
<span class="normal">267</span>
<span class="normal">268</span>
<span class="normal">269</span>
<span class="normal">270</span>
<span class="normal">271</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""Prototype implementation of NFA-based regex engine.</span>
<span class="sd">See https://swtch.com/~rsc/regexp/regexp1.html</span>
<span class="sd">"""</span>
<span class="c1"># My old nemesis</span>
<span class="c1"># pylint: disable=too-few-public-methods</span>
<span class="kn">import</span> <span class="nn">enum</span>
<span class="kn">import</span> <span class="nn">typing</span>
<span class="kn">import</span> <span class="nn">typing_extensions</span>
<span class="c1"># I think pylint is getting a little big for its britches when it tells us not</span>
<span class="c1"># to follow the usage given by the official documentation for the typing module</span>
<span class="n">Index</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">NewType</span><span class="p">(</span><span class="s1">'Index'</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span> <span class="c1"># pylint: disable=invalid-name</span>
<span class="n">Grapheme</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">NewType</span><span class="p">(</span><span class="s1">'Grapheme'</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="c1"># pylint: disable=invalid-name</span>
<span class="k">class</span> <span class="nc">Tail</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""A "pointer" to an out-field of a State in an arena."""</span>
<span class="n">source</span><span class="p">:</span> <span class="n">Index</span>
<span class="n">field</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">_T</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">TypeVar</span><span class="p">(</span><span class="s1">'_T'</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">State</span><span class="p">(</span><span class="n">typing_extensions</span><span class="o">.</span><span class="n">Protocol</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""States have tails, and the ability to assign to tails."""</span>
<span class="c1"># I really hope there's a plugin or something for dealing with Protocols.</span>
<span class="c1"># pylint: disable=no-self-use, unused-argument</span>
<span class="k">def</span> <span class="nf">tails</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterator</span><span class="p">[</span><span class="n">Tail</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the state's tails."""</span>
<span class="c1"># I don't know if protocols NEED-need this, I'm just following the doc.</span>
<span class="o">...</span> <span class="c1"># pylint: disable=pointless-statement</span>
<span class="c1"># There's probably a more correct interface to this...</span>
<span class="k">def</span> <span class="nf">_replace</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">_T</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-></span> <span class="n">_T</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Point the state's tail at an index."""</span>
<span class="c1"># I don't know if protocols NEED-need this, I'm just following the doc.</span>
<span class="o">...</span> <span class="c1"># pylint: disable=pointless-statement</span>
<span class="k">class</span> <span class="nc">GraphemeMatch</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Match a single grapheme."""</span>
<span class="c1"># When I extend it, I end up noticing that tuple has an obnoxiously big API</span>
<span class="c1"># surface. So many common words I can't use because all methods go in the</span>
<span class="c1"># same namespace...</span>
<span class="n">index_</span><span class="p">:</span> <span class="n">Index</span>
<span class="n">grapheme</span><span class="p">:</span> <span class="n">Grapheme</span>
<span class="n">out</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">Index</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">def</span> <span class="nf">tails</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterator</span><span class="p">[</span><span class="n">Tail</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Yield the only followup state."""</span>
<span class="k">yield</span> <span class="n">Tail</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">index_</span><span class="p">,</span> <span class="s1">'out'</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Split</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Split NFA evaluation between two possible states."""</span>
<span class="n">index_</span><span class="p">:</span> <span class="n">Index</span>
<span class="n">out</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">Index</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">out1</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">Index</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">def</span> <span class="nf">tails</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterator</span><span class="p">[</span><span class="n">Tail</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Yield both followup states."""</span>
<span class="k">yield</span> <span class="n">Tail</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">index_</span><span class="p">,</span> <span class="s1">'out'</span><span class="p">)</span>
<span class="k">yield</span> <span class="n">Tail</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">index_</span><span class="p">,</span> <span class="s1">'out1'</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Match</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Terminate NFA evaluation."""</span>
<span class="n">index_</span><span class="p">:</span> <span class="n">Index</span>
<span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="nf">tails</span><span class="p">()</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterator</span><span class="p">[</span><span class="n">Tail</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Yield nothing, there is no followup state."""</span>
<span class="k">yield from</span> <span class="nb">iter</span><span class="p">(())</span>
<span class="k">class</span> <span class="nc">Fragment</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""NFA fragment."""</span>
<span class="n">start</span><span class="p">:</span> <span class="n">Index</span>
<span class="n">tail_list</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">Tail</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span>
<span class="k">class</span> <span class="nc">NFA</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Completed NFA of a regex."""</span>
<span class="n">start_index</span><span class="p">:</span> <span class="n">Index</span>
<span class="n">arena</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">State</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">_addstate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">indices</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Set</span><span class="p">[</span><span class="n">Index</span><span class="p">],</span> <span class="n">index</span><span class="p">:</span> <span class="n">Index</span><span class="p">):</span>
<span class="n">state</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">arena</span><span class="p">[</span><span class="n">index</span><span class="p">]</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">Split</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_addstate</span><span class="p">(</span><span class="n">indices</span><span class="p">,</span> <span class="n">state</span><span class="o">.</span><span class="n">out</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_addstate</span><span class="p">(</span><span class="n">indices</span><span class="p">,</span> <span class="n">state</span><span class="o">.</span><span class="n">out1</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">indices</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">index</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">match</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stream</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterable</span><span class="p">[</span><span class="n">Grapheme</span><span class="p">])</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return whether given grapheme stream is accepted by the regex."""</span>
<span class="n">indices</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Set</span><span class="p">[</span><span class="n">Index</span><span class="p">]</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_addstate</span><span class="p">(</span><span class="n">indices</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">start_index</span><span class="p">)</span>
<span class="k">for</span> <span class="n">grapheme</span> <span class="ow">in</span> <span class="n">stream</span><span class="p">:</span>
<span class="n">new_indices</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Set</span><span class="p">[</span><span class="n">Index</span><span class="p">]</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
<span class="k">for</span> <span class="n">index</span> <span class="ow">in</span> <span class="n">indices</span><span class="p">:</span>
<span class="n">state</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">arena</span><span class="p">[</span><span class="n">index</span><span class="p">]</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span>
<span class="n">state</span><span class="p">,</span> <span class="n">GraphemeMatch</span><span class="p">)</span> <span class="ow">and</span> <span class="n">state</span><span class="o">.</span><span class="n">grapheme</span> <span class="o">==</span> <span class="n">grapheme</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_addstate</span><span class="p">(</span><span class="n">new_indices</span><span class="p">,</span> <span class="n">state</span><span class="o">.</span><span class="n">out</span><span class="p">)</span>
<span class="n">indices</span> <span class="o">=</span> <span class="n">new_indices</span>
<span class="n">final_index</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">arena</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span>
<span class="k">return</span> <span class="n">final_index</span> <span class="ow">in</span> <span class="n">indices</span>
<span class="k">def</span> <span class="nf">patch</span><span class="p">(</span>
<span class="n">arena</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">State</span><span class="p">],</span>
<span class="n">tail_list</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Sequence</span><span class="p">[</span><span class="n">Tail</span><span class="p">],</span>
<span class="n">index</span><span class="p">:</span> <span class="n">Index</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Connect all tails to the given index."""</span>
<span class="k">for</span> <span class="n">tail</span> <span class="ow">in</span> <span class="n">tail_list</span><span class="p">:</span>
<span class="n">arena</span><span class="p">[</span><span class="n">tail</span><span class="o">.</span><span class="n">source</span><span class="p">]</span> <span class="o">=</span> <span class="n">arena</span><span class="p">[</span><span class="n">tail</span><span class="o">.</span><span class="n">source</span><span class="p">]</span><span class="o">.</span><span class="n">_replace</span><span class="p">(</span><span class="o">**</span><span class="p">{</span><span class="n">tail</span><span class="o">.</span><span class="n">field</span><span class="p">:</span> <span class="n">index</span><span class="p">})</span>
<span class="k">class</span> <span class="nc">Token</span><span class="p">(</span><span class="n">typing_extensions</span><span class="o">.</span><span class="n">Protocol</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Protocol for postfix tokens."""</span>
<span class="c1"># I really hope there's a plugin or something for dealing with Protocols.</span>
<span class="c1"># pylint: disable=no-self-use, unused-argument</span>
<span class="k">def</span> <span class="nf">fragment_args</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">stack</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">Fragment</span><span class="p">])</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterable</span><span class="p">[</span><span class="n">Fragment</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the fragment args required by the fragment() call."""</span>
<span class="c1"># I don't know if protocols NEED-need this, I'm just following the doc.</span>
<span class="o">...</span> <span class="c1"># pylint: disable=pointless-statement</span>
<span class="k">def</span> <span class="nf">fragment</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">arena</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">State</span><span class="p">],</span>
<span class="n">fragment_args</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterable</span><span class="p">[</span><span class="n">Fragment</span><span class="p">])</span> <span class="o">-></span> <span class="n">Fragment</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Create a new fragment."""</span>
<span class="c1"># I don't know if protocols NEED-need this, I'm just following the doc.</span>
<span class="o">...</span> <span class="c1"># pylint: disable=pointless-statement</span>
<span class="k">class</span> <span class="nc">Literal</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Postfix token for matching a grapheme."""</span>
<span class="n">grapheme</span><span class="p">:</span> <span class="n">Grapheme</span>
<span class="c1"># pylint: disable=unused-argument</span>
<span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="nf">fragment_args</span><span class="p">(</span>
<span class="n">stack</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">Fragment</span><span class="p">])</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterable</span><span class="p">[</span><span class="n">Fragment</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""No need to manipulate the stack."""</span>
<span class="k">return</span> <span class="p">()</span>
<span class="k">def</span> <span class="nf">fragment</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">arena</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">State</span><span class="p">],</span>
<span class="n">fragment_args</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterable</span><span class="p">[</span><span class="n">Fragment</span><span class="p">])</span> <span class="o">-></span> <span class="n">Fragment</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Create a completely new Fragment."""</span>
<span class="n">index</span> <span class="o">=</span> <span class="n">push</span><span class="p">(</span><span class="n">arena</span><span class="p">,</span> <span class="n">GraphemeMatch</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">grapheme</span><span class="p">)</span>
<span class="k">return</span> <span class="n">Fragment</span><span class="p">(</span><span class="n">index</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">arena</span><span class="p">[</span><span class="n">index</span><span class="p">]</span><span class="o">.</span><span class="n">tails</span><span class="p">()))</span>
<span class="k">class</span> <span class="nc">Operator</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Postfix token for operators.</span>
<span class="sd"> This class may not be necessary.</span>
<span class="sd"> """</span>
<span class="k">def</span> <span class="nf">fragment_args</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">stack</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">Fragment</span><span class="p">])</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterable</span><span class="p">[</span><span class="n">Fragment</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the fragment_args required by the fragment() call."""</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
<span class="k">def</span> <span class="nf">fragment</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">arena</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">State</span><span class="p">],</span>
<span class="n">fragment_args</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterable</span><span class="p">[</span><span class="n">Fragment</span><span class="p">])</span> <span class="o">-></span> <span class="n">Fragment</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Create a new fragment."""</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
<span class="k">class</span> <span class="nc">Binary</span><span class="p">(</span><span class="n">Operator</span><span class="p">,</span> <span class="n">enum</span><span class="o">.</span><span class="n">Enum</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Postfix token for binary operators."""</span>
<span class="n">CONCATENATE</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="n">ALTERNATE</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">fragment_args</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">stack</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">Fragment</span><span class="p">])</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterable</span><span class="p">[</span><span class="n">Fragment</span><span class="p">]:</span>
<span class="n">fragment_2</span> <span class="o">=</span> <span class="n">stack</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
<span class="n">fragment_1</span> <span class="o">=</span> <span class="n">stack</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
<span class="k">return</span> <span class="n">fragment_1</span><span class="p">,</span> <span class="n">fragment_2</span>
<span class="k">def</span> <span class="nf">fragment</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">arena</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">State</span><span class="p">],</span>
<span class="n">fragment_args</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterable</span><span class="p">[</span><span class="n">Fragment</span><span class="p">])</span> <span class="o">-></span> <span class="n">Fragment</span><span class="p">:</span>
<span class="n">fragment_1</span><span class="p">,</span> <span class="n">fragment_2</span> <span class="o">=</span> <span class="n">fragment_args</span>
<span class="k">if</span> <span class="bp">self</span> <span class="o">==</span> <span class="n">Binary</span><span class="o">.</span><span class="n">CONCATENATE</span><span class="p">:</span>
<span class="n">patch</span><span class="p">(</span><span class="n">arena</span><span class="p">,</span> <span class="n">fragment_1</span><span class="o">.</span><span class="n">tail_list</span><span class="p">,</span> <span class="n">fragment_2</span><span class="o">.</span><span class="n">start</span><span class="p">)</span>
<span class="k">return</span> <span class="n">Fragment</span><span class="p">(</span><span class="n">fragment_1</span><span class="o">.</span><span class="n">start</span><span class="p">,</span> <span class="n">fragment_2</span><span class="o">.</span><span class="n">tail_list</span><span class="p">)</span>
<span class="k">assert</span> <span class="bp">self</span> <span class="o">==</span> <span class="n">Binary</span><span class="o">.</span><span class="n">ALTERNATE</span>
<span class="n">index</span> <span class="o">=</span> <span class="n">push</span><span class="p">(</span><span class="n">arena</span><span class="p">,</span> <span class="n">Split</span><span class="p">,</span> <span class="n">fragment_1</span><span class="o">.</span><span class="n">start</span><span class="p">,</span> <span class="n">fragment_2</span><span class="o">.</span><span class="n">start</span><span class="p">)</span>
<span class="k">return</span> <span class="n">Fragment</span><span class="p">(</span><span class="n">index</span><span class="p">,</span> <span class="n">fragment_1</span><span class="o">.</span><span class="n">tail_list</span> <span class="o">+</span> <span class="n">fragment_2</span><span class="o">.</span><span class="n">tail_list</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Unary</span><span class="p">(</span><span class="n">Operator</span><span class="p">,</span> <span class="n">enum</span><span class="o">.</span><span class="n">Enum</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Postfix token for unary operators."""</span>
<span class="n">OPTIONAL</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="n">ANY_AMOUNT</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="n">ONE_PLUS</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">fragment_args</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">stack</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">Fragment</span><span class="p">])</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterable</span><span class="p">[</span><span class="n">Fragment</span><span class="p">]:</span>
<span class="k">return</span> <span class="n">stack</span><span class="o">.</span><span class="n">pop</span><span class="p">(),</span>
<span class="k">def</span> <span class="nf">fragment</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">arena</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">State</span><span class="p">],</span>
<span class="n">fragment_args</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterable</span><span class="p">[</span><span class="n">Fragment</span><span class="p">]):</span>
<span class="n">fragment</span><span class="p">,</span> <span class="o">=</span> <span class="n">fragment_args</span>
<span class="n">index</span> <span class="o">=</span> <span class="n">push</span><span class="p">(</span><span class="n">arena</span><span class="p">,</span> <span class="n">Split</span><span class="p">,</span> <span class="n">fragment</span><span class="o">.</span><span class="n">start</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span> <span class="o">==</span> <span class="n">Unary</span><span class="o">.</span><span class="n">OPTIONAL</span><span class="p">:</span>
<span class="k">return</span> <span class="n">Fragment</span><span class="p">(</span>
<span class="n">index</span><span class="p">,</span> <span class="n">fragment</span><span class="o">.</span><span class="n">tail_list</span> <span class="o">+</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">arena</span><span class="p">[</span><span class="n">index</span><span class="p">]</span><span class="o">.</span><span class="n">tails</span><span class="p">()))</span>
<span class="k">elif</span> <span class="bp">self</span> <span class="o">==</span> <span class="n">Unary</span><span class="o">.</span><span class="n">ANY_AMOUNT</span><span class="p">:</span>
<span class="n">patch</span><span class="p">(</span><span class="n">arena</span><span class="p">,</span> <span class="n">fragment</span><span class="o">.</span><span class="n">tail_list</span><span class="p">,</span> <span class="n">index</span><span class="p">)</span>
<span class="k">return</span> <span class="n">Fragment</span><span class="p">(</span><span class="n">index</span><span class="p">,</span> <span class="p">(</span><span class="n">Tail</span><span class="p">(</span><span class="n">index</span><span class="p">,</span> <span class="s1">'out1'</span><span class="p">),))</span>
<span class="k">assert</span> <span class="bp">self</span> <span class="o">==</span> <span class="n">Unary</span><span class="o">.</span><span class="n">ONE_PLUS</span>
<span class="n">patch</span><span class="p">(</span><span class="n">arena</span><span class="p">,</span> <span class="n">fragment</span><span class="o">.</span><span class="n">tail_list</span><span class="p">,</span> <span class="n">index</span><span class="p">)</span>
<span class="k">return</span> <span class="n">Fragment</span><span class="p">(</span><span class="n">fragment</span><span class="o">.</span><span class="n">start</span><span class="p">,</span> <span class="p">(</span><span class="n">Tail</span><span class="p">(</span><span class="n">index</span><span class="p">,</span> <span class="s1">'out1'</span><span class="p">),))</span>
<span class="k">def</span> <span class="nf">push</span><span class="p">(</span><span class="n">arena</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">State</span><span class="p">],</span> <span class="n">factory</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Create a state using given factory, add to arena, return index."""</span>
<span class="n">index</span> <span class="o">=</span> <span class="n">Index</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">arena</span><span class="p">))</span>
<span class="n">state</span> <span class="o">=</span> <span class="n">factory</span><span class="p">(</span><span class="n">index</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="n">arena</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">state</span><span class="p">)</span>
<span class="k">return</span> <span class="n">index</span>
<span class="k">def</span> <span class="nf">post_to_nfa</span><span class="p">(</span><span class="n">tokens</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Sequence</span><span class="p">[</span><span class="n">Token</span><span class="p">]):</span>
<span class="w"> </span><span class="sd">"""Convert a list of postfix tokens to an NFA."""</span>
<span class="n">stack</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">Fragment</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">arena</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">State</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">token</span> <span class="ow">in</span> <span class="n">tokens</span><span class="p">:</span>
<span class="n">stack</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">token</span><span class="o">.</span><span class="n">fragment</span><span class="p">(</span><span class="n">arena</span><span class="p">,</span> <span class="n">token</span><span class="o">.</span><span class="n">fragment_args</span><span class="p">(</span><span class="n">stack</span><span class="p">)))</span>
<span class="c1"># pylint pointed out a bug on this next line. It's possible to hit it by</span>
<span class="c1"># passing an empty string, which raises the question of how the C</span>
<span class="c1"># implementation handles it. I don't know C well enough, so I'm just</span>
<span class="c1"># staring at the for-loop and wondering "So, like, does that end if the</span>
<span class="c1"># current character is null, or something?"</span>
<span class="n">fragment</span><span class="p">,</span> <span class="o">=</span> <span class="n">stack</span>
<span class="n">index</span> <span class="o">=</span> <span class="n">push</span><span class="p">(</span><span class="n">arena</span><span class="p">,</span> <span class="n">Match</span><span class="p">)</span>
<span class="n">patch</span><span class="p">(</span><span class="n">arena</span><span class="p">,</span> <span class="n">fragment</span><span class="o">.</span><span class="n">tail_list</span><span class="p">,</span> <span class="n">index</span><span class="p">)</span>
<span class="k">return</span> <span class="n">NFA</span><span class="p">(</span><span class="n">fragment</span><span class="o">.</span><span class="n">start</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">arena</span><span class="p">))</span>
</pre></div></td></tr></table></div>
<hr class="docutils" />
<p>Postscript: I made some changes to the match and post_to_nfa methods that fix the bug, but the resulting invariants are... confusing, which makes me think that this needs more work.</p>
<div class="highlight"><pre><span></span> <span class="k">def</span> <span class="nf">match</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stream</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterable</span><span class="p">[</span><span class="n">Grapheme</span><span class="p">])</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return whether given grapheme stream is accepted by the regex."""</span>
<span class="n">indices</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Set</span><span class="p">[</span><span class="n">Index</span><span class="p">]</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_addstate</span><span class="p">(</span><span class="n">indices</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">start_index</span><span class="p">)</span>
<span class="k">for</span> <span class="n">grapheme</span> <span class="ow">in</span> <span class="n">stream</span><span class="p">:</span>
<span class="n">new_indices</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Set</span><span class="p">[</span><span class="n">Index</span><span class="p">]</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
<span class="k">for</span> <span class="n">index</span> <span class="ow">in</span> <span class="n">indices</span><span class="p">:</span>
<span class="n">state</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">arena</span><span class="p">[</span><span class="n">index</span><span class="p">]</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span>
<span class="n">state</span><span class="p">,</span> <span class="n">GraphemeMatch</span><span class="p">)</span> <span class="ow">and</span> <span class="n">state</span><span class="o">.</span><span class="n">grapheme</span> <span class="o">==</span> <span class="n">grapheme</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_addstate</span><span class="p">(</span><span class="n">new_indices</span><span class="p">,</span> <span class="n">state</span><span class="o">.</span><span class="n">out</span><span class="p">)</span>
<span class="n">indices</span> <span class="o">=</span> <span class="n">new_indices</span>
<span class="n">final_index</span> <span class="o">=</span> <span class="n">Index</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">return</span> <span class="n">final_index</span> <span class="ow">in</span> <span class="n">indices</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">post_to_nfa</span><span class="p">(</span><span class="n">tokens</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Sequence</span><span class="p">[</span><span class="n">Token</span><span class="p">]):</span>
<span class="w"> </span><span class="sd">"""Convert a list of postfix tokens to an NFA."""</span>
<span class="n">stack</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">Fragment</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">arena</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">State</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">fragment</span> <span class="o">=</span> <span class="n">Fragment</span><span class="p">(</span><span class="n">Index</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="p">())</span>
<span class="k">for</span> <span class="n">token</span> <span class="ow">in</span> <span class="n">tokens</span><span class="p">:</span>
<span class="n">fragment</span> <span class="o">=</span> <span class="n">token</span><span class="o">.</span><span class="n">fragment</span><span class="p">(</span><span class="n">arena</span><span class="p">,</span> <span class="n">token</span><span class="o">.</span><span class="n">fragment_args</span><span class="p">(</span><span class="n">stack</span><span class="p">))</span>
<span class="n">stack</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">fragment</span><span class="p">)</span>
<span class="n">index</span> <span class="o">=</span> <span class="n">push</span><span class="p">(</span><span class="n">arena</span><span class="p">,</span> <span class="n">Match</span><span class="p">)</span>
<span class="n">patch</span><span class="p">(</span><span class="n">arena</span><span class="p">,</span> <span class="n">fragment</span><span class="o">.</span><span class="n">tail_list</span><span class="p">,</span> <span class="n">index</span><span class="p">)</span>
<span class="k">return</span> <span class="n">NFA</span><span class="p">(</span><span class="n">fragment</span><span class="o">.</span><span class="n">start</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">arena</span><span class="p">))</span>
</pre></div>
<hr class="docutils" />
<p>Postpostscript: Okay, <em>now</em> I'm going to take a break, even though I haven't improved the invariants any.</p>
<div class="highlight"><pre><span></span> <span class="n">out</span><span class="p">:</span> <span class="n">Index</span> <span class="o">=</span> <span class="n">Index</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="o">...</span>
<span class="n">out</span><span class="p">:</span> <span class="n">Index</span> <span class="o">=</span> <span class="n">Index</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">out1</span><span class="p">:</span> <span class="n">Index</span> <span class="o">=</span> <span class="n">Index</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">post_to_nfa</span><span class="p">(</span><span class="n">tokens</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Sequence</span><span class="p">[</span><span class="n">Token</span><span class="p">]):</span>
<span class="w"> </span><span class="sd">"""Convert a list of postfix tokens to an NFA."""</span>
<span class="n">stack</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">Fragment</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">arena</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">State</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">start_index</span> <span class="o">=</span> <span class="n">push</span><span class="p">(</span><span class="n">arena</span><span class="p">,</span> <span class="n">Match</span><span class="p">)</span>
<span class="k">for</span> <span class="n">token</span> <span class="ow">in</span> <span class="n">tokens</span><span class="p">:</span>
<span class="n">fragment</span> <span class="o">=</span> <span class="n">token</span><span class="o">.</span><span class="n">fragment</span><span class="p">(</span><span class="n">arena</span><span class="p">,</span> <span class="n">token</span><span class="o">.</span><span class="n">fragment_args</span><span class="p">(</span><span class="n">stack</span><span class="p">))</span>
<span class="n">start_index</span> <span class="o">=</span> <span class="n">fragment</span><span class="o">.</span><span class="n">start</span>
<span class="n">stack</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">fragment</span><span class="p">)</span>
<span class="c1"># There should really be a better way to handle this invariant.</span>
<span class="k">if</span> <span class="n">start_index</span><span class="p">:</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">stack</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span>
<span class="k">return</span> <span class="n">NFA</span><span class="p">(</span><span class="n">start_index</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">arena</span><span class="p">))</span>
</pre></div>
Music Theory 2018-05-282018-05-28T04:00:00-04:002018-05-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-28:/music-theory-2018-05-28<p class="first last">Perhaps a bit less than I "should have" done.</p>
<p>In this post:</p>
<ul class="simple">
<li>I come up with a perhaps too-elaborate analysis of how to represent the intensity of accents in music, and figure out what that means for BeatStructures.</li>
<li>I edit the BeatStructure code to account for that, then integrate it into the rest of the code.</li>
<li>I don't actually write analysis using the new concepts.</li>
</ul>
<hr class="docutils" />
<p>I spent some time thinking about what the beat structure concept means in terms of terminology and the rest of the code.
Here's my first stab at laying it out:</p>
<p>A <strong>beat structure</strong> consists of a <strong>base duration</strong> and a sequence of <strong>beat lengths</strong>.
The sum of all the <strong>beat lengths</strong> is the <strong>count</strong>.
Taken as a whole, each <strong>beat length</strong> has an <strong>on_beat</strong> at the beginning of it, and the remaining beats within the length are <strong>primary off_beats</strong>, while a note that starts completely unaligned is a <strong>secondary off_beat</strong>.
The first <strong>on_beat</strong> in the structure is a <strong>primary on_beat</strong>, there are one or two <strong>secondary on_beats</strong>, and the remainder are <strong>tertiary on_beats</strong>.</p>
<p>This requires a nested structure to pull off.
4/4 time gets ((1, 1), (1, 1)) (primary, tertiary, secondary, tertiary), while 6/8 gets ((3,), (3,)) (primary, off, off, secondary, off, off), and 12/8 gets ((3, 3), (3, 3)), and I think 2/2 should get ((1,), (1,))</p>
<p>The choice of structure determines the natural placement and intensities of accents.</p>
<p>Let's get that put together.
Step one, create an enum.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""Data structures for representing beat types."""</span>
<span class="kn">import</span> <span class="nn">enum</span>
<span class="k">class</span> <span class="nc">BeatType</span><span class="p">(</span><span class="n">enum</span><span class="o">.</span><span class="n">Enum</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Enum of beat values."""</span>
<span class="n">PRIMARY_ON_BEAT</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">SECONDARY_ON_BEAT</span> <span class="o">=</span> <span class="mi">2</span>
<span class="n">TERTIARY_ON_BEAT</span> <span class="o">=</span> <span class="mi">3</span>
<span class="n">PRIMARY_OFF_BEAT</span> <span class="o">=</span> <span class="mi">4</span>
<span class="n">SECONDARY_OFF_BEAT</span> <span class="o">=</span> <span class="mi">5</span>
</pre></div></td></tr></table></div>
<p>Step two, realize that I jumped the gun defining BeatStructures last week.</p>
<p>I've changed it up to this, which mostly makes sense for the time signatures I care about, I think.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""Data structures for representing durations."""</span>
<span class="kn">import</span> <span class="nn">typing</span>
<span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">duration</span>
<span class="k">def</span> <span class="nf">beat_breakdown</span><span class="p">(</span><span class="n">parts</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">length</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span>
<span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="o">...</span><span class="p">],</span> <span class="o">...</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Break down the given number of beat lengths of the given length."""</span>
<span class="k">if</span> <span class="n">parts</span> <span class="o">==</span> <span class="mi">3</span><span class="p">:</span>
<span class="k">return</span> <span class="p">((</span><span class="n">length</span><span class="p">,),</span> <span class="p">(</span><span class="n">length</span><span class="p">,),</span> <span class="p">(</span><span class="n">length</span><span class="p">,))</span>
<span class="k">if</span> <span class="n">parts</span> <span class="o">%</span> <span class="mi">2</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s1">'Cannot break down into </span><span class="si">{</span><span class="n">parts</span><span class="si">}</span><span class="s1"> parts'</span><span class="p">)</span>
<span class="k">return</span> <span class="p">((</span><span class="n">length</span><span class="p">,)</span> <span class="o">*</span> <span class="p">(</span><span class="n">parts</span> <span class="o">//</span> <span class="mi">2</span><span class="p">),)</span> <span class="o">*</span> <span class="mi">2</span>
<span class="k">def</span> <span class="nf">is_compound</span><span class="p">(</span><span class="n">top</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return whether input is the top of a compound time signature."""</span>
<span class="k">return</span> <span class="ow">not</span> <span class="p">(</span><span class="n">top</span> <span class="o">==</span> <span class="mi">3</span> <span class="ow">or</span> <span class="n">top</span> <span class="o">%</span> <span class="mi">3</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">BeatStructure</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Wrapper type representing a duration as a fraction of a whole note."""</span>
<span class="n">base_duration</span><span class="p">:</span> <span class="n">duration</span><span class="o">.</span><span class="n">Duration</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">duration</span><span class="o">.</span><span class="n">Duration</span><span class="o">.</span><span class="n">from_fraction</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">))</span> <span class="c1"># pylint: disable=no-member</span>
<span class="n">durations</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="o">...</span><span class="p">],</span> <span class="o">...</span><span class="p">]</span> <span class="o">=</span> <span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">simple</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">top</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">bottom</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return the beat structure of a simple time signature."""</span>
<span class="k">if</span> <span class="n">is_compound</span><span class="p">(</span><span class="n">top</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">top</span><span class="si">}</span><span class="s1"> is compound'</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span>
<span class="n">duration</span><span class="o">.</span><span class="n">Duration</span><span class="o">.</span><span class="n">from_fraction</span><span class="p">(</span> <span class="c1"># pylint: disable=no-member</span>
<span class="mi">1</span><span class="p">,</span> <span class="n">bottom</span><span class="p">),</span> <span class="n">beat_breakdown</span><span class="p">(</span><span class="n">top</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">compound</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">top</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">bottom</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return the beat structure of a compound time signature."""</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">is_compound</span><span class="p">(</span><span class="n">top</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">top</span><span class="si">}</span><span class="s1"> is simple'</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span>
<span class="n">duration</span><span class="o">.</span><span class="n">Duration</span><span class="o">.</span><span class="n">from_fraction</span><span class="p">(</span> <span class="c1"># pylint: disable=no-member</span>
<span class="mi">1</span><span class="p">,</span> <span class="n">bottom</span><span class="p">),</span> <span class="n">beat_breakdown</span><span class="p">(</span><span class="n">top</span> <span class="o">//</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span>
</pre></div></td></tr></table></div>
<p>For the current analysis, I actually... slightly... don't need most of this.
I'm going to add a "count" property, and then most of this gets slotted into existing code without much inspection.</p>
<div class="highlight"><pre><span></span><span class="nd">@property</span>
<span class="k">def</span> <span class="nf">count</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the number of beats in the structure."""</span>
<span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="nb">sum</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">durations</span><span class="p">))</span>
</pre></div>
<p>It's a little golf-y, but there's an excellent reason: I didn't feel like typing out more code.</p>
<p>Anyway, I could work out the exact sequence of changes required to propagate the change from the "time signature" tuple to using BeatStructure, ooooor, hear me out on this, I could just replace it, and figure out after the fact what I just broke.</p>
<p>Okay, I got it all done.
I had to rename the property above to beat_count, because I forgot that methods don't namespace in Python.
I then had to rearrange things aggressively to fit in disables to compensate for <a class="reference external" href="https://github.com/PyCQA/pylint/issues/1628">a pylint bug</a>.
Looking into the stuff around that bug, I see that there have been some new releases of various libraries.
I'll have to look into taking those later.</p>
<p>At some point, I should code in the analysis according to the ideas at the top of this post, but I can get away with skipping that for now.
At the moment, I'm just glad to have finished this up.</p>
<hr class="docutils" />
<p>Next week, I start looking into representing pitches.</p>
Weekly Roundup 2018-05-272018-05-27T04:00:00-04:002018-05-27T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-27:/weekly-roundup-2018-05-27<p class="first last">Groundwork, groundwork, groundwork.</p>
<ul class="simple">
<li>Music Theory Monday: I laid the groundwork for supporting non-simple time signatures, but didn't yet <em>do</em> it.</li>
<li>Free-Topic Tuesday: Notes from the peanut gallery on Valve's latest failure in its duties.</li>
<li>Demiurgent Business Wednesday: I looked at Raspberry Heaven and School Daze, and thought about what differentiated them.</li>
<li>Conworld Codex Thursday: I attempted to write glue code between pytest, which I understand reasonably well, and SQLAlchemy, which I do not.</li>
<li>Draw a Box Friday: Yep, still drawing those lines.</li>
<li>Homunculus Saturday: I laid the groundwork for converting each GameState into its own class, a change that will allow me to drastically simplify the Game code.</li>
</ul>
Homunculus Devlog 2018-05-262018-05-26T04:00:00-04:002018-05-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-26:/homunculus-devlog-2018-05-26<p class="first last">I appear to be trying to summon Cthulhu, but he's not implemented yet.</p>
<p>In this post:</p>
<ul class="simple">
<li>I rewrote the save and load code a little.</li>
<li>I then started pondering the path forward I need to make GameStates more flexible.</li>
<li>I extended the Visitor code I wrote, in... somewhat strange ways.</li>
</ul>
<hr class="docutils" />
<p>All right.
I've just converted the save format into being a single versioned object.
This took some adjustment and fiddly stuff to maintain the save file I'm testing stuff in.
(I cheated a little, I think, by writing an upgrade path, then stripping it out.)
This means that, once I have test data for all of the things the YAML can represent, I can then get coverage on this, and iterate on the structure.</p>
<p>*Cue Benny Hill chase scene as I get chased by a horde of orcs and trolls, while looking for a confusion scroll.*</p>
<p>Okay, I've got a confused monster and a test using the save file. Next step is to look into messing with the GameStates structure.
GameStates can be divided into "game flow" (PLAYERS_TURN, ENEMY_TURN, PLAYER_DEAD) and "modal" (SHOW_INVENTORY, DROP_INVENTORY, TARGETING).
However I change the representation of this stuff, it's going to get a little weird.
So, I'll list some goals, to see if I can get a handle on it.</p>
<ul class="simple">
<li>The "modal" states must be instances of some form of class.</li>
<li>This means that the visitor code that's keying off of GameStates right now needs to be more like a typical visitor implementation, and look at the class.</li>
<li>This means that the "game flow" states need their own classes.</li>
<li>But this is aesthetically problematic, because they have no associated state.</li>
<li>Then again, neither does the basic AI.</li>
</ul>
<p>Okay, step one in this next bit is to put together a conventional Visitor implementation.
Step two is to convert the GameStates from an enum into a bunch of classes.
That will be somewhat problematic, because I need to make sure that I don't break the serialization code.</p>
<p>As an aside, it's possible that my extensive use of generators gave the impression that I'm just crowbarring in fancy stuff for the sake of fanciness.
In that light, it should seem odd that I'm removing a usage of Enum that the tutorial explicitly put in, since Enum is a fancy new 3.4 feature.
The truth is, I've just cultivated a strong sense of when a design demands a certain feature, and the design I'm iterating towards just does not work with Python enums in this context.
Rust enums, maybe...</p>
<p>I never give myself enough time for these coding posts.
That might change in the future, but for now, I'm going to work out the Visitor code I want, then call it a night.</p>
<p>Okay, I've got some kind of horrible desire to be quite generic, so I'm going to try to extend the current visitor with the idea of creating a "match generator" that produces multiple keys from a single input, in order from most to least specific.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span></pre></div></td><td class="code"><div><pre><span></span><span class="k">def</span> <span class="nf">identity</span><span class="p">(</span><span class="n">state</span><span class="p">):</span>
<span class="k">yield</span> <span class="n">state</span>
<span class="k">def</span> <span class="nf">classes</span><span class="p">(</span><span class="n">state</span><span class="p">):</span>
<span class="k">yield from</span> <span class="n">state</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__mro__</span>
<span class="k">class</span> <span class="nc">Visitor</span><span class="p">:</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">matches</span><span class="o">=</span><span class="n">identity</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">state_methods</span> <span class="o">=</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">default</span> <span class="o">=</span> <span class="n">default</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_default</span>
<span class="bp">self</span><span class="o">.</span><span class="n">matches</span> <span class="o">=</span> <span class="n">matches</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Visitor</span><span class="p">(</span><span class="n">func</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">matches</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_default</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span><span class="sa">f</span><span class="s1">'Not implemented for </span><span class="si">{</span><span class="n">state</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">bind</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">inner_bind</span><span class="p">(</span><span class="n">function</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">state_methods</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="n">function</span>
<span class="k">return</span> <span class="n">function</span>
<span class="k">return</span> <span class="n">inner_bind</span>
<span class="k">def</span> <span class="nf">visit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">for</span> <span class="n">match</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">matches</span><span class="p">(</span><span class="n">state</span><span class="p">):</span>
<span class="k">if</span> <span class="n">match</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">state_methods</span><span class="p">:</span>
<span class="n">visitor</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">state_methods</span><span class="p">[</span><span class="n">match</span><span class="p">]</span>
<span class="k">break</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">visitor</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">default</span>
<span class="k">return</span> <span class="n">visitor</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</pre></div></td></tr></table></div>
<p>Well.
That kind of gives me the heebie-jeebies.
I should take a break here, just to reflect on what I just wrote.</p>
<p>(It occurs to me that I could make this even worse, like by constructing the full list of matches, and replicating super() in some way to delegate between them, but I'll hold off for now, since I arguably don't even need some of the stuff I've written here already.)</p>
<hr class="docutils" />
<p>Next week, I dig deeper into what's bothering me about that code, and then try to tease apart the GameStates enum into a class hierarchy.</p>
<p>I've also got some ideas I want to just let bounce around in my head.
Like, what if the dumper code lived next to the associated class, and the loader functions handled their associated imports?
I'm interested in reorganizing the imports somehow, and I think something along those lines has potential, in terms of eliminating top-level imports in the serialization code, so it can be imported freely.</p>
Draw a Box 2018-05-252018-05-25T04:00:00-04:002018-05-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-25:/draw-a-box-2018-05-25<p class="first last">More drawing... no boxes...</p>
<p>In this post:</p>
<ul class="simple">
<li>Coming in on the home stretch... for <em>this</em> sheet of paper.</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>15 lines on May 18</li>
<li>15 lines on May 19</li>
<li>15 lines on May 20</li>
<li>15 lines on May 21</li>
<li>15 lines on May 22</li>
<li>15 lines on May 23</li>
<li>15 lines on May 24</li>
</ul>
<p>For a total of 105 lines this week,
and 330 lines since I started counting.</p>
<p>Also I accidentally left the pen uncapped overnight, and it might or might not be working properly after that, so I just ordered a new thing of pens.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Conworld Codex 2018-05-242018-05-24T04:00:00-04:002018-05-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-24:/conworld-codex-2018-05-24<p class="first last">Learning to wiggle my feet before I crawl.</p>
<p>In this post:</p>
<ul class="simple">
<li>I attempt to wire up the stuff SQLAlchemy needs in a testing context.</li>
</ul>
<hr class="docutils" />
<p>Okay, here's the plan for the code I wrote last week.
I'm going to write tests against it at that layer, and then try to have the GUI code just be thin wrappers around that functionality.</p>
<p>First, I want to write those tests, so I can get my coverage back up.</p>
<p>Okay, let's see...
I'm slightly adding functionality at random, which is bad.
The next thing to do must be figuring out how to spin these things up in the first place.
So, first up, let's see how to use SQLAlchemy with pytest.
I found a blogpost, <a class="reference external" href="http://robb.re/notes/2013-09-10-testing-with-pytest-and-sqlalchemy.html">Testing with py.test and Sqlalchemy</a>, that looks like it provides a decent starting point, but it does appear to be more pyramid-specific than I think it lets on to start with.
I have no good idea where some of these modules are coming from, and I think I'll need to do some things differently, on account of I legitimately am planning to use SQLite to power the Conworld Codex, since it's a GUI app and all.</p>
<p>Like, let's see, it looks like I don't care in the same way about sessions...</p>
<p>Okay, this is going to be yet another post where I didn't give myself enough lead time.
My goal now is to lay out the logic I need to create test fixtures that will suffice to handle this code.
I don't want to deal with the multiple session setup right now, because that can't possibly gain me anything with my plans.
I want to have a distinct in-memory SQLite engine for each test.
This should just be a matter of deleting the right code.</p>
<p>The SQLAlchemy documentation, on "<a class="reference external" href="http://docs.sqlalchemy.org/en/latest/orm/session_transaction.html#joining-a-session-into-an-external-transaction-such-as-for-test-suites">Joining a Session into an External Transaction (such as for test suites)</a>" was also very helpful, and I ended up leaning more on that.</p>
<p>I moved things around some more, and I've got code that looks plausible; I'll have to try it out later.
Something I'm going to have to accept is that I won't be able to move as fast in these posts when I'm learning so much.
Here's the current state of things:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""Test fixtures for conworld_codex tests."""</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">create_engine</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="n">sessionmaker</span>
<span class="kn">import</span> <span class="nn">pytest</span>
<span class="nd">@pytest</span><span class="o">.</span><span class="n">fixture</span><span class="p">(</span><span class="n">scope</span><span class="o">=</span><span class="s1">'session'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">models</span><span class="p">():</span>
<span class="w"> </span><span class="sd">"""Import the models module."""</span>
<span class="kn">import</span> <span class="nn">conworld_codex.models</span>
<span class="k">return</span> <span class="n">conworld_codex</span><span class="o">.</span><span class="n">models</span>
<span class="nd">@pytest</span><span class="o">.</span><span class="n">fixture</span><span class="p">(</span><span class="n">scope</span><span class="o">=</span><span class="s1">'session'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_session</span><span class="p">():</span>
<span class="w"> </span><span class="sd">"""Create a global session."""</span>
<span class="k">return</span> <span class="n">sessionmaker</span><span class="p">()</span>
<span class="nd">@pytest</span><span class="o">.</span><span class="n">fixture</span><span class="p">(</span><span class="n">scope</span><span class="o">=</span><span class="s1">'session'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">engine</span><span class="p">():</span>
<span class="w"> </span><span class="sd">"""Create a global engine.</span>
<span class="sd"> Honestly unsure whether this should be session scoped, or function scoped.</span>
<span class="sd"> """</span>
<span class="k">return</span> <span class="n">create_engine</span><span class="p">(</span><span class="s1">'sqlite://'</span><span class="p">)</span>
<span class="nd">@pytest</span><span class="o">.</span><span class="n">fixture</span>
<span class="k">def</span> <span class="nf">connection</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">models</span><span class="p">,</span> <span class="n">engine</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Create a connection and set up the database, for the duration of a test.</span>
<span class="sd"> I'm not sure if it actually makes sense to do this work every time.</span>
<span class="sd"> """</span>
<span class="n">models</span><span class="o">.</span><span class="n">Base</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">create_all</span><span class="p">(</span><span class="n">engine</span><span class="p">)</span>
<span class="n">connection</span> <span class="o">=</span> <span class="n">engine</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span>
<span class="n">models</span><span class="o">.</span><span class="n">Base</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">bind</span> <span class="o">=</span> <span class="n">engine</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">yield</span> <span class="n">connection</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">models</span><span class="o">.</span><span class="n">Base</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">drop_all</span><span class="p">()</span>
<span class="n">connection</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="nd">@pytest</span><span class="o">.</span><span class="n">fixture</span>
<span class="k">def</span> <span class="nf">db_session</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">_session</span><span class="p">,</span> <span class="n">connection</span><span class="p">,</span> <span class="n">models</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Create a transaction against a session, and roll it back after the test.</span>
<span class="sd"> To use subtransactions, call begin_nested. I think.</span>
<span class="sd"> """</span>
<span class="n">trans</span> <span class="o">=</span> <span class="n">connection</span><span class="o">.</span><span class="n">begin</span><span class="p">()</span>
<span class="n">session</span> <span class="o">=</span> <span class="n">_session</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">connection</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">yield</span> <span class="n">session</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">session</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">trans</span><span class="o">.</span><span class="n">rollback</span><span class="p">()</span>
</pre></div></td></tr></table></div>
<p>I'll be very interested to see which parts of this make sense, which cause minor ergonomics issues, and which are just plain wrong.</p>
<hr class="docutils" />
<p>Next week, I attempt to put this code into practice.</p>
Demiurgent Business 2018-05-232018-05-23T04:00:00-04:002018-05-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-23:/demiurgent-business-2018-05-23<p class="first last">A look at prior art in the high school RPG space.</p>
<p>In this post:</p>
<ul class="simple">
<li>I contrast two games set in high school, that have different rules and deliver different experiences.</li>
</ul>
<hr class="docutils" />
<p>I'm actually not sure how much insight I'm going to get out in this post; I might need to change something about this series.
Anyway, for this post, I looked over <a class="reference external" href="www.drivethrurpg.com/product/156194/Raspberry-Heaven">Raspberry Heaven</a>, <a class="reference external" href="http://www.drivethrurpg.com/product/104650/School-Daze">School Daze</a>, and <a class="reference external" href="http://www.drivethrurpg.com/product/142924/Schoolgirl-RPG-Complete-Edition">Schoolgirl RPG</a>.
I didn't look over Schoolgirl RPG too closely, after I realized just how much it was in the same design lineage as Kagegami High.
Raspberry Heaven is thematically inspired by 4-panel manga, while School Daze is thematically inspired by teen dramas.</p>
<p>Let's look at how they make that thematic connection work.</p>
<div class="section" id="raspberry-heaven">
<h2>Raspberry Heaven</h2>
<ul class="simple">
<li>By default, Raspberry Heaven has 6 player characters designed, and 12 scene cards.</li>
<li>Player characters are a name, a concept, a biography, and a "special move".</li>
<li>The scene is the basic unit of organization in play.</li>
<li>Each scene consists of multiple paragraphs.</li>
<li>Someone reads the scene card aloud, and after each paragraph, the players play out their responses to the situation that paragraph sets up.</li>
<li>Each player character has a "special move" that they can trigger once-per-scene, to shake things up.</li>
<li>Randomness exists in the form of the choice of scene, and in the outcome of special moves.</li>
</ul>
</div>
<div class="section" id="school-daze">
<h2>School Daze</h2>
<ul class="simple">
<li>School Daze has a character creation process meant to guide players into designing characters that embody teen drama archetypes, and encourages the "Administrator" to create "Group Projects"; each Group Project is a self-contained story.</li>
<li>Characters are a name, a "favorite subject", some "ranks" (every example character seems to have one, but the character sheet looks like it has space for more?), a "motivation", and some relationships to other characters.</li>
<li>Each Rank is a description of a character archetype, and ways in which fitting into that archetype makes things easier or harder for the character.</li>
<li>All ranks provide both advantages and disadvantages.</li>
<li>Group Projects are a theme, some NPCs, and a time frame.</li>
<li>Character motivations typically relate to the current Group Project.</li>
<li>The characters involved in a Group Project attempt to achieve the goals set by their motivations, helped by their favorite subjects, and helped or hindered by their Ranks.</li>
<li>School Daze has characters engage in conflict with each other, and with adverse circumstances.</li>
<li>Such conflict is mediated by simple die rolls, with modifiers based on Rank and Favorite Subject.</li>
<li>Failing a roll results in a character experiencing a Consequence, which further hinders them in some circumstances.</li>
</ul>
<p>The ultimate takeaway I have from all this is that, to reinforce the high-school setting, I need to write some scenarios, or other kinds of material, that establish the setting.
At the same time, to capture the gameplay experience I'm looking for, I need to look at games with a similar thematic focus.
That is, focusing on engaging with and covering up bizarre conspiracies and supernatural occurrences.
And I just happen to have one handy...</p>
<hr class="docutils" />
<p>Next week, <a class="reference external" href="https://www.drivethrurpg.com/product/211512/Conspiracist-the-Game-THEY-Dont-Want-You-to-Play">Conspiracist: the Game THEY Don't Want You to Play!</a></p>
</div>
Valve Commitments2018-05-22T04:00:00-04:002018-05-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-22:/valve-commitments<p class="first last">Putting your games on Steam seems like a questionable business proposition.</p>
<p>In this post:</p>
<ul class="simple">
<li>I'm very unimpressed with the state of things at Valve.</li>
<li>A call to action.</li>
</ul>
<hr class="docutils" />
<p>Valve... Commitments...
That's just it, isn't it?
It kind of seems like they <em>don't</em>.
Commit, that is.</p>
<p>Over the past week, Valve first <a class="reference external" href="https://www.destructoid.com/-update-valve-is-suddenly-targeting-adult-visual-novels-for-removal-from-steam-503730.phtml">bowed to external pressure targeting visual novels</a>, and then, if I'm understanding things correctly <a class="footnote-reference" href="#footnote-1" id="footnote-reference-1">[1]</a> reversed course.
I don't know exactly what changed things on Valve's end, but my money is on the backlash being louder than the initial pressure.</p>
<p>Valve's overall trajectory is so weird.
They walked away from making excellent <a class="footnote-reference" href="#footnote-2" id="footnote-reference-2">[2]</a> games to do tech support, and seemingly nothing else, for the storefront they built to sell their games.</p>
<p>In any case, it looks to me, as a random outsider, like Valve cannot currently make the promise that it'll maintain its commitments and stick to a principle, any principle.
What this means to someone planning to sell a game is, knowing that Valve is willing to throw publishers/developers under the bus, it's not prudent to rely on Valve financially.
This is not a call for a boycott; boycotts usually involve not doing something one may want to do, and one should not, going forward, want to put their eggs in Valve's basket.</p>
<p>The alternatives I'm focusing on right now are <a class="reference external" href="https://itch.io/">itch.io</a>, <a class="reference external" href="https://www.humblebundle.com/">Humble Bundle</a>, and <a class="reference external" href="https://www.gog.com/">GOG.com</a>.
For my part, since I am working on various bits of software I wouldn't mind putting up for sale, I'll probably want to focus solely on Itch to start with, and put anything I get on there in the near future as <abbr title="Pay What You Want">PWYW</abbr>.
In general, it seems like Itch is a good entry point, I'd personally be interested in using Humble's tools if I make more of a name for myself, and GOG is honestly a little pie-in-the-sky from my perspective, but right now it's certainly a more palatable gatekeeper than Valve, especially since it's not (currently?) effectively a monopoly.</p>
<p>For any independent developers reading this, if you have an audience, you should be gauging their feelings to inform your decisions, rather than solely trying to work this out from first principles like I just did.</p>
<p>One concrete thing I want to do in response to all this is, when one of the current features winds down, I want to replace it with, I go on Itch each week to look for a game that I have something interesting to say about.
Support independent voices, try to do substantive game criticism.
Everyone reading this, if you're not already, please think about doing something like this as well, putting your own stamp on the discussion.
Because there are so many people out there who get marginalized and erased, and if that happens to you, I think a powerful defense would be, to be able to point at your reaction, to whatever art or event was meaningful to you, or indeed to point at your own art, and to say something like "I'm here, and this mark I made on the world would not exist if I were not exactly as I am."</p>
<p>(I also just now turned off all marketing emails, that's a thing anyone can do. Go to "Account details", "Manage Email Preferences", and opt out selectively, or just switch it all off. If you're stronger than I am, you can delete your account outright, but I lack the fortitude right now.)</p>
<table class="docutils footnote" frame="void" id="footnote-1" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-1">[1]</a></td><td>I'm a couple layers removed, so this is doubtful.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="footnote-2" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-2">[2]</a></td><td>Not all Valve games are excellent, but I'm not here to drag games I've never played.</td></tr>
</tbody>
</table>
Music Theory 2018-05-212018-05-21T04:00:00-04:002018-05-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-21:/music-theory-2018-05-21<p class="first last">Somewhat underwhelming, but it is progress.</p>
<p>In this post:</p>
<ul class="simple">
<li>I come up with a plan to replace my current ad-hoc time signature data type.</li>
<li>I execute all of it...</li>
<li>Except the "replace the time signature type" bit.</li>
</ul>
<hr class="docutils" />
<p>Looking over the details of various kinds of time signatures, I see that I want the time signature objects to be somewhat sophisticated, and to carry much of the weight in placing the beats within a measure.
In short, the current beat determination code only produces sensible results for simple time signatures.
There's a single well-defined beat structure for compound time signatures, <em>but</em> a single asymmetric time signature can have different beat structures as close as consecutive measures.</p>
<p>Since I'm storing beat structure data (in the form of time signature) on every measure <em>anyway</em>, I'll keep on doing that, but instead have an explicit "beat structure" object, with various constructor methods.</p>
<p>Here's what I need to make this happen:</p>
<ul>
<li><p class="first">I'm going to rename the "NoteDuration" class to "Note".</p>
</li>
<li><p class="first">Then, I'm going to add a "NoteDuration" class that wraps the Fraction type, and thread that through the codebase where I'm currently using Fractions.</p>
</li>
<li><p class="first">The BeatStructure object is a base NoteDuration, and a sequence of integer beat durations.</p>
</li>
<li><p class="first">Several helper methods to create common BeatStructures:</p>
<blockquote>
<ul class="simple">
<li>Symmetrical beat structures may have length one or three. A single function creates both.</li>
<li>There are two functions that explicitly create simple or compound time signatures, which do basic validation and forward to the previous function. Or maybe it's a little the other way around.</li>
</ul>
</blockquote>
</li>
</ul>
<p>So, it's almost eleven pm now, and here's where I stand:</p>
<ul class="simple">
<li>I did (almost) everything in that list up there.</li>
<li>But that's not enough.</li>
<li>The remaining work is to replace the "time_signature" tuple with a BeatStructure, and rewrite the code that consumes it.</li>
<li>This is non-trivial, at least compared to what I've done so far.</li>
<li>I'm currently cursing my past self for not reading ahead, and playing Minecraft instead of working on this earlier today.</li>
<li>My head hurts, and I have to know my limits.</li>
</ul>
<hr class="docutils" />
<p>Next week, I'll replace the time signature with a beat structure.
I <em>may</em> have a chance to make the analysis code more sophisticated; I read ahead just now, and that's pretty much the last thing to do before I start getting actual pitches involved.</p>
Weekly Roundup 2018-05-202018-05-20T04:00:00-04:002018-05-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-20:/weekly-roundup-2018-05-20<p class="first last">A solid week.</p>
<ul class="simple">
<li>Music Theory Monday: I added rests, and did a little refactoring.</li>
<li>Free-Topic Tuesday: I started pondering how to differentiate a new social media platform, in terms of discouraging harassment.</li>
<li>Demiurgent Business Wednesday: I looked over what Polaris offered in terms of gameplay.</li>
<li>Conworld Codex Thursday: I did some design work, and wrote a bunch of stubs.</li>
<li>Draw a Box Friday: I drew more lines. Making good progress on filling this first sheet of paper.</li>
<li>Homunculus Saturday: I re-did the input handling, and thought hard about my goals for some of the rewrites.</li>
</ul>
Homunculus Devlog 2018-05-192018-05-19T04:00:00-04:002018-05-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-19:/homunculus-devlog-2018-05-19<p class="first last">Rubber Duck Blogging</p>
<p>In this post:</p>
<ul class="simple">
<li>I talk about, and then somewhat rewrite, the input-handling code.</li>
<li>I then talk about how I'm not totally sure about my plan for rewriting things, then have an idea for clarifying the meaning of the various bits of code.</li>
</ul>
<hr class="docutils" />
<p>I switched most of the dict return values to a custom type that emulates enough of the dict interface to get by.
These new "Events" each contain a single type of value, which makes them easily amenable to changing to some other form of layout later.
I haven't touched the input processing code, because I'm not exactly sure how it should look.</p>
<p>Anyway, possible directions to take this include moving the specification of "how an event behaves" out of the Game class.
I'm not exactly sure what the events of The Distant Future Of Several Weeks From Now should look like.
Perhaps the events are module-level constants or returned from a factory function, and the actual structure is just a pretty-printing wrapper around a generator function.</p>
<p>Probably, I want to next go for turning them into constants and factories, and I can worry about what's in them later.</p>
<p>Thinking about the input handling, I think what's confusing me is that there's this weird inter-weaving of knowing-about-state, wherein the GameState controls both which events can be generated, and what those events mean?
And so sometimes ideas with different semantics are expressed using the same variable, because that's more compact in the main method?
But I want to offload the processing into the Event itself potentially, so I'm willing to take the hit for refactoring purposes.</p>
<p>Here's an interesting idea that will break my save game (no great loss), but might really clear up the structure of things: instead of a game object that includes all state including the state enum, instead make each enum state its own class, where its instance variables represent "all of the required state", and state transitions are handled by returning the new state object.
This would be kind of a big change, and I'm not sure how to get to it gradually, which is really important, but it seems like a worthy goal, so far as getting rid of high-level if-statements.</p>
<p>In any case, step one here is to use Events in the context of input handling, then add in more variables to deal with the fact that sometimes a message can mean different things.
Formalizing that idea will let me get rid of some state checks in the take_player_turn method, which will let me move towards not varying behavior based on the state, which should make it easier to clean things up.
Yeah.
Separate out the names, rewrite to deal with the separated names, rewrite the blocks into their own generators, and see where I want to go from there.</p>
<p>It seems to me that I should be able to have "all details of behavior" collected into distinct classes, which all rely on other modules for stuff like "interpreting input events".
So, such a GameState class would have all the details of how to render and deal with state, and would basically be a unified "mode".</p>
<p>I've got a few hours between getting home later, and publishing this post.
Let's see what I can do.</p>
<p>Ah, sudden inspiration first: I don't want to put <em>everything</em> in the GameState, just the data that is specific to certain GameStates.
So, stuff like the targeting item or the previous state goes in there, but the map doesn't.
This might shake out a few different ways in practice, but it's a good thing to have in mind.</p>
<p>Here's what I got so far.
I have different names for identical events, in the assumption that I'll later diverge them so I can tease the logic apart.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span>
<span class="normal">102</span>
<span class="normal">103</span>
<span class="normal">104</span>
<span class="normal">105</span>
<span class="normal">106</span>
<span class="normal">107</span>
<span class="normal">108</span>
<span class="normal">109</span>
<span class="normal">110</span>
<span class="normal">111</span>
<span class="normal">112</span>
<span class="normal">113</span>
<span class="normal">114</span>
<span class="normal">115</span>
<span class="normal">116</span>
<span class="normal">117</span>
<span class="normal">118</span>
<span class="normal">119</span>
<span class="normal">120</span>
<span class="normal">121</span>
<span class="normal">122</span>
<span class="normal">123</span>
<span class="normal">124</span>
<span class="normal">125</span>
<span class="normal">126</span>
<span class="normal">127</span>
<span class="normal">128</span>
<span class="normal">129</span></pre></div></td><td class="code"><div><pre><span></span><span class="c1"># To test: is thankfully self-contained.</span>
<span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">events</span>
<span class="kn">from</span> <span class="nn">.game_states</span> <span class="kn">import</span> <span class="n">GameStates</span><span class="p">,</span> <span class="n">Visitor</span>
<span class="n">EVENT_UP</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'move'</span><span class="p">,</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">))</span>
<span class="n">EVENT_DOWN</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'move'</span><span class="p">,</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
<span class="n">EVENT_LEFT</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'move'</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
<span class="n">EVENT_RIGHT</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'move'</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
<span class="n">EVENT_PICKUP</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'pickup'</span><span class="p">,</span> <span class="kc">True</span><span class="p">)</span>
<span class="n">EVENT_SHOW_INVENTORY</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'show_inventory'</span><span class="p">,</span> <span class="kc">True</span><span class="p">)</span>
<span class="n">EVENT_DROP_INVENTORY</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'drop_inventory'</span><span class="p">,</span> <span class="kc">True</span><span class="p">)</span>
<span class="n">EVENT_SAVE_AND_QUIT</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'exit'</span><span class="p">,</span> <span class="kc">True</span><span class="p">)</span>
<span class="n">EVENT_CANCEL_TARGETING</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'exit'</span><span class="p">,</span> <span class="kc">True</span><span class="p">)</span>
<span class="n">EVENT_SHOW_DEAD_INVENTORY</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'show_inventory'</span><span class="p">,</span> <span class="kc">True</span><span class="p">)</span>
<span class="n">EVENT_QUIT</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'exit'</span><span class="p">,</span> <span class="kc">True</span><span class="p">)</span>
<span class="n">EVENT_EXIT_INVENTORY</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'exit'</span><span class="p">,</span> <span class="kc">True</span><span class="p">)</span>
<span class="n">EVENT_FULLSCREEN</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'fullscreen'</span><span class="p">,</span> <span class="kc">True</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">inventory_index</span><span class="p">(</span><span class="n">index</span><span class="p">):</span>
<span class="k">return</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'inventory_index'</span><span class="p">,</span> <span class="n">index</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">left_click</span><span class="p">(</span><span class="n">cell</span><span class="p">):</span>
<span class="k">return</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'left_click'</span><span class="p">,</span> <span class="n">cell</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">right_click</span><span class="p">(</span><span class="n">cell</span><span class="p">):</span>
<span class="k">return</span> <span class="n">events</span><span class="o">.</span><span class="n">Event</span><span class="p">(</span><span class="s1">'right_click'</span><span class="p">,</span> <span class="n">cell</span><span class="p">)</span>
<span class="nd">@Visitor</span>
<span class="k">def</span> <span class="nf">state_visitor</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">user_input</span><span class="p">):</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="nd">@Visitor</span>
<span class="k">def</span> <span class="nf">input_visitor</span><span class="p">(</span><span class="n">user_input</span><span class="p">,</span> <span class="n">state</span><span class="p">):</span>
<span class="k">return</span> <span class="n">state_visitor</span><span class="o">.</span><span class="n">visit</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">user_input</span><span class="p">)</span>
<span class="nd">@input_visitor</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">no_input</span><span class="p">(</span><span class="n">user_input</span><span class="p">,</span> <span class="n">state</span><span class="p">):</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="nd">@state_visitor</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">GameStates</span><span class="o">.</span><span class="n">PLAYERS_TURN</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">handle_player_turn_keys</span><span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="n">user_input</span><span class="p">):</span>
<span class="n">key_char</span> <span class="o">=</span> <span class="n">user_input</span><span class="o">.</span><span class="n">char</span>
<span class="k">if</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'UP'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_UP</span>
<span class="k">elif</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'DOWN'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_DOWN</span>
<span class="k">elif</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'LEFT'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_LEFT</span>
<span class="k">elif</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'RIGHT'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_RIGHT</span>
<span class="k">elif</span> <span class="n">key_char</span> <span class="o">==</span> <span class="s1">'g'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_PICKUP</span>
<span class="k">elif</span> <span class="n">key_char</span> <span class="o">==</span> <span class="s1">'i'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_SHOW_INVENTORY</span>
<span class="k">elif</span> <span class="n">key_char</span> <span class="o">==</span> <span class="s1">'d'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_DROP_INVENTORY</span>
<span class="k">if</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'ENTER'</span> <span class="ow">and</span> <span class="n">user_input</span><span class="o">.</span><span class="n">alt</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_FULLSCREEN</span>
<span class="k">elif</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'ESCAPE'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_SAVE_AND_QUIT</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="nd">@state_visitor</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">GameStates</span><span class="o">.</span><span class="n">TARGETING</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">handle_targeting_keys</span><span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="n">user_input</span><span class="p">):</span>
<span class="k">if</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'ESCAPE'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_CANCEL_TARGETING</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="nd">@state_visitor</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">GameStates</span><span class="o">.</span><span class="n">PLAYER_DEAD</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">handle_player_dead_keys</span><span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="n">user_input</span><span class="p">):</span>
<span class="n">key_char</span> <span class="o">=</span> <span class="n">user_input</span><span class="o">.</span><span class="n">char</span>
<span class="k">if</span> <span class="n">key_char</span> <span class="o">==</span> <span class="s1">'i'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_SHOW_DEAD_INVENTORY</span>
<span class="k">if</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'ENTER'</span> <span class="ow">and</span> <span class="n">user_input</span><span class="o">.</span><span class="n">alt</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_FULLSCREEN</span>
<span class="k">elif</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'ESCAPE'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_QUIT</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="c1"># This stuff maybe wants to be split up somehow?</span>
<span class="nd">@state_visitor</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">GameStates</span><span class="o">.</span><span class="n">DROP_INVENTORY</span><span class="p">)</span>
<span class="nd">@state_visitor</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">GameStates</span><span class="o">.</span><span class="n">SHOW_INVENTORY</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">handle_inventory_keys</span><span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="n">user_input</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">user_input</span><span class="o">.</span><span class="n">char</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="n">index</span> <span class="o">=</span> <span class="nb">ord</span><span class="p">(</span><span class="n">user_input</span><span class="o">.</span><span class="n">char</span><span class="p">)</span> <span class="o">-</span> <span class="nb">ord</span><span class="p">(</span><span class="s1">'a'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">index</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span> <span class="n">inventory_index</span><span class="p">(</span><span class="n">index</span><span class="p">)</span>
<span class="k">if</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'ENTER'</span> <span class="ow">and</span> <span class="n">user_input</span><span class="o">.</span><span class="n">alt</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_FULLSCREEN</span>
<span class="k">elif</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'ESCAPE'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">EVENT_EXIT_INVENTORY</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="k">def</span> <span class="nf">handle_mouse</span><span class="p">(</span><span class="n">mouse_event</span><span class="p">):</span>
<span class="k">if</span> <span class="n">mouse_event</span><span class="p">:</span>
<span class="k">if</span> <span class="n">mouse_event</span><span class="o">.</span><span class="n">button</span> <span class="o">==</span> <span class="s1">'LEFT'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">left_click</span><span class="p">(</span><span class="n">mouse_event</span><span class="o">.</span><span class="n">cell</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">mouse_event</span><span class="o">.</span><span class="n">button</span> <span class="o">==</span> <span class="s1">'RIGHT'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">right_click</span><span class="p">(</span><span class="n">mouse_event</span><span class="o">.</span><span class="n">cell</span><span class="p">)</span>
<span class="k">return</span> <span class="p">{}</span>
</pre></div></td></tr></table></div>
<p>The big thing I'm trying to work out right now is, how do I want to handle the fact that I've got two distinct sources of input here?
I was kind of considering using itertools.zip_longest, or something.
But switching the key interpretation to generators seems like the wrong move.
It probably ought to be done with data structures of some kind, like I was saying earlier.</p>
<p>All sorts of things I want to be doing with this...</p>
<p>One thing I should note is that I do have the nagging sense that I'm missing something, and potentially setting myself up to over-extend an idea or something.
Take the idea of the "item_dropped" event, for example.
The event is emitted from within the Inventory component, and intepreted by a generator method on the Game class.
If I move the logic into the "Event" instances, then that means that the Inventory component must somehow be able to access the logic, but the logic centers around changes to the Game and GameState, so the logic can't reside within the Inventory module.
(On the other hand, the current implementation of Inventory knows about the Map and Entity systems to a degree I'm not quite comfortable with.)
So, if the semantics of "item_dropped" focus on stuff in the Game object, but the Inventory cannot (should not, will not) see the Game object, does that mean that there needs to be a module that just contains functions that look like, but are not, methods of the game object?
That doesn't seem right.
Ideally, and I'm coming back to this so I think there might be something to it, there wouldn't be too much behavior embedded in the Events; instead, they'd key into some kind of data structure that converts input into a method call.
Maybe this would make more sense if the Inventory did some translation.
If, instead of drop_item emitting "item_dropped", it emitted something like "place: entity, coordinates", and everything that ends the player's turn perhaps emits some kind of "turn end" event.
Basically, instead of implementing drop_item as "do some bookkeeping and emit the item_dropped event", facyor it into "determine where the item will be placed, remove it from the list, and tell the game to place it at the coordinates".</p>
<hr class="docutils" />
<p>Next week, I'm not quite sure.
Maybe I'll re-do the save format so it's properly contained within a versioned object.
After that, maybe it's a good time to convert the GameStates into classes that contain state-specific data and keep it out of the Game object.</p>
Draw a Box 2018-05-182018-05-18T04:00:00-04:002018-05-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-18:/draw-a-box-2018-05-18<p class="first last">It's getting there.</p>
<p>In this post:</p>
<ul class="simple">
<li>I am consistent.</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>15 lines on May 11</li>
<li>15 lines on May 12</li>
<li>15 lines on May 13. I'm getting really tired of doing these repeated drawing lines exercises. I can't tell if the pen is actually working unless I mess up. Also, I did this batch late at night, and so it's bad. Hands are all shaky and stuff.</li>
<li>15 lines on May 14.</li>
<li>15 lines on May 15.</li>
<li>15 lines on May 16.</li>
<li>15 lines on May 17.</li>
</ul>
<p>For a total of 105 lines this week,
and 225 lines since I started counting.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Conworld Codex 2018-05-172018-05-17T04:00:00-04:002018-05-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-17:/conworld-codex-2018-05-17<p class="first last">This stuff is pretty tricky when you have almost no idea what you're doing.</p>
<p>In this post:</p>
<ul class="simple">
<li>Step one proves to be naïvely optimistic.</li>
<li>I do, though, manage to outline the adapter code between the models and the GUI (not yet implemented)... and then promptly rewrite both models and adapter.</li>
</ul>
<hr class="docutils" />
<p>Okay, let's see.
Step one here, is to put together some GUI code.</p>
<p>I should note here and now that a lot of my attempts to "do" GUI code are going to be kind of flailing and confused.</p>
<p>Anyway, what I have so far is the idea that "getting to the meat" of an event actually requires some somewhat deep nesting.
An event has four overall categories of events it relates to, and within those, the events that it relates to in such a way, and within those relationships, how the event is talked about.
Also, events relate to topics.</p>
<p>I think I'm going to have to try to sketch this out, because using words is a mess.</p>
<p>I had a revelation on Mastodon:</p>
<blockquote>
<p>I wish I could write GUI code as, like, a bunch of high-level relationships between components, and then apply styling to actually instantiate concrete components to implement the design.</p>
<p>Basically, I have been spoiled by the fact that CSS lets me toss down layout that looks completely asinine without styling, and then style the heck out of it.</p>
<p>I wonder if I'd get my wish if I made some "container" types, then wrote visitor code to process them...</p>
</blockquote>
<p>The basic idea is, what if I wrote code so as to defer the decisions that I, personally, do not feel qualified to make?
This feels like it would be kind of janky in a collaborative context, but that's not this code.
Basically, instead of wireframing the layout, I want to "wireframe the interactions".
Like, "here's the data you need to fulfill such and such hypothetical GUI action".</p>
<p>I took that idea and ran with it.
Now the "GUI" code is full of stub methods, some of which have some API in mind.
I'll try documenting the code first, so I know what it's supposed to do.</p>
<p>Hm.
Here's where I am now:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span>
<span class="normal">102</span>
<span class="normal">103</span>
<span class="normal">104</span>
<span class="normal">105</span>
<span class="normal">106</span>
<span class="normal">107</span>
<span class="normal">108</span>
<span class="normal">109</span>
<span class="normal">110</span>
<span class="normal">111</span>
<span class="normal">112</span>
<span class="normal">113</span>
<span class="normal">114</span>
<span class="normal">115</span>
<span class="normal">116</span>
<span class="normal">117</span>
<span class="normal">118</span>
<span class="normal">119</span>
<span class="normal">120</span>
<span class="normal">121</span>
<span class="normal">122</span>
<span class="normal">123</span>
<span class="normal">124</span>
<span class="normal">125</span>
<span class="normal">126</span>
<span class="normal">127</span>
<span class="normal">128</span>
<span class="normal">129</span>
<span class="normal">130</span>
<span class="normal">131</span>
<span class="normal">132</span>
<span class="normal">133</span>
<span class="normal">134</span>
<span class="normal">135</span>
<span class="normal">136</span>
<span class="normal">137</span>
<span class="normal">138</span>
<span class="normal">139</span>
<span class="normal">140</span>
<span class="normal">141</span>
<span class="normal">142</span>
<span class="normal">143</span>
<span class="normal">144</span>
<span class="normal">145</span>
<span class="normal">146</span>
<span class="normal">147</span>
<span class="normal">148</span>
<span class="normal">149</span>
<span class="normal">150</span>
<span class="normal">151</span>
<span class="normal">152</span>
<span class="normal">153</span>
<span class="normal">154</span>
<span class="normal">155</span>
<span class="normal">156</span>
<span class="normal">157</span>
<span class="normal">158</span>
<span class="normal">159</span>
<span class="normal">160</span>
<span class="normal">161</span>
<span class="normal">162</span>
<span class="normal">163</span>
<span class="normal">164</span>
<span class="normal">165</span>
<span class="normal">166</span>
<span class="normal">167</span>
<span class="normal">168</span>
<span class="normal">169</span>
<span class="normal">170</span>
<span class="normal">171</span>
<span class="normal">172</span>
<span class="normal">173</span>
<span class="normal">174</span>
<span class="normal">175</span>
<span class="normal">176</span>
<span class="normal">177</span>
<span class="normal">178</span>
<span class="normal">179</span>
<span class="normal">180</span>
<span class="normal">181</span>
<span class="normal">182</span>
<span class="normal">183</span>
<span class="normal">184</span>
<span class="normal">185</span>
<span class="normal">186</span>
<span class="normal">187</span>
<span class="normal">188</span>
<span class="normal">189</span>
<span class="normal">190</span>
<span class="normal">191</span>
<span class="normal">192</span>
<span class="normal">193</span>
<span class="normal">194</span>
<span class="normal">195</span>
<span class="normal">196</span>
<span class="normal">197</span>
<span class="normal">198</span>
<span class="normal">199</span>
<span class="normal">200</span>
<span class="normal">201</span>
<span class="normal">202</span>
<span class="normal">203</span>
<span class="normal">204</span>
<span class="normal">205</span>
<span class="normal">206</span>
<span class="normal">207</span>
<span class="normal">208</span>
<span class="normal">209</span>
<span class="normal">210</span>
<span class="normal">211</span>
<span class="normal">212</span>
<span class="normal">213</span>
<span class="normal">214</span>
<span class="normal">215</span>
<span class="normal">216</span>
<span class="normal">217</span>
<span class="normal">218</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""Main GUI code for Conworld Codex.</span>
<span class="sd">The model handler classes assume they have exclusive access to the database.</span>
<span class="sd">"""</span>
<span class="kn">import</span> <span class="nn">enum</span>
<span class="kn">import</span> <span class="nn">typing</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="n">session</span>
<span class="kn">from</span> <span class="nn">..</span> <span class="kn">import</span> <span class="n">models</span>
<span class="k">class</span> <span class="nc">Relation</span><span class="p">(</span><span class="n">enum</span><span class="o">.</span><span class="n">Enum</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""The four ways events can relate."""</span>
<span class="n">CONTAINED_BY</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="n">PRECEDED_BY</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="n">FOLLOWED_BY</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="n">CONTAINS</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">App</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""High-level abstraction."""</span>
<span class="n">session</span><span class="p">:</span> <span class="n">session</span><span class="o">.</span><span class="n">Session</span>
<span class="k">class</span> <span class="nc">EventWindow</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Container for rendering the window associated with an Event."""</span>
<span class="n">event</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Event</span>
<span class="n">app</span><span class="p">:</span> <span class="n">App</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">session</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">session</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the associated SQLAlchemy session."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">session</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">contained_by</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'RelationTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the RelationTab for Events that contain this one."""</span>
<span class="k">return</span> <span class="n">RelationTab</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">Relation</span><span class="o">.</span><span class="n">CONTAINED_BY</span><span class="p">)</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">preceded_by</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'RelationTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the RelationTab for Events that precede this one."""</span>
<span class="k">return</span> <span class="n">RelationTab</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">Relation</span><span class="o">.</span><span class="n">PRECEDED_BY</span><span class="p">)</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">followed_by</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'RelationTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the RelationTab for Events that follow this one."""</span>
<span class="k">return</span> <span class="n">RelationTab</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">Relation</span><span class="o">.</span><span class="n">FOLLOWED_BY</span><span class="p">)</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">contains</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'RelationTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the RelationTab for Events that are contained by this one."""</span>
<span class="k">return</span> <span class="n">RelationTab</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">Relation</span><span class="o">.</span><span class="n">CONTAINS</span><span class="p">)</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">topics</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'TopicsTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the TopicsTab for this Event."""</span>
<span class="k">return</span> <span class="n">TopicsTab</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">RelationTab</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Container for each tab within an EventWindow."""</span>
<span class="n">event_window</span><span class="p">:</span> <span class="n">EventWindow</span>
<span class="n">relation</span><span class="p">:</span> <span class="n">Relation</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">session</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">session</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the associated SQLAlchemy session."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">event_window</span><span class="o">.</span><span class="n">session</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">events</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="s1">'EventTab'</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of EventTabs associated with this tab."""</span>
<span class="c1"># TODO</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">unlinked_events</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">models</span><span class="o">.</span><span class="n">Event</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of events with no associated EventTab."""</span>
<span class="c1"># TODO</span>
<span class="k">def</span> <span class="nf">add_event</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Event</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'EventTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Add a tab for the given Event, and return the EventTab.</span>
<span class="sd"> Raises an exception if the Event already has a tab.</span>
<span class="sd"> """</span>
<span class="c1"># TODO</span>
<span class="k">class</span> <span class="nc">EventTab</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Container for each event within a RelationTab."""</span>
<span class="n">relation_tab</span><span class="p">:</span> <span class="n">RelationTab</span>
<span class="n">event</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Event</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">session</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">session</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the associated SQLAlchemy session."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">relation_tab</span><span class="o">.</span><span class="n">session</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">tellers</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="s1">'EventTellerTab'</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of EventTellerTabs associated with this tab."""</span>
<span class="c1"># TODO</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">unlinked_tellers</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">models</span><span class="o">.</span><span class="n">Teller</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of Tellers with no associated EventTellerTab."""</span>
<span class="c1"># TODO</span>
<span class="k">def</span> <span class="nf">add_teller</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">teller</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Teller</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'EventTellerTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Add a tab for the given Teller, and return the EventTellerTab.</span>
<span class="sd"> Raises an exception if the Teller already has a tab.</span>
<span class="sd"> """</span>
<span class="c1"># TODO</span>
<span class="k">def</span> <span class="nf">drop</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Remove this tab from the UI model, and the database if necessary."""</span>
<span class="c1"># TODO</span>
<span class="k">class</span> <span class="nc">EventTellerTab</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Container for each Teller within an EventTab."""</span>
<span class="n">event_tab</span><span class="p">:</span> <span class="n">EventTab</span>
<span class="n">teller</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Teller</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">session</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">session</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the associated SQLAlchemy session."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">event_tab</span><span class="o">.</span><span class="n">session</span>
<span class="k">def</span> <span class="nf">drop</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Remove this tab from the UI model, and the database if necessary."""</span>
<span class="c1"># TODO</span>
<span class="k">class</span> <span class="nc">TopicsTab</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Container for related topics."""</span>
<span class="n">event_window</span><span class="p">:</span> <span class="n">EventWindow</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">session</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">session</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the associated SQLAlchemy session."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">event_window</span><span class="o">.</span><span class="n">session</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">topics</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="s1">'TopicTab'</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of TopicTabs associated with this tab."""</span>
<span class="c1"># TODO</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">unlinked_topics</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">models</span><span class="o">.</span><span class="n">Topic</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of topics with no associated TopicTab."""</span>
<span class="c1"># TODO</span>
<span class="k">def</span> <span class="nf">add_topic</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">topic</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Topic</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'TopicTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Add a tab for the given Topic, and return the TopicTab.</span>
<span class="sd"> Raises an exception if the Topic already has a tab.</span>
<span class="sd"> """</span>
<span class="c1"># TODO</span>
<span class="k">class</span> <span class="nc">TopicTab</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Container for a specific Topic."""</span>
<span class="n">topics_tab</span><span class="p">:</span> <span class="n">TopicsTab</span>
<span class="n">topic</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Topic</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">session</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">session</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the associated SQLAlchemy session."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">topics_tab</span><span class="o">.</span><span class="n">session</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">tellers</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="s1">'TopicTellerTab'</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of TopicTellerTabs associated with this tab."""</span>
<span class="c1"># TODO</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">unlinked_tellers</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">models</span><span class="o">.</span><span class="n">Teller</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of Tellers with no associated TopicTellerTab."""</span>
<span class="c1"># TODO</span>
<span class="k">def</span> <span class="nf">add_teller</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">teller</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Teller</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'TopicTellerTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Add a tab for the given Teller, and return the TopicTellerTab.</span>
<span class="sd"> Raises an exception if the Teller already has a tab.</span>
<span class="sd"> """</span>
<span class="c1"># TODO</span>
<span class="k">def</span> <span class="nf">drop</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Remove this tab from the UI model, and the database if necessary."""</span>
<span class="c1"># TODO</span>
<span class="k">class</span> <span class="nc">TopicTellerTab</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Container for each Teller within an TopicTab."""</span>
<span class="n">topic_tab</span><span class="p">:</span> <span class="n">TopicTab</span>
<span class="n">teller</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Teller</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">session</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">session</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the associated SQLAlchemy session."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">topic_tab</span><span class="o">.</span><span class="n">session</span>
<span class="k">def</span> <span class="nf">drop</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Remove this tab from the UI model, and the database if necessary."""</span>
<span class="c1"># TODO</span>
</pre></div></td></tr></table></div>
<p>My big concern with this is that my current conception of this design attempts to track state that doesn't currently fit in the database.
I think I ought to rewrite the database layout some to normalize it more, and enforce the constraints I want with some kind of policy, rather than through the database structure.</p>
<p>I made the changes.
Here's where things ended up:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span>
<span class="normal">102</span>
<span class="normal">103</span>
<span class="normal">104</span>
<span class="normal">105</span>
<span class="normal">106</span>
<span class="normal">107</span>
<span class="normal">108</span>
<span class="normal">109</span>
<span class="normal">110</span>
<span class="normal">111</span>
<span class="normal">112</span>
<span class="normal">113</span>
<span class="normal">114</span>
<span class="normal">115</span>
<span class="normal">116</span>
<span class="normal">117</span>
<span class="normal">118</span>
<span class="normal">119</span>
<span class="normal">120</span>
<span class="normal">121</span>
<span class="normal">122</span>
<span class="normal">123</span>
<span class="normal">124</span>
<span class="normal">125</span>
<span class="normal">126</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""SQLAlchemy ORM classes for modeling codex data."""</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">Column</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">String</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">,</span> <span class="n">UniqueConstraint</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="n">relationship</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.ext.declarative</span> <span class="kn">import</span> <span class="n">declarative_base</span>
<span class="n">Base</span> <span class="o">=</span> <span class="n">declarative_base</span><span class="p">()</span> <span class="c1"># pylint: disable=invalid-name</span>
<span class="k">class</span> <span class="nc">Event</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""The events within the history of the codex."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'events'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Teller</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""The people talking about the events."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'tellers'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">topic_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'topics.id'</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">topic</span> <span class="o">=</span> <span class="n">relationship</span><span class="p">(</span><span class="s1">'Topic'</span><span class="p">,</span> <span class="n">back_populates</span><span class="o">=</span><span class="s1">'teller'</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Topic</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""A person, place, or thing."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'topics'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">teller</span> <span class="o">=</span> <span class="n">relationship</span><span class="p">(</span><span class="s1">'Teller'</span><span class="p">,</span> <span class="n">back_populates</span><span class="o">=</span><span class="s1">'topic'</span><span class="p">,</span> <span class="n">uselist</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">EventTopic</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""How a topic relates to an event."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'event_topics'</span>
<span class="n">__table_args__</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">UniqueConstraint</span><span class="p">(</span><span class="s1">'topic_id'</span><span class="p">,</span> <span class="s1">'event_id'</span><span class="p">),</span>
<span class="p">)</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">topic_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'topics.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">event_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'events.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">TopicRelation</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""How a topic relates to an event, according to a teller."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'topic_relations'</span>
<span class="n">__table_args__</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">UniqueConstraint</span><span class="p">(</span><span class="s1">'event_topic_id'</span><span class="p">,</span> <span class="s1">'teller_id'</span><span class="p">),</span>
<span class="p">)</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">event_topic_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span>
<span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'event_topics.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">teller_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'tellers.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Contribution</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""How one event contributed to another."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'contributions'</span>
<span class="n">__table_args__</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">UniqueConstraint</span><span class="p">(</span><span class="s1">'cause'</span><span class="p">,</span> <span class="s1">'effect'</span><span class="p">),</span>
<span class="p">)</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">cause</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'events.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">effect</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'events.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">ContributionTeller</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""How one event contributed to another, according to a teller."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'contribution_tellers'</span>
<span class="n">__table_args__</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">UniqueConstraint</span><span class="p">(</span><span class="s1">'contribution_id'</span><span class="p">,</span> <span class="s1">'teller_id'</span><span class="p">),</span>
<span class="p">)</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">contribution_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span>
<span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'contributions.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">teller_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'tellers.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">PartOf</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""How one event was part of another."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'parts_of'</span>
<span class="n">__table_args__</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">UniqueConstraint</span><span class="p">(</span><span class="s1">'part'</span><span class="p">,</span> <span class="s1">'whole'</span><span class="p">),</span>
<span class="p">)</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">part</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'events.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">whole</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'events.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">PartOfTeller</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""How one event was part of another, according to a teller."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'part_of_tellers'</span>
<span class="n">__table_args__</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">UniqueConstraint</span><span class="p">(</span><span class="s1">'part_of_id'</span><span class="p">,</span> <span class="s1">'teller_id'</span><span class="p">),</span>
<span class="p">)</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">part_of_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'parts_of.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">teller_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'tellers.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">)</span>
</pre></div></td></tr></table></div>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span>
<span class="normal">102</span>
<span class="normal">103</span>
<span class="normal">104</span>
<span class="normal">105</span>
<span class="normal">106</span>
<span class="normal">107</span>
<span class="normal">108</span>
<span class="normal">109</span>
<span class="normal">110</span>
<span class="normal">111</span>
<span class="normal">112</span>
<span class="normal">113</span>
<span class="normal">114</span>
<span class="normal">115</span>
<span class="normal">116</span>
<span class="normal">117</span>
<span class="normal">118</span>
<span class="normal">119</span>
<span class="normal">120</span>
<span class="normal">121</span>
<span class="normal">122</span>
<span class="normal">123</span>
<span class="normal">124</span>
<span class="normal">125</span>
<span class="normal">126</span>
<span class="normal">127</span>
<span class="normal">128</span>
<span class="normal">129</span>
<span class="normal">130</span>
<span class="normal">131</span>
<span class="normal">132</span>
<span class="normal">133</span>
<span class="normal">134</span>
<span class="normal">135</span>
<span class="normal">136</span>
<span class="normal">137</span>
<span class="normal">138</span>
<span class="normal">139</span>
<span class="normal">140</span>
<span class="normal">141</span>
<span class="normal">142</span>
<span class="normal">143</span>
<span class="normal">144</span>
<span class="normal">145</span>
<span class="normal">146</span>
<span class="normal">147</span>
<span class="normal">148</span>
<span class="normal">149</span>
<span class="normal">150</span>
<span class="normal">151</span>
<span class="normal">152</span>
<span class="normal">153</span>
<span class="normal">154</span>
<span class="normal">155</span>
<span class="normal">156</span>
<span class="normal">157</span>
<span class="normal">158</span>
<span class="normal">159</span>
<span class="normal">160</span>
<span class="normal">161</span>
<span class="normal">162</span>
<span class="normal">163</span>
<span class="normal">164</span>
<span class="normal">165</span>
<span class="normal">166</span>
<span class="normal">167</span>
<span class="normal">168</span>
<span class="normal">169</span>
<span class="normal">170</span>
<span class="normal">171</span>
<span class="normal">172</span>
<span class="normal">173</span>
<span class="normal">174</span>
<span class="normal">175</span>
<span class="normal">176</span>
<span class="normal">177</span>
<span class="normal">178</span>
<span class="normal">179</span>
<span class="normal">180</span>
<span class="normal">181</span>
<span class="normal">182</span>
<span class="normal">183</span>
<span class="normal">184</span>
<span class="normal">185</span>
<span class="normal">186</span>
<span class="normal">187</span>
<span class="normal">188</span>
<span class="normal">189</span>
<span class="normal">190</span>
<span class="normal">191</span>
<span class="normal">192</span>
<span class="normal">193</span>
<span class="normal">194</span>
<span class="normal">195</span>
<span class="normal">196</span>
<span class="normal">197</span>
<span class="normal">198</span>
<span class="normal">199</span>
<span class="normal">200</span>
<span class="normal">201</span>
<span class="normal">202</span>
<span class="normal">203</span>
<span class="normal">204</span>
<span class="normal">205</span>
<span class="normal">206</span>
<span class="normal">207</span>
<span class="normal">208</span>
<span class="normal">209</span>
<span class="normal">210</span>
<span class="normal">211</span>
<span class="normal">212</span>
<span class="normal">213</span>
<span class="normal">214</span>
<span class="normal">215</span>
<span class="normal">216</span>
<span class="normal">217</span>
<span class="normal">218</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""Main GUI code for Conworld Codex.</span>
<span class="sd">The model handler classes assume they have exclusive access to the database.</span>
<span class="sd">"""</span>
<span class="kn">import</span> <span class="nn">enum</span>
<span class="kn">import</span> <span class="nn">typing</span>
<span class="kn">import</span> <span class="nn">sqlalchemy.orm.session</span>
<span class="kn">from</span> <span class="nn">..</span> <span class="kn">import</span> <span class="n">models</span>
<span class="k">class</span> <span class="nc">Relation</span><span class="p">(</span><span class="n">enum</span><span class="o">.</span><span class="n">Enum</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""The four ways events can relate."""</span>
<span class="n">CONTAINED_BY</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="n">PRECEDED_BY</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="n">FOLLOWED_BY</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="n">CONTAINS</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">App</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""High-level abstraction."""</span>
<span class="n">session</span><span class="p">:</span> <span class="n">sqlalchemy</span><span class="o">.</span><span class="n">orm</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">Session</span>
<span class="k">class</span> <span class="nc">EventWindow</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Container for rendering the window associated with an Event."""</span>
<span class="n">event</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Event</span>
<span class="n">app</span><span class="p">:</span> <span class="n">App</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">session</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">sqlalchemy</span><span class="o">.</span><span class="n">orm</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the associated SQLAlchemy session."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">session</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">contained_by</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'RelationTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the RelationTab for Events that contain this one."""</span>
<span class="k">return</span> <span class="n">RelationTab</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">Relation</span><span class="o">.</span><span class="n">CONTAINED_BY</span><span class="p">)</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">preceded_by</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'RelationTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the RelationTab for Events that precede this one."""</span>
<span class="k">return</span> <span class="n">RelationTab</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">Relation</span><span class="o">.</span><span class="n">PRECEDED_BY</span><span class="p">)</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">followed_by</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'RelationTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the RelationTab for Events that follow this one."""</span>
<span class="k">return</span> <span class="n">RelationTab</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">Relation</span><span class="o">.</span><span class="n">FOLLOWED_BY</span><span class="p">)</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">contains</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'RelationTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the RelationTab for Events that are contained by this one."""</span>
<span class="k">return</span> <span class="n">RelationTab</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">Relation</span><span class="o">.</span><span class="n">CONTAINS</span><span class="p">)</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">topics</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'TopicsTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the TopicsTab for this Event."""</span>
<span class="k">return</span> <span class="n">TopicsTab</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">RelationTab</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Container for each tab within an EventWindow."""</span>
<span class="n">event_window</span><span class="p">:</span> <span class="n">EventWindow</span>
<span class="n">relation</span><span class="p">:</span> <span class="n">Relation</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">session</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">sqlalchemy</span><span class="o">.</span><span class="n">orm</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the associated SQLAlchemy session."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">event_window</span><span class="o">.</span><span class="n">session</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">events</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="s1">'EventTab'</span><span class="p">,</span> <span class="o">...</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of EventTabs associated with this tab."""</span>
<span class="c1"># TODO</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">unlinked_events</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">models</span><span class="o">.</span><span class="n">Event</span><span class="p">,</span> <span class="o">...</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of events with no associated EventTab."""</span>
<span class="c1"># TODO</span>
<span class="k">def</span> <span class="nf">add_event</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Event</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'EventTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Add a tab for the given Event, and return the EventTab.</span>
<span class="sd"> Raises an exception if the Event already has a tab.</span>
<span class="sd"> """</span>
<span class="c1"># TODO</span>
<span class="k">class</span> <span class="nc">EventTab</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Container for each event within a RelationTab."""</span>
<span class="n">relation_tab</span><span class="p">:</span> <span class="n">RelationTab</span>
<span class="n">event</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Event</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">session</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">sqlalchemy</span><span class="o">.</span><span class="n">orm</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the associated SQLAlchemy session."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">relation_tab</span><span class="o">.</span><span class="n">session</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">tellers</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="s1">'EventTellerTab'</span><span class="p">,</span> <span class="o">...</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of EventTellerTabs associated with this tab."""</span>
<span class="c1"># TODO</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">unlinked_tellers</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">models</span><span class="o">.</span><span class="n">Teller</span><span class="p">,</span> <span class="o">...</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of Tellers with no associated EventTellerTab."""</span>
<span class="c1"># TODO</span>
<span class="k">def</span> <span class="nf">add_teller</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">teller</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Teller</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'EventTellerTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Add a tab for the given Teller, and return the EventTellerTab.</span>
<span class="sd"> Raises an exception if the Teller already has a tab.</span>
<span class="sd"> """</span>
<span class="c1"># TODO</span>
<span class="k">def</span> <span class="nf">drop</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Remove this tab from the UI model."""</span>
<span class="c1"># TODO</span>
<span class="k">class</span> <span class="nc">EventTellerTab</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Container for each Teller within an EventTab."""</span>
<span class="n">event_tab</span><span class="p">:</span> <span class="n">EventTab</span>
<span class="n">teller</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Teller</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">session</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">sqlalchemy</span><span class="o">.</span><span class="n">orm</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the associated SQLAlchemy session."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">event_tab</span><span class="o">.</span><span class="n">session</span>
<span class="k">def</span> <span class="nf">drop</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Remove this tab from the UI model."""</span>
<span class="c1"># TODO</span>
<span class="k">class</span> <span class="nc">TopicsTab</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Container for related topics."""</span>
<span class="n">event_window</span><span class="p">:</span> <span class="n">EventWindow</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">session</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">sqlalchemy</span><span class="o">.</span><span class="n">orm</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the associated SQLAlchemy session."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">event_window</span><span class="o">.</span><span class="n">session</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">topics</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="s1">'TopicTab'</span><span class="p">,</span> <span class="o">...</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of TopicTabs associated with this tab."""</span>
<span class="c1"># TODO</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">unlinked_topics</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">models</span><span class="o">.</span><span class="n">Topic</span><span class="p">,</span> <span class="o">...</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of topics with no associated TopicTab."""</span>
<span class="c1"># TODO</span>
<span class="k">def</span> <span class="nf">add_topic</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">topic</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Topic</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'TopicTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Add a tab for the given Topic, and return the TopicTab.</span>
<span class="sd"> Raises an exception if the Topic already has a tab.</span>
<span class="sd"> """</span>
<span class="c1"># TODO</span>
<span class="k">class</span> <span class="nc">TopicTab</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Container for a specific Topic."""</span>
<span class="n">topics_tab</span><span class="p">:</span> <span class="n">TopicsTab</span>
<span class="n">topic</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Topic</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">session</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">sqlalchemy</span><span class="o">.</span><span class="n">orm</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the associated SQLAlchemy session."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">topics_tab</span><span class="o">.</span><span class="n">session</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">tellers</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="s1">'TopicTellerTab'</span><span class="p">,</span> <span class="o">...</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of TopicTellerTabs associated with this tab."""</span>
<span class="c1"># TODO</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">unlinked_tellers</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">models</span><span class="o">.</span><span class="n">Teller</span><span class="p">,</span> <span class="o">...</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Return the list of Tellers with no associated TopicTellerTab."""</span>
<span class="c1"># TODO</span>
<span class="k">def</span> <span class="nf">add_teller</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">teller</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Teller</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'TopicTellerTab'</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Add a tab for the given Teller, and return the TopicTellerTab.</span>
<span class="sd"> Raises an exception if the Teller already has a tab.</span>
<span class="sd"> """</span>
<span class="c1"># TODO</span>
<span class="k">def</span> <span class="nf">drop</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Remove this tab from the UI model."""</span>
<span class="c1"># TODO</span>
<span class="k">class</span> <span class="nc">TopicTellerTab</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Container for each Teller within an TopicTab."""</span>
<span class="n">topic_tab</span><span class="p">:</span> <span class="n">TopicTab</span>
<span class="n">teller</span><span class="p">:</span> <span class="n">models</span><span class="o">.</span><span class="n">Teller</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">session</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">sqlalchemy</span><span class="o">.</span><span class="n">orm</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the associated SQLAlchemy session."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">topic_tab</span><span class="o">.</span><span class="n">session</span>
<span class="k">def</span> <span class="nf">drop</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Remove this tab from the UI model."""</span>
<span class="c1"># TODO</span>
</pre></div></td></tr></table></div>
<p>(Pictured: why I don't like the idea of changing code after I paste it in. It's full of random quality-of-life changes I realized I wanted after I wrote it.)
Anyway, I can definitely see some places this might change, but I think the interface is <em>almost</em> correct, which is good enough for now, since nobody else depends on this code.
What I'm hitting now is, I'm actually not so familiar with queries in SQLAlchemy, so I'll have to learn to use them before I can implement most of this.</p>
<hr class="docutils" />
<p>Next week, I should learn how to use SQLAlchemy queries.</p>
Demiurgent Business 2018-05-162018-05-16T04:00:00-04:002018-05-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-16:/demiurgent-business-2018-05-16<p class="first last">There's some really good stuff in here.</p>
<p>In this post:</p>
<ul class="simple">
<li>Polaris's design really blows me away. It looks like a great choice if you want a really tragic experience.</li>
</ul>
<hr class="docutils" />
<p>Shortly after the last post, I purchased and read over <a class="reference external" href="http://www.tao-games.com/polaris/">Polaris: Chivalric Tragedy at the Utmost North</a>.
It wasn't what I'm looking for tonally, but I think I can take a lot of inspiration from the structure of play.</p>
<p>At a high level, I picked out:</p>
<ul class="simple">
<li>GM duties are split between players, and depend on seating. I'm neutral on this.</li>
<li>The choice of what to use conflict resolution mechanics for is down, not to what's "reasonable", but whatever actions that the players contest the feasibility/outcome of. This sounds like a useful direction to take things.</li>
<li>Flow of play, including conflict resolution, is regulated using some pre-defined "ritual phrases" that relate to play and each other in specific ways. I don't want all of the precise phrases from Polaris, for obvious reasons, but I can see a lot of utility in introducing a character each session with something like "<strong>Yep, that's me, [name]. I'm sure you're wondering why I'm in this situation.</strong>"</li>
<li>Characters advance by becoming more bitter, self-centered, and jaded, and can only die after passing specific thresholds. This is obviously not something I want, tonally. As I said, my gut feeling is that advancement should be done via bonds between characters, somehow.</li>
</ul>
<p>I'm definitely in favor of moving more towards Polaris's mostly-diceless setup.
I know I don't want to come up with some kind of "high-detail simulation of the fictional world" setup.
Another thing I know is that I want the ability to pull off non-linear stuff, which, I'm not really sure how to square with any form of character advancement.
Maybe a given "episode" could be non-linear, at the players' option, but everything between episodes takes place in chronological order, because that's easier.</p>
<p>Anyway, I'll probably come back to Polaris to get more mechanical ideas, but now I want to focus on tone and setting.
Maybe setting first.</p>
<hr class="docutils" />
<p>Next week, I don't know which RPG-set-in-a-high-school I want, so I'll be looking at a few.</p>
Interactions Afforded By Online Media2018-05-15T04:00:00-04:002018-05-29T15:32:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-15:/interactions-afforded-by-online-media<p class="first last">Attempting To Develop A Theoretical Framework For Why People Are Yelling At You</p>
<p>In this post:</p>
<ul class="simple">
<li>A preliminary (from me) attempt to describe failure modes in online media.</li>
<li>I try to come up with something visibly distinct from the above.</li>
<li>Updates following feedback, <strong>in bold</strong>. (Feedback on May 29 from <a class="reference external" href="https://niu.moe/@Wolf480pl">Wolf480pl</a>.)</li>
<li>The "<strong>The Algorithm</strong>" stuff and similar things aren't updates; I didn't really think this through.</li>
</ul>
<hr class="docutils" />
<p>I recently joined a discussion on Mastodon, where everyone involved realized that, although it has some helpful features and good communities, and isn't going to have <strong>The Algorithm</strong>, Mastodon still has some of the same affordances that are such a problem on Twitter.
After some back-and-forth, I decided that it would probably help to have a comparison the affordances that different services offer/have offered over the years, and to reason about their effects at scale.</p>
<p>So, here's a high-level view of various means of communication.
This is limited to services I'm somewhat familiar with, and my own experiences with them.
Also, some of the details are probably wrong, because I was prioritizing getting a quick sketch out over complete accuracy in the face of constant software updates.</p>
<dl class="docutils">
<dt>a simple webpage</dt>
<dd><dl class="first last docutils">
<dt>barrier to entry:</dt>
<dd>Has lowered over time</dd>
<dt>where posts go:</dt>
<dd>On a single website.</dd>
<dt>how content is discovered:</dt>
<dd>Originally, the URL was required to find content, but search engines have automated the process of discovery, so now keyword search is sufficient to browse the surface web.</dd>
<dt>how may users react:</dt>
<dd>On its own, static websites don't allow for direct feedback.
They may embed or link to some of the other services.
Also, one person could publish a webpage in response to another webpage.
<strong>Email-based contact forms</strong></dd>
<dt>who sees the reaction when:</dt>
<dd>In the <strong>first</strong> case, the feedback characteristics depend on the service used.
In the <strong>second</strong> case, the reaction doesn't relate to the original in a structured way, except that it could contain a link back, which search engines will index.
<strong>In the third case, the reaction is in the form of an email thread. See below.</strong></dd>
<dt>what is "push" and what is "pull":</dt>
<dd>The webpage gets published, updated, and possibly taken down, at the desires of (mostly) the maintainer.
The webpage is not updated very quickly, so the consumers can read it at leisure.</dd>
</dl>
</dd>
<dt>email</dt>
<dd><dl class="first last docutils">
<dt>barrier to entry:</dt>
<dd>Low</dd>
<dt>where posts go:</dt>
<dd>To the specified recipient(s).
People can form "mailing lists".</dd>
<dt>how content is discovered:</dt>
<dd>Through sharing.
Incoming email is often subjected to various forms of algorithmic filtering.</dd>
<dt>how may users react:</dt>
<dd>They can reply to specific messages, forward them to other people, or write new messages.</dd>
<dt>who sees the reaction when:</dt>
<dd>Reactions are another kind of "post", and are subject to the same controls.</dd>
<dt>what is "push" and what is "pull":</dt>
<dd>The writer publishes to a server, which the reader then downloads the message from, and reads at leisure.
<strong>Counterpoint: many email servers and clients provide notification functionality, which, in terms of user experience, acts as "push".</strong>
<strong>Mailing lists are an early example of the "firehose" effect, in which a single post demands individual attention from many people, which tends to turn into "at least one person has to deal with many posts". The use of automated systems to manage email arguably made this worse in some contexts than Twitter today.</strong></dd>
</dl>
</dd>
<dt>bulletin board</dt>
<dd><dl class="first last docutils">
<dt>barrier to entry:</dt>
<dd>Needs email</dd>
<dt>where posts go:</dt>
<dd>New topics go in the top-level, or sub-forums.
The layout is determined by the forum administrator.
Many bulletin boards also include "private message" functionality, which resembles a reduced form of email.</dd>
<dt>how content is discovered:</dt>
<dd><strong>The hierarchy of sub-forums guides the user based on which topics they're interested in, and each sub-forum often has a link to the most-recently replied-to topic.</strong>
The website often provides search functionality.</dd>
<dt>how may users react:</dt>
<dd>By posting "replies" to a topic.
All posts look almost the same within a topic, but replies aren't visible next to topics at a high level.</dd>
<dt>who sees the reaction when:</dt>
<dd>Anyone with access to a sub-forum can read replies within it at leisure.
Many bulletin boards offer the ability to "subscribe" to a topic, in order to receive email notifications of replies, on some schedule.</dd>
<dt>what is "push" and what is "pull":</dt>
<dd>Topics and replies are published to the central server, which the readers then browse the messages from.</dd>
</dl>
</dd>
<dt>livejournal and similar sites</dt>
<dd><dl class="first last docutils">
<dt>barrier to entry:</dt>
<dd>Needs email</dd>
<dt>where posts go:</dt>
<dd>On personal journals, or specially created communities.
The communities are created by any user who wants.</dd>
<dt>how content is discovered:</dt>
<dd>There are various ways to subscribe to content from different sources.
I think.
I don't really remember how this worked.</dd>
<dt>how may users react:</dt>
<dd>Entries have threaded comments</dd>
<dt>who sees the reaction when:</dt>
<dd>I believe it's mostly similar to the bulletin board system.</dd>
<dt>what is "push" and what is "pull":</dt>
<dd>I believe it's mostly similar to the bulletin board system.</dd>
</dl>
</dd>
<dt>independent blogs</dt>
<dd><dl class="first last docutils">
<dt>barrier to entry:</dt>
<dd>similar to that of a simple webpage, depending on how much control you want</dd>
<dt>where posts go:</dt>
<dd>On the blog</dd>
<dt>how content is discovered:</dt>
<dd>Blogs can offer search engines, tagging, categories.</dd>
<dt>how may users react:</dt>
<dd>Some blogging software has commenting modules.
Comments are visible below the associated post.</dd>
<dt>who sees the reaction when:</dt>
<dd>Comments are public; also, the blog may have a moderation feature that requires someone to explicitly approve some or all comments.</dd>
<dt>what is "push" and what is "pull":</dt>
<dd>Again, it pretty much works like bulletin boards.</dd>
</dl>
</dd>
<dt>twitter</dt>
<dd><dl class="first last docutils">
<dt>barrier to entry:</dt>
<dd>Needs email</dd>
<dt>where posts go:</dt>
<dd>On the personal timeline, on followers' timelines, in the timeline for hashtags, and anywhere else deemed appropriate by <strong>The Algorithm</strong>.
Some posts are only visible in a sub-view.
Also offers "direct message" capabilities about on par with some bulletin boards.</dd>
<dt>how content is discovered:</dt>
<dd>Users can follow each other to get a subset of their posts.
There's also a "list" feature that I've barely engaged with.
And search.</dd>
<dt>how may users react:</dt>
<dd>The answer to this question changed drastically over time.
Twitter is, in some respects, retrofitted on top of its original conception, which didn't anticipate retweets, or, if I'm understanding its original purpose correctly, replies.
Users can "reply" to a tweet, or retweet it, or like it.</dd>
<dt>who sees the reaction when:</dt>
<dd>"Reply" tweets are (<em>I think</em>) only visible in a follower's timeline if the parent tweet was visible, and they are also following the replier.
Or something.
Reply tweets are not automatically visible from profile timelines.
Retweets are visible from the profile timeline, and in followers' timelines.
I don't know how multiple retweets of the same tweet, spread out through time, work.
Likes used to just send a notification to the poster of the liked tweet, but now they are <strong>Grist For The Algorithm</strong>, and cause the liked tweet to appear all over the place, seemingly at random.</dd>
<dt>what is "push" and what is "pull":</dt>
<dd>Many, many notifications can be delivered through email, text, or other clients.
Compared to the previous entries, it's quite easy to end up with a "firehose" type situation, in which new content enters your feed faster than you can read through it.</dd>
</dl>
</dd>
<dt>facebook</dt>
<dd><dl class="first last docutils">
<dt>barrier to entry:</dt>
<dd>I think it needs a phone</dd>
<dt>where posts go:</dt>
<dd>You have a "wall", and that's where posts usually go.
You can also post in groups.
There are a bunch of privacy settings that apparently are never set how you want them to be, even immediately after you try to fix them.</dd>
<dt>how content is discovered:</dt>
<dd>It used to be about chronological feeds and such, but <strong>The Algorithm</strong> made sure we don't have to deal with that nonsense.
And search.</dd>
<dt>how may users react:</dt>
<dd>A single "like" button has turned into a variety of emotional reactions.
Posts can be commented on, with threading.</dd>
<dt>who sees the reaction when:</dt>
<dd>There are some really pushy emails that I eventually turned off, years ago.</dd>
<dt>what is "push" and what is "pull":</dt>
<dd>I assume that the mobile clients have push notifications, and maybe through the web as well.
Also susceptible to "firehose".</dd>
</dl>
</dd>
<dt>tumblr</dt>
<dd><dl class="first last docutils">
<dt>barrier to entry:</dt>
<dd>Needs email</dd>
<dt>where posts go:</dt>
<dd>On the personal blog, or a side-blog.
Posts have tags, which cause the post to appear in the stream for that tag.</dd>
<dt>how content is discovered:</dt>
<dd>Content is visible through a blog's subdomain, and users can subscribe to blogs, and I think tags.
And search.</dd>
<dt>how may users react:</dt>
<dd>There is a "like" feature, which is thankfully somewhat more restrained than Twitter's.
Somewhat confusingly, there's both "reply" and "reblog".
"Reblog" is a new post, "reply" is not.</dd>
<dt>who sees the reaction when:</dt>
<dd>Reblogs are exactly as visible as normal posts.
Replies send a message to... the original poster? I think? and are also visible in the notes if you try really hard.</dd>
<dt>what is "push" and what is "pull":</dt>
<dd>I assume there are various ways to get notifications, but I turned most of them off.
Also susceptible to "firehose".</dd>
</dl>
</dd>
<dt>reddit</dt>
<dd><dl class="first last docutils">
<dt>barrier to entry:</dt>
<dd>Needs email</dd>
<dt>where posts go:</dt>
<dd>In a pre-selected sub-reddit.
The sub-reddits are created by any user who wants.</dd>
<dt>how content is discovered:</dt>
<dd>Users can manage their subscriptions to sub-reddits.
There are "top posts" for both the site as a whole and subscribed sub-reddits.</dd>
<dt>how may users react:</dt>
<dd>Topics can be replied to with threaded comments.
Topics and comments have upvote/downvote arrows that are supposed to rate the content on relevance and constructiveness.
In practice, they've been griefed so much that they require obfuscation to avoid vote manipulation.
Some sub-reddits have bot users that can publicize stuff like links from other sub-reddits.</dd>
<dt>who sees the reaction when:</dt>
<dd>The original poster gets informed of replies, and I think there's similar logic for threaded replies.
It's supposed to be hard to tell when a post got a vote.</dd>
<dt>what is "push" and what is "pull":</dt>
<dd>It pretty much works like bulletin boards.</dd>
</dl>
</dd>
<dt>disqus</dt>
<dd><dl class="first last docutils">
<dt>barrier:</dt>
<dd>Needs email</dd>
<dt>where posts go:</dt>
<dd>disqus is a service that adds commenting functionality to other websites.
The comments are threaded.</dd>
<dt>how content is discovered:</dt>
<dd>A user's comments are visible through their profile, but mostly, the comments are mainly going to be seen from the associated entry.</dd>
<dt>how may users react:</dt>
<dd>I think there's a voting system.</dd>
<dt>who sees the reaction when:</dt>
<dd>Like a lot of services, notifications go to the original poster and the person who got replied to.</dd>
<dt>what is "push" and what is "pull":</dt>
<dd>I don't know when disqus becomes aware of the original post, but all comments go to, and are served from, the disqus servers.</dd>
</dl>
</dd>
<dt>google plus</dt>
<dd><dl class="first last docutils">
<dt>barrier:</dt>
<dd>Needs Google account</dd>
<dt>where posts go:</dt>
<dd>On the personal feed, or within personally curated "circles".</dd>
<dt>how content is discovered:</dt>
<dd>Posts to circles are visible to the people in those circles, and I assume there's some kind of <strong>Algorithmic Curation</strong> to filter down the public posts based on who's looking.</dd>
<dt>how may users react:</dt>
<dd>They can "+1" stuff, and comment on posts.
G+ got shoved into YouTube somehow, so I assume there's some form of comment threading.</dd>
<dt>who sees the reaction when:</dt>
<dd>I believe it's the typical "notification to poster" thing.</dd>
<dt>what is "push" and what is "pull":</dt>
<dd>It's like bulletin boards.</dd>
</dl>
</dd>
<dt>wave</dt>
<dd><dl class="first last docutils">
<dt>barrier to entry:</dt>
<dd>Needed Google account back in the day, now I have no idea
<strong>Nobody pointed this out to me, but I just checked the incubator page, and "The Wave project retired on 2018-01-15", probably to nobody's great surprise.</strong></dd>
<dt>where posts go:</dt>
<dd>... Like... anywhere. I think. I don't know.
Thread replies to a threaded reply, start up a game of checkers in the comments.
Wave is very hard to reason about.</dd>
<dt>how content is discovered:</dt>
<dd>I actually have no recollection of what caused me to be aware of any given post.</dd>
<dt>how may users react:</dt>
<dd>Reply to everything.
Edit everything in real-time.
It's bonkers.</dd>
<dt>who sees the reaction when:</dt>
<dd>Everyone sees everything simultaneously, then all their laptops overheat at once.</dd>
<dt>what is "push" and what is "pull":</dt>
<dd>Keystrokes are streamed to and from the server in real time.</dd>
</dl>
</dd>
</dl>
<p>With regards to the last one, I'd like to point out <a class="reference external" href="https://twitter.com/kellygoround/status/257905419765305344">this evergreen tweet</a>.</p>
<p>In any case, a lot of these platforms have launched harassment campaigns.
Someone attempting to design a platform around reducing online harassment has to figure out two things:</p>
<ul class="simple">
<li>How to discourage harassment campaigns within the service.</li>
<li>How to be more appealing than other services, so as to reduce those services' ability to field harassment campaigns.</li>
</ul>
<p>Notes from looking over the above:</p>
<ul class="simple">
<li>Voting/karma systems should not take center stage. When they're not really "for" anything, they appear to be able to aspire to neutrality. In the case of reddit, I'd guess that they contributed to cultures of groupthink and echo chambers.</li>
<li>I feel like twitter and tumblr treating posts and reactions to posts as mostly the same, is a contributing factor. It's not as bad in the context of email, because email is not publicly visible. When combined with public visibility, the retweet/reblog functionality gets more and more eyes on the post, leading to exponential growth. This is desirable in some contexts, such as promoting fundraisers, but in other contexts it contributes to dogpiles.</li>
<li>In a public context, I think I prefer to have "replies" be distinct from "posts", but I doubt the writeup really bears that out.</li>
</ul>
<p>One possible way to handle retweet functionality would be to make it function explicitly as endorsements.
Have the moderation for a bad retweet assign "fractional strikes" for infractions, to everyone who retweets, according to a PageRank score or something.</p>
<hr class="docutils" />
<p>One strength of social media that came up in the discussion was:</p>
<blockquote>
<p>I'd treat talking on socnets like talking in the hall - anyone can just come by and join the discussion.</p>
<p>If you want a private conversation, there are DMs, chatrooms, etc.</p>
<p class="attribution">—<a class="reference external" href="https://niu.moe/@Wolf480pl">https://niu.moe/@Wolf480pl</a></p>
</blockquote>
<p>To promote that functionality, perhaps "conversation" should be the first-class citizen of the site?
I can take that in all sorts of directions, but I think the main question should be, how do the users' affordances interact at scale.</p>
<p>So, a User can start a Conversation.
Perhaps it has a Title, or a Tagline.
Any User in a Conversation should be able to make a Comment.
How are Conversations to be discovered?
I could imagine a tumblr-style Tag system, except that the Tags apply to the Conversation as a whole, and Users can Vote, not on the "worth" of a Conversation or Comment, but how well a Tag applies to the Conversation.
And when a User Comments in a Conversation, that Conversation should appear in their Profile.</p>
<p>Suppose a new Conversation can have a Title of at most 500 Characters (whatever <em>those</em> are!), and then an optional initial Comment.
I don't know whether we'd want Comments to have a length limit.
I'd want to put the reactions on like a 3-state toggle:</p>
<ul class="simple">
<li>No reaction</li>
<li>Private Like</li>
<li>Public Like (should also make the Conversation visible, as if they had Commented)</li>
</ul>
<p>This overall concept is not even all the way to "half-baked", so I don't have any confidence yet that it would fulfill the first goal.</p>
<p>I've been really down on <strong>The Algorithm</strong> over the course of this post, but perhaps algorithmic stuff could deliver value in the form of suggested courses of action; there does need to be some way to deal with spam.</p>
<p>Actually, I don't want to slot this into my rotation, but you know what would be really cool if it didn't already exist?
High-level modeling of social dynamics given different interacting websites.
Like, model the content of a social network in terms of the content's call-to-action, and look at the outcomes of different forms of discoverability.</p>
<p>There are various ways to try to mediate the effects of dogpiling.
The Conversation idea would collect all Comments on a single page, and the natural place to put the reply box would be <em>under</em> the rest of the Comments.
Perhaps the reply form could display the number of unread Comments above.
Like, not stopping them, but just letting them know that there are 500 comments they haven't bothered to look at, or whatever.</p>
<p>Possibly, there'd be some way to incorporate G+'s circles concept, be the one in control of who your participation gets publicized to.
I'm kind of down on the follower model, when I think about it, but I'm not really sure what I'd like instead, if anything.</p>
<p>(Also, I was trying to work a crack in there about how, if you have a time machine, you can play Angry Birds on Google Plus.)</p>
<p>I never know how to end these.</p>
<p><strong>Everything after this is from the May 29 update or later:</strong></p>
<p><a class="reference external" href="https://niu.moe/@Wolf480pl">Wolf480pl</a> reacts shortly after I <em>finally</em> posted the link:</p>
<blockquote>
<p>Judging by my own experience with Masto, the most interesting interactions often look like that:
A posts an idea or opinion.
B boosts it, I follow B so I see it.
I reply, mentioning both A and B.
Discussion ensues.
I reply with a conclusion.
People fav/boost it because they agree with it.
I boost it, because it's a good thought on its own, and I want to spread it - the fruit of the discussion - to as many people as reasonable.</p>
<p>...</p>
<p>I think it's important to be able to collapse a part of the discussion, put the conclusion in front, and then endorse it.</p>
<p>...</p>
<p>maybe a self-boost should be treated differently.</p>
<p>...</p>
<p>Maybe only people approved (followed/friended?) by you should be able to boost your posts? Maybe every boost should be manually approved by it's author? Or maybe there boostability should be a per-post option?</p>
<p>...</p>
<p>Maybe posts should be un-boostable by default, but once I approve a single boost, everyone can boost them?</p>
<p class="attribution">—<a class="reference external" href="https://niu.moe/@Wolf480pl">https://niu.moe/@Wolf480pl</a></p>
</blockquote>
<p>My initial reactions are "this sounds promising" and "my proposal up there does not obviously support some of this".
Like, maybe if it's possible to call out posts as significant <em>within the context of a Conversation</em>?
I don't think that's quite right.
Like, within the framework of my proposal, a "Featured Comment" would have to be some form of start to a Conversation?
This would work out something like:</p>
<ul class="simple">
<li>A posts a Comment in Conversation C.</li>
<li>B Public Likes A's Comment.</li>
<li>This brings Conversation C to the attention of (some part of?) B's social graph, and highlights A's Comment within it.</li>
<li>W is in B's social graph, and responds to A's Comment.</li>
<li>W forms a conclusion in the form of a Comment.</li>
<li>W wishes to showcase the Comment on its own, and starts a new Conversation of the type "Featured Comment".</li>
</ul>
<p>This is just my very early thoughts on this, so I'm going to put this out there, then think about it more.</p>
Music Theory 2018-05-142018-05-14T04:00:00-04:002018-05-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-14:/music-theory-2018-05-14<p class="first last">I had trouble coming up with something to talk about, so here's a bunch of code.</p>
<p>In this post:</p>
<ul class="simple">
<li>I changed one field type.</li>
<li>I rewrote the rest of the dang code.</li>
</ul>
<hr class="docutils" />
<p>Okay, step one of this rewrite: change "tied_to_previous" into an enum-valued field.</p>
<p>I then... kind of just went through the whole rewrite.
Highlights include moving analysis logic down into lower-level classes, adding a higher-level validator, adding helper methods for the validators, and fully handling rests.</p>
<p>Here's where things stand:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""Data structures for representing note durations."""</span>
<span class="kn">import</span> <span class="nn">enum</span>
<span class="kn">import</span> <span class="nn">fractions</span>
<span class="kn">import</span> <span class="nn">typing</span>
<span class="k">class</span> <span class="nc">NoteType</span><span class="p">(</span><span class="n">enum</span><span class="o">.</span><span class="n">Enum</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Enum of simple note values."""</span>
<span class="n">START</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="n">TIED</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="n">REST</span> <span class="o">=</span> <span class="n">enum</span><span class="o">.</span><span class="n">auto</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">clap</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">beat_string</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the beat notation for this note type, given beat number."""</span>
<span class="k">if</span> <span class="bp">self</span> <span class="o">==</span> <span class="n">NoteType</span><span class="o">.</span><span class="n">START</span><span class="p">:</span>
<span class="k">return</span> <span class="s1">'CLAP'</span>
<span class="k">elif</span> <span class="bp">self</span> <span class="o">==</span> <span class="n">NoteType</span><span class="o">.</span><span class="n">TIED</span><span class="p">:</span>
<span class="k">return</span> <span class="n">beat_string</span>
<span class="k">assert</span> <span class="bp">self</span> <span class="o">==</span> <span class="n">NoteType</span><span class="o">.</span><span class="n">REST</span>
<span class="k">return</span> <span class="sa">f</span><span class="s1">'(</span><span class="si">{</span><span class="n">beat_string</span><span class="si">}</span><span class="s1">)'</span>
<span class="k">class</span> <span class="nc">NoteDuration</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Class representing a single note as written."""</span>
<span class="n">base_duration</span><span class="p">:</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span> <span class="o">=</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">augmentation_dots</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">note_type</span><span class="p">:</span> <span class="n">NoteType</span> <span class="o">=</span> <span class="n">NoteType</span><span class="o">.</span><span class="n">START</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">full_duration</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return the duration of the note, after augmentation."""</span>
<span class="n">fraction_of_whole</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">base_duration</span>
<span class="n">fraction_to_add</span> <span class="o">=</span> <span class="n">fraction_of_whole</span>
<span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">augmentation_dots</span><span class="p">):</span>
<span class="n">fraction_to_add</span> <span class="o">/=</span> <span class="mi">2</span>
<span class="n">fraction_of_whole</span> <span class="o">+=</span> <span class="n">fraction_to_add</span>
<span class="k">return</span> <span class="n">fraction_of_whole</span>
<span class="k">def</span> <span class="nf">beats_as_written</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">beats_per_whole</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">4</span><span class="p">)</span> <span class="o">-></span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the number of beats in the note, given number in whole."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">full_duration</span> <span class="o">*</span> <span class="n">beats_per_whole</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">per_whole</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">beats_per_whole</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return the note corresponding to given division of a whole note."""</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span><span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">beats_per_whole</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">subdivide</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">beats_per_whole</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
<span class="n">offset</span><span class="p">:</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="s1">'NoteDuration'</span><span class="p">],</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Convert this note into beat-aligned notes tied together."""</span>
<span class="n">notes</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">duration</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">beats_as_written</span><span class="p">(</span><span class="n">beats_per_whole</span><span class="p">)</span>
<span class="n">remaining</span> <span class="o">=</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">-</span> <span class="n">offset</span>
<span class="n">first_duration</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">remaining</span><span class="p">,</span> <span class="n">duration</span><span class="p">)</span>
<span class="n">notes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_replace</span><span class="p">(</span> <span class="c1"># pylint: disable=no-member</span>
<span class="n">base_duration</span><span class="o">=</span><span class="n">first_duration</span> <span class="o">/</span> <span class="n">beats_per_whole</span><span class="p">,</span>
<span class="n">augmentation_dots</span><span class="o">=</span><span class="mi">0</span><span class="p">))</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">note_type</span> <span class="o">==</span> <span class="n">NoteType</span><span class="o">.</span><span class="n">REST</span><span class="p">:</span>
<span class="n">note_type</span> <span class="o">=</span> <span class="n">NoteType</span><span class="o">.</span><span class="n">REST</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">note_type</span> <span class="o">=</span> <span class="n">NoteType</span><span class="o">.</span><span class="n">TIED</span>
<span class="n">offset</span> <span class="o">+=</span> <span class="n">first_duration</span>
<span class="n">duration</span> <span class="o">-=</span> <span class="n">first_duration</span>
<span class="k">while</span> <span class="n">duration</span><span class="p">:</span>
<span class="n">offset</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">offset</span><span class="p">,</span> <span class="n">duration</span><span class="p">)</span>
<span class="n">notes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">NoteDuration</span><span class="p">(</span>
<span class="n">base_duration</span><span class="o">=</span><span class="n">offset</span> <span class="o">/</span> <span class="n">beats_per_whole</span><span class="p">,</span>
<span class="n">note_type</span><span class="o">=</span><span class="n">note_type</span><span class="p">))</span>
<span class="n">duration</span> <span class="o">-=</span> <span class="n">offset</span>
<span class="k">if</span> <span class="n">offset</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">offset</span> <span class="o">=</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">()</span>
<span class="k">return</span> <span class="n">notes</span><span class="p">,</span> <span class="n">offset</span>
<span class="k">def</span> <span class="nf">as_tied</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return this note, but tied to the previous note."""</span>
<span class="c1"># pylint: disable=no-member</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_replace</span><span class="p">(</span><span class="n">note_type</span><span class="o">=</span><span class="n">NoteType</span><span class="o">.</span><span class="n">TIED</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">as_rest</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return this note, but as a rest."""</span>
<span class="c1"># pylint: disable=no-member</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_replace</span><span class="p">(</span><span class="n">note_type</span><span class="o">=</span><span class="n">NoteType</span><span class="o">.</span><span class="n">REST</span><span class="p">)</span>
<span class="n">BREVE</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="p">(</span><span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">(</span><span class="mi">2</span><span class="p">))</span>
<span class="n">WHOLE</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="p">()</span>
<span class="c1"># pylint doesn't know how classes work, sometimes.</span>
<span class="n">HALF</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="o">.</span><span class="n">per_whole</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># pylint: disable=no-member</span>
<span class="n">QUARTER</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="o">.</span><span class="n">per_whole</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span> <span class="c1"># pylint: disable=no-member</span>
<span class="n">EIGHTH</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="o">.</span><span class="n">per_whole</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span> <span class="c1"># pylint: disable=no-member</span>
<span class="n">SIXTEENTH</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="o">.</span><span class="n">per_whole</span><span class="p">(</span><span class="mi">16</span><span class="p">)</span> <span class="c1"># pylint: disable=no-member</span>
<span class="n">THIRTY_SECOND</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="o">.</span><span class="n">per_whole</span><span class="p">(</span><span class="mi">32</span><span class="p">)</span> <span class="c1"># pylint: disable=no-member</span>
<span class="n">DOTTED_HALF</span> <span class="o">=</span> <span class="n">HALF</span><span class="o">.</span><span class="n">_replace</span><span class="p">(</span><span class="n">augmentation_dots</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">DOTTED_QUARTER</span> <span class="o">=</span> <span class="n">QUARTER</span><span class="o">.</span><span class="n">_replace</span><span class="p">(</span><span class="n">augmentation_dots</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</pre></div></td></tr></table></div>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span>
<span class="normal">102</span>
<span class="normal">103</span>
<span class="normal">104</span>
<span class="normal">105</span>
<span class="normal">106</span>
<span class="normal">107</span>
<span class="normal">108</span>
<span class="normal">109</span>
<span class="normal">110</span>
<span class="normal">111</span>
<span class="normal">112</span>
<span class="normal">113</span>
<span class="normal">114</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""Data structures for representing measures."""</span>
<span class="kn">import</span> <span class="nn">fractions</span>
<span class="kn">import</span> <span class="nn">typing</span>
<span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">note</span>
<span class="k">class</span> <span class="nc">Measure</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Class representing a measure as a collection of notes."""</span>
<span class="n">notes</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">note</span><span class="o">.</span><span class="n">NoteDuration</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span>
<span class="n">time_signature</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">is_valid</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return whether the notes given fit exactly into the measure."""</span>
<span class="n">beats_total</span><span class="p">,</span> <span class="n">beats_per_whole</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">time_signature</span>
<span class="k">if</span> <span class="nb">sum</span><span class="p">(</span>
<span class="n">note</span><span class="o">.</span><span class="n">beats_as_written</span><span class="p">(</span><span class="n">beats_per_whole</span><span class="p">)</span>
<span class="k">for</span> <span class="n">note</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">notes</span><span class="p">)</span> <span class="o">!=</span> <span class="n">beats_total</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">for</span> <span class="n">fst</span><span class="p">,</span> <span class="n">snd</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">notes</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">notes</span><span class="p">[</span><span class="mi">1</span><span class="p">:]):</span>
<span class="k">if</span> <span class="p">(</span><span class="n">fst</span><span class="o">.</span><span class="n">note_type</span> <span class="o">==</span> <span class="n">note</span><span class="o">.</span><span class="n">NoteType</span><span class="o">.</span><span class="n">REST</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span>
<span class="n">snd</span><span class="o">.</span><span class="n">note_type</span> <span class="o">==</span> <span class="n">note</span><span class="o">.</span><span class="n">NoteType</span><span class="o">.</span><span class="n">TIED</span><span class="p">):</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">final_rest</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return whether the final note in the measure is a rest."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">notes</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">note_type</span> <span class="o">==</span> <span class="n">note</span><span class="o">.</span><span class="n">NoteType</span><span class="o">.</span><span class="n">REST</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">initial_tie</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return whether the initial note in the measure is tied."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">notes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">note_type</span> <span class="o">==</span> <span class="n">note</span><span class="o">.</span><span class="n">NoteType</span><span class="o">.</span><span class="n">TIED</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">notes_merged</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="s2">"Measure"</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return a measure that sounds the same, but with the least notes."""</span>
<span class="n">notes</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">notes</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span>
<span class="k">for</span> <span class="n">note_</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">notes</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
<span class="n">last_note</span> <span class="o">=</span> <span class="n">notes</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="k">if</span> <span class="p">(</span><span class="n">note_</span><span class="o">.</span><span class="n">note_type</span> <span class="o">==</span> <span class="n">note</span><span class="o">.</span><span class="n">NoteType</span><span class="o">.</span><span class="n">TIED</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span>
<span class="n">last_note</span><span class="o">.</span><span class="n">note_type</span> <span class="o">==</span> <span class="n">note</span><span class="o">.</span><span class="n">NoteType</span><span class="o">.</span><span class="n">REST</span>
<span class="ow">and</span> <span class="n">note_</span><span class="o">.</span><span class="n">note_type</span> <span class="o">==</span> <span class="n">note</span><span class="o">.</span><span class="n">NoteType</span><span class="o">.</span><span class="n">REST</span><span class="p">):</span>
<span class="n">notes</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">note</span><span class="o">.</span><span class="n">NoteDuration</span><span class="p">(</span>
<span class="n">last_note</span><span class="o">.</span><span class="n">full_duration</span> <span class="o">+</span> <span class="n">note_</span><span class="o">.</span><span class="n">full_duration</span><span class="p">,</span>
<span class="n">note_type</span><span class="o">=</span><span class="n">last_note</span><span class="o">.</span><span class="n">note_type</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">notes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">note_</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_replace</span><span class="p">(</span><span class="n">notes</span><span class="o">=</span><span class="nb">tuple</span><span class="p">(</span><span class="n">notes</span><span class="p">))</span> <span class="c1"># pylint: disable=no-member</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">beat_separated</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="s2">"Measure"</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return a measure that sounds the same, but with defined beats."""</span>
<span class="n">notes</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">offset</span> <span class="o">=</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">()</span>
<span class="n">beats_per_whole</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">time_signature</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">for</span> <span class="n">note_</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">notes_merged</span><span class="o">.</span><span class="n">notes</span><span class="p">:</span>
<span class="n">new_notes</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="n">note_</span><span class="o">.</span><span class="n">subdivide</span><span class="p">(</span><span class="n">beats_per_whole</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
<span class="n">notes</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">new_notes</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_replace</span><span class="p">(</span><span class="n">notes</span><span class="o">=</span><span class="nb">tuple</span><span class="p">(</span><span class="n">notes</span><span class="p">))</span> <span class="c1"># pylint: disable=no-member</span>
<span class="k">def</span> <span class="nf">beats</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterator</span><span class="p">[</span><span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">note</span><span class="o">.</span><span class="n">NoteDuration</span><span class="p">,</span> <span class="o">...</span><span class="p">]]:</span>
<span class="w"> </span><span class="sd">"""Yield each individual beat as a tuple of notes."""</span>
<span class="n">beat_target</span> <span class="o">=</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">time_signature</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="n">beats</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">note_</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">beat_separated</span><span class="o">.</span><span class="n">notes</span><span class="p">:</span>
<span class="n">beats</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">note_</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">sum</span><span class="p">(</span><span class="n">note__</span><span class="o">.</span><span class="n">base_duration</span> <span class="k">for</span> <span class="n">note__</span> <span class="ow">in</span> <span class="n">beats</span><span class="p">)</span> <span class="o">==</span> <span class="n">beat_target</span><span class="p">:</span>
<span class="k">yield</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">beats</span><span class="p">)</span>
<span class="n">beats</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">def</span> <span class="nf">clap_strs</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Iterator</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Yield the clap strings associated with the measure."""</span>
<span class="n">beats</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">beats</span><span class="p">())</span>
<span class="k">for</span> <span class="n">beat</span><span class="p">,</span> <span class="n">notes</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">beats</span><span class="p">):</span>
<span class="n">beat</span> <span class="o">+=</span> <span class="mi">1</span> <span class="c1"># Account for indexing conventions</span>
<span class="n">realizations</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">realizations</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">notes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">note_type</span><span class="o">.</span><span class="n">clap</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">beat</span><span class="p">)))</span>
<span class="k">for</span> <span class="n">note_</span> <span class="ow">in</span> <span class="n">notes</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
<span class="c1"># Assume we only do half-divisions</span>
<span class="k">assert</span> <span class="n">note_</span><span class="o">.</span><span class="n">beats_as_written</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">time_signature</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">==</span> <span class="mf">0.5</span><span class="p">,</span> <span class="n">notes</span>
<span class="n">realizations</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">note_</span><span class="o">.</span><span class="n">note_type</span><span class="o">.</span><span class="n">clap</span><span class="p">(</span><span class="s1">'and'</span><span class="p">))</span>
<span class="k">yield</span> <span class="s1">'-'</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">realizations</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">MultiMeasure</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Class representing several measures in sequence."""</span>
<span class="n">measures</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">Measure</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">is_valid</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return whether the overall collection of measures is valid."""</span>
<span class="k">for</span> <span class="n">measure</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">measures</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">measure</span><span class="o">.</span><span class="n">is_valid</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">for</span> <span class="n">fst</span><span class="p">,</span> <span class="n">snd</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">measures</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">measures</span><span class="p">[</span><span class="mi">1</span><span class="p">:]):</span>
<span class="k">if</span> <span class="n">fst</span><span class="o">.</span><span class="n">final_rest</span> <span class="ow">and</span> <span class="n">snd</span><span class="o">.</span><span class="n">initial_tie</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">clap_str</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the clap pattern for the measures."""</span>
<span class="n">accumulator</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">measure</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">measures</span><span class="p">:</span>
<span class="n">accumulator</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">measure</span><span class="o">.</span><span class="n">clap_strs</span><span class="p">())</span>
<span class="k">return</span> <span class="s1">' '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">accumulator</span><span class="p">)</span>
</pre></div></td></tr></table></div>
<p>Getting pylint happy with the NoteType.clap function was bad enough that I'm considering turning my visitor thing from Homunculus into some kind of library.</p>
<p>I'm not totally happy with some of the interfaces here, but I'm not sure what to do to improve it.
I might need to get further into the details of notes to find something good.</p>
<hr class="docutils" />
<p>Next week, I'll get more into time signatures, probably turn that 2-tuple up there into its own type.</p>
Weekly Roundup 2018-05-132018-05-13T04:00:00-04:002018-05-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-13:/weekly-roundup-2018-05-13<p class="first last">To be honest, I might need to set limits on how big an individual post can be.</p>
<ul class="simple">
<li>Music Theory Monday: I implemented ties and cleaned up the analysis code, then prepared to implement rests.</li>
<li>Free-Topic Tuesday: I tossed out a bunch of concepts for a mockumentary book about the MIB.</li>
<li>Demiurgent Business Wednesday: I read over Kagegami High, and decided on the next thing to read: Polaris.</li>
<li>Conworld Codex Thursday: I impulsively wrote a database schema, immediately regretted doing so, and resolved to push on regardless.</li>
<li>Draw a Box Friday: I did not miss a day. That's a lot of lines.</li>
<li>Homunculus Saturday: I got rid of some if-blocks, and came up with some more ambitious ideas.</li>
</ul>
Homunculus Devlog 2018-05-122018-05-12T04:00:00-04:002018-05-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-12:/homunculus-devlog-2018-05-12<p class="first last">I'm not a fan of long if-elif-else chains.</p>
<p>In this post:</p>
<ul class="simple">
<li>I rewrite some if-blocks into a more scoped form.</li>
<li>I figure out more stuff to do, next week.</li>
</ul>
<hr class="docutils" />
<p>Looking over the code that I've yet to collapse down with abstractions, I realized that I didn't like the basic state machine setup.
My current plan is to try replacing the if statements with functions and lookup tables.</p>
<p>Although, the way this is done now, the state machine is the overall run method, since the transition logic is just all over the place.</p>
<p>I'll try implementing this stuff as a visitor.</p>
<p>Here's how game_states.py looks after putting in a visitor:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span></pre></div></td><td class="code"><div><pre><span></span><span class="c1"># To test: just import.</span>
<span class="kn">from</span> <span class="nn">enum</span> <span class="kn">import</span> <span class="n">Enum</span><span class="p">,</span> <span class="n">auto</span>
<span class="k">class</span> <span class="nc">Visitor</span><span class="p">:</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">state_methods</span> <span class="o">=</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">default</span> <span class="o">=</span> <span class="n">default</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_default</span>
<span class="k">def</span> <span class="nf">_default</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span><span class="sa">f</span><span class="s1">'Not implemented for </span><span class="si">{</span><span class="n">state</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">bind</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">inner_bind</span><span class="p">(</span><span class="n">function</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">state_methods</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="n">function</span>
<span class="k">return</span> <span class="n">function</span>
<span class="k">return</span> <span class="n">inner_bind</span>
<span class="k">def</span> <span class="nf">visit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">state_methods</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">default</span><span class="p">)(</span>
<span class="n">state</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">GameStates</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
<span class="n">PLAYERS_TURN</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span>
<span class="n">ENEMY_TURN</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span>
<span class="n">PLAYER_DEAD</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span>
<span class="n">SHOW_INVENTORY</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span>
<span class="n">DROP_INVENTORY</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span>
<span class="n">TARGETING</span> <span class="o">=</span> <span class="n">auto</span><span class="p">()</span>
</pre></div></td></tr></table></div>
<p>The Visitor class is the new thing.
Because I'm not writing Java, it's a single class that gets instantiated with different behaviors, and handles the behaviors in a mapping on the instance.
It should probably get moved to its own module, because it's not really coupled to the idea of using states specifically.
In fact, one module that got rewritten uses it in several contexts:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span>
<span class="normal">74</span>
<span class="normal">75</span>
<span class="normal">76</span>
<span class="normal">77</span>
<span class="normal">78</span>
<span class="normal">79</span>
<span class="normal">80</span>
<span class="normal">81</span>
<span class="normal">82</span>
<span class="normal">83</span>
<span class="normal">84</span>
<span class="normal">85</span>
<span class="normal">86</span>
<span class="normal">87</span>
<span class="normal">88</span>
<span class="normal">89</span>
<span class="normal">90</span>
<span class="normal">91</span>
<span class="normal">92</span>
<span class="normal">93</span>
<span class="normal">94</span>
<span class="normal">95</span>
<span class="normal">96</span></pre></div></td><td class="code"><div><pre><span></span><span class="c1"># To test: is thankfully self-contained.</span>
<span class="kn">from</span> <span class="nn">.game_states</span> <span class="kn">import</span> <span class="n">GameStates</span><span class="p">,</span> <span class="n">Visitor</span>
<span class="nd">@Visitor</span>
<span class="k">def</span> <span class="nf">state_visitor</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">user_input</span><span class="p">):</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="nd">@Visitor</span>
<span class="k">def</span> <span class="nf">input_visitor</span><span class="p">(</span><span class="n">user_input</span><span class="p">,</span> <span class="n">state</span><span class="p">):</span>
<span class="k">return</span> <span class="n">state_visitor</span><span class="o">.</span><span class="n">visit</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">user_input</span><span class="p">)</span>
<span class="nd">@input_visitor</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">no_input</span><span class="p">(</span><span class="n">user_input</span><span class="p">,</span> <span class="n">state</span><span class="p">):</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="nd">@state_visitor</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">GameStates</span><span class="o">.</span><span class="n">PLAYERS_TURN</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">handle_player_turn_keys</span><span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="n">user_input</span><span class="p">):</span>
<span class="n">key_char</span> <span class="o">=</span> <span class="n">user_input</span><span class="o">.</span><span class="n">char</span>
<span class="k">if</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'UP'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'move'</span><span class="p">:</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">)}</span>
<span class="k">elif</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'DOWN'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'move'</span><span class="p">:</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)}</span>
<span class="k">elif</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'LEFT'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'move'</span><span class="p">:</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)}</span>
<span class="k">elif</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'RIGHT'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'move'</span><span class="p">:</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)}</span>
<span class="k">elif</span> <span class="n">key_char</span> <span class="o">==</span> <span class="s1">'g'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'pickup'</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
<span class="k">elif</span> <span class="n">key_char</span> <span class="o">==</span> <span class="s1">'i'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'show_inventory'</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
<span class="k">elif</span> <span class="n">key_char</span> <span class="o">==</span> <span class="s1">'d'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'drop_inventory'</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
<span class="k">if</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'ENTER'</span> <span class="ow">and</span> <span class="n">user_input</span><span class="o">.</span><span class="n">alt</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'fullscreen'</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
<span class="k">elif</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'ESCAPE'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'exit'</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="nd">@state_visitor</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">GameStates</span><span class="o">.</span><span class="n">TARGETING</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">handle_targeting_keys</span><span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="n">user_input</span><span class="p">):</span>
<span class="k">if</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'ESCAPE'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'exit'</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="nd">@state_visitor</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">GameStates</span><span class="o">.</span><span class="n">PLAYER_DEAD</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">handle_player_dead_keys</span><span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="n">user_input</span><span class="p">):</span>
<span class="n">key_char</span> <span class="o">=</span> <span class="n">user_input</span><span class="o">.</span><span class="n">char</span>
<span class="k">if</span> <span class="n">key_char</span> <span class="o">==</span> <span class="s1">'i'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'show_inventory'</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
<span class="k">if</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'ENTER'</span> <span class="ow">and</span> <span class="n">user_input</span><span class="o">.</span><span class="n">alt</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'fullscreen'</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
<span class="k">elif</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'ESCAPE'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'exit'</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="nd">@state_visitor</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">GameStates</span><span class="o">.</span><span class="n">DROP_INVENTORY</span><span class="p">)</span>
<span class="nd">@state_visitor</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">GameStates</span><span class="o">.</span><span class="n">SHOW_INVENTORY</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">handle_inventory_keys</span><span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="n">user_input</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">user_input</span><span class="o">.</span><span class="n">char</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="n">index</span> <span class="o">=</span> <span class="nb">ord</span><span class="p">(</span><span class="n">user_input</span><span class="o">.</span><span class="n">char</span><span class="p">)</span> <span class="o">-</span> <span class="nb">ord</span><span class="p">(</span><span class="s1">'a'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">index</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'inventory_index'</span><span class="p">:</span> <span class="n">index</span><span class="p">}</span>
<span class="k">if</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'ENTER'</span> <span class="ow">and</span> <span class="n">user_input</span><span class="o">.</span><span class="n">alt</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'fullscreen'</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
<span class="k">elif</span> <span class="n">user_input</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="s1">'ESCAPE'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'exit'</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
<span class="k">return</span> <span class="p">{}</span>
<span class="k">def</span> <span class="nf">handle_mouse</span><span class="p">(</span><span class="n">mouse_event</span><span class="p">):</span>
<span class="k">if</span> <span class="n">mouse_event</span><span class="p">:</span>
<span class="k">if</span> <span class="n">mouse_event</span><span class="o">.</span><span class="n">button</span> <span class="o">==</span> <span class="s1">'LEFT'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'left_click'</span><span class="p">:</span> <span class="n">mouse_event</span><span class="o">.</span><span class="n">cell</span><span class="p">}</span>
<span class="k">elif</span> <span class="n">mouse_event</span><span class="o">.</span><span class="n">button</span> <span class="o">==</span> <span class="s1">'RIGHT'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'right_click'</span><span class="p">:</span> <span class="n">mouse_event</span><span class="o">.</span><span class="n">cell</span><span class="p">}</span>
<span class="k">return</span> <span class="p">{}</span>
</pre></div></td></tr></table></div>
<p>I'm not done rewriting this.
My goal with this module is to turn the whole thing into, like, a static data-structure that just gets consumed by a simple function.
Just get rid of as many if blocks as possible.
I don't like changing code after I've copied it into a post, so I'll probably do this after I publish, but I ought to factor out all that dict stuff into a common function, so I can find some other way to represent things later, without needing a painful search-and-replace, and also start looking around for magic string stuff to turn into constants.</p>
<p>I just realized something interesting: the different parts of the "result" dictionaries don't actually need to be bundled together, if they're being yielded, so they can be converted into multiple statements.
And that frees me up to convert them into some other data type.</p>
<p>I don't know when I'm going to be fully satisfied with this, but I'm starting to think that when I am, I should try to put together my own tutorial, since the code is going to look so different when all is said and done.</p>
<hr class="docutils" />
<p>Next week, I demux the engine events, and convert them to custom classes.</p>
Draw a Box 2018-05-112018-05-11T04:00:00-04:002018-05-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-11:/draw-a-box-2018-05-11<p class="first last">More Lines</p>
<p>In this post:</p>
<ul class="simple">
<li>LINES</li>
</ul>
<hr class="docutils" />
<p>Since I came up with the plan, I have drawn:</p>
<ul class="simple">
<li>15 lines on May 4</li>
<li>15 lines on May 5</li>
<li>15 lines on May 6</li>
<li>15 lines on May 7</li>
<li>15 lines on May 8</li>
<li>15 lines on May 9</li>
<li>15 lines on May 10</li>
</ul>
<p>For a total of 105 lines this week,
and 120 lines since I started counting.</p>
<hr class="docutils" />
<p>Next week, the entry will be about the same.</p>
Conworld Codex 2018-05-102018-05-10T04:00:00-04:002018-05-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-10:/conworld-codex-2018-05-10<p class="first last">I probably shouldn't have done it this way, but I did. Might need to throw stuff out later.</p>
<p>In this post:</p>
<ul class="simple">
<li>A change in plans, and some questionable ORM code.</li>
</ul>
<hr class="docutils" />
<p>One thing I realized recently was that I'd rather focus on in-world stories than presenting "actual events".
Something, then, that would help the structure of things would be to associate commentary with different historians etc.
So, instead of annotations directly on a link, each link would be eligible for commentary by each possible commentator.</p>
<p>I thought I was going to plan things, but then I went and cobbled together a database schema, which was maybe not the best idea.</p>
<div class="highlight"><pre><span></span><span class="sd">"""SQLAlchemy ORM classes for modeling codex data."""</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">Column</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">String</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">,</span> <span class="n">UniqueConstraint</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="n">relationship</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.ext.declarative</span> <span class="kn">import</span> <span class="n">declarative_base</span>
<span class="n">Base</span> <span class="o">=</span> <span class="n">declarative_base</span><span class="p">()</span> <span class="c1"># pylint: disable=invalid-name</span>
<span class="k">class</span> <span class="nc">Event</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""The events within the history of the codex."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'events'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Teller</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""The people talking about the events."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'tellers'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">topic_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'topics.id'</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">topic</span> <span class="o">=</span> <span class="n">relationship</span><span class="p">(</span><span class="s1">'Topic'</span><span class="p">,</span> <span class="n">back_populates</span><span class="o">=</span><span class="s1">'teller'</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Topic</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""A person, place, or thing."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'topics'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">teller</span> <span class="o">=</span> <span class="n">relationship</span><span class="p">(</span><span class="s1">'Teller'</span><span class="p">,</span> <span class="n">back_populates</span><span class="o">=</span><span class="s1">'topic'</span><span class="p">,</span> <span class="n">uselist</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">TopicRelation</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""How a topic relates to an event, according to a teller."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'topic_relations'</span>
<span class="n">__table_args__</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">UniqueConstraint</span><span class="p">(</span><span class="s1">'topic_id'</span><span class="p">,</span> <span class="s1">'event_id'</span><span class="p">,</span> <span class="s1">'teller_id'</span><span class="p">),</span>
<span class="p">)</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">topic_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'topics.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">event_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'events.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">teller_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'tellers.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Contribution</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""How one event contributed to another, according to a teller."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'contributions'</span>
<span class="n">__table_args__</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">UniqueConstraint</span><span class="p">(</span><span class="s1">'cause'</span><span class="p">,</span> <span class="s1">'effect'</span><span class="p">,</span> <span class="s1">'teller_id'</span><span class="p">),</span>
<span class="p">)</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">cause</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'events.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">effect</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'events.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">teller_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'tellers.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">PartOf</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># type: ignore</span>
<span class="w"> </span><span class="sd">"""How one event was part of another, according to a teller."""</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'parts_of'</span>
<span class="n">__table_args__</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">UniqueConstraint</span><span class="p">(</span><span class="s1">'part'</span><span class="p">,</span> <span class="s1">'whole'</span><span class="p">,</span> <span class="s1">'teller_id'</span><span class="p">),</span>
<span class="p">)</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">part</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'events.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">whole</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'events.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">teller_id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'tellers.id'</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">)</span>
</pre></div>
<p>Taken as a whole, this passes tests with full coverage, but I'm not trying to <em>do</em> anything yet.
I'm reasonably sure this is going to go through some serious changes, and to find out what they are, I'm going to need to put together an interface for all this stuff.</p>
<p>First, though, a quick note: this code is using surrogate keys everywhere it can, which is a decision mainly influenced by a completely different, and somewhat outdated, technology stack.
I tried to outsource the question of surrogate vs natural keys to the internet, and the main thing I learned is that you can find an article advocating for any position on that whatsoever.</p>
<hr class="docutils" />
<p>Next week, I figure out what I did wrong here.</p>
Demiurgent Business 2018-05-092018-05-09T04:00:00-04:002018-05-09T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-09:/demiurgent-business-2018-05-09<p class="first last">A Very Very Rough Idea</p>
<p>In this post:</p>
<ul class="simple">
<li>I figure out some elements of my current influences that I do <em>not</em> want to use.</li>
<li>I try to nail down the structure of play a little more.</li>
</ul>
<hr class="docutils" />
<p>I decided to start studying potential influences by looking at Kagegami High.
I've got way more to look into, but I did realize a few things that I want out of Demiurgent Business:</p>
<ul class="simple">
<li>The race/class stuff shouldn't encode ideas of "progression", and instead just all be accessible to the player to start with. At the same time, it should be less impressive than in Legend, D&D, etc.</li>
<li>The focus of "advancement" should be on the characters' interpersonal relationships. I don't have a good picture of what that looks like, but the idea is that when characters are good friends, that translates into broadly applicable abilities to get things done. (Said abilities do not manifest as 'friendship lasers' or something.)</li>
<li>I could use tables like Kagegami High does, but in a more restricted fashion, centering around the Demiurge's plans and outside complications, rather than overall setting details.</li>
</ul>
<p>One thing that I've been kind of considering is how the situation reaches its "steady state".
I wonder if it'd be feasible to intermingle character creation with "founding the club".
Like "Okay, you've just been recruited. Quick, what's your deal?"
(Ideally with better questions than "what's your deal", like "what club activities are you leaving undone as a result of this" or something.)</p>
<p>Further general refinements:</p>
<ul class="simple">
<li>Assume that all player characters are in the Demiurge's club now, and that significant events rarely happen in class. The game is probably a mix of "club activities" and "downtime".</li>
<li>The advancement system should be based on "bonds", which need brief sentences added to qualify for advancement.</li>
<li>The player characters should never have quite enough in the way of resources to pull everything off flawlessly. Someone is inevitably going to have to sacrifice some dignity.</li>
</ul>
<p>... Inevitable outcomes.
I think I know <a class="reference external" href="http://www.tao-games.com/polaris/">which game to check out next</a>.</p>
<hr class="docutils" />
<p>Next week, Chivalric Tragedy at the Utmost North, probably.</p>
Story Concept: Behind The Masquerade2018-05-08T04:00:00-04:002018-05-08T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-08:/story-concept-behind-the-masquerade<p class="first last">Wait, Why Is This Secret, Again?</p>
<p>In this post:</p>
<ul class="simple">
<li>I can't write something <em>good</em> in a day, so it's brainstorming and outlining.</li>
</ul>
<hr class="docutils" />
<p>My wife and I recently watched <em>Plan 9 from Outer Space</em>, as part of a broader plan to watch as much schlock and horror from the 20th century as we can think of.
One of the many things that the movie didn't really explain in a satisfying fashion was, what was with the secrecy?
And this is an issue that I think a lot of UFO narratives have, that the people who make the initial discovery must have reflexively acted to allow for maximum secrecy down the road.</p>
<p>So, the idea I want to hash out here is, what's the psychology that would have to go into a UFO coverup, to allow it to get off the ground, as it were, in the first place?
Sort of a mockumentary about UFO coverups.</p>
<p>Since this is all kind of a silly pisstake anyway, let's posit that the original discovery was by a fictional agency.
Maybe some kind of black-ops outfit that managed to secure adequate funding through low-profile criminal activity?
Call it the IAS, say, for the Institute for Aerial Superiority.
At a base somewhere in Arizona, they were pushing the limits of their detection apparatus.
When they discover a faint blip, nothing like what they expect, going from Colorado to nowhere in particular.</p>
<p>When they keep seeing more blips, they conscript a local airplane pilot to try to get a closer look.
When they see the pilot's photographs, they conclude that they're dealing with some form of alien intelligence.
One member of the operation, an allegedly reformed grifter who keeps on disappearing over the border on weekends, pitches them the idea of creating a fake world government headquarters, to get exclusive access to the alien technology.
They convince the pilot to be the "supreme ruler".</p>
<p>I have a bunch of ideas that need to be untangled to make this work:</p>
<ul class="simple">
<li>That the aliens find out, and leave in disgust, leading to a temporary drop in UFO sightings. The operation finds out, and starts faking sightings to make it look like nothing has changed.</li>
<li>That the pilot ends up actually in charge of things, even if it's not like that on paper.</li>
<li>That before the aliens leave, the IAS does, in fact, have to coordinate a massive coverup operation, to hide their deceptive and illegal activities.</li>
<li>These coverups gradually drew more attention to the IAS, and this increased scrutiny may in fact have tipped off the aliens.</li>
<li>After the aliens left, most of the IAS relocated to an island somewhere in the tropics.</li>
<li>But maybe the grifter got left behind, and is the investigator's main source. "Now, before I tell you anything about this, you need to remember that I am, by inclination, habit, and trade, an untrustworthy man. You'd be a fool to take my word alone for any of this."</li>
</ul>
<p>That stuff can be the first part.
In the second part, the investigator goes south to try to track down the rest of the IAS.
Finds them holed up in a compound, engaged in some kind of PR battle with the local authorities, who claim the IAS has committed all sorts of crimes.
The investigator makes it into the compound, and interviews the IAS members.
Most are reluctant to talk directly about the UFO stuff, and focus on their current situation, with asides occasionally calling back to back then.</p>
<p>One of them mainly discusses "genome-tailored smart drugs" he's been developing, which allegedly allow him to perform feats of extreme mental computation, and elborate physicality.</p>
<p>Maybe it could also be revealed that the grifter had a whole team that he didn't mention, and nobody directly knew about.</p>
<p>I'm sure I've seen somewhere else, the angle of "the MIB are a bunch of con artists in over their heads", but it seems like a fun thing to explore regardless.</p>
Music Theory 2018-05-072018-05-07T04:00:00-04:002018-05-07T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-07:/music-theory-2018-05-07<p class="first last">Not Restful At All</p>
<p>In this post:</p>
<ul class="simple">
<li>I use tied notes and a simpler specification of note lengths to simplify the clapping code.</li>
<li>I think about implementing rests, but decide not to just yet.</li>
</ul>
<hr class="docutils" />
<p>When last we saw our heroic music theory code, the measure analysis functionality looked like <strong>this</strong>:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MultiMeasure</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Class representing several measures in sequence."""</span>
<span class="n">measures</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">Measure</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">clap_str</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return the clap pattern for the measures."""</span>
<span class="n">accumulator</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">measure</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">measures</span><span class="p">:</span>
<span class="n">beats_per_whole</span> <span class="o">=</span> <span class="n">measure</span><span class="o">.</span><span class="n">time_signature</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">beat_count</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">offbeat</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">prefix</span> <span class="o">=</span> <span class="s1">''</span>
<span class="k">for</span> <span class="n">note_</span> <span class="ow">in</span> <span class="n">measure</span><span class="o">.</span><span class="n">notes</span><span class="p">:</span>
<span class="n">beats_per_note</span> <span class="o">=</span> <span class="n">note_</span><span class="o">.</span><span class="n">beats_as_written</span><span class="p">(</span><span class="n">beats_per_whole</span><span class="p">)</span>
<span class="k">if</span> <span class="n">offbeat</span><span class="p">:</span>
<span class="n">beats_per_note</span> <span class="o">+=</span> <span class="mf">0.5</span>
<span class="n">entire_beats</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">beats_per_note</span><span class="p">)</span>
<span class="n">excess</span> <span class="o">=</span> <span class="n">beats_per_note</span> <span class="o">-</span> <span class="n">entire_beats</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">entire_beats</span><span class="p">):</span>
<span class="k">if</span> <span class="n">i</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">accumulator</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">prefix</span> <span class="o">+</span> <span class="s1">'CLAP'</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">accumulator</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">beat_count</span><span class="p">))</span>
<span class="n">beat_count</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="n">excess</span><span class="p">:</span>
<span class="k">assert</span> <span class="n">excess</span> <span class="o">==</span> <span class="mf">0.5</span>
<span class="n">offbeat</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">if</span> <span class="n">entire_beats</span><span class="p">:</span>
<span class="n">prefix</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">beat_count</span><span class="p">)</span> <span class="o">+</span> <span class="s1">'-'</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">prefix</span> <span class="o">=</span> <span class="s1">'CLAP-'</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">offbeat</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">prefix</span> <span class="o">=</span> <span class="s1">''</span>
<span class="k">return</span> <span class="s1">' '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">accumulator</span><span class="p">)</span>
</pre></div>
<p>... Ew.
There's something wrong with the way I'm doing that, quite aside from the fact that there's missing functionality.
(This is exactly as it was last week, so it doesn't handle ties at all.)
Let's try to break this down differently.</p>
<ul class="simple">
<li>A measure is made up of beats.</li>
<li>Beats are space-separated in the output.</li>
<li>A beat (currently) either starts a note (in which case it gets annotated "CLAP") or continues one (in which case it gets annotated with the beat number (counting from 1))</li>
<li>If the note ends before the beat does, then the beat contains more notes (annotated "CLAP"), and joined with dashes/hyphens/whatever.</li>
<li>If the note extends beyond the beat... we don't want that, not really.</li>
</ul>
<p>Before considering ties, we have to deal with the last bullet.
But, with access to ties, we can "re-spell" an arbitrary pattern of notes into notes entirely within a beat, but tied between them.</p>
<p>To accomplish this, we need to add a property to the measure class, to reinterpret it in light of its time signature.</p>
<p>I went and confused myself implementing it, so I need to take another look.
My current plan is to accumulate newly created notes into a list, and construct the new measure from that.
But there's something I missed: I'm doing all the logic at the measure level currently, when I could be putting some of it on the note.
The note class needs a method to say "given a beats per whole and an initial offset into the beat, return a sequence of notes that don't straddle beats, and a new offset"</p>
<p>I then realized that I should be MERGING notes within the measure, and point is, it all works now.
It's basically fine.
The code now looks like this:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">NoteDuration</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Class representing a single note as written."""</span>
<span class="n">base_duration</span><span class="p">:</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span> <span class="o">=</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">augmentation_dots</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">tied_to_previous</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">full_duration</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return the duration of the note, after augmentation."""</span>
<span class="n">fraction_of_whole</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">base_duration</span>
<span class="n">fraction_to_add</span> <span class="o">=</span> <span class="n">fraction_of_whole</span>
<span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">augmentation_dots</span><span class="p">):</span>
<span class="n">fraction_to_add</span> <span class="o">/=</span> <span class="mi">2</span>
<span class="n">fraction_of_whole</span> <span class="o">+=</span> <span class="n">fraction_to_add</span>
<span class="k">return</span> <span class="n">fraction_of_whole</span>
<span class="k">def</span> <span class="nf">beats_as_written</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">beats_per_whole</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">4</span><span class="p">)</span> <span class="o">-></span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return the number of beats in the note, given number in whole."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">full_duration</span> <span class="o">*</span> <span class="n">beats_per_whole</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">per_whole</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">beats_per_whole</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return the note corresponding to given division of a whole note."""</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span><span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">beats_per_whole</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">subdivide</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">beats_per_whole</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
<span class="n">offset</span><span class="p">:</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span>
<span class="p">)</span> <span class="o">-></span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">typing</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="s1">'NoteDuration'</span><span class="p">],</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">"""Convert this note into beat-aligned notes tied together."""</span>
<span class="n">notes</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">duration</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">beats_as_written</span><span class="p">(</span><span class="n">beats_per_whole</span><span class="p">)</span>
<span class="n">remaining</span> <span class="o">=</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">-</span> <span class="n">offset</span>
<span class="n">first_duration</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">remaining</span><span class="p">,</span> <span class="n">duration</span><span class="p">)</span>
<span class="n">notes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_replace</span><span class="p">(</span> <span class="c1"># pylint: disable=no-member</span>
<span class="n">base_duration</span><span class="o">=</span><span class="n">first_duration</span> <span class="o">/</span> <span class="n">beats_per_whole</span><span class="p">,</span>
<span class="n">augmentation_dots</span><span class="o">=</span><span class="mi">0</span><span class="p">))</span>
<span class="n">offset</span> <span class="o">+=</span> <span class="n">first_duration</span>
<span class="n">duration</span> <span class="o">-=</span> <span class="n">first_duration</span>
<span class="k">while</span> <span class="n">duration</span><span class="p">:</span>
<span class="n">offset</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">offset</span><span class="p">,</span> <span class="n">duration</span><span class="p">)</span>
<span class="n">notes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">NoteDuration</span><span class="p">(</span>
<span class="n">base_duration</span><span class="o">=</span><span class="n">offset</span> <span class="o">/</span> <span class="n">beats_per_whole</span><span class="p">,</span>
<span class="n">tied_to_previous</span><span class="o">=</span><span class="kc">True</span><span class="p">))</span>
<span class="n">duration</span> <span class="o">-=</span> <span class="n">offset</span>
<span class="k">if</span> <span class="n">offset</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">offset</span> <span class="o">=</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">()</span>
<span class="k">return</span> <span class="n">notes</span><span class="p">,</span> <span class="n">offset</span>
<span class="p">[</span><span class="o">...</span><span class="p">]</span>
<span class="k">class</span> <span class="nc">Measure</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Class representing a measure as a collection of notes."""</span>
<span class="n">notes</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">note</span><span class="o">.</span><span class="n">NoteDuration</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span>
<span class="n">time_signature</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">is_valid</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return whether the notes given fit exactly into the measure."""</span>
<span class="n">beats_total</span><span class="p">,</span> <span class="n">beats_per_whole</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">time_signature</span>
<span class="k">return</span> <span class="nb">sum</span><span class="p">(</span>
<span class="n">note</span><span class="o">.</span><span class="n">beats_as_written</span><span class="p">(</span><span class="n">beats_per_whole</span><span class="p">)</span>
<span class="k">for</span> <span class="n">note</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">notes</span><span class="p">)</span> <span class="o">==</span> <span class="n">beats_total</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">notes_merged</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="s2">"Measure"</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return a measure that sounds the same, but with the least notes."""</span>
<span class="n">notes</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">notes</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span>
<span class="k">for</span> <span class="n">note_</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">notes</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
<span class="k">if</span> <span class="n">note_</span><span class="o">.</span><span class="n">tied_to_previous</span><span class="p">:</span>
<span class="n">last_note</span> <span class="o">=</span> <span class="n">notes</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">notes</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">note</span><span class="o">.</span><span class="n">NoteDuration</span><span class="p">(</span>
<span class="n">last_note</span><span class="o">.</span><span class="n">full_duration</span> <span class="o">+</span> <span class="n">note_</span><span class="o">.</span><span class="n">full_duration</span><span class="p">,</span>
<span class="n">tied_to_previous</span><span class="o">=</span><span class="n">last_note</span><span class="o">.</span><span class="n">tied_to_previous</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">notes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">note_</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_replace</span><span class="p">(</span><span class="n">notes</span><span class="o">=</span><span class="nb">tuple</span><span class="p">(</span><span class="n">notes</span><span class="p">))</span> <span class="c1"># pylint: disable=no-member</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">beat_separated</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="s2">"Measure"</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""Return a measure that sounds the same, but with defined beats."""</span>
<span class="n">notes</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">offset</span> <span class="o">=</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">()</span>
<span class="n">beats_per_whole</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">time_signature</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">for</span> <span class="n">note_</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">notes_merged</span><span class="o">.</span><span class="n">notes</span><span class="p">:</span>
<span class="n">new_notes</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="n">note_</span><span class="o">.</span><span class="n">subdivide</span><span class="p">(</span><span class="n">beats_per_whole</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
<span class="n">notes</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">new_notes</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_replace</span><span class="p">(</span><span class="n">notes</span><span class="o">=</span><span class="nb">tuple</span><span class="p">(</span><span class="n">notes</span><span class="p">))</span> <span class="c1"># pylint: disable=no-member</span>
<span class="k">def</span> <span class="nf">beats</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Yield each individual beat as a tuple of notes."""</span>
<span class="n">beat_target</span> <span class="o">=</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">time_signature</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="n">beats</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">note_</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">beat_separated</span><span class="o">.</span><span class="n">notes</span><span class="p">:</span>
<span class="n">beats</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">note_</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">sum</span><span class="p">(</span><span class="n">note__</span><span class="o">.</span><span class="n">base_duration</span> <span class="k">for</span> <span class="n">note__</span> <span class="ow">in</span> <span class="n">beats</span><span class="p">)</span> <span class="o">==</span> <span class="n">beat_target</span><span class="p">:</span>
<span class="k">yield</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">beats</span><span class="p">)</span>
<span class="n">beats</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">class</span> <span class="nc">MultiMeasure</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Class representing several measures in sequence."""</span>
<span class="n">measures</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">Measure</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">clap_str</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return the clap pattern for the measures."""</span>
<span class="n">accumulator</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">measure</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">measures</span><span class="p">:</span>
<span class="n">beats</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">measure</span><span class="o">.</span><span class="n">beats</span><span class="p">())</span>
<span class="k">for</span> <span class="n">beat</span><span class="p">,</span> <span class="n">notes</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">beats</span><span class="p">):</span>
<span class="n">beat</span> <span class="o">+=</span> <span class="mi">1</span> <span class="c1"># Account for indexing conventions</span>
<span class="n">realizations</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">if</span> <span class="n">notes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">tied_to_previous</span><span class="p">:</span>
<span class="n">realizations</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">beat</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">realizations</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">'CLAP'</span><span class="p">)</span>
<span class="k">for</span> <span class="n">note_</span> <span class="ow">in</span> <span class="n">notes</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
<span class="c1"># Assume we only do half-divisions</span>
<span class="k">assert</span> <span class="n">note_</span><span class="o">.</span><span class="n">beats_as_written</span><span class="p">(</span>
<span class="n">measure</span><span class="o">.</span><span class="n">time_signature</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">==</span> <span class="mf">0.5</span><span class="p">,</span> <span class="n">notes</span>
<span class="n">realizations</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">'CLAP'</span><span class="p">)</span>
<span class="n">accumulator</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">'-'</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">realizations</span><span class="p">))</span>
<span class="k">return</span> <span class="s1">' '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">accumulator</span><span class="p">)</span>
</pre></div>
<p>Now that I've got ties working, let's see what's next to implement.
I'm going to get some tests added from the book to be completely thorough, but I'm feeling good about this code.</p>
<p>The next thing to do to it is add a bunch of ideas that change up the workings of it.
Yay.</p>
<p>Introducing rests brings in some necessary complication.
Previously, all notes were beginnings and continuations.
I think long-term, I'm going to want to add in explicit note values, and intervals from previous notes, but for now, we've got some tri-state logic in here to confound things.
I believe I want to represent this with an enum:</p>
<ul class="simple">
<li>START (CLAP)</li>
<li>TIED (beat number) (cannot follow a rest)</li>
<li>REST (how about... beat number or "and" in parens)</li>
</ul>
<p>Since getting the tie logic working was such a chore (there was a long stretch in there where I was just littering the code with asserts until I could get it to make sense), I'm going to leave the rest logic for next week.</p>
<hr class="docutils" />
<p>Next week, I rework the logic to handle rests.</p>
Weekly Roundup 2018-05-062018-05-06T04:00:00-04:002018-05-06T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-06:/weekly-roundup-2018-05-06<p class="first last">So many files. Everywhere. Help.</p>
<p>This whole blogging thing is so confusing that I just made a Trello for myself.</p>
<ul class="simple">
<li>Music Theory Monday: I tried to teach my computer basic music theory. It needs work.</li>
<li>Free-Topic Tuesday: I thought about mashing up some concepts to create an RPG design project, which is handy, because I need a new category after...</li>
<li>Site Design Wednesday: I got the theme to "done enough" and pushed it out. Shaved a couple hundred kilobytes off the site size, getting rid of all the theme bits I wasn't using.</li>
<li>Conworld Codex Thursday: I played around with the wxPython tutorials.</li>
<li>Draw a Box Friday: Incremental progress. Very incremental.</li>
<li>Homunculus Saturday: I made a course correction on my attempts to redo the main method, and made some real progress by not trying to <a class="reference external" href="https://en.wiktionary.org/wiki/boil_the_ocean">boil the ocean</a>.</li>
</ul>
Homunculus Devlog 2018-05-052018-05-05T04:00:00-04:002018-05-05T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-05:/homunculus-devlog-2018-05-05<p class="first last">I recovered!</p>
<p>In this post:</p>
<ul class="simple">
<li>Bargaining</li>
<li>Rewrite process</li>
</ul>
<hr class="docutils" />
<p>Okay, here's the deal. It's 9:30 PM right now, and I haven't had a chance to touch the code, let alone write anything up.
I'm going to put this up, poke at the code a little, and publish by midnight GMT.
I just do not want to force my way through this right now.</p>
<p>One thing to keep in mind for later is <a class="reference external" href="https://github.com/python-effect/effect">effect</a>.
It looks like someone did a lot of the hard work in making something like what I envisioned for replacing all the plumbed-in TDL calls.</p>
<p>Okay, so here's where things stand after a good night's sleep.
I realized that the way I was trying to convert the main loop to an object wasn't working, so I deleted that attempt.
Instead, I started modifying the function directly.
First, I consolidated all of its non-rendering-related arguments into a "Game" object.
Then, I moved it to the beginning and renamed it "self", and brought it into the "Game" class.
I divided the new method into a top-level loop that takes the rendering variables, and goes into an infinite loop of rendering, and stepping.
The step function does not take the rendering arguments, so that's a really good sign.</p>
<p>Split out some functions, then realized that I'd like to try moving the message log up a level, turn the step function into a generator.
The hurdle here is that the step function currently has some return values that the program uses.
I turned the return value into another instance variable, simplified control flow a bit, and converted more of the code to using generators.</p>
<p>Of course, I do all that and find I've managed to introduce a bug from all the rewrites.
I managed to miss one change from local variable to instance variable.
Looks like everything else is okay, though.</p>
<p>I've now divided up a monolithic function into many smaller components that don't mingle scope so much.
I think I need to take some time to evaluate the code, see what looks scary now.</p>
<hr class="docutils" />
<p>Next week, I should probably rank the remainder of the code by how big the functions are.
Big functions are suspect because they almost certainly mingle concerns that are possible to separate.</p>
Draw a Box 2018-05-042018-05-04T04:00:00-04:002018-05-04T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-04:/draw-a-box-2018-05-04<p class="first last">I had to come back</p>
<p>In this post:</p>
<ul class="simple">
<li>I'm going to have to inflict the boredom on everyone to make progress.</li>
</ul>
<hr class="docutils" />
<p>After not really working on the exercise much, I realized that I'm going to need to set regular goals for the purpose of just getting through this stuff.
My plan is to draw fifteen lines a day, every day.</p>
<p>Since I came up with this plan, I have drawn:</p>
<ul class="simple">
<li>15 lines on May 3</li>
</ul>
<p>For a total of 15 lines this week,
and 15 lines since I started counting.</p>
<hr class="docutils" />
<p>Next week, the entry will be like this, but more.</p>
Conworld Codex 2018-05-032018-05-03T04:00:00-04:002018-05-03T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-03:/conworld-codex-2018-05-03<p class="first last">Taking A Detour</p>
<p>In this post:</p>
<ul class="simple">
<li>I pivot to Python.</li>
<li>I tweak the wxPython tutorials a little.</li>
<li>The context manager is a bad idea. Just put all of the top-level code in order.</li>
<li>Everything is fine.</li>
</ul>
<hr class="docutils" />
<p>I messed around in Lua a bit, started implementing the logic to store the setting data, and I decided that what I'd like to try to have is, a GUI app backed by SQLite or something.
I'm not up for doing that in Lua, but I'm aware of libraries for that in Python.
I was contemplating using one of them, <a class="reference external" href="https://www.sqlalchemy.org/">SQLAlchemy</a>, for Homunculus, and I've used the other, <a class="reference external" href="https://www.wxpython.org/">wxPython</a>, in a project that didn't get off the ground.</p>
<p>The basic idea is to represent all of the relations I have in mind using annotated adjacency tables.
I don't have a great idea of what the GUI should be like, but I'm going to focus on that first, because I have plenty of experience with ORM code from my day job.</p>
<p>The big break my attempts to follow the tutorial are going to have with what the tutorials say is, I'm really leery of subclassing framework classes, aside from stuff like ORM code.</p>
<p>Let's adapt the Hello World example to my taste, and... hm.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span></pre></div></td><td class="code"><div><pre><span></span><span class="ch">#!/usr/bin/env python3</span>
<span class="kn">import</span> <span class="nn">contextlib</span>
<span class="kn">import</span> <span class="nn">wx</span>
<span class="n">_WX_APP</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_WX_COUNTER</span> <span class="o">=</span> <span class="mi">0</span>
<span class="nd">@contextlib</span><span class="o">.</span><span class="n">contextmanager</span>
<span class="k">def</span> <span class="nf">wx_app</span><span class="p">():</span>
<span class="k">global</span> <span class="n">_WX_APP</span>
<span class="k">global</span> <span class="n">_WX_COUNTER</span>
<span class="k">if</span> <span class="n">_WX_APP</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">_WX_APP</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">App</span><span class="p">(</span><span class="kc">False</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_WX_COUNTER</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">yield</span> <span class="n">_WX_APP</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">_WX_COUNTER</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="n">_WX_COUNTER</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">_WX_APP</span><span class="o">.</span><span class="n">MainLoop</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="k">with</span> <span class="n">wx_app</span><span class="p">():</span>
<span class="n">frame</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">Frame</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">wx</span><span class="o">.</span><span class="n">ID_ANY</span><span class="p">,</span> <span class="s2">"Hello World"</span><span class="p">)</span>
<span class="n">frame</span><span class="o">.</span><span class="n">Show</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</pre></div></td></tr></table></div>
<p>I'll need to use this code more to tell whether some of this is, like, actually a good idea or not.</p>
<p>Text editor:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span></pre></div></td><td class="code"><div><pre><span></span><span class="ch">#!/usr/bin/env python3</span>
<span class="kn">import</span> <span class="nn">contextlib</span>
<span class="kn">import</span> <span class="nn">typing</span>
<span class="kn">import</span> <span class="nn">wx</span>
<span class="n">_WX_APP</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_WX_COUNTER</span> <span class="o">=</span> <span class="mi">0</span>
<span class="nd">@contextlib</span><span class="o">.</span><span class="n">contextmanager</span>
<span class="k">def</span> <span class="nf">wx_app</span><span class="p">():</span>
<span class="k">global</span> <span class="n">_WX_APP</span>
<span class="k">global</span> <span class="n">_WX_COUNTER</span>
<span class="k">if</span> <span class="n">_WX_APP</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">_WX_APP</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">App</span><span class="p">(</span><span class="kc">False</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_WX_COUNTER</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">yield</span> <span class="n">_WX_APP</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">_WX_COUNTER</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="n">_WX_COUNTER</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">_WX_APP</span><span class="o">.</span><span class="n">MainLoop</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">MyFrame</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="n">frame</span><span class="p">:</span> <span class="n">wx</span><span class="o">.</span><span class="n">Frame</span>
<span class="n">control</span><span class="p">:</span> <span class="n">wx</span><span class="o">.</span><span class="n">TextCtrl</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">new</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">parent</span><span class="p">,</span> <span class="n">title</span><span class="p">):</span>
<span class="n">frame</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">Frame</span><span class="p">(</span><span class="n">parent</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="n">title</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="p">(</span><span class="mi">200</span><span class="p">,</span> <span class="mi">100</span><span class="p">))</span>
<span class="n">control</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">TextCtrl</span><span class="p">(</span><span class="n">frame</span><span class="p">,</span> <span class="n">style</span><span class="o">=</span><span class="n">wx</span><span class="o">.</span><span class="n">TE_MULTILINE</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span><span class="n">frame</span><span class="p">,</span> <span class="n">control</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="k">with</span> <span class="n">wx_app</span><span class="p">():</span>
<span class="n">frame</span> <span class="o">=</span> <span class="n">MyFrame</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="s1">'Small editor'</span><span class="p">)</span>
<span class="n">frame</span><span class="o">.</span><span class="n">frame</span><span class="o">.</span><span class="n">Show</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</pre></div></td></tr></table></div>
<p>Maybe in a larger project I could prove my assumptions about what makes sense, but for now, I'm sorry, Larry Wall, but I'm not feeling the hubris yet.</p>
<p>Hm.
I adapted more tutorial code, and something is wrong.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span></pre></div></td><td class="code"><div><pre><span></span><span class="ch">#!/usr/bin/env python3</span>
<span class="kn">import</span> <span class="nn">contextlib</span>
<span class="kn">import</span> <span class="nn">typing</span>
<span class="kn">import</span> <span class="nn">wx</span>
<span class="n">_WX_APP</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_WX_COUNTER</span> <span class="o">=</span> <span class="mi">0</span>
<span class="nd">@contextlib</span><span class="o">.</span><span class="n">contextmanager</span>
<span class="k">def</span> <span class="nf">wx_app</span><span class="p">():</span>
<span class="k">global</span> <span class="n">_WX_APP</span>
<span class="k">global</span> <span class="n">_WX_COUNTER</span>
<span class="k">if</span> <span class="n">_WX_APP</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">_WX_APP</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">App</span><span class="p">(</span><span class="kc">False</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_WX_COUNTER</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">yield</span> <span class="n">_WX_APP</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">_WX_COUNTER</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="n">_WX_COUNTER</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">_WX_APP</span><span class="o">.</span><span class="n">MainLoop</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">MainWindow</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="n">frame</span><span class="p">:</span> <span class="n">wx</span><span class="o">.</span><span class="n">Frame</span>
<span class="n">control</span><span class="p">:</span> <span class="n">wx</span><span class="o">.</span><span class="n">TextCtrl</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">new</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">parent</span><span class="p">,</span> <span class="n">title</span><span class="p">):</span>
<span class="n">frame</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">Frame</span><span class="p">(</span><span class="n">parent</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="n">title</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="p">(</span><span class="mi">200</span><span class="p">,</span> <span class="mi">100</span><span class="p">))</span>
<span class="n">control</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">TextCtrl</span><span class="p">(</span><span class="n">frame</span><span class="p">,</span> <span class="n">style</span><span class="o">=</span><span class="n">wx</span><span class="o">.</span><span class="n">TE_MULTILINE</span><span class="p">)</span>
<span class="n">frame</span><span class="o">.</span><span class="n">CreateStatusBar</span><span class="p">()</span>
<span class="n">filemenu</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">Menu</span><span class="p">()</span>
<span class="n">filemenu</span><span class="o">.</span><span class="n">Append</span><span class="p">(</span>
<span class="n">wx</span><span class="o">.</span><span class="n">ID_ABOUT</span><span class="p">,</span> <span class="s2">"&About"</span><span class="p">,</span> <span class="s2">" Information about this program"</span><span class="p">)</span>
<span class="n">filemenu</span><span class="o">.</span><span class="n">AppendSeparator</span><span class="p">()</span>
<span class="n">filemenu</span><span class="o">.</span><span class="n">Append</span><span class="p">(</span><span class="n">wx</span><span class="o">.</span><span class="n">ID_EXIT</span><span class="p">,</span> <span class="s2">"E&xit"</span><span class="p">,</span> <span class="s2">" Terminate the program"</span><span class="p">)</span>
<span class="n">menubar</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">MenuBar</span><span class="p">()</span>
<span class="n">menubar</span><span class="o">.</span><span class="n">Append</span><span class="p">(</span><span class="n">filemenu</span><span class="p">,</span> <span class="s2">"&File"</span><span class="p">)</span>
<span class="n">frame</span><span class="o">.</span><span class="n">SetMenuBar</span><span class="p">(</span><span class="n">menubar</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span><span class="n">frame</span><span class="p">,</span> <span class="n">control</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="k">with</span> <span class="n">wx_app</span><span class="p">():</span>
<span class="n">frame</span> <span class="o">=</span> <span class="n">MainWindow</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="s1">'Sample editor'</span><span class="p">)</span>
<span class="n">frame</span><span class="o">.</span><span class="n">frame</span><span class="o">.</span><span class="n">Show</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</pre></div></td></tr></table></div>
<p>The file menu doesn't open for me.
I should look into this, try to figure out what's wrong.
Oh, this is <a class="reference external" href="https://github.com/wxWidgets/Phoenix/issues/476">a Mac thing</a>.</p>
<p>I've added some callbacks, and now it's at...</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span></pre></div></td><td class="code"><div><pre><span></span><span class="ch">#!/usr/bin/env python3</span>
<span class="kn">import</span> <span class="nn">contextlib</span>
<span class="kn">import</span> <span class="nn">typing</span>
<span class="kn">import</span> <span class="nn">wx</span>
<span class="n">_WX_APP</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_WX_COUNTER</span> <span class="o">=</span> <span class="mi">0</span>
<span class="nd">@contextlib</span><span class="o">.</span><span class="n">contextmanager</span>
<span class="k">def</span> <span class="nf">wx_app</span><span class="p">():</span>
<span class="k">global</span> <span class="n">_WX_APP</span>
<span class="k">global</span> <span class="n">_WX_COUNTER</span>
<span class="k">if</span> <span class="n">_WX_APP</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">_WX_APP</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">App</span><span class="p">(</span><span class="kc">False</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">_WX_COUNTER</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">yield</span> <span class="n">_WX_APP</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">_WX_COUNTER</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="n">_WX_COUNTER</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">_WX_APP</span><span class="o">.</span><span class="n">MainLoop</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">MainWindow</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="n">frame</span><span class="p">:</span> <span class="n">wx</span><span class="o">.</span><span class="n">Frame</span>
<span class="n">control</span><span class="p">:</span> <span class="n">wx</span><span class="o">.</span><span class="n">TextCtrl</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">new</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">parent</span><span class="p">,</span> <span class="n">title</span><span class="p">):</span>
<span class="n">frame</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">Frame</span><span class="p">(</span><span class="n">parent</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="n">title</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="p">(</span><span class="mi">200</span><span class="p">,</span> <span class="mi">100</span><span class="p">))</span>
<span class="n">control</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">TextCtrl</span><span class="p">(</span><span class="n">frame</span><span class="p">,</span> <span class="n">style</span><span class="o">=</span><span class="n">wx</span><span class="o">.</span><span class="n">TE_MULTILINE</span><span class="p">)</span>
<span class="n">frame</span><span class="o">.</span><span class="n">CreateStatusBar</span><span class="p">()</span>
<span class="n">filemenu</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">Menu</span><span class="p">()</span>
<span class="n">menu_about</span> <span class="o">=</span> <span class="n">filemenu</span><span class="o">.</span><span class="n">Append</span><span class="p">(</span>
<span class="n">wx</span><span class="o">.</span><span class="n">ID_ABOUT</span><span class="p">,</span> <span class="s2">"&About"</span><span class="p">,</span> <span class="s2">" Information about this program"</span><span class="p">)</span>
<span class="n">filemenu</span><span class="o">.</span><span class="n">AppendSeparator</span><span class="p">()</span>
<span class="n">menu_exit</span> <span class="o">=</span> <span class="n">filemenu</span><span class="o">.</span><span class="n">Append</span><span class="p">(</span>
<span class="n">wx</span><span class="o">.</span><span class="n">ID_EXIT</span><span class="p">,</span> <span class="s2">"E&xit"</span><span class="p">,</span> <span class="s2">" Terminate the program"</span><span class="p">)</span>
<span class="n">menubar</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">MenuBar</span><span class="p">()</span>
<span class="n">menubar</span><span class="o">.</span><span class="n">Append</span><span class="p">(</span><span class="n">filemenu</span><span class="p">,</span> <span class="s2">"&File"</span><span class="p">)</span>
<span class="n">frame</span><span class="o">.</span><span class="n">SetMenuBar</span><span class="p">(</span><span class="n">menubar</span><span class="p">)</span>
<span class="bp">self</span> <span class="o">=</span> <span class="bp">cls</span><span class="p">(</span><span class="n">frame</span><span class="p">,</span> <span class="n">control</span><span class="p">)</span>
<span class="n">frame</span><span class="o">.</span><span class="n">Bind</span><span class="p">(</span><span class="n">wx</span><span class="o">.</span><span class="n">EVT_MENU</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">on_about</span><span class="p">,</span> <span class="n">menu_about</span><span class="p">)</span>
<span class="n">frame</span><span class="o">.</span><span class="n">Bind</span><span class="p">(</span><span class="n">wx</span><span class="o">.</span><span class="n">EVT_MENU</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">on_exit</span><span class="p">,</span> <span class="n">menu_exit</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">self</span>
<span class="k">def</span> <span class="nf">on_about</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">e</span><span class="p">):</span>
<span class="n">dlg</span> <span class="o">=</span> <span class="n">wx</span><span class="o">.</span><span class="n">MessageDialog</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">frame</span><span class="p">,</span> <span class="s2">"A small text editor"</span><span class="p">,</span> <span class="s2">"About Sample Editor"</span><span class="p">,</span> <span class="n">wx</span><span class="o">.</span><span class="n">OK</span><span class="p">)</span>
<span class="n">dlg</span><span class="o">.</span><span class="n">ShowModal</span><span class="p">()</span>
<span class="n">dlg</span><span class="o">.</span><span class="n">Destroy</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">on_exit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">e</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">frame</span><span class="o">.</span><span class="n">Close</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="k">with</span> <span class="n">wx_app</span><span class="p">():</span>
<span class="n">frame</span> <span class="o">=</span> <span class="n">MainWindow</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="s1">'Sample editor'</span><span class="p">)</span>
<span class="n">frame</span><span class="o">.</span><span class="n">frame</span><span class="o">.</span><span class="n">Show</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</pre></div></td></tr></table></div>
<p>This is all very serviceable, though I am coming to the conclusion that the context manager was a bad idea.
HOWEVER, I've got some new shininess I want to try out.</p>
<p>The new shininess works.
I don't feel like pasting the code here though, because it is completely normal and not at all strange.
Everything is fine.</p>
<hr class="docutils" />
<p>Next week, I'll aim to write code more relevant to conworlds and codexing.</p>
Site Design 2018-05-022018-05-02T04:00:00-04:002018-05-02T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-02:/site-design-2018-05-02<p class="first last">This Theme Is The MVP</p>
<p>In this post:</p>
<ul class="simple">
<li>I finish iterating on the theme enough to be satisfied with it. Hooray!</li>
</ul>
<hr class="docutils" />
<p>I stuck a magenta border around the post content.
This really brings things together.
I should do something similar for the pages.</p>
<p>Stuck a cyan border on it, and it's in good shape.
Now the obvious thing to do is make an atom link somewhere.</p>
<p>I stuck it in the bottom bar.
Looking over this, there's obviously a lot of fanciness missing, but I think it's ready to go.
I'll sleep on this for a few days, and push the changes when I take this post live.</p>
<hr class="docutils" />
<p>Next week, I consider whether I want to keep blogging about this, or find another category to write in, ideally one that's light on coding.
Maybe I'll keep on that RPG concept from yesterday...</p>
RPG Idea: Demiurgent Business2018-05-01T04:00:00-04:002018-05-01T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-05-01:/rpg-idea-demiurgent-business<p class="first last">Or, The Hopeful Non-Infringement Of Haruhi Suzumiya</p>
<p>In this post:</p>
<ul class="simple">
<li>I outline an idea for a roleplaying game.</li>
<li>I come up with a bunch of games to research so I'm not flying blind.</li>
</ul>
<hr class="docutils" />
<p>I've been thinking about tabletop roleplaying games lately.
I've been trying to get some steam into GMing a solo campaign for my wife, but we keep on not thinking to get into it.
Maybe we should set a time each week.</p>
<p>Anyway, a couple other ideas kind of swirled around in my head...</p>
<ul class="simple">
<li>Legend's track-based multi-classing system</li>
<li>Playing Smash-Up, and getting better memories from selecting decks to combine than putting them into practice</li>
<li>The suggestion to try building an RPG without combat mechanics</li>
</ul>
<p>Basically, can I come up with a way to replicate some of the details of Legend's system (humanoid race plus three class features, or monstrous race with feature replacing class feature, either option can freely replace a class feature with one from another class), but divorced from the "combat balance" ideas?
Tonally, I want to have the class features represent different pop culture archetypes.
Suppose I get together pirates, aliens, zombies, robots, etc... what's a setting that lets them shine without dealing with combat resolution?</p>
<p>Thinking over this, my impulse is to do some kind of high school/college drama, maybe.
Or perhaps some other situation with jockeying for status.
Or maybe something that's like Haruhi Suzumiya, but with the serial numbers filed off.
Having to deal with a god-like NPC would be interesting, but only if the rules transparently dictated the NPC's mood/whims, and the GM's job was just to convey them flavorfully.</p>
<p>Although, if there are legitimate fantasy creatures running around openly, the NPC would have to be comically nearsighted or something, not to notice.</p>
<p>The basic structure I'm thinking of is that the player characters all have various extraordinary abilities, but risk gaining Break when they use them normally.
Under some circumstances, things are explicitly unreal, and they can use their abilities freely.</p>
<p>Race concepts:</p>
<ul class="simple">
<li>Human</li>
<li>Elf Wearing A Bandana Or Other Hat</li>
<li>Dwarf</li>
<li>Orc In The Theatre Program</li>
<li>Fairy, Insisting That They Are Further Away Than They Actually Are</li>
<li>Alien (class feature)</li>
<li>Android (class feature)</li>
<li>Undead (class feature) (zombies, vampires, ghosts)</li>
<li>Dragon (class feature)</li>
<li>Ancient One (class feature)</li>
<li>Werewolves maybe</li>
</ul>
<p>Class concepts:</p>
<ul class="simple">
<li>Esper</li>
<li>Time Jumper</li>
<li>Pirate</li>
<li>Ninja</li>
<li>Wizard</li>
<li>Survivalist</li>
<li>Everyman</li>
<li>Summoner</li>
<li>Gunslinger</li>
<li>Rock Star</li>
<li>Shaman</li>
<li>Seer</li>
</ul>
<p>Characters would be a class and race, and some further customization: what do they look like, what clubs are they in, how do they know each other...</p>
<p>If I go with numerical stats, there probably wouldn't be strength. More likely:</p>
<ul class="simple">
<li>ENDurance: your character's ability to withstand adverse conditions</li>
<li>FASt-talking: your character's ability to persuade people of things</li>
<li>UNFlappability: your character's ability to deal with outrageous conditions</li>
</ul>
<p>This has been throwing out some concepts, but I think what I need if I'm going to pursue this is a lot of reference material, and a few gameplay assumptions.</p>
<p>Assumptions:</p>
<ul class="simple">
<li>The masquerade will never actually be broken, but the characters should act as if it could be. This pushes play towards "I’m an actor, and my character is my role. I’ll do whatever I think my character would do." and "My character is the protagonist of a story I’m telling. I’ll do whatever makes for the most interesting narrative."</li>
<li>This also means that restrictions based on Break should be hard limits that players can look for ways to circumvent, rather than risks they'd be tempted to take.</li>
<li>Player characters will divide their time between managing the Demiurge, and fulfilling class obligations of some kind, whether that's reporting to superiors, hunting down traitors, performing some form of meditation, etc.</li>
<li>The race/class stuff is meant to be a flashy starting point that draws the player into designing their character's high-school persona, which should generally be more mechanically relevant.</li>
</ul>
<p>Gameplay elements to look for:</p>
<ul class="simple">
<li>Rules-mandated character with specific power dynamics (Maid RPG? My Life With Master?)</li>
<li>Maintaining a masquerade (Some form of urban fantasy)</li>
<li>Characters often must do bizarre, demeaning things. Aim for something that amuses the players controlling them. (That sounds a little like Fiasco, but the tonal components are very different. Look for similar games, ponder lifting the scene resolution mechanics in a different context)</li>
<li>High school setting (I don't know what to look at that I have on hand besides some stuff by Ewen Cluney, who also localized Maid RPG, so I've got lots of stuff to look at here; also, I should probably look into Teenagers from Outer Space, though it sounds kind of different from what I have in mind.)</li>
<li>No combat mechanics</li>
<li>In-universe events that alter the rules the players have (sounds like rituals from Chuubo's)</li>
<li>In a break from the source material, the spotlight should be shared evenly among player characters, rather than having an explicit viewpoint character.</li>
<li>Arc structure: start at status quo, something happens to disrupt it, player characters must reaffirm it</li>
</ul>
<p>Actually, looking at how much I wrote down stuff Ewen Cluney was involved in, and seeing stuff from Bully Pulpit, I wonder if something like Durance's planet creation/selection rules could be used to make a custom Demiurge.
Like, the initial report showed that dealing with the Demiurge would be no big deal, for reasons A, B, C, D, E, F.
Now pick three of those that were somehow mistaken, falsified, or otherwise wrong.</p>
<p>In any case, a few of those I don't really have ideas for, and I feel like my focus in tracking down reference material should be stuff with masquerade support of some kind, and stuff set in high school.</p>
<p>Trying to design a relatively focused game like this seems interesting.
I'll have to look into it... maybe sooner than you think... <em>ooooooo</em></p>
Music Theory 2018-04-302018-04-30T04:00:00-04:002018-04-30T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-30:/music-theory-2018-04-30<p class="first last">Back To Basics</p>
<p>In this post:</p>
<ul class="simple">
<li>I define the basic concepts around note durations.</li>
<li>I put notes into measures, and measures into larger units.</li>
<li>I started working on modeling beat structure within a measure.</li>
</ul>
<hr class="docutils" />
<p>I was a little too ambitious, I think, in my previous ideas.
I got a nice unified music theory guide that I don't need to click hyperlinks to get around in, so I'm going to try to teach my code the stuff this book is (re-)teaching me.</p>
<p>First up, beats.
The code must have a concept of a common-time measure (other time signatures come later), and note durations to fill it with.</p>
<p>(... God dammit, this section is called "Meeting the Beat". Cluckin fassy, guys.)</p>
<p>Anyway, I'm going to do the following:</p>
<ul class="simple">
<li>Powers of two durations</li>
<li>Augmentation dots</li>
<li>Ties</li>
</ul>
<p>And not yet stuff like tuplets, which are confusing.</p>
<p>A note is going to consist of an exponent to apply to 2 (usually ranging down from 1, rarely lower than -5), an augmentation dot count (usually 0, sometimes 1, rarely 2 or more) and a "tied" boolean.</p>
<p>Okay, that's the plan, let's get started.
I have my "tiny_music" project, which I've cloned from in preparation for making a cookie-cutter, but I don't need that yet.
First, I confirm that the tests are all green.
Next, I add a note.py file.
Before anything else, I rerun the tests.
The docstyle test fails because the module is undocumented.
Document it, and all green again.</p>
<p>Next, I add the class I described above.
The file now looks like:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""Data structures for representing note durations."""</span>
<span class="kn">import</span> <span class="nn">typing</span>
<span class="k">class</span> <span class="nc">NoteDuration</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Class representing a single note as written."""</span>
<span class="n">duration_power</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">augmentation_dots</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">tied_to_next</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
</pre></div></td></tr></table></div>
<p>I run the tests, and, oh no!, two failures!
One of them is because I missed properly configuring pylint.
The too-few-public-methods lint can go die in a fire.
The other is because this new module is never imported, and now that it has code in it, that's a problem.</p>
<p>... Hold on.</p>
<div class="highlight"><pre><span></span><span class="k">[MESSAGES CONTROL]</span>
<span class="c1"># ...</span>
<span class="na">disable</span><span class="o">=</span><span class="s">print-statement,</span>
<span class="w"> </span><span class="c1"># ...</span>
<span class="w"> </span><span class="na">too-few-public-methods</span>
</pre></div>
<p>What.</p>
<p>The machine uprising has a tastefully understated beginning.</p>
<p>Anyway, it's time to enter the world of yak shaving.
Step 1, generate a fresh pylintrc and check for discrepancies.</p>
<p>Got it.
The greatest trick the devil ever pulled was allowing multi-line sequences to require a comma between items, but not mandatorily end with a comma, and say nothing if there's just this random indented text after the list.
(It's like goto-fail, but for your config files!)</p>
<p>Anyway, back to green.
Let's make some constants.</p>
<div class="highlight"><pre><span></span><span class="n">BREVE</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">WHOLE</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="p">()</span>
<span class="n">HALF</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="n">QUARTER</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="p">(</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span>
<span class="n">EIGHTH</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="p">(</span><span class="o">-</span><span class="mi">3</span><span class="p">)</span>
<span class="n">SIXTEENTH</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="p">(</span><span class="o">-</span><span class="mi">4</span><span class="p">)</span>
<span class="n">THIRTY_SECOND</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="p">(</span><span class="o">-</span><span class="mi">5</span><span class="p">)</span>
<span class="n">DOTTED_HALF</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">DOTTED_QUARTER</span> <span class="o">=</span> <span class="n">NoteDuration</span><span class="p">(</span><span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</pre></div>
<p>Simple enough so far.
The tests still all pass, because this code is run at import time.</p>
<p>Anyway, synthesis is a separate issue, but we still want to establish that the code "understands" these durations, in some sense.
First, we need to be able to contain the notes in measures.
Let's add another file for that, because I like small modules.</p>
<div class="highlight"><pre><span></span><span class="sd">"""Data structures for representing measures."""</span>
<span class="kn">import</span> <span class="nn">fractions</span>
<span class="kn">import</span> <span class="nn">typing</span>
<span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">note</span>
<span class="k">class</span> <span class="nc">Measure</span><span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">NamedTuple</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Class representing a measure as a collection of notes."""</span>
<span class="n">notes</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Tuple</span><span class="p">[</span><span class="n">note</span><span class="o">.</span><span class="n">NoteDuration</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span>
<span class="c1"># This does not account for beat division.</span>
<span class="n">length</span><span class="p">:</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span> <span class="o">=</span> <span class="n">fractions</span><span class="o">.</span><span class="n">Fraction</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</pre></div>
<p>I add basic tests, and that all passes.
Long-term, measures will use an ABC rather than an explicit reference to NoteDuration, but I don't need to write that yet.</p>
<p>Now, we need to confirm that measures cannot "overflow".
So, let's write some tests, first containing various valid combinations of durations, then more that are invalid.</p>
<p>Well, I added that test, and then realized I'd need more features to implement it.
If one failing test is good, two must be great!
The necessary feature is the ability to determine the "beats as written" (that is, ignoring ties) of a note, <em>given</em> the number of beats in a whole note.</p>
<p>... Huh.
Turns out I can't override the constructors or initializers of typing.NamedTuple to introduce stuff like validation logic.
I'm willing to change the interface to accommodate this.
Now, you can construct any measure you want, but maybe it will not be valid, which is why you want to check the is_valid property.</p>
<p>Now that we have the ability to represent a written measure in code, let's get the computer to analyze it.
I don't have any synthesis capabilities set up, so I'll instead write functions that generate "spoken-out" renditions of the duration structure.
Like, three measures of a whole note each would be "CLAP 2 3 4 CLAP 2 3 4 CLAP 2 3 4".
First, this needs the ability to consider several measures in sequence.</p>
<p>I got really into porting examples into tests and getting everything working.
I just want to state for the record that getting eighth notes to sort of work right was <em>really obnoxious</em>.</p>
<p>Next up, respecting ties when it comes to notating the claps.
This is going to <em>suck</em>.
I mean, it "shouldn't" be so bad, but the big reason I have ties treated the way they are so far is, they let a note duration cross measure boundaries, which is pretty important.
Here's what I need: if a note is tied to a note <em>within</em> the measure, the correct course of action is to add its length to a local and continue.
If a note is <em>not</em> tied, reset the local.
If a note is tied at the end of a measure, process it normally and set a flag.
When I see that flag, <em>do not</em> notate a clap, then unset the flag.</p>
<p>Let's start off simple, though.
I made a test.
The test fails.
I honestly feel like working on other posts instead, so maybe I'm done with this for the week.</p>
<p>LATE CHANGE: <em>except that</em>, I realized that, for later extensions, I want to store whether a note is tied to the <em>previous note</em>, instead of the <em>next</em>.
So it's a good thing I didn't start on that algorithm yet.</p>
<hr class="docutils" />
<p>Next week, I'll try to get ties working properly, then move on to rests.</p>
Weekly Roundup 2018-04-292018-04-29T04:00:00-04:002018-04-29T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-29:/weekly-roundup-2018-04-29<p class="first last">I have readers?!</p>
<p>Before anything else, I happened to look at my site stats recently, and...</p>
<p>WOW!</p>
<p>I don't know who's reading this, but plenty of people are, so:</p>
<p>Thank you!</p>
<p>¡Gracias!</p>
<p>Danke schön!</p>
<p>Спасибо!</p>
<p>ありがとうございました!</p>
<p>All those emotions made me feel like showing off the languages I'm trying to learn, I guess, heh.</p>
<p>In the past week, I wrote the following posts:</p>
<ul class="simple">
<li>Music Theory Monday: I listened to a bunch of intervals, and tried to rate them. I also got a little ahead of myself. I've revised my plans for the next post.</li>
<li>Free-Topic Tuesday: I talked about objects as distinct from classes, and posted some <em>hilarious</em> UML diagrams.</li>
<li>Site Design Wednesday: I fixed most of the big issues with the theme I'm working on.</li>
<li>Conworld Codex Thursday: I hastily put together a prototype to develop the library against.</li>
<li>Draw a Box Friday: I didn't post anything, because I still haven't drawn a box.</li>
<li>Homunculus Saturday: I made a little progress, by recasting the "main" loop as a series of "steps", where the "step" function has minimal flow control.</li>
</ul>
Homunculus Devlog 2018-04-282018-04-28T04:00:00-04:002018-04-28T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-28:/homunculus-devlog-2018-04-28<p class="first last">Good Coding Practices, My Ass</p>
<p>In this post:</p>
<ul class="simple">
<li>I got a late start again, and so it's short.</li>
<li>I jump ahead to the "step function" idea, because the loosey-goosey way things are set up is just so draining to think about.</li>
</ul>
<hr class="docutils" />
<p>As I mentioned on Tuesday, I noticed that some of the functions making up the current version of Homunculus could quite easily be considered as methods of an object, rather than a long-running loop with locals.
I started trying to write a replacement for the main function, and it's a little painful.
I just feel like the code as presented in the tutorial has a "get things done quick, no matter the cost" feel, and that tends to obscure the code's motivation.</p>
<p>Okay, since the new code is currently dead anyway, let's see if I can represent the stuff in the main function as a bunch of logical steps.
... Okay, I was able to start on that, but it's hard to think about how to change the "action" stuff.
Basically, mouse and keyboard input gets converted into "actions".
Type-wise, these things are really weird to me, because the underlying data type is a dict that maps strings to arbitrary objects, but it's <em>guaranteed</em> that the current implementation will never produce a dict with more than one entry.
It almost looks like I could replace them with a 2-tuple with a special do_nothing state.
I might try that now, see if that makes me happier.
Or I might not. It's kind of a half-measure, doing that, when what I really want is to make some namedtuple subclasses that contain behavior.
Maybe the bahavior should be <em>defined</em> on the actions, which get passed the game object and mouse action, and process them?
I think using polymorphism like that is ultimately the way to go.
Per the single-responsibility principle, it means that changing the implementation of any action doesn't lead to a change in the step method, so it's better than what I have now, I think.</p>
<p>I've made the step function just act like that stuff is already in place.</p>
<p>I'm feeling good about taking these changes forward.
I basically have three methods to implement now, and a bunch of classes to write.
It's all the same amount of code, but now I can sort it into a bite-sized checklist.
Divide and conquer, it's how we get anything done with this computer stuff.</p>
<hr class="docutils" />
<p>Next week, I'll fill in as much as I can of the new methods and the action classes.
Also, I want to write serializers for the new "game" class.</p>
Conworld Codex 2018-04-262018-04-26T04:00:00-04:002018-04-26T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-26:/conworld-codex-2018-04-26<p class="first last">I would have liked to do more, but oh well</p>
<p>In this post:</p>
<ul class="simple">
<li>Pasted code showing off my attempt to design the Codex library by using it before it exists.</li>
<li>Notes on stuff I introduced just for this.</li>
<li>Getting philosophical about having written this stuff in a frantic haze.</li>
</ul>
<hr class="docutils" />
<p>I didn't have a lot of lead time for this post.
Starting a few hours before I published it, I took an empty file and started typing plausible-looking code into it.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span></pre></div></td><td class="code"><div><pre><span></span><span class="c1">---</span>
<span class="c1">-- Setting codex for Linked Seas 'Verse.</span>
<span class="c1">-- @module linked_seas</span>
<span class="kd">local</span> <span class="n">cc</span> <span class="o">=</span> <span class="nb">require</span> <span class="s1">'conworld_codex'</span>
<span class="kd">local</span> <span class="n">codex</span> <span class="o">=</span> <span class="n">cc</span><span class="p">:</span><span class="n">new</span><span class="p">()</span>
<span class="kd">local</span> <span class="n">salt_mill_critiqued</span> <span class="o">=</span> <span class="n">codex</span><span class="p">:</span><span class="n">event</span><span class="p">(</span>
<span class="s2">"The Yeffle Salon-Gazette criticizes the Aternabel salt mill design"</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">bilusic_population_boom</span> <span class="o">=</span> <span class="n">codex</span><span class="p">:</span><span class="n">event</span><span class="p">(</span>
<span class="s2">"New farming and sanitation techniques lead to a massive population increase in Bilus"</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">bilusic_expansion</span> <span class="o">=</span> <span class="n">codex</span><span class="p">:</span><span class="n">event</span><span class="p">(</span>
<span class="s2">"Bilus expands agressively, but ultimately is defeated"</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">gaewon_empire</span> <span class="o">=</span> <span class="n">codex</span><span class="p">:</span><span class="n">event</span><span class="p">(</span>
<span class="s2">"Gaewon controls an expansive empire, briefly"</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">aternabel_at_spansen</span> <span class="o">=</span> <span class="n">codex</span><span class="p">:</span><span class="n">event</span><span class="p">(</span>
<span class="s2">"Admiral Aternabel petitions for a commission against Afepes"</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">plague_of_gaewon</span> <span class="o">=</span> <span class="n">codex</span><span class="p">:</span><span class="n">event</span><span class="p">(</span>
<span class="s2">"A plague along the southern coast of Gaewon fractures the empire"</span><span class="p">)</span>
<span class="c1">-- This next one is of course a complete fantasy idea. Governments NEVER pursue</span>
<span class="c1">-- exclusively short-term solutions and put off responsibility onto the future.</span>
<span class="n">codex</span><span class="p">:</span><span class="n">contributed_to</span><span class="p">(</span>
<span class="n">bilusic_population_boom</span><span class="p">,</span> <span class="n">bilusic_expansion</span><span class="p">,</span>
<span class="s2">"The reigning belief in Bilus's government was that war would address "</span> <span class="o">..</span>
<span class="s2">"the crowding, either through colonization or attrition"</span><span class="p">)</span>
<span class="n">codex</span><span class="p">:</span><span class="n">contributed_to</span><span class="p">(</span>
<span class="n">salt_mill_critiqued</span><span class="p">,</span> <span class="n">aternabel_at_spansen</span><span class="p">,</span>
<span class="s2">"Admiral Aternabel wishes to realize the designs of his grandfather(?)"</span><span class="p">)</span>
<span class="n">codex</span><span class="p">:</span><span class="n">contributed_to</span><span class="p">(</span>
<span class="n">bilusic_expansion</span><span class="p">,</span> <span class="n">gaewon_empire</span><span class="p">,</span>
<span class="s2">"The defeat of the Bilusic navy gives Gaewon the confidence to expand, "</span> <span class="o">..</span>
<span class="s2">"itself"</span><span class="p">)</span>
<span class="n">codex</span><span class="p">:</span><span class="n">part_of</span><span class="p">(</span>
<span class="n">aternabel_at_spansen</span><span class="p">,</span> <span class="n">gaewon_empire</span><span class="p">,</span>
<span class="s2">"Admiral Aternabel's speech was part of a general sentiment that "</span> <span class="o">..</span>
<span class="s2">"Gaewon had 'proven itself' by defeating Bilus"</span><span class="p">)</span>
<span class="n">codex</span><span class="p">:</span><span class="n">part_of</span><span class="p">(</span>
<span class="n">plague_of_gaewon</span><span class="p">,</span> <span class="n">gaewon_empire</span>
<span class="s2">"The Plague threw the island of Gaewon into chaos, severing "</span> <span class="o">..</span>
<span class="s2">"administrative ties with the colonies"</span><span class="p">)</span>
</pre></div></td></tr></table></div>
<p>The basic idea right now is that a given setting has its own "codex", which is basically a database.
The codex contains events, with a short description, and relates them in various ways, with a further description of the relationship.</p>
<p>I've held off on actually implementing any of this until I'm sure this is how I want to do it.
This is approximately the second revision already, and the first revision had some very different ideas that didn't fit in this context.</p>
<p>Expanding on this is going to be kind of a delicate thing.
I kind of assume that I'm going to want to tag stuff, like, Bilus, Gaewon, Kuirkentord, Aternabel, Masilomaru yan Grevitch, salt, but I don't know what I want that tagging to look like.
Wait, actually...</p>
<div class="highlight"><pre><span></span><span class="kd">local</span> <span class="n">salt</span> <span class="o">=</span> <span class="n">codex</span><span class="p">:</span><span class="n">tag</span> <span class="s1">'salt'</span>
<span class="kd">local</span> <span class="n">deoshen_aternabel</span> <span class="o">=</span> <span class="n">codex</span><span class="p">:</span><span class="n">tag</span> <span class="s1">'Deoshen Aternabel'</span>
<span class="kd">local</span> <span class="n">atsimats_aternabel</span> <span class="o">=</span> <span class="n">codex</span><span class="p">:</span><span class="n">tag</span> <span class="s1">'Atsimats Aternabel'</span>
<span class="c1">--...</span>
<span class="n">codex</span><span class="p">:</span><span class="n">relates_to</span><span class="p">(</span>
<span class="n">salt</span><span class="p">,</span> <span class="n">salt_mill_critiqued</span><span class="p">,</span>
<span class="s2">"Deoshen Aternabel's salt mill design was intended to use sun, wind, "</span> <span class="o">..</span>
<span class="s2">"etc, to extract salt from the ocean."</span><span class="p">)</span>
<span class="n">codex</span><span class="p">:</span><span class="n">relates_to</span><span class="p">(</span>
<span class="n">deoshen_aternabel</span><span class="p">,</span> <span class="n">salt_mill_critiqued</span><span class="p">,</span>
<span class="s2">"Deoshen Aternabel designed a 'salt mill'. Despite the care he put "</span> <span class="o">..</span>
<span class="s2">"into its architecture, he never addressed the fact that his design "</span> <span class="o">..</span>
<span class="s2">"was impractical in the cool, moist climate of Gaewon."</span><span class="p">)</span>
<span class="n">codex</span><span class="p">:</span><span class="n">relates_to</span><span class="p">(</span>
<span class="n">atsimats_aternabel</span><span class="p">,</span> <span class="n">aternabel_at_spansen</span><span class="p">,</span>
<span class="s2">"Admiral Atsimats Aternabel saw Gaewon's victory over Bilus as a "</span> <span class="o">..</span>
<span class="s2">"chance to bring glory to his family by realizing Deoshen's design. He "</span> <span class="o">..</span>
<span class="s2">"framed it in terms of the glory of Gaewon."</span><span class="p">)</span>
</pre></div>
<p>I'll need to think about this more, but this looks sort of reasonable.
Also, I came up with Deoshen and Atsimats as names just for this, because it was really obnoxious calling them "Aternabel" and "Admiral Aternabel".
I want to get into the linguistics of all this at some point, have naming languages, make sure that Deoshen and Atsimats (Дэошэн and Ацимац?) are legit Gaewon names.</p>
<p>The big thing I wonder right now is if I want to remove the "codex" references, and just relate tags and events to each other directly.
That would more closely resemble English grammar, which is potentially useful for function names made of English words.</p>
<p>Regardless, I didn't have a design when I started, and now I do, so that's cool.</p>
<hr class="docutils" />
<p>Next week, I'll have tried out some minor syntax changes, and hopefully have gotten LDoc integrated into the publishing toolchain.</p>
Site Design 2018-04-252018-04-25T04:00:00-04:002018-04-25T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-25:/site-design-2018-04-25<p class="first last">You Can't See It Right Now, But I'm Making Progress</p>
<p>In this post:</p>
<ul class="simple">
<li>I talk myself most of the way through getting the new theme into a usable state.</li>
</ul>
<hr class="docutils" />
<p>I'm not working with the best of buffers here, so this might be a little rushed.
Right now I'm trying to focus on adding navigation links to the header.
The basic idea is, given the list of articles by category, filter to the current category, then find the adjacent articles.</p>
<p>So, first, filter the "categories" variable to things where the first element matches the current category.
It looks like this might need custom settings code.
... I feel like Pelican has some kind of horrible impedance mismatch that I'm failing to hit <em>only</em> because I'm too stubborn to give up my <abbr title="Not Invented Here">NIH</abbr> feelings.</p>
<p>Well, I gave them up enough to copy a solution off GitHub, but not enough that I didn't rewrite it several times.
I've got a proof of concept for the navigation links now.
I think really what I need to do now is to survey all of the pages and see what needs touching up.</p>
<p>Let's just put the entire set of templates in here...</p>
<ul class="simple">
<li>archives.html: single page, all articles in a definition list</li>
<li>article.html: footer is above the post? Need some kind of indicator for indicating lack of nav links, and category. Like "next in [blah]"</li>
<li>author.html: list of blog posts. I don't really care about it right now</li>
<li>authors.html: list of authors (me) along with post counts</li>
<li>base.html: doesn't do some of the links</li>
<li>categories.html: list of categories</li>
<li>index.html: blog posts in summary form only</li>
<li>page.html: it's fine</li>
<li>pagination.html</li>
<li>period_archives.html: this is a definition list of articles, and I don't seem to be using it? I'll think about messing with this later, but I don't see anything urgent.</li>
<li>tag.html: this looks... broken? I'll look into it later.</li>
<li>tags.html: list of tags, along with post counts</li>
<li>translations.html</li>
</ul>
<p>To my mind, solving niggles with the article template is the highest priority.
Changes to the article template require the most reuploads.</p>
<p>"But Max, the website fits on a floppy disk right now!"</p>
<p>Ssssh.</p>
<p>Okay, here are the priorities:</p>
<ul class="simple">
<li>Stop generating author pages, so I don't feel like thinking about them.</li>
<li>That has a setting twiddle. Make the theme respect it.</li>
<li>Clean up the nav link display.</li>
<li>Put things in the right order.</li>
<li>Get social links and blogroll into the footer area, above the Neocities badge/banner/whatever</li>
<li>The Neocities badge/banner/whatever should go on the right.</li>
</ul>
<p>Once I've done everything through the second-last item on that list, I'll be ready to roll out the new theme.</p>
<p>... Turns out the last one was pretty easy to get sort of working, so now it's the rest of it.</p>
<p>Okay, I've got most of the stuff I wanted done.
Maybe there are a few tweaks left, but I'm going to focus on styles now.
And maybe host local copies of the fonts while I'm in this area.</p>
<p>I think there are some lingering style issues, but the code is very close.
I still didn't fix the tags page, but I'm not even sure how to access that.
I'm going to sleep on this, and see what other changes I want to make.</p>
<hr class="docutils" />
<p>Next week, in addition to necessary changes, I should probably toss in some chunky horizontal lines for the AESTHETIC.</p>
Instantiations of the Object Pattern2018-04-24T04:00:00-04:002018-04-24T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-24:/instantiations-of-the-object-pattern<p class="first last">Patterns Can Be Replaced With Language Features, But They Are Not Always</p>
<p>In this post:</p>
<ul class="simple">
<li>An elaborate piss-take of some kind.</li>
<li>Legitimate thoughts.</li>
</ul>
<hr class="docutils" />
<p>Working on <a class="reference external" href="https://mwchase.neocities.org/category/homunculus">Homunculus</a> and the new script for publishing this blog, I ran across two different "classless" uses of the object pattern in Python. To be specific about what the object pattern <em>is</em>:</p>
<dl class="docutils">
<dt>Pattern Name and Classification</dt>
<dd>Object</dd>
<dt>Intent</dt>
<dd>Given (only) a cohesive collection of program state, have a means of obtaining functions that alter their behavior based on the state, or alter the state.</dd>
<dt>Also Known As</dt>
<dd>Traits and typeclasses, probably.</dd>
<dt>Motivation (Forces)</dt>
<dd>A collection of variables or a data structure can provide all of the data needed for some computational task, but does not afford any particular means of interacting with the data.
It cannot enforce invariants, and if different collections of data could be put to the same purpose, consumers of the data must be aware of which kind of collection they are acting on, to use the proper functions.
By providing a means to obtain or create the specific functions meant for a collection of state, that collection of state assumes the responsibility of maintaining invariants and implementing behavior; all callers have merely to use the object protocols to obtain the desired behavior.</dd>
<dt>Applicability</dt>
<dd><p class="first">In some languages, the use of this pattern is basically mandatory to accomplish anything.
In freer contexts, the criteria for applicability are:</p>
<ol class="last arabic simple">
<li>There are multiple underlying implementations that could conceivably be provided to the same consuming code, <strong>OR</strong> at least one implementation involves state subject to invariants.</li>
<li>This form of dispatch is actually supported by the language.</li>
</ol>
</dd>
<dt>Structure</dt>
<dd><p class="first">A survey of <em>some</em> possible implementations:</p>
<ul class="last simple">
<li>Module structure: <span class="raw-html"><br /></span> <img alt="Modules have functions and variables." src="https://mwchase.neocities.org/images/module_class.png" /> <span class="raw-html"><br /></span> <img alt="The caller resolves a function in the module scope, then calls it. The function implicitly has access to the module scope, and can read and write to it." src="https://mwchase.neocities.org/images/module_sequence.png" /></li>
<li>Closure structure: <span class="raw-html"><br /></span> <img alt="Closures close over a function scope, which contains variables." src="https://mwchase.neocities.org/images/closure_class.png" /> <span class="raw-html"><br /></span> <img alt="The caller invokes a closure, which resolves variables in its current scope, possibly mutating them before returning." src="https://mwchase.neocities.org/images/closure_sequence.png" /></li>
<li>Class structure: <span class="raw-html"><br /></span> <img alt="Objects are instances of a class. Objects have attributes, and classes have methods." src="https://mwchase.neocities.org/images/class_class.png" /> <span class="raw-html"><br /></span> <img alt="The caller looks up the class of the object, resolves the method from the class, passes the object into the method, which operates on the object, then returns a result." src="https://mwchase.neocities.org/images/class_sequence.png" /></li>
</ul>
</dd>
<dt>Participants</dt>
<dd><ul class="first last simple">
<li>Module structure:<ol class="arabic">
<li>Module</li>
<li>Values</li>
<li>Functions</li>
</ol>
</li>
<li>Closure structure:<ol class="arabic">
<li>Function scope</li>
<li>Values</li>
<li>Closures</li>
</ol>
</li>
<li>Class structure:<ol class="arabic">
<li>Class</li>
<li>Instance</li>
<li>Values</li>
<li>Methods</li>
</ol>
</li>
</ul>
</dd>
<dt>Collaboration</dt>
<dd><ul class="first last simple">
<li>Module structure: The module contains values and functions. The functions are scoped to or passed the module, which allows them to read and mutate the variables.</li>
<li>Closure structure: The closures close over the function scope, which contains the values. This allows them to read and mutate the variables.</li>
<li>Class structure: The object is an instance of the class. The class exposes methods, which define the interface to the object's state.</li>
</ul>
</dd>
<dt>Consequences</dt>
<dd><ul class="first last simple">
<li>Module structure: All data is directly accessible.</li>
<li>Closure structure: To be accessible, data must be explicitly exposed through closures.</li>
<li>Class structure: The language can provide privacy controls.</li>
</ul>
</dd>
<dt>Implementation</dt>
<dd>The language support for these patterns varies considerably.
Some languages support all versions, and some support none, while others are in-between.
The module structure is possible to implement "by accident", and may be a candidate for refactoring into another model.</dd>
<dt>Sample Code</dt>
<dd><ul class="first simple">
<li>Module structure:</li>
</ul>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span></pre></div></td><td class="code"><div><pre><span></span><span class="sd">"""An object-shaped module."""</span>
<span class="n">_SECRET_LIST</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">def</span> <span class="nf">put_to_list</span><span class="p">(</span><span class="n">item</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""A method-shaped function."""</span>
<span class="n">_SECRET_LIST</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">pop_from_list</span><span class="p">():</span>
<span class="w"> </span><span class="sd">"""Another method-shaped function."""</span>
<span class="k">return</span> <span class="n">_SECRET_LIST</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="c1"># Use by importing the module.</span>
</pre></div></td></tr></table></div>
<ul class="simple">
<li>Closure structure:</li>
</ul>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">constructor</span><span class="p">():</span>
<span class="w"> </span><span class="sd">"""A constructor-shaped function."""</span>
<span class="n">a</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">def</span> <span class="nf">increment</span><span class="p">():</span>
<span class="w"> </span><span class="sd">"""A method-shaped function. Increment a and return its value."""</span>
<span class="k">nonlocal</span> <span class="n">a</span>
<span class="n">a</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">return</span> <span class="n">a</span>
<span class="k">return</span> <span class="n">increment</span>
<span class="c1"># Usage</span>
<span class="n">increment1</span> <span class="o">=</span> <span class="n">constructor</span><span class="p">()</span>
<span class="n">increment2</span> <span class="o">=</span> <span class="n">constructor</span><span class="p">()</span>
<span class="k">assert</span> <span class="n">increment1</span><span class="p">()</span> <span class="o">==</span> <span class="mi">1</span>
<span class="k">assert</span> <span class="n">increment1</span><span class="p">()</span> <span class="o">==</span> <span class="mi">2</span>
<span class="k">assert</span> <span class="n">increment2</span><span class="p">()</span> <span class="o">==</span> <span class="mi">1</span>
</pre></div>
<ul class="simple">
<li>Class structure:</li>
</ul>
<div class="last"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Class</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""A class."""</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">secret</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_secret</span> <span class="o">=</span> <span class="n">secret</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">secret</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""An accessor function/method."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_secret</span>
<span class="k">assert</span> <span class="n">Class</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">secret</span> <span class="o">==</span> <span class="mi">1</span>
</pre></div>
</div></dd>
<dt>Known Uses</dt>
<dd>Like... any bit of Python code, technically?
Rust does this in a statically-dispatched fashion.</dd>
<dt>Related Patterns</dt>
<dd>... All of them?</dd>
</dl>
<p>Where is the lie?</p>
<p>Anyway, point is, Homunculus's <tt class="docutils literal">main</tt> loop should be an "update" function or several, a method on some kind of "Game" object.</p>
<p>Meanwhile, the "blog.py" script is really showing its roots.
I need to divide the global variables up by problem domain, and make classes for stuff like Mercurial repositories, Pelican projects, Neocities sites, and LDoc.</p>
Music Theory 2018-04-232018-04-23T04:00:00-04:002018-04-23T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-23:/music-theory-2018-04-23<p class="first last">Approximately Rational</p>
<p>In this post:</p>
<ul class="simple">
<li>I somehow rate a bunch of rational numbers, and don't do an inspiring job of it.</li>
<li>I then pick out a xenharmonic scale to mess with, because I learned western music theory and I want a change of pace.</li>
<li>Though not so much of a change of pace that I'm not planning to try to do homophony, so...</li>
</ul>
<hr class="docutils" />
<p>Okay, let's talk about ratios of small integers.
For my initial attempt to recapitulate the history of musical intervals, I'm going to use intervals rooted at 440 Hz, below 880 Hz, and with and without 880 Hz above.
The intervals will include factors of 2 up to the third power, 3 up to the second power, 5, 7, and 11.
I'll be using pure sine waves because I'm lazy.</p>
<p>List of intervals:</p>
<ul class="simple">
<li>3:2 (660)<ul>
<li>Without 880: adds decent texture</li>
<li>With 880: good support</li>
</ul>
</li>
<li>4:3 (587)<ul>
<li>Without 880: slightly different texture</li>
<li>With 880: comes together well</li>
</ul>
</li>
<li>5:3 (733)<ul>
<li>Without 880: bright tone</li>
<li>With 880: something really good from this</li>
</ul>
</li>
<li>5:4 (550)<ul>
<li>Without 880: this just feels kind of muddy</li>
<li>With 880: kind of salvages it</li>
<li>With 660: eh</li>
<li>With 880 and 660: okay, now that comes together</li>
<li>I think exposure to 12-TET has me hearing this interval all weird</li>
</ul>
</li>
<li>7:4 (770)<ul>
<li>Without 880: harsh but interesting</li>
<li>With 880: nice</li>
</ul>
</li>
<li>6:5 (528)<ul>
<li>Without 880: harsh and interesting</li>
<li>With 880: doesn't quite gel</li>
<li>With 660: pretty cool</li>
<li>With 880 and 660: nice</li>
<li>I guess I just like minor chords better?</li>
</ul>
</li>
<li>7:5 (616)<ul>
<li>Without 880: interesting</li>
<li>With 880: doesn't gel</li>
</ul>
</li>
<li>8:5 (704)<ul>
<li>Without 880: nice and bright</li>
<li>With 880: a good collection</li>
<li>... With 528: excellent</li>
<li>With 528 and 880: also excellent</li>
<li>So, I like major chords fine... but not in root position</li>
</ul>
</li>
<li>9:5 (792)<ul>
<li>Without 880: that feels really discordant</li>
<li>With 880: this doesn't help</li>
</ul>
</li>
<li>7:6 (513)<ul>
<li>Without 880: this is one of the "harsh but interesting" combinations</li>
<li>With 880: but it doesn't work well with just these three</li>
</ul>
</li>
<li>11:6 (807)<ul>
<li>Without 880: this is one of the "harsh but interesting" combinations</li>
<li>With 880: but it doesn't work well with just these three</li>
<li>(Yes, they're that similar, aesthetically)</li>
</ul>
</li>
<li>8:7 (503)<ul>
<li>Without 880: Almost growly</li>
<li>With 880: actually works well, but it wants something more</li>
</ul>
</li>
<li>9:7 (566)<ul>
<li>Without 880: these are all kind of blurring together; this sounds almost like 6:5, which isn't bad</li>
<li>With 880: but it doesn't handle this combination well</li>
</ul>
</li>
<li>10:7 (629)<ul>
<li>Without 880: harsh, but I like it</li>
<li>With 880: I also like this one</li>
</ul>
</li>
<li>11:7 (691)<ul>
<li>Without 880: it's good</li>
<li>With 880: still good</li>
</ul>
</li>
<li>12:7 (754)<ul>
<li>Without 880: low and harsh</li>
<li>With 880: discordant</li>
</ul>
</li>
<li>9:8 (495)<ul>
<li>Without 880: I wish I could come up with better adjectives, because there are certain patterns of commonality. It's fine.</li>
<li>With 880: also fine</li>
</ul>
</li>
<li>11:8 (605)<ul>
<li>Without 880: now this is cool</li>
<li>With 880: this sounds very similar to 9:8 with 2:1</li>
</ul>
</li>
<li>10:9 (489)<ul>
<li>Without 880: It's mostly like 9:8</li>
<li>With 880: Everything must be converging, very similar effects</li>
</ul>
</li>
<li>11:9 (538)<ul>
<li>Without 880: it really is sounding quite similar at this stage</li>
<li>With 880: yeah</li>
</ul>
</li>
<li>11:10 (484)<ul>
<li>Without 880: a bit harsh</li>
<li>With 880: and it doesn't blend well</li>
</ul>
</li>
</ul>
<p>I look over my terribly-articulated subjective reactions, and I wonder what kind of scale I could build using 11:7.
It looks like that's a somewhat stretched 3:2.
Binary logarithm shows it to be quite close to 2^(13/20), so now I'm curious about 20edo.</p>
<p>Suppose I try to build a diatonic equivalent in 20edo, containing degrees 12 and 13.
Actually, maybe that's the wrong approach.
I liked the major chord in first inversion, and if you look at what would be inverted to get degree 13, you get degree 7.</p>
<p>The frequencies for 0-7-12-20 on 440 in 20edo are: 440, 561, 667, 880.
Let's try that in root position and first inversion.
I'm liking the result.
The <a class="reference external" href="http://xenharmonic.wikispaces.com/">xenharmonic wiki</a> calls this cord "downmajor".
I clearly don't grasp all the theory going into this, because it surprises me that degree 8 is both a major third and a perfect fourth.
Looks like if I want to mess with this, I want the Blackwood Major decatonic scale, which hits a few other intervals I liked.
Looks like the chords in this are: either minor and upminor, and major and downmajor.
There are two interlocking circles of fifths.</p>
<p>I'm going to pivot a little now from considering music theory, to trying to do algorithmic composition, or at least composition on the computer, now that I've decided that Blackwood Major decatonic sounds like it could be interesting.</p>
<p>I don't know if I'll accomplish anything with this in this entry; there are some problems with the uploader that I need to get worked out by Monday night.
But let's see about making composition stuff myself, since it seems really tricky to get the features that I want, together with... actually working.</p>
<p>Let's have the idea of a "scale".
I'll represent scales using a sequence of interval sizes, combined with the period (which defaults to 2).
I'm going to focus on equal temperament for now.
The wiki describes various other types of tunings, some of which I don't understand yet.</p>
<p>(In between these paragraphs, I fixed the uploader.)</p>
<p>Okay, time to make another project.
Call it... tiny_music.
Pulled a bunch of bits out of Homunculus, and the result is a decent starting point for an arbitrary Python project.
I should make a cookie-cutter for this layout sometime, because I don't like the cookie-cutters I've seen so far.</p>
<p>In fact, I'm going to focus on gettin things right for a bit, before I start writing code.
Things kind of blew up in our face at work because we weren't pinning requirements properly, and I'd rather not face that again.
So, I'll wrap up here for now, and try to get back to 20ed2 decatonic goodness next week, once I've completely-foreseeable-circumstances-proofed my code.</p>
<hr class="docutils" />
<p>Next week, very basic synthesis, common scales, blackwood scales.
I should probably also dip my toes into different synthesis techniques, because using pure sine waves like I did above is extremely limiting.</p>
Weekly Roundup 2018-04-222018-04-22T04:00:00-04:002018-04-22T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-22:/weekly-roundup-2018-04-22<p class="first last">Pardon The Dust</p>
<p>In the past week, I wrote the following posts:</p>
<ul class="simple">
<li>Music Theory Monday: Not a great start. I'm planning to retreat into number theory a bit more for next week.</li>
<li>Free-Topic Tuesday: I wrote about some fiddly details of Rust. I don't know if it edified anyone else, but <em>I</em> got stuff out of it.</li>
<li>Site Design Wednesday: I pulled styling from <a class="reference external" href="http://bettermotherfuckingwebsite.com/">Better Motherfucking Website</a>, then ignored any ideals of minimalism with some incredibly elaborate flexbox usage. I had fun with Block Element Modifier, and did not have fun with Pygments.</li>
<li>Linked Seas Thursday: I talked about the elvish empire, then resolved to write software worthy of containing my creative genius.</li>
<li>Draw a Box Friday: Nobody is more anxious than I am for me to finally draw a dang box.</li>
<li>Homunculus Saturday: My writeup of why I'm worried about touching the code is nearly half as long as the code in question.</li>
</ul>
<p>In addition, I redid my publishing flow some.
I took the pelican-generated makefile I hadn't been using, translated part of it into messy Python, added more Python to interface with undocumented-as-far-as-I-can-tell parts of the Neocities API.
The end goal is to have a nice framework for pulling in and manipulating other data, so I can use other generators in concert with pelican, and do some sanity checks before building.
I want all this by next Thursday, so I can be publishing Conworld Codex documentation here. (At some point I'll put it on GitHub and it can have documentation somewhere more obvious.)
I also looked up and did the tweaks needed to use external HTML, with processing disabled (so I can use stuff like LDoc) locally (so I can try to write articles and pages in the form of tiddlywikis, because that sounds <em>hilarious</em>).
Doing that also needs some hg ignores.
I also got tmuxinator set up, and tried to get back into neovim.
Basically, it's been a few days of mad scramble to get tooling ready for the stuff I want to do.</p>
Homunculus Devlog 2018-04-212018-04-21T04:00:00-04:002018-04-21T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-21:/homunculus-devlog-2018-04-21<p class="first last">Taking Inventory</p>
<p>In this post:</p>
<ul class="simple">
<li>I want Single Responsibility, not, like, a billion.</li>
</ul>
<hr class="docutils" />
<p>Before I mess with the code, I want to document all of the responsibilities it has.</p>
<p>The code is accessed through a console entry point.
The <tt class="docutils literal">main</tt> function:</p>
<ul class="simple">
<li>To create the game object:<ul>
<li>Reads the save file</li>
<li>Loads data if applicable</li>
<li>Skips over the error if the file does not exist</li>
<li>Creates a new game if it didn't load one</li>
</ul>
</li>
<li>To set up the game window:<ul>
<li>Loads the "arial10x10" font from the resources directory</li>
<li>Creates a console using the values specified in the constants module</li>
<li>Creates sub-consoles</li>
</ul>
</li>
<li>To play the game:<ul>
<li>Calls the <tt class="docutils literal">play_game</tt> function with the above arguments</li>
</ul>
</li>
</ul>
<p>The <tt class="docutils literal">play_game</tt> function:</p>
<ul class="simple">
<li>To set up the game loop:<ul>
<li>Sets the <tt class="docutils literal">fov_recompute</tt>, <tt class="docutils literal">mouse_coordinates</tt>, <tt class="docutils literal">previous_game_state</tt>, and <tt class="docutils literal">targeting_item variables</tt></li>
</ul>
</li>
<li>To run the game loop (buckle up, this is going to be a long ride):<ul>
<li>Conditionally recomputes the fov</li>
<li>Renders everything</li>
<li>Flushes the console</li>
<li>Clears the console</li>
<li>Sets fov_recompute to <tt class="docutils literal">False</tt></li>
<li>Iterates over the event queue until it finds an event it recognizes</li>
<li>Skips the rest of the loop if it <em>didn't</em> find an event it recognized</li>
<li>Converts the user input into an action dictionary</li>
<li>Unpacks various flags from the action dictionary</li>
<li>Creates a list of action results</li>
<li>Extends the list:<ul>
<li>If a <tt class="docutils literal">move</tt> action exists:<ul>
<li>Do map collision detection</li>
<li>If no collisions:<ul>
<li>Attempt to initiate combat</li>
<li>If targets, add the combat result to the action results</li>
<li>If no targets, move</li>
<li>Set the <tt class="docutils literal">game_state</tt> to <tt class="docutils literal">ENEMY_TURN</tt> (this is the only code in this part of the function that does this?)</li>
</ul>
</li>
</ul>
</li>
<li>Else if a pickup action exists:<ul>
<li>Iterate through the items until we find one under the player</li>
<li>Add a pickup result to the action results</li>
</ul>
</li>
<li>If a <tt class="docutils literal">show_inventory</tt> action exists, use <tt class="docutils literal">previous_game_state</tt> to temporarily enter use mode</li>
<li>If a <tt class="docutils literal">drop_inventory</tt> action exists, use <tt class="docutils literal">previous_game_state</tt> to temporarily enter drop mode</li>
<li>If the <tt class="docutils literal">inventory_index</tt> value is defined, and the player is not dead, and the index is in range, add the appropriate result to the action results</li>
<li>Handle targeting actions:<ul>
<li>Left click to attempt to use the item at the mouse coordinates; if successful, add the results to the action results</li>
<li>Right click to add a <tt class="docutils literal">targeting_cancelled</tt> result to the action results</li>
</ul>
</li>
<li>If an <tt class="docutils literal">exit</tt> action exists:<ul>
<li>In an inventory mode, switch to the previous game state</li>
<li>In targeting mode, cancel targeting as above</li>
<li>In all other cases, close the game:<ul>
<li>If the player is dead, delete the save file</li>
<li>Otherwise, save over the save file</li>
<li>Return</li>
</ul>
</li>
</ul>
</li>
<li>If a <tt class="docutils literal">fullscreen</tt> action exists, toggle fullscreen</li>
</ul>
</li>
<li>Process the action results; for each result:<ul>
<li>Extract various possible values</li>
<li>Put messages in the message log</li>
<li>Process deaths, add the death message to the message log</li>
<li>Process item pickups, switch to <tt class="docutils literal">ENEMY_TURN</tt></li>
<li>Process item uses, switch to <tt class="docutils literal">ENEMY_TURN</tt></li>
<li>Process item drops, switch to <tt class="docutils literal">ENEMY_TURN</tt></li>
<li>If targeting, use <tt class="docutils literal">previous_game_state</tt> to switch to targeting mode, add the targeting message to the message log</li>
<li>If <tt class="docutils literal">targeting_cancelled</tt>, restore the game state, and add the cancel message to the message log</li>
</ul>
</li>
<li>If it's the <tt class="docutils literal">ENEMY_TURN</tt>, iterate through all entities:<ul>
<li>If it has an AI component, take the AI's turn and get the results</li>
<li>To process the results:<ul>
<li>Extract <tt class="docutils literal">message</tt> and <tt class="docutils literal">dead_entity</tt> variables</li>
<li>Put messages in the message log</li>
<li>Process dead entities:<ul>
<li>If it's the player, put the message from the <tt class="docutils literal">kill_player</tt> function in the message log, and set the game state to <tt class="docutils literal">PLAYER_DEAD</tt></li>
<li>Otherwise, put the message from the <tt class="docutils literal">kill_monster</tt> function in the message log</li>
<li>Break out of the inner two loops if the player is dead</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>If the player is not dead, set the game state to <tt class="docutils literal">PLAYERS_TURN</tt></li>
</ul>
</li>
</ul>
<p>The way I want to cope with this is to turn the collection of variables that represent the game state into a cohesive object, and have the game loop coordinate between different methods:</p>
<ul class="simple">
<li>conditional_fov_recompute</li>
<li>(process any render events from the previous iteration)</li>
<li>render</li>
<li>pipeline:<ul>
<li>on the player's turn:<ul>
<li>input events to actions</li>
<li>actions to actions results</li>
<li>action results to messages</li>
</ul>
</li>
<li>on the enemy turn:<ul>
<li>action results to messages</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Ideally later, the details of rendering get pulled out into another function, and the event loop then pipelines messages into abstract render events, then yields render events to a concrete render process. So at a high level, the loop would go: apply render events, render with the renderer, populate render events from the game logic.</p>
<hr class="docutils" />
<p>Next week, I try to execute on the above plan.
Also, I should look at the rest of the code, but the main() function is distractingly huge.</p>
Draw a Box 2018-04-202018-04-20T04:00:00-04:002018-04-20T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-20:/draw-a-box-2018-04-20<p class="first last">These exercises are a drag</p>
<p>In this post:</p>
<ul class="simple">
<li>I'm SO BORED.</li>
</ul>
<hr class="docutils" />
<p>I got to the homework, which is really trying my patience so far.
I'm going to have to put this series on hold until I make actual progress here, because I don't want to skip ahead, but also, this is a lot of lines.</p>
<hr class="docutils" />
<p>Next week, there probably won't be an entry.</p>
Linked Seas 2018-04-192018-04-19T04:00:00-04:002018-04-19T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-19:/linked-seas-2018-04-19<p class="first last">I'm lucky it's sort of possible to write stories with this.</p>
<p>In this post:</p>
<ul class="simple">
<li>I turned my focus outward from Kena'o instead.</li>
<li>Discussed some of the other races. (Which is the right word. They're all, like, equally human.)</li>
<li>Then, I re-realized that I really shouldn't be writing up my worldbuilding as just a flat text file.</li>
</ul>
<hr class="docutils" />
<p>I ended up focusing on the nitty-gritty of faster-than-light travel to start with.
The main change I made was, there's no longer the idea of the "first travel".
Instead, all planets are accessible if they're in range in phase space, but travel between known locations takes so many hops, and the routes change so often, that there's no motivation to investigate or settle most worlds.</p>
<p>This implies that the empire that's going to conquer Kena'o relies heavily on indigenous labor, which makes sense.
The fact that they don't look implies that intelligent life is sort of rare.
Also, this implies to me that contact gets made when a scout follows a "ghost ship", not from just randomly stumbling across a settlement.</p>
<p>Anyway, let's get back to Kena'o.
Okay, I wrote up to the discovery of the empire.
Just kind of introduced two more planets into this, rather than pin down more details about Kena'o.
Alalusindralaska is the capital world of the elvish empire, and they have colonies on the orc world, Korochgraklos.</p>
<p>We can see here that I have basically zero shame about using stereotypical linguistic features.
I'm thinking, Alalusindralaska is not the original world the elves came from.
It's no single-climate world, but it does have lots of deciduous forests.
Korochgraklos has a very harsh sun.
Most latitudes are settled, but the elvish empire only got a foothold in the tropics.</p>
<p>I should try to hammer out my ideas about the elves.
Now, I haven't really thought about setting backstory, but I'd say, if this setting has some kind of interested creator, that creator's "chosen people" would be the now-dead empire that's responsible for all these (spoiler) interfertile humanoids on completely different planets.
Regardless, from such a creator's perspective, all these humanoids doing things, including the elves, is kind of an accident.
Something irrelevant to their plans.
But I'd rather mess with civilizations and lower-level, than try to write stories about cosmic bullshit.
So, elves.
They're sort of inspired by the disgusted reaction my wife had to my understanding of how half-elves work in Tolkien.
Basically, that half-elves end up having to choose one or the other, and they become fully what they choose.
So, that implies to me that the difference is not biological, to the extent that that's a thing it makes sense to consider in this context.
So, what I had in mind for these elves was, they were normal humanoids that wandered into the forest for whatever reason, and their bodies came back with some kind of forest spirit within them.
Half-elves then get born with two warring spirits within them, and one must consume the other.
I don't have a great handle on what practical effect the different spirits have.
Probably something to do with magical ability, longevity, and some kind of feeling of power.
Like, the elvish spirit makes them feel like they can ignore "human limitations" and "human decency".
Perhaps the most definite effect on their psyche is just feeling "beyond human".</p>
<p>To accompany this, I think there should be a culture somewhere that can kind of swap spirits at will, for martial or religious purposes.
They would have different spirits to work with.</p>
<p>Okay, I think I haven't fully worked out what I want some of the details here to be like, and I should probably step away from this and let it percolate.
The big thing I want to make sure I'm not botching is the relationship between the effects of the elvish spirit, and the colonial imperialist structure.
Fundamentally, the elvish spirit is a tool that affords empire-building.
The point is not that they're evil because of the different spirit, but that the elvish spirit is kind of a force multiplier for oppression.</p>
<p>I imagine I'll want to come up with a resolution to the whole empire thing, and probably the way I want to address it is that the elves aren't willing to give up the spirit unless they can be convinced to face life without it.
It seems likely that there will be some proportion of holdouts that, at first, would rather go to war, so that might end up being kind of a fixture.</p>
<p>It should by now be obvious that my intent here wasn't escapism.
Escapism is valuable, but also, I am really tired of the state of the world today, and apologism for the history of the United States, and this whole thing is probably pretty obviously inspired by that.</p>
<p>What I need now is to work out how to organize all of the data.
I want some kind of flowchart structure, I think.
Like, I want to focus on events (I really should get the One Man Institute posted sometime), linking contributing factors and effects, different levels of abstraction, labeling with space and time information...
And I want to be able to be vague about it where I'm not sure.
At some point, I'm basically describing a database of events that relate to each other via arbitrary binary predicates, and have associated attribute-value tags.</p>
<p>Might as well try building such a thing.
My gut feeling is to try building it in Lua.
Watch this space, I'm going to pivot.</p>
<hr class="docutils" />
<p>Next week, I try to write a setting database in Lua.</p>
Site Design 2018-04-182018-04-18T04:00:00-04:002018-04-18T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-18:/site-design-2018-04-18<p class="first last">Let us improve the website, good sir.</p>
<p>In this post:</p>
<ul class="simple">
<li>I really really like Block Element Modifier, it turns out.</li>
<li>Not as much of a fan of Pelican's "simple" theme, or Pygments.</li>
</ul>
<hr class="docutils" />
<p>I grabbed most of the CSS rules off of <a class="reference external" href="http://bettermotherfuckingwebsite.com/">Better Motherfucking Website</a>, and that made things look a little nicer.
However, the overall navigability suffers from the fact that this is still basically just the "simple" theme.
I'm going to step away from the CSS for a bit and see about making the page templates nicer.</p>
<p>Right now, though, I'm stuck on the mystery of why my custom theme isn't rendering categories in the top nav list.
Oh.
Well, those conditionals are very wrong.
And it's not quite my fault.
That's just how the simple theme is, for... some reason.</p>
<p>Okay, next change: instead of listing all categories, link to the category listing.
This should help mitigate one of the things visible on the website as of this writing, which is that the category listing has overflowed in less than three weeks of posting.</p>
<p>Okay, I did that, and added some styling and such.
One thing I kind of want to do is to make the categories link be right-justified, once the list is horizontal.
Another thing I want to do is convert as much of this as possible to <abbr title="Block Element Modifier">BEM</abbr>.
So, I'll do that now.</p>
<p>While I was in there, I figured out how to embed the text of a page into every rendered page.
This should come in handy for some hacks I have in mind, but for now, it means I get to have the hosting link everywhere, and free up a space in the header.</p>
<p>One thing I'm not a fan of is how much trouble I'm having, figuring out how to customize the Pygments output.
It's like, this is the only syntax highlighter I can use (please yell at me on Masto if that is not actually true), and there's no obvious way for me to customize it for, like, BEM stuff.</p>
<p>This was all fun, but I really should get around to:</p>
<ul class="simple">
<li>Adding in all the information I wanted to show.</li>
<li>Working out the in-category navigation system.</li>
<li>Figuring out what else it would take for me to feel like the new theme is "ready" for my initial use.</li>
</ul>
<hr class="docutils" />
<p>Next week, I should mess with the article rendering.
There are a few other areas I want to hit, but that's the obvious one.</p>
Defining Types In Rust2018-04-17T04:00:00-04:002018-04-17T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-17:/defining-types-in-rust<p class="first last">I need a better idea of how to do it.</p>
<p>In this post:</p>
<ul class="simple">
<li>I muck around a bit in some of the confusing corners of Rust's type system.</li>
</ul>
<hr class="docutils" />
<p>I recently read a <a class="reference external" href="https://www.ralfj.de/blog/2018/01/31/sharing-for-a-lifetime.html">blog post about types and sharing in Rust</a>, which made the point that:</p>
<blockquote>
every type gets to pick for itself what it means to share this type</blockquote>
<p>The rest of that section goes over how this works out a high level (some types need very particular behavior, some can just delegate to their contained types).
This made me realize that I hadn't really been aware of all of this before.
Whatever the types I defined were doing to "pick [...] what it mean[t] to share" them, I had been unaware I was making those decisions.
This is bad, and I should do something about it.</p>
<p>Okay, I took the <abbr title="from Late Latin radicalis ("of or pertaining to the root, having roots, radical")">radical</abbr> step of reading the dang documentation, and I'm starting to get a better handle on things.
One thing that confused me for a while was lifetime constraints, but I think I've figured out how to make my intuition go.
Here's a snippet of code that compiled using the <a class="reference external" href="https://play.rust-lang.org/">Rust Playground</a>:</p>
<div class="highlight"><pre><span></span><span class="k">fn</span> <span class="nf">longest</span><span class="o"><'</span><span class="na">a</span>: <span class="o">'</span><span class="na">c</span><span class="p">,</span><span class="w"> </span><span class="o">'</span><span class="na">b</span>: <span class="o">'</span><span class="na">c</span><span class="p">,</span><span class="w"> </span><span class="o">'</span><span class="na">c</span><span class="o">></span><span class="p">(</span><span class="n">x</span>: <span class="kp">&</span><span class="o">'</span><span class="na">a</span> <span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">y</span>: <span class="kp">&</span><span class="o">'</span><span class="na">b</span> <span class="kt">str</span><span class="p">)</span><span class="w"> </span>-> <span class="kp">&</span><span class="o">'</span><span class="na">c</span> <span class="kt">str</span> <span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">x</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">y</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">x</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">y</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>Most explanations I read about constraining lifetimes talked about variance, which is technically correct, but didn't land with me in this context.
We can see from this sample that, if you constrain one lifetime by another, it must be possible to "cast" the constrained lifetime to the constraining lifetime.
In other words, the constraining lifetime must be a subset of the constrained lifetime.</p>
<p>Now, because types can contain lifetimes, constraining a type with a lifetime has the same semantics: the type is valid over the entire scope of the lifetime.
In other words, it is valid to construct a reference to the type, that has the lifetime.
These statements are (I <em>think</em>) completely equivalent.</p>
<p>In practice, the above gymnastics aren't necessary to defining the lifetimes for that function, because (I <em>think</em>) the variance is already factored in if you constrain everything to the same lifetime.
Putting in the explicit-looking things there just adds some irrelevant degrees of freedom.</p>
<p>Oh, wait, borrowing and sharing are distinct but related concepts.
I don't know about anyone else, but I'm pretty sure I just learned a valuable lesson about something or other.
Point is, <em>if</em> I'm understanding this right, much of this is about sharing data between threads; much of what I've hit messing with generics in Rust has (mercifully) not hit Send/Sync, and instead I've had to worry about whether it makes sense to relax the Sized bound.
I might have a better handle on that from writing this post? We'll have to see.</p>
Music Theory 2018-04-162018-04-16T04:00:00-04:002018-04-16T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-16:/music-theory-2018-04-16<p class="first last">Starting from basics.</p>
<p>In this post:</p>
<ul class="simple">
<li>Psychoacoustics is complicated, so let's gloss over it.</li>
<li>Tuning systems.</li>
<li>Basics of scales.</li>
</ul>
<hr class="docutils" />
<p>Okay, this is a little rough...
I got a lot of post written, before I realized I wasn't sure where I was going with all this.
I guess what I want to figure out, in terms of music theory, is how to use symmetries in a musical structure, to simplify composition on a computer.
Like, when I learned music theory, one thing we went over was repeated phrasal structure.
But every composition software I've used has me entering in every note; I can't tell it "use a common section here, and I'll fill in the last measure or so, so they have different cadences".</p>
<p>Music is normally understood to consist of some sounds, each of which has a recognizable pitch, spaced out according to a rhythm.
I mean, it's a spectrum.
But anyway.</p>
<p>A lot of music theory derives from the relationships between tones.
Which relationships are important?
Well, it's possible to get bogged down in too much detail, which a previous version of this post did.
How tricky can it all be?
Well...</p>
<p>The details of how hearing works are very elaborate.
In the nineteenth century, Ohm and Helmholtz believed that human the human ear separated sounds into component frequencies of sine waves.
This is part of the story.
The ear, in addition to separating out frequencies, can selectively alter its sensitivity to frequencies.
Furthermore, the brain processes related frequencies together, which can create the perception of tones that a simple spectral breakdown doesn't contain.
And our ability to distinguish small differences in frequency is greater for overlaid tones, in contrast to consecutive tones.</p>
<p>So, psychoacoustics is complicated.
All the same, we can identify musical notes with a <strong>fundamental frequency</strong>, and consider the relationships between notes in terms of the relationships between the sine waves.</p>
<p>There are several philosophies of choosing relationships between frequencies:</p>
<ul class="simple">
<li>Pythagorean tuning is focused on constructing notes using the ratios of 2:1 and 3:2. This causes most other intervals to sound dissonant.</li>
<li>Just intonation uses more prime factors overall. This allows more intervals to sound consonant, by kind of spreading out the dissonance.</li>
<li>Equal temperament spreads it out the most, by using algebraic ratios rather than rational ratios.</li>
</ul>
<p>Equal temperament has gotten more popular over time.
Ultimately, consonance of a ratio comes from how close it is to a small integer ratio.</p>
<p>The choice of instrumentation can constrain the choice of tuning, and because the ear is more sensitive to dissonance in overlaid tones, the musical texture of a piece can influence which choice of tuning is acceptable.
A piece of music can have different textures at different times.
Because it's possible for the tuning to change in different parts of a piece (unaccompanied vocals vs vocals plus piano), a scale should ideally fit into multiple systems of tuning.</p>
<ul class="simple">
<li>Monophonic music has just a melodic line, with no independent or harmonic movement.</li>
<li>Biphonic music only has to consider the ratio between the melody and a fixed tone.</li>
<li>Polyphonic music has multiple independent melodies.</li>
<li>Homophonic music has a single melody accompanied by chords.</li>
</ul>
<p>Anyone who's learned music has had to deal with musical scales.
These are usually presented as a collection of notes to play in sequence, but the reason why those frequencies are chosen, and not some other, lies in what happens when some of those notes are picked out, and played together.</p>
<p>Integer ratios between frequencies sort of fade into the lowest frequency, because the sounds made by a musical instrument are a linear combination of integer multiples of the note's fundamental frequency.
Therefore, instead of sounding like "another pitch", adding in a 2:1 ratio alters the character of a note, but not its perceived pitch.
With this in mind, 2:1 is the simplest ratio at which to "loop" a tuning system, and 3:2 is the simplest ratio to produce distinct but harmonious sounds.
This is why most chords are based on a ratio that contains exactly one factor of three, opposite some power of two.</p>
<p>In any case, when building a scale "above" some pitch, you want to fill out the pitches to twice that pitch.
You want to include the 3:2 ratio.</p>
<p>Simple ratios below 3:2 include:</p>
<ul class="simple">
<li>4:3</li>
<li>5:4</li>
<li>6:5</li>
<li>7:5</li>
</ul>
<p>One interesting thing about some of these ratios is that 5:4 times 6:5 equals 3:2; they fit together into the simpler ratio.
Combining them with the 3:2 ratio gives the smaller ratio the "support" of the simpler one.
The results of this are known as the "major" and "minor" chords.</p>
<p>A fixed scale extends the 3:2 ratio, or an approximation, around the scale, except for one note, which has its note 3:2 above "outside" the scale.
Within a given (approximate) 3:2 ratio, the note above the bottom is either (approximately) 6:5 up, or 5:4 up.</p>
<p>The most common scale in western music, the major scale, has 3:2 intervals (called fifths, because they are four notes above; thus, a fifth is two thirds <a class="footnote-reference" href="#footnote-1" id="footnote-reference-1">[1]</a>) above six of the notes, but not the seventh note in the scale.</p>
<p>One thing that I feel like should be more obvious to me how to do, is electronic composition outside of 12-TET.
I'd like to see something with an easier interface to, like, 31-TET, or using arbitrary rational numbers untethered from octaves.</p>
<p>I'll be honest, I look over this and I'm not really sure where I'm going with all of this.
I kind of want to take the different styles of composition, and the different ways of designing a scale, and have some formalism for converting that into a specific set of principles for composition using a set of related scales.</p>
<hr class="docutils" />
<p>Next week, I think I'll probably noodle around with rational numbers and powers of primes.</p>
<table class="docutils footnote" frame="void" id="footnote-1" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-1">[1]</a></td><td>You can mark that square off on your "STEM guy is smug about music theory" bingo card now.</td></tr>
</tbody>
</table>
Weekly Roundup 2018-04-152018-04-15T04:00:00-04:002018-04-15T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-15:/weekly-roundup-2018-04-15<p class="first last">Cool. Now Do It Again.</p>
<p>In the past week, I wrote the following posts:</p>
<ul class="simple">
<li>Music Theory Monday: I didn't, because I wanted these roundup posts to be on Sunday, and I worked out the schedule last Monday. I'll get to it tomorrow, though.</li>
<li>Free-Topic Tuesday: I wrote about... this. I think next week I'm going to try to talk my way through some Rust stuff.</li>
<li>Site Design Wednesday: I discarded a bunch of those sketches I made. For next week, I found <a class="reference external" href="http://bettermotherfuckingwebsite.com/">a site</a> that I should probably crib CSS from.</li>
<li>Linked Seas Thursday: I babbled a bunch about the geography of a made-up planet, except that I was focused a lot more on the political boundaries, which changed over the course of the stuff I've written up, so it was all really vague, sorry. Not sure how to do better, but I refuse to stop.</li>
<li>Draw a Box Friday: I should have taken connect-the-dots books more seriously.</li>
<li>Homunculus Saturday: The first 30% of coverage probably took just a few percent of the overall effort, if that.</li>
</ul>
Homunculus Devlog 2018-04-142018-04-14T04:00:00-04:002018-04-14T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-14:/homunculus-devlog-2018-04-14<p class="first last">This code has no tests whatsoever. That's scary.</p>
<p>In this post:</p>
<ul class="simple">
<li>I explain a little bit of what "homunculus" is.</li>
<li>I throw shade at the tutorial it's based on.</li>
<li>It turns out I broke installation, but it was a simple fix.</li>
<li>Getting to 30% coverage was not such a big deal. Even 10% more looks like an adventure.</li>
</ul>
<hr class="docutils" />
<p>I'm trying to develop a game, actually finish a project.
While a roguelike may not be, like, the <em>best</em> genre for "I'm going finally ship a game", I think it's going well so far, sort of.</p>
<p>The <a class="reference external" href="https://github.com/TStand90/roguelike_tutorial_revised_tdl">tutorial</a> (GitHub link because the main site has been coughing up gateway errors for a while now) I'm using is, I think, better about code style than the version it's updated from, but it's still not up to my usual standards in some respects.
The key issue is the lack of tests.
No tests, no protection against bugs.
Which is <strong>pretty fucking wild</strong> for a tutorial series that has you hand-applying diffs.
I have architectural and stylistic niggles, but I'd rather actually execute what I have in mind, than pontificate about it.
Which needs tests, so I don't break everything.</p>
<p>Let's get tests set up.
Well, I don't remember exactly what I have, so let's start with just invoking the test runner.</p>
<p>Huh.</p>
<p>The MANIFEST.in was all kinds of messed up.</p>
<p>I guess that's what happens if you only ever run in editable mode.
Anyway, it ran, and everything is on fire.
Step one is to add a test.
I usually have a "test that it's actually importable" test.
To my mind, having broken imports should blow up when you run the tests, not when you're doing test discovery.
So there should be no top-level imports from the module under test, in the test code.
Anyway, it's at 1% coverage currently.
Let's see, what are quick hits...
The constants file looks like a good bet.
With that, and some other low-hanging fruit, I'm at 5% coverage.
I think at this point, I should just add an import test for every module and see what I can soak up like that.
And when I do that, it gets up to 29%.</p>
<p>Okay, I pushed through some slightly less low-hanging fruit, and got to 31%.
There's some other stuff that I could write tests for, but the big annoying bit of this is the "main" module, which accounts for fully one fourth of the missing coverage.</p>
<p>I can render code testable by isolating the tdl calls, and isolating everything else into its own function.
For now, though, I'm just going to finish up this blog post.</p>
<hr class="docutils" />
<p>Next week, I'm going to focus on lowering the cyclomatic complexity of the game loop.
I usually think focusing on cyclomatic complexity is kind of silly, but this monstrosity has to go down.</p>
Draw a Box 2018-04-132018-04-13T04:00:00-04:002018-04-13T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-13:/draw-a-box-2018-04-13<p class="first last">I haven't gotten as far as drawing a box yet.</p>
<p>In this post:</p>
<ul class="simple">
<li>A summary of the value of the Draw a Box lessons.</li>
<li>An Earth-shattering revelation.</li>
<li>Musings on the art supplies I have destroyed with my untrained hands.</li>
</ul>
<hr class="docutils" />
<p>When I was thinking about the <em>idea</em> of following online art tutorials, I assumed I'd be able to basically breeze through them.
On the briefest possible reflection, I have no idea why I thought that.</p>
<p>I haven't looked at the overall trajectory of Draw a Box.
Instead, I've just been focused on the first lesson.
The first part of the first lesson.
The first parts of the first part of the first lesson.</p>
<p>Drawing is <em>hard</em>.</p>
<p>What I've covered so far is techniques around drawing lines.
Mostly straight lines, but there's some stuff about curves so far.
The main thing I learned so far is, my mental model for "draw a line" was all wrong.</p>
<p>I assumed, at such a deep level that I couldn't really examine the assumption, that, well, if you draw a straight line, clearly you had to move the pen straight, so if you just send the pen out straight, then you have a straight line and you're done.
For purposes of putting together an overall shape or composition, this is wrong, possibly entirely so.</p>
<p>These early lessons focus on training to draw a line with specified endpoints.
Once I thought about this, the utility was obvious.
Instead of trying to get every error and deviation to match up, just outline things by end-point, and...</p>
<p>and...</p>
<p>AND...</p>
<p>Connect the dots.
Oh my god.</p>
<p>Anyway, these exercises are for a felt-tip pen, which I'm willing to go along with, but I have messed up two pens already I think.
I've accumulated a surprising bunch of art supplies, some of which I'm not planning to replace.
I probably need a new Sakura Micron 01.
For future exercises, I'm going to try out the 05.</p>
<p>Once I get past these exercises, I feel like I'd rather use ball-point pens; these felt-tip ones feel really unforgiving right now.</p>
<p>(By the way, I <em>could</em> scan in the exercises I've done, but they aren't... like... interesting, I think.)</p>
<p>In any case, I've since gone through the rest of part 1. (Of lesson 1.)</p>
<hr class="docutils" />
<p>I should do the "homework" assignment at the end of part 1, though I'm not currently planning to ask for feedback. After that, I'll try to get onto part 2.</p>
Linked Seas 2018-04-122018-04-12T04:00:00-04:002018-04-12T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-12:/linked-seas-2018-04-12<p class="first last">Trying to figure out what this planet even looks like</p>
<p>In this post:</p>
<ul class="simple">
<li>A bunch of names of countries.</li>
<li>Not much context overall.</li>
<li>Some thoughts about what Kena'o looks like.</li>
</ul>
<hr class="docutils" />
<p>Currently, I'm focusing on a single planet in this setting.
I don't know if it'll be significant, but I wanted an outside perspective on the empire that controls most of the setting.</p>
<p>The planet is called, in one of its languages, Kena'o.
I've sketched out parts of its history related to the development of FTL travel.
I'm not certain, but I'm thinking that it has multiple large land-masses close to the equator, and only one large land-mass outside of that band.</p>
<p>Of note, when I was sketching this stuff out, I tried to make the names as the fictional character speaking would render them.
I didn't always work out the exact change.
So, for example, "Grusil" is probably "correct" as a romanization, but "Afepes" is filtered through the speech of Gaewon, and I didn't actually figure out what it was before being changed.</p>
<p>The northernmost island is Gaewon.</p>
<p>Just to the south-west of Gaewon is a continent that has several regions separated by mountain ranges.
Immediately opposite Gaewon is a coastline that at one point belongs to a country called Bilus.
Elsewhere on the continent is a country called Sereloi, which has an excellent climate for growing some kind of easily-juiceable fruit, and raising animals that somehow produce a honey-like substance.
Somewhere on the continent, moveable type was applied to the reproduction of sacred texts.</p>
<p>Somewhere, there is a country called Spesena, and to its north, one called Grusil.</p>
<p>There is a continent that has several nations on it, including one called the Empire of the Moon and Sun.
To the south of the Empire is the Pamara River, northern border of a city-state called Grevitch.
Further south, among more city-states, one city-state controls the access to a salt lake known as the Desan Sea.
To the west of the Empire is a region called Sola Valley.</p>
<p>Somewhere, there is a desert.
Within the desert is a river.
At the mouth of the river, there is/was a nation called Afepes.</p>
<p>Somewhere, there is a city called Mesato Momo, which at one point has a population far higher than it can support.</p>
<p>Somewhere close to the equator is a kingdom called Beleruebo, which borders/contains a jungle of incredible biological diversity.</p>
<p>There are polar ice caps.
Nobody lives there.</p>
<p>I think I want to consolidate this by putting Grusil and Spesena on the north-west part of the continent that has Bilus and Sereloi.
Mesato Momo is on the eastern coast of the Empire.
I don't want Beleruebo to be on that continent.
However, it needs neighboring nations, as does the Empire.</p>
<p>I think I want Beleruebo to be in the eastern arm of a U or V shaped continent.
I envision it as being somewhere to the east of the Bilus-Sereloi continent.
Let's put Afepes wherever it would fit on that continent.</p>
<p>My basic intent is to have approximately the land area of Earth in a bunch of spread-out tropical continents.
Kena'o is probably bigger than Earth.</p>
<hr class="docutils" />
<p>Next week, I want to finish the history sketches leading to FTL, and figure out more about the three continents I have so far.</p>
Site Design 2018-04-112018-04-11T04:00:00-04:002018-04-11T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-11:/site-design-2018-04-11<p class="first last">Simplify, Simplify. No, I Mean REALLY—</p>
<p>In this post:</p>
<ul class="simple">
<li>My current scaled-back goals</li>
<li>Some future goals, explicitly out of scope for the first version of the theme</li>
</ul>
<hr class="docutils" />
<p>I've been looking into web design principles and practice, and I've come to a conclusion regarding my initial design.
I need to scale <em>way back</em> in terms of how fancy the styling is.</p>
<p>Where I'm at right now is:</p>
<ul class="simple">
<li>two-column design with a header and footer</li>
<li>first column is the post, second column is the metadata and various navigation elements that must go <em>somewhere</em></li>
<li>everything is just at some position and size; nothing fancy in the way of auto-adjusting <em>stuff</em> to start with</li>
</ul>
<p>Things to consider adding later:</p>
<ul class="simple">
<li>translation fanciness; I have some ideas that sound weird to me, but would allow for consistent handling of...</li>
<li>custom content for tag, category, and author pages; Pelican doesn't obviously support this, but the non-obvious ways aren't <em>that</em> non-obvious</li>
</ul>
<hr class="docutils" />
<p>The big thing I want for next week is to try out the two-column layout and see how it feels.</p>
Thoughts On Ramping Up2018-04-10T04:00:00-04:002018-04-10T04:00:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-10:/thoughts-on-ramping-up<p class="first last">I Hope It Works Out</p>
<p>This post isn't terribly focused, but the whole point is that it doesn't have to be.</p>
<hr class="docutils" />
<p>I decided to stick the "talk about anything" day immediately after the day I drew up my weekly schedule.
That was nice of me.</p>
<p>I'd actually started writing up another entry, but then I wasn't sure if I should be posting it, so I'm starting over.
The luxury of trying to have a buffer, I guess.</p>
<p>I called this "whatever is on my mind".
I guess what's on my mind is wondering right now if the schedule I set myself is too ambitious.
The whole idea is to keep up the daily flow of content, in a somewhat structured fashion, but I'm actually not sure if I budgeted everything right, timewise.</p>
<p>One thing I realized about the Linked Seas idea is that I'm <em>probably</em> going to want to be bringing in other authors once things ramp up.
I'll probably talk about why once I explain more what Linked Seas is like.</p>
<p>I just looked into Draw a Box.
When I wasn't thinking hard about it, I assumed I'd be speeding through it.
That is probably not going to be the case.
Might end up closer to one lesson a week.</p>
<p>Looking over the topics, yeah, I also want to get back to Homunculus.
I've been away from that for a while, and the initial push is going to be for stuff that's not exactly exciting.
Which maybe is valuable!
Procedural generation is really exciting and all, but it works out best with a strong foundation.</p>
<p>I'm going to try to work on two entries at a time to start with.
Once I've ramped up properly, I should hopefully be able to switch between seven at once and make good time.
This is "proved" by induction, so maybe it won't quite hold up.
We'll see.
"Write seven blog posts at once" is not my worst idea this year, is all I'm saying.</p>
<p>(Speaking of worse ideas I had this year, maybe I want to try getting back into vim.
We'll see.)</p>
Possible Topics2018-04-09T12:04:00-04:002018-04-09T12:04:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-09:/possible-topics<p class="first last">Going to go for a weekly rotation</p>
<p>Another workday, another agonizing fifteen minutes waiting for an overstuffed train, instead of the train I wanted to get on.
I've got to start getting ready quicker.</p>
<p>Anyway, here are some things I could discuss on this blog.</p>
<ul class="simple">
<li>Music theory, trying to start from the very basics.</li>
<li>Whatever is on my mind</li>
<li>The custom blog theme, coming Real Soon Now™</li>
<li>Linked seas conworlding</li>
<li>Drawing</li>
<li>Homunculus devlog</li>
<li>Weekly roundup, covering not just the past week of posts, but also everything else that's been up with my life.</li>
</ul>
<p>For each post, I'll open with a summary of what's in it, and close with what I want to try to cover in the next one.</p>
I Need A Schedule2018-04-09T02:18:00-04:002018-04-09T02:18:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-09:/i-need-a-schedule<p class="first last">See Title</p>
<p>I'm running myself slightly ragged trying to come up with a post each day with no preparation. I'm going to spend Monday trying to put together a plan of action.</p>
<p>For now, I'm really sleepy.</p>
Linked Seas Concept2018-04-08T02:21:00-04:002018-04-08T03:31:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-08:/linked-seas-concept<p class="first last">Inspired By Star Trek, But There Are No Space Ships</p>
<p>One of the cool things about science fiction and fantasy is the concept of entirely separate planets/worlds coming in contact with each other.
One of the problems with how this is usually done in science fiction is that the military applications of faster-than-light travel have to be circumscribed or ignored, because you can't tell a story if all of your characters are dead.
(Although, multiple obliterated civilizations suddenly finding out that ghosts are real does sound like an interesting hook.)
Basically, if you have something that can move very far, very quickly, in and out of gravity wells, with pinpoint accuracy (which is what many faster-than-light spaceships work out to be), then you have some very, very potent ballistic weapons.</p>
<p>Since the ships in e.g. Star Trek are somewhat notorious for acting mostly like naval ships, I thought, why not take the whole going-to-other-worlds thing to the age of sail?
Basically, there's some way to "link" regions of space in the "start" and "destination" universe, and smoothly exchange them.
This mostly avoids the weaponizable aspects of faster-than-light travel.
The paradoxical aspects can be avoided by assuming that the "linking" is mediated by an underlying privileged reference frame.
It's a bad idea to explain this to the reader, because all they really need to know is "time potentially passes at different relative rates on different planets, and those rates might change, but time travel in the sense of future events 'causing' past ones doesn't happen".
To keep with the flavor, I assume the "linking" is easiest aboard a ship.</p>
<p>So far, I've started sketching out the history of a single planet, focusing on the events that lead to the development of the "linking" technology.
I'll probably post it here once I've actually reached the first successful "link", devised a world map, sketched out some conlangs, and gone over the names.</p>
<p>The big thing that remains for me to work out is, why does this world, Kena'o, have to develop the "linking" technology itself?
The aftermath of the linking is colonization, so it's not that everyone else is "nice" or whatever.
I think there must be some kind of "beacon" that makes it easier to travel to a world, and is a real pain to try to influence other worlds to make.
Technically possible, may have happened, but just, a huge hassle.
Anyway, the first "link" between two worlds can then "score" the reference frame, making further travel easier.
It is somewhat easier to influence other worlds to travel outward; I designed the technology as a bringing-together of several distinct concepts that would develop separately, and then have a synergy be noticeable.</p>
<p>I've got some vague ideas for where I want this all to go.
I should probably start putting them down in earnest once I finish having fun building this one world.</p>
<p>I think the last missing piece for me in all of this consideration is the nature of "magic".
One of the components of "linking" is some form of mental discipline that allows for remote influence.
I want it to be something that got discovered, not something that's entirely within the grasp of an unintelligent being, so I think it must be some form of alien intelligence within the privileged reference frame.
Something with understanding, but not volition.
It can't be given lasting commands, generally, so magical strength is measured in terms of the ability to do more at once, or to keep a spell going longer.
Basically, there's no such thing as an "enchantment" that can be "broken".
If there's a persistent effect from magic, then either it's the mundane consequence of an already-completed spell, or there's someone you can punch to stop it.
Ooh, thinking about sleep cycles and stuff kind of makes me want to have dolphin magi.
Anything that breathes manually <em>while sleeping</em> could presumably maintain a spell indefinitely.</p>
<p>And with that, I'm done with today's blog entry.</p>
Room Escape Thoughts2018-04-07T03:11:00-04:002018-04-07T03:42:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-07:/room-escape-thoughts<p class="first last">What If I Made A Game</p>
<p>Recently, I've been replaying some room escape games from back in high school, and I kind of want to make my own now.
Since I never seem to end up wanting to do things quite like other people have done successfully in the past, I'm looking at something that's almost entirely flash-based and graphical, and thinking "What if I did a pure-text game in Ink?"</p>
<p>What I've got so far, conceptually, is that the player starts out in a log cabin; I don't know if I want it to be single-room, or a little more elaborate.
As is the way of such things, there turns out to be some kind of elaborate underground complex below it.</p>
<p>It occurs to me that putting this through the default Ink web player would run the risk of things seriously lagging out.
It's going to need some aggressive pruning of the narration to avoid things getting out of hand, but I don't have a good sense of how aggressive.</p>
<p>Anyway, this whole binge has mostly been Submachine thus far, so that's what I'm thinking of in terms of setting.
It just occurred to me that I've played up through 9, started on 10, and I don't have a super-great handle on what the Submachine, like, is.
Regardless, I don't want to just recapitulate the Submachine games, so I need a point of distinction.
One thing I've wanted more of in games is some form of rigorous and interesting alchemy-ish crafting system.
I ought to get back to Hadean Lands.
Maybe instead of something like Hadean Lands's time loop thing, there could be repeatable activities for harvesting alchemy components?</p>
<p>I feel like the overall structure I'd want for such a thing would be to have a series of puzzles in the cabin that introduce the alchemy concepts from the end first, working backwards.</p>
<p>I probably need some other angle on this concept, to complement things, but I'm not going to come up with it right now; I'm super sleepy.</p>
Shine Whave Logo2018-04-05T12:04:00-04:002018-04-06T02:44:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-05:/shine-whave-logo<p class="first last">I have no training in graphic design</p>
<p>Today I had the idea to come up with the names of things that would have a logo, then design that logo.
This post is dedicated in part to the like ten minutes earlier today that I spent convinced that "whaver" was a word that was just not in the dictionary when I went to look.</p>
<div class="section" id="shinewhave">
<h2>ShineWhave</h2>
<p>I'm not fully sure how I want this to look, also I don't know that it's not already real.
But anyway, the inspiration was thinking about representing English words in katakana, and I thought of "sine".</p>
<p>"Sine" is an interesting word to think about in that context, because it's like a false friend for transcription.
It looks like it could be 「シネ」, but that happens to sound like an unrelated word, and isn't pronounced right.
The correct pronunciation would be from 「サイン」, but suppose instead we pretended we knew less about English, and said "It starts with a 'si', so there must be a 'sh' sound."
This doesn't really make sense, but I thought it would be interesting.</p>
<p>It looks like a few other people have noticed "sine"/"shine" is a thing.</p>
<p>Anyway, I'd been thinking about Japanese music a bunch, because we've been watching FLCL lately, and The Pillows left way more of an impression on me this time.
So, I was thinking about this as, like, a band name in katakana.
"s(h)ine wave" is interesting to me because it's two words together, and they behave very differently when you try to put them into katakana.
The best katakana transcription of wave, in terms of pronuncibility, is probably 「ウエーブ」, which gets romanized back as "UĒBU".
But it's possible to represent it more exactly in all kinds of peculiar ways.</p>
<ul class="simple">
<li>Swap ブ for ヴ to get something that really emphasizes the loanword aspect, I think.</li>
<li>Instead of ウエ, represent the "we" component with:<ul>
<li>An obsolete character: ヱ. It seems like that would read really strangely.</li>
<li>A suggested digraph for more accurate transcription: ウェ. This is one mora instead of two; no matter what, though, transcribing "wave" will end up with way more morae than English syllables.</li>
</ul>
</li>
</ul>
<p>Why not pile on more, then?
By analogy with the first word, add an "h" after the first letter.
This looks to most English speakers like it should have no effect (beyond making it not a word), but Japanese transcription (sometimes) doesn't have the wine-whine merger, so suddenly there's a 「ホ」 at the beginning, which... replaces the 「ウ」.</p>
<p>Thinking over all of this, I think the most important consideration is what would sound cool to shout.
The major point of contention is the "wa".
It will either be:</p>
<ul class="simple">
<li>"UĒ" (3 morae)</li>
<li>"WĒ" (2 morae)</li>
<li>"HOĒ" (3 morae)</li>
</ul>
<p>Maybe the trick is to look at the overall balance in length.
This has to come after 「シャイン」 (3 morae), so do I want 6 or 7 morae total?</p>
<p>On reflection, I like the "Whave" idea because I could, in the latin alphabet version, replace it with "ℏ".
The Planck constant over the circle constant τ gives us a nice connection to the trigonometric functions.
This invites further consideration of the romanization of the transcription.
If we expand out the macron, one possible rendition is:</p>
<ul class="simple">
<li>sℏain</li>
<li>ℏoeivu</li>
</ul>
<p>Which looks like it <em>should</em> mean "egg" in some romance language or other, but I don't care about that right now.
One thing I see when they're in monospace is that two different kana got converted to the same letter, and they're near each other in the words:</p>
<ul class="simple">
<li>s <strong>ℏ</strong> a <strong>i</strong> n</li>
<li><strong>ℏ</strong> oe <strong>i</strong> vu</li>
</ul>
<p>Can we take advantage of that, share the letters?
To do so, we'd have to curve the words, like...
Like a sine wave.
The obvious thing to consider is that one of them has two letters between them, while the other has one.
We could distort the curves to accommodate, or we could change the letters...
"ℏœivu".
For now, I want to focus on distorted curves.
It's about time to put pencil to paper.</p>
<p>Well, I tried out these ideas in reality, and some stuff worked, and some stuff didn't.
This is a process blog, so here's what I processed:</p>
<img alt="" class="align-center" src="https://mwchase.neocities.org/images/Scan-180405-0001.jpg" />
</div>
What To Post2018-04-04T12:12:00-04:002018-04-05T01:44:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-04:/what-to-post<p class="first last">I've got some stuff to work through</p>
<p>A key motivation behind my starting this blog was to try to "be less of a coward".
For over a decade now, my online presence has been mediated through the desire to gate my interests.
The basic chilling effect on myself is that I've got this boundary that I'm trying to keep track of, and avoiding discussing anything that feels like it could ever potentially cross over.</p>
<p>It's worth noting that I have a highly developed, quite possibly overdeveloped, sense of negative consequences of my actions.
One result of this is that I have extreme difficulty lying, because I cannot contemplate a lie without visualizing the knock-on effects.
To me, the lie feels equivalent in weight to the supporting lies that would be required to commit to it.</p>
<p>The point of all that is, because I can extrapolate great conceptual distances across the boundary, I've been engaging in a lot of self-censorship, beyond the immediately obvious division.</p>
<p>So, what I'm trying to figure out is, what does it look like to not have an absolute boundary?
I keep up with people who manage this, even refer my coworkers to their Python posts.
But I don't have a good sense of how to do it.
Also, the person I have in mind has quite a different employment situation from me.
Does this matter?
I don't know!
Should it matter?
Probably not!</p>
<p>But I keep on feeling pulled away from honest self-expression by the siren call of pragmatism.
And now that I put that sentence down, I realize I need to think about what it's pragmatism in the service of.
... Partly this is paranoia about effects on work, but I just realized I have <em>no idea of</em>, and little interest in, what my coworkers do in their spare time.
Contemplating putting it in a web search actually makes me feel a little tired, or maybe I just need sleep.</p>
<p>In any case, if it's going to be associated with me, I need to figure out where it goes.
Just sticking everything together would be the equivalent of my apartment, which I wouldn't show off to random strangers.
I don't think I have an answer yet, but I don't want to pretend I haven't thought about this.
Here goes the post.</p>
<p>EDIT 2018-04-05 01:44:
I've got an idea.
For any given piece of media I'm working on, <em>process</em> posts go here.
In addition, stuff that wouldn't better go on a special-purpose site goes here.
I do think I want to showcase some stuff here:</p>
<ul class="simple">
<li>Original fiction</li>
<li>Simple puzzlescript and ink games</li>
<li>I <em>will</em> crowbar tiddlywikis into Pelican, I swear it.</li>
</ul>
<p>Most things though, will go on sites with more robust content warnings.
The content warnings on here would just be, like, a bit in the summary.
Like, "this story has themes of claustrophobia" or whatever.</p>
Site Design Thoughts2018-04-04T01:18:00-04:002018-04-04T12:09:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-04:/site-design-thoughts<p class="first last">I have no training in web design</p>
<p>From now on, I'm trying to have no more than one "blog post about how I want the blog to be" for every two days.
I talked about myself yesterday, so guess what that makes today!</p>
<p>One choice I made right off the bat for the new theme was, I wanted to use the <a class="reference external" href="http://ethanschoonover.com/solarized">solarized</a> colors.</p>
<ul class="simple">
<li>Per guidelines, use the base* colors for text and background, and consider using them for emphasis.</li>
<li>Per web convention, blue for non-visited hyperlinks, violet for visited, red for active, and right now the protoype switches the background to highlighted on hover.</li>
<li>I <em>think</em> I don't want violet for visited for stuff from the theme, only within the page content.</li>
</ul>
<p>I've put together some quick sketches of ideas I have in mind here. Thrill as I recapitulate basic graphical concepts in a confused and confusing fashion!</p>
<p>EDIT 2018-04-04 12:09:
I forgot about writing this down last night, but I'm also planning to switch some or all of the <pre> text to use <a class="reference external" href="https://github.com/tonsky/FiraCode">Fira Code</a>.
One hurdle this has hit in prototyping is that the font comes out bigger than using the "monospace" family, and I don't know why yet.</p>
<img alt="" class="align-center" src="https://mwchase.neocities.org/images/Scan-180403-0001.jpg" />
<img alt="" class="align-center" src="https://mwchase.neocities.org/images/Scan-180403-0002.jpg" />
Introductions2018-04-02T21:40:00-04:002018-04-02T21:40:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-02:/introductions<p class="first last">Hey, Whoa, This Is Who I Am</p>
<p>I don't know if anyone's stumbled across this blog; a good portion of the views are probably me making sure I didn't break the theming.
Anyway, it behooves me to explain just who the heck I am.</p>
<p>My name is Max Woerner Chase.
I'm a software engineer/developer/whatever for a small-ish company that recently moved its headquarters to Boston.
I live in Natick, a short distance from the old HQ, with my wife of almost three years now.</p>
<p>I got my degree in Chemical Engineering and Applied Mathematics, ran screaming away from the former, and decided the latter was still all right, when all was said and done.
I feel like I've got a bit of unfinished business from my senior thesis, in that it really should work to take the fourier transform of a lattice of gaussians, basically to approximate potentials in the frequency domain instead of the spatial domain.
I must have been messing up <em>something</em> with my calculations.
But this doesn't really matter, and revisiting that code would involve writing more Java than I care to consider.</p>
<p>When it comes to math, I'm really interested in unconventional notation systems, at least ones that derive some gain from breaking with convention.
Stuff like spider diagrams, balanced ternary, quater-imaginary base.
I've also lately been trying to get a better handle on generating functions.</p>
<p>There are a variety of creative endeavors that I've been wanting for a while to devote more effort to, such as writing, illustration, music composition, learning the guitar, and game design and development.
So far as pursuing each specifically: I've written in the past and should pick it back up, I've had basic drawing lessons and could maybe look into something like <a class="reference external" href="http://drawabox.com/">Draw a Box</a>, I've taken classes on music theory, but I think mostly I just need to try stuff, the guitar is... in storage, and I've followed along with a <a class="reference external" href="http://rogueliketutorials.com/">roguelike tutorial</a> (possible better accessed through <a class="reference external" href="https://web.archive.org/web/20170914125523/http://rogueliketutorials.com/">archive.org</a> as of this writing), which I hope to get back to at some point, and develop into its own thing.</p>
<p>I have been learning several languages through Duolingo; I should look into other avenues, like maybe musical soundtracks in Spanish, German, Russian, or Japanese.
(I tried listening to opera, but I think I'd like something a little more bite-sized.)</p>
<p>Also, my wife and I are hella bi.</p>
Coming To Grips With Pelican2018-04-02T02:54:00-04:002018-04-02T02:54:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-04-02:/coming-to-grips-with-pelican<p class="first last">I don't fully understand what I'm doing</p>
<p>It kind of seems to me like, if categories are exclusive, then there should be some kind of chronological link between things in the same category?
Maybe my mental models are all wrong here, or maybe this is a theme thing and I need to do it myself.
One sec.</p>
<p>Still here?
Cool.
It looks like this is something I'll have to write myself.
Good thing I was planning to put together my own theme anyway.
(It doesn't really matter how computationally intensive the result is, because it only has to run on my machine.)</p>
<p>I have various things I'm planning to put on this site (like, <em>somehow</em>, I'm going to publish the One Man Institute of Inapplicable Physics), and I think probably they ought to just be published as blog posts.
I'll see how that all works out.</p>
Code Block Test2018-03-31T22:17:00-04:002018-03-31T22:17:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-03-31:/code-block-test<p class="first last">Messing with Pelican's code block support</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span></pre></div></td><td class="code"><div><pre><span></span><span class="c1">---</span>
<span class="c1">-- A utility function for creating empty ephemeron tables.</span>
<span class="c1">-- @return empty ephemeron table</span>
<span class="c1">-- @module ephemeron</span>
<span class="kd">local</span> <span class="n">meta</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">__mode</span> <span class="o">=</span> <span class="s1">'k'</span><span class="p">,</span>
<span class="n">__metatable</span> <span class="o">=</span> <span class="s1">'ephemeron'</span><span class="p">,</span>
<span class="p">}</span>
<span class="kr">return</span> <span class="kr">function</span><span class="p">()</span>
<span class="kr">return</span> <span class="nb">setmetatable</span><span class="p">({},</span> <span class="n">meta</span><span class="p">)</span>
<span class="kr">end</span>
</pre></div></td></tr></table></div>
First Post2018-03-31T15:19:00-04:002018-03-31T15:42:00-04:00Max Woerner Chasetag:mwchase.neocities.org,2018-03-31:/first-post<p class="first last">Let's try out some new systems and services</p>
<p>Yesterday, I made the decision to break with one of the online communities I had been hanging out in (we'll see how <em>that</em> holds up) and blog more.
But my old blog kind of sucked, and I wanted somewhere more independent if I were making a new one, so I'm setting up shop on Neocities now.</p>
<p>I'm going to focus on getting content up first, then making it look nice, so the early revisions of this will probably be an eyesore.</p>
<p>EDIT 2018-03-31 15:42:
Okay, when the theme actually renders because I turned relative URLs on for development, it looks okay.
Probably going to tweak it, but it's not "no styling whatsoever".</p>