<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: DrBearhands</title>
    <description>The latest articles on DEV Community by DrBearhands (@drbearhands).</description>
    <link>https://dev.to/drbearhands</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F66748%2Fa2a0c293-2af7-4439-a3d7-ea5685eb7609.jpg</url>
      <title>DEV Community: DrBearhands</title>
      <link>https://dev.to/drbearhands</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/drbearhands"/>
    <language>en</language>
    <item>
      <title>The glTF file format for 3D models has some issues</title>
      <dc:creator>DrBearhands</dc:creator>
      <pubDate>Thu, 19 Dec 2024 15:00:52 +0000</pubDate>
      <link>https://dev.to/drbearhands/the-gltf-file-format-for-3d-models-has-some-issues-46jo</link>
      <guid>https://dev.to/drbearhands/the-gltf-file-format-for-3d-models-has-some-issues-46jo</guid>
      <description>&lt;p&gt;The glTF 2.0 file format has become a standard for sharing 3D assets between applications. Unfortunately, it has a few unnecessary problems, and these problems are quite typical for our industry and the sad state it is in: rushed development, additive thinking, and a disdain for formal correctness. I'm going to rant about them here in the hope that others might avoid them, and that perhaps one day we will have a sane standard.&lt;/p&gt;

&lt;h2&gt;
  
  
  The WebGL-first problem
&lt;/h2&gt;

&lt;p&gt;glTF 2.0 comes from glTF 1.0, the &lt;em&gt;WebGL&lt;/em&gt; Transfer Format. This name is apt, as it heavily focussed on WebGL. It allowed specifying glsl shaders and structured its data as though it is arguments to WebGL API calls. Supporting glTF 1.0 in other graphic APIs, such as APIs such as Vulkan, Direct3D, WebGPU, would have been difficult and inefficient. The industry later standardized around PBR shaders/materials. For glTF 2.0, the API-specific shaders where therefore replaced by PBR materials. In other words while glTF 1.0 was specific about API (WebGL) and generic in materials (any shader), glTF 2.0 is specific about materials (PBR) but generic about API, except glTF 2.0 still declares data in a very WebGL-centric fashion. The focus of the project shifted, but decision-makers were unwilling to "redo" work they had already crossed off once. The standard was rushed and is now in a permanently bad state and all us implementors must suffer because of it. Let's get into some examples where this shows.&lt;/p&gt;

&lt;p&gt;Meshes are defined using variable attributes. Rather than being a list of values, as in e.g. obj files, the attributes reference (by id) an accessor, defining stride, offset and bufferView id. The buffer view defines an offset and index into a buffer, where finally we get the data. This is basically the input to &lt;code&gt;ArrayView&lt;/code&gt;, &lt;code&gt;gl.bufferData()&lt;/code&gt; and &lt;code&gt;gl.vertexAttribPointer()&lt;/code&gt;, respectively. The specification essentially admits this tight coupling at &lt;a href="https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_accessor_componenttype:" rel="noopener noreferrer"&gt;https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_accessor_componenttype:&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Related WebGL functions: &lt;code&gt;type&lt;/code&gt; parameter of &lt;code&gt;vertexAttribPointer()&lt;/code&gt;. The corresponding typed arrays are &lt;code&gt;Int8Array&lt;/code&gt;, &lt;code&gt;Uint8Array&lt;/code&gt;, &lt;code&gt;Int16Array&lt;/code&gt;, &lt;code&gt;Uint16Array&lt;/code&gt;, &lt;code&gt;Uint32Array&lt;/code&gt;, and &lt;code&gt;Float32Array&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;In glTF 2.0, specifying data as input to WebGL functions like this is pointless. Not only is it supposedly targeting other APIs as well, switching to PBR also requires changing the data in some cases, so it will not be fed directly to WebGL functions even on applications running on WebGL. Normals and tangents, for instance, need to be generated if absent, which alter the vertex indices.&lt;/p&gt;

&lt;p&gt;What's more, even in glTF 1.0, which was specifically targeting WebGL, a model should not be defined as arguments to API calls. Because neither the modeler, nor the glTF exporter used, can know what the most efficient way to do this is. For instance, interleaving vertex attributes is a performance consideration that can be highly dependent on the application and deployment target. I was once maintaining a WebGL rendering engine for room planning. The graphics were fairly simple, but it did have 4 shadow-casting lights, which is 3 more than normal. As an optimization, I decided to interleave the vertex data. Essentially that means you have a single array with all the information you need for every vertex close together, rather that having a different array for every "field". Performance benefits on my laptop - with integrated graphics - were within margin of error. As it turned out, the same change tanked performance on GPUs and ARM architectures. The 4-shadow casters each needed to draw every object in the entire scene, but only needed the vertices' position to do it. Were first they had a tightly-packed array of positions, simply not using the other arrays, now each position was separated by strides of useless data, causing cache misses. The more advanced CPU caching strategy of my laptop with integrated graphics had likely hidden that issue. &lt;/p&gt;

&lt;p&gt;The advantages of defining buffersViews and accessors to match the structure of WebGL just aren't there for glTF 2.0, and were arguably never there for glTF 1.0 either, but this indirection makes extracting the actual data we need a lot more strenuous. A few of my colleagues had just given up, and while it didn't take me that long, the code I wrote definitely isn't the most readable. In comparison, an array of values would have been trivial.&lt;/p&gt;

&lt;p&gt;There's another place where it shows that glTF 2.0 was intended to define inputs to WebGL functions: default values and constants. In some places, defaults are missing from the spec, and you will have to look up the matching WebGL function. E.g. in samplers' &lt;code&gt;magFilter&lt;/code&gt; and &lt;code&gt;minFilter&lt;/code&gt;. They are optional, but no default is given at the time of writing. &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F603f5pt031juxbjc3u89.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F603f5pt031juxbjc3u89.png" alt="table showing magFilter and minFilter have no default values" width="800" height="476"&gt;&lt;/a&gt;&lt;br&gt;
The accepted values for such variables are also nonsensical outside the context of WebGL. Does &lt;code&gt;9728&lt;/code&gt; read like a magnification filter? No? Well it is and means &lt;code&gt;NEAREST&lt;/code&gt;. In WebGL.&lt;/p&gt;

&lt;p&gt;The moral here is: when performance allows, define data as what it &lt;em&gt;is&lt;/em&gt;, rather than trying to be clever about how some application would like to have it internally, leave that to the application.&lt;/p&gt;
&lt;h2&gt;
  
  
  Too much stuff
&lt;/h2&gt;

&lt;p&gt;Besides rushed development, glTF 2.0 is also plagued by what I've started to call "additive thinking", as I do not know of an existing name for it. People tend to think adding feature will make a thing better. Quite often, the opposite is true. Whether you want to call it the Unix Principle, orthogonality or encapsulation, a driving principle of good software engineering is easy composition: you make a thing that performs a function, and can be easily combined with other things to make bigger things. This is what makes category theory interesting for software developers; it is the study of composition. The opposite is the God object anti-pattern, where you give too much stuff to something, rather than making many small things that can interact.&lt;/p&gt;

&lt;p&gt;glTF 2.0 suffers from this too. Not a lot, but it does. I'll name a few things that, in my opinion, should not be in the specification in the way they currently are.&lt;/p&gt;

&lt;p&gt;The worst offender is using negative scale as a mirror function. When you scale by a negative value (in a single axis), you mirror the position of the vertices, but you also flip their rotational order. Where first their internal side would get culled because it was e.g. clockwise, now the external side is clockwise and gets culled. This prevents using negative scaling to mirror a mesh as-is. Nevertheless, some engines do allow for this. You can check if a mesh has a negative scale (by its matrix determinant), and cull the other side of the triangle if it does. Changing cull side requires changing the pipeline, which is detrimental to performance, so we probably don't want to do that while iterating meshes in the render function. Instead, we complicate the renderer by pre-sorting objects into positive and negative determinants.&lt;/p&gt;

&lt;p&gt;There are other features that I don't think are good defaults to have in the format: vertex animations, multiple texture coordinates, sparse accessors, lines and points... I would much rather have seen them in extensions to keep simple things simple. These features aren't necessary for a lot of e-commerce applications for instance. As it stands, an engine supporting glTF 2.0 needs to be pretty bloody robust and feature-complete, wasting developer time and bloating their engine.&lt;/p&gt;

&lt;p&gt;Then again, the cynic in my says that might have been the point. Make the standard format complicated enough to incentivize smaller companies to buy into the commercial engines whose owners are part of the Khronos group.&lt;/p&gt;

&lt;p&gt;Supposing your goal is to make a &lt;em&gt;good&lt;/em&gt; standard, the point I'm making is: try to keep it simple, and allow for extensions. On that last part at least, glTF 2.0 is pretty good as far as I can see, though I plan to verify this in the future by writing my own extension.&lt;/p&gt;
&lt;h2&gt;
  
  
  Please use sum types
&lt;/h2&gt;

&lt;p&gt;Finally, and I am getting tired of this being everywhere, glTF does not leverage sum types to ensure type-safety. These are not toys for academics. They are essential in accurately defining your data. Sum types are the dual to product types every programmer knows as structs, classes, objects, or dicts: they consist of one type &lt;em&gt;and&lt;/em&gt; another type. Sum types consist of some type &lt;em&gt;or&lt;/em&gt; another type. Let's take a look at glTF's camera definition:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzrgwqelgb5rldr9qbcf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzrgwqelgb5rldr9qbcf.png" alt="definition of a camera, where perspective and orthogonal are both optional, and a string called " width="800" height="641"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's a lot of text to say a camera needs to be either orthographic or perspective. The used type provides no information about this, orthographic and perspective field look independent of each other. A better approach would have been to use a sum of an orthographic camera and a perspective camera, placing the tag (&lt;code&gt;type&lt;/code&gt;) as a fixed string with the data. E.g. in JavaScript with JSDoc:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** 
 * @type { { 
 *    type: "orthographic", 
 *    orthographic : camera.orthographic
 *  } | {
 *    type : "perspective", 
 *    perspective : camera.perspective
 *  } } 
 */&lt;/span&gt;
&lt;span class="nx"&gt;camera&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would immediately inform the programmer and the type checker of the right intention. If it has type field "orthographic", it will have an orthographic camera, if it has a type field "perspective", it will have a perspective camera, and there are no other option. Much shorter than all that text explaining the same thing but in a format my type checker can't read.&lt;/p&gt;

&lt;h2&gt;
  
  
  The good
&lt;/h2&gt;

&lt;p&gt;I should also take some time to mention what glTF 2.0 does well. First off, it exists and can do basically everything I want it to do. When I was modding games, we had complex toolchains between proprietary formats that would always lose the material, animation, or more likely both. glTF 2.0 is, at least, a standard, and a well-documented one, with a lot of test-cases to boot. This is all the reason I need to implement it over obj, ply, or other formats. It's also not going to change every few months.&lt;br&gt;
There's also PBR, glTF 2.0's binary format, which is very nice to have. It allows packing all data, such as textures and meshes, into a single file, keeping everything together that belongs together and making it more portable. I've seen enough broken links in mesh and material files to appreciate this. On the other hand, referencing external resources is still possible, so no efficiency is lost due to data duplication in applications that reuse assets.&lt;br&gt;
Finally, glTF 2.0 is built to support extensions, which means it can stay relevant if market demand for some new feature emerges. I myself look forward to toying with an extension in the future.&lt;/p&gt;

&lt;p&gt;Out of the file formats for 3D virtual display, glTF is the best we have, but that fact should be rather embarrassing for our industry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Environment map in article header from &lt;a href="https://polyhaven.com/a/phalzer_forest_01" rel="noopener noreferrer"&gt;Andreas Mischok&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;gltf files in article header from &lt;a href="https://github.com/KhronosGroup/glTF-Sample-Assets/blob/main/Models/CompareRoughness/README.md" rel="noopener noreferrer"&gt;khronos&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Web Monetization debunked</title>
      <dc:creator>DrBearhands</dc:creator>
      <pubDate>Wed, 31 Aug 2022 06:58:41 +0000</pubDate>
      <link>https://dev.to/drbearhands/web-monetization-debunked-hh1</link>
      <guid>https://dev.to/drbearhands/web-monetization-debunked-hh1</guid>
      <description>&lt;p&gt;Over the last few years, grifters have been preying on naive content creators through the Web Monetization proposal. The companies involved are Coil, Ripple, and the Interledger foundation, while Mozilla and Creative Commons seem to have fallen for Coil's marketing material and became unwitting accomplices. Web Monetization is presented as an "open" and "fair" protocol for micropayments on the web. The idea being that, when browsing a website, you send tiny payments to said website, rather than watching ads. A cursory technical evaluation reveals that if that were truly the intention, it is an abysmal failure. Instead, it has all the hallmarks of a pyramid scheme, where its proponents attempt to sell a made-up currency they created themselves for real FIAT currencies, specifically US dollars, while at the same time forcing a more favorable exchange rate. Because of the lackluster design as a payment system, wide adoption of Web Monetization could have disastrous consequences on our society.&lt;/p&gt;

&lt;p&gt;Let's get into the details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shortcomings
&lt;/h2&gt;

&lt;p&gt;Web Monetization is woefully underspecified in many places. That is &lt;em&gt;not&lt;/em&gt; acceptable for a payment protocol. I believe this to be intentional, as some of the unspecified elements involve complex problems, core reasons why micropayments don't exist yet. Interested readers who are unfamiliar with the subject can easily miss such omissions. They would only notice the well-specified bits of the proposal, which are typically easy problems to solve, thus making the proposal seem much better than it is.&lt;/p&gt;

&lt;p&gt;When such issues come up, proponents of Web Monetization refer to vague future technology that is not part of the spec. They might as well hire a shaman to cast a spell on the specification, for all the technical validity such an argument has.&lt;/p&gt;

&lt;p&gt;This is a fairly common strategy in "new technology" scams. It was already used by more-or-less the same grifters in earlier scams, the XRP Ledger and Interledger, among others. More about those in the appendices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Price
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://web.archive.org/web/20220731050428/https://github.com/WICG/webmonetization/issues/32"&gt;One example of an important omission is price&lt;/a&gt;. Price determination is a key problem of micropayments. You don't want users to think about, or interact with, every micropayment. The effort and mental load would be too great for sub-cent values. Payment initiation and price determination are &lt;em&gt;critical&lt;/em&gt; design considerations that must carefully balance UX, safety, and legal requirements. Some experts even believe these requirements to be so stringent, that they make micropayments altogether impossible. Web Monetization offers no solution here. It instead leaves the problem up to undefined "agents". An agent, in this context, is a computer program acting on your behalf, deciding when you want to pay and how much you want to pay. The agent isn't controlled or directed by you, but by the company that acts as your Web Monetization service provider. If you like Net Neutrality, this should absolutely horrify you. It essentially means that Coil decides who gets how much money from Web Monetization. Potential recipients, of course, include their own websites.&lt;/p&gt;

&lt;p&gt;How will websites react to agents that unfairly disparage them? Will they block users with such agents? Or will they accept everyone and take what they can get? In the latter case, or if it's not possible to detect unfair agents, Web Monetization devolves to pay-what-you-want. Pay-what-you-want is an incredibly easy model for which we already have a variety of legitimate services. On the other hand, if websites would indeed start blocking users with underpaying agents, we would see a fragmentation of the web, where different Web Monetization providers would give access to different websites. Again, we already have fragmented content subscription services, and they don't require harebrained payment protocols based on cryptocurrencies.&lt;/p&gt;

&lt;p&gt;Biased agents aside, the idea that a computer program could analyze a website to determine how much money to send it, is ludicrous. Websites are free to act on payments however they want. They are Turing-complete, with all the unpredictability that entails. There is also no way an agent can assess the value of a website, much less the subjective value to a specific user. &lt;/p&gt;

&lt;p&gt;What's more, a set price &lt;em&gt;cannot&lt;/em&gt; be added to the Web Monetization specification, because it is not tied to a specific currency. The use of an exchange network (Interledger) creates a disconnect between what is sent and what is received. Tying price specification to XRP would obviously favor Coil/Ripple, whereas tying price to dollars, or anything else they can't make up themselves, would make the scam a lot less profitable.&lt;/p&gt;

&lt;p&gt;The use of agents controlled by service providers only favors Coil, as it allows Coil to set its own exchange rate. More on that later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Worse than ads
&lt;/h3&gt;

&lt;p&gt;The lack of price negotiation in the specification is serious enough that it alone should stop adoption. Yet there's another equally serious problem. Although a payment agent can pretty much do whatever it wants, Web Monetization is typically presented as a system that continuously sends payments over time. This is a horrible idea.&lt;/p&gt;

