<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

    <title>Wim Vanderbauwhede</title>
    <generator uri="https://github.com/jekyll/jekyll">Jekyll v4.3.3</generator>
		<icon>https://limited.systems/apple-touch-icon-precomposed.avif</icon>
    <subtitle>Wim Vanderbauwhede</subtitle>
    <link href="https://limited.systems/atom.xml" rel="self"/>
    <link href="https://limited.systems/" rel="alternate" type="text/html"/>
    <updated>2026-01-24T09:07:03+00:00</updated>
    <id>https://limited.systems/</id>
    <author>
			<name>Wim Vanderbauwhede</name>
			<uri>https://limited.systems/</uri>
			
		</author>

    
    <entry>
        <title>Resisting software driven hardware obsolescence</title>
        <link href="https://limited.systems/articles/resisting-hardware-obsolescence/"/>
        <updated>2025-12-02T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/resisting-hardware-obsolescence</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/resisting-hardware-obsolescence_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;Considering the sheer volume of mobile phones, and the high greenhouse gas emissions resulting from their manufacture, it is imperative to extend their useful life by several decades. What would it take?&lt;/p&gt;

&lt;h2 id=&quot;hardware-obsolescence&quot;&gt;Hardware obsolescence&lt;/h2&gt;

&lt;p&gt;Computer hardware, which includes phones and IoT devices, exists to run software. When hardware becomes obsolete, it is therefore often because the software is no longer supporting it. There are of course other reasons for hardware obsolescence such as changes in standards (e.g. very soon 3G phones will be obsolete because there will be no 3G networks left), or fashion (it has the wrong colour, is considered too big/too small, the camera is not good enough, …). Addressing this requires a change in consumer attitudes. And of course the hardware can fail or break, and not be repairable at the moment. The &lt;a href=&quot;https://commission.europa.eu/law/law-topic/consumer-protection-law/directive-repair-goods_en&quot;&gt;EU directive on repair of goods&lt;/a&gt; will come into force next year and will go some way to address physical hardware repairs. It requires amongst other things &lt;a href=&quot;https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=OJ:L:2023:214:FULL&quot;&gt;at least 7 years availability of spare parts for most common repairs&lt;/a&gt;. What is also very interesting is that it comes with a mandatory Repairability Index and Energy Efficiency Index.&lt;/p&gt;

&lt;p&gt;I will focus on software driven hardware obsolescence of mobile phones, but the problem exists for other hardware (e.g. laptops, TVs,…) as well. &lt;!-- should I discuss the recent Win11 situation as well? --&gt;&lt;/p&gt;

&lt;!-- 
* I got a smartphone in 2011 and it lasted until about 2022, when the USB connector finally failed completely. I moved on to an old iPhone which I got from a colleague, until the physical buttons on that one started to fail. So in both cases, for my needs, it was not the software that made these devices obsolete. 
--&gt;

&lt;h2 id=&quot;extending-phone-lifetimes-to-reduce-emissions&quot;&gt;Extending phone lifetimes to reduce emissions&lt;/h2&gt;

&lt;p&gt;Currently, most users replace their phones after two to three years. However, most of the greenhouse gas emissions related to phones are incurred during their manufacturing. To minimise the overall emissions, phones should be used for much longer. According to the &lt;a href=&quot;https://eeb.org/en/library/coolproducts-report/&quot;&gt;European Environmental Bureau report “Coolproducts don’t cost the Earth”&lt;/a&gt; (from 2019):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;from a global warming perspective our phones should last at least 20 years longer than they currently do&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For a phone to last 20-25 years, there would be a need for hardware repairs, and the device would have to designed for repairability. At the very least, the battery should be replaceable. But that is not enough. Current devices typically get 4 years of software updates. The &lt;a href=&quot;https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=OJ:L:2023:214:FULL&quot;&gt;EU directive on repair of goods&lt;/a&gt; requires at least 5 years. Recently, both Apple and Samsung have increased after-sales software update support to 7 years, which is a considerable improvement and hopefully indicates a trend of users holding on to their phones for longer, but is still not long enough by far.&lt;/p&gt;

&lt;p&gt;The result of the short replacement cycles is that there are lots of perfectly good phones out there, if you don’t mind being behind the curve. Buying a used phone means prolonging that phone’s useful life and avoiding manufacturing of a new phone, so it is a good way to reduce emissions.&lt;/p&gt;

&lt;h2 id=&quot;ideological-detour&quot;&gt;Ideological detour&lt;/h2&gt;

&lt;p&gt;I don’t mind being “behind the curve” at all. The curve is a scoial construct created to make you replace your technology early. My previous phone was from 2011 and it lasted until about 2022, when the USB connector finally failed completely. I moved on to an old iPhone which I got from a colleague, until the physical buttons on that one started to fail. Now I have a used phone from 2017. It’s an Android phone but I have not created a Google account on it. I use my phone effectively as barely more than a dumb phone. I don’t have a contract and I very rarerly use data, positioning, Bluetooth or even Wifi. I find there is no need. I also often walk around without a phone. It is hard to avoid all interaction with the likes of Google and Apple, but I don’t have to play their game.&lt;/p&gt;

&lt;h2 id=&quot;upgrading-the-phone-software&quot;&gt;Upgrading the phone software&lt;/h2&gt;

&lt;p&gt;Older phones will be running older software versions and therefore be of limited use. One option is to install a newer operating system on the phone (more on the terminology later). This is possible for Android devices (and also old Windows phones) but not for Apple devices.&lt;/p&gt;

&lt;p&gt;Upgrading the phone software means upgrading the operating system. The operating system is the software that makes it possible to make phone calls, use wifi or bluetooth, run apps etc.&lt;/p&gt;

&lt;h3 id=&quot;android-aosp-lineageos-e&quot;&gt;Android, AOSP, LineageOS, /e/&lt;/h3&gt;

&lt;p&gt;Android is an operating system for mobile phones. It is developed by the Open Handset Alliance, led by Google. The core system is known as the &lt;a href=&quot;https://source.android.com/&quot;&gt;Android Open Source Project (AOSP)&lt;/a&gt; and is free/open-source software. Alternatives such as &lt;a href=&quot;https://e.foundation/&quot;&gt;/e/&lt;/a&gt; or &lt;a href=&quot;https://lineageos.org/&quot;&gt;LineageOS&lt;/a&gt; are based on AOSP and typically support a more recent version of Android.&lt;/p&gt;

&lt;p&gt;Even though AOSP is technically free and open, Google drives the development as they have the contracts with the phone makers. If Google would disappear, AOSP and therefore LineageOS and /e/ would no longer progress. Not that this is to my mind a big issue, but it is important to realise that the phone makers will always rely on a large company to provide their OS, rather than on an open soource project, unless such a project would have the backing of a powerful entity (for example, if the EU would sponsor AOSP, it could exists independently of Google).&lt;/p&gt;

&lt;p&gt;In an ideal world, upgrading to LineageOS or /e/ or any such alternative would be supported as part of the regular update mechanism of your phone: when the commercial software support is discontinued, you would be given to option to upgrade to an open source variant. In the real world, as the phone manufacturers profit from the short replacement cycles, this is not the case. As a result, while it is techically possible to upgrade the phone software, the process is not seamless. There are many barriers to upgrading your phone.&lt;/p&gt;

&lt;h3 id=&quot;terminology&quot;&gt;Terminology&lt;/h3&gt;

&lt;p&gt;First of all there is the terminology, which speaks of “ROMs”, “flashing”, “sideloading” and a lot besides.&lt;/p&gt;

&lt;p&gt;“ROM” stands for Read-Only Memory, but “a ROM” means the file that contains the software to run on your phone. In the olden days, the system software of a computer would be stored in ROM memory.&lt;/p&gt;

&lt;p&gt;A phone has internal storage. Part of this storage is used for the operating system. On Samsung phones this is software called Android, as mentioned above this is effectively made and controlled by Google.&lt;/p&gt;

&lt;p&gt;“Flashing” derives from “flash memory”, a kind of non-volatile memory that can be erased in a flash. The typical storage in a phone is a kind of flash memory, and “flashing” is the process of writing the ROM in the appropriate locations on that storage.&lt;/p&gt;

&lt;h3 id=&quot;tools&quot;&gt;Tools&lt;/h3&gt;

&lt;p&gt;When you search on line, you will come across a bewildering array of tools that are all used in the process of upgrading a phone,  for example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Odin&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fastboot&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Freya&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrangeFox&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Heimdall&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TWRP&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;adb&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Magisk&lt;/code&gt;, and many more besides. You only need a few of them, but finding the right ones can be hard.&lt;/p&gt;

&lt;h3 id=&quot;finding-the-right-version-for-your-phone&quot;&gt;Finding the right version for your phone&lt;/h3&gt;

&lt;p&gt;Different models of phones run a slightly different variant of the operating system, even for same verions of Android, because they have slightly different specifications. You have to find the &lt;em&gt;exact&lt;/em&gt; version of the software for your phone or the upgrade will fail. 
(This is changing through the move towards what is called “Generic System Image”, a single ROM that works on many devices, but as far as I can tell neither LineageOS nor /e/ are using this approach yet.)&lt;/p&gt;

&lt;p&gt;Just finding out exactly what device you have is not trivial. Consider even the bluff old “Samsung Galaxy A3”. It is not simply that: at the very least it is a “2016” or “2017” (and the difference is not apparent); and the “2017” can be a SM-A320 F,FL, FL/DS, Y or Y/DS; the “2016” has 10 different models. And the “ROM” you need for it will have yet another name.&lt;/p&gt;

&lt;h3 id=&quot;the-upgrade-process&quot;&gt;The upgrade process&lt;/h3&gt;

&lt;p&gt;Let’s suppose you identified your phone, found a ROM and found appropriate versions of all the tools. What’s next?&lt;/p&gt;

&lt;p&gt;To replace the operating system, the phone has a special “recovery mode”, which the user can activate by pressing specific keys. In this recovery mode the phone runs special “recovery” software that can install updates and wipe data. This is what the engineer in the shop uses when your phone is “bricked” because of a software problem.&lt;/p&gt;

&lt;p&gt;It is possible to replace this recovery software by different software that can be used to install a different operating system on the phone. For this, the phone has a “download mode”, again activated by pressing specific keys. In that mode, when the phone is connected to a computer, yet another a special program on the computer can install this new recovery software, which can then be used to install the new operating system. Some phones have a “fastboot” mode which has a similar purpose.&lt;/p&gt;

&lt;p&gt;In my case, the alternative recovery software I used is called &lt;a href=&quot;https://twrp.me/about/&quot;&gt;TWRP&lt;/a&gt;; the program running on my laptop to install this new recovery software is called &lt;a href=&quot;https://glassechidna.com.au/heimdall/&quot;&gt;Heimdall&lt;/a&gt;,  the program to install the new operating system is called &lt;a href=&quot;https://developer.android.com/tools/adb&quot;&gt;adb&lt;/a&gt; and the new operating system itself is called LineageOS. So what I had to do is to find the correct versions of TWRP and LineageOS for my phone, as well as versions of Heimdall and adb that would work with those, and then carefully follow instructions – and hope for the best.&lt;/p&gt;

&lt;h2 id=&quot;case-study-lineageos-on-a-samsung-galaxy-a3&quot;&gt;Case Study: LineageOS on a Samsung Galaxy A3&lt;/h2&gt;

&lt;h3 id=&quot;what-is-to-be-gained&quot;&gt;What is to be gained?&lt;/h3&gt;

&lt;p&gt;The most recent version of LineageOS I found for the Samsung Galaxy A3 2017 is LineageOS 19.1. This version corresponds to Android Open Source Project version 12.1. The phone came with Android 6.0.1, upgradable to Android 8, so the LineageOS version is four generations more recent. Official Android security updates for this model in stopped 2021. LineageOS stopped updates for 19.1 on officially supported devices in 2024. The Samsung Galaxy A3 2017 was never officially supported, but beggars can’t be choosers. Meanwhile, LineageOS is at 23 and AOSP at version 16, so the updated device is still four generations behind, but that is still better than eight generations. For example, UK Government apps work on anything from Android 10 upwards. (They are only available on Google Play but that’s another story.)&lt;/p&gt;

&lt;p&gt;In any case, the limited support (both from Google and from LineageOS) is an organisational decision, it is not because of any device limitations. Ironically, the Samsung Galaxy A3 2016 is supported by AOSP up to version 13. But in principle, they could be supporting the most recent version, even on much older devices. Maybe we’ll live to see that day.&lt;/p&gt;

&lt;h3 id=&quot;why-do-this-at-all&quot;&gt;Why do this at all?&lt;/h3&gt;

&lt;p&gt;The main reason for this experiment was to see what the skills and knowledge are that are needed to do this.&lt;/p&gt;

&lt;h3 id=&quot;the-actual-experience&quot;&gt;The actual experience&lt;/h3&gt;

&lt;p&gt;Frankly, it was a bit of a nightmare.&lt;/p&gt;

&lt;p&gt;First I tried &lt;a href=&quot;https://openandroidinstaller.org&quot;&gt;OpenAndroidInstaller&lt;/a&gt;, “The graphical installer that makes installing alternative Android distributions nice and easy”. It runs on Windows and Linux. I am using the Ubuntu flavour of Linux, and installation was easy, but to run it I still needed to open a terminal and type&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;flatpak run org.openandroidinstaller.OpenAndroidInstaller
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;First hurdle was that it turned out I had the wrong version of LineageOS (“ROM”). I had searched for “lineageos samsung galaxy A3” and, after some persevering, found the “latest unofficial release” (the “latest official release” was no longer there). Turns ot this file is for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a3xelte&lt;/code&gt; (i.e. the 2016 version of the A3) and I needed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a3y17lte&lt;/code&gt; (because it turned out at that point that my device was a 2017 A3). I found &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lineage-19.1-20220904-UNOFFICIAL-a3y17lte.zip&lt;/code&gt; and I also found &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;twrp-3.7.0_9-0-a3y17lte.img&lt;/code&gt;, so all was well.&lt;/p&gt;

&lt;p&gt;Then it got stuck because of insufficient permissions on the USB device. Thank you, detailed log info! OK, I know how to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chmod&lt;/code&gt;, so I fixed that.&lt;/p&gt;

&lt;p&gt;Then it got stuck at the actual OS installation, detailed log said &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;adb -d wait-for-recovery&lt;/code&gt;, and waiting it did, forever, because by the time it issued that command the phone was already past the recovery stage. How a simple race condition can throw a spanner in the works. So that was the end of my attempt using the OpenAndroidInstaller. I don’t want to blame the project, It is a really good effort to make things easier. They listed this phone under “Officially supported devices” as “tested”, so it is a bit odd that it did not work for me.&lt;/p&gt;

&lt;p&gt;My next attempt was to use TWRP (version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;twrp-3.7.0_9-0-a3y17lte&lt;/code&gt;). I used the “adb sideload” method as explained &lt;a href=&quot;https://wiki.lineageos.org/devices/a3xelte/install/&quot;&gt;on the LineageOS wiki&lt;/a&gt;. I found it very hard to find this info on the wiki. There is no support for the A3 2017 but there is for the A3 2016, but even that is not official so there is no link there from the landing page.&lt;/p&gt;

&lt;p&gt;I did all the wiping etc. using TWRP as instructed, enabled adb sideload, issued&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;adb -d sideload  lineage-19.1-20220904-UNOFFICIAL-a3y17lte.zip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And that failed, “E2001: Failed to update vendor image.”&lt;/p&gt;

&lt;p&gt;Some &lt;a href=&quot;https://stackoverflow.com/questions/66788788/twrs-flashing-error-e2001-failed-to-update-vendor-image&quot;&gt;more internet searching&lt;/a&gt; got me both the explanation and the solution, after a fashion.&lt;/p&gt;

&lt;p&gt;The problem is that the ROM expects a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vendor&lt;/code&gt; partition and this was not present. This is because a crucial difference between the A3 2016 and A3 2017: Google introduced Project Treble, a major change to the Android OS to make it easier and faster for manufacturers to update devices to a new version of Android. Crucially, this involved the introduction of a new partition called “vendor”. The factory version of the A3 2017 doesn’t have this, as it predates this change. So the solution is to add this partition and the poster provided a script to do this.&lt;/p&gt;

&lt;p&gt;The explanation of how to use the script was “Flash attached zip file”. It did not specify how to flash it. I flashed it with Heimdall, and it did not work. At this point the phone was a brick: it had been wiped completely. I could not get back into the recovery mode or even switch it off.&lt;/p&gt;

&lt;p&gt;I re-flashed TWRP and could get back into recovery mode when connected to USB. The phone showed up on my computer so I copied the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repartitioner_a3y17lte.zip&lt;/code&gt; file to it and ran the script using TWRP’s “Install” function.&lt;/p&gt;

&lt;p&gt;This worked, but it installed an older version of TWRP in the process, and on that version, adb sideload did not work.&lt;/p&gt;

&lt;p&gt;I found a more recent version of TWRP with support for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vendor&lt;/code&gt; partition and flashed that using Heimdall. Now I could finally sideload the actual LineageOS zip file using adb, and it worked.&lt;/p&gt;

&lt;h2 id=&quot;required-skills-and-knowledge&quot;&gt;Required skills and knowledge&lt;/h2&gt;

&lt;p&gt;I think the most important skill needed to successfully upgrade a phone when things don’t go smoothly is debugging. This is not something you can teach quickly, it is a skill acquired through practice. You need to formulate a hypothesis of what went wrong, and try to test it and then remedy it. But to do that requires an understanding of what is supposed to happen, and that in turn requires an understanding of the overall system and the tools.&lt;/p&gt;

&lt;p&gt;In my case, I needed to know how to install and use a series of command-line tools. Without an understanding of what partitions are, I would not have been able to solve the problem as I would not have understood the proposed solution. I also needed to know how to deal with Linux device permissions.&lt;/p&gt;

&lt;p&gt;If I hadn’t found that handy partition script, I would have had to repartition the disk myself. This requires quite a bit of detailed Linux knowledge as it is a very critical step.&lt;/p&gt;

&lt;p&gt;Finally, if my phone was not supported, e.g. if I wanted the most recent version of LineageOS on it,  I would have to change LineageOS software to work with my phone. This requires detailed knowledge and understanding of both the phone hardware and the Android operating system. Android is based on Linux, so it also requires  detailed knowledge and understanding of the Linux kernel, which is the part of the operating system that interfaces with the hardware. It also requires familiarity with the process to create a ROM. And it requires programming skills.&lt;/p&gt;

&lt;p&gt;If we were serious about the circular economy, we should train the specialists to install upgrades. I think this should not take more than a week. Training the developers of the upgrades would of course take a lot longer, but there might not really be a need. It would be more important to ensure they are properly paid. In this way we would get more recent upgrades, as developers would be paid to create and support them, as well as professionals to install them. In this way anyone could easily prolong the life of their phones through software upgrades.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The banner picture shows a very blurry picture of person seen from the back, on the phone in a busy street.&lt;/em&gt;&lt;/p&gt;


        </content>
    </entry>
    
    <entry>
        <title>The Anti-Dystopians’ Guide to Generative AI</title>
        <link href="https://limited.systems/articles/anti-dystopians-guide-to-ai/"/>
        <updated>2025-10-10T00:00:00+01:00</updated>
        <id>https://limited.systems/articles/anti-dystopians-guide-to-ai</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/anti-dystopians-guide-to-ai_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;These are the slides for the talk “The Anti-Dystopians’ Guide to Generative AI – for students &amp;amp; educators” which is based on the &lt;a href=&quot;https://alinautrata.substack.com/p/the-anti-dystopians-guide-to-genai&quot;&gt;guide of the same title&lt;/a&gt; written by &lt;a href=&quot;https://www.alinautrata.com/&quot;&gt;Alina Utrata&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’d like me to deliver this talk for your community, please &lt;a href=&quot;mailto:Wim.Vanderbauwhede@glasgow.ac.uk&quot;&gt;contact me&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://limited.systems/presentation/The-Anti-Dystopians-Guide-to-Understanding-AI-pres-2025-10-10.pdf&quot;&gt;The Anti-Dystopians’ Guide to Generative AI (PDF)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://limited.systems/presentation/The-Anti-Dystopians-Guide-to-Understanding-AI-pres-2025-10-10.odp&quot;&gt;The Anti-Dystopians’ Guide to Generative AI (ODP)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


        </content>
    </entry>
    
    <entry>
        <title>Demystifying AI</title>
        <link href="https://limited.systems/articles/demystifying-ai/"/>
        <updated>2025-09-19T00:00:00+01:00</updated>
        <id>https://limited.systems/articles/demystifying-ai</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/demystifying-ai_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;These are the resources for a webinar I have delivered in collaboration with &lt;a href=&quot;https://strategic-consulting.scot/&quot;&gt;Catherine Brys&lt;/a&gt;. If you’d like me to deliver this webinar for your community, please &lt;a href=&quot;mailto:Wim.Vanderbauwhede@glasgow.ac.uk&quot;&gt;contact me&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;webinar-description&quot;&gt;Webinar description&lt;/h2&gt;

&lt;p&gt;In this webinar I cover:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The difference between AI, Generative AI and Machine Learning and why it matters&lt;/li&gt;
  &lt;li&gt;How generative AI tools used for daily tasks actually work – and what they can and can’t do&lt;/li&gt;
  &lt;li&gt;What to be aware of when using generative AI tools or commissioning work that uses generative AI tools&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;webinar-slides&quot;&gt;Webinar slides&lt;/h2&gt;

&lt;p&gt;These are the slides from the webinar of 18 September 2025.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://limited.systems/presentation/Demystifying-AI-webinar-2025-09-18.pdf&quot;&gt;Demystifying AI slides (PDF)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;h4 id=&quot;part-i-generative-ai-vs-machine-learning&quot;&gt;Part I: Generative AI vs Machine Learning&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mdpi.com/2076-3417/12/17/8668&quot;&gt;A Two-Step Learning Model for the Diagnosis of Coronavirus Disease-19 Based on Chest X-ray Images with 3D Rotational Augmentation &lt;/a&gt; Hyuk-Ju Kwon &amp;amp; Sung-Hak Lee, Applied Sciences, 2022, 12(17), 8668&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;part-ii-genai-based-tools&quot;&gt;Part II: GenAI-based tools&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.bbc.co.uk/news/articles/c0m17d8827ko&quot;&gt;AI chatbots unable to accurately summarise news, BBC finds&lt;/a&gt;; full report: &lt;a href=&quot;https://www.bbc.co.uk/aboutthebbc/documents/bbc-research-into-ai-assistants.pdf&quot;&gt;Representation of BBC News content in AI Assistants&lt;/a&gt;, Oli Elliott, February 2025&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://arstechnica.com/ai/2024/09/australian-government-trial-finds-ai-is-much-worse-than-humans-at-summarizing/&quot;&gt;Australian government trial finds AI is much worse than humans at summarizing&lt;/a&gt;; full report: &lt;a href=&quot;https://www.aph.gov.au/DocumentStore.ashx?id=b4fd6043-6626-4cbe-b8ee-a5c7319e94a0&quot;&gt;Generative artificial intelligence (AI) document summarisation proof of concept&lt;/a&gt; AWS Professional Services, prepared for the Australian Securities and Investments Commission (ASIC), March 2024&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.cjr.org/tow_center/we-compared-eight-ai-search-engines-theyre-all-bad-at-citing-news.php&quot;&gt;AI Search Has A Citation Problem&lt;/a&gt; Klaudia Jaźwińska, Aisvarya Chandrasekar,  Columbia Journalism Review, 2025&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://arxiv.org/abs/2407.16894&quot;&gt;Estimating the Increase in Emissions caused by AI-augmented Search&lt;/a&gt; Wim Vanderbauwhede, June 2024&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/&quot;&gt;Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity
&lt;/a&gt;
Joel Becker, Nate Rush, Elizabeth Barnes, David Rein
10 July 2025&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://mlq.ai/media/quarterly_decks/v0.1_State_of_AI_in_Business_2025_Report.pdf&quot;&gt;The GenAI Divide – State of AI in Business 2025&lt;/a&gt; Aditya Challapally Chris Pease Ramesh Raskar Pradyumna Chari July 2025&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://assets.publishing.service.gov.uk/media/68adbe409e1cebdd2c96a19d/dbt-microsoft-365-copilot-evaluation.pdf&quot;&gt;The Evaluation of the M365 Copilot Pilot in the Department for Business and Trade&lt;/a&gt;,  Digital Data and Technology Monitoring and Evaluation team,  Department for Business and Trade, August 2025&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;!--
* [Endoscopist deskilling risk after exposure to artificial intelligence in colonoscopy: a multicentre, observational study](https://www.thelancet.com/journals/langas/article/PIIS2468-1253(25)00133-5/abstract) Krzysztof Budzyń, Marcin Romańczyk, Diana Kitala, Paweł Kołodziej, Marek Bugajski, Hans O Adami, et al., The Lancet, Volume 10, Issue 10 p896-903 October 2025
--&gt;

&lt;h4 id=&quot;part-iii-ethical-issues&quot;&gt;Part III: Ethical issues&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://goodlawproject.org/ai-giants-are-stealing-our-creative-work/&quot;&gt;AI giants are stealing our creative work&lt;/a&gt; Good Law Project&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://restofworld.org/2025/big-tech-ai-labor-supply-chain-african-workers/&quot;&gt;How Big Tech hides its outsourced African workforce&lt;/a&gt;  Stephanie Wangari &amp;amp; Gayathri Vaidyanathan,April 2025&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://data-workers.org/&quot;&gt;Data Workers’Inquiry&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://docs.un.org/en/A/HRC/56/68A/HRC/56/68&quot;&gt;Contemporary forms of racism, racial discrimination, xenophobia and related intolerance&lt;/a&gt; UN Special Rapporteur on contemporary forms of racism, racial discrimination, xenophobia and related intolerance, Ashwini K.P., July 2024&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.reuters.com/article/world/insight-amazon-scraps-secret-ai-recruiting-tool-that-showed-bias-against-women-idUSKCN1MK0AG/&quot;&gt;Insight - Amazon scraps secret AI recruiting tool that showed bias against women&lt;/a&gt; Jeffrey Dastin, October 2018&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.reuters.com/legal/tutoring-firm-settles-us-agencys-first-bias-lawsuit-involving-ai-software-2023-08-10/&quot;&gt;Tutoring firm settles US agency’s first bias lawsuit involving AI software&lt;/a&gt; Daniel Wiessner, August 2023&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.amnesty.org.uk/files/2025-02/Automated%20Racism%20Report%20-%20Amnesty%20International%20UK%20-%202025.pdf&quot;&gt;Automated Racism: How police data and algorithms code discrimination into policing&lt;/a&gt; Amnesty International UK, February 2025&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://mit-genai.pubpub.org/pub/8ulgrckc/release/2&quot;&gt;The Climate and Sustainability Implications of Generative AI&lt;/a&gt; 
Bashir, Noman, Priya Donti, James Cuff, Sydney Sroka, Marija Ilic, Vivienne Sze, Christina Delimitrou, and Elsa Olivetti. 2024. ” An MIT Exploration of Generative AI.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://limited.systems/articles/https://limited.systems/articles/the-insatiable-hunger-of-openai/&quot;&gt;The insatiable hunger of (Open)AI&lt;/a&gt; Wim Vanderbauwhede, March 2024&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;part-iv-societal-impact&quot;&gt;Part IV: Societal impact&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;doi:10.2139/ssrn.4895486.&quot;&gt;Generative AI Can Harm Learning.&lt;/a&gt; Bastani, Hamsa, Osbert Bastani, Alp Sungu, Haosen Ge, Özge Kabakcı, and Rei Mariman. 2024.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://limited.systems/articles/the-real-problem-with-AI&quot;&gt;The real problem with the AI hype&lt;/a&gt; Wim Vanderbauwhede, January 2025&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;books&quot;&gt;Books&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://illusion.baldurbjarnason.com/&quot;&gt;The Intelligence Illusion&lt;/a&gt; Baldur Bjarnason&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://thecon.ai/&quot;&gt;The AI Con&lt;/a&gt; Emily M Bender &amp;amp; Alex Hanna&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://bristoluniversitypress.co.uk/resisting-ai&quot;&gt;Resisting AI&lt;/a&gt; Dan Mcquillan&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;other-resources&quot;&gt;Other Resources&lt;/h2&gt;

&lt;h3 id=&quot;ai-free-search&quot;&gt;AI-free search&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;“Disable AI” browser plugin (for Firefox and Chrome only)
    &lt;ul&gt;
      &lt;li&gt;Disables Google’s AI Overview, DuckDuckGo’s AI Assist, Ecosia’s AI Overview, Brave Search’s Answer with AI, and Qwant’s AI Flash Answer&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Google specific, no plugin needed:  add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-ai&lt;/code&gt; to your search&lt;/li&gt;
  &lt;li&gt;Or use a different search engine, for example &lt;a href=&quot;https://www.ecosia.org/&quot;&gt;Ecosia&lt;/a&gt; or &lt;a href=&quot;https://www.qwant.com/&quot;&gt;Qwant&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

        </content>
    </entry>
    
    <entry>
        <title>Interview on generative AI</title>
        <link href="https://limited.systems/articles/interview-ctxt-2025/"/>
        <updated>2025-02-05T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/interview-ctxt-2025</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/interview-ctxt-2025_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;I was interviewed by &lt;a href=&quot;https://ctxt.es/user/profile/elenadesus&quot;&gt;Elena de Sus&lt;/a&gt; of Spanish progressive magazine &lt;a href=&quot;https://ctxt.es&quot;&gt;CTXT (Contexto y Acción)&lt;/a&gt;. The article in Spanish is published &lt;a href=&quot;https://ctxt.es/es/20250201/Politica/48565/Elena-de-Sus-entrevista-Wim-Vanderbauwhede-IA-deepseek-medioambiente.htm&quot;&gt;on their web site&lt;/a&gt;. This is the English version of the interview, published with kind permission of CTXT.&lt;/p&gt;

&lt;p&gt;Wim Vanderbauwhede is Professor in Computing Science at the University of Glasgow, where he leads the  Low Carbon and Sustainable Computing research group.&lt;/p&gt;

&lt;p&gt;He has written about &lt;a href=&quot;https://limited.systems/articles/climate-cost-of-ai-revolution/&quot;&gt;the high energy consumption&lt;/a&gt; of the Large Language Models used for generative AI such as ChatGPT. He posits that their projectec expansion is not sustainable.He has is also skeptical that advances in efficiency will lead to a reduction in emissions from this industry.&lt;/p&gt;

&lt;p&gt;He talked to CTXT over video call.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;You research low-carbon and sustainable computing. How did you get interested in the topic?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I have been aware of climate change for a very long time, since the 1980s. After all, it is nothing new. Originally I am from Belgium, and when I lived there I was active in an environmental organization, I did volunteering work with them.&lt;/p&gt;

&lt;p&gt;For my academic career, my focus has been mostly on improving the efficiency of computers. But it’s been known for a long time that if you improve the efficiency of something, usually it means it gets cheaper and then you get more demand, and because you get more demand, your emissions actually go up, not down.&lt;/p&gt;

&lt;p&gt;The whole history of the Industrial revolution is one of improved efficiency. The efficiency gains of the steam engine led to us burning lots of coal, because it allowed to pump the mines more efficiently, so mining coal became cheaper.&lt;/p&gt;

&lt;p&gt;Computers have become literally millions of times more efficient since 1930s or 40s. At the same time their use has become ubiquitous. So the total emissions from computing have gone up despite all the efficiency savings. There was this conflict with doing efficiency work, and I wanted to look at sustainability of computing more widely. So some years ago, I essentially got the opportunity to start a new research activity in the department that I work and with the support of the head of the department, and that was the Low Carbon and Sustainable Computing group, which we have now.&lt;/p&gt;

&lt;p&gt;The term I use is &lt;em&gt;frugal computing&lt;/em&gt;. The frugal computing message is that we should use fewer computing resources, just like essentially we should use fewer of any resource if we don’t want catastrophic climate change. We should not go for growth in the terms of growth of resource consumption and growth of energy consumption, because that is destructive. Our whole societal model is built to encourage us to use more resources and more energy. But that is not a sustainable model.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;And the opposite is happening because we are developing very resource intensive stuff like generative AI and Bitcoin.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;At some point before the AI hype started, there was the Bitcoin bubble and it looked like Bitcoin might end up using a huge amount of compute resources. But Bitcoin is not a viable currency for something like a nation state. The former finance minister of Greece, Yanis Varoufakis, has written extensively to explain it. If there is a need for of evidence, El Salvador has abandoned bitcoin as their currency. That means that Bitcoin and the derived models will probably remain rather popular in some circles, but not grow dramatically. And therefore the emissions will probably not go up a lot. Also, cryptocurrencies like Ethereum, based on the proof of stake protocol as opposed to proof of work, have become more popular. The carbon footprint of those is literally a hundred times less, so the emissions from cryptocurrencies haven’t had a dramatic growth. The current amount of emissions is not dramatic. So if it stays that way it is not really a problem. It could have been different, but it didn’t turn out like that.&lt;/p&gt;

&lt;p&gt;AI is a different issue because there’s huge support from governments around the world. Everybody seems to think it’s like magic and it will create unlimited growth. Or maybe even if they don’t believe that, they act like they believe it. That means that the this is a serious driver for creating more computer chips, data centers and generating more electricity. And at the moment, around 70% of the electricity is still from fossil fuels. So it means we’re just going to burn more coal.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;So the problem here is the state support of AI?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;It works as a delaying factor. If there is a hype bubble, it would normally collapse by itself, because people start to see that there’s nothing in it. But if governments think this is a good idea and they should invest in it, they will commit the investments and the investments will happen even after people start to see that it wasn’t worth it, because they are slow. So the whole thing gets delayed. That’s really what happens. Not so much that it stops the process. It just causes a delay. But in that delay, of course, you create more emissions.&lt;/p&gt;

&lt;p&gt;These days it’s very hard to get economic growth. And if you believe that you must get growth, then anything that promises to give you growth is something that you may want to look into. The UK government, for example, is like that. The US government also, they think that AI is going to give them growth, so they commit to investments in that area and those investments will happen. Probably even if the bubble would burst this year, they would still happen, because they have already set things in motion. It’s not that the governments drive the hype, it just doesn’t help. Of course, if your government is saying that AI is good, then it’s much harder for the ordinary person to say that AI is bad.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;With the launch of generative AI models by the Chinese company DeepSeek, which are apparently more efficient and had to get around the chip export constraints for China, it looks like the bubble has burst. Nvidia stock has gone down and there has been a lot of discourse about the fact that we don’t need that many data centers if we can have a more efficient AI. But I think you are skeptical about this.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I looked at DeepSeek, based on the information that they have wanted to give. To start with, the narrative that they had to use less capable computer chips, because of the export restrictions of the US government, in short, this is not true. I’ll explain why. 
There are export restrictions on GPUs and to satisfy these restrictions, Nvidia has created a special series of chips for the Chinese market, and they are less capable in one specific respect: double precision floating point performance. Now, AI does not use double precision floating point performance. This is needed for supercomputers that do scientific computing. But the Chinese have their own very good supercomputers for scientific computing. So they’re not buying Nvidia GPUs for their supercomputers. They’re buying them for AI; and for AI, you don’t need this.&lt;/p&gt;

&lt;p&gt;OpenAI, Google, and the rest of the US companies use an Nvidia GPUs called A100 for running the model. For training, they use a more capable type called H100. For the Chinese market Nvidia sells A800 and H800. In their whitepaper, DeepSeek says that they use the H800. Now the H800 is more capable than the A100 in almost every respect. It’s a little bit less capable in the networking. So if you combine several of these GPUs in a network, the bandwidth of the network is less, and that’s what they explained in that paper, what they did to get around that. And that’s nice engineering, but that’s not getting you so much of a benefit.&lt;/p&gt;

&lt;p&gt;All in all, it’s not as if this is some really constrained compute device. This is high end. This is actually better than what most of the large companies use now for their data centers.&lt;/p&gt;

&lt;p&gt;Deep Seek has been very clever in two ways. They have this app that people started to like. Their pricing is competitive. They have a lot of smaller models that people can play with. And I think that’s what the media has jumped on, these smaller models. But then that’s nothing special. Meta also has released open source smaller models with Llama. They are not really open source, but DeepSeek is also not really open source because the data set is not open. It’s only the code that does the compute that is released as a binary. But that’s a very different discussion.&lt;/p&gt;

&lt;p&gt;I think this was a clever way to say that they have a small model, but what runs the main inference is not all that small.
Compared to GPT-4, if they can really get the same performance, then they have done something quite clever because they use a lot less of the parameters at any one time. So it will be a bit more energy efficient, but not all that much.&lt;/p&gt;

&lt;p&gt;I mean, this idea is clever, they show that it works and it is a good thing. But we get the same problem. If their pricing is competitive, it means it’s cheaper so more people will use it. So it’s very likely that there will not really be a decrease in emissions as a result. It might very well be an increase if the company gets really big.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;We talk a lot about the cost of training the generative AI models, but you have written that using them is a lot more costly.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Um, yes. And that’s both true in terms of environmental cost and in terms of financial cost. I’m not the only one to write about this. There’s lots of people who look at the economic costs and say the training cost is fast becoming just a detail. I calculated it.&lt;/p&gt;

&lt;p&gt;For inference (running prompts), it scales with the number of users, whereas the model training, of course, only scales if you make a bigger model. And this is probably where Deep Seek has done something clever because their cluster is not very big. So they managed to train the model on a smaller cluster. That saves them their initial cost. Because they started as a small company. So that’s the training cost, but if they are going to become a big company, then they will need lots of data centers for serving all the queries. Then that will be the dominant cost. If you’re an AI company that works with big models and you train them, and that’s a huge cost, then you need a huge amount of users to make it profitable. But to get all those users, you need a lot of hardware to support them, and that’s expensive.&lt;/p&gt;

&lt;p&gt;A few years ago, the costs of training were a lot higher because they started by training these models not very efficiently. They didn’t really know how to do this well. So they needed a lot of resources to get a not so good model. They probably needed to do it a few times and so on. But now it’s definitely the cost of inference that dominates. And also the emissions from inference dominate everything.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Do you think like the markets have overreacted a little bit?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Absolutely. Yeah. Especially the US markets because this is Chinese and they are afraid of China. But I think Nvidia should not be worried. I mean, for the reason I explained, their sales depend more on the fact that people project enormous growth.&lt;/p&gt;

&lt;p&gt;The CEOs of big tech companies had been saying that they need like a 100 times expansion of chip manufacturing in the next ten years or so. These claims made the market go up. The problem is the data centers are getting committed. And then the electricity generators have to provision the electricity ahead of time because the data center needs to get the electricity as soon as it’s finished. That means if you want more electricity, you have to start building today. And because most of it is not renewable, it’s going to be gas or coal. So even if all this AI stuff does not happen at all, they will have started building it and then they will want to use it because, well, once you’ve built capacity you want to sell your electricity, right? Otherwise you have made a very bad deal. So that’s the damage I think this is doing. It’s the hype that does the damage.&lt;/p&gt;

&lt;p&gt;It’s not possible to scale up semiconductor manufacturing by a factor of 100 because, at best, we could scale up the global mining capacity for all the materials that we need to make the chips by a factor of two. So this factor of 100 is not going to happen. And probably all those people know that.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;So everybody may know it’s a bubble?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Yes. But it does a lot of damage because it gives the fossil fuel industry a perfect excuse to produce more fossil fuels, to provide the energy that they say we will need for something that is probably not going to happen.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Do you think this large language models are obviously not worth it, right? Even if they can be useful for some things.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Yeah, I personally think that the generative AI that is pushed by OpenAI and then the other companies that follow suit to compete with them, this is not very useful. I mean, it is useful for specific scenarios, but then usually when you have a specific scenario, you could use a much, much smaller model and achieve the same thing.&lt;/p&gt;

&lt;p&gt;We have had the really big models that can do everything for everybody since 2020 or so, meanwhile global productivity definitely has not gone up. The companies that start using the Microsoft Copilot and so on, the large language models for programming, they see that it’s problematic, because it’s much harder to debug code that was not written by your own developers, but written by a machine. Although you may think that you write code faster because the machine writes it, the machine doesn’t guarantee your code is correct. It can’t. You know, a generative language model has no notion of what it means. It’s just guessing. So if you’re lucky, the guess works, and usually it doesn’t. And then the developers still have to debug it. And that takes more time because they can’t read the code so well because they haven’t written it.&lt;/p&gt;

&lt;p&gt;And there’s a lot of things like that. If you look at generative AI for image processing, for generating images, superficially it looks brilliant, but it’s actually quite average. It will not replace good illustrators because people who really want a decent illustration cannot use this. Do you want to burn the planet to produce cheap illustrations?&lt;/p&gt;

&lt;p&gt;I think before generative AI appeared, there was no demand by the people to have it. And so it’s technology push, right? That’s what it’s called, rather than market pull. So the problem is that by creating this extra technology we create a lot of extra emissions at a point in time where we cannot afford any extra emissions. Emissions should go down. It’s not affordable for the planet as a whole. That’s really the problem. Whether it’s useful or not is neither here nor there. It may be extremely useful, but if it’s still burns the planet, it’s no good.&lt;/p&gt;

&lt;p&gt;And from the calculations I’ve done, if those business people’s projections would be realized, AI on its own would be enough to miss all the climate targets. Like I said, this is very unlikely. But it means that they don’t care that it would happen. In terms of energy expenditure, we can’t afford it.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Plain and simple.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;We can afford smaller models. In computing science, we really make a big distinction between what we prefer to call Machine Learning and what is being called AI, which usually means generative AI.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Yeah. Okay. There’s a lot of confusion with this. Could you explain what is the difference?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;The UK government also makes this mistake. They talk about how AI can do great things like detect cancer in an MRI or X-ray image and therefore we should build more data centers for generative AI. But SegNet, the leading model in colon cancer detection, with a 99% accuracy rate, has 7.6 million parameters, while GPT4 has more than a trillion. 
This means that SegNet uses 100,000 times less energy than GPT4. It can run on a PC in the hospital. You don’t need to build any data center to get better diagnostics. Just a few servers in hospitals.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;But is there something in common between these different things that we call AI?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Most models these days use a neural network. A neural network is an abstraction inspired by the brain where essentially you get some inputs which are numbers, and you multiply them by other numbers and you add them, and that gives you another number as an output. And then usually you try to limit the range of that other number or something. That’s what they call a neuron. So something that gets a few inputs multiplies them by weights and then adds them and then normalizes the result and sends that on to another neuron. And if you do that enough times, you get something that actually can do extrapolation on a very large parameter space. So it is very good at… let’s call it guessing, but it’s statistical approximation.&lt;/p&gt;

&lt;p&gt;The model that is used for cancer detection is called a convolutional neural network. These are the ones that are used for images. For text, it’s called recurrent neural network. In an image, you have to look at all the data in parallel in space. So all the pixels are next to one another. In language, your words come one after another. So there are basically two types of neural networks. The generative AI, large language models that we use, they are essentially much advanced versions of these simple neural networks that I described.&lt;/p&gt;

&lt;p&gt;There is a difference between a model that detects a pattern in an image and a generative model has to produce new text or a new image. It’s more work than just finding a pattern. That’s also why generative models are more expensive in energy terms. They need to do more computations because they do more work.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Some people are saying that there is a limit on the training data, that that these models have already used as much data as possible and they maybe cannot find a lot more. I don’t know if that’s true.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Uh, it’s worse than that. A lot of the content on the internet now is AI generated. And the problem is that if you give an AI model AI generated content as input data, then it tends to get very poor performance very quickly. It’s called poisoning. But it’s not easy to avoid because the bots that scrape the internet cannot tell whether a page is AI generated or not. That actually means the best quality general purpose data sets will be from before 2022.&lt;/p&gt;

&lt;p&gt;Also, you can’t really keep on making the models bigger, you have to start doing these things like what DeepSeek does. Actually OpenAI already did that. They just didn’t do it on the same scale. But so OpenAI has a model that is 1.76 trillion parameters, but actually at any point in time they ever use, what was it again, two times 200 billion. So they use a much smaller subset of that. And this is purely because you can’t access all of them all the time. What DeepSeek has shown is that if you use even less, it still works well. Most of the concepts that they use in their paper are already being researched by all the other companies as well.&lt;/p&gt;

&lt;p&gt;Anyway, you can’t keep on making them all bigger and expect that it will perform better because there are limits both on the quality of the data, but also on the engineering of making this happen. So yeah, the performance will probably start to stagnate, will not get much better.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;So the notion that we can reach some kind of artificial general intelligence by doing this is false?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;This is absurd. I mean, I think the people who promote this idea, they know this this is a distraction, right? Because then you can say “Oh, artificial general intelligence would be very dangerous and we have to have all kinds of safeguards in place to make sure that if we have one, it behaves and it does the right thing for us and so on”, and that’s a perfect distraction not to have to worry about all the real negative consequences of the fact that companies put out all these products. That’s to my mind, what’s behind it.&lt;/p&gt;

&lt;p&gt;There is no chance that what is effectively just a statistical pattern generator can become intelligent. There is nothing in the model that actually mimics intelligence.&lt;/p&gt;

&lt;p&gt;I mean, people have been thinking about artificial intelligence for probably 50 years or more. Very deeply. And I think anyone who really has spent a lot of thought on this would agree that the generative AI models or whatever models that we call AI now really are not of the type that would give us a self-aware piece of software.
It seems intelligent because almost everything that we know is in there. A summary of all the knowledge that humans have put online is in those models. So there is an approximation of just about anything in there. But it’s by no means intelligent.&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>Cheaper AI does not mean greener AI</title>
        <link href="https://limited.systems/articles/cheaper-ai-is-not-greener-ai/"/>
        <updated>2025-01-26T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/cheaper-ai-is-not-greener-ai</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/cheaper-ai-is-not-greener-ai_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;In this article I have a look at the cost of running queries for GPT-4 and similar models, in view of the drop in price per prompt. The main conclusions are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The energy efficiency gains for queries to large language models (LLM) are not leading to lower emissions.&lt;/li&gt;
  &lt;li&gt;On the contrary, the lower prices are likely to lead to increased use and therefore higher emissions.&lt;/li&gt;
  &lt;li&gt;The cost of a query is mainly made up of the fixed cost (capex) of the data centre (building, cooling and network infrastructure) and GPU servers. The electricity consumption contribution is a small proportion.&lt;/li&gt;
  &lt;li&gt;Therefore, to maximise profit, the GPU server utilisation is optimised to support as many users as possible on the available hardware.&lt;/li&gt;
  &lt;li&gt;But higher utilisation means higher energy consumption and therefore higher emissions, even if the energy consumption per query would be lower. The projected strong growth in number of queries makes this even worse, as it means the data centre capacity needs to grow steepl as well.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-urgent-need-to-reduce-emissions&quot;&gt;The urgent need to reduce emissions&lt;/h2&gt;

&lt;p&gt;To reiterate, according to the 2024 Emissions Gap Report of the UN &lt;a href=&quot;#1&quot;&gt;[1]&lt;/a&gt;, the world must cut global greenhouse gas emissions to 20 gigatons CO₂-equivalent per year (GtCO₂e/y) by 2040 from the current level of 60 GtCO₂e/y to avoid catastrophic global warming, where “catastrophic” is meant quite literally: there will be a huge increase in the frequency and severity of natural catastrophes if we don’t do this. Large parts of the earth will become unsuitable for habitation and agriculture.&lt;/p&gt;

&lt;p&gt;To arrive at a sustainable level of emissions by 2040, global CO₂ emissions should be reduced by close to 20% per year. However, currently, emissions are still rising at 1% – 2% per year, despite the increase in renewable electricity generation capacity.&lt;/p&gt;

&lt;p&gt;The 2024 Emissions Gap Report of the UN &lt;a href=&quot;#1&quot;&gt;[1]&lt;/a&gt; explains in detail why renewables, carbon dioxide removal and carbon offsetting alone will not be sufficient to meet the targets.&lt;/p&gt;

&lt;h2 id=&quot;cheaper-prompts-greener-prompts&quot;&gt;Cheaper prompts, greener prompts?&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Note on terminology: I use the terms prompt and query interchangeably. The prompt is what you type, the query is the action of sending it to the server. Furthermore, a token is a small group of characters, between a single character and a word.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The price per query or token for various LLMs has come down considerably compared to prices when GPT-3 was released &lt;a href=&quot;#2&quot;&gt;[2]&lt;/a&gt;.
&lt;!-- better glue --&gt;&lt;/p&gt;

&lt;p&gt;However, the energy consumption of GPT-4 is still several times larger than for GPT-3 &lt;a href=&quot;#5&quot;&gt;[5]&lt;/a&gt;, and the energy consumption of Gemini 1.5 Pro is still of the order of GPT-3. How is this compatible with the more than ten times lower prices for GPT-4 compared to GPT-3? Let’s have a look at the figures — and the factors that influence these.&lt;/p&gt;

&lt;h3 id=&quot;electricity-pricing-for-data-centres-is-very-low&quot;&gt;Electricity pricing for data centres is very low&lt;/h3&gt;

&lt;p&gt;Large users of electricity pay wholesale prices for electrity. So the more electricity you use, the cheaper it is per unit, ironically. Because of their size, Google or OpenAI pay the lowest prices. The price they pay for their electricity is less than 6 cents per kWh &lt;a href=&quot;#6&quot;&gt;[6]&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;energy-consumption-of-a-gpt-4-style-large-language-model&quot;&gt;Energy consumption of a GPT-4 style large language model&lt;/h3&gt;

&lt;p&gt;As I have discussed in detail in my article &lt;a href=&quot;#7&quot;&gt;[7]&lt;/a&gt;, the best estimate for the electricity consumption for GPT-3 and BLOOM is 0.003 kWh per query. For the queries used in that work, the average query response length was 100 words. At 6 cents per kWh, the electricity cost for such a query would be 0.018 cents, i.e. $0.00018.&lt;/p&gt;

&lt;p&gt;GPT-4 is said to be 3× more expensive than GPT-3 &lt;a href=&quot;#5&quot;&gt;[5]&lt;/a&gt;, but GPT-4 Turbo could be only 1.5× more expensive, as it is a compressed model.&lt;/p&gt;

&lt;p&gt;Gemini 1.5 Pro is said to have 200B parameters &lt;a href=&quot;#17&quot;&gt;[17]&lt;/a&gt;, which is of the same order as GPT-3. Using the cost per query for GPT-3 query, and model energy consumption scaling as the square root with parameter size as in this paper &lt;a href=&quot;#18&quot;&gt;[18]&lt;/a&gt;, we  estimate that it is 1.07× more expensive than GPT-3. Some say that it is only a 120B parameter model &lt;a href=&quot;#19&quot;&gt;[19]&lt;/a&gt;; if that is the case, the factor is 0.8×, i.e. slightly cheaper than GPT-3.&lt;/p&gt;

&lt;h2 id=&quot;what-makes-up-the-cost-of-a-query&quot;&gt;What makes up the cost of a query?&lt;/h2&gt;

&lt;p&gt;There are three main components to the cost of running a query:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the capes cost of the servers,&lt;/li&gt;
  &lt;li&gt;the capex cost of the data centre and&lt;/li&gt;
  &lt;li&gt;the running cost of the data centre.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;the-capex-cost-of-the-servers&quot;&gt;The capex cost of the servers&lt;/h3&gt;

&lt;p&gt;For example, a Nvidia DGX-A100 server with eight A100 GPUs &lt;a href=&quot;#9&quot;&gt;[9]&lt;/a&gt; would cost $240k. (As I sanity check, in Feb 2023, SemiAnalysis &lt;a href=&quot;#10&quot;&gt;[10]&lt;/a&gt; quoted $195k for an 8× A100 server.) Running it for a year would cost about $2,400 (using a power consumption of 4550 W as reported by Nvidia &lt;a href=&quot;#11&quot;&gt;[11]&lt;/a&gt;).
So, for the running cost to exceed the fixed cost, the GPU server would need to run for a hundred years. But the servers will likely be replaced by the next generation GPU, which will arrive after two years, or at best after 5 years, so the hardware cost makes up the majority of the price.&lt;/p&gt;

&lt;h3 id=&quot;the-capex-cost-of-the-data-centre&quot;&gt;The capex cost of the data centre&lt;/h3&gt;

&lt;p&gt;Hyperscale data centres are very expensive to build. The cost for a 60MW data centre that could accommodate 10,000 of the above servers is between $420 and $770M for construction &lt;a href=&quot;#13&quot;&gt;[13]&lt;/a&gt;. Such a data centre has an expected life of 15 to 20 years &lt;a href=&quot;#12&quot;&gt;[12]&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;the-running-cost-of-the-data-centre&quot;&gt;The running cost of the data centre&lt;/h3&gt;

&lt;p&gt;The running cost of the data centre is dominated by the cost of the electricity for running the servers, network and cooling. In a modern data centre, the contribution of the network and cooling is small, certainly less that 10%.&lt;/p&gt;

&lt;p&gt;So let’s consider a 60MW data centre that can host 10,000 servers. As discussed above, running a single server for a year costs $2,400. We assume a conservative model where we replace the servers only after 5 years (usually they are replaced after 3 years). We take the average cost of $595M for construction and a 20-year lifespan. The data centre will not operate at full capacity from the start, so we assume that we start at 1/4 capacity (2,500 servers), and add 1/4 every 5 years for 20 years. With those assumptions, the electricity cost would be $15M/year.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;This assumes that server and electricity costs don’t change much over that period.&lt;/li&gt;
  &lt;li&gt;It is likely that each newer generation of hardware is about twice as energy efficient. If we took that into account, the electricity would only be $2.4M/year, or less than 2% of the cost average over 15 years.&lt;/li&gt;
  &lt;li&gt;If the costs for servers and electricity decreased over this period, the relative component of the infrastructure would increase but the electricity cost would still be a small proportion.&lt;/li&gt;
  &lt;li&gt;If servers were replaced more frequently (every two years), then the contribution of the electricity usage to the cost will be even lower.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(For completeness sake, such a 60MW data centre would use about 400M gallons of cooling water per year &lt;a href=&quot;#14&quot;&gt;[14]&lt;/a&gt;, but that would cost only about $1M/year.)&lt;/p&gt;

&lt;h3 id=&quot;overall-costs&quot;&gt;Overall costs&lt;/h3&gt;

&lt;p&gt;On a yearly basis, we have $120M/year for the capex contribution of the servers and $30M/year for the capex contribution of the infrastructure. Consequently, more than 70% of the cost of running a query is the capex contribution of the servers ans the $15M/year for the electricity is less than 10% of the total cost of about $165M/year.&lt;/p&gt;

&lt;p&gt;What this tells us is that what matters in terms of profit is to optimise the utilisation of those expensive GPUs. So when the cost per query goes down, it is likely the consequence of improved utilisation, which means more users can be supported simultaneously, rather than improved energy efficiency.&lt;/p&gt;

&lt;h2 id=&quot;pricing-versus-energy-cost&quot;&gt;Pricing versus energy cost&lt;/h2&gt;

&lt;p&gt;Let’s consider the pricing for two popular large language models: Google’s Gemini 1.5 Pro and OpenAI’s GPT-4. Both are very recent models and similar in capabilities.&lt;/p&gt;

&lt;h3 id=&quot;gemini-15-pro-pricing&quot;&gt;Gemini 1.5 Pro pricing&lt;/h3&gt;

&lt;p&gt;Generating 10,000 words using Gemini 1.5 Pro (10 RPM) costs ~$0.28 &lt;a href=&quot;#15&quot;&gt;[15]&lt;/a&gt; and the cost is proportional to the number of generated words (1000 words is ~$0.028, 100 words is ~$0.003)&lt;/p&gt;

&lt;h3 id=&quot;gpt-4-pricing&quot;&gt;GPT-4 pricing&lt;/h3&gt;

&lt;p&gt;OpenAI charges between $0.030 and $0.120 per 1,000 tokens on GPT-4 &lt;a href=&quot;#16&quot;&gt;[16]&lt;/a&gt; depending on the context length. The $0.030 is for GPT-4 Turbo, which is likely smaller than GPT-4.&lt;/p&gt;

&lt;h3 id=&quot;the-price-is-much-higher-than-the-energy-cost&quot;&gt;The price is much higher than the energy cost&lt;/h3&gt;

&lt;p&gt;From the above data on cost and pricing of the models, we can calculate the price/cost ratios.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;For Gemini 1.5 Pro, the ratio is  $0.028 / ($0.0018*1.07) = 14.55x; in other words, the price is 15× higher than the electricity cost. If the model was only a 120B parameters, the ratio would be 18.8×.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;For GPT-4, the ratios are {0.030/1.5, 0.06/3,0.120/3 }/ 0.0018 =  {11.1×, 11.1×, 22.2×}; in other words, the price is 11× or 22× higher than the electricity cost.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These figures are consistent with the relative cost contributions: with the GPU server and data centre capex cost about 10× larger than the electricity cost, the price should indeed be more than 10× that of the electricity consumption.&lt;/p&gt;

&lt;p&gt;As shown above, the electricity consumption does not contribute much to the overall cost. Therefore, Google and OpenAI don’t have a huge incentive to prioritise increasing energy efficiency. The main incentive is to increase utilisation. A higher utilisation means lower energy consumption per query and also a small conbtribution of the capex per query. But it also means a higher overall energy consumption.&lt;/p&gt;

&lt;p&gt;It’s also worth noting that the drop in prices can’t be explained by the utilisation gains or the energy efficiency gains: going from 50% utilisation to 100% would reduce the capex contribution by a factor of two and the energy consumption per query by 30%. And based on the above estimates, none of the models have improved dramatically in terms of energy efficiency. So most of the price drop is due to increased competition.&lt;/p&gt;

&lt;!--
Say load is 50% and idle is 30%., then 100*.5 +30*.5 for .5 = 130 per q but only 65 overall
Say load is 100%, 100*1 for 1 = 100 per q but 100 overall

Suppose we are 20% more energy efficient 

80*.5+30*.5 = 55
80*1+30*0 = 80 
--&gt;

&lt;h2 id=&quot;a-note-on-the-emissions&quot;&gt;A note on the emissions&lt;/h2&gt;

&lt;p&gt;There are two main components to the emissions for a query: the electricity use and the emissions from manufacturing the server. We have created a detailed life cycle analysis model for the GPU servers in and AI data centre &lt;a href=&quot;#20&quot;&gt;[20]&lt;/a&gt; and calculated the embodied carbon emissions and emissions from use for hardware replacement cycles of 2, 3 and 5 years. The results depend on many assumptions, but the conclusion is robust: embodied carbon from manufacturing the servers will be of the same order as the emissions from running the servers. Replacing the servers sooner by newer hardware does not change the overall picture much.&lt;/p&gt;

&lt;p&gt;This is mainly because of the strong growth in demand for AI data centres, which leads to production of ever increasing amounts of hardware, and the increased energy efficiency of the new hardware does not make up for this growth. I have used a figure of 22% growth per year as per the analysis by McKinsey &lt;a href=&quot;#21&quot;&gt;[21]&lt;/a&gt;. So although the energy efficiency of the hardware increases with every generation, the combination of embodied carbon emissions and emissions from use resulting from the growth in demand results in a huge increase in emissions. For a more detailed discussion on the growth projections of the demand for AI data centres and the concomitant emissions, please read my article “The real problem with the AI hype” &lt;a href=&quot;#22&quot;&gt;[22]&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;For both Gemini 1.5 Pro and GPT-4, we see that their energy consumption is still of the order of GPT-3, and even with current low prices, the price is more than ten times the energy cost. This is because the high cost and relatively short lifetime of the GPU servers makes up most of the total cost of running a query. Of course the argument is that both models are more capable than GPT-3. But the point is that large-scale deployment of these models leads to unacceptably high and rapidly increasing CO₂ emissions.&lt;/p&gt;

&lt;p&gt;From a climate change perspective, energy efficiency gains are only really meaningful if they result in a reduction of the overall emissions. That is clearly not the case. And the low price is likely to make this only worse, as it will drive adoption and further growth in data centres and so increase both embodied carbon and runtime emissions.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;&lt;small&gt;&lt;span id=&quot;1&quot;&gt;[1] &lt;a href=&quot;https://www.unep.org/resources/emissions-gap-report-2024&quot;&gt;&lt;em&gt;“Emissions Gap Report 2024”&lt;/em&gt;, UN Environment Programme, 24 October 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;2&quot;&gt;[2] &lt;a href=&quot;https://simonwillison.net/2024/Dec/31/llms-in-2024/&quot;&gt;&lt;em&gt;“Things we learned about LLMs in 2024”&lt;/em&gt;, Willison S., 31 December 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;5&quot;&gt;[5] &lt;a href=&quot;https://semianalysis.com/2023/07/10/gpt-4-architecture-infrastructure/&quot;&gt;&lt;em&gt;“GPT-4 Architecture, Infrastructure, Training Dataset, Costs, Vision, MoE Demystifying GPT-4: The engineering tradeoffs that led OpenAI to their architecture”&lt;/em&gt;, Patel D. and Wong G., 10 July 2023, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;6&quot;&gt;[6] &lt;a href=&quot;https://h5datacenters.com/cincinnati-data-centre.html&quot;&gt;&lt;em&gt;“Cincinnati I Data Center Attributes”&lt;/em&gt;, H5 Data Centers, 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;7&quot;&gt;[7] &lt;a href=&quot;https://arxiv.org/abs/2407.16894&quot;&gt;&lt;em&gt;“Estimating the Increase in Emissions caused by AI-augmented Search”&lt;/em&gt;, Vanderbauwhede W., 6 January 2025, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;8&quot;&gt;[8] &lt;a href=&quot;https://www.stylefactoryproductions.com/blog/chatgpt-statistics&quot;&gt;&lt;em&gt;“ChatGPT Statistics — The Key Facts and Figures”&lt;/em&gt;, Walsh M., 22 April 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;9&quot;&gt;[9] &lt;a href=&quot;https://bizon-tech.com/bizon-g9000.html#4654:46140;4656:46198;4658:46417;4660:46293;4661:46306&quot;&gt;&lt;em&gt;“BIZON G9000 – 4x 8x NVIDIA A100, H100, H200 Tensor Core AI GPU Server with AMD EPYC, Intel Xeon”&lt;/em&gt;, BIZON, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;10&quot;&gt;[10] &lt;a href=&quot;https://semianalysis.com/2023/02/09/the-inference-cost-of-search-disruption&quot;&gt;&lt;em&gt;“The Inference Cost Of Search Disruption – Large Language Model Cost Analysis $30B Of Google Profit Evaporating Overnight, Performance Improvement With H100 TPUv4 TPUv5”&lt;/em&gt;, Patel D. and Ahmad A., 9 February 2023, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;11&quot;&gt;[11] &lt;a href=&quot;https://developer-blogs.nvidia.com/wp-content/uploads/2024/10/Energy-Efficiency-GTC.pdf&quot;&gt;&lt;em&gt;“Energy and Power Efficiency for Applications on the Latest NVIDIA Technology”&lt;/em&gt;, Gray A, 
Alan Gray, GTC 24, GTC 2024, 20th March 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;12&quot;&gt;[12] &lt;a href=&quot;https://www.datacenterdynamics.com/en/analysis/the-data-center-life-story/&quot;&gt;&lt;em&gt;“The data center life story”&lt;/em&gt;, Judge P., 21 July 2017, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;13&quot;&gt;[13] &lt;a href=&quot;https://dgtlinfra.com/how-much-does-it-cost-to-build-a-data-center/&quot;&gt;&lt;em&gt;“How Much Does it Cost to Build a Data Center?”&lt;/em&gt;, Zhang M., 5 November 2023, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;14&quot;&gt;[14] &lt;a href=&quot;https://eng.ox.ac.uk/case-studies/the-true-cost-of-water-guzzling-data-centres&quot;&gt;&lt;em&gt;“Water-guzzling data centres”&lt;/em&gt;, Ashtine M. and Mytton D., retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;15&quot;&gt;[15] &lt;a href=&quot;https://invertedstone.com/calculators/gemini-pricing/&quot;&gt;&lt;em&gt;“Gemini Pro API Pricing Calculator”&lt;/em&gt;, InvertedStone, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;16&quot;&gt;[16] &lt;a href=&quot;https://help.openai.com/en/articles/7127956-how-much-does-gpt-4-cost&quot;&gt;&lt;em&gt;“How much does GPT-4 cost?”&lt;/em&gt;, OpenAI, 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;17&quot;&gt;[17] &lt;a href=&quot;https://felloai.com/2024/09/google-gemini-pro-1-5-all-you-need-to-know-about-this-near-perfect-ai-model/&quot;&gt;&lt;em&gt;“Google Gemini PRO 1.5: All You Need To Know About This Near Perfect AI Model”&lt;/em&gt;, Shittu H., 9 September 2024	, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;18&quot;&gt;[18] &lt;a href=&quot;https://ieeexplore.ieee.org/document/10549890&quot;&gt;&lt;em&gt;“Measuring and Improving the Energy Efficiency of Large Language Models Inference”&lt;/em&gt;, Argerich M. and Patiño-Martínez M., IEEE Access, 2024, Vol. 12, 5 June 2024&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;19&quot;&gt;[19] &lt;a href=&quot;https://www.reddit.com/r/LocalLLaMA/comments/1cxlsa9/i_read_the_full_gemini_15_may_technical_paper_i/&quot;&gt;&lt;em&gt;“Discussion: Gemini 1.5 May Technical paper”&lt;/em&gt;, 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;20&quot;&gt;[20] &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/low-carbon-computing/src/branch/master/LCA-model-equations/runLCAModel-AI.hs&quot;&gt;&lt;em&gt;“LCA model for servers in a data centre “&lt;/em&gt;, Vanderbauwhede W., 16 January 2025, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;21&quot;&gt;[21] &lt;a href=&quot;https://www.mckinsey.com/industries/technology-media-and-telecommunications/our-insights/ai-power-expanding-data-center-capacity-to-meet-growing-demand&quot;&gt;&lt;em&gt;“AI power: Expanding data center capacity to meet growing demand”&lt;/em&gt;,  McKinsey &amp;amp; Company, 29 October 2024 , retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;22&quot;&gt;[22] &lt;a href=&quot;https://limited.systems/articles/the-real-problem-with-AI/&quot;&gt;&lt;em&gt;“The real problem with the AI hype”&lt;/em&gt;,  Vanderbauwhede, W., 16 January 2025 , retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;


        </content>
    </entry>
    
    <entry>
        <title>The real problem with the AI hype</title>
        <link href="https://limited.systems/articles/the-real-problem-with-AI/"/>
        <updated>2025-01-16T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/the-real-problem-with-AI</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/the-real-problem-with-AI_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;Climate change is an environmental problem. But our environment is what allows our society to thrive. The damage from climate change is societal and economical as well as ecological. And the only way to minimise this damage is to reduce global CO₂ emissions. Even keeping them at the current level will cause catastrophic warming. All this is explained in detail in the 2024 Emissions Gap Report of the United Nations &lt;a href=&quot;#16&quot;&gt;[16]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The current push for generative AI is deeply problematic in many ways. In this article I want to focus on the very real environmental damage caused not so much by the technology itself as by the hype surrounding it.&lt;/p&gt;

&lt;p&gt;In short:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The hype creates an expectation of huge growth in demand for AI. Data centre companies have to start building capacity before this demand is realised, even if it never materialises. As a result, data centre capacity is being built up right now at an unprecedented scale.&lt;/li&gt;
  &lt;li&gt;This requires electricity generators to provision capacity for those future data centres, even if they would never be used.&lt;/li&gt;
  &lt;li&gt;Without strong growth in demand, electricity generators would phase out fossil fuel generation because generating electricity from renewable sources is more cost-effective. Because of the AI hype, they are no longer phasing out fossil fuel generation as they want to maximise generation capacity to maximise future profits. New fossil fuel powered electricity plants are being developed as a result &lt;a href=&quot;#1&quot;&gt;[1]&lt;/a&gt; and existing ones are kept open for longer &lt;a href=&quot;#2&quot;&gt;[2]&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;As electricity generators of course want to optimise current profits as well, they want to sell all the electricity they can generate, rather than let plants idle.&lt;/li&gt;
  &lt;li&gt;And so global emissions from electricity generation are not decreasing at all, and are even expected to rise in the near future. This at a time when we need to reduce global emissions urgently and drastically.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;breakdown-of-data-centre-emissions&quot;&gt;Breakdown of data centre emissions&lt;/h2&gt;

&lt;p&gt;The greenhous gas emissions from a data centre can be broken down into a few main components, based on when and where the emissions are incurred:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Emissions incurred while building the data centre infrastructure (mainly the building itself and the cooling system). We will not discuss this further as it is mostly likely a relatively small contribution.&lt;/li&gt;
  &lt;li&gt;Emissions incurred while manufacturing the servers used in the data centre. The part of server manufacturing that produces by far the most emissions is the chip production. We will therefore focus on emissions from chip production&lt;/li&gt;
  &lt;li&gt;Emissions incurred while producing the electricity to run the servers. This is called the carbon intensity of electricity generation. This depends on where the data centre is located. But as data centres are globally distributed, we can consider the global average emissions of electricity production.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We call 1. and 2. the “embodied carbon emissions” and 3. the “emissions from use”.&lt;/p&gt;

&lt;p&gt;I think it is important to note that the global carbon intensity of electricity generation is decreasing. Unfortunately, this does not result in a decrease in emissions: what we see is that renewables are installed &lt;em&gt;in addition&lt;/em&gt; to fossil fuel generation, rather than replacing them.&lt;/p&gt;

&lt;h2 id=&quot;a-rough-estimate-of-the-growth-in-emissions&quot;&gt;A rough estimate of the growth in emissions&lt;/h2&gt;

&lt;p&gt;Let’s first do a rough estimate. I present it mainly to give an idea of the scale of the global data centre power demand and of the chip production for the data centre servers.&lt;/p&gt;

&lt;h3 id=&quot;emissions-from-data-centre-use&quot;&gt;Emissions from data centre use&lt;/h3&gt;

&lt;p&gt;In 2023, the global electricity demand of data centres was 55 GW according to McKinsey &lt;a href=&quot;#3&quot;&gt;[3]&lt;/a&gt;. According to Cushman &amp;amp; Wakefield &lt;a href=&quot;#4&quot;&gt;[4]&lt;/a&gt; it was 17 GW + 6 GW + 11 GW = 34 GW for Americas, EMEA and APAC combined, with another 49 GW under development. For APAC &lt;a href=&quot;#5&quot;&gt;[5]&lt;/a&gt; and for EMEA &lt;a href=&quot;#6&quot;&gt;[6]&lt;/a&gt;, Savills confirm 11 GW resp. 6 GW; an extensive report by Lawrence Berkeley National Laboratory (LLNL) &lt;a href=&quot;#7&quot;&gt;[7]&lt;/a&gt; gives 20 GW for the US. So the figure used by McKinsey seems to be reliable.&lt;/p&gt;

&lt;p&gt;In terms of energy consumption that means 482 TWh/year. Global electricity generation is 30,000 TWh/y according to Our World in Data &lt;a href=&quot;#8&quot;&gt;[8]&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;embodied-carbon-emissions&quot;&gt;Embodied carbon emissions&lt;/h3&gt;

&lt;p&gt;I estimate the production of chips for data centres to consume 20 TWh/y. This is a very rough approximation, and likely an underestimate: I took the data for TSMC in Taiwan, which is producing most of Nvidia’s GPUs but is of course not the only chip producer in the world. But in Taiwan are the four Gigafabs that make most of the GPUs so I used this as my estimate.&lt;/p&gt;

&lt;p&gt;TSMC reports that there are in total 8 Gigafabs of which 4 in Taiwan &lt;a href=&quot;#9&quot;&gt;[9]&lt;/a&gt;; also in Taiwan, 4 8-inch fabs and 1 6-inch fab; overall, 16 million 12-inch equivalent wafers in 2023. The combined capacity of the four facilities exceeded 12 million 12-inch wafers in 2023. So the four Gigafabs account for 3/4 of the total production.&lt;/p&gt;

&lt;p&gt;In 2023, TSMC’s fabs consumed 23 TWh. Based on  a report by S&amp;amp;P Global &lt;a href=&quot;#10&quot;&gt;[10]&lt;/a&gt; this was 8% of Taiwan’s total electricity production, which was 288 TWh in 2023 &lt;a href=&quot;#11&quot;&gt;[11]&lt;/a&gt;. A article from Sept 2024 in IEEE Spectrum says it will be 12.5% in 2025 &lt;a href=&quot;#12&quot;&gt;[12]&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;growth-in-overall-data-centre-emissions&quot;&gt;Growth in overall data centre emissions&lt;/h3&gt;

&lt;p&gt;Suppose the demand for AI data centres grows by 10× in ten years. That is about 25% per year and is within McKinsey’s &lt;a href=&quot;#3&quot;&gt;[3]&lt;/a&gt; projections. 
Assuming a global electricity carbon intensity of 480 gCO₂e/kWh &lt;a href=&quot;#13&quot;&gt;[13]&lt;/a&gt; or 0.000480 GtCO₂e/TWh, then by 2035  the data centres would consume 4800 TWh/y and this would result in 2.3 GtCO₂e emissions. The chip production would consume 200 TWh/y or an extra 0.1 GtCO₂e. So the total data centre emissions as a result of 25% year on year growth over 10 years would be 2.4 GtCO₂e with this rough estimate.&lt;/p&gt;

&lt;h2 id=&quot;issues-with-this-estimate&quot;&gt;Issues with this estimate&lt;/h2&gt;

&lt;p&gt;There are several oversimplifications in the above estimate. The most important one is that we can expect the electricity carbon intensity to keep decreasing over time. This will also affect the emissions from chip production. Furthermore, the servers are not running at full power all the time. So the actual emissions should be lower than this rough estimate. There are many other factors affecting the estimate, so to do this properly we need a much more refined model.&lt;/p&gt;

&lt;h2 id=&quot;a-better-estimate-of-the-growth-in-emissions&quot;&gt;A better estimate of the growth in emissions&lt;/h2&gt;

&lt;p&gt;We made a model for the evolution of data centre emissions over time, which takes into account both the embodied carbon &lt;a href=&quot;#15&quot;&gt;[15]&lt;/a&gt; and the emissions from use &lt;a href=&quot;#14&quot;&gt;[14]&lt;/a&gt;. 
This model does not take into account the embodied carbon emissions from creating the actual infrastructure (data centres themselves, electricity supplies, networking, roads, water supplies). According to UNEP &lt;a href=&quot;#17&quot;&gt;[17]&lt;/a&gt;, the footprint of the gobal construction sector was 10 GtCO₂e/y. Data centres are only a small fraction of all global construction, but I could not find reliable data and therefore could not include this contribution in the calculations.&lt;/p&gt;

&lt;p&gt;Using our model, we arrive at an electricity consumption of 3330 TWh/y for the data centres by 2035. This is of the same order as the rough estimate, but as expected somewhat lower. 
&lt;!-- 
The embodied carbon (which we modeled above by the estimate share of TSMC&apos;s electricity) is also considerably lower. The overall figure is 1.6 GtCO₂e of additional emissions (rather than the 2.4 GtCO₂e from our rough model; but rough as it was, this is quite close). 
--&gt;&lt;/p&gt;

&lt;p&gt;The embodied carbon (which we modeled above by the estimate share of TSMC’s electricity) is considerably higher. The overall figure is 2.7 GtCO₂e of additional emissions (rather than the 2.4 GtCO₂e from our rough model; but rough as it was, this is quite close).&lt;/p&gt;

&lt;p&gt;This is quite problematic: the total global CO₂ budget for 2035 is 22 GtCO₂e/y according to the UNEP Emissions Gap Report 2024 &lt;a href=&quot;#16&quot;&gt;[16]&lt;/a&gt;. Global emissions from electricity generation were 14 GtCO₂e in 2023 and projected to rise to 15 GtCO₂e by 2035 without the growth in AI.&lt;/p&gt;

&lt;p&gt;And if this trend would persist, then after 20 years of 19% growth year on year (McKinsey’s lowest estimate), the additional emissions would be almost 20 GtCO₂e/y.&lt;/p&gt;

&lt;h2 id=&quot;what-about-a-hundred-times-growth&quot;&gt;What about a hundred times growth?&lt;/h2&gt;

&lt;p&gt;If you think that the above growth rates sound crazy, Dell’s CEO has said that data centre capacity will increase by 100× over the next 10 years &lt;a href=&quot;#18&quot;&gt;[18]&lt;/a&gt;. And OpenAI’s Altman has said &lt;a href=&quot;#19&quot;&gt;[19]&lt;/a&gt; the world need 100× more semiconductor production capacity, which amounts to the same.&lt;/p&gt;

&lt;p&gt;Needless to say, 100× growth would be a disaster: even if it happened in 20 years rather than in Michael Dell’s 10 years, it would mean we end up at 58,000 TWh/y just for the data centres, and additional emissions of 31 GtCO₂e/y on a global CO₂ budget of only 10 GtCO₂e/y &lt;a href=&quot;#16&quot;&gt;[16]&lt;/a&gt; by 2045. In other words purely the emissions from making and running the servers would be more than the global emissions budget to meet the climate targets.&lt;/p&gt;

&lt;h2 id=&quot;the-hype-on-its-own-is-the-real-problem&quot;&gt;The hype on its own is the real problem&lt;/h2&gt;

&lt;p&gt;To come back to my orginal premise: even if the growth in AI never materialises, the hype has set in motion a chain of events which, if allowed to go unchecked, can only lead to a rise in emissions.&lt;/p&gt;

&lt;p&gt;Once the extra electricity generation capacity has been created, generators will want to sell that electricity and therefore push hard to increase consumption. They will feel they have little choice, as they need at least to recoup their investment.&lt;/p&gt;

&lt;p&gt;Data centre operators also want to make a profit, or at least not a loss, so even if AI would die an ignoble death, they will try to find new workloads, and again push at consumers to use those new services.&lt;/p&gt;

&lt;p&gt;In this way the AI hype leads to increase emissions, even if there was no growth in AI workloads. And this at a time when we need to reduce global emissions urgently and drastically. Therefore &lt;em&gt;any&lt;/em&gt; source of considerable additional emissions are problematic.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: the banner picture is&lt;/em&gt; not &lt;em&gt;AI-generated&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;&lt;small&gt;
&lt;span id=&quot;1&quot;&gt;[1] &lt;a href=&quot;https://www.ft.com/content/63c3ceb2-5e30-44f4-bd39-cb40edafa4f8&quot;&gt;&lt;em&gt;“AI set to fuel surge in new US gas power plants”&lt;/em&gt;, Finanical Times, January 2025, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;2&quot;&gt;[2] &lt;a href=&quot;https://www.datacenterdynamics.com/en/news/iea-global-coal-power-use-reaches-all-time-high-driven-by-increased-electricity-demand/&quot;&gt;&lt;em&gt;“IEA: Global coal power use reaches all time high, driven by increased electricity demand”&lt;/em&gt;, Skidmore Z., 19 December 19 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;3&quot;&gt;[3] &lt;a href=&quot;https://www.mckinsey.com/industries/technology-media-and-telecommunications/our-insights/ai-power-expanding-data-center-capacity-to-meet-growing-demand&quot;&gt;&lt;em&gt;“AI power: Expanding data center capacity to meet growing demand”&lt;/em&gt;,  McKinsey &amp;amp; Company, 29 October 2024 , retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;4&quot;&gt;[4] &lt;a href=&quot;https://cushwake.cld.bz/K5Eiws&quot;&gt;&lt;em&gt;“Global Data Center Market Comparison”&lt;/em&gt;, Cushman &amp;amp; Wakefield, 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;5&quot;&gt;[5] &lt;a href=&quot;https://pdf.savills.asia/asia-pacific-research/asia-pacific-research/ap-data-centre-spotlight-05-2024.pdf&quot;&gt;&lt;em&gt;“Asia Pacific Data Centres”&lt;/em&gt;, Savills, May 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;6&quot;&gt;[6] &lt;a href=&quot;https://www.savills.co.uk/insight-and-opinion/savills-news/362723-0/european-data-centre-power-capacity-projected-to-rise-to-approximately-13-100-mw-by-2027&quot;&gt;&lt;em&gt;“European data centre power capacity projected to rise to approximately 13,100 MW by 2027”&lt;/em&gt;, Savills, 30 May 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;7&quot;&gt;[7] &lt;a href=&quot;https://eta-publications.lbl.gov/sites/default/files/2024-12/lbnl-2024-united-states-data-center-energy-usage-report.pdf&quot;&gt;&lt;em&gt;“2024 United States Data Center Energy
Usage Report”&lt;/em&gt;, Shehabi et al., December 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;8&quot;&gt;[8] &lt;a href=&quot;https://ourworldindata.org/grapher/electricity-prod-source-stacked?tab=table&quot;&gt;&lt;em&gt;“Electricity production by source”&lt;/em&gt;, Our World in Data, 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;9&quot;&gt;[9] &lt;a href=&quot;https://www.tsmc.com/english/aboutTSMC/TSMC_Fabs&quot;&gt;&lt;em&gt;“TSMC Fabs”&lt;/em&gt;, TMC, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;10&quot;&gt;[10] &lt;a href=&quot;https://www.datacenterdynamics.com/en/news/tsmc-could-account-for-24-of-taiwans-electricity-consumption-by-2030/&quot;&gt;&lt;em&gt;“TSMC could account for 24% of Taiwan’s electricity consumption by 2030”&lt;/em&gt;, Trueman C., 7 October 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;11&quot;&gt;[11] &lt;a href=&quot;https://www.ceicdata.com/en/indicator/taiwan/electricity-production&quot;&gt;&lt;em&gt;“Taiwan Electricity Production”&lt;/em&gt;, CEIC, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;12&quot;&gt;[12] &lt;a href=&quot;https://spectrum.ieee.org/taiwan-semiconductor&quot;&gt;&lt;em&gt;“TSMC’s Energy Demand Drives Taiwan’s Geopolitical Future”&lt;/em&gt;, Fairley P., IEEE Spectrum, 3 September 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;13&quot;&gt;[13] &lt;a href=&quot;https://ourworldindata.org/grapher/carbon-intensity-electricity?tab=chart&amp;amp;country=EU-27~EU~G20+%28Ember%29~OWID_WRL&quot;&gt;&lt;em&gt;“Carbon intensity of electricity generation, 2000 to 2023”&lt;/em&gt;, Our World in Data, 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;14&quot;&gt;[14] &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/low-carbon-computing/src/branch/master/LCA-model-equations/runLCAModel-AI.hs&quot;&gt;“LCA model for servers in a data centre”, Vanderbauwhede W., 16 January 2025, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;15&quot;&gt;[15] &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/low-carbon-computing/src/branch/master/LCA-model-equations/calculateServerEmbodiedCarbon-DGX-A100.hs&quot;&gt;&lt;em&gt;“Server embodied carbon model”&lt;/em&gt;, Vanderbauwhede W., 17 January 2025, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;16&quot;&gt;[16] &lt;a href=&quot;https://www.unep.org/resources/emissions-gap-report-2024&quot;&gt;&lt;em&gt;“Emissions Gap Report 2024”&lt;/em&gt;, UN Environment Programme, 24 October 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;17&quot;&gt;[17] &lt;a href=&quot;https://www.unep.org/resources/publication/2022-global-status-report-buildings-and-construction&quot;&gt;&lt;em&gt;“2022 Global Status Report for Buildings and Construction”&lt;/em&gt;, UN Environment Programme, 9 November 2022, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;18&quot;&gt;[18] &lt;a href=&quot;https://www.datacenterdynamics.com/en/news/michael-dell-ai-to-drive-data-center-demand-up-100-fold-over-next-10-years/&quot;&gt;&lt;em&gt;“Michael Dell: AI to drive data center demand up 100x over next 10 years”&lt;/em&gt;, Yadav N., 18 March 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span id=&quot;19&quot;&gt;[19] &lt;a href=&quot;{site.url}/articles/the-insatiable-hunger-of-openai/&quot;&gt;&lt;em&gt;“The insatiable hunger of (Open)AI”&lt;/em&gt;, Vanderbauwhede W., 10 March 2024, retrieved 17 January 2025&lt;/a&gt;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>Emissions from ChatGPT are much higher than from conventional search (updated)</title>
        <link href="https://limited.systems/articles/google-search-vs-chatgpt-emissions/"/>
        <updated>2025-01-06T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/google-search-vs-chatgpt-emissions</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/google-search-vs-chatgpt-emissions_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;Chat-assisted search is one of the key applications for ChatGPT. To illustrate the impact of ChatGPT-style augmented search queries more clearly, I compare the energy consumption and emission of a ChatGPT-style query with that of a conventional Google search-style query. If all search queries are replaced by ChatGPT-style queries, what does that mean for energy consumption and emissions?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;tl;dr: Emissions would increase by 60x for a GPT-3 style model of around 175B paramters; for a GPT-4 style model, it could be 200x.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;a href=&quot;https://limited.systems/articles/climate-cost-of-ai-revolution&quot;&gt;a previous post&lt;/a&gt; I wrote about the potential climate impact from widespread adoption of ChatGPT-style Large Language Models. My projections are in line with those made by de Vries in his recent article &lt;a href=&quot;#5&quot;&gt;[5]&lt;/a&gt;. In this post, I look in more detail at the increase in energy consumption from using ChatGPT for search tasks. A more detailed analysis is available &lt;a href=&quot;https://arxiv.org/abs/2407.16894&quot;&gt;as a preprint paper&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;update-2025-01-06&quot;&gt;Update 2025-01-06&lt;/h2&gt;

&lt;p&gt;I originally published the estimates below on 2023-11-17 and they are for GPT-3. According to &lt;a href=&quot;https://www.latent.space/p/geohot&quot;&gt;George Hotz&lt;/a&gt; GPT-4 consists of 8 instances of 220B-parameter GPT-3 models; &lt;a href=&quot;https://semianalysis.com/2023/07/10/gpt-4-architecture-infrastructure/&quot;&gt;Dylan Patel
and Gerald Wong&lt;/a&gt; claim it is 16 instances of each about ~111B, which is the same in total. But they also state that only 2 of these are routed, so the inference is performed on two 111B models; however, they also share Furthermore, ~55B shared parameters for attention, so we get about 280B parameters. For comparison, GPT-3.5 is a single 175B-parameter model. According to Patel and Wong, the inference cost of GPT-4 is 3x more expensive that of than GPT-3.5, which is much more than the increase of 1.6x in parameters would suggest. As for the inference, the energy consumption dominates, this means that GPT-4 likely consume up to 3x more energy than GPT-3.5, and consequently, a search query with a GPT-4 generated AI summary might have emissions of about 200x larger than a search query without AI summary.&lt;/p&gt;

&lt;h2 id=&quot;google-search-energy-and-emissions&quot;&gt;Google search energy and emissions&lt;/h2&gt;

&lt;p&gt;In 2009, The Guardian published &lt;a href=&quot;https://www.theguardian.com/environment/ethicallivingblog/2009/jan/12/carbon-emissions-google&quot;&gt;an article about the carbon cost of Google search&lt;/a&gt;. Google &lt;a href=&quot;https://googleblog.blogspot.com/2009/01/powering-google-search.html&quot;&gt;had posted a rebuttal to the claim that every search emits 7 g of CO₂ on their blog&lt;/a&gt;. What they claimed was that, in 2009, the energy cost was 0.0003 kWh per search, or 1 kJ. That corresponded to 0.2 g CO₂, and I think that was indeed a closer estimate.&lt;/p&gt;

&lt;p&gt;This number is still often cited but it is entirely outdated. In the meanwhile, &lt;a href=&quot;https://www.science.org/doi/abs/10.1126/science.aba3758&quot;&gt;computing efficiency has rapidly increased&lt;/a&gt;: Power Usage Effectiveness (PUE, metric for overhead of the data centre infrastructure) dropped by 25% from 2010 to 2018; server energy intensity dropped by a factor of four; the average number of servers per workload dropped by a factor of five, and average storage drive energy use per TB dropped by almost a factor of ten. Google has released &lt;a href=&quot;https://www.google.co.uk/about/datacenters/efficiency/&quot;&gt;some figures about their data centre efficiency&lt;/a&gt; that are in line with these broad trends. It is interesting to see that PUE has not improved much in the last decade.&lt;/p&gt;

&lt;p&gt;Therefore, with the ChatGPT hype, I wanted to revise that figure from 2009. Three things have changed: the carbon intensity of electricity generation has dropped &lt;a href=&quot;#11&quot;&gt;[11]&lt;/a&gt;, server energy efficiency has increased a lot &lt;a href=&quot;#9&quot;&gt;[9]&lt;/a&gt;, and PUE of data centres has improved &lt;a href=&quot;#10&quot;&gt;[10]&lt;/a&gt;. Combining all that, my new estimate for energy consumption and the carbon footprint of a Google search is 0.00004 kWh and 0.02 g CO₂ (using carbon intensity for the US).
According to Masanet’s peer-reviewed article &lt;a href=&quot;#9&quot;&gt;[9]&lt;/a&gt;, hardware efficiency increases with 4.17x from 2010 to 2018. This is a power law, so extrapolating this to 12 years gives 6.70x. I use 12 years instead of 14 from 2009 as typically servers have a life of 4 years. Therefore the most likely estimate is that the current servers are two years old, i.e. they have the efficiency from 2021.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PUE: 1.16 in 2010; 1.1 in 2023;
efficiency increase of hardware in 12 years: 6.70x
US overall carbon intensity: 367 gCO₂/kWh

0.0003*(1.1/1.16)*(1/6.70) = 0.0000424 kWh per search
0.0000424*367 = 0.02 g CO₂ per search
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So the energy consumption per conventional search query has dropped by 7x in 14 years. There is quite some uncertainty on this estimate, but it is conservative, so it will not be less than that, but could be up to 10x. Microsoft has not published similar figures but there is no reason to assume that their trend would be different; in fact, their use of FPGAs should in principle lead to a lower energy consumption per query. In that same period, carbon emissions per search have dropped about 10x because of the decrease in carbon intensity of electricity.&lt;/p&gt;

&lt;h2 id=&quot;chatgpt-energy-consumption-per-query&quot;&gt;ChatGPT energy consumption per query&lt;/h2&gt;

&lt;p&gt;There are several estimates of the energy consumption per query for ChatGPT. I have summarised the ones that I used in the following table. There are many more, these are the top ranked ones in a conventional search ☺.&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Ref&lt;/th&gt;&lt;th&gt;Estimate (kWh/query)&lt;/th&gt;&lt;th&gt;Increase vs Google search&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;!-- &lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#1&quot;&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.00297&lt;/td&gt;&lt;td&gt;42x&lt;/td&gt; &lt;/tr&gt; --&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#1&quot;&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.001 - 0.01&lt;/td&gt; &lt;td&gt;24x - 236x&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#2&quot;&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.0017 - 0.0026&lt;/td&gt;&lt;td&gt;40x - 61x&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#3&quot;&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.0068&lt;/td&gt;&lt;td&gt;160x&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#4&quot;&gt;[4]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.0012&lt;/td&gt;&lt;td&gt;28x&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#5&quot;&gt;[5]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.0029&lt;/td&gt;&lt;td&gt;68x&lt;/td&gt; &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Reference &lt;a href=&quot;#5&quot;&gt;[5]&lt;/a&gt; is the peer-reviewed article by Alex de Vries. It uses the estimates from &lt;a href=&quot;#6&quot;&gt;[6]&lt;/a&gt; for energy consumption but does not present a per-query value so I used the query estimate from &lt;a href=&quot;#6&quot;&gt;[6]&lt;/a&gt;. Overall, the estimates lie between 24x and 236x (from [1], which is a collation of estimates from Reddit and therefore very broad) or 28x to 160x (all other sources).&lt;/p&gt;

&lt;p&gt;I consider any estimate lower than 0.002 kWh/query overly optimistic and any estimate higher than 0.005 kWh/query overly pessimistic. However, rather than judging, I calculated the mean over all these estimates. I used four types of means. Typically, an ordinary average gives more weight to large numbers; a harmonic mean gives more weight to small numbers. Given the nature of the data, I think the geometric mean is the best estimate:&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Type of Mean&lt;/th&gt;&lt;th&gt;Mean increase &lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Average&lt;/td&gt;&lt;td&gt;88&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Median&lt;/td&gt;&lt;td&gt;61&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Geometric mean&lt;/td&gt;&lt;td&gt;63&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Harmonic mean&lt;/td&gt;&lt;td&gt;48&lt;/td&gt; &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;As you can see, there is not that much difference between the geometric mean and the media. So we can conclude that ChatGPT consumes between fifty and ninety times more energy per query than a conventional (“Google”) search, with sixty times being the most likely estimate.&lt;/p&gt;

&lt;h2 id=&quot;other-factors-contributing-to-emissions&quot;&gt;Other factors contributing to emissions&lt;/h2&gt;

&lt;h3 id=&quot;training&quot;&gt;Training&lt;/h3&gt;

&lt;p&gt;Contrary to popular belief, it is the use of ChatGPT, not its training, that dominates emissions. I wrote about this in &lt;a href=&quot;https://limited.systems/articles/climate-cost-of-ai-revolution&quot;&gt;my previous post&lt;/a&gt;. In the initial phase of adoption, with low numbers of users, emissions from training are not negligible, but I assume the scenario where conventional search is replaced by ChatGPT-style queries, and in that case emissions from training are only a small fraction. How much is hard to say as we don’t know how frequently the model gets retrained and what the emissions are from retraining; they are almost certainly much lower as the changes in the corpus are small, so it is tuning.&lt;/p&gt;

&lt;h3 id=&quot;data-centre-efficiency&quot;&gt;Data centre efficiency&lt;/h3&gt;

&lt;p&gt;As far as I can tell, PUE is not taken into account in the above estimates. For a typical hyperscale data centre, it is around 1.1.&lt;/p&gt;

&lt;h3 id=&quot;embodied-carbon&quot;&gt;Embodied carbon&lt;/h3&gt;

&lt;p&gt;Neither the Google search estimate nor the ChatGPT query estimates include embodied carbon. The embodied carbon can be anywhere between 20% and 50% of the emissions from use, depending on many factors. My best guess is that the embodied emission are proportionate to the energy consumption, so this would not affect the factor much.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Taken all this into account, it is possible that the emissions from a ChatGPT query are more than a hundred times that of a conventional search query. But as I don’t have enough data to back this up, I will keep the conservative estimates from above (50x - 90x; 60x most likely).&lt;/p&gt;

&lt;p&gt;Now, if we want sustainable ICT, then the sector as a whole needs to reduce its emissions to a quarter from the current ones by 2040. The combined increase in energy use and growth in adoption of ChatGPT-like applications is therefore deeply problematic.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;h3 id=&quot;google-search-energy-consumption-estimates&quot;&gt;Google Search energy consumption estimates&lt;/h3&gt;

&lt;p&gt;&lt;a name=&quot;7&quot;&gt;[7]&lt;/a&gt; &lt;a href=&quot;https://www.theguardian.com/environment/ethicallivingblog/2009/jan/12/carbon-emissions-google&quot;&gt;“The carbon cost of Googling”, Leo Hickman, 2009, The Guardian&lt;/a&gt;&lt;br /&gt;
&lt;a name=&quot;8&quot;&gt;[8]&lt;/a&gt; &lt;a href=&quot;https://googleblog.blogspot.com/2009/01/powering-google-search.html&quot;&gt;“Powering a Google search”, Google, 2009&lt;/a&gt;&lt;br /&gt;
&lt;a name=&quot;9&quot;&gt;[9]&lt;/a&gt; &lt;a href=&quot;https://www.science.org/doi/abs/10.1126/science.aba3758&quot;&gt;“Recalibrating global data center energy-use estimates”, Eric Masanet et al, 2020&lt;/a&gt;&lt;br /&gt;
&lt;a name=&quot;10&quot;&gt;[10]&lt;/a&gt; &lt;a href=&quot;https://www.google.co.uk/about/datacenters/efficiency/&quot;&gt;“Data Centers: Efficiency”, Google, 2023&lt;/a&gt;&lt;br /&gt;
&lt;a name=&quot;11&quot;&gt;[11]&lt;/a&gt; &lt;a href=&quot;https://ourworldindata.org/grapher/carbon-intensity-electricity&quot;&gt;“Carbon intensity of electricity, 2022”, Our World in Data, 2023&lt;/a&gt;)&lt;/p&gt;

&lt;h3 id=&quot;chatgpt-energy-consumption-estimates&quot;&gt;ChatGPT energy consumption estimates&lt;/h3&gt;

&lt;!-- &lt;a name=&quot;1&quot;&gt;[1]&lt;/a&gt; [&quot;ChatGPT’s Electricity Consumption&quot;, Kasper Groes Albin Ludvigsen, 2023, Towards Data Science](https://towardsdatascience.com/chatgpts-electricity-consumption-7873483feac4) --&gt;
&lt;p&gt;&lt;a name=&quot;1&quot;&gt;[1]&lt;/a&gt; &lt;a href=&quot;https://lifestyle.livemint.com/news/big-story/ai-carbon-footprint-openai-chatgpt-water-google-microsoft-111697802189371.html&quot;&gt;“AI and its carbon footprint: How much water does ChatGPT consume?”, Nitin Sreedhar, 2023, lifestyle.livemint.com&lt;/a&gt;&lt;br /&gt;
&lt;a name=&quot;2&quot;&gt;[2]&lt;/a&gt; &lt;a href=&quot;https://towardsdatascience.com/chatgpts-energy-use-per-query-9383b8654487&quot;&gt;“ChatGPT’s energy use per query”, Kasper Groes Albin Ludvigsen, 2023, Towards Data Science)&lt;/a&gt;&lt;br /&gt;
&lt;a name=&quot;3&quot;&gt;[3]&lt;/a&gt; &lt;a href=&quot;https://medium.com/@zodhyatech/how-much-energy-does-chatgpt-consume-4cba1a7aef85&quot;&gt;“How much energy does ChatGPT consume?” (Zodhya, 2023, medium.com)&lt;/a&gt;&lt;br /&gt;
&lt;a name=&quot;4&quot;&gt;[4]&lt;/a&gt; &lt;a href=&quot;https://medium.com/@chrispointon/the-carbon-footprint-of-chatgpt-e1bc14e4cc2a&quot;&gt;“The carbon footprint of ChatGPT” (Chris Pointon, 2023, medium.com)&lt;/a&gt;&lt;br /&gt;
&lt;a name=&quot;5&quot;&gt;[5]&lt;/a&gt; &lt;a href=&quot;https://www.cell.com/joule/fulltext/S2542-4351(23)00365-3&quot;&gt;“The growing energy footprint of artificial intelligence” (Alex de Vries, 2023, Joule&lt;/a&gt;&lt;br /&gt;
&lt;a name=&quot;6&quot;&gt;[6]&lt;/a&gt; &lt;a href=&quot;https://www.semianalysis.com/p/the-inference-cost-of-search-disruption&quot;&gt;“The Inference Cost Of Search Disruption – Large Language Model Cost Analysis” (Dylan Patel and Afzal Ahmad, 2023, SemiAnalysis)&lt;/a&gt;&lt;/p&gt;


        </content>
    </entry>
    
    <entry>
        <title>FORTRAN, an “infantile disorder”?</title>
        <link href="https://limited.systems/articles/dijkstra-fortran/"/>
        <updated>2024-11-23T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/dijkstra-fortran</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/dijkstra-fortran_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;A few notes on what the computing scientist Edsger Dijkstra said and didn’t say about Fortran, and the origin of that term “infantile disorder”.&lt;/p&gt;

&lt;h2 id=&quot;edsger-dijkstra&quot;&gt;Edsger Dijkstra&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://inference-review.com/article/the-man-who-carried-computer-science-on-his-shoulders&quot;&gt;Edsger Dijkstra&lt;/a&gt; was a Dutch computing scientist who helped shape the field in the 1960s-1980s and made important contributions to networking, concurrency and structured programming. He is probably best known for his strong objection to GOTO statements.&lt;/p&gt;

&lt;h2 id=&quot;what-dijkstra-said-and-didnt&quot;&gt;What Dijkstra said and didn’t&lt;/h2&gt;

&lt;p&gt;In an article about &lt;a href=&quot;https://time.com/69316/basic/&quot;&gt;Fifty years of BASIC&lt;/a&gt; ¹ I came across a claim about something Dijkstra had allegedly said:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;He also spewed bile in the direction of FORTRAN (an “infantile disorder”), PL/1 (“fatal disease”) and COBOL (“criminal offense”).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, in the article referenced to back up this claim, &lt;a href=&quot;https://dl.acm.org/doi/pdf/10.1145/947923.947924&quot;&gt;“How do we tell truths that might hurt?” (1975)&lt;/a&gt; , Dijkstra writes:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;FORTRAN, “the infantile disorder”, by now nearly 20 years old, is hopelessly inadequate for whatever computer application you have in mind today: it is now too clumsy, too risky, and too expensive to use.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;PL/I –“the fatal disease”– belongs more to the problem set than to the solution set.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note the quotes, which indicate he was quoting was someone else who called FORTRAN that. In &lt;a href=&quot;https://www.cs.utexas.edu/~EWD/transcriptions/EWD03xx/EWD340.html&quot;&gt;The Humble Programmer (1972)&lt;/a&gt; he says&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;When FORTRAN has been called an infantile disorder, full PL/1, with its growth characteristics of a dangerous tumor, could turn out to be a fatal disease.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So there also Dijkstra is saying that someone else called it that, and I will come back to this later. His own thoughts on FORTRAN are quite a bit more nuanced:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The second major development on the software scene that I would like to mention is the birth of FORTRAN. At that time this was a project of great temerity and the people responsible for it deserve our great admiration. It would be absolutely unfair to blame them for shortcomings that only became apparent after a decade or so of extensive usage: groups with a successful look-ahead of ten years are quite rare! In retrospect we must rate FORTRAN as a successful coding technique, but with very few effective aids to conception, aids which are now so urgently needed that time has come to consider it out of date.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Where Dijkstra went wrong in my opinion is in how he followed on from that:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The sooner we can forget that FORTRAN has ever existed, the better, for as a vehicle of thought it is no longer adequate: it wastes our brainpower, is too risky and therefore too expensive to use. FORTRAN’s tragic fate has been its wide acceptance, mentally chaining thousands and thousands of programmers to our past mistakes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because what effectively happened was that by 1977, the FORTRAN 77 standard incorporated the basic tenets of structured programming (control structures, recursive subroutines, blocks), and therefore effectively became a structured programming language, or at least a language that allowed structured programming  while not enforcing it.&lt;/p&gt;

&lt;p&gt;This was most likely a consequence of Dijkstra’s own efforts, and as result we have a programming language that has never been forgotten but indeed has grown to incorporate more and more modern features. But it still has that bad reputation under “serious” computing scientists.&lt;/p&gt;

&lt;p&gt;When Dijkstra calls FORTRAN “too risky” to use, it is hard to know which precise risks he had in mind, but presumable a key risk had to do with the fact that in early FORTRAN, every loop was effectively a labeled jump, rather than a proper control structure, and certain ways of selection were thinly disguised conditional jumps. Dijkstra held (see e.g. &lt;a href=&quot;https://dl.acm.org/doi/10.1145/362929.362947&quot;&gt;his famous “GOTO” article&lt;/a&gt;) that no loop should have an early exit.&lt;/p&gt;

&lt;p&gt;Another obvious risk is that even FORTRAN 77 is not type safe. However, Fortran 90 programs that disallow certain legacy FORTRAN 77 constructs are actually type safe.&lt;/p&gt;

&lt;p&gt;And in both cases, it is possible to use source-to-source compilation to &lt;a href=&quot;https://link.springer.com/article/10.1007/s11227-021-03839-9&quot;&gt;convert the risky code into safe code&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-infantile-disorder&quot;&gt;The “Infantile Disorder”&lt;/h2&gt;

&lt;p&gt;The term “infantile disorder” is not a medical term an most likely was borrowed from the famous work by Lenin, &lt;a href=&quot;https://www.marxists.org/archive/lenin/works/1920/lwc/&quot;&gt;“Left-Wing” Communism: An Infantile Disorder&lt;/a&gt;. But it should be noted that the original term in Russian, Детская болезнь (Detskaya Bolezn) means something closer to “childhood ailment”; in Dutch, Dijkstra’s mother tongue, it would be “kinderziekte” which is a lot less dramatic. In the first English translation, the term in the title was “infantile sickness”.&lt;/p&gt;

&lt;p&gt;And indeed, that was Lenin’s view: “Left-Wing” Communism was merely a childhood ailment which, easy to cure and which, when cured, would result in more robust organism:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;There is therefore nothing surprising, new, or terrible in the “infantile disorder” of “Left-wing communism” among the Germans. The ailment involves no danger, and after it the organism even becomes more robust. 
(Ch. 5)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;the error consisted in numerous manifestations of that “Leftwing” infantile disorder which has now come to the surface and will consequently be cured the more thoroughly, the more rapidly and with greater advantage to the organism. 
(Ch. 8)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Of course, the mistake of Left doctrinairism in communism is at present a thousand times less dangerous and less significant than that of Right doctrinairism (i.e., social-chauvinism and Kautskyism); but, after all, that is only due to the fact that Left communism is a very young trend, is only just coming into being. It is only for this reason that, under certain conditions, the disease can be easily eradicated, and we must set to work with the utmost energy to eradicate it. 
(Ch. 10)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is probably a stretch to extend this to the case of FORTRAN, but when we do, we could consider the state of FORTRAN before its standardisation in 1977  the childhood with its ailments; the standardisation process the cure; and the subsequent revisions the growth into the robust and versatile programming language that Fortran is today, including &lt;a href=&quot;https://wg5-fortran.org/N1801-N1850/N1824.pdf&quot;&gt;co-arrays&lt;/a&gt;, &lt;a href=&quot;https://epubs.stfc.ac.uk/manifestation/2080/oo_fortran.pdf&quot;&gt;OOP support&lt;/a&gt;, and &lt;a href=&quot;https://github.com/wavebitscientific/functional-fortran&quot;&gt;many functional programming features&lt;/a&gt;.&lt;/p&gt;

&lt;!-- and even [lambdas](https://flibs.sourceforge.net/lambda_expressions.pdf) . --&gt;

&lt;p&gt;&lt;small&gt;¹ I could say a lot about BASIC too, it was the first language I ever learned, thanks to the brilliant TI-994A user manual. I used various dialects over the years, up to Visual Basic. Dijstra said that “It is practically impossible to teach good programming to students that have had a prior exposure to BASIC”. Luckily, nobody taught me how to program.&lt;/small&gt;&lt;/p&gt;
&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;The banner picture shows the K Computer Mae Station (京コンピュータ前駅) in Kobe, Japan. The K Computer was the most powerful supercomputer in 2011, and its dominant workload until it was decommissioned in 2019 was Fortran.&lt;/em&gt;&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>Decarbonising the Computing Science curriculum</title>
        <link href="https://limited.systems/articles/sustainability-in-cs-education/"/>
        <updated>2024-04-17T00:00:00+01:00</updated>
        <id>https://limited.systems/articles/sustainability-in-cs-education</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/sustainability-in-cs-education_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;In this post I’d like to explain how we have embedded sustainability and decarbonisation learning outcomes in our undergradudate Computing Science and Software Engineering degree programmes.&lt;/p&gt;

&lt;h2 id=&quot;the-ambitious-goal&quot;&gt;The ambitious goal&lt;/h2&gt;

&lt;p&gt;I am a professor in the School of Computing Science of the University of Glasgow, in Scotland. In 2021, I started the &lt;a href=&quot;https://www.gla.ac.uk/schools/computing/research/researchthemes/lowcarbon/&quot;&gt;Low Carbon and Sustainable Computing&lt;/a&gt; research activity in our School (Glasgow has Schools and Colleges where other univs have Departments and Faculties). One of my aims is to get sustainability and decarbonisation learning outcomes embedded in all degree programmes of the University.&lt;/p&gt;

&lt;p&gt;Our students are the generation that will be affected strongly by climate change. Therefore,  they should learn about the need for decarbonisation, sustainability and sustainable development, the reasons for the current crisis and the ways in which change can be achieved. Through the curriculum, students should be equipped with knowledge, skills, attributes and values to act in their personal and professional lives, spread awareness and help create systemic solutions.&lt;/p&gt;

&lt;h2 id=&quot;the-current-state-of-affairs&quot;&gt;The current state of affairs&lt;/h2&gt;

&lt;p&gt;From next academic year (2024-25), all undergradudate degree programmes in Computing Science and Software Engineering will have sustainability and decarbonisation learning outcomes embedded in such a way that they must be assessed, in other words teaching sustainability is now a non-optional part of these programmes. I think this is a success, even though there is a long way to go yet.&lt;/p&gt;

&lt;h2 id=&quot;the-approach&quot;&gt;The approach&lt;/h2&gt;

&lt;p&gt;In 2022 I wrote a &lt;a href=&quot;https://limited.systems/papers/decarbonising-education-position-paper.html&quot;&gt;position paper on the need to embed sustainability and decarbonisation in our programmes&lt;/a&gt;, and shared it with some key people. My key point was that to realise this goal, Schools needed dedicated support. A lot of academics are willing to teach about sustainability and decarbonisation, but they don’t know where to start and are usually overworked as well. So I proposed to create a new role, that of “Sustainability Subject Advisor”. This person would have the know-how and the time to advise staff on embedding Sustainability and Decarbonisation in their courses and programmes. (The terminology was the subject of much debate, every single word of it — such is academia. Also, it turned out that, while “sustainability” is not controversial, the term “decarbonisation” can be).&lt;/p&gt;

&lt;p&gt;The Vice-Principal for Learning and Teaching agreed to sponsor a grassroots initiative in my College. I would have preferred if the University Learning and Teaching  Committee had agreed to approve the role at universit level, but at least it meant I had the authority to push for the creation of this new role in my College. The Dean for Learning and Teaching of the College championed the proposal in the College Senior Management Committee, which is made up of all Heads of School. So the role became official in every School.&lt;/p&gt;

&lt;!--
## The setback

But from there it went wrong: the volunteers did in practice not get the time to work on this and got no traction, because effectively they got no support internally. The main reason is the lack of high-level support in the University. The priorities of the Heads of School depend on the priorities of the University management, and at that level, although sustainability is a priority, embedding sustainability in teaching is not.
--&gt;

&lt;h2 id=&quot;the-implementation&quot;&gt;The implementation&lt;/h2&gt;

&lt;p&gt;So we went ahead. The Sustainability Subject Advisor my colleague &lt;a href=&quot;https://lauritzthamsen.org/&quot;&gt;Dr. Lauritz Thamsen&lt;/a&gt; and I analysed the programmes and created programme-level Aims and Intended Learning Outcomes (ILOs), which are the core of a programme specification. It is tempting to simply create a new course that will meet the aims, but our experience with other topics such as ethics etc has been that this does not work well, as students consider it “not real computing”. Also, in the Glasgow BSc Honours degrees, 1st and 2nd year do not count towards the degree classification, so our choice was to embed the material throughout the programme in existing courses, and preferentially in 3rd-year ones.&lt;/p&gt;

&lt;p&gt;As agreed with the VP, we started with a pilot programme. We analysed the courses and identified suitable courses with coordinators that were willing to support the initiative, and worked with them to define the sustainability Aims and ILOs. When we got approval for the pilot programme (a lengthy process), we repeated the exercise for all our undergraduate programmes. Because they share a common core of mandatory courses, in the end the number of courses with additional sustainability Aims and ILOs was small. Last month, we obtained approval for all these changes, so they can now be rolled out.&lt;/p&gt;

&lt;p&gt;This focus on relatively few courses does not mean that we only teach sustainability in those courses. But in those selected courses, these learning outcomes are not optional, so the material &lt;em&gt;must&lt;/em&gt; be taught and assessed, whereas in the other courses, it is optional. In this way we ensure that teaching of sustainability is embedded as an essential component of the programmes.&lt;/p&gt;

&lt;h2 id=&quot;lessons-learned&quot;&gt;Lessons learned&lt;/h2&gt;

&lt;p&gt;What we have learned from this initiative is that having a dedicated person like our Sustainability Subject Advisors is a necessary requirement; another key requirement is buy-in from the local stakeholders (lecturers and members of the teaching committee) for the required change. Once you have the buy-in, people will help you to achieve the change. 
However, to extend this initiative to the whole university, buy-in from high-level management is required, because that is what is needed to ensure that the role can be created in every School in the university, and that the Heads of School will support the initiative locally.&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next&lt;/h2&gt;

&lt;p&gt;I intend to keep working on two fronts: one, to keep on trying to get sustainability embedded in Glasgow’s degree programmes, first in our College, then more widely; and the other, to try and convince departments at other universities to follow suit, by giving talks, and writing articles like this one. So if you’d like me to give a talk to your department on this, please &lt;a href=&quot;https://limited.systems/about/&quot;&gt;get in touch&lt;/a&gt;.&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>The insatiable hunger of (Open)AI</title>
        <link href="https://limited.systems/articles/the-insatiable-hunger-of-openai/"/>
        <updated>2024-03-10T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/the-insatiable-hunger-of-openai</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/the-insatiable-hunger-of-openai_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;(Open)AI needs enormous amounts of energy and compute hardware. Meeting these needs would lead to a huge increase in CO₂ emissions. The only way to avoid catastrophic warming is to drastically reduce CO₂ emissions. In other words, the planned growth of (Open)AI is entirely unsustainable.&lt;/p&gt;

&lt;p&gt;Others have written about the energy needs to provide AI services. Here I focus on the impact of the production of the computer chips needed for this.&lt;/p&gt;

&lt;h2 id=&quot;the-urgent-need-to-reduce-emissions&quot;&gt;The urgent need to reduce emissions&lt;/h2&gt;

&lt;p&gt;To &lt;a href=&quot;https://limited.systems/articles/frugal-computing&quot;&gt;reiterate&lt;/a&gt;, &lt;a href=&quot;https://www.unep.org/resources/emissions-gap-report-2023&quot;&gt;according to the UN Emissions Gap Report 2023&lt;/a&gt;, the world must cut global greenhouse gas emissions to 20 gigatons CO₂-equivalent per year (GtCO₂e/y) by 2040 from the current level of 60 GtCO₂e/y to avoid catastrophic global warming, where “catastrophic” is meant quite literally: there will be a huge increase in frequency and severity of natural catastrophes if we don’t do this. Large parts of the earth will become unsuitable for habitation and agriculture.&lt;/p&gt;

&lt;p&gt;To arrive at a sustainable level of emissions by 2040, global CO₂ emissions should reduced by close to 20% per year. However, currently, emissions are still rising at 1% - 2% per year.&lt;/p&gt;

&lt;p&gt;The Emissions Gap Report explains in detail why renewables, carbon dioxide removal and carbon offsetting alone will not be sufficient to meet the targets.&lt;/p&gt;

&lt;h2 id=&quot;the-growth-of-ai-is-unsustainable&quot;&gt;The growth of AI is unsustainable&lt;/h2&gt;

&lt;p&gt;Many experts have pointed out that the energy required to provide AI services is huge, and that this in itself means the steep growth of AI is unsustainable. Apart from &lt;a href=&quot;https://limited.systems/articles/climate-cost-of-ai-revolution/&quot;&gt;my own estimates&lt;/a&gt; about the energy needs and resulting CO₂ emissions from AI, there have been many other recent articles, for example &lt;a href=&quot;https://www.nature.com/articles/d41586-024-00478-x&quot;&gt;Kate Crawford in Nature&lt;/a&gt;, &lt;a href=&quot;https://theconversation.com/it-takes-a-lot-of-energy-for-machines-to-learn-heres-why-ai-is-so-power-hungry-151825&quot;&gt;Kate Saenko in The Conversation&lt;/a&gt;, &lt;a href=&quot;https://www.cell.com/joule/fulltext/S2542-4351(23)00365-3&quot;&gt;Alex de Vries in specialist journal Joule&lt;/a&gt;, or &lt;a href=&quot;https://www.theguardian.com/technology/2024/mar/07/ai-climate-change-energy-disinformation-report&quot;&gt;this recent article in The Guardian&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the rest of this article I focus on OpenAI as the main proponent of this unsustainable growth. There are many other such AI companies (e.g. Anthropic), but OpenAI has been most clear in their messaging about their needs for energy and computer chips.&lt;/p&gt;

&lt;h2 id=&quot;openai-needs-a-lot-more-energy-in-the-world&quot;&gt;(Open)AI needs a lot more energy in the world&lt;/h2&gt;

&lt;p&gt;OpenAI is probably the best known AI company. It is responsible for AI products such as DALL·E, ChatGPT and Sora. OpenAI is a private company owned 49% by Microsoft (49% by all other investors, and 2% by the OpenAI non-profit foundation). So for practical purposes, it is a Microsoft-controlled company, the same Microsoft that claims it will be &lt;a href=&quot;https://blogs.microsoft.com/blog/2020/01/16/microsoft-will-be-carbon-negative-by-2030/&quot;&gt;“carbon negative by 2030”&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;https://www.bloomberg.com/news/videos/2024-01-16/openai-s-atlman-and-makanju-on-global-implications-of-ai&quot;&gt;an interview with Bloomberg at the WEF in Davos in January 2024&lt;/a&gt;, the CEO of OpenAI, Sam Altman, made clear how huge the energy needs of this company are, and admitted that this is goes contary to meeting the global climate targets:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Interviewer: Considering the compute costs and the need for chips, does the development of AI in the path to AGI threaten to take us in the opposite direction on the climate?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Altman: Yes, we do need way more energy in the world than I think we thought we needed before. My my whole model of the world is that the two important currencies of the future are compute/intelligence and energy. You know, the ideas that we want and the ability to make stuff happen and the ability to like run the compute.
And I think we still don’t appreciate the energy needs of this technology.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then Altman goes on to say we need more nuclear and we need fusion, “at massive scale, like a scale that no one is really planning for”.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Interviewer: So I want to just go back to my question in terms of moving in the opposite direction. It sounds like the answer is potentially yes on the demand side, unless we take drastic action on the supply side.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Altman: But there, there is no – I see no way to supply this, to manage the supply side, without a really big breakthrough.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Interviewer: Right. Which is this is, does this frighten you guys? Because you know, the world hasn’t been that versatile when it comes to supply. But AI as you know, as you have pointed out, is not going to take its time until we start generating enough power.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Altman: It motivates us to go invest more in fusion and invest more in new storage.  And not only the technology but what it’s going to take to deliver this at the scale that AI needs and that the whole globe needs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;where-can-all-that-energy-come-from&quot;&gt;Where can all that energy come from?&lt;/h3&gt;

&lt;p&gt;There is a question of timescales here. Most companies have horizons of 5-10 years but not much beyond that. Building new nuclear power plants takes at least 20 years, and fusion at scale is still not even viable in the lab, so at best that will also take another 20 years. And in the meanwhile, we desperately need to cut emissions to stop catastrophic warming, and we can only do this by stopping the use of fossil fuels.&lt;/p&gt;

&lt;p&gt;What Altman (and therefore Microsoft) is really saying is therefore “keep the fossil fuels” and even “increase fossil fuel electricity generation” because they know that fusion will not be around, and nuclear capacity will not increase substantially, for another several decades. They also know that the growth in renewables is too slow to meet their demands. So for the next decades, the only way to produce the energy they need is by burning more carbon. And two decades more of emissions from fossil fuels is an unmitigated disaster.&lt;/p&gt;

&lt;!--
The additional problem is contention for sparse resources. If there is already not enough energy in the world purely for OpenAI&apos;s near-future needs, energy will fast become a very sparse resource. This will make the price go up. And companies like Micrsoft have quasi-unlimited funds, the prices could get very high indeed. As a result, everybody suffers, especially the poor.
--&gt;

&lt;h3 id=&quot;but-what-about-energy-efficiency&quot;&gt;But what about energy efficiency?&lt;/h3&gt;

&lt;p&gt;The energy efficiency of computing is still doubling every 2.6 years. If we assume, very optimistically, that this trend will hold for another 20 years, then by 2040, computers would be 64 times more energy efficient. So in this best-case scenario, we could double compute capacity every 2.6 years without increasing energy consumption.&lt;/p&gt;

&lt;p&gt;Which means that Altman wants AI to grow even faster than that. This is borne out by another action of OpenAI that was recently in the news. To do all that additional compute, they needs a lot more computers, and that requires a dramatic increase in chip manufacturing.&lt;/p&gt;

&lt;p&gt;And making chips is one of the human activities that releases huge amounts of greenhouse gases.&lt;/p&gt;

&lt;h2 id=&quot;openai-also-needs-tremendous-amounts-of-chips&quot;&gt;(Open)AI also needs tremendous amounts of chips&lt;/h2&gt;

&lt;p&gt;According to &lt;a href=&quot;https://www.wsj.com/tech/ai/sam-altman-seeks-trillions-of-dollars-to-reshape-business-of-chips-and-ai-89ab3db0&quot;&gt;an article of February 2024 in the Wall Street Journal&lt;/a&gt;, discussed in more detail &lt;a href=&quot;https://www.cnbc.com/2024/02/09/openai-ceo-sam-altman-reportedly-seeking-trillions-of-dollars-for-ai-chip-project.html&quot;&gt;on CNBC&lt;/a&gt;,&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;OpenAI CEO Sam Altman wants to overhaul the global semiconductor industry with trillions of dollars in investment&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Altman has said AI chip limitations hinder OpenAI’s growth, and as this project would increase chip-building capacity globally&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Altman wants to raise $7,000 billion. For reference, &lt;a href=&quot;https://technode.com/2022/06/06/tsmc-to-invest-34-billion-to-expand-2nm-chip-production-report/&quot;&gt;the new 2 nm TSMC fab will cost $34 billion&lt;/a&gt;. Seven trillion would allow to build two hundred such fabs. According to &lt;a href=&quot;https://www.z2data.com/insights/9-statistics-on-new-semiconductor-fabs-being-built&quot;&gt;Z2Data&lt;/a&gt;, 16 fabs for &amp;lt; 10 nm are currently being built. So Altman’s plan could increase this by more than ten times, even if some of the money is used for other purposes.&lt;/p&gt;

&lt;p&gt;TSMC says that the combined capacity of their four GigaFabs &lt;a href=&quot;https://www.tsmc.com/english/dedicatedFoundry/manufacturing/gigafab&quot;&gt;exceeded 12 million 12-inch wafers in 2023&lt;/a&gt;. As the fabs also produce silicon for older nodes &amp;gt; 28 nm, I have conservatively assumed that the capacity for a new GigaFab would be 1.2 million 12-inch wafers per year. Using data on embodied carbon of chip production from &lt;a href=&quot;https://doi.org/10.1145/3470496.3527408&quot;&gt;a paper by researchers from Harvard University&lt;/a&gt;, such a fab is responsible for 13.6 MtCO₂e/y of embodied carbon in chips.&lt;/p&gt;

&lt;p&gt;If there were two hundred such fabs, that would amount to 2.7 GtCO₂e/y.&lt;/p&gt;

&lt;p&gt;Considering the planet’s carbon budget by 2040 is 20 GtCO₂e/y, purely making so many chips would take 14% of the global carbon budget; running them could take again as much, so if this estimate is accurate, this plan could see “AI” eating almost 30% of the global carbon budget for 2040.&lt;/p&gt;

&lt;h2 id=&quot;refining-the-estimates&quot;&gt;Refining the estimates&lt;/h2&gt;

&lt;p&gt;(tl;dr: estimates have considerable uncertainty but the overall conclusions don’t change)&lt;/p&gt;

&lt;p&gt;It looks doubtful that production of raw materials, esp. rare earths, can meet this kind of demand. From January 2024 MIT Technology Review article &lt;a href=&quot;https://www.technologyreview.com/2024/01/05/1084791/rare-earth-materials-clean-energy/&quot;&gt;&lt;em&gt;The race to produce rare earth elements&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;According to the IEA, demand for rare earths is expected to reach 3 to 7 times current levels by 2040. Delivering on the 2016 Paris Agreement would require the global mineral supply to quadruple within the same time frame. At the current rate, supply is on track to merely double.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The reason why the 2016 Paris Agreement requires the global mineral supply to quadruple is mainly to do with the need to electrification of the global economy, not with chip production. On the other hand, a gigantic investment in the semiconductor industry would most likely increase the rate of production of raw materials. So we can cautiously assume that the chip production might still quadruple.&lt;/p&gt;

&lt;p&gt;This is not necessarily good news though, because, although it means that we can’t produce ten times more chips, and so embodied carbon emissions will grow more slowly, it also means there is less scope for moving to more energy-efficient chips. If a company can’t replace its servers by more energy efficient ones, but still wants to grow its compute capacity, it will need to keep using the previous, less efficient generation. The compute capability of that generation will be similar to the next one, the main difference is in energy efficiency. The result is that growth in compute capacity means growth in emissions.&lt;/p&gt;

&lt;p&gt;The estimate from Harvard I used might be on the high side. &lt;a href=&quot;https://www.imec-int.com/en/articles/environmental-footprint-logic-cmos-technologies&quot;&gt;Imec’s analysis of 2020&lt;/a&gt; gives a considerably lower estimate, nearly ten times lower, but their model only counts water, electricity and greenhouse gases from the process, not the emissions from mining, producing the precursor materials, packaging etc., so it is not the full emissions. Nevertheless, even taking those into account, it might still be 3-4 times lower.&lt;/p&gt;

&lt;p&gt;On the other hand, I did not include the older fabs that are still producing chips in my estimate, nor the 16 fabs being built at the moment. The emissions for anything &amp;lt; 28 nm are of the same order of those for a 2 nm process. Using the data from Wikipedia’s &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_semiconductor_fabrication_plants&quot;&gt;&lt;em&gt;List of semiconductor fabrication plants&lt;/em&gt;&lt;/a&gt;, then the total production capacity of all current fabs &amp;lt; 28 nm amounts to about 14 GigaFabs. Taking into account these 30 fabs would increase my estimate by about 10% to 12%.&lt;/p&gt;

&lt;p&gt;Also, in the above calculation I assumed that the chips produced were CPUs or GPUs, as this is what the GigaFab produces. In practice, every server will have RAM and SSDs as well. So let’s assume the two hundred new fabs produce these in equal amounts, so instead of producing four CPUs, for every CPU they will produce a GPU, RAM and SSD. Using data from &lt;a href=&quot;https://hotcarbon.org/assets/2022/pdf/hotcarbon22-tannu.pdf&quot;&gt;the 2022 paper by Tannu et al&lt;/a&gt;, the contribution of each of these is resp. 4%, 11%, 9% and 38%. Compared to the CPU this means that the GPU has 2.7x more embodied carbon, the RAM 2.2x and the SSD nearly 10x. So we’d need to revise our estimate upwards by a factor of (1+2.7+2.2+10)/4 = 4x. We also see from these figures that the chips amount only for 62% of the total embodied carbon, so a closer estimate for the embodied carbon resulting from the envisaged expansion in semiconductor production capacity might be up to six times higher.&lt;/p&gt;

&lt;p&gt;Using the Harvard and Imec figures as upper and lower bounds, and assuming at least a doubling and a most a tenfold increase in production, this would mean that the best estimate is an increase in emissions between 0.7 and 20 GtCO₂e/y. The geometric average would be 3.7 GtCO₂e/y, which is in any case a staggeringly high number, about 20% of the world’s 2040 carbon budget, purely due to the embodied carbon in the production of the chips.&lt;/p&gt;

&lt;h2 id=&quot;conclusion-the-world-cant-afford-this-growth-in-ai&quot;&gt;Conclusion: the world can’t afford this growth in AI&lt;/h2&gt;

&lt;p&gt;Both the embodied carbon an the emissions from use entailed purely by the needs of OpenAI are huge.&lt;/p&gt;

&lt;p&gt;Even with my most optimistic estimate, they would account for close to 10% of the world’s 2040 carbon budget. OpenAI’s plans would make emissions from ICT grow steeply at a time when we simply can’t afford &lt;em&gt;any&lt;/em&gt; rise in emissions. This projected growth will make it incredible hard to reduce global emissions to a sustainable level by 2040.&lt;/p&gt;

&lt;p&gt;In the worst case, the embodied emissions of the chips needed for AI compute could already exceed the world’s 2040 carbon budget. Running the computations would make the situation even worse. AI on its own could be responsible for pushing the world into catastrophic warming.&lt;/p&gt;


        </content>
    </entry>
    
    <entry>
        <title>Universal stack operations using Uxn primitives</title>
        <link href="https://limited.systems/articles/universal-stack-operations-uxn/"/>
        <updated>2023-12-04T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/universal-stack-operations-uxn</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/universal-stack-operations-uxn_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;I wanted to know if the &lt;a href=&quot;https://wiki.xxiivv.com/site/uxntal.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Uxntal&lt;/code&gt;&lt;/a&gt; primitives are complete, in the sense that they allow access to all elements on the stack (what I call “covering the stack”). And if so, what the minimum set of Uxntal primitives is required to move an element to or from any location on the working stack.&lt;/p&gt;

&lt;p&gt;The proof of these claims is by construction of a recursive algorithm, so it is a proof by induction. I have written this in Haskell notation because I think it is most clear. For completeness, I also looked at duplication and deletion. As the set of primitives is Uxn-specific, I assume the presence of a return stack.&lt;/p&gt;

&lt;p&gt;tl;dr:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The Uxn primitives are complete (no surprise there)&lt;/li&gt;
  &lt;li&gt;The instructions &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWP&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ROT&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STH&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STHr&lt;/code&gt; are sufficient to cover the entire stack.&lt;/li&gt;
  &lt;li&gt;Adding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DUP&lt;/code&gt;, we can replicate arbitrary sequences.&lt;/li&gt;
  &lt;li&gt;Adding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POP&lt;/code&gt; we can remove arbitrary sequences.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;uxntal-and-uxn&quot;&gt;Uxntal and Uxn&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://wiki.xxiivv.com/site/uxntal.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Uxntal&lt;/code&gt;&lt;/a&gt; is the programming language for the &lt;a href=&quot;https://wiki.xxiivv.com/site/uxn.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Uxn&lt;/code&gt;&lt;/a&gt; virtual machine. As Uxn is a stack machine, Uxntal is a stack language, similar to e.g. &lt;a href=&quot;https://forth-standard.org/&quot;&gt;Forth&lt;/a&gt; or &lt;a href=&quot;https://dev.to/palm86/church-encoding-in-the-concatenative-language-joy-3nd8&quot;&gt;Joy&lt;/a&gt; in that it uses reverse Polish notation (postfix). It is an assembly language with opcodes for 8-bit and 16-bit operations on the stack and memory. To get the most out of this article, it is best if you have basic knowledge of Uxntal, either from the above resources or for example &lt;a href=&quot;https://compudanzas.net/uxn_tutorial.html&quot;&gt;the great tutorial at Compudanzas&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;a-brief-overview-of-used-haskell-syntax&quot;&gt;A brief overview of used Haskell syntax&lt;/h2&gt;

&lt;p&gt;In Haskell, for example a function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y&lt;/code&gt; is written as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f x y&lt;/code&gt;, so no parentheses. Parentheses are only used to enforce precedence, for example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f (x+1)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Also, a recursive function can be defined as&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So there is no need for an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;case&lt;/code&gt; or similar constructs. Also, if a function argument is used in final position on both sides of the definition, it can be omitted, for example&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;can be written as&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(In this example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; is the identity function, which returns its argument)&lt;/p&gt;

&lt;p&gt;Finally, composing functions is done using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&lt;/code&gt; operators. For example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f1 (f2 (f3 x))&lt;/code&gt; can be written as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(f1 . f2 . f3) x&lt;/code&gt;. Combining both features, we can write for example&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;minimal-set-of-primitives&quot;&gt;Minimal set of primitives&lt;/h2&gt;

&lt;p&gt;The type for all primitives is&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;n&quot;&gt;prim&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The primitive &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prim&lt;/code&gt; takes a tuple (pair) of two lists of bytes and returns a tuple of two lists of bytes. (You can read the arrow as “from … to”.) For this discussion, the stacks don’t have to be of fixed size, so using lists is fine.&lt;/p&gt;

&lt;p&gt;The notation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x:xs&lt;/code&gt; means that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; is the first element of a list and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xs&lt;/code&gt; is the rest of the list.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The following Uxn primitives allow access to the entire stack&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;        &lt;span class=&quot;n&quot;&gt;swp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wst&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wst&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- swap in Forth&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;rot&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wst&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wst&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sth&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wst&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wst&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sthr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;For replication and deletion, we also need&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;        &lt;span class=&quot;n&quot;&gt;dup&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wst&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wst&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wst&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wst&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- drop in Forth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;accessing-the-stack&quot;&gt;Accessing the stack&lt;/h2&gt;

&lt;p&gt;I define two functions, one to move the kth element on the stack to the 1st position, the other its inverse.&lt;/p&gt;

&lt;h3 id=&quot;put-the-kth-element-of-the-stack-at-position-1&quot;&gt;Put the kth element of the stack at position 1&lt;/h3&gt;

&lt;p&gt;In Forth terminology this is called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;roll&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;c1&quot;&gt;-- ( x a b -- a b x )&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;k_to_top&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;k_to_top&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;swp&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;k_to_top&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rot&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;k_to_top&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;swp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sthr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k_to_top&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;put-the-1st-element-of-the-stack-at-position-k&quot;&gt;Put the 1st element of the stack at position k&lt;/h3&gt;

&lt;p&gt;Somewhat to my surprise, Forth does not define an inverse for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;roll&lt;/code&gt;. Of course it is not necessary, as we can apply &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;roll k&lt;/code&gt; k-1 times. But that means quadratic complexity; and I like to have an inverse for every primitive.&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;c1&quot;&gt;-- ( a b x -- x a b )&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;top_to_k&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- k==1, do nothing&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;top_to_k&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;swp&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;top_to_k&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rot&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rot&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;top_to_k&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sthr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;top_to_k&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;swp&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;top_to_k&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k_to_top&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With these two functions, any element on the stack can be moved between two arbitrary position k1 and k2:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;top_to_k&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k_to_top&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This proves that the four primitives are sufficient to cover the entire stack.&lt;/p&gt;

&lt;h2 id=&quot;growing-the-stack&quot;&gt;Growing the stack&lt;/h2&gt;

&lt;p&gt;Variants that keep the original element in place and so grow the stack are easily defined based on these two:&lt;/p&gt;

&lt;h3 id=&quot;put-the-kth-element-of-the-stack-at-position-1-keep-the-original-element&quot;&gt;Put the kth element of the stack at position 1, keep the original element&lt;/h3&gt;

&lt;p&gt;This function grows the stack by duplication of the element. In Forth terms, this is called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pick&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;c1&quot;&gt;-- ( x a b -- x a b x )&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;k_to_top_keep&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dup&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;k_to_top_keep&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;swp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sthr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k_to_top_keep&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The inverse of this is simply &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pop&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drop&lt;/code&gt; in Forth).&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k_to_top_keep&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;put-the-1st-element-of-the-stack-at-position-k-keep-the-original-element&quot;&gt;Put the 1st element of the stack at position k, keep the original element&lt;/h3&gt;

&lt;p&gt;This function also grows the stack by duplication of the element:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;c1&quot;&gt;-- ( a b x -- x a b x )&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;top_to_k_keep&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;top_to_k_keep&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sthr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;top_to_k&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dup&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The inverse of this requires the ability to delete a value at a given position of the stack:&lt;/p&gt;

&lt;h2 id=&quot;shrinking-the-stack&quot;&gt;Shrinking the stack&lt;/h2&gt;

&lt;p&gt;This function deletes an element from an arbitrary position on the stack.&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;c1&quot;&gt;-- ( x a b -- a b )&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;delete_k&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;delete_k&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sthr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete_k&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With this function, the inverse of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;top_to_k_keep&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delete_k (k+1)&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete_k&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;top_to_k_keep&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/devel/stack-manipulation-universal-uxn.hs&quot;&gt;Haskell code&lt;/a&gt; shows these functions at work and demonstrates the inverses. It is straightforward to implement the above functions in Uxntal, I leave that to the reader as an exercise.&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>Embedding a stack-based programming language</title>
        <link href="https://limited.systems/articles/stack-based-programming-in-raku/"/>
        <updated>2023-11-27T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/stack-based-programming-in-raku</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/stack-based-programming-in-raku_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;When &lt;a href=&quot;https://scholar.social/@lizmat@mastodon.social&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@lizmat&lt;/code&gt;&lt;/a&gt; asked me to write a post for the &lt;a href=&quot;https://raku-advent.blog/category/2023/&quot;&gt;Raku advent calendar&lt;/a&gt; I was initially a bit at a loss. I have spent most of the year not writing &lt;a href=&quot;https://raku.org/&quot;&gt;Raku&lt;/a&gt; but working on my own language &lt;a href=&quot;https://limited.systems/articles/funktal/&quot;&gt;Funktal&lt;/a&gt;, a postfix functional language that compiles to &lt;a href=&quot;https://wiki.xxiivv.com/site/uxntal.html&quot;&gt;Uxntal&lt;/a&gt;, the stack-based assembly language for the tiny &lt;a href=&quot;https://wiki.xxiivv.com/site/uxn.html&quot;&gt;Uxn&lt;/a&gt; virtual machine.&lt;/p&gt;

&lt;p&gt;But as Raku is nothing if not flexible, could we do Uxntal-style stack-based programming in it? Of course I could embed the entire Uxntal language in Raku using &lt;a href=&quot;https://raku.land/zef:lizmat/Slangify&quot;&gt;a slang&lt;/a&gt;. But could we have a more shallow embedding? Let’s find out.&lt;/p&gt;

&lt;h2 id=&quot;stack-oriented-programming&quot;&gt;Stack-oriented programming&lt;/h2&gt;

&lt;p&gt;An example of simple arithmetic in Uxntal is&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;    6 4 3 ADD MUL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This should be self-explanatory: it is called postfix, stack-based or reverse Polish notation. In infix notation, that is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6*(4+3)&lt;/code&gt;. In prefix notation, it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MUL(6, ADD(4,3))&lt;/code&gt;. The integer literals are pushed on a stack, and the primitive operations &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ADD&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MUL&lt;/code&gt; pop the arguments they need off the stack an push the result.&lt;/p&gt;

&lt;h2 id=&quot;the-mighty--operator-part-i-definition&quot;&gt;The mighty &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;∘&lt;/code&gt; operator, part I: definition&lt;/h2&gt;

&lt;p&gt;In Raku, we can’t redefine the whitespace to act as an operator. I could of course do something like&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;    my \stack-based-code = &amp;lt;6 4 3 ADD MUL&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;but I don’t want to write an interpreter starting from strings. So instead, I will define an infix operator &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;∘&lt;/code&gt;. Something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;    6 ∘ 4 ∘ 3 ∘ ADD ∘ MUL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The operator either puts literals on the stack or calls the operation on the values on the stack.&lt;/p&gt;

&lt;p&gt;By necessity, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;∘&lt;/code&gt; is a binary operator, but it will put only one element on the stack. I chose to have it process its second argument, and ignore the first one,because in that way it is easy to terminate the calculation. However, because of that, the first element of each sequence needs to be handled separately.&lt;/p&gt;

&lt;h2 id=&quot;returning-the-result&quot;&gt;Returning the result&lt;/h2&gt;

&lt;p&gt;To obtain a chain of calculations, the operator needs to put the result of every computation on the stack. This means that in the example, the result of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MUL&lt;/code&gt; will be on the stack, and not returned to the program. To return the final result to the program, I slightly abuse Uxntal’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BRK&lt;/code&gt; opcode. On encountering this opcode, the value of the computation is returned and the stack is cleared (in native Uxntal, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BRK&lt;/code&gt; simply terminates the program). So a working example of the above code is&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;    my \res = 6 ∘ 4 ∘ 3 ∘ ADD ∘ MUL ∘ BRK
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;some-abstraction-with-subroutines&quot;&gt;Some abstraction with subroutines&lt;/h2&gt;

&lt;p&gt;Uxntal allows to define subroutines. They are just blocks of code that you jump to. In my Raku implementation we can simply define custom subroutines and call them using the Uxntal instructions &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSR&lt;/code&gt; (jump and return), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JMP&lt;/code&gt; (jump and don’t return, used for tail calls) and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JCN&lt;/code&gt; (conditional jump).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;my \res =  3 ∘ 2 ∘ 1 ∘ INC ∘ ADD ∘ MUL ∘ 4 ∘ &amp;amp;f ∘ JMP ;

sub f {
    SUB ∘ 5 ∘ MUL ∘ 2 ∘ ADD ∘ RET
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(the instruction &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RET&lt;/code&gt; is called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JMP2r&lt;/code&gt; in Uxntal)&lt;/p&gt;

&lt;h2 id=&quot;stack-manipulation-operations&quot;&gt;Stack manipulation operations&lt;/h2&gt;

&lt;p&gt;One of the key features of a stack language is that it allows you to manipulate the stack. In Uxntal, there are several operations to duplicate, remove and reorder items on the stack. Here is a contrived example&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;my \res =
    4 ∘ 2 ∘ DUP ∘ INC ∘ # 4 2 3
    OVR ∘  # 4 2 3 2
    ROT ∘ # 4 3 2 2
    ADD ∘ 2 ∘ ADD ∘ MUL ∘ BRK ; # 42
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;keeping-it-simple&quot;&gt;Keeping it simple&lt;/h2&gt;

&lt;p&gt;Uxntal has more ALU operations and device IO operations. It also has a second stack (return stack) and operations to move data between stacks. Furthermore, every instruction can take the suffix ‘2’, meaning it will work on two bytes, and ‘k’, meaning that it will not consume its arguments but leave them on the stack. I am omitting all these for simplicity.&lt;/p&gt;

&lt;h2 id=&quot;the-mighty--operator-part-ii-implementation&quot;&gt;The mighty &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;∘&lt;/code&gt; operator, part II: implementation&lt;/h2&gt;

&lt;p&gt;With the above, we have enough requirements to design and implement the operator. As usual, I will eschew the use of objects. It was my intention to use all kind of fancy Raku features such as introspection but it turns out I don’t need them.&lt;/p&gt;

&lt;p&gt;We start by defining the Uxntal instructions as enums. I could use a single enum but grouping them makes their purpose clearer.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;enum StackManipOps is export &amp;lt;POP NIP DUP SWP OVR ROT BRK&amp;gt; ;
enum StackCalcOps is export &amp;lt;ADD SUB MUL INC DIV&amp;gt;;
enum JumpOps is export &amp;lt;JSR JMP JCN RET&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We use a stateful custom operator with the stack &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@wst&lt;/code&gt; (working stack) as state. The operator returns the top of the stack and is left-associative. Anything that is not an Uxntal instruction is pushed onto the stack.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;our sub infix:&amp;lt;∘&amp;gt;(\x, \y)  is export {
    state @wst = ();

    if y ~~ StackManipOps {
        given y {
            when POP { ... }
            ...
        }
    } elsif y ~~ StackCalcOps {
        given y {
            when INC { ... }
            ...
        }
    } elsif y ~~ JumpOps {
        given y {
            when JSR { ... }
            ...
        }
    } else {
        @wst.push(y);
    }

    return @wst[0]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is not quite good enough: the operator is binary, but the above implementation ignores the first element. This is only relevant for the first element in a sequence. We handle this using a boolean state &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$isFirst&lt;/code&gt;. When &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt;, we simply call the operator again with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Nil&lt;/code&gt; as the first element.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$isFirst&lt;/code&gt; state is reset on every &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BRK&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;    state Bool $isFirst = True;
    ...
    if $isFirst {
        @wst.push(x);
        $isFirst = False;
        Nil ∘ x
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The final complication lies in the need to support conditional jumps. The problem is that in e.g.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;    &amp;amp;ft ∘ JCN ∘ &amp;amp;ff ∘ JMP
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;depending on the condition, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ft&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ff&lt;/code&gt; should be called. If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ft&lt;/code&gt; is called, nothing after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JCN&lt;/code&gt; should be executed. I solve this by introducing another boolean state variable, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$skipInstrs&lt;/code&gt;, which is set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt; when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JCN&lt;/code&gt; is called with a true condition.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;    when JCN {
        my &amp;amp;f =  @wst.pop;
        my $cond = @wst.pop;
        if $cond&amp;gt;0 {
            $isFirst = True;
            f();
            $skipInstrs = True;
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The boolean is cleared on encountering a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JMP&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RET&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;    if $skipInstrs {
        if (y ~~ JMP) or (y ~~ RET) {
            $skipInstrs = False
        }
    } else {
        ...
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This completes the implementation of the operator &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;∘&lt;/code&gt;. The final structure is:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;our sub infix:&amp;lt;∘&amp;gt;(\x, \y)  is export {
    state @wst = ();
    state Bool $isFirst = True;
    state $skipInstrs = False;

    if $skipInstrs {
        if (y ~~ JMP) or (y ~~ RET) {
            $skipInstrs = False
        }
    } else {

        if $isFirst and not (x ~~ Nil) {
            @wst.push(x);
            $isFirst = False;
            Nil ∘ x
        }

        if y ~~ StackManipOps {
            given y {
                when POP { ... }
                ...
            }
        } elsif y ~~ StackCalcOps {
            given y {
                when INC { ... }
                ...
            }
        } elsif y ~~ JumpOps {
            given y {
                when JSR { ... }
                ...
            }
        } else {
            @wst.push(y);
        }
    }
    return @wst[0]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;memory-and-pointers&quot;&gt;Memory and pointers&lt;/h2&gt;

&lt;p&gt;Like most stack languages, Uxntal also has load and store operations to work with memory. Uxntal does not have a separate instruction memory, so you can mix code and data and even write self-modifying code. There are load and store operations on absolute (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LDA&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STA&lt;/code&gt;) and relative (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LDR&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STR&lt;/code&gt;) addresses. In my Raku implementation, I don’t distinguish between those. I use arrays as named stretches of memory. So for example the following native Uxntal snippet&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;@array #11 #22 #33
;array #0001 ADD2 LDA ( puts 0x22 on the stack )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;becomes&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;    my @array = 0x11, 0x22, 0x33;
    @array ∘ 0x0001 ∘ ADD ∘ LDA
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and that would be close enough, were it not that in Uxntal memory is declared after subroutines. So what I actually need to do is&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;    (array) ∘ 0x0001 ∘ ADD ∘ LDA
    sub array { [ 0x11, 0x22, 0x33 ] }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The way I handle the pointer arithmetic is by pattern matching on the type. Instructions &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ADD&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUB&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INC&lt;/code&gt; can take an integer or a label, which in Raku is an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array&lt;/code&gt;. The valid argument type for these operations is in pseudo-code for types:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Pair  = (Fst,Int)
Fst = Array | (Fst,Int)
Addr = Int | Array | Pair
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In words, it can be an integer, a label or a pair where the second element of the pair must be an integer and the first is either a label or a pair.&lt;/p&gt;

&lt;p&gt;For example for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INC&lt;/code&gt; operation, we do&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;    given (arg) {
        when Int { push @wst,arg+1}
        when Array { push @wst,(arg,1)}
        when List { push @wst,(arg,1)}
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ADD&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUB&lt;/code&gt; we do something similar but check if either arg is Int, Array or List. 
If both arguments are Int, we return the result of the operation; if only one of the arguments is an Int, we return the pair of arguments as a List; otherwise we throw an error as it is not a valid type.&lt;/p&gt;

&lt;p&gt;The non-integer return values of this kind of arithmetic are used in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LDA&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STA&lt;/code&gt;. Here, the only valid type is the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Addr = Array | (Addr, Int)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In other words, an address must always be relative to a label. So we will check if the argument is not an integer.&lt;/p&gt;

&lt;h2 id=&quot;hello-uxntal&quot;&gt;Hello, Uxntal&lt;/h2&gt;

&lt;p&gt;With this machinery we can run the following Uxntal “Hello World” program&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    |0100

        ;hello JSR2

    BRK

    @hello
        ;hello-word ;print-text JSR2
    JMP2r

    @print-text ( str* -- )
        ;while JSR2
        POP2
    JMP2r

    @while
            ( send ) DUP2 LDA #18 DEO
            ( loop ) INC2 DUP2 LDA ;while JCN2
    JMP2r

    @hello-word &quot;Hello 20 &quot;World! 00

( the `#18 DEO` instruction prints a byte on STDOUT )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;in Raku as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;    #|0100
        &amp;amp;hello ∘ JSR2 ∘ 
    BRK;

    sub hello {
        (hello-world) ∘ &amp;amp;print-text ∘ JSR2 ∘ 
        RET
    }

    sub print-text { # str* --
        &amp;amp;loop ∘ JSR2 ∘ 
        RET
    }

    sub loop {
        DUP2 ∘ LDA ∘ 0x18 ∘ DEO ∘ 
        INC2 ∘ DUP2 ∘ LDA ∘ &amp;amp;loop ∘ JCN2 ∘ 
        RET
    }

    sub hello-world { [&quot;Hello,&quot;,0x20,&quot;World!&quot;, 0x0a,0x00] }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As this program has a loop implemented as a tail recursion, it is complete in terms of illustrating the features of a stack-based program in Uxntal.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;So in conclusion, we can easily embed a stack-based programming language such as Uxntal in Raku purely by defining a single binary operator and a few enums for the instructions. This is mainly courtesy of Raku’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;state&lt;/code&gt; variables and powerful pattern matching.&lt;/p&gt;

&lt;p&gt;The code for this little experiment is available in my &lt;a href=&quot;https://github.com/wimvanderbauwhede/raku-examples&quot;&gt;raku-examples&lt;/a&gt; repo, with two sample programs &lt;a href=&quot;https://github.com/wimvanderbauwhede/raku-examples/blob/master/stack-based-programming.raku&quot;&gt;stack-based-programming.raku&lt;/a&gt; and &lt;a href=&quot;https://github.com/wimvanderbauwhede/raku-examples/blob/master/hello-uxntal.raku&quot;&gt;hello-uxntal.raku&lt;/a&gt; and the module implementing the operator &lt;a href=&quot;https://github.com/wimvanderbauwhede/raku-examples/blob/master/Uxn.rakumod&quot;&gt;Uxn.rakumod&lt;/a&gt;.&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>More on Funktal: I/O devices and state</title>
        <link href="https://limited.systems/articles/funktal-devices-state/"/>
        <updated>2023-08-03T00:00:00+01:00</updated>
        <id>https://limited.systems/articles/funktal-devices-state</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/funktal-devices-state_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;In &lt;a href=&quot;https://limited.systems/articles/funktal/&quot;&gt;a previous post&lt;/a&gt;, I introduced &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Funktal&lt;/code&gt;&lt;/a&gt;, a frugal functional programming language created for the &lt;a href=&quot;https://wiki.xxiivv.com/site/uxn.html&quot;&gt;Uxn&lt;/a&gt; VM. The Uxn VM is the heart of a clean-slate computing platform called &lt;a href=&quot;https://wiki.xxiivv.com/site/varvara.html&quot;&gt;Varvara&lt;/a&gt;. This post explains how you can access Varvara’s I/O devices from Funktal, and the closely related support for mutable state. I illustrate these features using three small GUI-based programs.&lt;/p&gt;

&lt;p&gt;The main purpose of Uxn and Varvara is as a portable platform for GUI-based applications, such as the &lt;a href=&quot;https://wiki.xxiivv.com/site/noodle.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;left&lt;/code&gt;&lt;/a&gt; editor, the &lt;a href=&quot;https://wiki.xxiivv.com/site/noodle.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;noodle&lt;/code&gt;&lt;/a&gt; drawing program and many others, in particular games. To make Funktal a practical language for this platform, support for I/O devices (keyboard, mouse, screen, audio) is essential.&lt;/p&gt;

&lt;h2 id=&quot;mutable-state-why-and-how&quot;&gt;Mutable state: why and how&lt;/h2&gt;

&lt;p&gt;Uxn I/O is event based, for example a button press or mouse click results in an event handler (aka vector or callback) being called. These handlers can access the Uxn VM’s  working and return stack as well as its memory. Most programs are stateful, so a efficient mechanism for handling state is important.&lt;/p&gt;

&lt;h3 id=&quot;keeping-state-on-the-stack&quot;&gt;Keeping state on the stack&lt;/h3&gt;

&lt;p&gt;We could keep the state on the stack. This is OK for simple cases but quickly gets cumbersome. Suppose we have three items of state then our function needs to look like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(\s1_in s2_in s3_in.
    &amp;lt;all computations&amp;gt;
    s3_out s2_out s1_out
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But we don’t know the type of items on the stack, so we need explicit typing, e.g.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;types {
    RGB = Int Int Int MkRGB
}

(\(RGB,Int,Bool) &amp;lt;- s1_in:Bool&amp;lt;- s2_in: Int&amp;lt;- s3_in:RGB.
    &amp;lt;all computations&amp;gt;
    s3_out s2_out s1_out
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The tuple syntax only indicates that the function pushes multiple values on the stack, it is not an algebraic data type and so we can’t construct it or pattern match on it.&lt;/p&gt;

&lt;h3 id=&quot;putting-the-state-in-a-record-type&quot;&gt;Putting the state in a record type&lt;/h3&gt;

&lt;p&gt;An improvement would be if the stack held an instance of a record type, because then all we have to do is keep such an instance on the stack.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;types {
    RGB = Int Int Int MkRGB
    State = Bool Int RGB MkState
}

(\State &amp;lt;- s_in:State. &amp;lt;all computations&amp;gt; s_out )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It still means that this state should remain on the stack, and if there are several event handlers each with their own state, either that means juggling those states or creating an overall state for all event handlers in the program and passing that around. Either way that would mean additional code for accessing the state.&lt;/p&gt;

&lt;p&gt;Because each instance of a type is immutable, this approach also means that every update of the state requires to construct a new type. (And in practice we’ll have to delete the old one, otherwise we’d run out of memory very quickly. But Funktal does not have managed memory yet. Yet another story.) Constructing types is expensive (and deletion even more so).&lt;/p&gt;

&lt;h3 id=&quot;making-state-mutable&quot;&gt;Making state mutable&lt;/h3&gt;

&lt;p&gt;For all these reasons, I decided to add mutable state to Funktal. It is very simple: in a special block called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;state&lt;/code&gt; we define a singleton instance of the type used for the state:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;types {
    RGB = Int Int Int MkRGB
    State = Bool Int RGB MkState
}

state {
    s : State
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So this defines &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s&lt;/code&gt; as a mutable instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;State&lt;/code&gt;. There can only be one such instance per type.
And now the function simple becomes&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;( &amp;lt;all computations on s&amp;gt; )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To access the information in a stateful record, there are two built-in functions, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;put&lt;/code&gt;, which access a field in the record using its (base-0) index:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0_1 s get -- gets the Bool from the record
42 1_1 s put -- puts 42 in the Int slot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These are polymorphic functions that work for any record type registered as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;state&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To make this more readable, I define some constants to identify the fields. Suppose the purpose of the fields in the State type are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;greyscale&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transparency&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;colour&lt;/code&gt;, we can define&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;constants {
    greyscale#State = 0_1
    transparency#State = 1_1
    colour#State = 2_1
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and write&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;greyscale#State s get -- gets the greyscale from the record
42 transparency#State s put -- puts 42 in the transparency field
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(The ‘#’ has no special meaning, I use it as a separator so that I can use the same field names in different types.)&lt;/p&gt;

&lt;p&gt;Because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;State&lt;/code&gt; is a proper Funktal type, you can also use pattern matching to bind the field values to names:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;s (\None &amp;lt;- (greyscale transparency colour MkState) : State . &amp;lt;all computations on s&amp;gt; )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But as bound variables are immutable, you can’t update the state this way.&lt;/p&gt;

&lt;h3 id=&quot;mutable-arrays&quot;&gt;Mutable arrays&lt;/h3&gt;

&lt;p&gt;Funktal has a built-in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array&lt;/code&gt; type for immutable array constants, with built-in functions &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;size&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;at&lt;/code&gt;.
Within the context of a mutable state type, such arrays can be updated using a built-in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update&lt;/code&gt; function. 
For example, assuming a state &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s : AState&lt;/code&gt; has a field labelled &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;array&lt;/code&gt; which is of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array&lt;/code&gt;, we can write&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;val idx array#AState s get update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;devices&quot;&gt;Devices&lt;/h2&gt;

&lt;p&gt;I/O devices in Uxn are typically defined in this way:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|20 @Screen &amp;amp;vector $2 
    &amp;amp;width $2 &amp;amp;height $2 &amp;amp;pad $2 
    &amp;amp;x $2 &amp;amp;y $2 &amp;amp;addr $2 
    &amp;amp;pixel $1 &amp;amp;sprite $1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In Funktal we simply define a corresponding record type:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;types {
    Screen = Int Int Int Int Int Int Int Int8 Int8 MkScreen
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And to make this more readable, there is an aliasing mechanism&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;aliases {
    Vector = Int
    Width = Int; Height = Int; Pad = Int; X = Int; Y = Int; Addr = Int; Pixel = Int8; Sprite = Int8
}

types {
    Screen = Vector Width Height Pad X Y Addr Pixel Sprite MkScreen
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The key difference with our mutable state is that each device has a unique address.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;devices {
    0x20 scr : Screen
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And to make a clear distinction with state operations, the built-in function to access I/O devices are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;write&lt;/code&gt;, for example&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(\None&amp;lt;-colour:Int8 . colour sprite#Screen scr write )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;bits-and-bobs-blocks-loops-done&quot;&gt;Bits and bobs: blocks, loops, done&lt;/h2&gt;

&lt;p&gt;There are a few more features of Funktal that make implementing device interactions easier.&lt;/p&gt;

&lt;h3 id=&quot;the-block-type&quot;&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Block&lt;/code&gt; type&lt;/h3&gt;

&lt;p&gt;A very common action in Uxn programs is to read constant data for sprites. For example, the following is typical:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;font-hex ADD2 .Screen/addr DEO2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This can’t be implemented with the existing Arrays API in Funktal, because the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;addr&lt;/code&gt; field of the screen device expect the actual address in Uxn memory. Therefore I added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Block&lt;/code&gt; datatype, which is simply a contiguous sequence of bytes:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;font_hex : Byte 128 Block = [
     0x00,0x7c ,0x82,0x82 ,0x82,0x82 
    ... ]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is only used for constants, and the instance of the type (i.e. the constant) contains the address of the first element (like an array in C). So you can write:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;font_hex + addr#Screen scr write
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;the-loop-built-in&quot;&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loop&lt;/code&gt; built-in&lt;/h3&gt;

&lt;p&gt;Although I conceived Funktal as a functional language, where a natural programming paradigm is using higher-order list functions such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fold&lt;/code&gt;, for I/O actions it is very common to loop over some action that does not return anything. It is of course easy to implement such a loop in native Funktal, but it can be done more efficiently in Uxntal, so Funktal has a built-in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loop&lt;/code&gt; function which takes a start and end value and a lambda function, and returns nothing:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;loop: None &amp;lt;- Int &amp;lt;- Int &amp;lt;- (None&amp;lt;-Int)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For example&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0 9 `(\None&amp;lt;-idx:Int. idx 1 + print ) loop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;will print all values in the range. (And although I know all the arguments to the contrary, the range is 0 to 9, not 0 to 8).&lt;/p&gt;

&lt;h3 id=&quot;stateful-loop-iteration&quot;&gt;Stateful loop iteration&lt;/h3&gt;

&lt;p&gt;Sometimes you might to maintain some state during the loop iteration, similar to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fold&lt;/code&gt;. This can be done via the stack:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0 -- This puts a 0 on the working stack
0 len 1_1 - Int
`(\ Int &amp;lt;- val : Int &amp;lt;- idx : Int .
    idx array at (\Int &amp;lt;- elt : Int .
        val idx array update
        elt
    )
) loop
-- Clear the working stack
(\None&amp;lt;-null:Int.)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This example loops over indices 0 to len-1, and gets the element from an array. It then updates the array with the value on the stack, and puts the element on the stack. So if the array was [11, 22, 33, 44], it will become [0, 11, 22, 33]. The one thing to look out for is that this will leave the final element on the stack, so you may want to remove it by calling an empty lambda on it, which is what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(\None&amp;lt;-null:Int.)&lt;/code&gt; does.&lt;/p&gt;

&lt;h3 id=&quot;the-done-built-in&quot;&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;done&lt;/code&gt; built-in&lt;/h3&gt;

&lt;p&gt;Funktal normally expects a called function to return. Event handlers have nowhere to return to. As a simple way to handle this is I added the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;done&lt;/code&gt; built-in, which will tell the compiler to emit a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BRK&lt;/code&gt; rather than a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JMP2r&lt;/code&gt; at the end of a function. If it is used elsewhere, it simply emits a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BRK&lt;/code&gt; which is useful for debugging.&lt;/p&gt;

&lt;h2 id=&quot;examples&quot;&gt;Examples&lt;/h2&gt;

&lt;p&gt;I have implemented a few examples of GUI-based programs. Two are ports of Uxn demos, the third renders the Funktal logo.&lt;/p&gt;

&lt;h3 id=&quot;example-1-dvd&quot;&gt;Example 1: DVD&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/devel/examples/dvd.ftal&quot;&gt;This example&lt;/a&gt; is a simple program that bounces the DVD icon around the screen.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;https://limited.systems/images/dvd.avif&quot; alt=&quot;A white DVD logo on a blue background&quot; title=&quot;A white DVD logo on a blue background&quot; /&gt;
&lt;figcaption&gt;DVD icon bouncing&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;It is a straight port of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dvd.tal&lt;/code&gt; program. We define types for the system and screen devices and the dvd state:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;types {
    System = Word Int8 Int8 Int Int8 Int8 Word Word Word Int8 Int8 MkSystem
    Screen = Int Int Int Byte Int8 Int Int Int Int8 Int8 MkScreen
    DVD = Int Int Int Int MkDVD
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then we create the instance:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;state {
    dvd : DVD
}

devices {
    0x00 sys : System
    0x20 scr : Screen
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are no loops in this program, and no controls. It simply calculates the new position of the icon on every clock tick. The only event handler is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;onFrame&lt;/code&gt;. Because this is a straight port, it does use the stack for some values. The main program registers that event handler, does some setup and puts the borders on the stack:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;main {
    ...
`onFrame vec#Screen scr write
...
    20 w#Screen scr read 20 -
    20 h#Screen scr read 20 -
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These borders are used by the event handler but not modified:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;functions {

    -- takes the borders from the stack
    onFrame = ( \ xmin xmax ymin ymax .
        0x00 drawDVD
        x#DVD dvd get
        y#DVD dvd get
        dx#DVD dvd get
        dy#DVD dvd get
        (\ Int &amp;lt;- x : Int &amp;lt;- y : Int &amp;lt;- dx : Int &amp;lt;- dy : Int .
            ... calculate new position ....
        )
        0x01 drawDVD
        -- put the borders back on the stack
        xmin xmax ymin ymax
        done
    )
}

-- takes the colour (0 or 1) as argument
drawDVD = (\ None &amp;lt;- c : Int8. ... )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;done&lt;/code&gt; at the end of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;onFrame&lt;/code&gt; function, because it is an event handler.&lt;/p&gt;

&lt;h2 id=&quot;example-2-snake&quot;&gt;Example 2: Snake&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/devel/examples/snake.ftal&quot;&gt;This example&lt;/a&gt; is a straight port of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;snake.tal&lt;/code&gt; program, a game where you control a snake to eat apples, and the snake grows longer and longer.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;https://limited.systems/images/snake.avif&quot; alt=&quot;A green snake with a tail of 5 segments, about to eat a red apple, on a black background &quot; title=&quot;A green snake with a tail of 5 segments, about to eat a red apple, on a black background&quot; /&gt;
&lt;figcaption&gt;Snake in action&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The main differences with the DVD code is that there are buttons to control the direction of the snake, so we need a controller device, and that the tail of the snake is an array, so we use loops to update it.&lt;/p&gt;

&lt;p&gt;The controller device:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;types {
    Controller = Vector Button Key MkController
}

devices {
    0x80 ctl : Controller
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The button handler is registered as before:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;`onButton vec ctl write
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The handler itself:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;onButton = (
    button#Ctl ctl read
    (\None &amp;lt;-b:Int8.
         b 8_1 /=
        `( b noEscape )
        `( reset )
         if
    )
    done
)

noEscape = (\ None &amp;lt;- b : Int8 .
    b 4_1 &amp;gt;&amp;gt; (\None &amp;lt;-bb : Int8 .
        bb 0_1 /=
        `( bb dir#Snake snake put )
        `() if
    )
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So we read the button value, compute a value based on the button that is pressed, and write that into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dir&lt;/code&gt; field if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;snake&lt;/code&gt; state. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Snake&lt;/code&gt; type is&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;aliases {
    X=Int8; Y=Int8
    Dir=Int8; Len=Int8; Dead=Int8
    Tail = Int 32 Array
}

types {
    Snake = Dir Len Dead X Y Tail MkSnake
}

state {
    snake : Snake
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is an example of a state containing an array. The main action is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drawSnake&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;drawSnake = (\None&amp;lt;-c:Int8.
    -- draw tail
    snake_icns addr#Screen scr write 
    len#Snake snake get (\None &amp;lt;- len:Int8 .
        0 len 1_1 - Int
        `(\None&amp;lt;-idx:Int .
            idx (tail#Snake snake get) at (\None &amp;lt;- xy:Int.
            xy 8_1 &amp;gt;&amp;gt; Int8 Int 3_1 &amp;lt;&amp;lt; x#Screen scr write
            xy        Int8 Int 3_1 &amp;lt;&amp;lt; y#Screen scr write
        )
        c sprite#Screen scr write
        ) loop
    )
    -- draw head
    ...
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The tail is an array of 16-bit integers which are actually pairs of 8-bit integers representing the coordinate for each segment of the tail. So what the code does is reading &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xy&lt;/code&gt; from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tail&lt;/code&gt; array, unpacking it into an x and y value, and multiplying these by 8 because we have 8x8 sprites so the movement is in steps of 8 pixels.&lt;/p&gt;

&lt;h2 id=&quot;example-3-funktal-logo-rendering&quot;&gt;Example 3: Funktal logo rendering&lt;/h2&gt;

&lt;p&gt;I implemented various ways of rendering the Funktal logo.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;https://limited.systems/images/funktal-logo.avif&quot; alt=&quot;The Funktal logo, triangles and rectangles rendered as a grid of black dots&quot; title=&quot;The Funktal logo, triangles and rectangles rendered as a grid of black dots&quot; /&gt;
&lt;figcaption&gt;Funktal logo rendered using the example code&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/devel/examples/render-logo-gui-state-onFrame.ftal&quot;&gt;This example&lt;/a&gt; is rendering it one pixel at a time for every frame event (clock tick). So it has no internal loops. It is a bit complicated because the Funktal logo can be decomposed into isosceles right triangles (the base and height are the same) and symmetry operations.
The array &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;triangleEncodings&lt;/code&gt; contains a list of (triangle orientation, triangle position) pairs. There is a state &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;counters&lt;/code&gt; with a counter for the triangle and the row and column position of the current pixel to be drawn.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;onFrame = (\None.
    0_1 run get 1_1 ==
   `(
        trCodeIdx counters get
        rowIdx counters get
        colIdx counters get
        (\None &amp;lt;- tIdx:Int8 &amp;lt;- rIdx:Int8 &amp;lt;- cIdx:Int8.
             tIdx Int triangleEncodings at rIdx cIdx drawPixel
             cIdx rIdx &amp;lt;
            `( cIdx 1_1 + colIdx counters put )
            `( 0_1 colIdx counters put
                 rIdx triangleDim 1_1 - &amp;lt;
                `( rIdx 1_1 + rowIdx counters put )
                `( 0_1 rowIdx counters put
                     tIdx 14_1 &amp;lt;
                    `( tIdx 1_1 + trCodeIdx counters put )
                    `() if
                 ) if
             ) if
        )
    ) `() if
    done
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There is a single control, pressing any key toggles pausing/continuing the rendering. That is the purpose of the first condition in the above code, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run&lt;/code&gt; is a separate state.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I hope this post and the previous one have provided some idea of what Funktal is like and what you can do with it. I plan to write another, longer article on how the compiler is made. For more information, see the a &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/main/SPEC.md&quot;&gt;specification&lt;/a&gt; (aimed at people who want to program in Funktal) and the &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/main/DESIGN.md&quot;&gt;design document&lt;/a&gt; (aimed at people who want to help develop Funktal or are just curious), both still very much in flux.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The banner picture shows a detail of the control panel of a Japanese train&lt;/em&gt;&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>Funktal: a frugal functional programming language</title>
        <link href="https://limited.systems/articles/funktal/"/>
        <updated>2023-04-10T00:00:00+01:00</updated>
        <id>https://limited.systems/articles/funktal</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/funktal_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;&lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Funktal&lt;/code&gt;&lt;/a&gt; is a functional programming language for the &lt;a href=&quot;https://wiki.xxiivv.com/site/uxn.html&quot;&gt;Uxn&lt;/a&gt; virtual machine, a tiny VM with 8-bit opcodes and 64 kB of memory. I have written about implementing functional constructs in Uxn’s native stack based assembly language &lt;a href=&quot;https://wiki.xxiivv.com/site/uxntal.html&quot;&gt;Uxntal&lt;/a&gt; in &lt;a href=&quot;https://limited.systems/articles/uxntal-quoting/&quot;&gt;a previous post&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;rationale&quot;&gt;Rationale&lt;/h2&gt;

&lt;p&gt;The main reason for creating Funktal was to see if it was possible to create a statically typed functional language with &lt;a href=&quot;https://limited.systems/articles/roles-as-adts-in-raku/&quot;&gt;algebraic data types&lt;/a&gt; and &lt;a href=&quot;https://limited.systems/articles/function-types/&quot;&gt;function types&lt;/a&gt; that could run on the Uxn VM, with a compiler that could be implemented in Uxntal. This is motivated by the observation that most modern languages are very resource-intensive: typical projects take a lot of disk space, compilers are large and require a lot of CPU cycles and memory to compile code, and the programs themselves are also very often CPU- and memory-intensive.&lt;/p&gt;

&lt;p&gt;Hard disks and solid-state drives are major contributors to the &lt;a href=&quot;https://principles.green/principles/embodied-carbon/&quot;&gt;embodied carbon&lt;/a&gt; in a computer, followed by the CPU and memory. Reducing these resources is an important way to reduce CO₂ emissions from computing. The ability to write useful software for older generations of hardware allows to use them for longer, and that is the main way to reduce embodied carbon.&lt;/p&gt;

&lt;h2 id=&quot;funktal-design-principles&quot;&gt;Funktal design principles&lt;/h2&gt;

&lt;p&gt;The main principle for the design of Funktal is that it should use as little memory as possible, both for the compiler and the programs it produces. This influences most of the design decisions. But at the same time, it should be minimally but fully featured: I want a pure, strict functional language, with a sufficiently expressive static type system. Also, I want the language to be simple to write easy code but expressive enough to write more complex code.&lt;/p&gt;

&lt;p&gt;The main characteristics of Funktal are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It uses postfix notations (aka Reverse Polish Notation, Forth-style).&lt;/li&gt;
  &lt;li&gt;It is entirely based on lambda functions (anonymous functions), but has named functions too.&lt;/li&gt;
  &lt;li&gt;All variables are immutable (as they are lambda function arguments)&lt;/li&gt;
  &lt;li&gt;The type system is based on primitive types and product and sum types and function types to create new types.&lt;/li&gt;
  &lt;li&gt;Typing is optional, and therefore Funktal is not fully type safe.&lt;/li&gt;
  &lt;li&gt;I/O is not pure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/main/SPEC.md&quot;&gt;specification&lt;/a&gt; (aimed at people who want to program in Funktal) and a &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/main/DESIGN.md&quot;&gt;design document&lt;/a&gt; (aimed at people who want to help develop Funktal or are just curious), both still very much in flux.&lt;/p&gt;

&lt;h2 id=&quot;funktal-by-example&quot;&gt;Funktal by example&lt;/h2&gt;

&lt;p&gt;All examples can be found in the &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/main/examples&quot;&gt;examples folder in the repo&lt;/a&gt;. To try them out, please see the &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/&quot;&gt;README&lt;/a&gt; for installation instructions.&lt;/p&gt;

&lt;h3 id=&quot;basic-syntax&quot;&gt;Basic syntax&lt;/h3&gt;

&lt;p&gt;Funktal is whitespace separated and consists of a number of blocks, the most important of which are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;types&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;constants&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;functions&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt;. There are only expressions, so the entire main program is a single sequence of expressions. Newlines are only for readability and as comment delimiters: anything after a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--&lt;/code&gt; until a newline is considered a comment.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;main {
    6 7 * print -- prints 42
    0x0a print  -- prints a newline
    &quot;Hello&quot; print -- prints Hello
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;small&gt;&lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/main/examples/01-print.ftal&quot;&gt;Example 1: printing&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;h3 id=&quot;lambdas-and-named-functions&quot;&gt;Lambdas and named functions&lt;/h3&gt;

&lt;p&gt;Funktal is a functional language so the key building block is the lambda function (anonymous function). Each lambda is enclosed in parentheses and the arguments are listed between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Lambdas do not need to have arguments. Because Funktal is a stack language, if there is anything on the stack, it will be used as argument for the functions. But arguments are often convenient.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;main {
    6 (\x. x x * x 2 * + x -  print ) -- 42
    6  (\x. 7 (\y . x y * print ) ) -- 42
    2 84 `( / ) (\ x y div . y x div apply ) print -- 0x002a
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;small&gt;&lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/main/examples/02-lambdas.ftal&quot;&gt;Example 2: lambdas&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;The second example shows a nesting lambdas, with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; argument of the outer lambda in scope in the body of the nested lambda.&lt;/p&gt;

&lt;p&gt;The last line is an example of &lt;em&gt;quoting&lt;/em&gt; of functions: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;( / )&lt;/code&gt; is anonymous function without arguments which only performs a division. More fully we could write it as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(\ x y . x y /)&lt;/code&gt;. Normally, this function would be called right away. By quoting it with a backtick, it is not called until we call it explicitly using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply&lt;/code&gt;. The example also shows that functions can be passed as arguments to other functions.&lt;/p&gt;

&lt;h3 id=&quot;primitive-types&quot;&gt;Primitive types&lt;/h3&gt;

&lt;p&gt;Funktal has primitive types &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Int8&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Int16&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AChar&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Byte&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Short&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Int&lt;/code&gt; is currently a synonym for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Int16&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AChar&lt;/code&gt; is an ASCII character; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Byte&lt;/code&gt; is a raw byte value and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Short&lt;/code&gt; a raw 2-byte value. The arrow &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;-&lt;/code&gt; in the type signature separates arguments and return type of a function. The colon &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:&lt;/code&gt; separates the argument from its type.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;main {
    6 (\ Int &amp;lt;- x : Int . x x * 2 x * + x - ) print
    (\ Int8 . 6 (\ Int8 &amp;lt;- x : Int8 . x x * 2 x * + x - ) print )
    0x2a 0x2b (\ Byte &amp;lt;- b1: Byte &amp;lt;- b2 : Byte . b1 b2 &amp;amp; ) print
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;small&gt;&lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/main/examples/03-primitive-types.ftal&quot;&gt;Example 3: primitive types&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Without type information, Funktal defaults to 16-bit operations. If you want to use 8-bit operations, explicit typing is necessary, as in the examples above. As shown in the second example, a lambda without arguments can still have an explicit return type.&lt;/p&gt;

&lt;h3 id=&quot;constants&quot;&gt;Constants&lt;/h3&gt;

&lt;p&gt;Constants are a convenience. The main purpose is to define arrays of values (e.g. bitmaps) and strings, but scalars are also supported. There is a built-in type that is not strictly speaking primitive: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array&lt;/code&gt;, used to create array constants. Its constructor takes the type and number of the elements in the array.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;constants {
    hello : AChar 6 Array = &quot;Hello!&quot;
}

main {
    hello print
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;small&gt;&lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/main/examples/04-constants.ftal&quot;&gt;Example 4: constants&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;h3 id=&quot;sum-types-and-conditionals&quot;&gt;Sum types and conditionals&lt;/h3&gt;

&lt;p&gt;As mentioned above, Funktal has algebraic data types. The Boolean type is an example of a sum type (similar to an enum): it has two alternatives, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt;. The example also shows the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; builtin, which takes two quoted lambdas and a condition, i.e. any expression which returns True or False.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Any&lt;/code&gt; type is the supertype of all types. Funktal does (currently) not have polymorphism. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Any&lt;/code&gt; type can be used explicitly and is also the type of any untyped expression. Because Funktal allows untyped expressions and does not do type inference (yet), it is not fully type safe.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;types {
    Bool = True | False
}

main {
    True (\ Any &amp;lt;- cond : Bool .
         cond
        `( &quot;true&quot; print )
        `( &quot;false&quot; print )
         if
    )
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;small&gt;&lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/main/examples/05-if.ftal&quot;&gt;Example 5: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt;&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;h3 id=&quot;product-data-type-construction-and-pattern-matching&quot;&gt;Product data type construction and pattern matching&lt;/h3&gt;

&lt;p&gt;This is an example of a record or product type. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RGB&lt;/code&gt; type is a triplet of 8-bit integers. The reason why the entire expression is wrapped in a typed lambda is that otherwise the integers would be treated as 16-bit. Funktal does not have proper type checking yet. The return type of a function determines the size of the operations and constants used in the function body.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;types {
    RGB =  Int8 Int8 Int8 RGB
}

main {
        (\ Int8 . 42 43 44 RGB (\ Int8 &amp;lt;- (r g b RGB) : RGB . r ) ) print
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;small&gt;&lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/main/examples/06-rgb.ftal&quot;&gt;Example 6: records&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;h3 id=&quot;recursion&quot;&gt;Recursion&lt;/h3&gt;

&lt;p&gt;Funktal does not have mutable variables so it has no loops. Instead, it uses recursion.&lt;/p&gt;

&lt;h4 id=&quot;factorial-with-named-functions&quot;&gt;Factorial with named functions&lt;/h4&gt;

&lt;p&gt;This is a straightforward recursion to calculate a factorial: if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b==e&lt;/code&gt; then return the result &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt; else recurse with the counter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b+1&lt;/code&gt; and the accumulator &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r*b&lt;/code&gt;. This is a tail recursion. It also demonstrates the use if named functions, and Funktal’s natural ability to support point-free programming.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function {
    fact = ( 1 1 fact_rec )
    fact_rec =  (\ Int  &amp;lt;- e : Int &amp;lt;- b : Int &amp;lt;- r : Int . b e == `( r e * )  `(  e b 1 + r b * fact_rec) if )
}

main {
    5 fact 1 * print
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;small&gt;&lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/main/examples/07-fact.ftal&quot;&gt;Example 7: factorial&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;I use an actual recursive function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fact_rec&lt;/code&gt; and a wrapper to initialise the counter and the accumulator.&lt;/p&gt;

&lt;h4 id=&quot;recursion-without-named-functions&quot;&gt;Recursion without named functions&lt;/h4&gt;

&lt;p&gt;Recursion means a function calls itself. But what if the function doesn’t have a name? A &lt;em&gt;fixed-point combinator&lt;/em&gt; allows to do recursion on unnamed functions. The most common one is the Y-combinator. The way I’ve done this here is a bit different, but equivalent. The quoted function describes the recursion. But because that function has no name, it can’t call itself. The function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(\f. f f apply)&lt;/code&gt; takes it as its argument, so now it has a name and can be called recursively.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;main {
    5
    `(\ n &amp;lt;- f . n 1 == `(1) `( n 1 - f f apply n * ) if)
    (\ Int &amp;lt;- f : Any . f f apply ) print
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;small&gt;&lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/main/examples/08-fact-fix.ftal&quot;&gt;Example 8: factorial with fixed-point&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;h4 id=&quot;lists-and-fold&quot;&gt;Lists and fold&lt;/h4&gt;

&lt;p&gt;Algebraic data types can also be used to construct lists, like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;types {
    List = List Any Cons | Nil
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is a recursive type, a List is either a function Cons with takes a List and some value, or a function Nil which takes no arguments. So we can build lists by writing e.g.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Nil 11 Cons 22 Cons 33 Cons
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In practice, it is handy to have a function to generate a range of numbers (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;range&lt;/code&gt; below) and list manipulation functions like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;head&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tail&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fold&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt;. The example shows the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;range&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fold&lt;/code&gt; to calculate a factorial by multiplying all values in a list.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;functions {
    -- First element of a list
    head = (\ Any &amp;lt;- (xs x Cons) . x )
    -- The rest of the list
    tail = (\ List &amp;lt;- (xs x Cons) . xs )
    -- Creates a list with a range of integers
    range = ( Nil range_rec )
    range_rec = (\List &amp;lt;- b: Int &amp;lt;- e: Int &amp;lt;- lst : List . b e == `( lst e Cons ) `( b 1 + e lst b Cons range_rec ) if )
    -- A reduction: fold takes a list, an accumulator and a function and combines all elements of the list into the accumulator
    fold = (\ Any &amp;lt;- lst : List &amp;lt;- acc : Any  &amp;lt;- f : Any . lst `Nil is `( acc ) `( lst tail acc lst head f apply f fold ) if )
}

main {
    (\Int . 1 5 range 1 `( * ) fold ) print
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;small&gt;&lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/funktal/src/branch/main/examples/09-lists.ftal&quot;&gt;Example 9: lists&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;/h2&gt;

&lt;p&gt;The Funktal compiler should be implementable in Uxntal (or even Funktal) and run on Uxn. I did not feel I was sufficiently fluent in Uxntal to use it as the implementation language. Instead, I opted to write the compiler in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fortran&lt;/code&gt;, but in such a way that porting to Uxntal should be straightforward.&lt;/p&gt;

&lt;p&gt;Why Fortran? Funktal is essentially an art project; using Fortran is a statement. I could have done this in C, but I prefer Fortran’s arrays. I am using Fortran-90 but with a very restricted feature set. In case you don’t know Fortran, here are some of its characteristics:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;No lexical scoping&lt;/li&gt;
  &lt;li&gt;Numeric labels for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;goto&lt;/code&gt;; no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;break&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Arrays starting by default at 1 but can start at any integer value&lt;/li&gt;
  &lt;li&gt;No unsigned integers&lt;/li&gt;
  &lt;li&gt;No native hash tables&lt;/li&gt;
  &lt;li&gt;Implicit typing based on the first letter of the variable name (*)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;small&gt;(*) But luckily you can disable that feature in Fortran-90&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Furthermore, because of the restricted subset I use:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;No pointers so no native linked lists&lt;/li&gt;
  &lt;li&gt;No derived types, so no structs&lt;/li&gt;
  &lt;li&gt;No dynamic allocation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is almost as if I’d have taken the &lt;a href=&quot;https://homepages.inf.ed.ac.uk/rni/papers/realprg.html&quot;&gt;“Real Programmers Don’t Use PASCAL”&lt;/a&gt; essay too literally:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;LANGUAGES&lt;br /&gt;
The easiest way to tell a Real Programmer from the crowd is by the programming language he (or she) uses. Real Programmers use FORTRAN. […]&lt;/p&gt;

  &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Real Programmers do List Processing in FORTRAN
Real Programmers do String Manipulation in FORTRAN.
[...] If you can&apos;t do it in FORTRAN, do it in assembly language. If you can&apos;t do it in assembly language, it isn&apos;t worth doing.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;STRUCTURED PROGRAMMING&lt;br /&gt;
[…] Some quick observations on Real Programmers and Structured Programming:&lt;/p&gt;

  &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Real Programmers aren&apos;t afraid to use GOTO&apos;s.
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

  &lt;p&gt;[…]. As all Real Programmers know, the only useful data structure is the Array. Strings, lists, structures, sets – these are all special cases of arrays and can be treated that way just as easily without messing up your programming language with all sorts of complications. […]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Be that as it may, this restricted subset maps cleanly to Uxntal, and also forces me to think very carefully about data structures. As a result, the compiler in its current states about 5,000 lines of code, allocates less than 64 kB and compiles to an executable of about 100 kB. For reference, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uxnasm&lt;/code&gt; is 20 kB, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uxncli&lt;/code&gt; is   25 kB and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uxnemu&lt;/code&gt; is 50 kB. But &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gfortran&lt;/code&gt; are 1.2 MB and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rustc&lt;/code&gt; is 15 MB.&lt;/p&gt;

&lt;h2 id=&quot;status&quot;&gt;Status&lt;/h2&gt;

&lt;p&gt;Funktal needs a lot more work (compilers are never finished), but it is now in a state that most of &lt;a href=&quot;https://git.sr.ht/~rabbits/uxn/tree/main/item/projects/examples/demos&quot;&gt;the Uxn demo applications&lt;/a&gt; can be ported to it. It already supports devices and state, as explained in &lt;a href=&quot;https://limited.systems/articles/funktal-state-devices&quot;&gt;the follow-on post&lt;/a&gt;. At the top of my long wish list is library support and memory management.&lt;/p&gt;

&lt;p&gt;Apart from that, there are plenty of bugs and shortcomings that need fixing. But it is already good enough to have some fun with, which is of course the main purpose.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The banner picture shows a wooden telephone in a temple in Kyoto&lt;/em&gt;&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>The climate cost of the AI revolution</title>
        <link href="https://limited.systems/articles/climate-cost-of-ai-revolution/"/>
        <updated>2023-03-06T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/climate-cost-of-ai-revolution</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/climate-cost-of-ai-revolution_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;ChatGPT and other AI applications such as Midjourney have pushed “Artificial Intelligence” high on the hype cycle. In this article, I want to focus specifically on the energy cost of training and using applications like ChatGPT, what their widespread adoption could mean for global CO₂ emissions, and what we could do to limit these emissions.&lt;/p&gt;

&lt;h2 id=&quot;key-points&quot;&gt;Key points&lt;/h2&gt;

&lt;h3 id=&quot;training-of-large-ai-models-is-not-the-problem&quot;&gt;Training of large AI models is not the problem&lt;/h3&gt;

&lt;p&gt;Training of large AI models requires a lot of electricity. However, for a modest growth scenario where there would be a hundred very popular AI-based services in the entire world, I estimate that the global CO₂ emissions from training AI are likely to remain relatively small.&lt;/p&gt;

&lt;h3 id=&quot;large-scale-use-of-large-ai-models-would-be-unsustainable&quot;&gt;Large-scale use of large AI models would be unsustainable&lt;/h3&gt;

&lt;p&gt;For that same  modest growth scenario, with a hundred very popular AI-based services in the entire world, the electricity consumption resulting from the use of these services would lead to unsustainable increases in global CO₂ emissions.&lt;/p&gt;

&lt;h3 id=&quot;renewables-are-not-making-ai-more-sustainable&quot;&gt;Renewables are not making AI more sustainable&lt;/h3&gt;

&lt;p&gt;Using renewables to power AI is not the solution. Large scale adoption of AI would lead to a huge increase in electricity consumption, much more than can be offset even by the fastest possible roll-out of renewables. So even if all AI is powered by renewables, it will not help us reduce global emissions and we will still miss the global climate targets.&lt;/p&gt;

&lt;h3 id=&quot;reducing-the-climate-cost-of-ai&quot;&gt;Reducing the climate cost of AI&lt;/h3&gt;

&lt;p&gt;Technological solutions to increase energy efficiency of AI are likely to lead to a more than proportionate increase in demand for AI - as history has shown us with other technology adoptions. As with any activity that consumes energy, the best way to limit energy consumption is to limit the activity. As a society we need to treat AI resources as finite and precious, to be utilised only when necessary, and as effectively as possible. We need &lt;em&gt;frugal AI&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;carbon-cost-of-electricity-usage&quot;&gt;Carbon cost of electricity usage&lt;/h2&gt;

&lt;p&gt;Many tech companies make much of their use of renewables to power their services. What metric should we use for the electricity usage of ICT in general and Large Language Models in particular? I argue that the metric to use is the carbon intensity of the geographical area in which the electricity is generated and can be traded. In practice, that means the country or group of countries of generation. If the usage is globally distributed, we should use the weighted average intensity.&lt;/p&gt;

&lt;p&gt;Because electricity is still predominantly generated from fossil fuels. In the US, where most of the data centres for AI training and use are located, &lt;a href=&quot;https://www.eia.gov/tools/faqs/faq.php?id=427&amp;amp;t=3&quot;&gt;according to IEA data&lt;/a&gt; this is 60%; only 21% is truly renewable. According to &lt;a href=&quot;https://ec.europa.eu/eurostat/statistics-explained/index.php?title=Renewable_energy_statistics&quot;&gt;EuroStat&lt;/a&gt;, in the EU renewables account for 22% and according to &lt;a href=&quot;https://www.nationalgrid.com/stories/energy-explained/how-much-uks-energy-renewable&quot;&gt;National Grid&lt;/a&gt;, in the UK it is 38%. Therefore, using renewables for increased electricity usage simply results in displacement of the emissions. &lt;a href=&quot;https://www.weforum.org/agenda/2021/07/renewables-cheapest-energy-source/&quot;&gt;Renewables are already the cheapest form of generation&lt;/a&gt;, so generators do not need market pull to install more capacity: to maximise their profit, they will maximise their renewables capacity. Even when the generation is on-site, the argument still stands: the electricity use to power AI could be traded on the grid. So in the case of GPT-3 we should use the overall carbon intensity of the US, which is 371 gCO₂/kWh according to &lt;a href=&quot;https://carbonfund.org/calculation-methods/&quot;&gt;the Carbon Fund&lt;/a&gt;, or alternatively the global carbon intensity, 476 gCO₂/kWh according to &lt;a href=&quot;https://www.iea.org/reports/world-energy-outlook-2019&quot;&gt;the IEA World Energy Outlook 2019&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;carbon-emissions-from-ict&quot;&gt;Carbon emissions from ICT&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://limited.systems/articles/frugal-computing/&quot;&gt;There is an imperative to &lt;em&gt;reduce&lt;/em&gt; emissions from information and communication technologies&lt;/a&gt; (ICT): purely to keep to the Paris agreement, they should drop to a quarter of current emissions in the next 20 years, from about &lt;a href=&quot;https://www.sciencedirect.com/science/article/pii/S2666389921001884&quot;&gt;2 GtCO₂e/y (including embodied emissions)&lt;/a&gt; to 500 MtCO₂e/y. So this is the global ICT carbon budget for the future.&lt;/p&gt;

&lt;p&gt;This is not going to happen through renewables: with business as usual, by 2040 renewables will be &lt;a href=&quot;https://iea.blob.core.windows.net/assets/deebef5d-0c34-4539-9d0c-10b13d840027/NetZeroby2050-ARoadmapfortheGlobalEnergySector_CORR.pdf&quot;&gt;at best 70% of all generated electricity&lt;/a&gt;, and crucially, &lt;a href=&quot;https://iea.blob.core.windows.net/assets/deebef5d-0c34-4539-9d0c-10b13d840027/NetZeroby2050-ARoadmapfortheGlobalEnergySector_CORR.pdf&quot;&gt;generation from fossil fuels will largely remain constant&lt;/a&gt;. So even though we will have more electricity, we will not have less emissions. Therefore, reducing global electricity consumption from ICT is critical.&lt;/p&gt;

&lt;h2 id=&quot;training-large-language-models&quot;&gt;Training Large Language Models&lt;/h2&gt;

&lt;p&gt;Although the large amount of CO₂ emissions resulting from AI training has received a lot of attention, I would argue that training of LLMs is not the main problem.&lt;/p&gt;

&lt;p&gt;According to a peer-reviewed paper by &lt;a href=&quot;https://arxiv.org/pdf/2104.10350.pdf&quot;&gt;Patterson et al.&lt;/a&gt;, training GPT-3 generates 552 ton of CO₂ (tCO₂e). (Using yearly average carbon intensity, it is 477 tCO₂e; the paper used the actual intensity during the period of training, and that was slightly higher).
This is not much compared to the &lt;a href=&quot;https://www.sciencedirect.com/science/article/pii/S2666389921001884&quot;&gt;total emissions from ICT&lt;/a&gt;, but it is still the same amount of CO₂ as produced by &lt;a href=&quot;https://heatable.co.uk/boiler-advice/average-carbon-footprint&quot;&gt;heating 250 average UK homes for one year&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, on the one hand, this is just a single model. On the other hand, one of the problems with those large language models is that they need to be kept up-to-date. People will expect the chat bot to know who this week’s Prime Minister is, or the current hit songs, games and movies. Which means that training will need to be an ongoing process. So the carbon footprint will become many times larger than it already is. For the sake of argument, let’s assume as a worst case that the model would need to be retrained fully every day. Then emissions from training would be 365 times larger, so about 175 ktCO₂e/y. If globally there would be a hundred such models from competing companies in different countries, that would mean an increase in global emissions of about 20 MtCO₂e/y.&lt;/p&gt;

&lt;p&gt;This assumes full retraining; it will likely become possible to split the training data into a large static pre-trained set which needs to be updated infrequently, and a dynamic set which needs to be updated weekly or even daily. It is also likely that computational efficiency gains will be found.&lt;/p&gt;

&lt;p&gt;In any case, even if this was not so, and even if updates were daily, emissions from electricity generation used for training would not exceed 2% of global ICT CO₂ budget — assuming that the number of such large models does not rise to thousands.&lt;/p&gt;

&lt;p&gt;What about the embodied carbon? &lt;a href=&quot;https://news.microsoft.com/source/features/ai/openai-azure-supercomputer/&quot;&gt;Microsoft claims&lt;/a&gt; that the supercomputer used to train GPT-3 hosts 10,000 GPUs and 285,000 CPU cores. Assuming these were similar to &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/virtual-machines/ndv2-series&quot;&gt;NDv2 instances&lt;/a&gt;, we can estimate their embodied carbon &lt;a href=&quot;https://www.boavizta.org/en/blog/empreinte-de-la-fabrication-d-un-serveur&quot;&gt;starting from work by Boavizta&lt;/a&gt; in the order of 2 tCO₂e per node, for 1250 nodes (8 GPUs per node). This is based on the assumptions that each node has a 3TB SSD, 512GB RAM and 2 Xeon CPUs, plus 8 V100 GPUs with each 32GB RAM.&lt;/p&gt;

&lt;p&gt;So the total embodied carbon is of the order 2.5 ktCO₂ per machine. However, it takes 14 days to train GPT-3. So to manage daily retraining, 14 such machines are needed. Assuming 4 years useful life, that would result  in embodied carbon of the order of 35 ktCO₂e/y. So the embodied carbon is of the order of 20% of the total emissions, and we can put the total between 10 and 100 MtCO₂e/y to account for uncertainties in the estimates.&lt;/p&gt;

&lt;p&gt;This means that the increased consumption from training of LLMs could with the highest estimate amount to 20% of the global ICT CO₂ budget. Nevertheless, as the cost of this amount of energy for training would probably be prohibitive, and there are clearly technical options to reduce the energy consumption, I don’t think it is likely that training of LLMs will lead to more than a few percent increase in ICT CO₂ emissions. So far, so good.&lt;/p&gt;

&lt;h2 id=&quot;using-large-language-models&quot;&gt;Using Large Language Models&lt;/h2&gt;

&lt;p&gt;Next, let’s consider the use of LLMs. An estimate for the footprint of ChatGPT is given by  &lt;a href=&quot;https://medium.com/@chrispointon/the-carbon-footprint-of-chatgpt-e1bc14e4cc2a&quot;&gt;Chris Pointon&lt;/a&gt; as 77,160 kWh per day assuming 13 million users per day with 5 questions each, so 65 million queries. This would generate
30 tCO₂e per day or 0.5 gCO₂e per query.&lt;/p&gt;

&lt;p&gt;Just to be clear, in the big picture (&lt;a href=&quot;https://www.sciencedirect.com/science/article/pii/S2666389921001884&quot;&gt;total global ICT emissions of 2 GtCO₂e&lt;/a&gt;) this kind of footprint is still very small. But with a billions of queries per day, that means tens of MtCO₂e/y.&lt;/p&gt;

&lt;p&gt;If that sounds improbable, consider this:  currently, Bing and Google each process 10 billion queries per day. So already, we would be looking at an electricity consumption of 8.7 TWh/y or emissions of 4 MtCO₂e/y purely from Bing and Google searches alone, without any growth or any other applications.&lt;/p&gt;

&lt;p&gt;If there would be 100 such models as assumed above, that would mean 435 TWh/y or 200 MtCO₂e/y, even without taking into account the embodied carbon; recall that ICT has a proportional carbon budget of 500 MtCO₂e/y by 2040, so that would be 40% of that budget; and this is a budget that can’t be exceeded without letting global warming get out of control.&lt;/p&gt;

&lt;p&gt;There is probably no room for a hundred major search engines, but there are many other use cases for ChatGPT and other LLMs, e.g. dynamic content generation for SEO spamming, better email spam etc and there are of course also the image-based generative models. So the coexistence of just a hundred large applications of LLMs in the whole world is entirely plausible.&lt;/p&gt;

&lt;p&gt;From this it is clear that large-scale adoption of LLMs would lead to unsustainable increases in ICT CO₂ emissions.&lt;/p&gt;

&lt;h2 id=&quot;reducing-the-climate-cost&quot;&gt;Reducing the climate cost&lt;/h2&gt;

&lt;p&gt;Assuming that ChatGPT-style LLMs make it through the &lt;a href=&quot;https://www.gartner.com/en/research/methodologies/gartner-hype-cycle&quot;&gt;Gartner hype cycle&lt;/a&gt; and are here to stay, then their energy consumption will become a major concern. In the big picture, the best way to address this would of course be not to use this highly polluting technology. After all, there is no burning need for LLMs, it is currently very much a case of a solution looking for a problem.&lt;/p&gt;

&lt;p&gt;Second best would be to put a carbon tax on electricity usage. That might seem like a good way to curb electricity use in general. However, companies would likely resort to on-site generation. Considering the scale of the required electricity generation, it is more precise to say “private generation” than “on-site” or “local”:
435 TWh/y is 15% of the global ICT electricity consumption. This can’t simply be generated by putting a few solar panels on the roofs of the data centres. It would require a 500 MW wind farm per application. For example, the &lt;a href=&quot;https://en.wikipedia.org/wiki/Whitelee_Wind_Farm&quot;&gt;Whitelee wind farm&lt;/a&gt; near Glasgow, the largest on-shore wind farm in the UK, has a maximum generative capacity of 539 MW and covers an area of 55 km² (about the size of Manhattan). Solar power in hot countries has a higher energy density, but is still of the same order: e.g. the &lt;a href=&quot;https://www.theecoexperts.co.uk/solar-panels/biggest-solar-farms&quot;&gt;Bhadla Solar Park&lt;/a&gt; in India, one of the largest solar farms in the world, has 2.7 GW capacity and covers 160 km², so 500MW would require 30 km².&lt;/p&gt;

&lt;p&gt;So to provide “on-site” generation for an LLM application such as ChatGPT-enabled search, a company would have to buy a similar area of land for its private wind or solar farm, thereby reducing the area available for replacing generation from fossil fuels.&lt;/p&gt;

&lt;p&gt;There is however a lot of scope for energy savings. To start with, for many applications there is no need for a model of the size of GPT-3. Something 10x smaller will do the job just fine, at a fraction of the cost. For example, many of Google’s current models are of that size. Of course, if there are many, then combined they will have similar footprints.&lt;/p&gt;

&lt;p&gt;Then there are potential efficiency savings, e.g. through use of energy-efficient hardware accelerators such as FPGAs, Google’s TPU chips or Cerebras’ Wafer-Scale Engine. All of these have in principle the potential to be an order of magnitude more efficient for both the training tasks and queries.&lt;/p&gt;

&lt;p&gt;In fact, for many tasks an LLM or other large-scale model is at best total overkill, and at worst unsuitable, and a conventional Machine Learning or Information Retrieval technique will be orders of magnitude more energy efficient and cost effective to run. Especially in the context of chat-based search, the energy consumption could be reduced significantly through generalised forms of caching, replacement of the LLM with a rule-based engines for much-posed queries, or of course simply defaulting to non-AI search.&lt;/p&gt;

&lt;p&gt;However, improved resource usage efficiency also lowers the relative cost of using a resource, which leads to increased demand [1]. This is known as &lt;a href=&quot;https://www.oecd-forum.org/posts/the-jevons-paradox-and-rebound-effect-are-we-implementing-the-right-energy-and-climate-change-policies&quot;&gt;Jevons paradox&lt;/a&gt; or the “rebound effect”. Jevons described in 1865 how energy efficiency improvements increased  consumption of coal. What this means is that the way to reduce the climate cost of the AI revolution can’t be purely technological. As with any activity that consumes energy, the best way to limit energy consumption is to limit the activity.&lt;/p&gt;

&lt;p&gt;As a society we need to treat AI resources as finite and precious, to be utilised only when necessary, and as effectively as possible. We need &lt;em&gt;frugal AI&lt;/em&gt;.&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>Immutable data structures and reduction in Raku</title>
        <link href="https://limited.systems/articles/immutable-datastructures-reduction/"/>
        <updated>2022-11-20T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/immutable-datastructures-reduction</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/immutable-datastructures-reduction_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;For &lt;a href=&quot;https://wimvanderbauwhede.github.io/articles/uxntal-to-C/&quot;&gt;a little compiler&lt;/a&gt; I’ve been writing, I felt increasingly the need for immutable data structures to ensure that nothing was passed by references between passes. I love Perl and Raku but I am a functional programmer at heart, so I prefer map and reduce over loops. It bothered me to run reductions on a mutable data structure. So I made &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/src/branch/main/lib/ImmutableDatastructureHelpers.rakumod&quot;&gt;a small library&lt;/a&gt; to make it easier to work with immutable maps and lists.&lt;/p&gt;

&lt;p&gt;A reduction combines all elements of a list into a result. A typical example is the sum of all elements in a list. According to the Raku docs, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reduce()&lt;/code&gt; has the following signature&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;multi sub reduce (&amp;amp;with, +list)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In general, if we have a list of elements of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T1&lt;/code&gt; and a result of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T2&lt;/code&gt;, Raku’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reduce()&lt;/code&gt; function takes as first argument a function of the form&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;-&amp;gt; T2 \acc, T1 \elt --&amp;gt; T2 { ... }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I use the form of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reduce&lt;/code&gt; that takes three arguments: the reducing function, the accumulator (what the Raku docs call the initial value) and the list.  As explained in the docs, Raku’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reduce&lt;/code&gt; operates from left to right. (In Haskell speak, it is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldl :: (b -&amp;gt; a -&amp;gt; b) -&amp;gt; b -&amp;gt; [a]&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;The use case is the traversal of a role-based datastructure &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ParsedProgram&lt;/code&gt; which contains a map and an ordered list of keys. The map itself contains elements of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ParsedCodeBlock&lt;/code&gt; which is essentially a list of tokens.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;role ParsedProgram {
    has Map $.blocks = Map.new; # {String =&amp;gt; ParsedCodeBlock}
    has List $.blocks-sequence = List.new; # [String]
	...
}

role ParsedCodeBlock {
    has List $.code = List.new; # [Token]
	...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;List and Map are immutable, so we have immutable datastructures. What I want do do is update these datastructures using a nested reduction where I iterate over all the keys in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blocks-sequence&lt;/code&gt; List and then modify the corresponding ParsedCodeBlock. For that purpose, I wrote a small API, and in the code below, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;append&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;insert&lt;/code&gt; are part of that API. What they do is create a fresh List resp. Map rather than updating in place.&lt;/p&gt;

&lt;p&gt;I prefer to use sigil-less variables for immutable data, so that sigils in my code show where I have use mutable variables.&lt;/p&gt;

&lt;p&gt;The code below is an example of a typical traversal. We iterate over a list of code blocks in a program, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parsed_program.blocks-sequence&lt;/code&gt;; on every iteration, we update the program &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parsed_program&lt;/code&gt; (the accumulator).
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reduce()&lt;/code&gt; call takes a lambda function with the accumulator  (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ppr_&lt;/code&gt;) and a list element (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code_block_label&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;We get the code blocks from the program’s map of blocks, and use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reduce()&lt;/code&gt; again to update the tokens in the code block. So we iterate over the original list of tokens (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parsed_block.code&lt;/code&gt;) and build a new list. The lambda function therefore has as accumulator the updated list (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mod_block_code_&lt;/code&gt;) and as element a token (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;token_&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The inner reduce creates a modified token and puts it in the updated list using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;append&lt;/code&gt;. Then the outer reduce updates the block code using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clone&lt;/code&gt; and updates the map of code blocks in the program using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;insert&lt;/code&gt;, which updates the entry if it was present. Finally, we update the program using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clone&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;reduce(
    -&amp;gt; ParsedProgram \ppr_, String \code_block_label {
        my ParsedCodeBlock \parsed_block =
            ppr_.blocks{code_block_label};

        my List \mod_block_code = reduce(
            -&amp;gt; \mod_block_code_,\token_ {
                my Token \mod_token_ = ...;
                append(mode_block_code_,mod_token_);
            },
            List.new,
            |parsed_block.code
        );
        my ParsedCodeBlock \mod_block_ =
            parsed_block.clone(code=&amp;gt;mode_block_code);
        my Map \blocks_ = insert(
            ppr_glob.blocks,code_block_label,mod_block_);
        ppr_.clone(blocks=&amp;gt;blocks_);
    },
    parsed_program,
    |parsed_program.blocks-sequence
);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The entire library is only a handful of functions. The naming of the functions is based on Haskell’s, except where Raku already claimed a name as a keyword.&lt;/p&gt;

&lt;h2 id=&quot;map-manipulation&quot;&gt;Map manipulation&lt;/h2&gt;

&lt;p&gt;Insert, update and remove entries in a Map. Given an existing key, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;insert&lt;/code&gt; will update the entry.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;sub insert(Map \m_, Str \k_, \v_ --&amp;gt; Map )
sub update(Map \m_, Str \k_, \v_ --&amp;gt; Map )
sub remove(Map \m_, Str \k_ --&amp;gt; Map )
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;list-manipulation&quot;&gt;List manipulation&lt;/h2&gt;

&lt;p&gt;There are more list manipulation functions because reductions operate on lists.&lt;/p&gt;

&lt;h3 id=&quot;addremove-an-element-at-the-front&quot;&gt;Add/remove an element at the front:&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;# push
sub append(List \l_, \e_ --&amp;gt; List)
# unshift
sub prepend(List \l_, \e_ --&amp;gt; List)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;split-a-list-into-its-first-element-and-the-rest&quot;&gt;Split a list into its first element and the rest:&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;# return the first element, like shift
sub head(List \l_ --&amp;gt; Any)
# drops the first element
sub tail(List \l_ --&amp;gt; List)

# This is like head:tail in Haskell
sub headTail(List \l_ --&amp;gt; List) # List is a tuple (head, tail)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The typical use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;headTail&lt;/code&gt; is something like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;my (Str \leaf, List \leaves_) = headTail(leaves);
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;similar-operations-but-for-the-last-element&quot;&gt;Similar operations but for the last element:&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;# drop the last element
sub init(List \l_ --&amp;gt; List)
# return the last element, like pop.
sub top(List \l_ --&amp;gt; Any) ,
# Split the list on the last element
sub initLast(List \l_ --&amp;gt; List) # List is a tuple (init, top)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The typical use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;initLast&lt;/code&gt; is something like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;my (List \leaves_, Str \leaf) = initLast(leaves);
&lt;/code&gt;&lt;/pre&gt;


        </content>
    </entry>
    
    <entry>
        <title>Compiling stack-based assembly to C</title>
        <link href="https://limited.systems/articles/uxntal-to-C/"/>
        <updated>2022-10-15T00:00:00+01:00</updated>
        <id>https://limited.systems/articles/uxntal-to-C</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/uxntal-to-C_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;I wrote a proof-of-concept compiler from &lt;a href=&quot;https://wiki.xxiivv.com/site/uxntal.html&quot;&gt;Uxntal&lt;/a&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt;. The generated code is linked with a slightly modified version of the &lt;a href=&quot;https://git.sr.ht/~rabbits/uxn&quot;&gt;Uxn VM/Varvara code&lt;/a&gt; to provide stand-alone applications.&lt;/p&gt;

&lt;h2 id=&quot;uxntal-and-uxn&quot;&gt;Uxntal and Uxn&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://wiki.xxiivv.com/site/uxntal.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Uxntal&lt;/code&gt;&lt;/a&gt; is the programming language for the &lt;a href=&quot;https://wiki.xxiivv.com/site/uxn.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Uxn&lt;/code&gt;&lt;/a&gt; virtual machine which forms the heart of the &lt;a href=&quot;https://wiki.xxiivv.com/site/varvara.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Varvara&lt;/code&gt;&lt;/a&gt; clean-slate computing stack. As Uxn is a stack machine, Uxntal is a stack language, similar to e.g. &lt;a href=&quot;https://forth-standard.org/&quot;&gt;Forth&lt;/a&gt; or &lt;a href=&quot;https://dev.to/palm86/church-encoding-in-the-concatenative-language-joy-3nd8&quot;&gt;Joy&lt;/a&gt; in that it uses reverse Polish notation (postfix). It is an assembly language with opcodes for 8-bit and 16-bit operations on the stack and memory. To get the most out of this article, it is best if you have basic knowledge of Uxntal, either from the above resources or for example &lt;a href=&quot;https://compudanzas.net/uxn_tutorial.html&quot;&gt;the great tutorial at Compudanzas&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;an-uxntal-to-c-compiler&quot;&gt;An Uxntal-to-C compiler&lt;/h2&gt;

&lt;p&gt;What I call an Uxntal-to-C compiler is a program that converts an Uxntal program into a C program that, when compiled with a C compiler and executed, has the same functionality as the Uxntal program has when assembled and run on the Uxn emulator.&lt;/p&gt;

&lt;p&gt;Why compile Uxntal to C? Mainly for fun, and out of curiosity. I was curious about the challenges involved and the limitations. Compiling Uxntal programs does result in speed-ups for compute-intensive applications. However, the fact that Uxn is computationally not very efficient is to my mind a bit of a red herring. As the main purpose of Uxn is to create interactive applications, the behaviour of these is dominated by the I/O activity, including the display and audio which are managed by SDL. The effect of the Uxntal code being compiled or interpreted will therefore be small for typical Uxn target, because either the program run time will be dominated by I/O waits or the computations will take place in the SDL layer. And that was another reason behind this experiment: it provides evidence. I verified my assumptions on a number of examples (see below), and the total power saving of the compiled version is negligible.&lt;/p&gt;

&lt;p&gt;I initially considered &lt;a href=&quot;https://llvm.org&quot;&gt;LLVM&lt;/a&gt; and &lt;a href=&quot;https://webassembly.github.io&quot;&gt;WASM&lt;/a&gt; as targets. WASM seems attractive at first because it is purportedly stack based, but it turns out that loops are not stack based, nor is function argument passing. Both WASM and LLVM are typed assembly languages and assume that code and data are in separate memory spaces and that code is read-only, so they offer no additional benefit as a compilation target for Uxntal over C.&lt;/p&gt;

&lt;h2 id=&quot;limitations&quot;&gt;Limitations&lt;/h2&gt;

&lt;p&gt;There are two aspects of Uxntal that can’t be supported in an ahead-of-time C compiler with static code analysis.&lt;/p&gt;

&lt;h3 id=&quot;jumps-to-computed-addresses&quot;&gt;Jumps to computed addresses&lt;/h3&gt;

&lt;p&gt;The first is jumps to computed addresses, because that is a concept that is not supported in C (nor in LLVM or WASM). A jump to a constant relative address can be resolved at compile time and supported, but run-time computed jumps have no equivalent. Fortunately, in practice Uxntal’s linter discourages this for jumps longer than one instruction, and the allowed case of a run-time computed binary value is supported.&lt;/p&gt;

&lt;h3 id=&quot;self-modifiable-code&quot;&gt;Self-modifiable code&lt;/h3&gt;

&lt;p&gt;The second is self-modifiable code. In C, LLVM and WASM, code and data are separated and a program can’t modify its on source. Fortunately, in practice the use of self-modification in Uxntal is limited to storing of local variables through code such as&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;LIT &amp;amp;x $1 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and evaluation of instructions from the stack using code such as&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;LIT MUL
... 
#00 STR $1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Run-time evaluation through self-modification of the instructions is only supported for a specific case:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#06 #07 LIT ADD 
...
#00 STR BRK 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In principle, any store of a byte in the code memory results in self-modification, but the above is the most common pattern used to evaluate a byte on the stack as an instruction.&lt;/p&gt;

&lt;p&gt;Also fundamentally, the compiler expects human-readable Uxntal code, in particular it relies on the mnemonics to identify instructions. So while this is valid Uxntal code, it will not work:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;80 06 80 07 1a
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is in general impossible for a compiler to distinguish between opcodes and data because of Uxntal’s dynamic nature. In fact, a value can be used as both depending on a run-time condition. So the compiler needs the meta-information provided by the mnemonic notation.&lt;/p&gt;

&lt;h2 id=&quot;design&quot;&gt;Design&lt;/h2&gt;

&lt;p&gt;The overall approach is to use the runtime data structures used in the Uxn emulator, i.e. arrays that represent the ram, stacks and devices. Rather than reading bytes from the rom file and evaluating them using a case statement, we generate C code with subroutines corresponding to the instructions. The control flow is purely based on subroutine calls.&lt;/p&gt;

&lt;p&gt;The design is quite simple. There is a Token sum type for all token variants and some record types for code blocks and the full program. All of these are in &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/lib/UxntalTypes.rakumod&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UxntalTypes&lt;/code&gt;&lt;/a&gt;. Definitions of the Uxntal operations are in &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/lib/UxntalDefs.rakumod&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UxntalDefs&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Because of Uxntal’s very regular structure, the &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/lib/UxntalTokeniser.rakumod&quot;&gt;tokeniser&lt;/a&gt; is trivial (split on whitespace and newlines); the &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/lib/UxntalParser.rakumod&quot;&gt;parser&lt;/a&gt; is using regular expressions and is also straightforward. Because Uxntal programs are simply sequences of instructions, labels and data of one or two bytes, the parser does need only limited context. We parse the code into a data type that reflects the different types of tokens as described on the &lt;a href=&quot;https://wiki.xxiivv.com/site/uxntal.html&quot;&gt;Uxntal page of the XXIIVV wiki&lt;/a&gt;:&lt;/p&gt;

&lt;table border=&quot;1&quot;&gt;
	&lt;tr&gt;&lt;th colspan=&quot;4&quot;&gt;Padding&lt;/th&gt;&lt;th colspan=&quot;4&quot;&gt;Literals&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;code&gt;|&lt;/code&gt;&lt;/td&gt;&lt;td&gt;absolute&lt;/td&gt;&lt;td&gt;&lt;code&gt;$&lt;/code&gt;&lt;/td&gt;&lt;td&gt;relative&lt;/td&gt;&lt;td&gt;&lt;code&gt;#&lt;/code&gt;&lt;/td&gt;&lt;td colspan=&quot;3&quot;&gt;literal hex&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;th colspan=&quot;4&quot;&gt;Labels&lt;/th&gt;&lt;th colspan=&quot;4&quot;&gt;Ascii&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;code&gt;@&lt;/code&gt;&lt;/td&gt;&lt;td&gt;parent&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;child&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;raw word&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;#39;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;raw char&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;th colspan=&quot;4&quot;&gt;Addressing&lt;/th&gt;&lt;th colspan=&quot;4&quot;&gt;Pre-processor&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;code&gt;,&lt;/code&gt;&lt;/td&gt;&lt;td&gt;literal relative&lt;/td&gt;&lt;td&gt;.&lt;/td&gt;&lt;td&gt;literal zero-page&lt;/td&gt;&lt;td&gt;&lt;code&gt;%&lt;/code&gt;&lt;/td&gt;&lt;td&gt;macro-define&lt;/td&gt;&lt;td&gt;&lt;code&gt;~&lt;/code&gt;&lt;/td&gt;&lt;td&gt;include&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;code&gt;:&lt;/code&gt;&lt;/td&gt;&lt;td&gt;raw absolute&lt;/td&gt;&lt;td&gt;&lt;code&gt;;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;literal absolute&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Then we perform two transformation passes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Replace all relative addressing by absolute addressing.&lt;/p&gt;

    &lt;p&gt;So after this step, only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;;&lt;/code&gt; remain.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Split the code into blocks and identify them as subroutines or data.&lt;/p&gt;

    &lt;p&gt;This is only slightly more complex because we need to add an explicit jump to the next block for blocks that do not end in a jump. Blocks that do not contain operations are considered data, all other blocks are subroutines.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This transformation allows us to create equivalent C subroutines an  store the data in RAM. There are a few special cases, see the &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/lib/UxntalParser.rakumod&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UxntalParser&lt;/code&gt;&lt;/a&gt; code for details.&lt;/p&gt;

&lt;p&gt;After this step we &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/lib/UxntalAnalyser.rakumod&quot;&gt;analyse&lt;/a&gt; the code to determine which labels refer to subroutines and which to data.&lt;/p&gt;

&lt;p&gt;The main advantage of this approach is that it simplifies control flow handling: there is no need for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;goto&lt;/code&gt; statements or labels because Uxntal’s label-based loops have been turned into recursive subroutines. So all we need to do is generate the code for those subroutines and the code to call them.&lt;/p&gt;

&lt;p&gt;The actual &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/lib/UxntalStackBasedCEmitter.rakumod&quot;&gt;emitter&lt;/a&gt; is straightforward because it relies on &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/uxn-runtime-libs/&quot;&gt;a runtime library&lt;/a&gt; which contains a subroutine for every Uxntal instruction.&lt;/p&gt;

&lt;p&gt;In practice there are a few additional complications, specifically to handle the limited use of self-modification, and to handle conditional jumps. Also, the memory allocations and subroutine declarations need to be collected and grouped at the start of the source code, so there is quite a bit of state to be maintained.&lt;/p&gt;

&lt;p&gt;Each instruction subroutine takes the required arguments from the stack and pushes its result on the stack, if any. Consequently, all subroutines have a signature &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;void f(void)&lt;/code&gt;. This means all function pointers are of the same type. Because function pointers in C are machine size, we can’t put them directly on the Uxn stack. Instead, we store them in a separate array and put the index into that array on the stack.&lt;/p&gt;

&lt;p&gt;With this approach, we can handle most of the dynamic nature of Uxntal.&lt;/p&gt;

&lt;h2 id=&quot;optimisations&quot;&gt;Optimisations&lt;/h2&gt;

&lt;h3 id=&quot;inlining-operations&quot;&gt;Inlining operations&lt;/h3&gt;

&lt;p&gt;The generated C code at this stage has a very large number of subroutine calls, and disappointingly the C compiler (gcc) does not inline most of them. So we do this ourselves in a &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/lib/UxntalStackBasedCOpsEmitter.rakumod&quot;&gt;first optimisation pass&lt;/a&gt;. This is easy (if cumbersome) because the subroutines don’t take or return arguments and are guaranteed non-recursive, so we can simply replace the call with the definition.&lt;/p&gt;

&lt;h3 id=&quot;stack-to-register&quot;&gt;Stack to register&lt;/h3&gt;

&lt;p&gt;A &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/lib/UxntalStackBasedCOpsEmitter.rakumod&quot;&gt;second optimisation&lt;/a&gt; is more complicated but has also a much bigger effect on performance: we replace as much as possible stack operations with register operations. This is a little bit more complicated than at first sight appears. I might write a separate post about the algorithm.&lt;/p&gt;

&lt;h3 id=&quot;further-optimisations&quot;&gt;Further optimisations&lt;/h3&gt;

&lt;p&gt;There are a number of further optimisations that could be considered, but all of them are more complex and would not result in a dramatic additional performance improvement. Some of them I have implemented but they are not enabled:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/lib/UxntalInliner.rakumod&quot;&gt;Inline subroutines&lt;/a&gt;. This is only partially implemented. It is rather tricky because recursive subroutines can’t be inlined, so we need an analysis to detect recursion. For simple, in-routine recursion that is easy, but recursion can occur through a chain of tail calls, so we need to identify tail calls and follow those through.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;goto&lt;/code&gt; instead of function call. This is a simple optimisation which does not require a separate pass so it’s done directly in the &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/lib/UxntalStackBasedCEmitter.rakumod&quot;&gt;emitter&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both of these optimisations make little or no difference for most applications I tested so I don’t enable them. Some other optimisations I have not finished implementing:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Stack to register for subroutine calls. This is quite complicated, mostly because of recursion, but also because it is (in general) not possible to infer the type of a function called via a function pointers.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Stack to register for conditional blocks. This is the case where a condition is created through a computed jump, a typical example would be&lt;/p&gt;

    &lt;p&gt;… EQU JMP [ INC2 ] …&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EQU&lt;/code&gt; returns 0, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ADD2&lt;/code&gt; will be executed, else it will be jumped over. The instruction has to be idempotent, and I think most commonly this is used with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JMP2r&lt;/code&gt;. The effect on performance will generally be minimal.&lt;/p&gt;

&lt;h2 id=&quot;performance&quot;&gt;Performance&lt;/h2&gt;

&lt;h3 id=&quot;code-used-for-testing&quot;&gt;Code used for testing&lt;/h3&gt;

&lt;p&gt;I did some limited performance evaluation using five command-line programs: three versions of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fib*&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;primes&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stencil&lt;/code&gt;. With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-O=2&lt;/code&gt; (inlined ops and stack-to-reg), the compiled version is up to 12x faster than the original version. With the additional optimisations this might increase a bit, maybe to     15x, but not more.&lt;/p&gt;

&lt;p&gt;The three version of the Fibonacci calculation are a modified version of &lt;a href=&quot;https://git.sr.ht/~rabbits/uxn/tree/main/item/projects/examples/exercises/fib.tal&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uxn/projects/examples/exercises/fib.tal&lt;/code&gt;&lt;/a&gt; and the two versions used in &lt;a href=&quot;https://applied-langua.ge/posts/i-dont-want-to-go-to-chel-c.html&quot;&gt;an article&lt;/a&gt; that criticised Uxn for being inefficient.&lt;/p&gt;

&lt;p&gt;The original &lt;a href=&quot;https://git.sr.ht/~rabbits/uxn/tree/main/item/projects/examples/exercises/fib.tal&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fib.tal&lt;/code&gt;&lt;/a&gt; is very terse (ignoring the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;print&lt;/code&gt; function):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|0100 ( -&amp;gt; ) @reset

    #0000 INC2k ADD2k
    &amp;amp;loop
        ( print ) DUP2 ,print JSR
        ( linebreak ) #0a18 DEO
        ADD2k LTH2k ,&amp;amp;loop JCN
    ( halt ) #010f DEO

BRK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/src/branch/main/demos/fib.tal&quot;&gt;modified it&lt;/a&gt; by writing a loop around it to repeat the calculations 2^16 times:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#ffff #0000 &amp;amp;iterate
...
INC2 GTH2k ,&amp;amp;iterate JCN
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What I call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fib2.tal&lt;/code&gt; is taken from the article:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|0100

#0020 ;fib JSR2
#01 #0f DEO BRK

@fib ( N -- fib[N] )
    DUP2 #0001 GTH2 ,&amp;amp;inductive-case; JCN JMP2r
    &amp;amp;inductive-case;
    DUP2 #0001 SUB2 ;fib JSR2 ( stack now N fib[N-1] )
    SWP2 #0002 SUB2 ;fib JSR2 ( stack now fib[N-1] fib[N-2] )
    ADD2 JMP2r
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fib32.tal&lt;/code&gt; is a 32-bit version of this code, also from that article:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|0100

#0020 ;fib JSR2
#01 #0f DEO BRK

@fib ( N -- fib[N] )
( not[n &amp;lt; 2] equivalent to n &amp;gt; 1 )
    DUP2 #0001 GTH2 ,&amp;amp;inductive-case; JCN #0000 SWP JMP2r
    &amp;amp;inductive-case;
    DUP2 #0001 SUB2 ;fib JSR2 ( stack now N fib[N-1] )
    ROT2 #0002 SUB2 ;fib JSR2 ( stack now fib[N-1] fib[N-2] )
    ;add32 JSR2 JMP2r
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This uses the &lt;a href=&quot;http://plastic-idolatry.com/erik/nxu/math32.tal&quot;&gt;32-bit math library&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I also tested &lt;a href=&quot;https://git.sr.ht/~rabbits/uxn/tree/main/item/projects/examples/exercises/primes.tal&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uxn/projects/examples/exercises/primes.tal&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|0100 ( -&amp;gt; ) @reset

    #0000 INC2k
    &amp;amp;loop
        DUP2 ,is-prime JSR #00 EQU ,&amp;amp;skip JCN
            DUP2 DUP2 ;mem STA2
            ,print/short JSR
            ( space ) #2018 DEO
            &amp;amp;skip
        INC2 NEQ2k ,&amp;amp;loop JCN
    POP2 POP2
    ;mem LDA2 ,print/short JSR
    ( halt ) #010f DEO

BRK

@is-prime	
    DUP2
    #0001 EQU2 ,&amp;amp;fail JCN
    STH2k
    #01 SFT2 #0002
    &amp;amp;loop
        STH2kr OVR2 ( mod2 ) [ DIV2k MUL2 SUB2 ] ORA ,&amp;amp;continue JCN
            POP2 POP2 POP2r #00 JMP2r
            &amp;amp;continue
        INC2  GTH2k ,&amp;amp;loop JCN
    POP2 POP2 POP2r #01
JMP2r
    &amp;amp;fail POP2 #00 JMP2r
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, I wrote &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito/src/branch/main/demos/stencil.tal&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stencil.tal&lt;/code&gt;&lt;/a&gt;, which is a 3-D 6-point stencil code, so the value of each point in a 3-D space is calculated based on the values of its six neighbours (i+1,i-1),(j+1,j-1),(k+1,k-1). This is a very common pattern in scientific computing and a good number crunching test. The code is a bit long to list here. It is a quadruple-nested loop: a time loop containing loops over the x, y and z directions of the 3-D space. At each point, the calculation is simply the weighted average of the current value and the sum of the six neighbours:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.idx LDZ2 #0001 ADD2 LDA2 ( p(x-1,y,z) )
.idx LDZ2 #0001 SUB2 LDA2 ( p(x+1,y,z) )
ADD2
.idx LDZ2 #0010 ADD2 LDA2 ( p(x,y-1,z) )
.idx LDZ2 #0010 SUB2 LDA2 ( p(x,y+1,z) )
ADD2
ADD2
.idx LDZ2 #0100 ADD2 LDA2 ( p(x,y,z-1) )
.idx LDZ2 #0100 SUB2 LDA2 ( p(x,y,z+1) )
ADD2 
ADD2
#0003 MUL2 

.idx LDZ2 LDA2 ( p(x,y,z) ) 
ADD2
#0004 DIV2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The time loop repeats this calculation 2^16 times.&lt;/p&gt;

&lt;h3 id=&quot;performance-results&quot;&gt;Performance results&lt;/h3&gt;

&lt;p&gt;I compiled these example with as optimisations inlining of operations and stack-to-register transformation. I used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time&lt;/code&gt; to obtain the timings.&lt;/p&gt;

&lt;table&gt;
	&lt;tr&gt;&lt;th&gt;Code&lt;/th&gt;&lt;th&gt;Emulated (s)&lt;/th&gt;&lt;th&gt;Compiled (s)&lt;/th&gt;&lt;th&gt;Speed-up&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;code&gt;fib.tal&lt;/code&gt;&lt;/td&gt;&lt;td&gt;1.57&lt;/td&gt;&lt;td&gt;0.96&lt;/td&gt;&lt;td&gt;1.6x&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;code&gt;fib2.tal&lt;/code&gt;&lt;/td&gt;&lt;td&gt;0.471&lt;/td&gt;&lt;td&gt;0.047&lt;/td&gt;&lt;td&gt;10x&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;code&gt;fib32.tal&lt;/code&gt;&lt;/td&gt;&lt;td&gt;1.86&lt;/td&gt;&lt;td&gt;0.151&lt;/td&gt;&lt;td&gt;12.3x&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;code&gt;primes.tal&lt;/code&gt;&lt;/td&gt;&lt;td&gt;6.9&lt;/td&gt;&lt;td&gt;0.93&lt;/td&gt;&lt;td&gt;7.4x&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;code&gt;stencil.tal&lt;/code&gt;&lt;/td&gt;&lt;td&gt;96.9&lt;/td&gt;&lt;td&gt;7.8&lt;/td&gt;&lt;td&gt;12.4x&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;For the examples with low speed-ups, the reason is that a lot of the time spend is I/O activity, which takes the same amount of time for the emulated and compiled versions:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ time uxncli fib.rom &amp;gt;/dev/null
real	0m1.568s
user	0m0.924s
sys	0m0.644s

$ time uxncliprog &amp;gt;/dev/null
real	0m0.964s
user	0m0.384s
sys	0m0.580s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Even if we print to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/null&lt;/code&gt;, that still takes considerable I/O time.&lt;/p&gt;

&lt;p&gt;For the tests without I/O (fib2, fib32, stencil), the speed-up is between 10x and 12.4x. I think with the additional optimisations, it might increase to maybe 15x but not more than that.&lt;/p&gt;

&lt;h2 id=&quot;power-consumption&quot;&gt;Power consumption&lt;/h2&gt;

&lt;p&gt;Finally, I had a look at the power consumption of a typical GUI-based Uxn app. I used powertop with the &lt;a href=&quot;https://git.sr.ht/~rabbits/uxn/tree/main/item/projects/examples/demos/bunnymark.tal&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bunnymark&lt;/code&gt;&lt;/a&gt; benchmark, running 10,000 rabbits. I used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;htop&lt;/code&gt; for the CPU utilsation.&lt;/p&gt;

&lt;p&gt;My laptop is nearly three years old, it is a &lt;a href=&quot;https://www.pcspecialist.co.uk&quot;&gt;PCSpecialist&lt;/a&gt; Fusion IV, which is really a &lt;a href=&quot;http://www.hk.tongfangpc.com/&quot;&gt;TongFang&lt;/a&gt; PF4MN2F. The CPU is an Intel Core i7-10510U 1.80GHz and it has 16GB DDR4 memory.&lt;/p&gt;

&lt;h3 id=&quot;baseline&quot;&gt;Baseline&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;System baseline power is estimated at 766 mW

Power est.    Usage     Device name
564 mW      3.1%        DRAM
157 mW      3.1%        CPU core
44.9 mW      3.1%        CPU misc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;emulated&quot;&gt;Emulated&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;15% CPU

System baseline power is estimated at 7.98 W

Power est.    Usage     Device name
5.03 W     57.7%        CPU core
1.43 W     57.7%        CPU misc
1.02 W     57.7%        DRAM
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;compiled&quot;&gt;Compiled&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;9% CPU

System baseline power is estimated at 8.17 W

Power est.    Usage     Device name
5.09 W     55.4%        CPU core
1.59 W     55.4%        CPU misc
978 mW     55.4%        DRAM    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What we see is that most of the power is drawn by the CPU and that there is effectively no difference between the emulated and compiled versions. I measured this a few times and the error margin is about 0.5 W so within that margin the results are identical. I also measured the power consumption for emulated and compiled versions of other applications in the &lt;a href=&quot;https://git.sr.ht/~rabbits/uxn/tree/main/item/projects/examples/demos&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;demos&lt;/code&gt;&lt;/a&gt; folder. They all consume considerably less power than bunnymark but there was no significant difference between emulated and compiled versions.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The main takeaway of this experiment of compiling Uxntal to C is that it provides evidence that there is no need to do this for most Uxn applications: it will have no significant effect on performance or power consumption.&lt;/p&gt;

&lt;p&gt;On the other hand, if you have to or want to you now can compile Uxntal to C and it can give speed-ups of the order of 10x for compute-heavy applications.&lt;/p&gt;

&lt;h2 id=&quot;code&quot;&gt;Code&lt;/h2&gt;

&lt;p&gt;The compiler code and demos can be found &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/nito&quot;&gt;in my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nito&lt;/code&gt; repo on Codeberg&lt;/a&gt;. The README has the instructions and a list of the code on which I tested the compiler.&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;The banner picture shows a row of bronze prayer wheels in a temple in Kyoto at night.&lt;/em&gt;&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>Functional programming in stack-based assembly</title>
        <link href="https://limited.systems/articles/uxntal-quoting/"/>
        <updated>2022-10-09T00:00:00+01:00</updated>
        <id>https://limited.systems/articles/uxntal-quoting</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/uxntal-quoting_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;h2 id=&quot;quoting-in-uxntal-lambda-functions-tuples-and-lists-for-free&quot;&gt;Quoting in Uxntal: lambda functions, tuples and lists for free&lt;/h2&gt;

&lt;p&gt;What does it take to bring functional programming to a stack-based assembly language? &lt;em&gt;tl;dr&lt;/em&gt;: not all that much. Uxntal has everything it takes to build a basic mechanism (“quoting”) that lets us create lambda functions, tuples, cons lists and more.&lt;/p&gt;

&lt;h2 id=&quot;uxntal-and-uxn&quot;&gt;Uxntal and Uxn&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://wiki.xxiivv.com/site/uxntal.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Uxntal&lt;/code&gt;&lt;/a&gt; is the programming language for the &lt;a href=&quot;https://wiki.xxiivv.com/site/uxn.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Uxn&lt;/code&gt;&lt;/a&gt; virtual machine. As Uxn is a stack machine, Uxntal is a stack language, similar to e.g. &lt;a href=&quot;https://forth-standard.org/&quot;&gt;Forth&lt;/a&gt; or &lt;a href=&quot;https://dev.to/palm86/church-encoding-in-the-concatenative-language-joy-3nd8&quot;&gt;Joy&lt;/a&gt; in that it uses reverse Polish notation (postfix). It is an assembly language with opcodes for 8-bit and 16-bit operations on the stack and memory. To get the most out of this article, it is best if you have basic knowledge of Uxntal, either from the above resources or for example &lt;a href=&quot;https://compudanzas.net/uxn_tutorial.html&quot;&gt;the great tutorial at Compudanzas&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Concepts such as lambda functions, quoting, partial application and closures are common in functional programming languages, but if you are not familiar with these you should still be able to follow most of the explanation. My article &lt;a href=&quot;https://limited.systems/articles/decluttering-with-functional-programming/&quot;&gt;“Cleaner code with functional programming”&lt;/a&gt;, explains the basics of functional programming.&lt;/p&gt;

&lt;p&gt;Although Uxn is a stack machine and Uxntal a stack language, it is quite easy to do register based programming by using labels as variables: the purely stack based&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|0100
#06 #07 MUL
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;can be written as&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|0000
@r1 $1 @r2 $1 @r3 $1
|0100
#06 .r1 STZ
#07 .r2 STZ
.r1 LDZ .r2 LDZ MUL .r3 STZ
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;where we store the values in memory and load them when needed. My implementation of lambda functions makes use of this approach.&lt;/p&gt;

&lt;p&gt;Uxntal also has a simple but powerful macro mechanism which just creates short names for groups of tokens. I make heavy use of macros in what follows.&lt;/p&gt;

&lt;p&gt;Because of the conciseness of its syntax, I use the venerable functional language &lt;a href=&quot;https://haskell.org/&quot;&gt;Haskell&lt;/a&gt; for some of the examples below. A short primer on Haskell is my article &lt;a href=&quot;https://limited.systems/articles/everything-is-a-function/&quot;&gt;“Everything is a function”&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;anonymous-functions&quot;&gt;Anonymous functions&lt;/h2&gt;

&lt;p&gt;Uxntal supports variables and named function calls through labels. And as the program is stored in writeable memory, it can be overwritten or modified in place.&lt;/p&gt;

&lt;p&gt;I wanted to see if I could implement or emulate the behaviour of anonymous functions (called “lambda functions” in functional programming). For example, I’d like to be able to write something similar to the following Haskell code:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;or equivalent in Python:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;which would square all elements in the list &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lst&lt;/code&gt;. And I would like to be able to use lambda functions as arguments and as return values:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I also want to be able to combine lambdas and named functions:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sq&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The reason I want to do this is mostly curiosity, but there are some practical advantages because the lambda functions can be generated dynamically based on runtime values. Also, the “quoting” mechanism used to build lambdas is more general and allows for “lazy” or delayed evaluation.&lt;/p&gt;

&lt;p&gt;From the above examples, the clear feature of a lambda function is that it identifies by name the variables used as its arguments. I want to reflect this closely in Uxntal. The other key feature is that the lambda functions are values, and we need to apply them to an argument to get a computation. That is very similar to calling a function in Uxntal. Suppose we have&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|0100
#0003 #0004 ;f JSR2
BRK
@f
    .x STZ2
    .y STZ2
    .x LDZ2 .x LDZ2 MUL2 .y LDZ2 .y LDZ2 MUL2 ADD2
    .x LDZ2 .y LDZ2 MUL2 #0002 MUL2 ADD2
    JMP2r
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using some macros I have defined for convenience, I can write this as&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|0100
3 4 ;f call
BRK
@f
    -&amp;gt;x
    -&amp;gt;y
    x x * y y * +
    x y * 2 * +
    return
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With a lambda notation, this would become&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|0100
3 4  [&apos; \x. \y.
        x&apos; x&apos; *&apos; y&apos; y&apos; *&apos; +&apos;
        x&apos; y&apos; *&apos; 2&apos; *&apos; +&apos;
    ]&apos; apply
BRK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The nested example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(\x -&amp;gt; (\y -&amp;gt; x+y)) 2 3&lt;/code&gt; would be with named functions:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|0100
3 2 ;f call
BRK
@f
    -&amp;gt;x
    ;g call
    return
@g
    -&amp;gt;y
    x y +
    return
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and with lambdas&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|0100
3 2 [&apos; \x.
        [&apos; \y.
            x&apos; y&apos; +&apos;
        ]&apos;
    ]&apos; apply
    apply
BRK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In other words, the function is defined inside the quoted brackets and called using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply&lt;/code&gt; rather than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;/h2&gt;

&lt;p&gt;So how do we do this? There are several components than need to be brought together to have named variables, nesting, and functions as values.&lt;/p&gt;

&lt;h3 id=&quot;uxntal-quoting-and-unquoting&quot;&gt;Uxntal quoting and unquoting&lt;/h3&gt;

&lt;h4 id=&quot;quoting&quot;&gt;Quoting&lt;/h4&gt;

&lt;p&gt;First of all, we need some mechanism to defer evaluation of an operation, which I call “quoting” for short.
Luckily, Uxntal has the essential feature: it is possible to quote an operation and unquote it later. For example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#06 #07 ADD
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;would immediately compute 6*7; but if we write&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#06 #07 LIT ADD
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;then we have the ADD operation as a symbol on the stack. This is what I call “quoting” for opcodes.&lt;/p&gt;

&lt;h4 id=&quot;unquoting-through-self-modification&quot;&gt;Unquoting through self-modification&lt;/h4&gt;

&lt;p&gt;To unquote the symbol and so evaluate the expression, we can do&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#00 STR $1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;which is a bit of Uxn magic: it is a relative store with a relative address of 0, and effectively it takes the symbol from the stack and puts it as the next instruction to be executed. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$1&lt;/code&gt; is just a placeholder on the stack to create the space for the store. So the following would calculate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6*7&lt;/code&gt; and print out &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|0100
    #06 #07 LIT ADD
    #00 STR $1
    #18 DEO ( prints the character to stdout )
BRK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There isn’t really anything magical going on here: an equivalent program would be&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|0100
    #06 #07 LIT ADD
    ;eval STA @eval $1
    #18 DEO ( prints the character to stdout )
BRK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;or even&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;|0100
    #06 #07 LIT ADD
    ;eval STA ;eval JSR2
    #18 DEO ( prints the character to stdout )
BRK

@eval $1
JMP2r
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The key mechanism is that Uxntal allows to overwrite the program code, so the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$1&lt;/code&gt; placeholder can at runtim be replaced by any byte, and all bytes are valid instructions.&lt;/p&gt;

&lt;h4 id=&quot;unquoting-without-self-modification&quot;&gt;Unquoting without self-modification&lt;/h4&gt;

&lt;p&gt;Even if Uxntal did not have modifiable code, we could still quote and unquote. After all, e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIT MUL&lt;/code&gt; is exactly the same as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIT 1a&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#1a&lt;/code&gt; so we can always put opcodes on the stack, they are just bytes. And to unquote them, we could use conditional jumps, for example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#06 #07 LIT MUL
( opcode on the stack )
#1a EQU ,&amp;amp;eval-mul JCN
...
&amp;amp;eval-mul
MUL
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So the self-modification is purely a more efficient way of unquoting.&lt;/p&gt;

&lt;h3 id=&quot;kinds-of-symbols&quot;&gt;Kinds of symbols&lt;/h3&gt;

&lt;p&gt;Apart from the opcodes, there are several other types of symbols we need to be able to quote and unquote: variables, constants and function calls.&lt;/p&gt;

&lt;p&gt;For the variables, we need to handle declaration and use: the declaration results in the argument being stored at the location referenced by the variable, and the use results in the value stored at the referenced location being read. I store the variables in the zero-page memory:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;@x $2 @y $2 @z $2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The declaration macro &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\x.&lt;/code&gt; should when unquoted result in&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.x STZ2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using a variable macro &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&apos;&lt;/code&gt; should when unquoted result in&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.x LDZ2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Unquoting a constant simply means putting it on the stack.&lt;/p&gt;

&lt;p&gt;Finally, named function call should when unquoted result in&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;f JSR2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;grouping-symbols&quot;&gt;Grouping symbols&lt;/h3&gt;

&lt;p&gt;As we want to be able to nest lambdas, we need some delimiters to group the quoted symbols. That is what the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[&apos;&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;]&apos;&lt;/code&gt; bracket macros do.  A quoted sequence returns its address onto the working stack. In this way we can pass lambdas around as values.&lt;/p&gt;

&lt;h3 id=&quot;building-the-lambda&quot;&gt;Building the lambda&lt;/h3&gt;

&lt;p&gt;To build the lambda function, I need to store the quoted symbols. Crucially, I need to be able to identify the kind of each symbol. I encode each symbol using three bytes, the third byte is a label to identify the kind of symbol. The opening and closing brackets are also labelled and stored in this way. The opening bracket symbol contains the size of the lambda; the closing bracket is only there as a jump target. For example,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[&apos; \x. x&apos; 1&apos; +&apos; ;f call&apos; ]&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;is encoded as&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Value   Label
------  ------
00 07   LAMBDA
.x __  BIND
.x __  ARG
00 01   CONST
ADD __  OPCODE
;f      CALL
__ __   END
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__&lt;/code&gt; are unused slots because for simplicity I have currently made all symbols the same size (this will probably change as I don’t like inefficiency). For an 8-bit version, it would be possible to encode everything in two bytes.&lt;/p&gt;

&lt;p&gt;Each quoting operation is implemented as a function and those functions keep track of where to write the symbols in memory. The memory for the lambdas starts from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|0100&lt;/code&gt;, so I effectively overwrite the program. This is OK because the lambda definition in the program takes up more space than the encoding of the lambda, so there is no risk of overwriting named functions.&lt;/p&gt;

&lt;h3 id=&quot;the-lambda-stack&quot;&gt;The lambda stack&lt;/h3&gt;

&lt;p&gt;Because I want to be able to nest lambdas, I need a stack. I could abuse the return stack for this purpose, but I don’t think using either of the Uxn stacks for persistent state is a good idea. So I build a stack in the second half of the zero-page memory. This stack stores tuples of the starting address and the size (in 3-byte words) of each lambda. Each quoting operation manipulates that stack to create the memory encoding for each lambda.&lt;/p&gt;

&lt;h3 id=&quot;applying-the-lambda&quot;&gt;Applying the lambda&lt;/h3&gt;

&lt;p&gt;The unquoting operation (the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply&lt;/code&gt; call) uses the same lambda stack. It takes the address of the lambda as argument, and loops over all symbols in the stored representation. The interesting case is that of nested lambdas: when the symbol represents an opening bracket, the evaluator puts the address of the nested lambda on the stack and jumps to the closing bracket, which acts as a no-op. For non-nested lambdas, the closing bracket returns the lambda’s address. In this way I can evaluate nested lambdas as part of an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply&lt;/code&gt; call, and I can also return lambdas.&lt;/p&gt;

&lt;h2 id=&quot;more-uses-of-quoting&quot;&gt;More uses of quoting&lt;/h2&gt;

&lt;p&gt;The quoting mechanism can be used for other purposes than creating lambda functions. Or to look at it another way, lambda functions that take no arguments (“blocks”) are valid:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[&apos; ;f call&apos; ]&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This gives us an option to have deferred calls.&lt;/p&gt;

&lt;h3 id=&quot;a-lazy-if&quot;&gt;A lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Lazy means here that we will only evaluate the true or false branch after evaluating the condition, instead of evaluating both and returning the result based on the condition. We can create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lazy-if&lt;/code&gt; function using quoting as follows:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[&apos; &amp;lt;false-expr&amp;gt;&apos; ]&apos; [&apos; &amp;lt;true-expr&amp;gt;&apos; ]&apos; &amp;lt;cond&amp;gt;  ;lazy-if call
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lazy-if&lt;/code&gt; function is quite simple:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;@lazy-if
    ,&amp;amp;if-true JCN
    ( if-false )
    POP2 apply-tc
    &amp;amp;if-true
    NIP2 apply-tc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply-tc&lt;/code&gt; is a tail call version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply&lt;/code&gt;, so equivalent to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply return&lt;/code&gt;. We could of course create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;case&lt;/code&gt; expression in this way too.&lt;/p&gt;

&lt;h3 id=&quot;tuples&quot;&gt;Tuples&lt;/h3&gt;

&lt;p&gt;The quoting mechanism can also be used to create immutable lists, or actually tuples (a tuple is a generalisation of a pair, can have any number of values of any type but can’t be modified):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[&apos; 2 4 + \&apos; 3 5 + \&apos; ]&apos; ( a tuple (6,8) )
[&apos; 1 2 + \&apos; 4 \&apos; ]&apos;  ( a tuple (3,4) )
SWP2
apply * apply * / ( 4 )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[&apos; ... ]&apos;&lt;/code&gt; first creates two tuples and stores it somewhere;
then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply&lt;/code&gt; puts the values on the stack. It would be quite easy to write an indexing function to access element by index.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[&apos; 2 4 + \&apos; 3 5 + \&apos; ]&apos;  ( creates (6,8) )
[&apos; 1 2 + \&apos; 4 2 /  2&apos; ]&apos;  ( creates (3,2,2) )
SWP2
apply * ( 6*8 )
SWP2
apply [ * * ]  ( 3*2*2 )
/ ( 48/12 )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Another example to illustrate the functions to work on tuples:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[&apos; [ 1 2 + ] \&apos; [ 3 4 * ] \&apos; 5&apos; ]&apos; -&amp;gt;l ( store the tuple in l )
l fst  print16-nl ( first element )
l snd print16-nl ( second element )
l 2 at print16-nl ( at takes the index (base 0) and returns the element )
[  + + ] POP2
l empty print8-nl ( test if the tuple is empty, returns #00 here )
[&apos; ]&apos; empty print8-nl ( test if the tuple is empty, returns #01 here )
l size print16-nl ( returns the number of elements in the tuple, i.e. 3 )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Because Uxntal is not statically typed, there is no difference between immutable lists and tuples.&lt;/p&gt;

&lt;h3 id=&quot;cons-lists&quot;&gt;Cons lists&lt;/h3&gt;

&lt;p&gt;What I call a “cons list” is a list constructed starting from an empty list by adding a single element. The function to construct such a list is typically called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cons&lt;/code&gt; in functional programming languages, and in Haskell it has a corresponding operator &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:&lt;/code&gt;. So the list&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[ 1 2 3 4 ]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;is really syntactic sugar for&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1:2:3:4:()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;which is a shorter notation for&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(cons 1 (cons 2 (cons 3 (cons 4 ()))))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can use the tuples in combination with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cons&lt;/code&gt; function in Uxntal to create cons lists:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[&apos; ]&apos; 7 cons 6 cons 5 cons ( [ 5 6 7 ] )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are a few functions to manipulate such lists, the most common ones are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;head&lt;/code&gt; which returns the first element and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tail&lt;/code&gt; which returns the rest of the list (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;car&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdr&lt;/code&gt; in Scheme).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[&apos; ]&apos; 7 cons 6 cons 5 cons -&amp;gt;l ( (5:6:(7:[])) )
l tail tail head ( )
l tail head
*
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There is of course also a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;length&lt;/code&gt; function, and a function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt; to check if the list is empty:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[&apos; ]&apos; 7 cons 6 cons 5 cons -&amp;gt;l ( (5:6:(7:[])) )
l 4 cons length ( 4 )
l tail tail tail null  ( #01 )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;partial-application-and-closures&quot;&gt;Partial application and closures&lt;/h3&gt;

&lt;p&gt;The nested lambdas allow partial application:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;5 [&apos; \x.  [&apos; \y. x&apos; y&apos; +&apos; ]&apos;  ]&apos; lambda-call
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This means that we don’t have to provide values for all arguments, and what we return is a function that has been specialised with the arguments that have been provided. In the example, we will effective obtain a function that will calculate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y+5&lt;/code&gt;. This is a technique that can be used to generate specialised functions from a template.&lt;/p&gt;

&lt;p&gt;This looks a lot like a proper &lt;a href=&quot;https://en.wikipedia.org/wiki/Closure_(computer_programming)&quot;&gt;closure&lt;/a&gt; but while it seems to work, the value is not really captured. We simply store 5 in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@x&lt;/code&gt;; if I modify &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; between the lambda calls, it will use the modified value. With a proper closure, once it has been created, it does not matter that the original value gets modified. This is not the case in my approach because x and y are globals, not locals. It is possible to address this but it would be very expensive:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\x.&lt;/code&gt;, we store the address of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.x&lt;/code&gt; somewhere;&lt;/li&gt;
  &lt;li&gt;Then we check the entire downstream lambda definition for occurrences of that address;&lt;/li&gt;
  &lt;li&gt;We need to take into account that any further occurrence of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\x.&lt;/code&gt; resets this;&lt;/li&gt;
  &lt;li&gt;Then we could replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.x LIT LDZ2 OPCODE&apos;&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.x LDZ2 CONST&apos;&lt;/code&gt;, so the value would become embedded in the lambda.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to address this issue, please let me know.&lt;/p&gt;

&lt;h3 id=&quot;desugaring&quot;&gt;Desugaring&lt;/h3&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;5 \[ \x. x&apos; x&apos; *&apos; \[ \y. y&apos; 1&apos; +&apos; \] lambda-call&apos; \] lambda-call ( returns #001a )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\[&lt;/code&gt; … &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\]&lt;/code&gt; brackets indicate the start and end of a quoting region. Within a quoting region, all quote symbols make up the anonymous function. I use macros to make it a bit nicer. Desugaring the example one layer, we get the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#0033
[&apos;
    .x bind&apos;
    .x arg&apos;
    .x arg&apos;
    LIT MUL2 opcode&apos;
    [&apos;
        .y bind&apos;
        .y arg&apos;
        #0001 const&apos;
        LIT ADD2 opcode&apos;
    ]&apos;
    ;lambda-call call&apos;
]&apos;
;lambda-call call
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Although it may seem at first sight that a stack-based assembly language is quite far removed from a high-level functional language, in Uxntal we can implement many fundamental functional programming concepts such as lambdas, lazy conditionals, tuples and lists and concepts such as partial application and closures, simply by introducing the concept of quoting and unquoting symbols. Uxntal’s simple macro mechanism provides sufficient abstraction to create readable functional programs.&lt;/p&gt;

&lt;h2 id=&quot;code&quot;&gt;Code&lt;/h2&gt;

&lt;p&gt;The code implementing the constructs described in this article is available &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/hyakuwa/src/branch/main/quoting-lambdas&quot;&gt;in my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hyakuwa&lt;/code&gt; repo on Codeberg&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;8-bit-vs-16-bit&quot;&gt;8-bit vs 16-bit&lt;/h3&gt;

&lt;p&gt;By default, my implementation uses 16-bit words as values. It is possible to use 8-bit constants, arguments and operations. The macro files  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;quote-lambda_macros_8bit.tal&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lambda_decls_8bit.tal&lt;/code&gt; have the appropriate definitions, or with less sugar you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind8&apos;&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arg8&apos;&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const8&apos;&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;

&lt;p&gt;As is the nature of such projects, there is always a lot more that could be done. There are two main drawbacks to the current approach: the macro mechanism is not expressive enough and the computational overhead is very high.&lt;/p&gt;

&lt;p&gt;To address the former we could create a custom assembler, which effectively means we have a new functional language that assembles into Uxntal, either source or rom. If we did that, we could write&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;5 \[ \x. x&apos; x&apos; *&apos; \[ \y. y&apos; 1&apos; +&apos; \] lambda-call&apos; \] lambda-call
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;as, for example,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;5 (\x -&amp;gt; x x * (\y -&amp;gt; y 1 +))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This would be a lot more readable and it would also allow to tailor the memory allocation for variables.&lt;/p&gt;

&lt;p&gt;We can’t fundamentally address the computational overhead. It can definitely be reduced as the current implementation is not optimised. But effectively, the quoting mechanism is a kind of interpreter, so it always incurs the read-eval-write overhead. What we could do instead is compile the Uxntal code itself, rather than emulating it. But that will be the topic of another article.&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;The banner picture shows a row of small rabbit status at a Shinto shrine in Kyoto.&lt;/em&gt;&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>The politics of writing compilers</title>
        <link href="https://limited.systems/articles/politics-of-compiler-writing/"/>
        <updated>2021-12-20T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/politics-of-compiler-writing</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/politics-of-compiler-writing_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;Compilers are pieces of software that convert program code from one format into another. Typically, they convert source code into a binary format for execution on specific hardware. Compilers can also target virtual machines instead of physical hardware, or they can convert source code into different source code.&lt;/p&gt;

&lt;p&gt;(Some programming languages are not compiled but interpreted, which means they require another piece of software, an interpreter, to run them. An interpreter is effectively a compiler and virtual machine combined, because it transforms the source code into some internal representation that it can execute. In this article, I focus on compilers but the same issues apply to interpreters.)&lt;/p&gt;

&lt;p&gt;Most end users never deal with compilers because they simply run the compiled applications. Some users have the need, know-how and skills to compile code written by others; fewer again have the need, know-how and skills to write their own code and compile it. And quite few people have the know-how and skills to write a compiler. And yet, compilers are crucially important, as without a compiler, programs can’t run.&lt;/p&gt;

&lt;p&gt;This automatically takes me to the question of politics. Whoever controls the compiler has some power over the users (both the programmers and the end users), and therefore compilers are political objects.&lt;/p&gt;

&lt;p&gt;But what about compiler research, the field of computing science which investigates new theories, formalisms and techniques to advance the knowledge on compilers? Generally speaking, compiler researchers will not consider their work political. A compiler is a tool that can be used regardless of political convictions, and research into better compilers just leads to better tools. Compiler writers can make a similar argument: we just make them.&lt;/p&gt;

&lt;p&gt;There are many different aspects to this. As a compiler researcher or compiler writer, you could ask yourself the following questions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;What are the reasons for doing this work?
    &lt;ul&gt;
      &lt;li&gt;Why are you writing this compiler? Or what is the target compiler for your research?&lt;/li&gt;
      &lt;li&gt;Who is going to benefit from your work? You? Your employer? The community? What community?&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;What are your assumptions?
    &lt;ul&gt;
      &lt;li&gt;Assumptions on the programmer:
        &lt;ul&gt;
          &lt;li&gt;What do they need to know?&lt;/li&gt;
          &lt;li&gt;What education level do they need?&lt;/li&gt;
          &lt;li&gt;How wealthy do they need to be?&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Assumptions on the user:
        &lt;ul&gt;
          &lt;li&gt;Who is the user of your compiler?&lt;/li&gt;
          &lt;li&gt;What are their required skills and background?&lt;/li&gt;
          &lt;li&gt;How usable and accessible is your compiler?&lt;/li&gt;
          &lt;li&gt;Which users can afford to use your compiler?&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Assumptions on the computer:
        &lt;ul&gt;
          &lt;li&gt;If your compiler targets a specific hardware architecture, who has access to this hardware?&lt;/li&gt;
          &lt;li&gt;Does your compiler need the latest hardware and/or latest operating system to run?&lt;/li&gt;
          &lt;li&gt;How much memory and disk space does it need?&lt;/li&gt;
          &lt;li&gt;Does it need internet access?&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Assumptions on the availability:
        &lt;ul&gt;
          &lt;li&gt;Is it available free of charge?&lt;/li&gt;
          &lt;li&gt;Does it work on many operating systems?&lt;/li&gt;
          &lt;li&gt;Is it available in a readily-useable form?&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inevitably, the answers to these questions are inherently political.&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;The banner picture shows activists and a candidate of the Communist Party of Japan.&lt;/em&gt;&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>Frugal computing: developer perspective</title>
        <link href="https://limited.systems/articles/frugal-computing-developer/"/>
        <updated>2021-12-20T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/frugal-computing-developer</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/frugal-computing-developer_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;On the need for low-carbon and sustainable computing and what developers can do about it.&lt;/p&gt;

&lt;p&gt;This is a follow-up on my &lt;a href=&quot;https://limited.systems/articles/frugal-computing&quot;&gt;article about Frugal Computing&lt;/a&gt;, focusing on the what developers can do to help reduce the carbon emissions from computing.&lt;/p&gt;

&lt;h2 id=&quot;key-points&quot;&gt;Key points&lt;/h2&gt;

&lt;h3 id=&quot;the-problem&quot;&gt;The problem:&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;The current emissions from computing are about 2% of the world total but are projected to rise steeply over the next two decades. By 2040 emissions from computing alone will be more than half the emissions level acceptable to keep global warming below 1.5°C. This growth in computing emissions is unsustainable: it would make it virtually impossible to meet the emissions warming limit.&lt;/li&gt;
  &lt;li&gt;The emissions from production of computing devices far exceed the emissions from their electricity usage, so even if devices are more energy efficient producing more of them will make the emissions problem worse.&lt;/li&gt;
  &lt;li&gt;The CO₂ emissions from the internet infrastructure resulting from individual internet usage are also very large and growing steeply because of the increased use of higher-resolution video and VR/AR.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;the-solution&quot;&gt;The solution:&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;As a society we need to start treating computational resources as finite and precious, to be utilised only when necessary, and as effectively as possible. We need &lt;em&gt;frugal computing&lt;/em&gt;: achieving the same results for less energy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;developer-actions&quot;&gt;Developer actions:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Make software that works on older devices, the older the better.&lt;/li&gt;
  &lt;li&gt;Make software that will keep on working for a very long time.&lt;/li&gt;
  &lt;li&gt;Make software that uses the least amount of total energy to achieve its results.&lt;/li&gt;
  &lt;li&gt;Make software that also uses the least amount of network data transfer, memory and storage.&lt;/li&gt;
  &lt;li&gt;Make software that encourages the user to use it in a frugal way.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;extending-the-useful-life-of-computing-devices-is-key&quot;&gt;Extending the useful life of computing devices is key&lt;/h2&gt;

&lt;p&gt;End-user computing devices (phones, laptops, desktops) &lt;a href=&quot;https://reboxed.co/blogs/outsidethebox/the-carbon-footprint-of-your-phone-and-how-you-can-reduce-it&quot;&gt;create more emissions during their manufacturing than during their useful life, and this is not likely to change significantly in the next two decades&lt;/a&gt;. Therefore, we must extend the useful life of our computing devices. This is the top priority.&lt;/p&gt;

&lt;h3 id=&quot;make-software-that-works-on-older-devices-the-older-the-better&quot;&gt;Make software that works on older devices, the older the better&lt;/h3&gt;

&lt;p&gt;One of the main reason why users upgrade their devices is that the device is no longer capable of supporting the needs of new software. This can be because the new software requires&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;more resources than the device has (memory, CPU speed, network bandwidth, screen resolution);&lt;/li&gt;
  &lt;li&gt;a more recent version of other software than device can support, including the operating system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why when developing software, you should make it work on older devices by design. That way, users with older devices can use your software without having to upgrade. That also means your software should use the least amount of resources (CPU, memory, storage etc) possible to achieve its results, as older devices have fewer resources.&lt;/p&gt;

&lt;h3 id=&quot;make-software-that-will-keep-on-working-for-a-very-long-time&quot;&gt;Make software that will keep on working for a very long time&lt;/h3&gt;

&lt;p&gt;It is also important that the software you write will keep on working for as long as possible, ideally forever. One reason why your software might stop working is that its resource utilisation grows over time. This can for example be the case if it needs increasingly more memory or disk space the longer it gets used. Another reason is that bugs and vulnerabilities that are discovered only after a long time might not get fixed.&lt;/p&gt;

&lt;p&gt;The software needs to be supported for as long the device lasts. So frugal software requires a long-term commitment in terms of updates for security and bugfixing.&lt;/p&gt;

&lt;h2 id=&quot;being-frugal-with-resources&quot;&gt;Being frugal with resources&lt;/h2&gt;

&lt;p&gt;Whereas for mobile phones the emissions from usage are much lower than the emissions from manufacturing, for laptops and desktop computers, emissions from usage are still significant.&lt;/p&gt;

&lt;h3 id=&quot;make-software-that-uses-the-least-amount-of-total-energy-to-achieve-its-results&quot;&gt;Make software that uses the least amount of total energy to achieve its results&lt;/h3&gt;

&lt;p&gt;Not only do older devices have fewer resources, resource consumption eventually means emissions, because all resources on a device consume energy. In practice, a large source of emissions resulting from end user device activity is the local Wifi, because transfering the data (e.g. video) consumes a lot of energy. However, on laptops, desktops and servers, CPU and GPU power consumption is also a significant factor.&lt;/p&gt;

&lt;p&gt;The consequence is that as a developer, you need to be aware of all factors that contribute to the total energy consumption of a task performed by your software. For apps and web sites, the dominant sources of emissions are &lt;a href=&quot;https://www.carbontrust.com/our-work-and-impact/guides-reports-and-tools/carbon-impact-of-video-streaming&quot;&gt;in the home&lt;/a&gt;. For &lt;a href=&quot;https://www.researchgate.net/publication/336909520_Toward_Greener_Gaming_Estimating_National_Energy_Use_and_Energy_Efficiency_Potential&quot;&gt;non-networked games, the power consumption of the CPU and GPU&lt;/a&gt; is the main source of emissions.&lt;/p&gt;

&lt;h3 id=&quot;make-software-that-encourages-the-user-to-be-frugal&quot;&gt;Make software that encourages the user to be frugal&lt;/h3&gt;

&lt;p&gt;For some applications, the behaviour of the user can have a major effect on the resources it uses. If you are developing such an application, consider if you can encourage or nudge the user to use fewer resources.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Web browsers need resources depending on the number of sites the user is accessing concurrently as well as on the design of the sites;&lt;/li&gt;
  &lt;li&gt;for video based applications, energy consumption depends on the resolution of the video;&lt;/li&gt;
  &lt;li&gt;if the user experiences the app as sluggish or erratic, they might be more inclined to upgrade their device.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[Note: post edited on 2022-12-07 because the original post assumed that internet network emissions are proportional to the traffic volume, and more recent research shows this is not the case.]&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>Generic datastructure traversals with roles and introspection</title>
        <link href="https://limited.systems/articles/generic-traversals-in-raku/"/>
        <updated>2021-12-13T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/generic-traversals-in-raku</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/generic-traversals-in-raku_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;I am a &lt;a href=&quot;https://andrewshitov.com/2015/05/05/interview-with-audrey-tang/&quot;&gt;lambdacamel&lt;/a&gt; and therefore I like to adapt concepts and techniques from functional programming, and in particular from the &lt;a href=&quot;https://www.haskell.org/&quot;&gt;Haskell&lt;/a&gt; language, to Raku. One of the techniques that I use a lot is &lt;em&gt;generic traversals&lt;/em&gt;, also known as “Scrap Your Boilerplate” after the title of &lt;a href=&quot;https://archive.alvb.in/msc/02_infogp/papers/SYB1.pdf&quot;&gt;the paper by Simon Peyton Jones and Ralf Lämmel&lt;/a&gt; that introduced this approach. In their words:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Many programs traverse data structures built from rich mutually-recursive data types. Such programs often have a great deal of “boilerplate” code that simply walks the structure, hiding a small amount of “real” code that constitutes the reason for the traversal. ”Generic programming” is the umbrella term to describe a wide variety of programming technology directed at this problem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So to save you having to write your own custom traversal, this approach gives you generic functions that do traversals on arbitrary data strucures. In this article, I will explain how you can easily implement such generics in Raku for arbitrary role-based datastructures. There is no Haskell in this article.&lt;/p&gt;

&lt;h2 id=&quot;roles-as-datatypes-by-example&quot;&gt;Roles as datatypes by example&lt;/h2&gt;

&lt;p&gt;I implemented of these generics for use with role-based datatypes. Raku’s &lt;a href=&quot;https://docs.raku.org/language/objects#index-entry-Parameterized_Roles&quot;&gt;parameterised roles&lt;/a&gt; make creating complex datastructures very easy. I use the roles purely as datatypes, so they have no associated methods.&lt;/p&gt;

&lt;p&gt;For example, here is an example code snippet in a little language that I use in my research.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;map (f1 . f2) (map g (zipt (v1,map h v2)))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The primitives are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&lt;/code&gt; (function composition), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zipt&lt;/code&gt; and the tuple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(...)&lt;/code&gt;, and the names of functions and vectord. The datatype for the abstract syntax of this little language is called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expr&lt;/code&gt; and looks as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;# Any expression in the language
role Expr {}
# map f v
role MapV[Expr \f_,Expr \v_] does Expr {
    has Expr $.f = f_;
    has Expr $.v = v_;
}
# function composition f . g
role Comp[Expr \f_, Expr \g_] does Expr {
    has Expr $.f = f_;
    has Expr $.g = g_;
}
# zipt t turns a tuple of vectors into a vector of tuples
role ZipT[Expr \t_] does Expr {
    has Expr $.t = t_
}
# tuples are just arrays of Expr
role Tuple[Array[Expr] \e_] does Expr {
    has Array[Expr] $.e = e_
}
# names of functions and vectors are just string constants
role Name[Str \n_] does Expr {
    has Str $.n = n_
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expr&lt;/code&gt; role is the toplevel datatype. It is empty because it is implemented entirely in terms of the other roles, which thanks to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;does&lt;/code&gt; are all of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expr&lt;/code&gt;. And most of the roles have attributes that are also of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expr&lt;/code&gt;. So we have a recursive datatype, a tree with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Name&lt;/code&gt; node as leaves.&lt;/p&gt;

&lt;p&gt;We can now write the abstract syntax tree (AST) of the example code using this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expr&lt;/code&gt; datatype:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;my \ast = MapV[ 
    Comp[
        Name[&apos;f1&apos;].new,
        Name[&apos;f2&apos;].new
    ].new,
    MapV[
        Name[&apos;g&apos;].new,
        ZipT[
            Tuple[
                Array[Expr].new(
                    Name[&apos;v1&apos;].new,
                    MapV[
                        Name[&apos;h&apos;].new,
                        Name[&apos;v2&apos;].new
                    ].new
                )
            ].new
        ].new
    ].new
].new;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The typical way to work with such a datastructure is using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;given/when&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;sub worker(Expr \expr) {
    given expr {
        when MapV {...}
        when Comp {...}
        when ZipT {...}
        ...        
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alternatively, you can use a multi sub:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;multi sub worker(Mapv \expr) {...}
multi sub worker(Comp \expr) {...}
multi sub worker(ZipT \expr) {...}
...        
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In both cases, we use the roles as the types to match against for the actions we want to take.&lt;/p&gt;

&lt;p&gt;(For more details about algebraic datatypes see my earlier article &lt;a href=&quot;https://wimvanderbauwhede.github.io/articles/roles-as-adts-in-raku/&quot;&gt;Roles as Algebraic Data Types in Raku&lt;/a&gt;.)&lt;/p&gt;

&lt;h2 id=&quot;generics&quot;&gt;Generics&lt;/h2&gt;

&lt;p&gt;If I want to traverse the AST above, what I would normally do is write a worker as above, where for every node except the leaf nodes, I would call the worker recursively, for example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;sub worker(Expr \expr) {
    given expr {
        when MapV {
            my \f_ = worker(expr.f);
            my \v_ = worker(expr.v);
            ...
        }
        ...        
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But wouldn’t it be nice if I did not have to write that code at all? Enter generics.&lt;/p&gt;

&lt;p&gt;I base my naming and function arguments on that of the &lt;a href=&quot;https://hackage.haskell.org/package/syb-0.7.2.1/docs/Data-Generics.html&quot;&gt;Haskell library &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data.Generics&lt;/code&gt;&lt;/a&gt;. It provides many schemes for traversals, but the most important ones are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;everything&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;everywhere&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;everything&lt;/code&gt; is a function which takes a datastructure, a matching function, an accumulator and an update function for the accumulator. The matching function defines what you are looking for in the datastructure. The result is put into the accumulator using the update function.&lt;/p&gt;

    &lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;  sub everything(
      Any \datastructure, 
      Any \accumulator, 
      &amp;amp;joiner, 
      &amp;amp;matcher 
      --&amp;gt; Any){...}
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;everywhere&lt;/code&gt; is a function which takes a datastructure and a modifier function. The modifier function defines which parts of the datastructure you want to modify. The result of the traversal is a modified version of the datastructure.&lt;/p&gt;

    &lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;  sub everywhere(
      Any \datastructure, 
      &amp;amp;modifier 
      --&amp;gt; Any){...}
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most common case for the accumulator is to use a list, so the updated function appends lists to the accumulator:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;sub append(\acc, \res) {
    return (|acc, |res);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As an example of a matching function, let’s for example find all the function and vector names in our AST above:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;sub matcher(\expr) {
    given expr {
        when Name {
            return [expr.n]
        } 
    }
    return []
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So if we find a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Name&lt;/code&gt; node, we return its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; attribute as a single-element list; otherwise we return an empty list.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;my \names = everything(ast,[],&amp;amp;append,&amp;amp;matcher); 
# =&amp;gt; returns (f1 f2 g h v1 v2)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or let’s say we want to change the names in this AST:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;sub modifier(\t) {
    given t {
        when Name {
            Name[t.n~&apos;_updated&apos;].new 
        }
        default {t}
    }
}

my \ast_ = everywhere(ast,&amp;amp;modifier); 
# =&amp;gt; returns the AST with all names appended with &quot;_updated&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;implementing-generics&quot;&gt;Implementing Generics&lt;/h2&gt;

&lt;p&gt;So how do we implement these magic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;everything&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;everywhere&lt;/code&gt; functions? The problem to solve is that we want to iterate through the attributes of every role without having to name it. The solution for this is to use Raku’s &lt;a href=&quot;https://docs.raku.org/language/mop&quot;&gt;Metaobject protocol (MOP)&lt;/a&gt; for introspection. In practice, we use the Rakudo-specific &lt;a href=&quot;https://docs.raku.org/type/Metamodel::ClassHOW&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Metamodel&lt;/code&gt;&lt;/a&gt;. We need only three methods: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;attribute&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_value&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set_value&lt;/code&gt;. With these, we can iterate through the attributes and visit them recursively.&lt;/p&gt;

&lt;p&gt;Attributes can be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%&lt;/code&gt; (and even &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;&lt;/code&gt; but I will skip this). What this means in terms of Raku’s type system is that they can be scalar, Iterable or Associative, and we need to distinguish these cases. With that, we can write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;everything&lt;/code&gt; as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;sub everything (\t, \acc,&amp;amp;update,&amp;amp;match) {
    # Arguments a immutable, so copy to $acc_
    my $acc_ = acc;
    # Match and update $acc_
    $acc_ =update($acc_,match(t));
    # Test the attribute type
    if t ~~ Associative {
        # Iterate over the values
        for t.values -&amp;gt; \t_elt  {
            $acc_ = everything(t_elt,$acc_,&amp;amp;update,&amp;amp;match)
        }
        return $acc_; 
    }     
    elsif t ~~ Iterable {
        # Iterate
        for |t -&amp;gt; \t_elt  {
            $acc_ = everything(t_elt,$acc_,&amp;amp;update,&amp;amp;match)
        }
        return $acc_; 
    }

    else { 
        # Go through all attributes
        for t.^attributes -&amp;gt; \attr {
            # Not everyting return by ^attributes 
            # is of type Attribute
            if attr ~~ Attribute {
                # Get the attribute value
                my \expr = attr.get_value(t);
                if not expr ~~ Any  { # for ContainerDescriptor::Untyped
                    return $acc_;
                }
                # Descend into this expression
                $acc_ = everything(expr,$acc_,&amp;amp;update, &amp;amp;match);
            }
        }
    }
    return $acc_
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So what we do here essentially is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%&lt;/code&gt; we iterate through the values&lt;/li&gt;
  &lt;li&gt;iterate through the attributes using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^attributes&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;for each attribute, get the expression using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_value&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;everything&lt;/code&gt; on that expression&lt;/li&gt;
  &lt;li&gt;the first thing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;everything&lt;/code&gt; does is update the accumulator&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;everywhere&lt;/code&gt; is similar:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;sub everywhere (\t_,&amp;amp;modifier) {
    # Modify the node
    my \t = modifier(t_);
    # Test the type for Iterable or Associative
    if t ~~ Associative {
        # Build the updated map
        my %t_;
        for t.keys -&amp;gt; \t_k  {
            my \t_v = t{t_k};
            %t_{t_k} = everywhere (t_v,&amp;amp;modifier);
        }
        return %t_; 
    }     
    elsif t ~~ Iterable {
        # Build the updated list
        my @t_=[];
        for |t -&amp;gt; \t_elt  {
            @t_.push( everywhere(t_elt,&amp;amp;modifier) );
        }
        return @t_; 
    }

    else {
        # t is immutable so copyto $t_
        my $t_ = t;
        for t.^attributes -&amp;gt; \attr {            
            if attr ~~ Attribute {
                my \expr = attr.get_value(t);
                if not expr ~~ Any  { # for ContainerDescriptor::Untyped
                    return $t_;
                }
                my \expr_ = everywhere(expr,&amp;amp;modifier);                
                attr.set_value($t_,expr_);
            }
        }
        return $t_;
    }
    return t;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So what we do here essentially is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%&lt;/code&gt; we iterate through the values&lt;/li&gt;
  &lt;li&gt;iterate through the attributes using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^attributes&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;for each attribute, get the expression using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_value&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;everywhere&lt;/code&gt; on that expression&lt;/li&gt;
  &lt;li&gt;update the attribute using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set_value&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;this-works-without-roles-too&quot;&gt;This works without roles too&lt;/h2&gt;

&lt;p&gt;First of all, the above works for classes too, because the Metamodel methods are not specific to roles. Furthermore, because we test for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%&lt;/code&gt;, the generics above work just fine for data structures without roles, built from hashes and arrays:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;my \lst = [1,[2,3,4,[5,6,7]],[8,9,[10,11,[12]]]];

sub matcher (\expr) {
    given expr {
        when List {
            if expr[0] % 2 == 0 {                
                    return [expr]                
            }            
        }
    }
    return []
}

my \res = everything(lst,[],&amp;amp;append,matcher);
say res;
# ([2 3 4 [5 6 7]] [8 9 [10 11 [12]]] [10 11 [12]] [12])
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or for hashes:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;my %hsh = 
    a =&amp;gt; {
        b =&amp;gt; {
            c =&amp;gt; 1,
            a =&amp;gt; {
                b =&amp;gt;1,c=&amp;gt;2
            } 
        },
        c =&amp;gt; {
            a =&amp;gt;3
        }
    },
    b =&amp;gt; 4,
    c =&amp;gt; {d=&amp;gt;5,e=&amp;gt;6}
;

sub hmatcher (\expr) {
    given (expr) {
        when Map {
            my $acc=[];
            for expr.keys -&amp;gt; \k {                
                if k eq &apos;a&apos; {
                    $acc.push(expr{k})
                }
            }
            return $acc;
        }
    }
    return []
}

my \hres = everything(%hsh,[],&amp;amp;append,&amp;amp;hmatcher);
say hres;
# ({b =&amp;gt; {a =&amp;gt; {b =&amp;gt; 1, c =&amp;gt; 2}, c =&amp;gt; 1}, c =&amp;gt; {a =&amp;gt; 3}} {b =&amp;gt; 1, c =&amp;gt; 2} 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Generic datastructure traversals are a great way to reduce boilerplate code and focus on the actual purpose of the traversals. And now you can have them in Raku too. I have shown the implementation for the two main schemes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;everything&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;everywhere&lt;/code&gt; and shown that they work for role based datastructures as well as traditional hash- or array-based datastructures.&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>How to reduce the carbon footprint of your digital lifestyle</title>
        <link href="https://limited.systems/articles/frugal-computing-consumer/"/>
        <updated>2021-11-19T00:00:00+00:00</updated>
        <id>https://limited.systems/articles/frugal-computing-consumer</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/frugal-computing-consumer_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;The CO₂ emissions from &lt;a href=&quot;https://limited.systems/articles/frugal-computing&quot;&gt;manufacturing and use of digital devices (laptops, phones, tablets, TVs, …) are huge and rising steeply&lt;/a&gt;. Here is what you as a consumer can do to help reduce your digital carbon footprint.&lt;/p&gt;

&lt;h2 id=&quot;key-points&quot;&gt;Key points&lt;/h2&gt;

&lt;h3 id=&quot;the-problem&quot;&gt;The problem:&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;The current CO₂ emissions from the internet and digital devices form about 2% of the world CO₂ emissions but are expected to rise steeply over the next two decades. By 2040 this “digital carbon footprint” alone will make up more than half of the acceptable global carbon footprint to keep global warming below 1.5°C. So the growth in digital carbon footprint is unsustainable: it would make it virtually impossible to keep global warming below the safe limit.&lt;/li&gt;
  &lt;li&gt;What is little known is that the CO₂ emissions from production of digital devices exceed the emissions from the electricity they use over their lifetime. So even if newer devices are more energy efficient, producing more of them will make the emissions problem worse.&lt;/li&gt;
  &lt;li&gt;Apart from the carbon footprint of production and energy consumption of our digital devices, their main purpose — accessing the internet — also causes increasing amounts of CO₂ emissions. As an end user, you only have direct control over a small fraction of this: the energy consumption of your home (or office etc) network. The core network consumes a huge amount of energy but it does this regardless of how much data you transfer. But there is indirect consumer control: if we collectively use more and more data, the network operators have to install additional capacity. Conversely, if we collectively used a lot less data, some of the networking infrastructure could be powered down and even decommissioned. So it still makes sense to be frugal with your internet data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;the-solution--what-you-as-a-consumer-can-do&quot;&gt;The solution — what you as a consumer can do:&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Buy fewer new devices (laptop/desktop/phone/tablet/TV):
    &lt;ul&gt;
      &lt;li&gt;Keep using your existing devices for as long as possible.&lt;/li&gt;
      &lt;li&gt;Have your devices repaired rather than replacing them.&lt;/li&gt;
      &lt;li&gt;Only buy devices you really need.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;When you use your devices, use them as little as possible and in the most energy-efficient manner:
    &lt;ul&gt;
      &lt;li&gt;Reduce your internet usage.&lt;/li&gt;
      &lt;li&gt;Reduce your resolution when watching streaming video.&lt;/li&gt;
      &lt;li&gt;Turn off your camera in online meetings.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;buy-fewer-new-devices&quot;&gt;Buy fewer new devices&lt;/h2&gt;

&lt;p&gt;The CO₂ emissions from production of digital devices far exceeds the emissions from the electricity they use. Therefore the best possible action from a consumer perspective is not to buy new devices.&lt;/p&gt;

&lt;p&gt;For digital devices such as mobile phones, tablets, laptops, desktop computers and televisions, the carbon footprint from manufacturing is so large that no amount of energy efficiency savings during use can compensate for it. So buying a new device effectively results in more emissions, even if it is a more energy-efficient model. It is better to keep using an older device for longer, even if it less energy-efficient. For the same reason it is better to have your devices repaired than to replace them.&lt;/p&gt;

&lt;p&gt;Companies are starting to realise that increasing numbers of consumers want to use their devices for longer. Apple has recently introduced &lt;a href=&quot;https://www.apple.com/newsroom/2021/11/apple-announces-self-service-repair/&quot;&gt;a repair self-service&lt;/a&gt; and several brands of Android phones have started to offer up to &lt;a href=&quot;https://www.techadvisor.com/buying-advice/google-android/best-brands-for-android-updates-3798154/&quot;&gt;four years of support&lt;/a&gt; on some models.&lt;/p&gt;

&lt;h2 id=&quot;when-you-use-your-devices-use-them-frugally&quot;&gt;When you use your devices, use them frugally&lt;/h2&gt;

&lt;p&gt;The internet network infrastructure also generates huge amounts of CO₂ emissions. This is the “invisible” carbon footprint of the physical infrastructure required to serve, store and transfer video, voice and data.&lt;/p&gt;

&lt;p&gt;As an end user, you only have direct control over a small fraction of this: the energy consumption of your home (or office etc) network. The core network consumes a huge amount of energy but it does this regardless of how much data you transfer. But there is indirect consumer control: if we collectively use more and more data, the network operators have to install additional capacity. Conversely, if we collectively used a lot less data, some of the networking infrastructure could be powered down and even decommissioned. So it still makes sense to be frugal with your internet data. The same argument holds for cloud storage: manufacturing storage devices has a huge carbon footprint. If we collectively store less data in the cloud, fewer storage devices are needed, and that reduces emissions.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For video calls, the most effective action is to switch off your camera whenever possible, even if this does not save a lot of energy in the immediate sense.&lt;/li&gt;
  &lt;li&gt;For watching streaming video (including TV), reducing the resolution has a similar effect.&lt;/li&gt;
  &lt;li&gt;When you use a search engine or browse the web you also increase your footprint. Search requires a lot of storage hardware as well as compute power to calculate the ranking of results. The cost of browsing the web is also high in an less intuitive way: the machinery for brokering and serving ads and tracking user behaviour requires a lot of compute power.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In a nutshell, the key actions you can take to reduce your digital carbon footprint are to buy fewer new devices, keep using your existing devices for as long as possible and only buy devices you really need: this reduces the carbon footprint of manufacturing. And when using your device, the most effective action is to be frugal: reduce your internet usage, reduce the resolution when watching streaming video and turn off your camera in video calls. Store as little data as possible, especially in the cloud.&lt;/p&gt;

&lt;h3 id=&quot;postscript-video-calls-are-still-better-than-cars-even-electric-ones&quot;&gt;Postscript: video calls are still better than cars, even electric ones&lt;/h3&gt;

&lt;p&gt;Even with your camera on, it is still better to have a video conference than to drive to a face-to-face meeting. Assuming average estimates for the emissions from internet usage and car journeys, driving just 500 m causes the same emissions as a video call of one hour. And it might come as a surprise that even if you drive a new electric car, that distance only increases to 1 km.&lt;/p&gt;

&lt;p&gt;[Note: post edited on 2022-12-07 because the original post assumed that internet network emissions are proportional to the traffic volume, and more recent research shows this is not the case.]&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>Why I wrote Haku</title>
        <link href="https://limited.systems/articles/why-i-wrote-haku/"/>
        <updated>2021-10-17T00:00:00+01:00</updated>
        <id>https://limited.systems/articles/why-i-wrote-haku</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/why-i-wrote-haku_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;A few weeks ago I released &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/haku&quot;&gt;Haku&lt;/a&gt;, a Japanese natural-language programming language. Haku is a strict functional language with implicit typing, and &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/haku/src/branch/main/examples/pwc131-t1.haku&quot;&gt;an example program&lt;/a&gt; looks like this:&lt;/p&gt;

&lt;div style=&quot;writing-mode: vertical-rl&quot;&gt;
&lt;pre&gt;
裂くとはパーツとヨウソで
若しパーツが空に等しいなら
［［ヨウソ］］ですけど
そうでなければ、
一パートはパーツの頭、
一パーツ一はパーツの尻尾、
一マエはパートの頭、
では
若しマエが〈ヨウソ引く一〉に等しいなら
［ヨウソ・パート］・パーツ一ですが
そうでなければ
［ヨウソ］・パーツ
の事です。

本とは
列は壱と弐と三と四と五と七と八と十一と十三と十六と十七、
仮一は列と空を裂くので畳み込む、
仮二は逆な仮一、
魄は仮二を逆で写像する、
魄を見せる
の事です。
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/haku#haku&quot;&gt;repository README&lt;/a&gt; explains the language and gives some background, as does this &lt;a href=&quot;https://www.slideshare.net/WimVanderbauwhede/haku-a-toy-functional-language-based-on-literary-japanese&quot;&gt;presentation&lt;/a&gt;. I have also written a separate post about the &lt;a href=&quot;https://limited.systems/articles/haku-in-raku&quot;&gt;implementation of Haku in Raku&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article is about my motivation for creating Haku.&lt;/p&gt;

&lt;p&gt;I am interested in how programming languages influence the programmer’s thinking (the old adage of “to the programmer with a hammer, everything looks like a thumb”).&lt;/p&gt;

&lt;p&gt;From personal experience, I observe that my thinking patterns are quite different when I program in a functional language, an imperative one or an object-oriented one. There is also a marked difference between programming in a statically or dynamically typed language.&lt;/p&gt;

&lt;p&gt;But what about the influence of the programmer’s native language? Most programming languages are based on English, and in particular function calls typically use English word order.&lt;/p&gt;

&lt;h2 id=&quot;arithmetic-in-english-and-flemish&quot;&gt;Arithmetic in English and Flemish&lt;/h2&gt;

&lt;p&gt;For example, let’s consider the common arithmetic operations +, -, *, /. If we use named functions rather than operators for these, and used the common parentheses-and-commas syntax for function calls, we get something like&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;A+B: add(A,B) 
A-B: subtract(A,B)
A*B: multiply(A,B)
A/B: divide(A,B)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In English we would express this most commonly as an infinitive or as an imperative. For the infinitive, we have:&lt;/p&gt;

&lt;!-- &lt;div class=&quot;highlight&quot; style=&quot;background-color: #eadcb2&quot;&gt;--&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;to add A and/to B
to subtract A and/from B
to multiply A and B
to divide A and/by B
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The pattern is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;to&apos; &amp;lt;verb&amp;gt; A &apos;and&apos; B&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the imperative, we have:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;add A and/to B
subtract A and/from B
multiply A and B
divide A and/by B
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The pattern is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;verb&amp;gt; A &apos;and&apos; B&lt;/code&gt;, so the same pattern apart from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to&lt;/code&gt;. And it is easy to see how this pattern informed the typical function call syntax &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;verb&amp;gt; &apos;(&apos; A &apos;,&apos; B &apos;)&apos;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, in Flemish (or Dutch), the order of the arguments is quite different. For the infinitive, we have:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;A en/bij B optellen; A optellen bij B
A en/van B aftrekken; A aftrekken van B
A en/met B vermenigvuldigen; A vermenigvuldigen met B
A en/door B delen; A delen door B
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first variant has the pattern &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A &apos;en&apos; B &amp;lt;verb&amp;gt;&lt;/code&gt;; the second variant needs a different preposition for each verb but the pattern is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A &amp;lt;verb&amp;gt; &amp;lt;preposition&amp;gt; B&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the imperative, we have:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tel A op bij B; tel A en/bij B op
trek A af van B; trek A en/van B af
vermenigvuldig A en/met B
deel A en/door B
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There is not just one single general pattern but three: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;verb&amp;gt; A &apos;en&apos; B&lt;/code&gt;, 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;verb&amp;gt; A &amp;lt;preposition&amp;gt; &amp;lt;preposition&amp;gt; B&lt;/code&gt; and  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;verb&amp;gt; A &amp;lt;preposition&amp;gt; B &amp;lt;preposition&amp;gt;&lt;/code&gt;, depending on whether the verb has a preposition as part of it or not, and on the position we choose for that preposition.&lt;/p&gt;

&lt;p&gt;So not only are word orders for infinitive and imperative quite different, there is no simple rule for the imperative word order. Which makes me wonder what programming languages would look like if their developers had not been English native speakers.&lt;/p&gt;

&lt;p&gt;That question becomes even more interesting for non-Indo-European languages, because despite the example above, there are still lots of grammatical similarities between languages such as English, French and German.&lt;/p&gt;

&lt;h2 id=&quot;japanese-natural-language-programming-languages&quot;&gt;Japanese natural-language programming languages&lt;/h2&gt;

&lt;p&gt;There is one such language that particularly interests me and that is Japanese. I have been learning it for a long time and written &lt;a href=&quot;https://quickandtastycooking.org.uk/articles/&quot;&gt;several posts on Japanese language related topics&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Besides having a very different grammar, Japanese has writing system that is a very different from the Latin alphabet as well as its own number system.&lt;/p&gt;

&lt;p&gt;So I decided to create a natural-language programming language based on Japanese.&lt;/p&gt;

&lt;p&gt;There are already several Japanese natural-language programming languages, all made by Japanese native speakers. &lt;a href=&quot;https://en.wikipedia.org/wiki/Non-English-based_programming_languages&quot;&gt;Wikipedia lists eight&lt;/a&gt; but there are actually only four that are still under active development: &lt;a href=&quot;https://dolittle.eplang.jp/&quot;&gt;Dolittle&lt;/a&gt;, &lt;a href=&quot;https://rdr.utopiat.net/&quot;&gt;Produire&lt;/a&gt;, &lt;a href=&quot;https://nadesi.com/top/&quot;&gt;Nadeshiko&lt;/a&gt; and &lt;a href=&quot;https://www.scripts-lab.co.jp/mind/whatsmind.html&quot;&gt;Mind&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Dolittle&lt;/em&gt; ドリトル is an object-oriented language specifically designed for teaching children to program and follows the &lt;a href=&quot;http://people.eecs.berkeley.edu/~bh/logo.html&quot;&gt;Logo&lt;/a&gt; tradition with a turtle to draw shapes.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Produire&lt;/em&gt; プロデル is an imperative and object-oriented language but more general purpose. It also has a turtle library, so education is definitely one of the main design purposes.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Nadeshiko&lt;/em&gt; なでしこ (meaning “pink”, the flower) is an open source general purpose imperative language.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Mind&lt;/em&gt; is also imperative. Although it is actually a &lt;a href=&quot;https://www.forth.com/&quot;&gt;Forth&lt;/a&gt;-style stack-based language, in general structure it is similar to the other three.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these language are complete with support for graphics, networking etc and their own IDE and/or web-based editor. They are practical programming languages, so they all support the use of Arabic numerals as well as operators for arithmetic, logic and comparison operations.&lt;/p&gt;

&lt;h2 id=&quot;haku&quot;&gt;Haku&lt;/h2&gt;

&lt;p&gt;My motivation to create Haku was not to create a practical language. I wanted to explore what the result is of creating a programming language based on a non-English language, in terms of syntax, grammar and vocabulary. In particular, I wanted to allow the programmer to control the register of the language to some extent (informal/polite/formal). &lt;a href=&quot;https://nadesi.com/v3/doc/index.php?%E6%96%87%E6%B3%95%2F%E6%95%AC%E8%AA%9E&amp;amp;show&quot;&gt;Nadeshiko&lt;/a&gt; and &lt;a href=&quot;https://www.scripts-lab.co.jp/mind/ver8/doc/02-Program-Hyoki.html#okurigana&quot;&gt;Mind&lt;/a&gt; allow this to some extent, but I wanted even more flexibility.&lt;/p&gt;

&lt;h3 id=&quot;grammar&quot;&gt;Grammar&lt;/h3&gt;

&lt;p&gt;My main motivation for creating Haku is the difference in grammar between Japanese and most Indo-European languages.&lt;/p&gt;

&lt;p&gt;Notions such as “noun”, “adjective”, “adverb” and “verb” are not quite so clearly defined in Japanese. For example, consider the word &lt;em&gt;yasashii&lt;/em&gt;, “kind”. A person who is kind is a &lt;em&gt;yasashii hito&lt;/em&gt;. A person who is not kind is a &lt;em&gt;yasashikunai hito&lt;/em&gt;. But in its own right, &lt;em&gt;yasashiku&lt;/em&gt; is and adverb, and &lt;em&gt;~nai&lt;/em&gt; is the plain negative verb ending, e.g. “I don’t understand” is &lt;em&gt;wakaranai&lt;/em&gt;. And this “adjective” can get a past tense: “the person who was not kind” is &lt;em&gt;yasashikunakatta hito&lt;/em&gt;. And if we chain adjectives, e.g. “a kind and and clever person”, we get &lt;em&gt;yasashikute kashikoi hito&lt;/em&gt;. And indeed we can have &lt;em&gt;yasashihunakute　kashikonkatta hito&lt;/em&gt;, “the kerson who was not kind and smart”. It is also very easy to nominalise a verb or verbalise a noun by adding a suffix.&lt;/p&gt;

&lt;p&gt;The word order in a sentence is also quite different from most Indo-European languages. The typical order is main topic, secondary topic(s), verb. The function of the topics is indicated with what is called a “particle”, a kind of suffix. For example, “I ate the pudding with a spoon” is &lt;em&gt;purin wo supuun de tabeta&lt;/em&gt;. In this example, the main topic “I” is implied. Japanese is quite a parsimonious language: whenever possible, implied topics are left out, to be inferred from the context.&lt;/p&gt;

&lt;p&gt;Finally, compared to Indo-European languages, verb conjugation serves a different purpose in Japanese. For example in English, French and German, tenses are mainly uses to give precise indications of the time and duration of the action: simple past, present continuous, future perfect continuous etc. Japanese has essentially two tenses: the past and the non-past; and a form to similar to the -ing form in English to indicated an ongoing action, although that is again a loose approximation. However, there are many tenses to indicate modifiers to the verb to say e.g. that something is possible, that the speaker wants something, that a third party wants something, that the speaker has begun to do something, that someone is doing someone a favour and of course to express the level of politeness. For example, &lt;em&gt;shachou ha kiite kuremashita&lt;/em&gt; “the boss did me the favour of listening to me” (the &lt;em&gt;~mashita&lt;/em&gt; is a polite verb form), or &lt;em&gt;wasurekaketeita&lt;/em&gt; “I had begun to forget” (&lt;em&gt;~ta&lt;/em&gt; is a plain past, rather than polite).&lt;/p&gt;

&lt;p&gt;Putting at least some of this grammar in the programming language seemed like an interesting challenge to me. In particular, I was interested in how programmers perceive functions calls. Some time ago I ran a poll about this, and 3/4 of respondents answered “imperative” (other options were infinitive, noun, -ing form).&lt;/p&gt;

&lt;p&gt;In Japanese, the imperative (&lt;em&gt;meireikei&lt;/em&gt;, “command form”) is rarely used. Therefore in Haku you can’t use this form. Instead, you can use the plain form, the polite &lt;em&gt;-masu&lt;/em&gt; form or the &lt;em&gt;-te&lt;/em&gt; form (like “-ing”), including &lt;em&gt;-te kudasai&lt;/em&gt; (similar to “please”). Whether a function is perceived as a verb or a noun is up to you, and the difference is clear from the syntax. If it is a noun, you can turn it into a verb by adding &lt;em&gt;suru&lt;/em&gt;, and if it is a verb, you can add the &lt;em&gt;no&lt;/em&gt; or &lt;em&gt;koto&lt;/em&gt; nominalisers. And you can conjugate the verb forms in many different ways, although in practice the verb ending has no semantic function in the Haku language.&lt;/p&gt;

&lt;h3 id=&quot;naming-and-giving-meaning&quot;&gt;Naming and giving meaning&lt;/h3&gt;

&lt;p&gt;In principle, a programming language does not need to be based on natural language at all. The notorious example is APL, which uses symbols for everything. Agda programmers also tends to use lots of mathematical symbols. It works because they are very familiar with those symbols. An interesting question is if an experienced programmer who does not know Japanese could understand a Haku program; or if not, what the minimal changes would be to make it understandable.&lt;/p&gt;

&lt;p&gt;To allow to investigate that question, the Scheme and Raku emitters for Haku support (limited) transliteration to Romaji. I have the intention (but maybe not the time) to create a Romaji version of Haku as well as a version that does not use any Japanese but keeps the word order.&lt;/p&gt;

&lt;h3 id=&quot;syntax-and-parsing&quot;&gt;Syntax and parsing&lt;/h3&gt;

&lt;p&gt;I also wanted the language to be closer, at lease visually, to literary Japanese. Therefore Haku does not use Roman letters, Arabic digits or common arithmetic, logical and comparison operators. It also supports top-to-bottom, right-to-left writing.&lt;/p&gt;

&lt;p&gt;Literary Japanese does not use spaces. So another question of interest to was how to tokenise a string of Japanese.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;There are three writing systems: &lt;em&gt;katakana&lt;/em&gt; (angular), &lt;em&gt;hiragana&lt;/em&gt; (squigly) and &lt;em&gt;kanji&lt;/em&gt; (complicated).&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;katakana&lt;/em&gt; is used in a similar way as italics, and also for loanwords and names of plants and animals.&lt;/li&gt;
  &lt;li&gt;Nouns, verb, adjectives and adverbs normally start with a &lt;em&gt;kanji&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;hiragana&lt;/em&gt; is used for verb/adjective/adverb endings and “particles”, small words or suffixes that help identify the words in a sentence.&lt;/li&gt;
  &lt;li&gt;A verb/adjective/adverb can’t end with a &lt;em&gt;hiragana&lt;/em&gt; character that represents a particle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we have some simple tokenisation rules:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;a sequence of &lt;em&gt;katakana&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;a &lt;em&gt;kanji&lt;/em&gt; followed by more &lt;em&gt;kanji&lt;/em&gt; or &lt;em&gt;hiragana&lt;/em&gt; that do not represent particles&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;hiragana&lt;/em&gt; that represent particles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is in fact a formalisation of the rules a human uses when reading Japanese.&lt;/p&gt;

&lt;p&gt;Where that fails, we can introduce parentheses. A human reader uses context, and a considerable amount of look-ahead parsing and backtracking, but that would make the parser very complex and slow.&lt;/p&gt;

&lt;p&gt;In practice, only specific adverbs and adjectives are used in Haku. For example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ラムダ|は|或|エクス|で|エクス|掛ける|エクス|です

ラムダ: katakana word
は: particle
或: pre-noun adjective
エクス: katakana word
で: particle
エクス: katakana word
掛ける: verb
エクス: katakana word　
です: verb (copula)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;number-system&quot;&gt;Number system&lt;/h3&gt;

&lt;p&gt;For large numbers, Japanese uses a number system based on multiples of ten thousand (called &lt;em&gt;myriads&lt;/em&gt;) rather than a thousand. A peculiar feature of this system is that there are &lt;em&gt;kanji&lt;/em&gt; for all powers of 10,000 up to 10&lt;sup&gt;48&lt;/sup&gt;. For more background on this, please read &lt;a href=&quot;https://quickandtastycooking.org.uk/articles/japanese-large-numbers/&quot;&gt;my article on this topic&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The consequence is that a number such as&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1,234,567,890 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;is composed as&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  (10 + 2) * 100,000,000 
+ (3 * 1000 + 4 * 100 + 5 * 10 + 6) * 10,000
+  7 * 1000 + 8 * 100 + 9 * 10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;which can is written in &lt;em&gt;kanji&lt;/em&gt; as&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;十二億三千四百五十六万七千八百九十
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are also &lt;em&gt;kanji&lt;/em&gt; for numbers smaller than one. They go down to 10&lt;sup&gt;-12&lt;/sup&gt; in powers of 10 and rational numbers are indicated with the &lt;em&gt;kanji&lt;/em&gt; 点 (&lt;em&gt;ten&lt;/em&gt;, “dot”). So&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;3.14159
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;can be written as&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; 三点一分四厘一毛五糸九忽 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Apart from this format, the decimal format is also used, and is indeed more common for rational numbers and also for years (and dates in general), e.g. 2021 is written 二〇二一 instead of 二千二十一. Haku supports all these formats.&lt;/p&gt;

&lt;h2 id=&quot;poetry&quot;&gt;Poetry&lt;/h2&gt;

&lt;p&gt;The expressiveness of Haku as a programming language is on purpose rather spartan. It is after all a “toy language”, an experimental rather than general-purpose language.&lt;/p&gt;

&lt;p&gt;I am more interested in the natural-language expressiveness of Haku, and for that my criterion  is: Can the programmer write poetry in it? Several of Haku’s features such as adjectives and verb conjugation (&lt;em&gt;okurigana&lt;/em&gt;) are there entirely to make Haku programs sufficiently expressive on the natural-language level to support this idea. For that reason, my &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/haku/src/branch/main/examples/yuki.haku&quot;&gt;favourite Haku program&lt;/a&gt; is one that demonstrates this ability:&lt;/p&gt;

&lt;div style=&quot;writing-mode: vertical-rl&quot;&gt;
&lt;pre&gt;
忘れるとは件で空のことです。

遠いとは物で物を見せるのことです。

本とは
記憶は「忘れられないあの冬の the new fallen snow」、
忘れかけてた遠い記憶
の事です
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;When run, this program prints out the string 「忘れられないあの冬の the new fallen snow」. The line that causes this string to be printed is&lt;/p&gt;

&lt;p&gt;忘れかけてた遠い記憶&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Wasurekaketeta tooi kioku&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is on the one hand an example of some of the Japanese grammar features that Haku supports:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;adjectives as functions: &lt;em&gt;tooi&lt;/em&gt; is a so-called “i-adjective”;&lt;/li&gt;
  &lt;li&gt;adjectival verbs: &lt;em&gt;wasurekaketeta&lt;/em&gt; is a verb used as an adjective;&lt;/li&gt;
  &lt;li&gt;complex verb conjucations: the plain form, used to define the function, is &lt;em&gt;wasureru&lt;/em&gt;. The form &lt;em&gt;~kakeru&lt;/em&gt; means “starting to” and the final ending &lt;em&gt;~ta&lt;/em&gt; is a plain past.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But on the other hand, it is also poetry.&lt;/p&gt;

&lt;h2 id=&quot;why-haku&quot;&gt;Why &lt;em&gt;haku&lt;/em&gt;?&lt;/h2&gt;

&lt;p&gt;I decided to call my language &lt;em&gt;haku&lt;/em&gt; because I like the sound of it, and also because that word can be written in many ways and mean many things in Japanese (in my dictionary there are 89 &lt;em&gt;kanji&lt;/em&gt; that have &lt;em&gt;haku&lt;/em&gt; as one of their possible pronunciations). I was definitely thinking about the character Haku from the &lt;a href=&quot;https://ghiblicollection.com/product/spirited-away-collector-s-edition?product_id=7231&quot;&gt;Studio Ghibli movie “Spirited Away”&lt;/a&gt;. Also, I like the resemblance with &lt;a href=&quot;https://raku.org&quot;&gt;Raku&lt;/a&gt;, the implementation language.&lt;/p&gt;

&lt;p&gt;If I had to pick a &lt;em&gt;kanji&lt;/em&gt;, I would write it 珀 (amber) or 魄 (soul, spirit).&lt;/p&gt;

        </content>
    </entry>
    
    <entry>
        <title>Haku: a Japanese programming language</title>
        <link href="https://limited.systems/articles/haku-in-raku/"/>
        <updated>2021-09-20T00:00:00+01:00</updated>
        <id>https://limited.systems/articles/haku-in-raku</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/haku-in-raku_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;Haku is a natural language functional programming language based on literary Japanese. This article is about the implementation of Haku in &lt;a href=&quot;https://raku.org&quot;&gt;Raku&lt;/a&gt;. You don’t need to know Japanese or &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/haku&quot;&gt;have read the Haku documentation&lt;/a&gt;. I you are not familiar with Raku, you might want to read my &lt;a href=&quot;https://limited.systems/articles/roles-as-adts-in-raku/#raku-intro&quot;&gt;quick introduction&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I do assume familiarity with the concepts of parsing, syntax tree and code generation. I you find you lack background for what follows, I recommend Andrew Shitov’s series of posts &lt;a href=&quot;https://andrewshitov.com/creating-a-compiler-with-raku/&quot;&gt;Creating a Compiler with Raku
&lt;/a&gt; which takes a step-by-step approach.&lt;/p&gt;

&lt;h2 id=&quot;haku&quot;&gt;Haku&lt;/h2&gt;

&lt;p&gt;Haku aims to be close to written Japanese, so it is written in a combination of the three Japanese writing systems &lt;em&gt;kanji&lt;/em&gt; (Chinese characters), &lt;em&gt;hiragana&lt;/em&gt; and &lt;em&gt;katakana&lt;/em&gt;, and Japanese punctuation. There are no spaces, and Haku does not use Arabic (or even Roman) digits nor any operators. The design of the language is explained &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/haku&quot;&gt;in more detail in the documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is an example of a small Haku program (for more examples see &lt;a href=&quot;https://codeberg.org/wimvanderbauwhede/haku/src/branch/main/examples&quot;&gt;the repo&lt;/a&gt;):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;本とは
「魄から楽まで」を見せる
の事です。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This translates as&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“main is: to show ‘From Haku to Raku’”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And the Raku version would be&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;say &apos;From Haku to Raku&apos;;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The strings “本とは” and “の事です。” indicate the start and end of the main program. “「魄から楽まで」” is a string constant. “見せる” is the print function. The ‘を’ indicates that anything before it is an argument of the function. The newlines in the example code are optional and purely there for readability. A Haku program is a single string without whitespace or newlines.&lt;/p&gt;

&lt;p&gt;The actual generated Raku code for this example is&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;use v6;
use HakuPrelude;

sub main() {
    show(&apos;魄から楽まで&apos;)
}

main();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To be even closer to literary Japanese, Haku programs can be written vertically from right to left:&lt;/p&gt;

&lt;div class=&quot;highlight&quot; style=&quot;writing-mode: vertical-rl&quot;&gt;
&lt;pre&gt;
忘れるとは
物で空
のことです。

遠いとは
条で条を見せる
のことです。

本とは
記憶は無、
忘れかけてた遠い記憶
の事です。
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The generated Raku code for this Haku program is again quite simple:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;use v6;
use HakuPrelude;

sub wasureru( \mono) {[]}

sub tooi( \jou) {show(jou)}

sub hon() {
    my \kioku = Nil;
    wasureru(tooi(kioku))
}

hon();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Haku is implemented in Raku. The Haku compiler is a source-to-source compiler (sometimes called &lt;em&gt;transpiler&lt;/em&gt;) which generates Raku source from the Haku source and executes it. Raku makes writing such a compiler easy in many ways:&lt;/p&gt;

&lt;h2 id=&quot;parsing-using-grammars&quot;&gt;Parsing using Grammars&lt;/h2&gt;

&lt;p&gt;I decided to implement Haku in Raku mostly because I wanted to use Raku’s &lt;a href=&quot;https://docs.raku.org/language/grammars&quot;&gt;Grammars&lt;/a&gt; feature, and it did not disappoint. A grammar is like a class, but instead of methods it has rules or tokens, which are the building blocks of the parser. Any token can be used in the definition of another token by enclosing it in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;...&amp;gt;&lt;/code&gt;, for example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;token adjective {
    &amp;lt;i-adjective&amp;gt; | &amp;lt;na-adjective&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The tokens &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i-adjective&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;na-adjective&lt;/code&gt; have been defined separately and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;adjective&lt;/code&gt; matches one or the other.&lt;/p&gt;

&lt;p&gt;I have always liked parser combinators (like &lt;a href=&quot;https://www.futurelearn.com/info/courses/functional-programming-haskell/0/steps/27222&quot;&gt;Parsec&lt;/a&gt; in Haskell) and from a certain angle, Raku’s Grammar’s are quite similar. They are both scannerless, i.e. there is no separate tokenisation step, and highly composable. Many of the features offered by Parsec (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;many&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oneOf&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sepBy&lt;/code&gt;) are available courtesy of Raku’s regexes.&lt;/p&gt;

&lt;p&gt;There are several features of Raku’s Grammars that helped to make the parser for Haku easy to implement.&lt;/p&gt;

&lt;h3 id=&quot;excellent-unicode-support&quot;&gt;Excellent Unicode support&lt;/h3&gt;

&lt;p&gt;I think Raku’s Unicode support is really excellent. For example, thanks to the support for Unicode blocks, I can simply write&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;token kanji {  
    &amp;lt;:Block(&apos;CJK Unified Ideographs&apos;)&amp;gt;
}  
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;rather than having to enumerate them all (there are 92,865 kanji in that block!). In fact, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;:...&amp;gt;&lt;/code&gt; syntax works for any Unicode property, not just for Blocks.&lt;/p&gt;

&lt;p&gt;Even better: I have some kanji that are reserved as keywords:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;token reserved-kanji { &apos;本&apos; | &apos;事&apos; | ... }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To make sure these are excluded from the valid kanji for Haku, I can simply use a set difference:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;token kanji {  
    &amp;lt;:Block(&apos;CJK Unified Ideographs&apos;) - reserved-kanji &amp;gt;
}  
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(One detail that bit me is that the equivalent syntax for a user-defined character class requires an explicit ‘+’ : &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;token set-difference { &amp;lt; +set1 -set2&amp;gt; }&lt;/code&gt; )&lt;/p&gt;

&lt;h3 id=&quot;tokens-and-rules&quot;&gt;Tokens and rules&lt;/h3&gt;

&lt;p&gt;Luckily, Raku does not assume by default that you want to parse something where whitespace can be ignored, or that you want to tokenise on whitespace. If you want to ignore whitespace, you can use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rule&lt;/code&gt;. But in Haku, extraneous whitespace is not allowed (except for newlines at certain locations). So I use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;token&lt;/code&gt; everywhere. (There is also &lt;a href=&quot;https://docs.raku.org/language/grammars#index-entry-declarator_token-Named_Regexes&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;regex&lt;/code&gt;, which backtracks&lt;/a&gt;. In Haku’s grammar I have not needed it.)&lt;/p&gt;

&lt;h3 id=&quot;very-powerful-regexes&quot;&gt;Very powerful regexes&lt;/h3&gt;

&lt;p&gt;As a lambdacamel, I’ve always been fond of Perl’s regexes, the now ubiquitous &lt;a href=&quot;https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions&quot;&gt;PCREs&lt;/a&gt;. Yet, &lt;a href=&quot;https://docs.raku.org/language/regexes&quot;&gt;Raku’s regexes&lt;/a&gt; go way beyond that in power, expressiveness and readability.&lt;/p&gt;

&lt;p&gt;For one thing, they are composable: you can defined a named regex with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;regex&lt;/code&gt; type and use it in subsequent regexes with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;...&amp;gt;&lt;/code&gt; syntax. Also, the care with which they have been designed makes them very easy to use.  For example, a negative look-ahead assertion is simply &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;no&amp;gt; &amp;lt;!before &amp;lt;koto&amp;gt; &amp;gt;&lt;/code&gt;; and the availability of both a try-in-order alternation (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;||&lt;/code&gt;) and longest-token match alternation (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|&lt;/code&gt;) is a huge boon. Another thing I like very much is the ability to make a character class non-capturing:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;    token lambda-expression { 
        &amp;lt;.aru&amp;gt; &amp;lt;variable-list&amp;gt; &amp;lt;.de&amp;gt; &amp;lt;expression&amp;gt; 
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;variable-list&amp;gt;&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;expression&amp;gt;&lt;/code&gt; will be captured, so a lot of the concrete syntax can be removed at parse time.&lt;/p&gt;

&lt;h3 id=&quot;grammar-composition-via-roles&quot;&gt;Grammar composition via roles&lt;/h3&gt;

&lt;p&gt;Roles (‘mixins’ in Ruby, ‘traits’ in Rust) define interfaces and/or implementation of those interfaces.&lt;br /&gt;
I found this a better fit for my purpose than the also-supported class inheritance. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;role Nouns does Characters {
    token sa { &apos;さ&apos; }
    token ki { &apos;き&apos; }
    # 一線 is OK,  一 is not OK, 線 is OK
    token noun { 
        &amp;lt;number-kanji&amp;gt;? &amp;lt;non-number-kanji&amp;gt; &amp;lt;kanji&amp;gt;* 
        [&amp;lt;sa&amp;gt;|&amp;lt;ki&amp;gt;]?
    }
}

role Identifiers 
does Verbs 
does Nouns 
does Adjectives 
does Variables 
{
    token nominaliser {
        | &amp;lt;no&amp;gt; &amp;lt;!before &amp;lt;koto&amp;gt; &amp;gt; 
        | &amp;lt;koto&amp;gt; &amp;lt;!before &amp;lt;desu&amp;gt; &amp;gt; 
    }
    # Identifiers are variables,
    # noun-style, verb-style
    # and adjective-style function names
    token identifier { 
        | &amp;lt;variable&amp;gt; 
        | &amp;lt;verb&amp;gt; &amp;lt;nominaliser&amp;gt;? 
        | &amp;lt;noun&amp;gt; &amp;lt;.sura&amp;gt;? 
        | &amp;lt;adjective&amp;gt; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(Although I would like a list syntax for this, something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;role Identifiers does Verbs, Nouns, Adjectives, Variables {...}&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;There is a lot more to grammars and regexes. The nice Raku folks on Twitter recommended me the book &lt;a href=&quot;https://link.springer.com/book/10.1007/978-1-4842-3228-6&quot;&gt;“Parsing with Perl 6 Regexes and Grammars” by Moritz Lenz&lt;/a&gt; and it was very useful in particular for debugging of the grammar and handling of error messages.&lt;/p&gt;

&lt;h2 id=&quot;abstract-syntax-tree-using-roles&quot;&gt;Abstract syntax tree using roles&lt;/h2&gt;

&lt;p&gt;I like to implement the abstract syntax tree (AST) as an algebraic data type, the way it is usually done in Haskell. In Raku, one way to do this is to use parametrised Roles &lt;a href=&quot;https://limited.systems/articles/roles-as-adts-in-raku/&quot;&gt;as I explained in an earlier post&lt;/a&gt;. Most of the AST maps directly to the toplevel parser for each role in my grammar, for example the lambda expression:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;role LambdaExpr[ @lambda-args, $expr] does HakuExpr {
    has Variable @.args = @lambda-args;
    has HakuExpr $.expr = $expr;
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;from-parse-tree-to-abstract-syntax-tree&quot;&gt;From parse tree to abstract syntax tree&lt;/h2&gt;

&lt;p&gt;Raku’s grammars provide a very convenient mechanism for turning the parse tree into an AST, called &lt;a href=&quot;https://docs.raku.org/language/grammars#index-entry-Actions&quot;&gt;Actions&lt;/a&gt;. Essentially, you create a class with a method with the same name as the token or rule in the Grammar. Each method gets the &lt;a href=&quot;https://docs.raku.org/type/Match&quot;&gt;Match object&lt;/a&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$/&lt;/code&gt;) created by the token as a positional argument.&lt;/p&gt;

&lt;p&gt;For example, to populate the AST node for a lambda expression from the parse tree:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;method lambda-expression($/) {
        my @args = $&amp;lt;variable-list&amp;gt;.made;
        my $expr = $&amp;lt;expression&amp;gt;.made;
        make LambdaExpr[@args,$expr].new;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The capturing tokens used in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lambda-expression&lt;/code&gt; token are accessible via the notation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$&amp;lt;...&amp;gt;&lt;/code&gt; which is shorthand for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$/&amp;lt;...&amp;gt;&lt;/code&gt;, i.e. they are named attributes of the current match object.&lt;/p&gt;

&lt;p&gt;In the Haku grammar, there are several tokens where the match is one from a list of alternatives, for example the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;expression&lt;/code&gt; token, which enumerates anything that is an expression in Haku. For such tokens I use the following code to “inherit” from the constituent tokens:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;method expression($/) { 
        make $/.values[0].made;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Because every match is a map with as keys the names of the capturing tokens, and because we know that in this case there will be only one token selected, we know the first element in the corresponding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;values&lt;/code&gt; list will be the match for that particular token.&lt;/p&gt;

&lt;h2 id=&quot;code-generation&quot;&gt;Code generation&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;haku.raku&lt;/code&gt; main program essentially does this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;my $hon_parse = 
    Haku.parse($program_str, :actions(HakuActions));
my $hon_raku_code =  
    ppHakuProgram($hon_parse.made);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The Haku program string is parsed using the Haku grammar and the methods defined in the corresponding HakuActions class are used to populate the AST. The toplevel parse tree node must be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$&amp;lt;haku-program&amp;gt;&lt;/code&gt;, and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;made&lt;/code&gt; method of this node returns the AST node &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HakuProgram&lt;/code&gt;.  The routine &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ppHakuProgram&lt;/code&gt; is the toplevel routine in the module &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Raku&lt;/code&gt;, which is the Raku emitter for Haku. (There is also a Scheme emitter, in the module &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Scheme&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;So &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ppHakuProgram($hon_parse.made)&lt;/code&gt; pretty-prints the HakuProgram AST node and thus the entire Haku program as Raku code.&lt;/p&gt;

&lt;p&gt;What I like about the role-based AST is that you can pattern match against the variants of a type using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;given/when&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;sub ppHakuExpr(\h) {            
    given h {
        when BindExpr { ... }
        when FunctionApplyExpr { ... }
        when ListExpr { ... }
        when MapExpr { ... }        
        when  IfExpr { ... }   
        when LetExpr { ... }
        when LambdaExpr { ... }        
        ...
        default {
            die &quot;TODO:&quot; ~ h.raku;
        }        
    }
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The Raku code corresponding to the Haku AST is quite straightforward, but there are a few things worth noting:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Because Haku’s variables are immutable, I use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\&lt;/code&gt; notation which means I don’t have to build a variable table with the sigils.&lt;/li&gt;
  &lt;li&gt;Because Haku is functional, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;let&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; are expressions, so in Raku I wrap them in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do {}&lt;/code&gt; block.&lt;/li&gt;
  &lt;li&gt;For partial application I use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.assuming()&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;In Haku, strings are lists. In Raku they aren’t. I created a small Prelude of functions, and the list manipulation functions in that Prelude use pattern matching on the type with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;given/when&lt;/code&gt; to see if the argument is a string or a list.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;running-the-generated-raku-code&quot;&gt;Running the generated Raku code&lt;/h2&gt;

&lt;p&gt;Running the generated Raku code is simple: I write the generated Raku code to a module and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require&lt;/code&gt; it. The generated code ends with a call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hon()&lt;/code&gt;, the main function in a Haku program, so this automatically executes the program.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;# Write the parsed program to a module 
&apos;Hon.rakumod&apos;.IO.spurt($hon_raku_code);

# Require the module. This will execute the program
require Hon;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Other things Haku makes really easy is to create command-line flags and document their usage:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-perl6&quot;&gt;sub USAGE() {
    print Q:to/EOH/;
    Usage: haku &amp;lt;Haku program, written horizontally or vertically, utf-8 text file&amp;gt;
        [--tategaki, -t] : do not run the program but print it vertically.
        [--miseru, -m] : just print the Raku source code, don&apos;t execute.
        ...
    EOH
}

unit sub MAIN(
          Str $src_file,
          Bool :t($tategaki) = False,   
          Bool :m($miseru) = False,
          ...
        );  

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;USAGE&lt;/code&gt; is called when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MAIN&lt;/code&gt; is called with the wrong (or no) arguments. Arguments of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MAIN&lt;/code&gt; prefixed with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:&lt;/code&gt; are flags. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unit sub&lt;/code&gt; means that anything after this declaration is part of the MAIN program, so no need for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{...}&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;to-conclude&quot;&gt;To conclude&lt;/h2&gt;

&lt;p&gt;This article shows the lazy programmer’s way to creating your own programming language: let Raku do all the hard work.&lt;/p&gt;

&lt;p&gt;Or to express it with a Haku program:&lt;/p&gt;

&lt;div style=&quot;writing-mode: vertical-rl&quot;&gt;
&lt;pre&gt;
本真とは
コンパイラを書いて、
プログラムを書いて、
プログラムを走らす
と言う事です。

&lt;/pre&gt;
&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;the truth:&lt;br /&gt;
write the compiler,&lt;br /&gt;
write the program,&lt;br /&gt;
run the program.&lt;/p&gt;
&lt;/blockquote&gt;


        </content>
    </entry>
    
    <entry>
        <title>Frugal computing </title>
        <link href="https://limited.systems/articles/frugal-computing/"/>
        <updated>2021-06-29T00:00:00+01:00</updated>
        <id>https://limited.systems/articles/frugal-computing</id>
        <author>
					<name>Wim Vanderbauwhede</name>
					<uri>https://limited.systems/</uri>
					
				</author>
        <content type="html">
        	&lt;img src=&quot;https://limited.systems/images/frugal-computing_1600x600.avif&quot;&gt;&lt;br/&gt;
        	&lt;p&gt;On the need for low-carbon and sustainable computing and the path towards zero-carbon computing.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://limited.systems/translations/fr&quot;&gt;Lisez en Français&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://limited.systems/translations/es&quot;&gt;Lea en Español&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;key-points&quot;&gt;Key points&lt;/h2&gt;

&lt;h3 id=&quot;the-problem&quot;&gt;The problem:&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;The current emissions from computing are about 2% of the world total but are projected to rise steeply over the next two decades. By 2040 emissions from computing alone will be more than of half the emissions level acceptable to keep global warming below 1.5°C. This growth in computing emissions is unsustainable: it would make it virtually impossible to meet the emissions warming limit.&lt;/li&gt;
  &lt;li&gt;The emissions from production of computing devices far exceed the emissions from operating them, so even if devices are more energy efficient producing more of them will make the emissions problem worse. Therefore we must extend the useful life of our computing devices.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;the-solution&quot;&gt;The solution:&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;As a society we need to start treating computational resources as finite and precious, to be utilised only when necessary, and as effectively as possible. We need &lt;em&gt;frugal computing&lt;/em&gt;: achieving the same results for less energy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;the-vision&quot;&gt;The vision:&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Imagine we can extend the useful life of our devices and even increase their capabilities without any increase in energy consumption, purely by improving the software.&lt;/li&gt;
  &lt;li&gt;Meanwhile, we will develop the technologies for the next generation of devices, designed for energy efficiency as well as long life.&lt;/li&gt;
  &lt;li&gt;Every subsequent cycle will last longer, until finally the world will have computing resources that last forever and hardly use any energy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;defining-computational-resources&quot;&gt;Defining computational resources&lt;/h2&gt;

&lt;p&gt;Computational resources are all resources of energy and material that are involved in any given task that requires computing. For example, when you perform a web search on your phone or participate in a video conference on your laptop, the computational resources involved are those for production and running of your phone or laptop, the mobile network or WiFi you are connected to, the fixed network it connects to, the data centres that perform the search or video delivery operations. If you are a scientist running a simulator in a supercomputer, then the computational resources involved are your desktop computer, the network and the supercomputer. For an industrial process control system, it is the production and operation of the Programmable Logic Controllers.&lt;/p&gt;

&lt;h2 id=&quot;computational-resources-are-finite&quot;&gt;Computational resources are finite&lt;/h2&gt;

&lt;p&gt;Since the start of general purpose computing in the 1970s, our society has been using increasing amounts of computational resources.&lt;/p&gt;

&lt;p&gt;For a long time the growth in computational capability as a function of device power consumption has literally been exponential, a trend expressed by &lt;a href=&quot;https://www.britannica.com/technology/Moores-law&quot;&gt;Moore’s law&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With this growth in computational capability, increasing use of computational resources has become pervasive in today’s society. Until recently, the total energy budget and carbon footprint resulting from the use of computational resources has been small compared to the world total. As a result, computational resources have until recently effectively been treated as unlimited.&lt;/p&gt;

&lt;p&gt;Because of this, the economics of hardware and software development have been built on the assumption that with every generation, performance would double for free. Now, this unlimited growth is no longer sustainable because of a combination of technological limitations and the climate emergency. Therefore, we need to do more with less.&lt;/p&gt;

&lt;p&gt;Moore’s law has effectively come to an end as integrated circuits can’t be scaled down any more. As a result, the improvement in performance per Watt is slowing down continuously. On the other hand, the demand for computational resources is set to increase considerably.&lt;/p&gt;

&lt;p&gt;The consequence is that at least for the next decades, growth in demand for computational resources will not be offset by increased power efficiency. Therefore with business as usual, the total energy budget and carbon footprint resulting from the use of computational resources will grow dramatically to become a major contributor to the world total.&lt;/p&gt;

&lt;p&gt;Furthermore, the resources required to create the compute devices and infrastructure are also finite, and the total energy budget and carbon footprint of production of compute devices is huge. Moore’s Law has conditioned us to doubling of performance ever two years, which has led to very short effective lifetimes of compute hardware. This rate of obsolescence of compute devices and software is entirely unsustainable.&lt;/p&gt;

&lt;p&gt;Therefore, as a society we need to start treating computational resources as finite and precious, to be utilised only when necessary, and as frugally as possible. And as computing scientists, we need to ensure that computing has the lowest possible energy consumption. And we should achieve this with the currently available technologies because the lifetimes of compute devices needs to be extended dramatically.&lt;/p&gt;

&lt;p&gt;I would like to call this “frugal computing”: achieving the same results for less energy by being more frugal with our computing resources.&lt;/p&gt;

&lt;h2 id=&quot;the-scale-of-the-problem&quot;&gt;The scale of the problem&lt;/h2&gt;

&lt;h3 id=&quot;meeting-the-climate-targets&quot;&gt;Meeting the climate targets&lt;/h3&gt;

&lt;p&gt;To limit global warming to 1.5°C, within the next decade a global reduction from 55 gigatonnes CO₂ equivalent (GtCO₂e) by 32 GtCO₂e to 23 GtCO₂e per year is needed &lt;a href=&quot;#5&quot;&gt;[5]&lt;/a&gt;. So by 2030 that would mean a necessary reduction in overall CO₂ emissions of more than 50%. By 2040, a further reduction to 13 GtCO₂e per year is necessary. According to the International Energy Agency &lt;a href=&quot;#10&quot;&gt;[10]&lt;/a&gt;, emissions from electricity are currently estimated at about 10 GtCO₂e. The global proportion of electricity from renewables is projected to rise from the current figure of 22% to slightly more than 30% by 2040 &lt;a href=&quot;#15&quot;&gt;[15]&lt;/a&gt;. A more optimistic scenario by the International Energy Agency &lt;a href=&quot;#17&quot;&gt;[17]&lt;/a&gt; projects 70% of electricity from renewables, but even in that scenario, generation from fossil fuels reduces only slightly, so there is only a slight reduction in emissions as a result.&lt;/p&gt;

&lt;p&gt;In other words, we cannot count on renewables to eliminate CO₂ emissions from electricity in time to meet the climate targets. Reducing the energy consumption is the only option.&lt;/p&gt;

&lt;h3 id=&quot;emissions-from-consumption-of-computational-resources&quot;&gt;Emissions from consumption of computational resources&lt;/h3&gt;

&lt;p&gt;The consequence of the end of Moore’s law was expressed most dramatically in a 2015 report by the Semiconductor Industry Association (SIA) “Rebooting the IT Revolution: a call to action” &lt;a href=&quot;#1&quot;&gt;[1]&lt;/a&gt;, which calculated that, based on projected growth rates and on the 2015 ITRS roadmap for CMOS chip engineering technologies &lt;a href=&quot;#16&quot;&gt;[16]&lt;/a&gt;,&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;computing will not be sustainable by 2040, when the energy required for computing will exceed the estimated world’s energy production.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It must be noted that this is purely the energy of the computing device, as explained in the report. The energy required by e.g. the data centre infrastructure and the network is not included.&lt;/p&gt;

&lt;p&gt;The SIA has reiterated this in their 2020 “Decadal Plan for Semiconductors” &lt;a href=&quot;#2&quot;&gt;[2]&lt;/a&gt;, although they have revised the projection based on a “market dynamics argument”:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If the exponential growth in compute energy is left unchecked, market dynamics will limit the growth of the computational capacity which would cause a flattening out the energy curve.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is merely an acknowledgement of the reality that the world’s energy production is not set to rise dramatically, and therefore increased demand will result in higher prices which will damp the demand. So computation is not actually going to exceed the world’s energy production.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Ever-rising energy demand for computing vs. global energy production is creating new risk, and new computing paradigms offer opportunities to dramatically improve energy efficiency.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the countries where most of the computational resources are consumed (US and EU), electricity production accounts currently for 25% of the total emissions &lt;a href=&quot;#4&quot;&gt;[4]&lt;/a&gt;. According to the SIA’s estimates, computation accounts currently for a little less than 10% of the total electricity production but is set to rise to about 30% by 2040. This would mean that, with business as usual, computational resources would be responsible for at least 10% of all global CO₂ emissions by 2040.&lt;/p&gt;

&lt;p&gt;The independent study “Assessing ICT global emissions footprint: Trends to 2040 &amp;amp; recommendations” &lt;a href=&quot;#3&quot;&gt;[3]&lt;/a&gt; corroborates the SIA figures: they estimate the computing greenhouse gas emissions for 2020 between 3.0% and 3.5% of the total, which is a bit higher than the SIA estimate of 2.5% because it does take into account networks and datacentres. Their projection for 2040 is 14% rather than 10%, which means a growth of 4x rather than 3x.&lt;/p&gt;

&lt;p&gt;To put it in absolute values, based on the above estimate, by 2040 energy consumption of compute devices would be responsible for 5 GtCO₂e, whereas the target for world total emissions from all sources is 13 GtCO₂e.&lt;/p&gt;

&lt;h3 id=&quot;emissions-from-production-of-computational-resources&quot;&gt;Emissions from production of computational resources&lt;/h3&gt;

&lt;p&gt;To make matters worse, the carbon emissions resulting from the production of computing devices exceeds those incurred during operation. This is a crucial point, because it means that we can’t rely on next-generation hardware technologies to save energy: the production of this next generation of devices will create more emissions than any operational gains can offset. It does not mean research into more efficient technologies should stop. But their deployment cycles should be much slower. Extending the useful life of compute technologies by improving the way we design and use software must become our priority.&lt;/p&gt;

&lt;p&gt;The report about the cost of planned obsolescence by the European Environmental Bureau &lt;a href=&quot;#7&quot;&gt;[7]&lt;/a&gt; makes the scale of the problem very clear. For laptops and similar computers, manufacturing, distribution and disposal account for 52% of their &lt;a href=&quot;https://www.sciencedirect.com/topics/earth-and-planetary-sciences/global-warming-potential&quot;&gt;Global Warming Potential&lt;/a&gt; (i.e. the amount of CO₂-equivalent emissions caused). For mobile phones, this is 72%. The report calculates that the lifetime of these devices should be at least 25 years to limit their Global Warming Potential. Currently, for laptops it is about 5 years and for mobile phones 3 years. According to &lt;a href=&quot;#8&quot;&gt;[8]&lt;/a&gt;, the typical lifetime for servers in data centres is also 3-5 years, which again falls short of these minimal requirements. According to this paper, the impact of manufacturing of the servers is 20% of the total, which would require an extension of the useful life to 11-18 years.&lt;/p&gt;

&lt;h3 id=&quot;the-total-emissions-cost-from-computing&quot;&gt;The total emissions cost from computing&lt;/h3&gt;

&lt;p&gt;Taking into account the carbon cost of both operation and production, computing would be responsible for 10 GtCO₂e by 2040, almost 80% of the acceptable CO₂ emissions budget &lt;a href=&quot;#2&quot;&gt;[2,3,14]&lt;/a&gt;.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;https://limited.systems/images/computing-emissions.avif&quot; alt=&quot;A graph with two bars: world emissions (55) and emissions from computing (0.1) in 2020; and for 2040, the world emissions target to limit warming to 1.5°C (13), and the projected emissions from computing (10)&quot; title=&quot;A graph with two bars: world emissions (55) and emissions from computing (0.1) in 2020; and for 2040, the world emissions target to limit warming to 1.5°C (13), and the projected emissions from computing (10)&quot; /&gt;
&lt;figcaption&gt;Actual and projected emissions from computing (production+operation), and 2040 emission target to limit warming to &amp;lt;1.5&amp;deg;C&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&quot;a-breakdown-per-device-type&quot;&gt;A breakdown per device type&lt;/h3&gt;

&lt;p&gt;To decide on the required actions to reduce emissions, it is important to look at the numbers of different types of devices and their energy usage. If we consider mobile phones as one category, laptops and desktops as another and servers as a third category, the questions are: how many devices are there in each category, and what is their energy consumption. The absolute numbers of devices in use are quite difficult to estimate, but the yearly sales figures &lt;a href=&quot;#10&quot;&gt;[10]&lt;/a&gt; and estimates for the energy consumption for each category &lt;a href=&quot;#11&quot;&gt;[11,12,13,14]&lt;/a&gt; are readily available from various sources. The tables below show the 2020 sales and yearly energy consumption estimates for each category of devices. A detailed analysis is presented in &lt;a href=&quot;#14&quot;&gt;[14]&lt;/a&gt;.&lt;/p&gt;

&lt;table&gt;
&lt;caption&gt;Number of devices sold worldwide in 2020&lt;/caption&gt;
&lt;tr&gt;&lt;th&gt;Device type&lt;/th&gt;&lt;th&gt;2020 sales&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Phones&lt;/td&gt;&lt;td&gt; 3000M&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Servers&lt;/td&gt;&lt;td&gt; 13M&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Tablets&lt;/td&gt;&lt;td&gt; 160M&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Displays&lt;/td&gt;&lt;td&gt; 40M&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Laptops&lt;/td&gt;&lt;td&gt; 280M&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Desktops&lt;/td&gt;&lt;td&gt; 80M&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;TVs&lt;/td&gt;&lt;td&gt;220M&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;IoT devices&lt;/td&gt;&lt;td&gt; 2000M&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;The energy consumption of all communication and computation technology currently in use in the world is currently around 3,000 TWh/y, about 11% of the world’s electricity consumption, projected to rise by 3-4 times by 2040 with business as usual according to &lt;a href=&quot;#2&quot;&gt;[2]&lt;/a&gt;. This is a conservative estimate: the study in &lt;a href=&quot;#14&quot;&gt;[14]&lt;/a&gt; includes a worst-case projection of a rise to 30,000 TWh (exceeding the current world electricity consumption) by 2030.&lt;/p&gt;

&lt;table&gt;
&lt;caption&gt;Yearly energy consumption estimates in TWh&lt;/caption&gt;
&lt;tr&gt;&lt;th&gt;Device type&lt;/th&gt;&lt;th&gt;TWh&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;TVs&lt;/td&gt;&lt;td&gt; 560&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Other Consumer devices&lt;/td&gt;&lt;td&gt; 240&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Fixed access network (wired+WiFi)&lt;/td&gt;&lt;td&gt; 900 + 500&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Mobile network&lt;/td&gt;&lt;td&gt; 100&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Data centres&lt;/td&gt;&lt;td&gt; 700&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Total&lt;/td&gt;&lt;td&gt; 3000&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;The above data make it clear which actions are necessary: the main carbon cost of phones, tablets and IoT devices is their production and the use of the mobile network, so we must extend their useful life very considerably and reduce network utilisation. Extending the life time is also the key action for datacentres and desktop computers, but their energy consumption also needs to be reduced considerably, as does the energy consumption of the wired, WiFi and mobile networks.&lt;/p&gt;

&lt;p&gt;From the technical side, these are primarily software issues: the hardware exists because of the software&lt;/p&gt;

&lt;h2 id=&quot;a-vision-for-low-carbon-and-sustainable-computing&quot;&gt;A vision for low carbon and sustainable computing&lt;/h2&gt;

&lt;p&gt;It is clear that urgent action is needed: in less than two decades, the global use of computational resources needs to be transformed radically. Otherwise, the world will fail to meet its climate targets, even with significant reductions in other emission areas. The carbon cost of both production and operation of the devices must be considerably reduced.&lt;/p&gt;

&lt;p&gt;To use devices for longer, a change in business models as well as consumer attitudes is needed. This requires raising awareness and education but also providing incentives for behavioural change. And to support devices for a long time, an infrastructure for repair and maintenance is needed, with long-term availability of parts, open repair manuals and training. To make all this happen, economic incentives and policies will be needed (e.g. taxation, regulation). Therefore we need to convince key decision makers in society, politics and business.&lt;/p&gt;

&lt;p&gt;Imagine that we can extend the useful life of our devices and even increase their capabilities, purely by improving the software. With every improvement, the computational capacity will in effect increase without any increase in energy consumption. Meanwhile, we will develop the technologies for the next generation of devices, designed for energy efficiency as well as long life. Every subsequent cycle will last longer, until finally the world will have computing resources that last forever and hardly use any energy.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;https://limited.systems/images/towards-zero-carbon-computing.avif&quot; alt=&quot;A graph with four trends: emissions from production, emissions in total, performance and emissions/performance.&quot; title=&quot;A graph with four trends: emissions from production, emissions in total, performance and emissions/performance.&quot; /&gt;
&lt;figcaption&gt;Towards zero carbon computing: increasing performance and lifetime and reducing emissions. Illustration with following assumptions: every new generation lasts twice as long as the previous one and cost half as much energy to produce; energy efficiency improves linearly with 5% per year.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This is a very challenging vision, spanning all aspects of computing science. To name just a few challenges:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We must design software so that it supports devices  with extended lifetimes.&lt;/li&gt;
  &lt;li&gt;We need software engineering strategies to handle the extended software life cycles, and in particular deal with &lt;a href=&quot;https://en.wikipedia.org/wiki/Technical_debt&quot;&gt;technical debt&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Longer life means more opportunities to exploit vulnerabilities, so we need better cyber security.&lt;/li&gt;
  &lt;li&gt;We need to develop new approaches to reduce overall energy consumption across the entire system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To address these challenges, action is needed on many fronts. What will you do to make frugal computing a reality?&lt;/p&gt;

&lt;h4 id=&quot;edits&quot;&gt;Edits&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;2023-03-06: edits to make it more clear that frugal computing is primarily a software issue.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;p&gt;&lt;small&gt;
  &lt;span id=&quot;1&quot;&gt;[1] &lt;a href=&quot;https://www.semiconductors.org/resources/rebooting-the-it-revolution-a-call-to-action-2/&quot;&gt;&lt;em&gt;“Rebooting the IT revolution: a call to action”&lt;/em&gt;, Semiconductor Industry Association/Semiconductor Research Corporation, Sept 2015&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;2&quot;&gt;[2] &lt;a href=&quot;https://www.src.org/about/decadal-plan/decadal-plan-full-report.pdf&quot;&gt;&lt;em&gt;“Full Report for the Decadal Plan for Semiconductors”&lt;/em&gt;, Semiconductor Industry Association/Semiconductor Research Corporation, Jan 2021&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;3&quot;&gt;[3] &lt;a href=&quot;https://www.sciencedirect.com/science/article/pii/S095965261733233X&quot;&gt;&lt;em&gt;“Assessing ICT global emissions footprint: Trends to 2040 &amp;amp; recommendations”&lt;/em&gt;, Lotﬁ Belkhir, Ahmed Elmeligi, Journal of Cleaner Production 177 (2018) 448–463&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;4&quot;&gt;[4] &lt;a href=&quot;https://www.epa.gov/ghgemissions/sources-greenhouse-gas-emissions&quot;&gt;&lt;em&gt;“Sources of Greenhouse Gas Emissions”&lt;/em&gt;, United States Environmental Protection Agency&lt;/a&gt;, Last updated on April 14, 2021&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;5&quot;&gt;[5] &lt;a href=&quot;https://www.unep.org/emissions-gap-report-2020&quot;&gt;&lt;em&gt;“Emissions Gap Report 2020”&lt;/em&gt;, UN Environment Programme, December 2020&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;6&quot;&gt;[6] &lt;a href=&quot;https://onlinelibrary.wiley.com/doi/full/10.1111/jiec.13123&quot;&gt;&lt;em&gt;“The link between product service lifetime and GHG emissions: A comparative study for different consumer products”&lt;/em&gt;, Simon Glöser-Chahoud, Matthias Pfaff, Frank Schultmann,  Journal of Industrial Ecology, 25 (2), pp 465-478, March 2021&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;7&quot;&gt;[7] &lt;a href=&quot;https://eeb.org/library/coolproducts-report/&quot;&gt;&lt;em&gt;“Cool products don’t cost the Earth – Report”&lt;/em&gt;, European Environmental Bureau, September 2019&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;8&quot;&gt;[8] &lt;a href=&quot;https://link.springer.com/article/10.1007/s11367-014-0838-7&quot;&gt;&lt;em&gt;“The life cycle assessment of a UK data centre”&lt;/em&gt;, Beth Whitehead, Deborah Andrews, Amip Shah, Graeme Maidment, Building and Environment 93 (2015) 395–405, January 2015&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;9&quot;&gt;[9] &lt;a href=&quot;https://www.statista.com&quot;&gt;Statista&lt;/a&gt;,  retrieved June 2021&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;10&quot;&gt;[10] &lt;a href=&quot;https://www.iea.org/reports/global-energy-CO₂-status-report-2019/emissions&quot;&gt;&lt;em&gt;“Global Energy &amp;amp; CO₂ Status Report”&lt;/em&gt;, International Energy Agency, March 2019&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;11&quot;&gt;[11] &lt;a href=&quot;https://link.springer.com/article/10.1007/s11367-015-0909-4&quot;&gt;&lt;em&gt;“Redefining scope: the true environmental impact of smartphones?”&lt;/em&gt;, James Suckling, Jacquetta Lee, The International Journal of Life Cycle Assessment volume 20, pages 1181–1196 (2015)&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;12&quot;&gt;[12] &lt;a href=&quot;https://www.racksolutions.com/news/blog/server-rack-power-consumption-calculator/&quot;&gt;&lt;em&gt;“Server Rack Power Consumption Calculator”&lt;/em&gt;, Rack Solutions, Inc., July 2019&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;13&quot;&gt;[13] &lt;a href=&quot;https://www.sciencedirect.com/science/article/pii/S111001682030524X&quot;&gt;&lt;em&gt;“Analysis of energy consumption and potential energy savings of an institutional building in Malaysia”&lt;/em&gt;, Siti Birkha Mohd Ali,  M.Hasanuzzaman, N.A.Rahim, M.A.A.Mamun, U.H.Obaidellah,  Alexandria Engineering Journal, Volume 60, Issue 1, February 2021, Pages 805-820&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;14&quot;&gt;[14] &lt;a href=&quot;https://doi.org/10.3390/challe6010117&quot;&gt;&lt;em&gt;“On Global Electricity Usage of Communication Technology: Trends to 2030”&lt;/em&gt;, Anders S. G. Andrae, Tomas Edler, Challenges 2015, 6(1), 117-157 &lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;15&quot;&gt;[15] &lt;a href=&quot;https://www.bp.com/en/global/corporate/energy-economics/energy-outlook.html&quot;&gt;&lt;em&gt;“BP Energy Outlook: 2020 Edition”&lt;/em&gt;,BP plc&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;16&quot;&gt;[16] &lt;a href=&quot;https://www.semiconductors.org/resources/2015-international-technology-roadmap-for-semiconductors-itrs/&quot;&gt;&lt;em&gt;“2015 International Technology Roadmap for Semiconductors (ITRS)”&lt;/em&gt;, Semiconductor Industry Association, June 2015&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
  &lt;span id=&quot;17&quot;&gt;[17] &lt;a href=&quot;https://iea.blob.core.windows.net/assets/deebef5d-0c34-4539-9d0c-10b13d840027/NetZeroby2050-ARoadmapfortheGlobalEnergySector_CORR.pdf&quot;&gt;&lt;em&gt;“Net Zero by 2050 — A Roadmap for the Global Energy Sector”&lt;/em&gt;, International Energy Agency, October 2021&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/small&gt;&lt;/p&gt;

        </content>
    </entry>
    
</feed>