&lt;p&gt;Let's remember why we want to get rid of ads. It's not just that they are annoying. Ads cause platforms to drive "engagement": keeping users on a website as long as possible so they can be made to watch more ads, which means more revenue for the website. This has resulted in some pretty awful strategies: social media driving insecurities, padding content with filler, clickbaiting, and most importantly, &lt;a href="https://www.youtube.com/watch?v=FLoR2Spftwg"&gt;serving ever more extreme, shocking, dangerous, and polarizing content&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since Web Monetization is a pay-by-second scheme, it creates a more direct incentive to keep users around as long as possible. This makes it worse. Advertisers don't want to be associated with negative content, and have on multiple occasions pulled their money when it financed hatred, misinformation, or shock videos. There is no such pushback mechanism in Web Monetization.&lt;/p&gt;

&lt;p&gt;Another reason why one might want to move away from advertisements is to avoid tracking. I find it hard to believe that Web Monetization will offer anything of value here. Tracking is being used on noncommercial websites as well, as some of them have blindly added external elements that came with tracking. Ad-free stores are still asking users for permission to place tracking cookies. It's bad, but unfortunately that's the way things are.&lt;/p&gt;

&lt;p&gt;In short, the Web Monetization pay-by-use model is so harmful that it more than undoes any good that could come from a reduction of advertisements. What's more, there is no reason why websites wouldn't double dip, serving you ads while also enabling web monetization.&lt;/p&gt;

&lt;h2&gt;
  
  
  The grift
&lt;/h2&gt;

&lt;p&gt;So the specification is terribly broken. This is not the kind of oversight someone genuinely trying to solve this issue would make. It is because the specification has been designed for something else entirely. Let's get into why I'm calling this bad specification a actual grift.&lt;/p&gt;

&lt;p&gt;The company pushing Web Monetization is Coil. Coil offers a Web Monetization "service" where you pay the company a fixed monthly amount &lt;em&gt;in dollars&lt;/em&gt; and they pay websites &lt;em&gt;in XRP&lt;/em&gt;. Remember that Web Monetization agents may decide how much they pay. So Coil's "service" is about them getting 5 dollars every month, and deciding themselves how much of some cryptocurrency they send out to participating websites. That sounds mighty convenient... but it gets worse. &lt;a href="https://finance.yahoo.com/news/ripple-grants-1-billion-xrp-144505202.html"&gt;Coil was funded by Ripple for a billion XRP&lt;/a&gt;, and Coil's CEO was CTO at Ripple. Ripple created XRP. From nothing. It's fake money that is not backed by anything.&lt;/p&gt;

&lt;p&gt;Most cryptocurrencies typically have some kind of mining scheme. Mining is the system that both creates new coins and allows a ledger to be decentralized. The creators of XRP discarded mining (and decentralization), to instead award every coin that would ever exist to themselves.&lt;br&gt;
This was too obvious for many investors, and so XRP didn't do amazingly well. I will cover the original excuse for XRP, and how that too was a scam, in an appendix.&lt;/p&gt;

&lt;p&gt;This left Ripple in an awkward spot: the company had billions worth of fake money, but couldn't really spend it. XRP was already heavily criticized for being a centralized scam coin. An obvious dump of XRP by its creator would likely result in a market crash and a number of lawsuits. Considered they had previously targetted banks, those lawsuits could hurt. Ripple needed to obfuscate things, so they created Coil.&lt;/p&gt;

&lt;p&gt;Since Coil is receiving dollars and sending out XRP at their own discretion, it is essentially letting Ripple covertly exchange their supply of made-up money at a valuation of their own choosing. Coil may technically be a different company from Ripple, but as its people come from Ripple, its money comes from Ripple, and its goals come from Ripple... that doesn't really matter.&lt;/p&gt;

&lt;p&gt;But this is just the first phase of the scam. Things get even worse in the off-chance the specification gets wider support.&lt;/p&gt;

&lt;h2&gt;
  
  
  Absolutely closed
&lt;/h2&gt;

&lt;p&gt;The fact that Coil is using it's own, made-up money for use in Web Monetization isn't just a bad deal for users, it is also an unfair competitive advantage that effectively closes up the specification. Will other companies offering Web Monetization services also get to use their own made up money? Of course not, and Coil's subscription service exacerbates that unfairness.&lt;/p&gt;

&lt;p&gt;A fixed subscription is typically much preferred by consumers than pay-by-use. This is a well known problem in micropayments. Coil can offer such a service &lt;em&gt;because&lt;/em&gt; they are using made-up money. Sending a payment doesn't actually cost them anything. Normally, companies cannot offer to cover your payments for a monthly fee. That would be way too easy to exploit. You could just send money to yourself, paid by the service provider, and only pay the monthly fee. If you were to try it with Coil, you are essentially just buying XRP, which is what they want you to do in the first place.&lt;/p&gt;

&lt;p&gt;But that's not all. Interledger is the technology supposed to make the protocol "fair" and "open". It's a network of exchanges that allows for the use of multiple (crypto-)currencies. Interledger is controlled by Coil/Ripple. &lt;a href="https://web.archive.org/web/20220731063518/https://interledger.org/about-us/"&gt;At the top of its board of directors sits the Coil CEO, followed by someone from Ripple&lt;/a&gt;. That's already suggests a blatant conflict of interests. Even if it weren't, Interledger still would not make the protocol fair or open, quite the contrary. Every exchange between a payment sender and recipient adds fees and delays. That means it's convenient for users to centralize onto a single currency. With Coil being the initial proponent of Web Monetization, that currency is going to be XRP. If new Web Monetization service providers are to be attractive for content creators, they will have to &lt;em&gt;buy XRP&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Interestingly, &lt;a href="https://web.archive.org/web/20210520112939/https://coinsutra.com/20-xrp-ripple-fee-reserve/"&gt;if you want to receive XRP, you must first buy and spend XRP to create a wallet&lt;/a&gt;. While this is supposedly done to prevent span, it is also the &lt;em&gt;exact&lt;/em&gt; approach of pyramid schemes: new entrants must pay old entrants (often by buying some asset for much more than it is worth).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The marketing material of Web Monetization is incredibly appealing. It would be great to have a straightforward system to pay for the content we enjoy directly. Advertisements are a roundabout way of achieving this, and are ultimately much more expensive if we factor in advertisers' return on investment. But Web Monetization is worse. It appears to be designed to pump and dump XRP, and suffers as a payment system as a result. Even Ripple themselves proclaimed their "investment" in Coil was to pump XRP. As a scam it is quite clever, because the victims can't easily recognize themselves as victims, and the difference between victim and scammer is quantitative, as with most (pseudo-)pyramid schemes.&lt;/p&gt;

&lt;p&gt;There are going to be some people other than Coil/Ripple who earn money from Web Monetization. They will receive their made up currency, and sell it to the next biggest fool for FIAT. This just means they are higher on the pyramid.&lt;/p&gt;

&lt;p&gt;Web Monetization needs to go away to make place for legit suggestions, free of cryptocoins or other asset pumps. In the meantime, it's better to fight against ads with new legislation, and making more people aware of the hidden costs of ads. GDPR, for instance, has done wonders exposing hidden privacy costs, and just how widespread unnecessary invasions of our privacy are.&lt;/p&gt;

&lt;p&gt;Ultimately, Web Monetization only covers voluntary payments, and is inadequate for anything else, due to a lack of price determination. Such voluntary payments are &lt;em&gt;easy&lt;/em&gt;. If you're willing to spend 5 dollars a month to support creators you enjoy, use the randomized donation model: bookmark the pages you enjoyed, pick one at random at the end of the month, and send them the 5 dollars. If the website is not taking donations, send the money to a charity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Appendix 1: The XRP ledger is also a scam
&lt;/h2&gt;

&lt;p&gt;If you've read this far you may also be interested in more details about Ripple's earlier scam, the XRP ledger.&lt;/p&gt;

&lt;p&gt;Let's start with some background. There is a bit of an open problem for banks: how to transfer money from an account on bank A, to an account on bank B. Your account balance is knowledge. It cannot be "moved" like a physical object. That means that if you want to transfer money from an account on bank A to an account on bank B, someone has to &lt;em&gt;physically move the money between the banks&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;An alternative does exist: &lt;a href="https://en.wikipedia.org/wiki/Nostro_and_vostro_accounts"&gt;nostro/vostro accounts&lt;/a&gt;. Slightly simplified: bank A keeps an account with bank B. Bank A can then transfer money to clients of B, from its own account with B. That way an inter-bank payment becomes a payment from an account within the same bank. A nostro/vostro account is essentially a monetary buffer that creates trust. There are other solutions, such as payment channels, that operate on essentially the same principle: set money aside to quantify trust.&lt;/p&gt;

&lt;p&gt;The problem of nostro/vostro accounts and similar systems is combinatorial explosion: there are too many banks to set up buffers to each of them. A more advanced solution is to create these buffers with a shared centralized party (the intermediary), such as the European Banking Association, or a large international bank. This works as long as everyone joins the same payment rail, i.e. so long as everyone maintains buffers with the same entity. Since changing payment rail is usually incredibly expensive, this would give a lot of power to those intermediaries. &lt;/p&gt;

&lt;p&gt;The key takeaway here is that making payments between banks can be done, but requires setting up trust buffers.&lt;/p&gt;

&lt;p&gt;Cryptocurrencies caught the interest of banks because they seemed to offered a solution to this problem. With decentralized cryptocurrencies, money is fully digital. Changing who owns/controls money does not require physically moving something, making trust buffers redundant. On the other hand, banks don't want to deal with cryptocurrencies. They are volatile, lawless, not backed by anything, and it's not what their clients are using. Furthermore, the biggest cryptocoin, Bitcoin, had way too low throughput.&lt;/p&gt;

&lt;p&gt;Ripple decided to capitalize on this niche with the XRP Ledger. The main idea behind the XRP Ledger was that banks could declare that they owned a certain asset (e.g. USD banknotes). A claim of ownership of that asset would be written to the XRP ledger, where the claim could then be traded with other parties on the XRP ledger. Essentially, the bank creating the claim is promising they would pay out the asset to the final owner. &lt;/p&gt;

&lt;p&gt;This doesn't solve the problem any better than nostro/vostro accounts. There is no certainty that an asset on the ledger can be cashed in, it's still a matter of trusting the issuing party. The XRP Ledger assumes banks have a precise trust score in the claims made by other banks, more-or-less expressed as the expected probability that a given asset is valid. That is highly dubious, and if present could also be used for implicit nostro/vostro accounts. It is a bad assumption in any case, as any nonzero trust score can in principle be exploited without limit, by creating infinite virtual assets they do not intend to pay out. In comparison, the balance of a nostro/vostro account sets a precise upper limit for how much one bank could damage another bank.&lt;br&gt;
Sure, the XRP Ledger would allow parties with a low trust score to receive a trust injection by using assets from parties with a high trust score, but this is not fundamentally any different from opening an account with an intermediary.&lt;/p&gt;

&lt;p&gt;So this system is fundamentally broken, but where does XRP factor in? The reported purpose of XRP is to function as spam prevention. Trading or opening an account on the XRP Ledger requires functionally destroying XRP coins. Yes, adding small payments to actions is a known way to prevent spam, but there are other methods. This one just so happens to be incredibly convenient for Ripple. XRP isn't a mined coin, and the XRP Ledger does not use proof-of-work algorithms. That does make transactions faster, but it also allowed Ripple to "pre-mine" every XRP coin when they created the XRP Ledger. That means they gave them all to themselves. Without coin mining, they need a different way to achieve consensus over multiple parties. A more traditional consensus strategy was chosen that relies on validators. Since the XRP Ledger need to at least &lt;em&gt;appear&lt;/em&gt; decentralized, most of these validators are not (known to be) Ripple themselves. In other words, the validators are doing the work, and Ripple gets paid.&lt;/p&gt;

&lt;p&gt;Relying on validators is an old strategy with some serious issues. When Satashi Nakamoto created Bitcoin, he invented the proof-of-work strategy. Ripple's consensus algorithm already existed at the time. It just wasn't good enough for Bitcoin. Validators must be appointed by someone, some authority. It's not a free-for-all type of decentralization as with proof-of-work. It matters who the validators are, as they are, as a whole, a &lt;em&gt;trusted central party&lt;/em&gt;. While I myself haven't done any research into who the validators are, it appears &lt;a href="https://jonhq.com/who-are-the-ripple-validators/"&gt;the state of XRP validators is pretty horrific&lt;/a&gt;. Validators are appointed &lt;em&gt;by Ripple&lt;/em&gt;, and we often don't know who they are. Most of them might be the same colluding entity, or even Ripple themselves. This is the kind of information you don't find out until you are already very deeply on board with Ripple and XRP. I personally only came across it by chance. XRP Ledger proponents might tell you that you choose your own validators, but that is utterly irrelevant. If a validator were to go against the majority, it essentially wouldn't be participating in the XRP Ledger. The point is to achieve &lt;em&gt;consensus&lt;/em&gt;. It's like saying you can choose to be rich by killing yourself if you are poor.&lt;/p&gt;

&lt;p&gt;In short, the Ripple protocol, the alleged reason for XRP's existence, is inferior to preexisting technology, and even quite dangerous. So why did it rise to prominence? &lt;/p&gt;

&lt;p&gt;After Ripple gave all the XRP to themselves, they had a lot of &lt;em&gt;potential&lt;/em&gt; money to play with, as long as people were buying XRP. They lured initial adopters by giving away large sums of XRP. Those investors would then also benefit if the market value of XRP were to rise. They would have incentives to make the XRP Ledger and XRP itself look legit. Making people think the market rate of XRP was going to go up even further, thereby driving the price of their vacuous assets. Let me spell it out: this is basically a pyramid scheme. But it has a twist. Even the most well-intentioned bank would have to consider investing in the XRP ledger. You see, technical qualities, or the lack thereof, are not the main driving force in banks' decisions. If there is a global shift in payment rail, individual banks &lt;em&gt;must&lt;/em&gt; switch to that payment rail, or they will no longer be able to provide their service to customers. If customers cannot make payments through their bank anymore, they are probably going to go elsewhere, and the bank goes belly-up. So banks cannot be allowed to be blindsided by global developments, such as potential wide adoption of the XRP Ledger for international payments. Switching payment rail is slow and expensive. Not something to which they can react on the fly. Hiring a few developers to play with XRP is relatively cheap. It is therefore the safest decision for banks to make small investments in XRP to gain experience with the emerging protocol. How unimpressive the technology behind it is, is simply irrelevant in this decision. &lt;/p&gt;

&lt;p&gt;To summarize the business strategy of the XRP Ledger: the first "adopters" could be won over and turned into co-conspirators with XRP gifts, and the rest would &lt;em&gt;have&lt;/em&gt; to follow because of the threat of a changing global payments environment.&lt;/p&gt;

&lt;p&gt;Luckily, people weren't &lt;em&gt;quite&lt;/em&gt; as stupid as Ripple Labs expected. The European Banking Association started warning banks against the dangers of virtual currencies. Many people were calling XRP a scam coin because it was centralized and pre-mined. &lt;a href="https://www.sec.gov/news/press-release/2020-338"&gt;The SEC started a lawsuit&lt;/a&gt;. Coinbase stopped trading XRP. Banks also started to realize there already was a central party they all trusted: the central banks. We will likely soon see Central Bank Digital Currencies emerge, which are far superior to Ripple in handling inter-bank payments. So, it appears Ripple has now changing strategy, and trying to pump-and-dump their worthless coin through Web Monetization and the XRP Ledger.&lt;/p&gt;

&lt;h2&gt;
  
  
  Appendix 2: interledger is not new technology
&lt;/h2&gt;

&lt;p&gt;Interledger is presented as something sort-of separate from Web Monetization. I don't think the two can truly be separated. Interledger is set up as a nonprofit to appear coin agnostic, while really being led by Ripple/Coil, and soft-locking other cryptocurrencies out of the market. However, I want to briefly consider the merits of Interledger on its own.&lt;/p&gt;

&lt;p&gt;Interledger is a specification for how a network of cryptocoin traders could communicate. The idea is to identify chains of multiple traders, allowing for more conversions than any individual trader might offer. As I explained earlier, the hardest part about enabling two parties to transfer digital currencies, is setting up the trust buffer between those parties. It doesn't really matter if it's a nostro/vostro account, a payment channel or something else. Interledger leaves that problem to the participants of the network themselves. They don't have a solution for it. They have, again, skipped the hard part. Interledger merely expects parties that have overcome this obstacle, to adhere to their silly protocol.&lt;/p&gt;

&lt;p&gt;This supposedly groundbreaking new technology is adds so little that it's hard to criticize. Path planning on a graph of exchanges, amazing!&lt;/p&gt;

&lt;p&gt;Eugh.&lt;/p&gt;

</description>
      <category>webmonetization</category>
      <category>scam</category>
    </item>
    <item>
      <title>The Abstract Syntax Tree</title>
      <dc:creator>DrBearhands</dc:creator>
      <pubDate>Thu, 02 Dec 2021 11:59:46 +0000</pubDate>
      <link>https://dev.to/drbearhands/the-abstract-syntax-tree-1p30</link>
      <guid>https://dev.to/drbearhands/the-abstract-syntax-tree-1p30</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;One of the first steps a compiler must take is parse the human-readable program format, usually a plain text file, and put it into a structure the compiler can work with; the &lt;a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree"&gt;Abstract Syntax Tree&lt;/a&gt; (abbreviated to AST).&lt;/p&gt;

&lt;p&gt;Here's a simple example with code followed by an AST:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kDaENfEY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7gquen7dtiwrqcsykkr5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kDaENfEY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7gquen7dtiwrqcsykkr5.png" alt="AST of above code" width="179" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and a slightly more complex example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5h5efOtX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6xcs0mskaef54udkckqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5h5efOtX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6xcs0mskaef54udkckqr.png" alt="AST of above code" width="315" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;in this post I wish to define the AST for my language based on requirements set forth previously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Underlying litterature
&lt;/h2&gt;

&lt;p&gt;I'm primarily basing myself on the following work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.microsoft.com/en-us/research/publication/implementing-functional-languages-a-tutorial/"&gt;[Peyton Jones &amp;amp; Lester 1992]&lt;/a&gt; &lt;em&gt;Implementing Functional Languages: a tutorial&lt;/em&gt;. The title of this book is self-explanatory, though I should mention it covers lazy languages specifically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[Martin-Löf 1973] &lt;em&gt;An intuitionistic theory of types: predicative part&lt;/em&gt;. This article first describes the Martin-Löf type system, that is, dependent types. It explains how propositions about values in a program can be expressed themselves as types and terms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://bentnib.org/quantitative-type-theory.pdf"&gt;[Atkey 2018]&lt;/a&gt; &lt;em&gt;Syntax and Semantics of Quantitative Type Theory&lt;/em&gt;. This article describes quantitative type theory, which marries dependent types with linear values and erasure.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, I'm also using a lot of transitive knowledge and things I picked up here and there, but have no specific source for.&lt;/p&gt;

&lt;h2&gt;
  
  
  A default AST
&lt;/h2&gt;

&lt;p&gt;To define how an AST might look, we must specify a language grammar. This is often done using &lt;a href="https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form"&gt;BNF (Backus-Naur Form)&lt;/a&gt; notation. In languages like Haskell and Idris it is incredibly easy to express it directly in a type, so I will do that instead.&lt;/p&gt;

&lt;p&gt;I start from the AST given in &lt;a href="https://www.microsoft.com/en-us/research/publication/implementing-functional-languages-a-tutorial/"&gt;[Peyton Jones &amp;amp; Lester 1992]&lt;/a&gt; p.17, translated to Idris:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data Expr a
  = EVar String
  | ENum Int
  | ECtr Int Int
  | EAp (Expr a) (Expr a)
  | ELet IsRec (List (a, Expr a)) (Expr a)
  | ECase (Expr a) (List (Alt a))           
  | ELam (List a) (Expr a)

data Alt a = (Int, List a, Expr a)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the type-variable &lt;code&gt;a&lt;/code&gt; is the "binder" of values. Generally this will be a &lt;code&gt;String&lt;/code&gt; representing the name of a variable, but different types could be used as well.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;EVar&lt;/code&gt; represents named variables, such as &lt;code&gt;x&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;ENum&lt;/code&gt; is for number primitives: &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;42&lt;/code&gt;, etc. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;ECtr&lt;/code&gt; is less intuitive, when we define a type, such as &lt;code&gt;data MaybeInt = Just Int | Nothing&lt;/code&gt;, each constructor can be given a number, called the tag. The tag can be used internally by case expressions to match on the right constructor. The other &lt;code&gt;Int&lt;/code&gt; argument to &lt;code&gt;ECtr&lt;/code&gt; is the arity: how many arguments the constructor takes. In the example &lt;code&gt;Just&lt;/code&gt; has arity 1 and &lt;code&gt;Nothing&lt;/code&gt; has arity &lt;code&gt;0&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;EAp&lt;/code&gt; is function application. For instance, &lt;code&gt;f x&lt;/code&gt; would parse to &lt;code&gt;EAp (EVar "f") (EVar "x")&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;ELet&lt;/code&gt; is for &lt;code&gt;let ... in&lt;/code&gt; expressions, where the &lt;code&gt;(a, Expr a)&lt;/code&gt; values are the variable definitions.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ECase&lt;/code&gt; is a case expression. The &lt;code&gt;Alt a&lt;/code&gt; type has a tag value to match, with a list of constructor arguments, and an expression.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ELam&lt;/code&gt; is for lambda functions.&lt;/p&gt;




&lt;p&gt;There are a few changes I wish to make based mostly on preference.&lt;/p&gt;

&lt;p&gt;First, we can determine whether a let-expression is recursive, e.g. &lt;code&gt;let xs = 1 : xs in ...&lt;/code&gt;, by static analysis of the enclosed definitions. &lt;a href="https://www.microsoft.com/en-us/research/publication/implementing-functional-languages-a-tutorial/"&gt;[Peyton Jones &amp;amp; Lester 1992]&lt;/a&gt; does this, more or less, in 6.8.3. I prefer not to have a specific field for it so that I have a single source of truth. I will remove the &lt;code&gt;IsRec&lt;/code&gt; field. I suspect the book only uses this field to avoid having to explain dependency analysis first.&lt;/p&gt;

&lt;p&gt;Second, numbers are just constructors that should really check their priviledge. Defaulting to &lt;code&gt;int&lt;/code&gt; is a fantastic source of bugs. By giving numbers special treatment we are also overlooking more generic optimizations. &lt;code&gt;ENum&lt;/code&gt; goes.&lt;/p&gt;

&lt;p&gt;Third, I'm taking a hint from Elm style guidelines and replacing builtin types by more meaningful custom ones.&lt;/p&gt;

&lt;p&gt;After those basic changes we are left with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data Expr a
  = EVar VarID
  | ECtr CtrID
  | EAp (Expr a) (Expr a)
  | ELet (List (Def a)) (Expr a)
  | ECase (Expr a) (List (Alt a))           
  | ELam (List a) (Expr a)

data Alt a = MkAlt CtrID (List VarID) (Expr a)

data Def a = MkDef a (Expr a)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have left the various IDs intentionally undefined.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the AST hollistic
&lt;/h2&gt;

&lt;p&gt;To consider what changes are necessary to support hollistic programming, we must go back to the language's goals.&lt;/p&gt;

&lt;p&gt;If we wish to define the whole system in a language, rather than one particular program, we must start considering changes in code over time. Typically, it is the responsibility of the developer to ensure that changes to not break compatibility with persistent systems, such as databases. If such systems are generated by the compiler, it is the compiler that must be able to prove compatibility with some previous version. Immutability helps a great deal here. Just as &lt;a href="https://elm-lang.org/news/blazing-fast-html"&gt;Elm uses immutability to quickly determine what areas of a DOM need updating&lt;/a&gt;, so too we wish to have immutability in program definitions themselves, so we can correctly determine what is compatible. It would be nice if we had some kind of "metapurity": make the act of programming itself pure.&lt;/p&gt;

&lt;p&gt;To achieve this, I will copy the identify-by-hash approach of &lt;a href="https://www.unisonweb.org/"&gt;unison&lt;/a&gt;. Where names are stateful and may point to different functions over time, hashes are stateless. If a function changes, so does its hash.&lt;/p&gt;

&lt;p&gt;Of course, programming with hashes directly is infeasible for programmers. We need a human-compatible language, let's call it the display language. In most other programming languages, the display language is the source of truth. The core language AST is derived from it during compilation. There is a missed opportunity here. &lt;/p&gt;

&lt;p&gt;A lot of effort is being wasted by developers fighting about pure display concerns: tabs vs spaces, camelCase vs PascalCase vs snake_case vs kebab-case, operators vs functions, import definitions, naming, alignment, egyptian brackets... after removing names as identifiers, none of these concerns change a program's AST in the core language. If we make the core language the source of truth, and define the display language as (isomorphic to) the core language plus some display information (e.g. variable names), we can do away with those issues entirely.&lt;/p&gt;

&lt;p&gt;Now, back to the AST&lt;/p&gt;




&lt;p&gt;Many naming issues are already resolved by resorting to hashes, but variables may also be bound by let-expressions, lambdas, and supercombinators. For there, we don't really need hashes. We can use a &lt;a href="https://en.wikipedia.org/wiki/De_Bruijn_index"&gt;&lt;em&gt;de Bruijn index&lt;/em&gt;&lt;/a&gt;, slightly adapted to work with let-expressions and supercombinators as well (both can be converted to lambda functions, but that seems counter-productive).&lt;/p&gt;

&lt;p&gt;I will have to distinguish between local variables, using de Bruijn indices, and global variables. Binder types have become superfluous, we just need to know &lt;em&gt;how many&lt;/em&gt; binders a binding-expression has.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data Expr
  = ELVar Nat               ||| de Bruijn index of locally-bound variable
  | EGVar Hash              ||| Hash of globally bound supercombinator
  | ECtr CtrID                    
  | EAp Expr Expr
  | ELet (List Expr) Expr   ||| 1st arg is definitions, second is the "in" part
  | ECase Expr (List Alt)           
  | ELam Nat (Expr a)       ||| Only need to know number of arguments

data Alt = MkAlt CtrID Expr ||| # arguments derived from CtrID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dependent typing
&lt;/h2&gt;

&lt;p&gt;This leaves us with 2 problems: &lt;code&gt;CtrID&lt;/code&gt; is not defined, and we are missing a way to use types as values. &lt;/p&gt;




&lt;p&gt;&lt;em&gt;unfortunately, I start using math heavily here, and have not found a satisfactory way to display it on dev.to that does not require a lot of manual work. I ask you to continue reading on &lt;a href="https://drbearhands.com/pl-design/2-ast/"&gt;my website&lt;/a&gt; instead.&lt;/em&gt;&lt;/p&gt;




</description>
    </item>
    <item>
      <title>On automated versioning strategies for CI/CD pipelines</title>
      <dc:creator>DrBearhands</dc:creator>
      <pubDate>Thu, 25 Nov 2021 12:15:31 +0000</pubDate>
      <link>https://dev.to/drbearhands/on-automated-versioning-strategies-for-cicd-pipelines-4kap</link>
      <guid>https://dev.to/drbearhands/on-automated-versioning-strategies-for-cicd-pipelines-4kap</guid>
      <description>&lt;p&gt;It is quite likely that one of your projects will need version numbers at some point in time. You might also want to generate them automatically in a CI/CD pipeline.&lt;/p&gt;

&lt;p&gt;The popular way of reporting version numbers is &lt;a href="https://semver.org/"&gt;semver&lt;/a&gt;. Three numbers, MAJOR.MINOR.PATCH, denoting breaking changes, new backward compatible features, and backward compatible bugfixes, in that order. Unfortunately, this strategy is wrong in such a way it will never result in correct automated versioning systems. At least, not beyond the trivial increment counter.&lt;/p&gt;

&lt;p&gt;The problem lies in the words "backward compatible". It is basically impossible to make changes to code that won't break &lt;em&gt;some&lt;/em&gt; theoretical dependent project. In many programming languages, adding new functions and leaving the old ones as is does not result in breaking changes, but doing that is often bad practice. New features are bloat. Here's another &lt;a href="https://snarky.ca/why-i-dont-like-semver/"&gt;explanation about the problems with semver&lt;/a&gt; that is more in-depth.&lt;/p&gt;

&lt;p&gt;In practice, developers label versions based on what they &lt;em&gt;think&lt;/em&gt; won't break too many dependent projects. It &lt;em&gt;is&lt;/em&gt; useful in practice, but an automated tool has no way of doing that.&lt;/p&gt;

&lt;p&gt;If semver cannot be automated, is there a useful strategy that can?&lt;/p&gt;

&lt;p&gt;A more "correct" versioning scheme would be MAJOR.PATCH.FEATURE, were MAJOR is for changes of which the author thinks will break projects, PATCH is for changes that can break projects in ways the author thinks are niche, and FEATURE is &lt;del&gt;an inverse function of quality&lt;/del&gt; for changes that maintain trace-equivalence with previously-existing endpoints. This versioning system of "descending chances of breakage" is not how we usually think about dependencies. We want the numbers that tell us what features can be used first. If I'm using dependency version X and read about a feature introduced in version Y, it should be immediately clear if I can use the feature from Y in X. There is a conflict in using version numbers to denote the feature set, and using version numebrs to describe potential breaking changes.&lt;/p&gt;

&lt;p&gt;This leads me to the following: versioning is multidimensional. We must first realize which dimensions are interesting for our use-case and, if we can, derive them automatically.&lt;/p&gt;

&lt;p&gt;Let's look at a few strategies that are not semver.&lt;/p&gt;

&lt;h4&gt;
  
  
  Type-level "semver"
&lt;/h4&gt;

&lt;p&gt;Elm uses automatic "semver", but it is not actually semver. Or rather, it is semver over the metalanguage of Elm types, not Elm itself. "Breaking changes" are changes to any pre-existing type definitions, MINOR changes are new type declarations, and PATH is no changes in type declarations.&lt;/p&gt;

&lt;p&gt;For instance, if we previously commited:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;seven&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
&lt;span class="n"&gt;seven&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;seven&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
&lt;span class="n"&gt;seven&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will be a PATH version bump.&lt;/p&gt;

&lt;p&gt;Type level semver indicates what will not break &lt;em&gt;at compile time&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Commit SHA
&lt;/h4&gt;

&lt;p&gt;Using commit hashes is probably the most precise way to specify dependency versions. It is also stateless, which comes with its own benefits. You can use it with shallow clones, for instance.&lt;/p&gt;

&lt;p&gt;Unfortunately it is also a bit inflexible. It does not give you a notion of backward compatibility. If there is a security patch you won't be able to pull it in automatically. If you have two dependencies that share a sub-dependency but require different but compatible versions of it... tough shit.&lt;/p&gt;

&lt;p&gt;Furthermore, it's hard to read by humans, and given only two version descriptors, it is unknown which one is the latest.&lt;/p&gt;

&lt;p&gt;Commit SHA are about the best identifiers you could have. Assuming you don't change your repository's history, which will lose references.&lt;/p&gt;

&lt;h4&gt;
  
  
  git describe
&lt;/h4&gt;

&lt;p&gt;Another way tool that is available to us is &lt;code&gt;git describe&lt;/code&gt;. This commands spits out &lt;code&gt;TAG-OFFSET-gCOMMIT&lt;/code&gt;, where TAG is the most recent (manually created) tag, offset it the number of commits since that tag, and COMMIT is the current (abbreviated) commit SHA.&lt;/p&gt;

&lt;p&gt;This has an advantage over simple commit SHAs in that they accurately allow to compare version numbers. We might consider TAG to be feature information, and OFFESET or gCOMMIT to be compatibility information. It is still as inflexible as simple commit hashes, unfortunately.&lt;/p&gt;

&lt;p&gt;The biggest problem with this approach is that it requires pulling the repository up to unknown depth. In a CI/CD pipeline you would generally pull only a shallow copy of the repository. Why slow down your jobs by downloading every commit since the beginning of time? Well, you rather have to with this strategy, or &lt;a href="https://gitlab.com/gitlab-org/gitlab/-/issues/28295"&gt;&lt;code&gt;git describe&lt;/code&gt; might suddenly return something unexpected&lt;/a&gt; if the tag is more commits away than the clone depth.&lt;/p&gt;

&lt;p&gt;Git describe gives us stateful identity with a partial order, potentially even a total order if tags have a total order. This strategy also only works assuming no history changes in your repository.&lt;/p&gt;

&lt;h4&gt;
  
  
  Release/build date
&lt;/h4&gt;

&lt;p&gt;Dates are nice for humans, but horribly inaccurate. The downsides are obvious: no compatibility information, no support for branches. Also, dates are subjective at best due to timezones, daylight savings time, and other more obscure changes to our timekeeping standards.&lt;/p&gt;

&lt;p&gt;You can get the date of a commit using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git show &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;%ci &amp;lt;commit&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you may be able to &lt;a href="https://stackoverflow.com/questions/6795070/is-there-a-way-in-git-to-obtain-a-push-date-for-a-given-commit"&gt;use the date when a commit was pushed to a central repository&lt;/a&gt;, provided you can configure said repository. That solves the subjectivity problem.&lt;/p&gt;

&lt;p&gt;Dates technically only offer a preorder, but result in total order quite often.&lt;/p&gt;

&lt;h4&gt;
  
  
  Not needing versions
&lt;/h4&gt;

&lt;p&gt;This is a bit of a copout, but there are situations where you can avoid version numbers altogether. The Unison language uses hashes as identifiers, and as such identifiers point to exact objects. Adding version information would be redundant. Except perhaps as a global restriction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;So, no solution is perfect, and I'm sure there's more possibilities than this. How do we chose what is right for our project?&lt;/p&gt;

&lt;p&gt;If you're making a library, I suggest following the standards people expect. Usually that will be semver. Haskell has &lt;a href="https://pvp.haskell.org/"&gt;Haskell PVP&lt;/a&gt;. It's likely that there are a few other standards that I'm not aware of. Is cases where you're supposed to denote backward compatibility, just give up on automated versioning. This is a fuzzy quantitative problem that requires a human. It is more important to match people's assumptions than to automate versioning.&lt;/p&gt;

&lt;p&gt;In general, I'm rather skeptical of type-level "semver". It prevents type mismatches, not behavioral changes. Type mismatches cause failures at compile time. Sure, the CI pipeline breaks, but that's what it's for. Unnoticed changes in runtime behavior are far more dangerous, and automatic semver might give us an unwarranted sense of security about them when all we've done is appease the CI pipeline. In fact, for the purpose of catching potential security issues, it would be best if compile-time errors bump only the lowest version pin possible. Compile-time failures can be caught before going into production. They are not something we need extra protection against in the form of &lt;/p&gt;

&lt;p&gt;You should still use type-level "semver" when distributing through channels that expect it.&lt;/p&gt;

&lt;p&gt;But what if you're not making libraries?&lt;/p&gt;

&lt;p&gt;There are too many variables to give a single correct answer. I will insteads detail an example for choices I made on a project of my own.&lt;/p&gt;

&lt;h2&gt;
  
  
  By example
&lt;/h2&gt;

&lt;p&gt;The project I want to version is a specification in the form of text in a pdf document. What kind of changes can I expect to make?&lt;/p&gt;

&lt;p&gt;Since this is a specification, any addition of features is equally breaking. Implementations would have to support the new feature, therefore their implementation would break. However, we can perhaps subdivide changes in a more linguistic approach.&lt;/p&gt;

&lt;p&gt;First there is semantic changes. The &lt;em&gt;intention&lt;/em&gt; of the document changes. The Bedeutung from Frege's &lt;a href="https://en.wikipedia.org/wiki/Sense_and_reference"&gt;Über Sinn und Bedeutung&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then there is changes in wording without changing the intent of the document. Frege's Sinn.&lt;/p&gt;

&lt;p&gt;Finally, there's plain old typos.&lt;/p&gt;

&lt;p&gt;Unfortunately there is not automated tool that can reliably tell such changes appart. A comma can be an innocent mistake or completely change the meaning of a sentence. A repeated "not" can be a real double negation or word that accidentally got typed twice in editing. If the potential interpretation of a sentence does not change, why would I even release a new version?&lt;/p&gt;

&lt;p&gt;It appears sensible to consider any change a breaking change. If typo's are so frequent they cause too many major version bumps, I just won't release typo corrections as often. So, semantic versioning (or a similar concept) does not seem like a good choice for this project.&lt;/p&gt;

&lt;p&gt;Going back to &lt;em&gt;why&lt;/em&gt; I want version numbers&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;People should easily be able to tell who has the newest version. I need a partial order, even better if it's total.&lt;/li&gt;
&lt;li&gt;I want to be able to find the source/repository state of a specific document.&lt;/li&gt;
&lt;li&gt;I thought about distringuishing between large changes and small changes, but thought better of it. Any change may be breaking, so let's act like it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Commit hashes are insufficient because I want people to immediately know which version of a document is the latest.&lt;/p&gt;

&lt;p&gt;Commit dates would work fine for the moment. I only have 1 branch that gets released in the wild, only work from my own timezone, and don't release more often than once daily. But I don't want to be forced to maintain that situation indefinitely.&lt;/p&gt;

&lt;p&gt;Git describe would be nice, but my CI/CD pipeline is using shallow clones, so versioning may suddenly break if the last tag is farther away than the clone depth. I could parse the result of git describe and throw an error if it is unexpected. That way bad versions don't make it to release, but how would should such a broken pipeline be fixed? Bump the release number? Increase clone depth? Neither option I particularly like.&lt;/p&gt;

&lt;p&gt;But versioning is a multidimensional problem, so I'm using two strategies. Commit hashes &lt;em&gt;and&lt;/em&gt; commit dates. That will give me both identifiers and comparability (most of the time).&lt;/p&gt;

&lt;h4&gt;
  
  
  In practice
&lt;/h4&gt;

&lt;p&gt;I took the above concepts into practice with the following steps:&lt;/p&gt;

&lt;p&gt;1) Make sure the version number is being used in the document. &lt;/p&gt;

&lt;p&gt;I'm creating the document in latex and using &lt;a href="https://stackoverflow.com/questions/2033844/passing-command-line-arguments-to-latex-document"&gt;this trick&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2) Adapt the CI/CD pipeline, my build stage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${DOC}.pdf&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;my latex container&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export DATE=$(echo ${CI_COMMIT_TIMESTAMP} | sed 's/T.*//')&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export VERSION=${CI_COMMIT_SHA}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pdflatex ${ARGS} -jobname=${DOC} "\def\version{${VERSION}} \input{${DOC}.tex}" -draftmode&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pdflatex ${ARGS} -jobname=${DOC} "\def\version{${VERSION}} \input{${DOC}.tex}" -draftmode &amp;gt; /dev/null&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bibtex ${DOC}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pdflatex ${ARGS} -jobname=${DOC} "\def\version{${VERSION}} \input{${DOC}.tex}" -draftmode &amp;gt; /dev/null&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pdflatex ${ARGS} -jobname=${DOC} "\def\version{${VERSION}} \date{${DATE}} \input{${DOC}.tex}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DOC and ARGS are defined alsewhere in the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file&lt;/p&gt;

&lt;p&gt;Latex requires you to repeat build commands. Don't ask, I don't know either.&lt;/p&gt;

&lt;p&gt;That's it!&lt;/p&gt;

&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;It is harder that one would expect to do automated versioning right. The main problem is statelessness. Versions generally depend on information from past commits, but that information may not be available for efficiency. It is also quite difficult to determine useful, correct semantics for version numbers.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Planning my own programming language.</title>
      <dc:creator>DrBearhands</dc:creator>
      <pubDate>Thu, 04 Nov 2021 10:27:17 +0000</pubDate>
      <link>https://dev.to/drbearhands/planning-my-own-programming-language-5h9a</link>
      <guid>https://dev.to/drbearhands/planning-my-own-programming-language-5h9a</guid>
      <description>&lt;p&gt;During my years of writing software, I've come across a few issues with how we write software. Since I've covered my reasoning before, I will only summarize them here: type safety is nice, but doesn't extend past the memory of a single machine. I therefore want to introduce "holistic programing": instead of writing individual programs, we write the entirety of the multi-machine system.&lt;/p&gt;

&lt;p&gt;There's a few more things I want for this language.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Accessible&lt;/strong&gt;: nothing about a language matters if nobody can use it because it is too complicated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Functional, dependently typed&lt;/strong&gt;: this is the current standard for type safety. Dependent typing is not difficult, it is just very poorly supported by documentation and examples. It also requires tearing down the mental barriers between types and terms if you have prior experience in strongly typed programming.&lt;/li&gt;
&lt;li&gt;Support for &lt;strong&gt;linear values&lt;/strong&gt;: linearity is the best way to handle resources and communication that I know of. In my experience, it is not particularly hard, removes the need for other complicated language structures, and catches more problems that traditional approaches like the &lt;code&gt;with&lt;/code&gt; keyword. Unfortunately, few languages support it well.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architecture agnostic&lt;/strong&gt;: when creating systems the traditional way, we &lt;em&gt;must&lt;/em&gt; architect the solution before writing code, because we need to identify what programs to write before we can write them. That requirement disappears with hollistic (purely declarative) programming. By omitting considerations tied to an architecture or backend from the code, we can postpone optimization and architecting to a later moment. This includes all performance considerations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, I want to adopt unison's &lt;strong&gt;hash-based function identifiers&lt;/strong&gt;. Rather than using names to identify functions, it generates hashes based on its contents. This way there is a single source of truth for function references, and human-readable formatting is decoupled from program specification. Hash-based identifiers should make some things a lot easier, with modest up-front development time, as the people who made unison already did the hard work of figuring out &lt;em&gt;what&lt;/em&gt; to do. Among other things, it should simplify modules, and once I get to it, database changes.&lt;/p&gt;

&lt;p&gt;So, with the feature set of the core language broadly laid out, where do I start?&lt;/p&gt;

&lt;p&gt;I decided &lt;em&gt;not&lt;/em&gt; to fork Idris 2. Not just &lt;a href="https://dev.to/citizen428/comment/1j184"&gt;because I'm a sucker for peer pressure&lt;/a&gt;, but also because Idris 2 is a bit too far from where I want to go, and the compiler seems a tad too complicated to boot.&lt;/p&gt;

&lt;p&gt;That said, I will use it to build my language. I sorely missed dependent types the &lt;a href="https://gitlab.com/DrBearhands/fp-language-experiments/-/tree/29c9e7d6d8f07f35f509fa050accfb7f1b9b8bd0"&gt;last time I decided to make a functional programming language&lt;/a&gt; and there are not many languages that support them. Plus, none of the problems I've encountered with Idris in the past would be relevant for a compiler. That's no coincidence, since Idris 2 is self-hosted, so any such problems are likely caught by the developers.&lt;/p&gt;

&lt;p&gt;Since I'm starting from scratch, I should begin by making an AST (Abstract Syntax Tree, the type representation of the language syntax), followed by an evaluator and a parser. I will also need to research &amp;amp; implement a type calculus (likely quantitative type theory), and I will need to implement hash-generation. That seems like a solid beginning. Concurrently, there is a fundamental issues I need to resolve: "real" async interop, particularly concurrent database use.&lt;/p&gt;

&lt;p&gt;With real async interop, I mean operations that are fundamentally asynchronous. A Turing-complete language may be able to compute anything that is computable, but that does not include real-world interactions, nor does it mean there is a clear mapping from/to asynchronous and functional representation. For the most part, I am fine with the worst case scenario where I just cannot do this, with one exception: concurrent database use.&lt;/p&gt;

&lt;p&gt;Databases are pretty common, and so is having multiple users/processes accessing one concurrently. Unfortunately I am not aware of any calculus that expresses concurrent database read/write in such a way that meaningful analysis and optimization can be performed. Linear types can sort-of model database changes, but not concurrent ones.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;someWriteOp&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Table&lt;/span&gt; &lt;span class="err"&gt;⊸&lt;/span&gt; &lt;span class="kt"&gt;Table&lt;/span&gt; 
&lt;span class="n"&gt;someWriteOp&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kr"&gt;let&lt;/span&gt;
    &lt;span class="n"&gt;row'&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doSomethingToRow&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;
  &lt;span class="kr"&gt;in&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row'&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above may be correct, but consumes the &lt;em&gt;entire&lt;/em&gt; table for just 1 row. Native lenses may be of help, but I rather stay away from anything native.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Prematurely hand-optimizing C++ code for shits and giggles</title>
      <dc:creator>DrBearhands</dc:creator>
      <pubDate>Mon, 01 Nov 2021 06:50:18 +0000</pubDate>
      <link>https://dev.to/drbearhands/prematurely-hand-optimizing-c-code-for-shits-and-giggles-3i31</link>
      <guid>https://dev.to/drbearhands/prematurely-hand-optimizing-c-code-for-shits-and-giggles-3i31</guid>
      <description>&lt;p&gt;Left in the void that comes after abandoning a project, I decided to port a previous JavaScript / WebGL project to C++. Changing languages meant a complete overhaul of some core systems. I was looking at a &lt;a href="https://austinmorlan.com/posts/entity_component_system/"&gt;post by Austin Morlan about ECS achitectures&lt;/a&gt; for inspiration.&lt;/p&gt;

&lt;p&gt;Here I saw this procedure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;EntityManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Initialize the queue with all possible entity IDs&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;MAX_ENTITIES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mAvailableEntities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this isn't bad code. Nonetheless, I did not like it. And not just because I have a distaste for CamelCase.&lt;/p&gt;

&lt;p&gt;Initializing the value &lt;code&gt;mAvailableEntities&lt;/code&gt; potentially takes a long time. In the example &lt;code&gt;MAX_ENTITIES&lt;/code&gt; was set to 5k, so it's not so bad, but I may require far more entities than that.&lt;/p&gt;

&lt;p&gt;Had this been a regular project with a clear goal, the correct approach would be to leave the code as is, since it's certainly readable. Then &lt;em&gt;if&lt;/em&gt; we run into performance issues in practice, find the procedures taking up the most times and optimize &lt;em&gt;those&lt;/em&gt;, and &lt;a href="https://youtu.be/r-TLSBdHe1A"&gt;&lt;em&gt;use statistical analysis&lt;/em&gt; to determine if our changes actually mattered&lt;/a&gt;. That is the correct way to optimize performance. That's not what I'm going to do here.&lt;/p&gt;

&lt;p&gt;In this particular architecture, &lt;code&gt;mAvailableEntities&lt;/code&gt; is a pool of &lt;em&gt;all available entities&lt;/em&gt;. That is why it must be filled. We cannot use a simple incrementing counter because entities can be destroyed as well, in which case we'd want to recycle them.&lt;/p&gt;

&lt;p&gt;Instead, we can combine the incrementing counter and the recycling pool. If the pool is not empty, grab an element from there, otherwise, use the counter. Unfortunately, that sentence contains the word "if".&lt;/p&gt;

&lt;p&gt;Naive implementation of the above is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include &amp;lt;queue&amp;gt;
#include &amp;lt;cstdint&amp;gt;
&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;recycling_pool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="nf"&gt;create_entity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;recycling_pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recycling_pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;recycling_pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(I've left out the check to prevent going over &lt;code&gt;MAX_ENTITIES&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;and as we see on &lt;a href="https://godbolt.org/"&gt;compile explorer&lt;/a&gt;, this compiles to conditional jumps (jne):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight llvm"&gt;&lt;code&gt;&lt;span class="err"&gt;create_entity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
        &lt;span class="err"&gt;movq&lt;/span&gt;    &lt;span class="err"&gt;recyclingPool+&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;%rip&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;%rax&lt;/span&gt;
        &lt;span class="err"&gt;cmpq&lt;/span&gt;    &lt;span class="err"&gt;recyclingPool+&lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;%rip&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;%rax&lt;/span&gt;
        &lt;span class="err"&gt;pushq&lt;/span&gt;   &lt;span class="nv"&gt;%r12&lt;/span&gt;
        &lt;span class="err"&gt;jne&lt;/span&gt;     &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;L9&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;conditional jumps can be a performance problem. &lt;/p&gt;

&lt;p&gt;Modern CPUs have deep pipelines. Rather than fully executing one instruction and then moving on to the next one, they execute every instruction in multiple steps like an assembly line. While instruction &lt;code&gt;n&lt;/code&gt; is going through step &lt;code&gt;x&lt;/code&gt;, instruction &lt;code&gt;n-1&lt;/code&gt; (the instruction that came before &lt;code&gt;n&lt;/code&gt;) is going through step &lt;code&gt;x+1&lt;/code&gt; and &lt;code&gt;n+1&lt;/code&gt; is going through step &lt;code&gt;n-1&lt;/code&gt;. A pipeline of 20 steps is essentially doing 20 things at the same time and therefore ~20x as fast as it would be executing instructions one-by-one.&lt;/p&gt;

&lt;p&gt;These pipelines require knowing ahead of time which instructions are coming up, which is uncertain with conditional jumps. Branch prediction works in some cases, such as loops, but not always.&lt;/p&gt;

&lt;p&gt;So how do we get rid of branching?&lt;/p&gt;

&lt;p&gt;The concept is conditional write-back. Rather than pick one branch or another, we do all branches, but don't write back the result in some cases. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.chessprogramming.org/Avoiding_Branches"&gt;C++ does not support conditional writeback directly, so we improvise a bit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, replace &lt;code&gt;std::queue&lt;/code&gt; with a stack, and just use a primitive array &lt;code&gt;entity recycling_pool[MAX_ENTITIES]&lt;/code&gt;. This will be a bit easier to hack.&lt;/p&gt;

&lt;p&gt;Then, we specify entity 0 to be invalid. We initialize &lt;code&gt;recycling_pool&lt;/code&gt; with a &lt;code&gt;0&lt;/code&gt; in the first element. Now we can take the head of &lt;code&gt;recycling_pool&lt;/code&gt; and it will function both as condition and value. This is rather like &lt;code&gt;Maybe Entity&lt;/code&gt; in e.g. Haskell, but more efficient and far less safe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="nf"&gt;create_entity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="n"&gt;new_entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recycling_pool&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;unused_idx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;b_stack_empty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;new_entity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have divergence: if not &lt;code&gt;b_stack_empty&lt;/code&gt;, we want to &lt;code&gt;pop&lt;/code&gt; the stack, otherwise, we want to increment the counter.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;b_stack_empty&lt;/code&gt; is a boolean with the value 0 or 1, since it was generated from the &lt;code&gt;!&lt;/code&gt; operation (anything that isn't 0 counts as true in C++, but true as output is 1). we can abuse this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  unused_idx -= !b_stack_empty;
  gen_counter += b_stack_empty;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(NOTE: &lt;code&gt;gen_counter&lt;/code&gt; starts at 0, but valid values start at 1, so it's increment-then-use)&lt;/p&gt;

&lt;p&gt;this is a specialized form of conditional write-back.&lt;/p&gt;

&lt;p&gt;Then, if &lt;code&gt;b_stack_empty&lt;/code&gt;, we want to replace &lt;code&gt;new_entity&lt;/code&gt;, which will be an all-0 bits invalid value, with the current value of &lt;code&gt;gen_counter&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;  &lt;span class="n"&gt;new_entity&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;b_stack_empty&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;gen_counter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;since &lt;code&gt;b_stack_empty&lt;/code&gt; can have values 0 or 1, a non empty stack will evaluate to &lt;code&gt;0 &amp;amp; gen_counter&lt;/code&gt;, which equals 0, whereas an empty stack will give &lt;code&gt;-1 &amp;amp; gen_counter&lt;/code&gt; and since we're dealing with &lt;em&gt;unsigned&lt;/em&gt; integers, -1 is all 1's in binary, so &lt;code&gt;-1 &amp;amp; gen_counter&lt;/code&gt; equals &lt;code&gt;gen_counter&lt;/code&gt;. In the latter case we also know &lt;code&gt;new_entity = 0&lt;/code&gt;, and &lt;code&gt;0 + gen_counter = gen_counter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And so the full code (minus checking MAX_ENTITIES violation) is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include &amp;lt;cstdint&amp;gt;
&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="n"&gt;unused_idx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="n"&gt;gen_counter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="n"&gt;MAX_ENTITIES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="n"&gt;recycling_pool&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAX_ENTITIES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="nf"&gt;create_entity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="n"&gt;new_entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recycling_pool&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;unused_idx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;b_stack_empty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;new_entity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;unused_idx&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;b_stack_empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;gen_counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;b_stack_empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;new_entity&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;b_stack_empty&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;gen_counter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new_entity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compiler explorer confirms there are no conditional jumps.&lt;/p&gt;

&lt;p&gt;The resulting assembly is also a lot smaller (24 lines vs 103), but I expect that is mostly due to the omission of &lt;code&gt;std::queue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I want to reiterate that this is &lt;em&gt;dumb&lt;/em&gt;. The code is likely to have gotten slower in practice, even though it is more consistent, because branch prediction is probably right more often than not, and now we're executing &lt;em&gt;all&lt;/em&gt; the branches. Code maintainability has also suffered.&lt;/p&gt;

&lt;p&gt;This is merely an interesting learning experience.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>performance</category>
    </item>
    <item>
      <title>Idris2+WebGL: Hiatus</title>
      <dc:creator>DrBearhands</dc:creator>
      <pubDate>Thu, 28 Oct 2021 14:35:33 +0000</pubDate>
      <link>https://dev.to/drbearhands/idris2webgl-hiatus-56o</link>
      <guid>https://dev.to/drbearhands/idris2webgl-hiatus-56o</guid>
      <description>&lt;p&gt;I'm putting my WebGL in Idris project on hiatus. &lt;br&gt;
I started this project to get a feeling for how far I could take type-safety using dependent typing. Unfortunately, I am no longer constrained by dependent typing in general, but by Idris in particular. I might continue once significant progress has been made on the Idris compiler.&lt;/p&gt;

&lt;p&gt;I've spent days debugging problems that turned out to be compiler problems. Error messages are extremely unhelpful. The prelude sometimes gets in the way. The syntax can be hard to read. Linear types exist but are not well-supported. The compiler code base is hard to get in to. Documentation is quite basic. In short, using Idris "in anger" is a pain in the butt, and if your problem requires Idris' particular feature set, you are probably already very angry. One doesn't typically use quantitive type theory to increment a counter. Although that is exactly whet I did in the last entry.&lt;/p&gt;

&lt;p&gt;I'm not blaming Idris' devs for these problems. Their scope is large and time limited. Working in academia probably also forces a focus onto e.g. publications rather than nice error messages.&lt;/p&gt;

&lt;p&gt;I don't like ending this project, because I hoped it could unify my love for type-safety with my love for 3D graphics, but after months of development I still only have a spinning white trianle, while I'm considering how supermonads qualified with dependently-typed destructors might allow monadic error handling for linear values if I can get idris to auto-construct destructors for values derived from function application. Needless to say my love for 3D graphics isn't particularly fulfilled.&lt;/p&gt;

&lt;p&gt;However, I did sort-of get my answer.&lt;/p&gt;

&lt;p&gt;I'm sold on dependent typing. It is actually &lt;em&gt;easier&lt;/em&gt; to use dependent types. At some point there will be something you wish to express that is easy with dependent types, but quite complex otherwise. Dependent types are just doing to types what you are already doing in terms. Not conceptually difficult, just a different way of doing things that takes some "unlearning".&lt;/p&gt;

&lt;p&gt;Linear types on the other hand are an entirely new thing. More research is needed to make them fun to use in practice, but they are already damned useful.&lt;/p&gt;

</description>
      <category>idris</category>
      <category>webgl</category>
    </item>
    <item>
      <title>Steam blockchain ban: pragmatic or essential?</title>
      <dc:creator>DrBearhands</dc:creator>
      <pubDate>Wed, 20 Oct 2021 07:58:32 +0000</pubDate>
      <link>https://dev.to/drbearhands/steam-blockchain-ban-pragmatic-or-essential-2eao</link>
      <guid>https://dev.to/drbearhands/steam-blockchain-ban-pragmatic-or-essential-2eao</guid>
      <description>&lt;p&gt;Steam has recently explicitly banned games built on blockchain. Specifically, ones that allowed the exchange of cryptocurrencies and NFTs. &lt;a href="https://www.reddit.com/r/pcgaming/comments/q8pxg0/steam_will_be_kicking_all_blockchain_games_off/"&gt;Reactions on reddit&lt;/a&gt; suggest this was a pretty popular move. It appears these games are perceived to be pyramid schemes; an excuse with little inherent worth, existing merely to drive value of the underlying NFTs or cryptocurrencies. In this sense, they have a similar role to cosmetics products in multi-level marketing.&lt;/p&gt;

&lt;p&gt;I tend to agree with the sentiment, for reasons that will become apparent.&lt;/p&gt;

&lt;p&gt;Regardless, the ban raises an interesting question. Let's accept blockchain games were low-quality facades for pyramid schemes. Is this causation or correlation? Can there be any legitimate reason for using a blockchain or some other DLT* in gaming? Or are games and DLTs theoretically incompatible?&lt;/p&gt;

&lt;p&gt;At their core, DLTs are methods used to agree on the order of events when nobody can be trusted**. &lt;/p&gt;

&lt;p&gt;Initially that would appear to make DLTs a bad fit for games. In games, everybody trusts the developer. You run their code on your machine, you use their servers. This is doubly true for steam games, where steam/valve is also a trusted party.&lt;/p&gt;

&lt;p&gt;But let's suppose we don't &lt;em&gt;want&lt;/em&gt; to maintain servers throughout the life of our game and still want some kind of persistent public state (as in MMOs or competitive speed running). I will be generous and ignore software updates. Can blockchain help?&lt;/p&gt;

&lt;p&gt;There are a few major limitations to DLTs that are relevant for gaming:&lt;/p&gt;

&lt;h5&gt;
  
  
  Not real time
&lt;/h5&gt;

&lt;p&gt;Time is subjective. So relativity theory tells us. This is not a problem for games with trusted, authoritative servers, as the discrepancies are small in practice. But if the point is to avoid trusted parties, time must be expressed objectively, which is impossible even before accounting for things like latency and partitions. A blockchain game can therefore not have meaningful real-time mechanics.&lt;/p&gt;

&lt;h5&gt;
  
  
  Replication delays
&lt;/h5&gt;

&lt;p&gt;Blockchains are replicated. That means every change in public data will be somewhat slow. Changes need to be replicated to other servers. Moving away from proof-of-work does nothing against it. Many white papers conveniently forget to mention this.&lt;/p&gt;

&lt;h5&gt;
  
  
  Leavers
&lt;/h5&gt;

&lt;p&gt;While players could interact with low latency through a side-channel, these channels can be stopped by either party at any time. It is not possible to determine who left a game without a central party, just that communication between x and y has not finished (yet). Partitions are subjective.&lt;/p&gt;

&lt;h5&gt;
  
  
  No hosting incentives
&lt;/h5&gt;

&lt;p&gt;It is unclear how to incentivize hosting blockchains &lt;em&gt;without&lt;/em&gt; some kind of cryptocoin pyramid scheme. Blockchains are not free, they are even more expensive than trusted servers.&lt;/p&gt;

&lt;h5&gt;
  
  
  Code limitations
&lt;/h5&gt;

&lt;p&gt;A lot of the code used in game is not well defined or non-deterministic. Drivers for instance are often an unknown. It may be possible to "fix" this issue, but doing so is a lot of work, much more than making the game itself.&lt;/p&gt;

&lt;h5&gt;
  
  
  Permanent mistakes
&lt;/h5&gt;

&lt;p&gt;It is quite common for exploits in-game to lead to some kind of undesirable global state. Items are stolen, in-game economy gets trashed, scarce virtual resources are depleted... without trusted authoritative parties exploits cannot be rectified.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;I started writing this article thinking there might be an interesting theoretical benefit to using blockchain in gaming. The fact that the entire game world is virtual appeared to make the approach more sensible than many of the real-life usage proposals. I no longer believe so.&lt;/p&gt;

&lt;p&gt;Because of aforementioned restrictions, I don't see any avenues for bona fide game development using blockchain. Many game mechanics simply cannot be expressed objectively, without trusts. A game built on top of blockchain is effectively an overblown graphical interface over virtual asset trading.&lt;/p&gt;

&lt;p&gt;Furthermore, the benefits of blockchains to consumers are outclassed by 3rd-party servers. Trust is an incredibly useful resource, and getting rid of it just isn't particularly beneficial to gaming.&lt;/p&gt;

&lt;h4&gt;
  
  
  Footnotes:
&lt;/h4&gt;

&lt;p&gt;* &lt;a&gt;&lt;/a&gt; Distributed Ledger Technology. A class of systems developed to do accounting without a trusted central party.&lt;br&gt;
** &lt;a&gt;&lt;/a&gt; This is an oversimplification, but far more accurate than most blockchain/DLT articles. Even in well-trusted newspapers.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>games</category>
      <category>cryptogaming</category>
      <category>nft</category>
    </item>
    <item>
      <title>Feedback request on "hollistic" programming language idea</title>
      <dc:creator>DrBearhands</dc:creator>
      <pubDate>Fri, 15 Oct 2021 11:09:29 +0000</pubDate>
      <link>https://dev.to/drbearhands/feedback-request-on-hollistic-programming-language-idea-30d5</link>
      <guid>https://dev.to/drbearhands/feedback-request-on-hollistic-programming-language-idea-30d5</guid>
      <description>&lt;p&gt;I want to make my own programming language, but I don't want to waste years of my life on a silly idea nobody would ever want, so here I am writing down my ideas and asking for feedback.&lt;/p&gt;

&lt;p&gt;Pure, functional programming, particularly the dependently typed variety, holds a lot of potential business value. It lets me express (parts of) the spec as types, and ensures my implementation matches the types, and therefore the spec. If there was no spec, the types are now the (proto-)spec. The same program in Haskell or Idris will have fewer faults than something in, say, Javascript, C++, or Java. At least, that is both my personal experience and what I keep hearing from other users. When strictly enforced, it is also a huge boon to security, especially when using third party libraries, which sometimes &lt;a href="https://www.theregister.com/2018/11/26/npm_repo_bitcoin_stealer/"&gt;steal your cryptocurrencies&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is a huge limitations in this approach: specifying a solution as programs. Type-safety ends at I/O, so defining a solution in terms of multiple communicating programs right from the get-go loses type-safety unnecessarily. E.g. in a CRUD application it is more insightful to declare how responses are produced for requests on an API endpoint, without mixing in explicit I/O operations to get data from one machine to the next. In theory, pure functions have explicit data-dependencies, so we can split off evaluation over nodes at a later point. &lt;/p&gt;

&lt;p&gt;I will call the approach of leaving program I/O undefined "hollistic programming", as it only specifies I/O of the whole system/solution.&lt;/p&gt;

&lt;p&gt;As an example, if we have a function:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;f : Int
f = g + h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;we could leave the definition as-is in the code, and at compile/deploy time decide to evaluate &lt;code&gt;g&lt;/code&gt; on a different node/thread/whatever. If we had to specify this as a program immediately, the type of &lt;code&gt;f&lt;/code&gt; would be lifted to &lt;code&gt;IO Int&lt;/code&gt;, which tells us next-to nothing about error handling, security, or correctness. The code would also be full of explicit communication.&lt;/p&gt;

&lt;p&gt;There are other such decisions that are often made in code, but (assuming temination and infinite resources) make no difference to the result of the evaluation: forking, vectorizing, monomorphizing, boxing, type-unrolling, type-mapping, evaluation strategy, heap recycling, choice of allocator...&lt;/p&gt;

&lt;p&gt;What I'm suggesting is, essentially, a fairly extreme separation of concerns.&lt;/p&gt;

&lt;p&gt;But if not with an IO monad, how should I/O be modelled? The precise model would be user-defined, specific to a solution. A CRUD application has conceptually different I/O than an embedded system, or a video game. IO would be declared by abstract linear types &lt;code&gt;c&lt;/code&gt;, denoting independent I/O channels, and handler functions &lt;code&gt;c ⊸ c&lt;/code&gt;. This is a generalized case of &lt;code&gt;IO ()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveats
&lt;/h3&gt;

&lt;p&gt;I realize there are some caveats that make hollistic programming non-trivial. I will list the ones I already thought about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Databases/shared state. 

&lt;ul&gt;
&lt;li&gt;How do I model inherently concurrent state changes? (as opposed to concurrency for the sake of speed optimization). I will have to formalize transactional state changes. I do not know how to do this &lt;em&gt;elegantly&lt;/em&gt;. Examples are multiple clients accessing the same database and asynchronous display/update in videogames.&lt;/li&gt;
&lt;li&gt;Data in databases persists over code changes. To preserve correctness and data, compilation would become stateful. This is difficult, but on the flipside, anything is a step up from current &lt;em&gt;ignoramus (et ignorabimus)&lt;/em&gt; approaches.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Adding communication adds potential for errors by partitions. Bottoms are inevitable even in the best case due to potential power loss. Nevertheless, smaller bottoms are better. I want to &lt;em&gt;decrease&lt;/em&gt; uncertainty, not increase it. Could be adressed by lifting to arrows with timeout condition in spec, or ignored with compile argument for non-critical applications.&lt;/li&gt;
&lt;li&gt;Some evaluation strategies (lazy, eager, greedy) may bottom when others don't. I'm not very concerned about this in practice. Most functions in BLOBA (Boring Line-of-Business Applications) are provably terminating in O(n) in my experience. In the worst case scenario, I can just force lazy evaluation on functions that cannot be proved to terminate by argument reduction. Good enough.&lt;/li&gt;
&lt;li&gt;Other processes on a system might break assumptions made by the compiler. E.g. a large constant value stored in a file might get deleted. I don't find this a valid concern. Messing with a system that the compiler assumes is dedicated is like changing bytecode, things will break.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Other stuff
&lt;/h3&gt;

&lt;p&gt;There are a few other, less novel and ambitious, things I want to achieve in my language&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limited feature set. I want people to actually try this out. Make dependently typed programming as approachable as possible.&lt;/li&gt;
&lt;li&gt;Removing primitive types from the language. What is primitive depends on architecture. Booleans and floats are good examples of common primitives that don't always exist. User-specified mappings defined at compile-time should be used instead.&lt;/li&gt;
&lt;li&gt;(Semi-)automatic type unrolling/optimization: e.g. &lt;code&gt;{Fin x | x &amp;lt;= (2^32)}&lt;/code&gt; to &lt;code&gt;int32&lt;/code&gt;, and &lt;code&gt;Vect a n&lt;/code&gt; to &lt;code&gt;a[n]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Encourage using correct types over "one size fits all". E.g. fixed point over floats and pretty much anything over string. If nothing else, strings and floats should not be in the prelude.&lt;/li&gt;
&lt;li&gt;Raise warnings, or have a similar mechanism, for dubious bits/changes in code (e.g. &lt;code&gt;unsafe&lt;/code&gt; operations).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My current plan of attack is to fork Idris 2, remove the things that are incompatible with my ideas (primitive types, interfaces, probably every single library), mock about to get a better feeling about how to define systems if not I/O monads, and start building a custom, interactive backend. I am not sure that this is sensible, or that I will stray too far from Idris to benefit from future updates.&lt;/p&gt;

&lt;p&gt;Your feedback is appreciated.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Idris2+WebGL, part #17: A Hoare state failure</title>
      <dc:creator>DrBearhands</dc:creator>
      <pubDate>Fri, 08 Oct 2021 11:21:01 +0000</pubDate>
      <link>https://dev.to/drbearhands/idris2-webgl-part-17-a-hoare-state-failure-2o0l</link>
      <guid>https://dev.to/drbearhands/idris2-webgl-part-17-a-hoare-state-failure-2o0l</guid>
      <description>&lt;p&gt;As explained in the last log entry, I set out to use decorated state monads to prove certain properties of a program.&lt;/p&gt;

&lt;p&gt;Since I have once already, somewhat unsuccesfully, used indexed monads in Haskell, I decided to aim big and &lt;a href="https://dev.to/drbearhands/the-hardest-thing-i-ever-did-explained-as-simply-as-possible-jg4"&gt;tackle Hoare state monads&lt;/a&gt;. I've changed a few details since writing that article, such as adding a &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; operator and replacing my custom &lt;code&gt;exists&lt;/code&gt; function with a standard dependent pair (both are existential quantification, but the latter has nicer syntactic sugar).&lt;br&gt;
While I did manage to get Hoare state monads working in Idris, I found their use rather frustrating. The main problem is that the type checker is strugling to find proofs, requiring manual proofs from the programmer. What's more, vague error messages in Idris 2 and the unability to put holes in some places makes the job substantially harder.&lt;/p&gt;

&lt;p&gt;For example, consider the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;init0 : HoareStateMonad Nat Top () (\_, _, s =&amp;gt; s = 0)
init0 = MkHSMonad $ \_ =&amp;gt; MkPostS () 0

increment : HoareStateMonad Nat Top () (\s1, _, s2 =&amp;gt; s2 = s1 + 1)
increment = MkHSMonad $ \s =&amp;gt; MkPostS () (s + 1)

init1 : HoareStateMonad Nat Top () (\_, _, s =&amp;gt; s = 1)
init1 = init0 &amp;gt;&amp;gt; increment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember that &lt;code&gt;HoareStateMonad s pre a post&lt;/code&gt; considers a state &lt;code&gt;s&lt;/code&gt;, a precondition &lt;code&gt;pre : s -&amp;gt; Type&lt;/code&gt; over an input state of type &lt;code&gt;s&lt;/code&gt;, a return-type &lt;code&gt;a&lt;/code&gt; and a postcondition &lt;code&gt;post : s -&amp;gt; a -&amp;gt; s -&amp;gt; Type&lt;/code&gt; over input state, return type, and output state.&lt;/p&gt;

&lt;p&gt;As such, &lt;code&gt;init0&lt;/code&gt; changes the state of a &lt;code&gt;Nat&lt;/code&gt;, works for any input state (&lt;code&gt;Top&lt;/code&gt; holds for any value), returns a unit, and guarantees that the output state is &lt;code&gt;0&lt;/code&gt;. Similarly, the &lt;code&gt;increment&lt;/code&gt; function guarantees that the output state is the input state + 1. It is obvious to a human that the postcondition of &lt;code&gt;init1&lt;/code&gt;, which first sets the state to 0 and then adds 1 to it, is that the output state is 1.&lt;/p&gt;

&lt;p&gt;For the typechecker, this is a little harder. First is the simple issue of how the bind (&lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt;) operation has been defined, the type signatures end in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HoareStateMonad s p1 a q1
-&amp;gt; ((x : a) -&amp;gt; HoareStateMonad s (p2 x) b (q2 x))
-&amp;gt; HoareStateMonad s (bind_pre p1 q1 p2) b (bind_post q1 q2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;so idris excepts the resulting postconditions to be &lt;code&gt;bind_post q1 q2&lt;/code&gt;, which specifically results in&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(x : a ** (s2 : s ** (q1 s1 x s2, q2 x s2 y s3)))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and not any arbitrary thing that can be derived from &lt;code&gt;bind_post q1 q2&lt;/code&gt;. In our case, the typechecker will conclude:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(x : a ** (s2 : s ** (s2 = 0, s3 = s2 + 1)))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;rather than&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;s3 = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nevertheless, since we can prove the latter from the former, we want the typechecker to accept this. A similar, but contravariant rather than covariant, situation occurs for the precondition.&lt;/p&gt;

&lt;p&gt;So I've experimented with a &lt;code&gt;simplify&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;simplify : {0 s : Type} 
        -&amp;gt; {0 a : Type}
        -&amp;gt; {0 preA : s -&amp;gt; Type}
        -&amp;gt; {0 preB : s -&amp;gt; Type}
        -&amp;gt; {auto 0 fPre : {s1 : s} -&amp;gt; preB s1 -&amp;gt; preA s1}
        -&amp;gt; {0 postA : s -&amp;gt; a -&amp;gt; s -&amp;gt; Type} 
        -&amp;gt; {0 postB : s -&amp;gt; a -&amp;gt; s -&amp;gt; Type} 
        -&amp;gt; {auto 0 fPost : {s1 : s} -&amp;gt; {x : a} -&amp;gt; {s2 : s} -&amp;gt; postA s1 x s2 -&amp;gt; postB s1 x s2} 
        -&amp;gt; HoareStateMonad s preA a postA
        -&amp;gt; HoareStateMonad s preB a postB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I can use this explicitely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;init1 : HoareStateMonad Nat Top () (\_, _, s =&amp;gt; s = S Z)
init1 = simplify {fPost=fPost} $ init0 &amp;gt;&amp;gt; increment
  where
    fPost : {s2 : Nat} 
          -&amp;gt; (((e1 : () ** (e2 : Nat ** (e2 = Z, s2 = S e2)))))
          -&amp;gt; (s2 = S Z)
    fPost (() ** (e2 ** (p1, p2))) = replace {p = \e =&amp;gt; s2 = S e} p1 p2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but this is not a particularly easy task. Expecting programmers to provide these proofs all throughout the code base is not realistic. I have not found a way to derive them automatically (although I believe it could theoretically be done).&lt;/p&gt;

&lt;p&gt;This, for now, concludes my forray into Hoare state monad. The conclusion being that it is too cumbersome in the current state of Idris 2. Perhaps language updates will change things. If you want to mess with it yourself you can get the code in the &lt;a href="https://gitlab.com/DrBearhands/idris-linear/-/tree/hoare-state"&gt;hoare-state branch&lt;/a&gt; of my idris-linear repository (there is no actual linear variant of the Hoare state monad yet), and in particular the &lt;a href="https://gitlab.com/DrBearhands/idris-linear/-/tree/487e3a22876119596301bde58c7ac4ed7acc93f2"&gt;latest commit at the time of writing&lt;/a&gt; in that branch.&lt;/p&gt;

</description>
      <category>idris</category>
      <category>functional</category>
      <category>webgl</category>
    </item>
    <item>
      <title>The hardest thing I ever did explained as simply as possible.</title>
      <dc:creator>DrBearhands</dc:creator>
      <pubDate>Sun, 05 Sep 2021 08:58:17 +0000</pubDate>
      <link>https://dev.to/drbearhands/the-hardest-thing-i-ever-did-explained-as-simply-as-possible-jg4</link>
      <guid>https://dev.to/drbearhands/the-hardest-thing-i-ever-did-explained-as-simply-as-possible-jg4</guid>
      <description>&lt;p&gt;A while ago, I came across a situation where I needed to know things about some hidden state at compile time. Traditionally, this is done using &lt;em&gt;Hoare logic&lt;/em&gt;. In Hoare logic, every statement has a precondition and a postcondition. That is, what must be true before the statement and what will be true after the statement. For the statement "set &lt;code&gt;x&lt;/code&gt; to &lt;code&gt;7&lt;/code&gt;", the precondition is that &lt;code&gt;x&lt;/code&gt; exists, and the postcondition is that is &lt;code&gt;x = 7&lt;/code&gt;. We can chain multiple statements and get a final postcondition using the rules of Hoare logic.&lt;/p&gt;

&lt;p&gt;Hoare logic is limited, which is one reason I strongly prefer (total) functional programming over imperative programming. Nevertheless, even functional programmers must deal with mutable state at some point. Generally we do this with a function of type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;s -&amp;gt; s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;s&lt;/code&gt; is the type of the state. That is, a function that takes as state as input, and produces a new state as output. A state-changing function may also return some value, so the actual type of the function is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;s -&amp;gt; (a, s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;a&lt;/code&gt; is the type of the return value. In functional programming we use tuples to "return" multiple values. When we define how several state-changing functions can be chained together, they are called &lt;em&gt;monads&lt;/em&gt;. You don't need to understand what that means exactly. "Monad" is just a mathematical name for a certain pattern.&lt;/p&gt;

&lt;p&gt;It seemed what I wanted was Hoare logic over state monads. I came across a paper about the &lt;a href="http://www.cs.ru.nl/~wouters/Publications/HoareLogicStateMonad.pdf"&gt;Hoare state monad&lt;/a&gt;. With the knowledge I had, this was one of the most difficult things I have ever implemented. I had already given up on Hoare state monads at least twice. This time I finally managed it after a full week. I feel that not sharing this journey would be a waste. Especially since they will probably turn out to be too complicated for the purpose I had in mind.&lt;/p&gt;

&lt;p&gt;The code in this article is what I actually used to deconstruct the problem for myself. Plus a few extras for things that are only obvious to me.&lt;/p&gt;

&lt;p&gt;Not every language can express Hoare state monad, we will need a sufficiently powerful type system. I was using Idris 2, so this was not a problem. Don't worry, I will go through any unusual concepts before using them.&lt;/p&gt;

&lt;p&gt;First, let's make our own state monad. I'm going to use a hardcoded state, usually this would be variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data MyState = Foo | Bar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For those unfamiliar with sum-types: the above declares that a value of type &lt;code&gt;MyState&lt;/code&gt; can be either &lt;code&gt;Foo&lt;/code&gt; or &lt;code&gt;Bar&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We go on to create a state monad for MyState, you might be unfamiliar with the notation so I will explain it afterward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data MyStateMonad : a -&amp;gt; Type where
  MkMyStateMonad : (MyState -&amp;gt; (a, MyState)) -&amp;gt; MyStateMonad a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that a single colon indicates a type declaration in Idris. E.g. &lt;code&gt;x : Int&lt;/code&gt; means "x is an integer".&lt;/p&gt;

&lt;p&gt;The first line, &lt;code&gt;data MyStateMonad : a -&amp;gt; Type where&lt;/code&gt; declares that the &lt;code&gt;MyStateMonad&lt;/code&gt; needs some &lt;code&gt;a&lt;/code&gt; as input to make a &lt;code&gt;Type&lt;/code&gt;. This is similar to arrays. In statically typed languages, we don't have just "an array", we have e.g. "an array of integers". We must specify what's "inside" it. Similarly we can have a state monad (think of it as a statement) that returns an integer &lt;code&gt;MyStateMonad Int&lt;/code&gt;, or a string &lt;code&gt;MyStateMonad String&lt;/code&gt;, or something else.&lt;/p&gt;

&lt;p&gt;Below the data declaration are all the type's constructors, only &lt;code&gt;MkMyStateMonad&lt;/code&gt; in this case. The constructor has certain arguments, &lt;code&gt;(MyState -&amp;gt; (a, MyState))&lt;/code&gt; in this case. Recall state-changing functions are &lt;code&gt;s-&amp;gt;(a,s)&lt;/code&gt;, with &lt;code&gt;s=MyState&lt;/code&gt; in this case. The constructor also has a return type, &lt;code&gt;MyStateMonad a&lt;/code&gt;, which must match the type given in the data declaration header. The &lt;code&gt;a&lt;/code&gt; is variable in this context, but every &lt;code&gt;a&lt;/code&gt; must match, so the return type of the function defines what the type of &lt;code&gt;MyStateMonad a&lt;/code&gt; is. E.g.: for a function &lt;code&gt;f : MyState -&amp;gt; (Int, MyState)&lt;/code&gt;, we know &lt;code&gt;MkMyStateMonad f : MyStateMonad Int&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But what about input? Idris is a curried language, meaning we can have the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;someFunction : Int -&amp;gt; Int
someFunction = (+) 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In other words, a function of type &lt;code&gt;MyState -&amp;gt; (a, MyState)&lt;/code&gt; can be a closure&lt;br&gt;
of as many arguments as you want.&lt;/p&gt;

&lt;p&gt;State monads are useful as is. They let us use do-notation rather than less readable pattern matching:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;do
  x &amp;lt;- actionA
  actionB
  actionC x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;vs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\s1 =&amp;gt;
  let
    (x, s2) = actionA s1
    s3 = actionB s2
  in
    actionC x s3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this is not what we set out to do though, so let's talk about proofs in Idris.&lt;/p&gt;

&lt;p&gt;You may have heard that types are propositions and values are proofs of propositions. The value &lt;code&gt;7&lt;/code&gt; is proof that &lt;code&gt;Int&lt;/code&gt;s exist. &lt;code&gt;7&lt;/code&gt; inhabits &lt;code&gt;Int&lt;/code&gt;. But we can do something a bit more interesting.&lt;br&gt;
Remember how &lt;code&gt;MyStateMonad&lt;/code&gt; needed some &lt;code&gt;a&lt;/code&gt;? We can do something similar with some other type over &lt;code&gt;a&lt;/code&gt;, say &lt;code&gt;P&lt;/code&gt;, so that &lt;code&gt;P a&lt;/code&gt; only holds for some &lt;code&gt;a&lt;/code&gt;. We do this by restricting what constructors are available.&lt;/p&gt;

&lt;p&gt;A good example is the &lt;code&gt;Equal&lt;/code&gt; type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data Equal : a -&amp;gt; b -&amp;gt; Type where
  Refl : Equal x x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we can use the &lt;code&gt;Refl&lt;/code&gt; constructor to prove &lt;code&gt;Equal x x&lt;/code&gt;, but there is no way to get an &lt;code&gt;Equal x y&lt;/code&gt; value. &lt;code&gt;Equal x y&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; a valid type, but there is no &lt;em&gt;value&lt;/em&gt; of that type unless &lt;code&gt;x = y&lt;/code&gt;. Therefore, if you can pass a value with type &lt;code&gt;Equal x y&lt;/code&gt; to a function, you know within that function that &lt;code&gt;x = y&lt;/code&gt;. There are more complex cases, of course, such as restricting inputs to members of a list.&lt;/p&gt;

&lt;p&gt;In the above example, &lt;code&gt;Equal&lt;/code&gt; is a &lt;em&gt;predicate&lt;/em&gt;, &lt;code&gt;Equal x y&lt;/code&gt; is a &lt;em&gt;proposition&lt;/em&gt;, and &lt;code&gt;Refl&lt;/code&gt; is a &lt;em&gt;proof&lt;/em&gt; of &lt;code&gt;Equal x x&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can use proofs in a function without adding runtime overhead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;acceptsOnlyFoo : (s1 : MyState)
              -&amp;gt; {auto 0 prf : Equal Foo s1}
              -&amp;gt; (Int, MyState)
acceptsOnlyFoo inState = (7, Bar)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's dissect the function type line by line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;(s1 : MyState)&lt;/code&gt;: this is similar to &lt;code&gt;MyState&lt;/code&gt;, but we have given the argument a name (&lt;code&gt;s1&lt;/code&gt;). In dependently typed programming, types can depend on values, so it's useful to have value names in the type.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{auto 0 prf : Equal Foo s1}&lt;/code&gt;: the curly brackets make this argument implicit. We don't have to specify it when calling the function, provided the compiler can figure it out itself. The &lt;code&gt;0&lt;/code&gt; means this argument will not exist at runtime. &lt;code&gt;auto&lt;/code&gt; denotes that the compiler will try to find a value for the type itself from the context. &lt;code&gt;prf&lt;/code&gt; is again the variable name and &lt;code&gt;Equal Foo s1&lt;/code&gt; is the type. In other words, we ask the compiler to find us some value of type &lt;code&gt;Equal Foo s1&lt;/code&gt;, with information known at compile time only. The compiler can only succeed in this by finding &lt;code&gt;Refl&lt;/code&gt; if it knows &lt;em&gt;for sure&lt;/em&gt; the first argument is &lt;code&gt;Foo&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;(Int, MyState)&lt;/code&gt; the output type as you are already familiar with.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means we can call &lt;code&gt;acceptsOnlyFoo&lt;/code&gt; as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;acceptsOnlyFoo Foo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but not&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\x =&amp;gt; acceptsOnlyFoo x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;unless we already know &lt;code&gt;Equal Foo x&lt;/code&gt; at compile time some other way.&lt;/p&gt;

&lt;p&gt;You might be able to see where this is going now. If we have one function that implicitly requires &lt;code&gt;Equal Foo x&lt;/code&gt;, and another that "returns" an &lt;code&gt;Equal Foo x&lt;/code&gt;, those could be safely chained together.&lt;/p&gt;

&lt;p&gt;While &lt;code&gt;acceptsOnlyFoo&lt;/code&gt; specifically requires a proof &lt;code&gt;Equal Foo&lt;/code&gt;, we do not want to limit ourselves to just proving equality. We need a more generic type for the precondition. A precondition could be any &lt;code&gt;MyState -&amp;gt; Type&lt;/code&gt;. A state monad with a precondition is therefore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data MyPreconditionMonad : (pre : MyState -&amp;gt; Type) -&amp;gt; a -&amp;gt; Type where
  MkMyPreconditionMonad :
    ( ( s1 : MyState) -&amp;gt;
      { auto 0 prf_pre : pre s1 } -&amp;gt;
      (a, MyState)
    ) -&amp;gt;
    MyPreconditionMonad pre a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice &lt;code&gt;{ auto 0 prf_pre : pre s1 }&lt;/code&gt;. The proof that must be found must be of type &lt;code&gt;pre s1&lt;/code&gt;. The initial state &lt;code&gt;s1&lt;/code&gt; is passed to it as argument at compile-time. Even though we don't &lt;em&gt;really&lt;/em&gt; know what it will be. In our previous example &lt;code&gt;pre&lt;/code&gt; was &lt;code&gt;Equal Foo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;An example of how to construct the state monad with precondition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;testPrecondition1 : MyPreconditionMonad (Equal Foo) Int
testPrecondition1 = MkMyPreconditionMonad acceptsOnlyFoo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what if we want to chain state monads that don't have a precondition? We create a &lt;code&gt;Top&lt;/code&gt; proposition, which can always be satisfied:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data Top : a -&amp;gt; Type where
  MkTop : Top a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whatever &lt;code&gt;a&lt;/code&gt; we have, &lt;code&gt;MkTop&lt;/code&gt; will be proof that &lt;code&gt;Top a&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The name Top comes from formal logic, where it is indicated with the symbol ⊤. It shouldn't actually take any arguments, but this servers our purpose well.&lt;/p&gt;

&lt;p&gt;And this is how you might use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;testPrecondition2 : MyPreconditionMonad Top Int
testPrecondition2 = MkMyPreconditionMonad f
  where
    f : (s1 : MyState) -&amp;gt; {auto 0 prf : Top s1} -&amp;gt; (Int, MyState)
    f s1 = (7, s1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So that about covers preconditions. Postconditions are a little bit harder.&lt;br&gt;
As far as I know, Idris has no implicit results. Instead, we must return something like a tuple with an implicit argument.&lt;br&gt;
To do this we create a special type &lt;code&gt;PostS'&lt;/code&gt;. I've added the apostrophe because the actual &lt;code&gt;PostS&lt;/code&gt; will be a little different.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data PostS' : (s : Type) -&amp;gt; (s -&amp;gt; Type) -&amp;gt; Type where
  MkPostS' : (val : s)
          -&amp;gt; {auto 0 prf : prop val}
          -&amp;gt; PostS' s prop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;PostS'&lt;/code&gt; is parametrized by a Type &lt;code&gt;s&lt;/code&gt; and a predicate about &lt;code&gt;s&lt;/code&gt;. Note that we pass &lt;code&gt;val&lt;/code&gt; to &lt;code&gt;prop&lt;/code&gt;, not &lt;code&gt;s&lt;/code&gt;, since &lt;code&gt;s&lt;/code&gt; is the type, and we want the proposition to hold about the value. For a concrete example, we want to be able to say &lt;code&gt;PostS' Int (Equal 7)&lt;/code&gt;, not &lt;code&gt;PostS' Int (Equal Int)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now let's use &lt;code&gt;PostS'&lt;/code&gt; in a function that increases a counter by 1. The type of the counter will be &lt;code&gt;Nat&lt;/code&gt;, a built-in type for natural numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;testPostS' : (s1 : Nat) -&amp;gt; PostS' Nat (Equal (s1 + 1))
testPostS' x = MkPostS' (x+1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we don't need to pass a proof, Idris has figured out &lt;code&gt;Equal (s1+1) (x+1)&lt;/code&gt; automatically, by unifying s1 and x. More or less. I think. Honestly I'm not that knowledgeable about how Idris searches for proofs.&lt;/p&gt;

&lt;p&gt;But the real &lt;code&gt;PostS&lt;/code&gt; needs to be a bit more complex. We don't just want the postcondition to be about the output state, it also needs to consider the returned value and input state. For instance we might want to declare that &lt;code&gt;s2 = s1 + x&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Luckily, if you understand the previous code, the next step is not particularly complicated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data PostS : (a : Type) -&amp;gt; (s : Type) -&amp;gt; (a -&amp;gt; s -&amp;gt; Type) -&amp;gt; Type where
  MkPostS  : (val : a)
          -&amp;gt; (state : s)
          -&amp;gt; {auto 0 prf : prop val state}
          -&amp;gt; PostS a s prop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;MkPostS&lt;/code&gt; consists of a value, a state, and a proof that a proposition about said state and value holds (at compile time). You may have noticed that &lt;code&gt;prop&lt;/code&gt; takes no input state. That is because &lt;code&gt;PostS&lt;/code&gt; does not know about input state. If we want a predicate about input state, that input state must already be passed to it outside of PostS. For instance, if we want to express a resulting state is equal to the input state plus the returned values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;testPostS : (s1 : Nat) -&amp;gt; PostS Nat Nat (\n =&amp;gt; Equal (s1 + n))
testPostS s1 = MkPostS 7 (s1+7)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that out of the way, let's make a Hoare monad for a specific state. We will keep using &lt;code&gt;Nat&lt;/code&gt; now instead of &lt;code&gt;MyState&lt;/code&gt;, since there's not much to prove about a &lt;code&gt;MyState&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data MyHoareMonad : (pre : Nat -&amp;gt; Type) -&amp;gt; (a : Type) -&amp;gt; (post : Nat -&amp;gt; a -&amp;gt; Nat -&amp;gt; Type) -&amp;gt; Type where
  MkMyHoareMonad :
    ( ( s1 : Nat) -&amp;gt;
      { auto 0 _ : pre s1 } -&amp;gt;
      PostS a Nat (post s1)
    ) -&amp;gt;
    MyHoareMonad pre a post
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we can use it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;testMyHoareMonad : MyHoareMonad (Equal 0) Nat (\s1 =&amp;gt; Equal)
testMyHoareMonad = MkMyHoareMonad f
  where
    f : (s1 : Nat) -&amp;gt; {auto 0 prf : Equal 0 s1} -&amp;gt; PostS Nat Nat (Equal)
    f inState {prf} = MkPostS{prf=Refl} (inState+1) (inState+1) --{prf=Refl} is needed here because of a compiler bug.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately there currently appears to be a &lt;a href="https://github.com/idris-lang/Idris2/issues/1875"&gt;bug in Idris' auto strategy&lt;/a&gt;. It means that, for now, we won't be able to rely on &lt;code&gt;auto&lt;/code&gt; as much. It's not a huge deal provided it will get fixed in the future, but a tad annoying.&lt;/p&gt;

&lt;p&gt;But it's time for the real thing, make a Hoare state monad without hardcoded state type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data HoareStateMonad : (s : Type) -&amp;gt; (pre : s -&amp;gt; Type) -&amp;gt; (a : Type) -&amp;gt; (post : s -&amp;gt; a -&amp;gt; s -&amp;gt; Type) -&amp;gt; Type where
  MkHSMonad :
    ( ( s1 : s ) -&amp;gt;
      { auto 0 prf : pre s1 } -&amp;gt;
      PostS a s (post s1)
    ) -&amp;gt;
    HoareStateMonad s pre a post
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it's not much different, we just replaced &lt;code&gt;Nat&lt;/code&gt; with a variable type &lt;code&gt;s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Unfortunately, the hardest part is still to come. We want to use a Hoare state monad as a monad, or sort-of a monad. Technically we won't be making a monad. A monad requires the rule &lt;code&gt;m m a -&amp;gt; m a&lt;/code&gt;, but since our "&lt;code&gt;m&lt;/code&gt;" has been decorated with pre- and postconditions, every "&lt;code&gt;m&lt;/code&gt;" in that formula would be different. Doesn't really matter for us though, it's close enough.&lt;/p&gt;

&lt;p&gt;We need to define a &lt;code&gt;pure&lt;/code&gt; and a &lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt; (bind) function.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;pure&lt;/code&gt; function lifts a value to a monadic value, like making a list with a single element, doing a no-op, or, in the case of a regular state monad, leave the state unchanged and return the lifted value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pure : a -&amp;gt; MyStateMonad a
pure val = MkMyStateMonad ((,) val)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what should the pre- and postconditions be for &lt;code&gt;pure&lt;/code&gt;? Since we're not using the state in any way, the precondition can just be &lt;code&gt;Top&lt;/code&gt;. Anything goes.&lt;/p&gt;

&lt;p&gt;We could also use &lt;code&gt;Top&lt;/code&gt; as the postcondition, but that would lose some useful information. We know the input state is equal to the output state (&lt;code&gt;Equal s1 s2&lt;/code&gt;), and the output value is equal to the lifted value. We can use a tuple as a conjunction to indicate to predicates must both hold. After all, we must be able to provide &lt;em&gt;both&lt;/em&gt; values of a tuple to construct it.&lt;/p&gt;

&lt;p&gt;With that, &lt;code&gt;pure&lt;/code&gt; becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pure : (a1 : a) -&amp;gt; HoareStateMonad s Top a (\s1, a2, s2 =&amp;gt; (Equal s1 s2, Equal a1 a2))
pure a1 = MkHSMonad $ \s1 =&amp;gt; MkPostS a1 s1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now for the tricky bit, the bind operator.&lt;/p&gt;

&lt;p&gt;For regular state monads, the bind operator chains the state-changing functions together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(&amp;gt;&amp;gt;=) : MyStateMonad a -&amp;gt; (a -&amp;gt; MyStateMonad b) -&amp;gt; MyStateMonad b
(&amp;gt;&amp;gt;=) (MkMyStateMonad f1) act2 = MkMyStateMonad $ \s1 =&amp;gt;
  let
    (val1, s2) = f1 s1
    (MkMyStateMonad f2) act2 val1
  in
     f2 s2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what we're really doing, is first executing action A, the executing action B, potentially using A's output. I will be using a notation from program algebra for clarity: &lt;code&gt;A ; B&lt;/code&gt; means "first do A, then do B".&lt;/p&gt;

&lt;p&gt;But, again, what should the pre- and postconditions be? Let's first look at the part of bind's type signature we do know:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(&amp;gt;&amp;gt;=) :  HoareStateMonad s p1 a q1
      -&amp;gt; ((x : a) -&amp;gt; HoareStateMonad s (p2 x) b (q2 x))
      -&amp;gt; HoareStateMonad s ?p3 b ?q3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;s&lt;/code&gt; is the state type, &lt;code&gt;p1&lt;/code&gt; is the precondition of action A, &lt;code&gt;a&lt;/code&gt; is the return type of action A, &lt;code&gt;q1&lt;/code&gt; is the postcondition of action A, and &lt;code&gt;x&lt;/code&gt; is the input to action B. &lt;code&gt;p2&lt;/code&gt; and &lt;code&gt;q2&lt;/code&gt; are a bit different than &lt;code&gt;p1&lt;/code&gt; and &lt;code&gt;q1&lt;/code&gt;. They are applied not just over input state, return value and output state, but also over the input value &lt;code&gt;x&lt;/code&gt;. Why? Consider the following function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;trySetState : (x : Nat) -&amp;gt; (s1 : Nat) -&amp;gt; (Bool, Nat)
trySetState x s1 =
  if (someCondition)
    then (True, x)
    else (False, s1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function sets the state based on some condition. This is a common pattern. A reasonable postcondition for &lt;code&gt;trySetState&lt;/code&gt; would express that if the return type is &lt;code&gt;True&lt;/code&gt;, then &lt;code&gt;Equal x s2&lt;/code&gt; is proven, and if it is &lt;code&gt;False&lt;/code&gt;, then &lt;code&gt;Equal s1 s2&lt;/code&gt; is proven. Declaring this proposition requires using &lt;code&gt;x&lt;/code&gt; as input.&lt;/p&gt;

&lt;p&gt;As the example shows, it is useful to also consider inputs in the pre- and postconidtion for the second argument of &lt;code&gt;bind&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Back to the bind operation. What is &lt;code&gt;p3&lt;/code&gt;, the precondition of the "first A then B"? Since A executes first, &lt;code&gt;p3&lt;/code&gt; must contain &lt;code&gt;p1&lt;/code&gt;. Furthermore, to satisfy &lt;code&gt;p2&lt;/code&gt;, &lt;code&gt;p3&lt;/code&gt; must ensure that &lt;code&gt;p2&lt;/code&gt; holds after A has executed, so the postcondition &lt;code&gt;q1&lt;/code&gt; of A must imply the precondition &lt;code&gt;p2&lt;/code&gt; of B. Remember also that the type of &lt;code&gt;p3&lt;/code&gt; is &lt;code&gt;s -&amp;gt; Type&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We define a function &lt;code&gt;bind_pre&lt;/code&gt; that constructs a new precondition from &lt;code&gt;p1&lt;/code&gt;, &lt;code&gt;q1&lt;/code&gt; and &lt;code&gt;p2&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bind_pre
  :  {s : Type}
  -&amp;gt; {a : Type}
  -&amp;gt; (p1 : s -&amp;gt; Type)
  -&amp;gt; (q1 : s -&amp;gt; a -&amp;gt; s -&amp;gt; Type)
  -&amp;gt; (p2 : a -&amp;gt; s -&amp;gt; Type)
  -&amp;gt; s -&amp;gt; Type
bind_pre p1 q1 p2 s1 =
  ( p1 s1
  , {x : a} -&amp;gt; {s2 : s} -&amp;gt; q1 s1 x s2 -&amp;gt; p2 x s2
  )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't easy, so let's go through it line by line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bind_pre&lt;/code&gt;: the function name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:  {s : Type}&lt;/code&gt;: the type declaration for an implicit argument. You can read this as "for any &lt;code&gt;s&lt;/code&gt; that is a type"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&amp;gt; {a : Type}&lt;/code&gt;: Read as "for any &lt;code&gt;a&lt;/code&gt; that is a type"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&amp;gt; (p1 : s -&amp;gt; Type)&lt;/code&gt;: first argument to the function (not counting implicits). A predicate over &lt;code&gt;s&lt;/code&gt;. The precondition of the first action.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&amp;gt; (q1 : s -&amp;gt; a -&amp;gt; s -&amp;gt; Type)&lt;/code&gt;: Postcondition of the first action&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&amp;gt; (p2 : a -&amp;gt; s -&amp;gt; Type)&lt;/code&gt;: precondition of the second action. Based on the output of the first action.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&amp;gt; s -&amp;gt; Type&lt;/code&gt;: The return type. Remember &lt;code&gt;p3&lt;/code&gt; must be &lt;code&gt;s -&amp;gt; Type&lt;/code&gt;. Idris is curried to &lt;code&gt;x -&amp;gt; s -&amp;gt; Type&lt;/code&gt; and &lt;code&gt;x -&amp;gt; (s -&amp;gt; Type)&lt;/code&gt; are exactly the same thing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bind_pre p1 q1 p2 s1 =&lt;/code&gt;: begin of function body. We give the arguments new names here, that is because the names in the type declaration are only valid within that type declaration. I used matching names for clarity.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;( p1 s1&lt;/code&gt;: The result is a tuple, with as first value the regular precondition of the first action.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;, {x : a} -&amp;gt; {s2 : s} -&amp;gt; q1 s1 x s2 -&amp;gt; p2 x s2&lt;/code&gt;: for any &lt;code&gt;x&lt;/code&gt; of type &lt;code&gt;a&lt;/code&gt;, and any &lt;code&gt;s2&lt;/code&gt; of type &lt;code&gt;s&lt;/code&gt;, if we can prove &lt;code&gt;q1 s1 x s2&lt;/code&gt;, then we must also be able to prove &lt;code&gt;p2 x s2&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Well, that was hard enough, but the postcondition is worse. &lt;code&gt;q1&lt;/code&gt; and &lt;code&gt;q2&lt;/code&gt; are qualified on intermediate results. These intermediate values won't appear in the resulting monad's type declaration. We only know that they exist and that the postconditions hold for them. We're going to need a function for existential quantification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exists : {p : _} -&amp;gt; (p -&amp;gt; Type) -&amp;gt; Type
exists f = {b : Type} -&amp;gt; ({a : _} -&amp;gt; f a -&amp;gt; b) -&amp;gt; b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we did here, is reverse universal quantification to get existential qualification. &lt;code&gt;{a : Type} -&amp;gt; a -&amp;gt; Type&lt;/code&gt; is a predicate that works &lt;em&gt;for all&lt;/em&gt; &lt;code&gt;a&lt;/code&gt;s that are &lt;code&gt;Type&lt;/code&gt;s. &lt;code&gt;Top&lt;/code&gt; is such a predicate. Conversely, we want to state that some &lt;code&gt;a&lt;/code&gt; &lt;em&gt;exists&lt;/em&gt; that satisfies a certain predicate. There is a duality here: if all you know is that something &lt;em&gt;exists&lt;/em&gt;, you can only reason about it using predicates that work &lt;em&gt;for all&lt;/em&gt; values. In programming, that means an existentially quantified ouput is mathematically the same as a universally quantified continuation. In other words: &lt;code&gt;exists x. x&lt;/code&gt; is the same as &lt;code&gt;forall y . (forall x . x -&amp;gt; y) -&amp;gt; y&lt;/code&gt;. The latter can be read as "you can prove any statement of type &lt;code&gt;y&lt;/code&gt; so long as you can prove it using any statement of type &lt;code&gt;x&lt;/code&gt;". Since we know nothing about &lt;code&gt;y&lt;/code&gt;, only that it can be proven using any &lt;code&gt;x&lt;/code&gt;, this tells us that some &lt;code&gt;x&lt;/code&gt; must exist. The other way works too: if we know some &lt;code&gt;x&lt;/code&gt; exists, we know that a &lt;code&gt;y&lt;/code&gt; can be proven if it can be proven for any &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now finally we can get to the postcondition of &lt;code&gt;A; B&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Remember that &lt;code&gt;q1&lt;/code&gt; and &lt;code&gt;q2&lt;/code&gt; are qualified over intermediate values, of which we only know they exist in the type signature. We therefore have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bind_post
  :  {s : Type}
  -&amp;gt; {a : Type}
  -&amp;gt; {b : Type}
  -&amp;gt; (q1 : s -&amp;gt; a -&amp;gt; s -&amp;gt; Type)
  -&amp;gt; (q2 : a -&amp;gt; s -&amp;gt; b -&amp;gt; s -&amp;gt; Type)
  -&amp;gt; (s -&amp;gt; b -&amp;gt; s -&amp;gt; Type)
bind_post q1 q2 s1 y s3
  =  exists (\x =&amp;gt; exists (\s2 =&amp;gt; (q1 s1 x s2, q2 x s2 y s3)))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which leaves the final declaration of bind, I'll explain it line-by-line later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(&amp;gt;&amp;gt;=)  : {a : Type}
      -&amp;gt; {b : Type}
      -&amp;gt; {s : Type}
      -&amp;gt; {p1 : s -&amp;gt; Type}
      -&amp;gt; {q1 : s -&amp;gt; a -&amp;gt; s -&amp;gt; Type}
      -&amp;gt; {p2 : a -&amp;gt; s -&amp;gt; Type}
      -&amp;gt; {q2 : a -&amp;gt; s -&amp;gt; b -&amp;gt; s -&amp;gt; Type}
      -&amp;gt; HoareStateMonad s p1 a q1
      -&amp;gt; ((x : a) -&amp;gt; HoareStateMonad s (p2 x) b (q2 x))
      -&amp;gt; HoareStateMonad s (bind_pre p1 q1 p2) b (bind_post q1 q2)
(&amp;gt;&amp;gt;=) (MkHSMonad f1) act2 = MkHSMonad f
  where
    f :  ( s1 : s )
      -&amp;gt; { auto 0 pre3 : bind_pre p1 q1 p2 s1 }
      -&amp;gt; PostS b s (bind_post q1 q2 s1)
    f s1 {pre3} =
      let
        MkPostS v1 s2 {prf=post1} = f1 s1
        MkHSMonad f2 = act2 v1
        MkPostS v2 s3 {prf=post2} = f2{prf= (snd pre3) post1} s2
      in MkPostS v2 s3 {prf=(\e1 =&amp;gt; (e1 $ \e2 =&amp;gt; e2 (post1, post2)))}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;{a : Type}&lt;/code&gt;: implicit argument. Read as "for all &lt;code&gt;a&lt;/code&gt;s that are types"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{b : Type}&lt;/code&gt;: for all &lt;code&gt;b&lt;/code&gt;s that are types&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{s : Type}&lt;/code&gt;: for all &lt;code&gt;s&lt;/code&gt;s that are types&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{p1 : s -&amp;gt; Type}&lt;/code&gt;: for all predicates &lt;code&gt;p1&lt;/code&gt; about an &lt;code&gt;s&lt;/code&gt; (this is the type of our first precondition)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{q1 : s -&amp;gt; a -&amp;gt; s -&amp;gt; Type}&lt;/code&gt; for all predicates &lt;code&gt;q1&lt;/code&gt; about an &lt;code&gt;s&lt;/code&gt;, &lt;code&gt;a&lt;/code&gt; and another &lt;code&gt;s&lt;/code&gt; (the type of our first postcondition)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{p2 : a -&amp;gt; s -&amp;gt; Type}&lt;/code&gt;: for all predicates &lt;code&gt;p2&lt;/code&gt; over &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;s&lt;/code&gt; (second precondition, extra qualified over the input)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{q2 : a -&amp;gt; s -&amp;gt; b -&amp;gt; s -&amp;gt; Type}&lt;/code&gt;: second postcondition&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;HoareStateMonad s p1 a q1&lt;/code&gt;: the first argument, a &lt;code&gt;HoareStateMonad&lt;/code&gt; about state &lt;code&gt;s&lt;/code&gt;, with precondition &lt;code&gt;p1&lt;/code&gt;, return value &lt;code&gt;a&lt;/code&gt;, and postcondition &lt;code&gt;q1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;((x : a) -&amp;gt; HoareStateMonad s (p2 x) b (q2 x))&lt;/code&gt;: the second argument, a function that takes an &lt;code&gt;a&lt;/code&gt; (with value &lt;code&gt;x&lt;/code&gt;), and yields a &lt;code&gt;HoareStateMonad&lt;/code&gt; about state &lt;code&gt;s&lt;/code&gt;, with precondition &lt;code&gt;p2 x&lt;/code&gt;, returning a &lt;code&gt;b&lt;/code&gt;, and with postcondition &lt;code&gt;q2 x&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;HoareStateMonad s (bind_pre p1 q1 p2) b (bind_post q1 q2)&lt;/code&gt;: results in a &lt;code&gt;HoareStateMonad&lt;/code&gt; about state &lt;code&gt;s&lt;/code&gt;, with precondition &lt;code&gt;bind_pre p1 q1 p2&lt;/code&gt;, returning a value &lt;code&gt;b&lt;/code&gt;, and with postcondition &lt;code&gt;bind_post q1 q2&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And for the function body:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;(&amp;gt;&amp;gt;=) (MkHSMonad f1) act2 = MkHSMonad f&lt;/code&gt;: unwrapping and wrapping the state-changing functions in monad constructors. &lt;code&gt;f&lt;/code&gt; is the new state-changing function we create as the sequence of our inputs.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;f :  ( s1 : s )&lt;/code&gt;: the first argument to the new function is the input state&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&amp;gt; { auto 0 pre3 : bind_pre p1 q1 p2 s1 }&lt;/code&gt;: we also require a proof that the combined preconditions hold&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&amp;gt; PostS b s (bind_post q1 q2 s1)&lt;/code&gt;: and produce a value with suitable postconditions&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;f s1 {pre3} =&lt;/code&gt;: we note the precondition proof &lt;code&gt;pre3&lt;/code&gt; explicitely as we will need to use it manually in the function body.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MkPostS v1 s2 {prf=post1} = f1 s1&lt;/code&gt;: "Run" the first action with the input state. This will result in a return value &lt;code&gt;v1&lt;/code&gt;, a new state &lt;code&gt;s2&lt;/code&gt; and an proof of the postcondition &lt;code&gt;post1&lt;/code&gt;. Note that &lt;code&gt;post1&lt;/code&gt; still has multiplicity 0 so it will not exist at runtime.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MkHSMonad f2 = act2 v1&lt;/code&gt;: pass the return value of the first action, this will result in a new state-changing function &lt;code&gt;f2&lt;/code&gt;, wrapped in a HoareStateMonad.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MkPostS v2 s3 {prf=post2} = f2{prf= (snd pre3) post1} s2&lt;/code&gt;: we "run" &lt;code&gt;f2&lt;/code&gt; with state &lt;code&gt;s2&lt;/code&gt;, but must also prove its precondition. The precondition &lt;code&gt;pre3&lt;/code&gt; is &lt;code&gt;( p1 s1 , {x : a} -&amp;gt; {s2 : s} -&amp;gt; q1 s1 x s2 -&amp;gt; p2 x s2 )&lt;/code&gt; The second argument is of interest here, and we have &lt;code&gt;q1 s1 v1 s2&lt;/code&gt; from &lt;code&gt;post1&lt;/code&gt;, and so &lt;code&gt;(snd pre3) post1&lt;/code&gt; is proof of &lt;code&gt;p2 v1 s2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MkPostS v2 s3 {prf=(\e1 =&amp;gt; (e1 $ \e2 =&amp;gt; e2 (post1, post2)))}&lt;/code&gt;: we create a return value with postcondition, but must provide proof of our new postcondition. Recall existential types are continuations, and so we create a continuation as proof.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;I still have to use &lt;code&gt;HoareStateMonads&lt;/code&gt; in practice. I planned to use them to reduce what mistakes can be made when writing a WebGL program. Those can be very tricky to debug. I fear &lt;code&gt;HoareStateMonads&lt;/code&gt; require passing around proofs far too much to be useful in most cases. The extra programming work might not weigh up against the reduction of bugs. But perhaps Idris will be able to find many proofs by itself. Or perhaps I will need a different data type entirely.&lt;/p&gt;

</description>
      <category>functional</category>
      <category>logic</category>
      <category>idris</category>
    </item>
    <item>
      <title>Idris2+WebGL, part #16: Binding programs again</title>
      <dc:creator>DrBearhands</dc:creator>
      <pubDate>Fri, 20 Aug 2021 14:27:08 +0000</pubDate>
      <link>https://dev.to/drbearhands/idris2-webgl-part-16-binding-programs-again-hfp</link>
      <guid>https://dev.to/drbearhands/idris2-webgl-part-16-binding-programs-again-hfp</guid>
      <description>&lt;p&gt;It's time to take up the issue I've been avoiding since part 9. The compiler somehow needs to more-or-less know what program is bound in order to determine whether certain commands are correct. This sucks, because it means we have to keep track of state statically, which is traditionally hard to do. But let's first take a step back.&lt;/p&gt;

&lt;p&gt;My initial idea was to use existential types to bind programs and uniform locations together. I realize now this was a bad idea. A quick recap.&lt;/p&gt;

&lt;p&gt;given the (simplified) types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export
data Program : ProgramID -&amp;gt; Type where
  ...

export
data UniformLocation : ProgramID -&amp;gt; Type where
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can define functions to work on a &lt;code&gt;Program pid&lt;/code&gt; and &lt;code&gt;UniformLocation pid&lt;/code&gt;, requiring that &lt;code&gt;pid&lt;/code&gt; values are the same. There is a trick we can pull with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;someFunction : forall a . (forall pid . Program pid -&amp;gt; UniformLocation pid -&amp;gt; a) -&amp;gt; a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;because &lt;code&gt;forall pid&lt;/code&gt; is part of the first argument, the first argument for &lt;code&gt;someFunction&lt;/code&gt; must be a function able to handle &lt;em&gt;any&lt;/em&gt; value of &lt;code&gt;pid&lt;/code&gt;. Because of that, it cannot know anything about &lt;code&gt;pid&lt;/code&gt; other than that it exists and it's the same between &lt;code&gt;Program&lt;/code&gt; and &lt;code&gt;UniformLocation&lt;/code&gt;. This way it's possible to tie specific variables together in their type.&lt;/p&gt;

&lt;p&gt;The problem is that this is not the correct restriction.&lt;/p&gt;

&lt;p&gt;When we call e.g. &lt;code&gt;unifom2fv&lt;/code&gt;, the rule is that the passed location in the bound program must be for a 2-element array of floats. It's perfectly fine to have the same uniform locations for different programs. While that seems silly for individual uniforms, WebGL2 introduced uniform blocks, which can be shared between programs to improve performance.&lt;/p&gt;

&lt;p&gt;Rather than typing programs with a phantom ID, I should type them by their attributes and uniforms. So long as they match our expectations, everything is fine, wherever we got a uniform location from.&lt;/p&gt;

&lt;p&gt;The program type signature should therefore be something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public export
Attribute = (String, Int32, GLEnum) --name, size, type

public export
Uniform = (String, Int32, GLEnum) -- same

export
data Program : List Attribute -&amp;gt; List Uniform -&amp;gt; Type where
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The real code is a bit more complicated, for instance to ensure only correct &lt;code&gt;GLEnum&lt;/code&gt; values can be used, but that's the gist of it.&lt;/p&gt;




&lt;p&gt;This still leaves the problem of keeping track of what program is in use, to which I have no nice solution.&lt;/p&gt;

&lt;p&gt;When we call e.g. &lt;code&gt;uniform2fv&lt;/code&gt;, we know the location and type of the passed variable, but not the program (not at compile time). This means we cannot compare the passed data to the inputs of the program, and a runtime type mismatch is possible. &lt;a href="https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glProgramUniform.xhtml"&gt;OpenGL4 allows for binding uniforms to specific programs&lt;/a&gt;, which circumvents the need of keeping track of used program. Unfortunately WebGL2 does not have these nice new functions. I could emulate them, but that's overhead I'm loathe to add.&lt;/p&gt;

&lt;p&gt;So we're back to indexed state monads, hoare monads, and passing linear values around.&lt;/p&gt;

&lt;p&gt;Consider the function to use a program:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useProgram : MonadState WebGL2.WebGLRenderingContext m =&amp;gt;
  (1 _ : WebGLProgram attributes uniforms) -&amp;gt;
  m (WebGLProgram attributes uniforms)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A naive approach is to add a phantom type to the program to denote if it was bound:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useProgram : MonadState WebGL2.WebGLRenderingContext m =&amp;gt;
  (1 _ : WebGLProgram  attributes uniforms NotInUse) -&amp;gt;
  m (WebGLProgram  attributes uniforms InUse)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(We could do something even fancier with dependent types that does not require changing our type definitions, but that's not particularly relevant here)&lt;/p&gt;

&lt;p&gt;This would allow us to do something rather cool with erased implicit arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uniform1fv : MonadState WebGL2.WebGLRenderingContext m =&amp;gt;
  WebGLUniformLocation uniformType -&amp;gt;
  {auto 0 prf : WebGLProgram attributes uniforms InUse} -&amp;gt;
  Float32Array -&amp;gt;
  m ()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which would check if a &lt;code&gt;WebGLProgram&lt;/code&gt; that has been marked as &lt;code&gt;InUse&lt;/code&gt; (by &lt;code&gt;useProgam&lt;/code&gt;) exists at all in the current context.&lt;/p&gt;

&lt;p&gt;The problem is that we can call &lt;code&gt;useProgram&lt;/code&gt; twice, getting 2 programs that are &lt;code&gt;InUse&lt;/code&gt;, even though only the last one actually is.&lt;/p&gt;

&lt;p&gt;So, one way or another, &lt;code&gt;useProgram&lt;/code&gt; must "consume" some form of program status when invoked.&lt;/p&gt;

&lt;p&gt;What's even worse, I'm not trying to prevent the user from binding to non-existing inputs. That's actually fine, even useful when debugging, and can be ignored. The problem is not binding values that &lt;em&gt;are&lt;/em&gt; used. So we also need to keep track of what inputs have been bound.&lt;/p&gt;

&lt;p&gt;Because of that, I'm currently inclined to think some form of indexed monads are inevitable. I'm not very happy about that because it makes things a bit more complicated for the end-user. Indexed monads are not all that common after all.&lt;/p&gt;

</description>
      <category>idris</category>
      <category>functional</category>
      <category>webgl</category>
    </item>
  </channel>
</rss>
