<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel>
        <title>blog :: Brent -> [String]</title>
        <link>http://byorgey.github.io/blog</link>
        <description><![CDATA[Brent Yorgey's academic blog]]></description>
        <atom:link href="http://byorgey.github.io/blog/rss.xml" rel="self"
                   type="application/rss+xml" />
        <lastBuildDate>Fri, 09 Jan 2026 00:00:00 UT</lastBuildDate>
        <item>
    <title>Disco Live!</title>
    <link>http://byorgey.github.io/blog/posts/2026/01/09/disco-live.html</link>
    <description><![CDATA[
<h1>Disco Live!</h1>

<div class="info">
  Posted on January  9, 2026
  
  
  <br />
  Tagged <a title="All pages tagged &#39;disco&#39;." href="/tag/disco.html" rel="tag">disco</a>, <a title="All pages tagged &#39;web&#39;." href="/tag/web.html" rel="tag">web</a>, <a title="All pages tagged &#39;WASM&#39;." href="/tag/WASM.html" rel="tag">WASM</a>, <a title="All pages tagged &#39;UI&#39;." href="/tag/UI.html" rel="tag">UI</a>, <a title="All pages tagged &#39;teaching&#39;." href="/tag/teaching.html" rel="tag">teaching</a>, <a title="All pages tagged &#39;discrete&#39;." href="/tag/discrete.html" rel="tag">discrete</a>, <a title="All pages tagged &#39;math&#39;." href="/tag/math.html" rel="tag">math</a>, <a title="All pages tagged &#39;Haskell&#39;." href="/tag/Haskell.html" rel="tag">Haskell</a>
  
</div>

<a href="https://share.joinmastodon.org/#text=Disco Live! https://byorgey.github.io/blog/posts/2026/01/09/disco-live.html" target="_blank" rel="noopener">Share on <svg role="img" aria-label="Mastodon" height="1em" viewBox="0 0 74 79" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M73.7014 17.4323C72.5616 9.05152 65.1774 2.4469 56.424 1.1671C54.9472 0.950843 49.3518 0.163818 36.3901 0.163818H36.2933C23.3281 0.163818 20.5465 0.950843 19.0697 1.1671C10.56 2.41145 2.78877 8.34604 0.903306 16.826C-0.00357854 21.0022 -0.100361 25.6322 0.068112 29.8793C0.308275 35.9699 0.354874 42.0498 0.91406 48.1156C1.30064 52.1448 1.97502 56.1419 2.93215 60.0769C4.72441 67.3445 11.9795 73.3925 19.0876 75.86C26.6979 78.4332 34.8821 78.8603 42.724 77.0937C43.5866 76.8952 44.4398 76.6647 45.2833 76.4024C47.1867 75.8033 49.4199 75.1332 51.0616 73.9562C51.0841 73.9397 51.1026 73.9184 51.1156 73.8938C51.1286 73.8693 51.1359 73.8421 51.1368 73.8144V67.9366C51.1364 67.9107 51.1302 67.8852 51.1186 67.862C51.1069 67.8388 51.0902 67.8184 51.0695 67.8025C51.0489 67.7865 51.0249 67.7753 50.9994 67.7696C50.9738 67.764 50.9473 67.7641 50.9218 67.7699C45.8976 68.9569 40.7491 69.5519 35.5836 69.5425C26.694 69.5425 24.3031 65.3699 23.6184 63.6327C23.0681 62.1314 22.7186 60.5654 22.5789 58.9744C22.5775 58.9477 22.5825 58.921 22.5934 58.8965C22.6043 58.8721 22.621 58.8505 22.6419 58.8336C22.6629 58.8167 22.6876 58.8049 22.714 58.7992C22.7404 58.7934 22.7678 58.794 22.794 58.8007C27.7345 59.9796 32.799 60.5746 37.8813 60.5733C39.1036 60.5733 40.3223 60.5733 41.5447 60.5414C46.6562 60.3996 52.0437 60.1408 57.0728 59.1694C57.1983 59.1446 57.3237 59.1233 57.4313 59.0914C65.3638 57.5847 72.9128 52.8555 73.6799 40.8799C73.7086 40.4084 73.7803 35.9415 73.7803 35.4523C73.7839 33.7896 74.3216 23.6576 73.7014 17.4323ZM61.4925 47.3144H53.1514V27.107C53.1514 22.8528 51.3591 20.6832 47.7136 20.6832C43.7061 20.6832 41.6988 23.2499 41.6988 28.3194V39.3803H33.4078V28.3194C33.4078 23.2499 31.3969 20.6832 27.3894 20.6832C23.7654 20.6832 21.9552 22.8528 21.9516 27.107V47.3144H13.6176V26.4937C13.6176 22.2395 14.7157 18.8598 16.9118 16.3545C19.1772 13.8552 22.1488 12.5719 25.8373 12.5719C30.1064 12.5719 33.3325 14.1955 35.4832 17.4394L37.5587 20.8853L39.6377 17.4394C41.7884 14.1955 45.0145 12.5719 49.2765 12.5719C52.9614 12.5719 55.9329 13.8552 58.2055 16.3545C60.4017 18.8574 61.4997 22.2371 61.4997 26.4937L61.4925 47.3144Z" fill="inherit"/></svg></a>
<section>
<p>A couple months ago, <a href="https://byorgey.github.io/blog/posts/2025/11/10/disco-web-ui.html">I asked for
help</a>
creating a web interface for
<a href="https://github.com/disco-lang/disco">Disco</a>, a
student-oriented programming language for teaching functional
programming and discrete mathematics. I am very happy to report that
<a href="https://apfelmus.nfshost.com/">Heinrich Apfelmus</a> responded to the
call, and this is the result:</p>
<p><a href="https://disco-lang.github.io/disco-live/">Disco Live!</a></p>
<p>It’s fairly bare bones at the moment, but it’s a fantastic place to
start, and far more than I would have been able to accomplish in a few
weeks. Give it a try, and let me know of any bugs you find! You are
also very welcome to contribute fixes, features, etc. on GitHub:</p>
<ul>
<li><a href="https://github.com/disco-lang/disco-live">The disco-live repo</a></li>
<li><a href="https://github.com/disco-lang/disco">The repo for disco itself</a></li>
</ul>
<p>If you want to know more about Disco, you can <a href="http://ozark.hendrix.edu/~yorgey/forest/yorgey-disco-2023/index.xml">read a paper about it
here</a>,
or <a href="https://disco-lang.readthedocs.io/en/latest/">read the language documentation</a>.</p>

</section>

<script data-isso="https://comments.byorgey.com/" src="https://comments.byorgey.com/js/embed.min.js"></script>
<section id="isso-thread"  data-title="Disco Live!" >
  <noscript>Javascript needs to be activated to view comments.</noscript>
</section>

]]></description>
    <pubDate>Fri, 09 Jan 2026 00:00:00 UT</pubDate>
    <guid>http://byorgey.github.io/blog/posts/2026/01/09/disco-live.html</guid>
    <dc:creator>Brent Yorgey</dc:creator>
</item>
<item>
    <title>Call for collaboration: Disco web UI</title>
    <link>http://byorgey.github.io/blog/posts/2025/11/10/disco-web-ui.html</link>
    <description><![CDATA[
<h1>Call for collaboration: Disco web UI</h1>

<div class="info">
  Posted on November 10, 2025
  
  
  <br />
  Tagged <a title="All pages tagged &#39;disco&#39;." href="/tag/disco.html" rel="tag">disco</a>, <a title="All pages tagged &#39;web&#39;." href="/tag/web.html" rel="tag">web</a>, <a title="All pages tagged &#39;WASM&#39;." href="/tag/WASM.html" rel="tag">WASM</a>, <a title="All pages tagged &#39;UI&#39;." href="/tag/UI.html" rel="tag">UI</a>, <a title="All pages tagged &#39;teaching&#39;." href="/tag/teaching.html" rel="tag">teaching</a>, <a title="All pages tagged &#39;discrete&#39;." href="/tag/discrete.html" rel="tag">discrete</a>, <a title="All pages tagged &#39;math&#39;." href="/tag/math.html" rel="tag">math</a>, <a title="All pages tagged &#39;Haskell&#39;." href="/tag/Haskell.html" rel="tag">Haskell</a>
  
</div>

<a href="https://share.joinmastodon.org/#text=Call for collaboration: Disco web UI https://byorgey.github.io/blog/posts/2025/11/10/disco-web-ui.html" target="_blank" rel="noopener">Share on <svg role="img" aria-label="Mastodon" height="1em" viewBox="0 0 74 79" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M73.7014 17.4323C72.5616 9.05152 65.1774 2.4469 56.424 1.1671C54.9472 0.950843 49.3518 0.163818 36.3901 0.163818H36.2933C23.3281 0.163818 20.5465 0.950843 19.0697 1.1671C10.56 2.41145 2.78877 8.34604 0.903306 16.826C-0.00357854 21.0022 -0.100361 25.6322 0.068112 29.8793C0.308275 35.9699 0.354874 42.0498 0.91406 48.1156C1.30064 52.1448 1.97502 56.1419 2.93215 60.0769C4.72441 67.3445 11.9795 73.3925 19.0876 75.86C26.6979 78.4332 34.8821 78.8603 42.724 77.0937C43.5866 76.8952 44.4398 76.6647 45.2833 76.4024C47.1867 75.8033 49.4199 75.1332 51.0616 73.9562C51.0841 73.9397 51.1026 73.9184 51.1156 73.8938C51.1286 73.8693 51.1359 73.8421 51.1368 73.8144V67.9366C51.1364 67.9107 51.1302 67.8852 51.1186 67.862C51.1069 67.8388 51.0902 67.8184 51.0695 67.8025C51.0489 67.7865 51.0249 67.7753 50.9994 67.7696C50.9738 67.764 50.9473 67.7641 50.9218 67.7699C45.8976 68.9569 40.7491 69.5519 35.5836 69.5425C26.694 69.5425 24.3031 65.3699 23.6184 63.6327C23.0681 62.1314 22.7186 60.5654 22.5789 58.9744C22.5775 58.9477 22.5825 58.921 22.5934 58.8965C22.6043 58.8721 22.621 58.8505 22.6419 58.8336C22.6629 58.8167 22.6876 58.8049 22.714 58.7992C22.7404 58.7934 22.7678 58.794 22.794 58.8007C27.7345 59.9796 32.799 60.5746 37.8813 60.5733C39.1036 60.5733 40.3223 60.5733 41.5447 60.5414C46.6562 60.3996 52.0437 60.1408 57.0728 59.1694C57.1983 59.1446 57.3237 59.1233 57.4313 59.0914C65.3638 57.5847 72.9128 52.8555 73.6799 40.8799C73.7086 40.4084 73.7803 35.9415 73.7803 35.4523C73.7839 33.7896 74.3216 23.6576 73.7014 17.4323ZM61.4925 47.3144H53.1514V27.107C53.1514 22.8528 51.3591 20.6832 47.7136 20.6832C43.7061 20.6832 41.6988 23.2499 41.6988 28.3194V39.3803H33.4078V28.3194C33.4078 23.2499 31.3969 20.6832 27.3894 20.6832C23.7654 20.6832 21.9552 22.8528 21.9516 27.107V47.3144H13.6176V26.4937C13.6176 22.2395 14.7157 18.8598 16.9118 16.3545C19.1772 13.8552 22.1488 12.5719 25.8373 12.5719C30.1064 12.5719 33.3325 14.1955 35.4832 17.4394L37.5587 20.8853L39.6377 17.4394C41.7884 14.1955 45.0145 12.5719 49.2765 12.5719C52.9614 12.5719 55.9329 13.8552 58.2055 16.3545C60.4017 18.8574 61.4997 22.2371 61.4997 26.4937L61.4925 47.3144Z" fill="inherit"/></svg></a>
<section>
<p><strong>tl;dr</strong>: I would like to have a web interface for <a href="https://github.com/disco-lang/disco">Disco</a>, a
student-oriented programming language for teaching functional
programming and discrete mathematics, which is implemented in Haskell.
I’m looking for others interested to help build it. If you like
building web stuff with Haskell compiled to WASM and want to have a
positive impact on students learning mathematics and functional
programming, <a href="http://ozark.hendrix.edu/~yorgey/forest/contact/index.xml">get in touch</a>!</p>
<section id="disco" class="level2">
<h2>Disco</h2>
<p>For the past nine (!) years I have been developing
<a href="https://github.com/disco-lang/disco">Disco</a>, a functional teaching
language for use in a discrete mathematics course. It features
first-class functions, polymorphism, and recursive algebraic data
types, along with various built-in mathematical niceties and syntax
that is designed to be close to mathematical practice.</p>
<p>As a simple example, here’s a recursive function in Disco to compute the
<a href="https://oeis.org/A002487">hyperbinary numbers</a>:</p>
<pre><code>h : N -&gt; N
h(0)      = 1
h(2n)     = h(n) + h(n .- 1)
h(2n + 1) = h(n)</code></pre>
<p>Since recursive functions in Disco are automatically memoized, this
evaluates almost instantly even on very large numbers:</p>
<pre><code>Disco&gt; h(1000000)
1287</code></pre>
<p>If you want to know more about Disco, you can <a href="http://ozark.hendrix.edu/~yorgey/forest/yorgey-disco-2023/index.xml">read a paper about it
here</a>,
or <a href="https://disco-lang.readthedocs.io/en/latest/">read the language documentation</a>.</p>
</section>
<section id="the-problem" class="level2">
<h2>The problem</h2>
<p>I want students in my <a href="https://hendrix-cs.github.io/math240/">Discrete Mathematics
course</a> (or any Discrete
Mathematics course) to be able to use Disco: to play around at a REPL,
write and test their own code, and so on.</p>
<p>However, getting students to install Haskell and build Disco from
source is a total non-starter, for multiple reasons. Some students in
the course are not all that tech-savvy. Some students don’t even have
their own computer, or the computer they do have chokes when trying to
compile a large Haskell project (<em>e.g.</em> because of limited memory).
Even aside from those issues, I simply don’t want to spend time and
effort helping students install stuff at the beginning of the semester
(at least not in this class).</p>
</section>
<section id="old-solution-replit" class="level2">
<h2>Old solution: Replit</h2>
<p>For a couple years, students were able to use Disco via a site called
Replit, which provided free educational accounts, and supported
arbitrary Nix configurations. Since the <a href="https://hackage.haskell.org/package/disco">disco package on
Hackage</a> was picked up by
nixpkgs, it was possible to spin up a Disco interpreter on Replit in
just a few seconds. Replit provided a virtual file system, an editor,
and, of course, a REPL.</p>
<p>This was a great solution while it lasted, but sadly it is no longer
viable:</p>
<ul>
<li>Disco has been broken in nixpkgs for a while now, and I have no idea
how to fix it.</li>
<li>Even if I could fix it, Replit has stopped supporting free education
accounts, and started trying to shove LLMs into everything, making it no
longer a viable teaching platform.</li>
</ul>
</section>
<section id="solution-criteria" class="level2">
<h2>Solution criteria</h2>
<p>There are a few non-negotiable criteria that any solution must meet:</p>
<ul>
<li><p>It must either run on existing cloud infrastructure, or run
completely client-side. I do not want to be in the business of
running a server, or of worrying about mitigating DOS attacks (by
which I mean students accidentally running infinite loops generating
infinite amounts of memory). I also do not want to be in the
business of managing accounts and logins.</p></li>
<li><p>Students should not have to install anything. As I mentioned
before, this is a nonstarter for some students.</p></li>
<li><p>It should allow students to work at a Disco REPL, and also test
their own Disco code.</p></li>
</ul>
</section>
<section id="potential-solutions" class="level2">
<h2>Potential solutions</h2>
<ul>
<li><p>Of course, a really nice solution would be to find an existing site
which replicates some of the functionality we used to have with
Replit and supports educational uses. I kind of doubt such a thing
exists, though I would be happy to be wrong about this.</p></li>
<li><p>Another possibility is to have students use VSCode in their browsers
via GitHub; to make this work we would have to add LSP support to
Disco and package it up appropriately. I’m not really excited about
using GitHub for this, although implementing LSP for Disco is
independently a great idea.</p></li>
<li><p>The other solution I can think of is to compile Disco to WASM, and
build a web UI on top of it, so that the whole thing runs in the
student’s browser. I spent some time on this last year and
successfully got Disco to compile to WASM, but didn’t make it any
farther than that. Honestly, I simply don’t know anything about web
development, and I am not very motivated to learn.</p></li>
</ul>
</section>
<section id="ui-levels" class="level2">
<h2>UI levels</h2>
<p>Running with the last idea above (WASM + a custom web UI), what could
such a thing look like? What features would we want? Here are some
different solutions I could imagine, in increasing order of effort.</p>
<ul>
<li><p><strong>Level 0</strong> would be to have just a web-based REPL. Students can
edit Disco code on their own device, upload it to the website, then
evaluate expressions at the REPL. Having to reupload their code
every time they make changes would be annoying, but this would still
be better than nothing.</p></li>
<li><p><strong>Level 1</strong> would be to have a web-based editor and REPL. Students
can type code in the editor, then push a button to load it into the
REPL and play with it.</p></li>
<li><p><strong>Level 2</strong> would be to have a web-based filesystem + editor + REPL.
Students can see a list of multiple files, edit them individually, and
load any of them into the REPL. The filesystem must live on their own
computer, not on a remote server; but it could be their real
filesystem, or a virtual filesystem.</p></li>
</ul>
<p>I don’t know how difficult any of these are; I would assume that
at least some of them can be achieved by gluing together some existing
Javascript components (e.g. <a href="https://codemirror.net/">CodeMirror</a>?).
I’m sure it will require extending Disco itself with some new APIs,
but I can definitely work on that part once I know what would be needed.</p>
<p>If you know how to build web UIs like this and are interested in
helping, <a href="http://ozark.hendrix.edu/~yorgey/forest/contact/index.xml">get in touch</a>!</p>
</section>

</section>

<script data-isso="https://comments.byorgey.com/" src="https://comments.byorgey.com/js/embed.min.js"></script>
<section id="isso-thread"  data-title="Call for collaboration: Disco web UI" >
  <noscript>Javascript needs to be activated to view comments.</noscript>
</section>

]]></description>
    <pubDate>Mon, 10 Nov 2025 00:00:00 UT</pubDate>
    <guid>http://byorgey.github.io/blog/posts/2025/11/10/disco-web-ui.html</guid>
    <dc:creator>Brent Yorgey</dc:creator>
</item>
<item>
    <title>Decidable equality for indexed data types, take 2</title>
    <link>http://byorgey.github.io/blog/posts/2025/08/22/OneLevelTypesIndexed2.lagda.html</link>
    <description><![CDATA[
<h1>Decidable equality for indexed data types, take 2</h1>

<div class="info">
  Posted on August 22, 2025
  
  
  <br />
  Tagged <a title="All pages tagged &#39;agda&#39;." href="/tag/agda.html" rel="tag">agda</a>, <a title="All pages tagged &#39;equality&#39;." href="/tag/equality.html" rel="tag">equality</a>, <a title="All pages tagged &#39;path&#39;." href="/tag/path.html" rel="tag">path</a>, <a title="All pages tagged &#39;dependent&#39;." href="/tag/dependent.html" rel="tag">dependent</a>, <a title="All pages tagged &#39;indexed&#39;." href="/tag/indexed.html" rel="tag">indexed</a>, <a title="All pages tagged &#39;agda&#39;." href="/tag/agda.html" rel="tag">agda</a>
  
</div>

<a href="https://share.joinmastodon.org/#text=Decidable equality for indexed data types, take 2 https://byorgey.github.io/blog/posts/2025/08/22/OneLevelTypesIndexed2.lagda.html" target="_blank" rel="noopener">Share on <svg role="img" aria-label="Mastodon" height="1em" viewBox="0 0 74 79" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M73.7014 17.4323C72.5616 9.05152 65.1774 2.4469 56.424 1.1671C54.9472 0.950843 49.3518 0.163818 36.3901 0.163818H36.2933C23.3281 0.163818 20.5465 0.950843 19.0697 1.1671C10.56 2.41145 2.78877 8.34604 0.903306 16.826C-0.00357854 21.0022 -0.100361 25.6322 0.068112 29.8793C0.308275 35.9699 0.354874 42.0498 0.91406 48.1156C1.30064 52.1448 1.97502 56.1419 2.93215 60.0769C4.72441 67.3445 11.9795 73.3925 19.0876 75.86C26.6979 78.4332 34.8821 78.8603 42.724 77.0937C43.5866 76.8952 44.4398 76.6647 45.2833 76.4024C47.1867 75.8033 49.4199 75.1332 51.0616 73.9562C51.0841 73.9397 51.1026 73.9184 51.1156 73.8938C51.1286 73.8693 51.1359 73.8421 51.1368 73.8144V67.9366C51.1364 67.9107 51.1302 67.8852 51.1186 67.862C51.1069 67.8388 51.0902 67.8184 51.0695 67.8025C51.0489 67.7865 51.0249 67.7753 50.9994 67.7696C50.9738 67.764 50.9473 67.7641 50.9218 67.7699C45.8976 68.9569 40.7491 69.5519 35.5836 69.5425C26.694 69.5425 24.3031 65.3699 23.6184 63.6327C23.0681 62.1314 22.7186 60.5654 22.5789 58.9744C22.5775 58.9477 22.5825 58.921 22.5934 58.8965C22.6043 58.8721 22.621 58.8505 22.6419 58.8336C22.6629 58.8167 22.6876 58.8049 22.714 58.7992C22.7404 58.7934 22.7678 58.794 22.794 58.8007C27.7345 59.9796 32.799 60.5746 37.8813 60.5733C39.1036 60.5733 40.3223 60.5733 41.5447 60.5414C46.6562 60.3996 52.0437 60.1408 57.0728 59.1694C57.1983 59.1446 57.3237 59.1233 57.4313 59.0914C65.3638 57.5847 72.9128 52.8555 73.6799 40.8799C73.7086 40.4084 73.7803 35.9415 73.7803 35.4523C73.7839 33.7896 74.3216 23.6576 73.7014 17.4323ZM61.4925 47.3144H53.1514V27.107C53.1514 22.8528 51.3591 20.6832 47.7136 20.6832C43.7061 20.6832 41.6988 23.2499 41.6988 28.3194V39.3803H33.4078V28.3194C33.4078 23.2499 31.3969 20.6832 27.3894 20.6832C23.7654 20.6832 21.9552 22.8528 21.9516 27.107V47.3144H13.6176V26.4937C13.6176 22.2395 14.7157 18.8598 16.9118 16.3545C19.1772 13.8552 22.1488 12.5719 25.8373 12.5719C30.1064 12.5719 33.3325 14.1955 35.4832 17.4394L37.5587 20.8853L39.6377 17.4394C41.7884 14.1955 45.0145 12.5719 49.2765 12.5719C52.9614 12.5719 55.9329 13.8552 58.2055 16.3545C60.4017 18.8574 61.4997 22.2371 61.4997 26.4937L61.4925 47.3144Z" fill="inherit"/></svg></a>
<section>
<p>In a <a href="https://byorgey.github.io/blog/posts/2024/09/09/OneLevelTypesIndexed.lagda.html">post from a year
ago</a>,
I explored how to prove decidable equality in Agda of a particular
indexed data type. Recently, I discovered a different way to
accomplish the same thing, without resorting to embedded sigma types.</p>
<p>This post is literate Agda; you can <a href="https://github.com/byorgey/blog/blob/main/posts/2025/08/22/OneLevelTypesIndexed2.lagda.md">download it
here</a>
if you want to play along. I tested everything here with Agda version
2.6.4.3 and version 2.0 of the standard library. (I assume it would
also work with more recent versions, but haven’t tested it.)</p>
<section id="background" class="level2">
<h2>Background</h2>
<p><em>This section is repeated from my <a href="https://byorgey.github.io/blog/posts/2024/09/09/OneLevelTypesIndexed.lagda.html">previous
post</a>,
which I assume no one remembers.</em></p>
<p>First, some imports and a module declaration. Note that the entire
development is parameterized by some abstract set <code>B</code> of base types,
which must have decidable equality.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">open</span> <span class="kw">import</span> Data<span class="ot">.</span>Product <span class="kw">using</span> <span class="ot">(</span>Σ <span class="ot">;</span> <span class="ot">_</span>×<span class="ot">_</span> <span class="ot">;</span> <span class="ot">_</span>,<span class="ot">_</span> <span class="ot">;</span> -,<span class="ot">_</span> <span class="ot">;</span> proj₁ <span class="ot">;</span> proj₂<span class="ot">)</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">open</span> <span class="kw">import</span> Data<span class="ot">.</span>Product<span class="ot">.</span>Properties <span class="kw">using</span> <span class="ot">(</span>≡-dec<span class="ot">)</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">open</span> <span class="kw">import</span> Function <span class="kw">using</span> <span class="ot">(_</span>∘<span class="ot">_)</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">open</span> <span class="kw">import</span> Relation<span class="ot">.</span>Binary <span class="kw">using</span> <span class="ot">(</span>DecidableEquality<span class="ot">)</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="kw">open</span> <span class="kw">import</span> Relation<span class="ot">.</span>Binary<span class="ot">.</span>PropositionalEquality <span class="kw">using</span> <span class="ot">(_</span>≡<span class="ot">_</span> <span class="ot">;</span> refl<span class="ot">)</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">open</span> <span class="kw">import</span> Relation<span class="ot">.</span>Nullary<span class="ot">.</span>Decidable <span class="kw">using</span> <span class="ot">(</span>yes<span class="ot">;</span> no<span class="ot">;</span> Dec<span class="ot">)</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> OneLevelTypesIndexed2 <span class="ot">(</span>B <span class="ot">:</span> <span class="dt">Set</span><span class="ot">)</span> <span class="ot">(</span>≟B <span class="ot">:</span> DecidableEquality B<span class="ot">)</span> <span class="kw">where</span></span></code></pre></div>
<p>We’ll work with a simple type system containing base types, function
types, and some distinguished type constructor □. So far, this is
just to give some context; it is not the final version of the code we
will end up with, so we stick it in a local module so it won’t end up
in the top-level namespace.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> Unindexed <span class="kw">where</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">data</span> Ty <span class="ot">:</span> <span class="dt">Set</span> <span class="kw">where</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    base <span class="ot">:</span> B <span class="ot">→</span> Ty</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="ot">_</span>⇒<span class="ot">_</span> <span class="ot">:</span> Ty <span class="ot">→</span> Ty <span class="ot">→</span> Ty</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    □<span class="ot">_</span> <span class="ot">:</span> Ty <span class="ot">→</span> Ty</span></code></pre></div>
<p>For example, if <span class="math inline">\(X\)</span> and <span class="math inline">\(Y\)</span> are base types, then we could write down a
type like <span class="math inline">\(\square ((\square \square X \to Y) \to \square Y)\)</span>:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">infixr</span> <span class="dv">2</span> <span class="ot">_</span>⇒<span class="ot">_</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">infix</span> <span class="dv">30</span> □<span class="ot">_</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">postulate</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    BX BY <span class="ot">:</span> B</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>  X <span class="ot">:</span> Ty</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>  X <span class="ot">=</span> base BX</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>  Y <span class="ot">:</span> Ty</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>  Y <span class="ot">=</span> base BY</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>  example <span class="ot">:</span> Ty</span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>  example <span class="ot">=</span> □ <span class="ot">((</span>□ □ X ⇒ Y<span class="ot">)</span> ⇒ □ Y<span class="ot">)</span></span></code></pre></div>
<p>However, for reasons that would take us too far afield in this blog
post, I <em>don’t</em> want to allow immediately nested boxes, like <span class="math inline">\(\square
\square X\)</span>. We can still have multiple boxes in a type, and even
boxes nested inside of other boxes, as long as there is at least one
arrow in between. In other words, I only want to rule out boxes
immediately applied to another type with an outermost box. So we
don’t want to allow the example type given above (since it contains
<span class="math inline">\(\square \square X\)</span>), but, for example, <span class="math inline">\(\square ((\square X \to Y)
\to \square Y)\)</span> would be OK.</p>
</section>
<section id="two-encodings" class="level2">
<h2>Two encodings</h2>
<p>In my <a href="https://byorgey.github.io/blog/posts/2024/09/09/OneLevelTypesIndexed.lagda.html">previous blog
post</a>,
I ended up with the following encoding of types indexed by a <code>Boxity</code>,
which records the number of top-level boxes. Since the boxity of the
arguments to an arrow type do not matter, we make them sigma types
that package up a boxity with a type having that boxity. I was then
able to define decidable equality for <code>ΣTy</code> and <code>Ty</code> by mutual
recursion.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> Boxity <span class="ot">:</span> <span class="dt">Set</span> <span class="kw">where</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  ₀ <span class="ot">:</span> Boxity</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  ₁ <span class="ot">:</span> Boxity</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="kw">variable</span> b b₁ b₂ b₃ b₄ <span class="ot">:</span> Boxity</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> WithSigma <span class="kw">where</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  ΣTy <span class="ot">:</span> <span class="dt">Set</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">data</span> Ty <span class="ot">:</span> Boxity <span class="ot">→</span> <span class="dt">Set</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>  ΣTy <span class="ot">=</span> Σ Boxity Ty</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">data</span> Ty <span class="kw">where</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>    □<span class="ot">_</span> <span class="ot">:</span> Ty ₀ <span class="ot">→</span> Ty ₁</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>    base <span class="ot">:</span> B <span class="ot">→</span> Ty ₀</span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a>    <span class="ot">_</span>⇒<span class="ot">_</span> <span class="ot">:</span> ΣTy <span class="ot">→</span> ΣTy <span class="ot">→</span> Ty ₀</span></code></pre></div>
<p>The problem is that working with this definition of <code>Ty</code> is really
annoying! Every time we construct or pattern-match on an arrow type,
we have to package up each argument type into a dependent pair with
its <code>Boxity</code>; this introduces syntactic clutter, and in many cases we
know exactly what the <code>Boxity</code> has to be, so it’s not even
informative. The version we really want looks more like this:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> Ty <span class="ot">:</span> Boxity <span class="ot">→</span> <span class="dt">Set</span> <span class="kw">where</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  base <span class="ot">:</span> B <span class="ot">→</span> Ty ₀</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  <span class="ot">_</span>⇒<span class="ot">_</span> <span class="ot">:</span> <span class="ot">{</span>b₁ b₂ <span class="ot">:</span> Boxity<span class="ot">}</span> <span class="ot">→</span> Ty b₁ <span class="ot">→</span> Ty b₂ <span class="ot">→</span> Ty ₀</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  □<span class="ot">_</span> <span class="ot">:</span> Ty ₀ <span class="ot">→</span> Ty ₁</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="kw">infixr</span> <span class="dv">2</span> <span class="ot">_</span>⇒<span class="ot">_</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="kw">infix</span> <span class="dv">30</span> □<span class="ot">_</span></span></code></pre></div>
<p>In this version, the boxities of the arguments to the arrow
constructor are just implicit parameters of the arrow constructor
itself. Previously, I was unable to get decidable equality to go
through for this version… but just the other day, I finally realized
how to make it work!</p>
</section>
<section id="path-dependent-equality" class="level2">
<h2>Path-dependent equality</h2>
<p>The key trick that makes everything work is to define a
<em>path-dependent equality</em> type. I <a href="https://martinescardo.github.io/dependent-equality-lecture/DependentEquality.html">learned this from Martín
Escardó</a>.
The idea is that we can express equality between two indexed things
with different indices, as long as we also have an equality between
the indices.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ot">_</span>≡⟦<span class="ot">_</span>⟧<span class="ot">_</span> <span class="ot">:</span> <span class="ot">{</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">{</span>B <span class="ot">:</span> A <span class="ot">→</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">{</span>a₀ a₁ <span class="ot">:</span> A<span class="ot">}</span> <span class="ot">→</span> B a₀ <span class="ot">→</span> a₀ ≡ a₁ <span class="ot">→</span> B a₁ <span class="ot">→</span> <span class="dt">Set</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>b₀ ≡⟦ refl ⟧ b₁   <span class="ot">=</span>   b₀ ≡ b₁</span></code></pre></div>
<p>That’s exactly what we need here: the ability to express
equality between <code>Ty</code> values, which may be indexed by different
boxities—as long as we know that the boxities are equal.</p>
</section>
<section id="decidable-equality-for-ty" class="level2">
<h2>Decidable equality for <code>Ty</code></h2>
<p>We can now use this to directly encode decidable equality for <code>Ty</code>.
First, we can easily define decidable equality for <code>Boxity</code>.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>Boxity-≟ <span class="ot">:</span> DecidableEquality Boxity</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>Boxity-≟ ₀ ₀ <span class="ot">=</span> yes refl</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>Boxity-≟ ₀ ₁ <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">()</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>Boxity-≟ ₁ ₀ <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">()</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>Boxity-≟ ₁ ₁ <span class="ot">=</span> yes refl</span></code></pre></div>
<p>Here is the type of the decision procedure: given two <code>Ty</code> values
which may have <em>different</em> boxities, we decide whether or not we can
produce a witness to their equality. Such a witness consists of a
<em>pair</em> of (1) a proof that the boxities are equal, and (2) a proof
that the types are equal, depending on (1).<span class="sidenote-wrapper"><label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote">We would really like to
write this as <code>Σ (b₁ ≡ b₂) λ p → σ ≡⟦ p ⟧ τ</code>, but for some reason Agda
requires us to fill in some extra implicit arguments before it is
happy that everything is unambiguous, <a href="https://github.com/agda/agda/issues/2264">requiring some ugly syntax</a>.<br />
<br />
</span></span></p>
<div class="sourceCode" id="cb8"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>Ty-≟′ <span class="ot">:</span> <span class="ot">(</span>σ <span class="ot">:</span> Ty b₁<span class="ot">)</span> <span class="ot">→</span> <span class="ot">(</span>τ <span class="ot">:</span> Ty b₂<span class="ot">)</span> <span class="ot">→</span> Dec <span class="ot">(</span>Σ <span class="ot">(</span>b₁ ≡ b₂<span class="ot">)</span> <span class="ot">λ</span> p <span class="ot">→</span> <span class="ot">_</span>≡⟦<span class="ot">_</span>⟧<span class="ot">_</span> <span class="ot">{_}</span> <span class="ot">{</span>Ty<span class="ot">}</span> σ p τ<span class="ot">)</span></span></code></pre></div>
<p>Before showing the definition of <code>Ty-≟′</code>, let’s see that we can use it
to easily define both a boxity-homogeneous version of decidable
equality for <code>Ty</code>, as well as decidable equality for <code>Σ Boxity Ty</code>:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>Ty-≟ <span class="ot">:</span> DecidableEquality <span class="ot">(</span>Ty b<span class="ot">)</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>Ty-≟ <span class="ot">{</span>b<span class="ot">}</span> σ τ <span class="kw">with</span> Ty-≟′ σ τ</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="ot">...</span> <span class="ot">|</span> no σ≢τ <span class="ot">=</span> no <span class="ot">(λ</span> σ≡τ <span class="ot">→</span> σ≢τ <span class="ot">(</span> refl , σ≡τ<span class="ot">))</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="ot">...</span> <span class="ot">|</span> yes <span class="ot">(</span>refl , σ≡τ<span class="ot">)</span> <span class="ot">=</span> yes σ≡τ</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>ΣTy-≟ <span class="ot">:</span> DecidableEquality <span class="ot">(</span>Σ Boxity Ty<span class="ot">)</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>ΣTy-≟ <span class="ot">(_</span> , σ<span class="ot">)</span> <span class="ot">(_</span> , τ<span class="ot">)</span> <span class="kw">with</span> Ty-≟′ σ τ</span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a><span class="ot">...</span> <span class="ot">|</span> no σ≢τ <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">{</span> refl <span class="ot">→</span> σ≢τ <span class="ot">(</span>refl , refl<span class="ot">)</span> <span class="ot">}</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a><span class="ot">...</span> <span class="ot">|</span> yes <span class="ot">(</span>refl , refl<span class="ot">)</span> <span class="ot">=</span> yes refl</span></code></pre></div>
<p>A lot of pattern matching on <code>refl</code> and everything falls out quite easily.</p>
<p>And now the definition of <code>Ty-≟′</code>. It looks complicated, but it is
actually not very difficult. The most interesting case is when
comparing two arrow types for equality: we must first compare the
boxities of the arguments, then consider the arguments themselves once
we know the boxities are equal.</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>Ty-≟′ <span class="ot">(</span>□ σ<span class="ot">)</span> <span class="ot">(</span>□ τ<span class="ot">)</span> <span class="kw">with</span> Ty-≟′ σ τ</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="ot">...</span> <span class="ot">|</span> yes <span class="ot">(</span>refl , refl<span class="ot">)</span> <span class="ot">=</span> yes <span class="ot">(</span>refl , refl<span class="ot">)</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="ot">...</span> <span class="ot">|</span> no σ≢τ <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">{</span> <span class="ot">(</span>refl , refl<span class="ot">)</span> <span class="ot">→</span> σ≢τ <span class="ot">(</span>refl , refl<span class="ot">)</span> <span class="ot">}</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>Ty-≟′ <span class="ot">(</span>base S<span class="ot">)</span> <span class="ot">(</span>base T<span class="ot">)</span> <span class="kw">with</span> ≟B S T</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="ot">...</span> <span class="ot">|</span> yes refl <span class="ot">=</span> yes <span class="ot">(</span>refl , refl<span class="ot">)</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="ot">...</span> <span class="ot">|</span> no S≢T <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">{</span> <span class="ot">(</span>refl , refl<span class="ot">)</span> <span class="ot">→</span> S≢T refl <span class="ot">}</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>Ty-≟′ <span class="ot">(_</span>⇒<span class="ot">_</span> <span class="ot">{</span>b₁<span class="ot">}</span> <span class="ot">{</span>b₂<span class="ot">}</span> σ₁ σ₂<span class="ot">)</span> <span class="ot">(_</span>⇒<span class="ot">_</span> <span class="ot">{</span>b₃<span class="ot">}</span> <span class="ot">{</span>b₄<span class="ot">}</span> τ₁ τ₂<span class="ot">)</span> <span class="kw">with</span> Boxity-≟ b₁ b₃ <span class="ot">|</span> Boxity-≟ b₂ b₄ <span class="ot">|</span> Ty-≟′ σ₁ τ₁ <span class="ot">|</span> Ty-≟′ σ₂ τ₂</span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="ot">...</span> <span class="ot">|</span> no b₁≢b₃ <span class="ot">|</span> <span class="ot">_</span> <span class="ot">|</span> <span class="ot">_</span> <span class="ot">|</span> <span class="ot">_</span> <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">{</span> <span class="ot">(</span>refl , refl<span class="ot">)</span> <span class="ot">→</span> b₁≢b₃ refl <span class="ot">}</span></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="ot">...</span> <span class="ot">|</span> yes <span class="ot">_</span> <span class="ot">|</span> no b₂≢b₄ <span class="ot">|</span> <span class="ot">_</span> <span class="ot">|</span> <span class="ot">_</span> <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">{</span> <span class="ot">(</span>refl , refl<span class="ot">)</span> <span class="ot">→</span> b₂≢b₄ refl <span class="ot">}</span></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a><span class="ot">...</span> <span class="ot">|</span> yes <span class="ot">_</span> <span class="ot">|</span> yes <span class="ot">_</span> <span class="ot">|</span> no σ₁≢τ₁ <span class="ot">|</span> <span class="ot">_</span> <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">{</span> <span class="ot">(</span>refl , refl<span class="ot">)</span> <span class="ot">→</span> σ₁≢τ₁ <span class="ot">(</span>refl , refl<span class="ot">)</span> <span class="ot">}</span></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a><span class="ot">...</span> <span class="ot">|</span> yes <span class="ot">_</span> <span class="ot">|</span> yes <span class="ot">_</span> <span class="ot">|</span> yes <span class="ot">_</span> <span class="ot">|</span> no σ₂≢τ₂ <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">{</span> <span class="ot">(</span>refl , refl<span class="ot">)</span> <span class="ot">→</span> σ₂≢τ₂ <span class="ot">(</span>refl , refl<span class="ot">)</span> <span class="ot">}</span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a><span class="ot">...</span> <span class="ot">|</span> yes <span class="ot">_</span> <span class="ot">|</span> yes <span class="ot">_</span> <span class="ot">|</span> yes <span class="ot">(</span>refl , refl<span class="ot">)</span> <span class="ot">|</span> yes <span class="ot">(</span>refl , refl<span class="ot">)</span> <span class="ot">=</span> yes <span class="ot">(</span>refl , refl<span class="ot">)</span></span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a>Ty-≟′ <span class="ot">(</span>□ <span class="ot">_)</span> <span class="ot">(</span>base <span class="ot">_)</span> <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">()</span></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a>Ty-≟′ <span class="ot">(</span>□ <span class="ot">_)</span> <span class="ot">(_</span> ⇒ <span class="ot">_)</span> <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">()</span></span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a>Ty-≟′ <span class="ot">(</span>base <span class="ot">_)</span> <span class="ot">(</span>□ <span class="ot">_)</span> <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">()</span></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a>Ty-≟′ <span class="ot">(</span>base <span class="ot">_)</span> <span class="ot">(_</span> ⇒ <span class="ot">_)</span> <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">{</span> <span class="ot">(</span>refl , <span class="ot">())</span> <span class="ot">}</span></span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a>Ty-≟′ <span class="ot">(_</span> ⇒ <span class="ot">_)</span> <span class="ot">(</span>□ <span class="ot">_)</span> <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">()</span></span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a>Ty-≟′ <span class="ot">(_</span> ⇒ <span class="ot">_)</span> <span class="ot">(</span>base <span class="ot">_)</span> <span class="ot">=</span> no <span class="ot">λ</span> <span class="ot">{</span> <span class="ot">(</span>refl , <span class="ot">())</span> <span class="ot">}</span></span></code></pre></div>
</section>

</section>

<script data-isso="https://comments.byorgey.com/" src="https://comments.byorgey.com/js/embed.min.js"></script>
<section id="isso-thread"  data-title="Decidable equality for indexed data types, take 2" >
  <noscript>Javascript needs to be activated to view comments.</noscript>
</section>

]]></description>
    <pubDate>Fri, 22 Aug 2025 00:00:00 UT</pubDate>
    <guid>http://byorgey.github.io/blog/posts/2025/08/22/OneLevelTypesIndexed2.lagda.html</guid>
    <dc:creator>Brent Yorgey</dc:creator>
</item>
<item>
    <title>Competitive programming in Haskell: sparse tables</title>
    <link>http://byorgey.github.io/blog/posts/2025/07/18/sparse-table.html</link>
    <description><![CDATA[
<h1>Competitive programming in Haskell: sparse tables</h1>

<div class="info">
  Posted on July 18, 2025
  
  
  <br />
  Tagged <a title="All pages tagged &#39;monoid&#39;." href="/tag/monoid.html" rel="tag">monoid</a>, <a title="All pages tagged &#39;semigroup&#39;." href="/tag/semigroup.html" rel="tag">semigroup</a>, <a title="All pages tagged &#39;idempotent&#39;." href="/tag/idempotent.html" rel="tag">idempotent</a>, <a title="All pages tagged &#39;range&#39;." href="/tag/range.html" rel="tag">range</a>, <a title="All pages tagged &#39;query&#39;." href="/tag/query.html" rel="tag">query</a>, <a title="All pages tagged &#39;sum&#39;." href="/tag/sum.html" rel="tag">sum</a>, <a title="All pages tagged &#39;sparse&#39;." href="/tag/sparse.html" rel="tag">sparse</a>, <a title="All pages tagged &#39;table&#39;." href="/tag/table.html" rel="tag">table</a>, <a title="All pages tagged &#39;Haskell&#39;." href="/tag/Haskell.html" rel="tag">Haskell</a>, <a title="All pages tagged &#39;competitive programming&#39;." href="/tag/competitive%20programming.html" rel="tag">competitive programming</a>
  
</div>

<a href="https://share.joinmastodon.org/#text=Competitive programming in Haskell: sparse tables https://byorgey.github.io/blog/posts/2025/07/18/sparse-table.html" target="_blank" rel="noopener">Share on <svg role="img" aria-label="Mastodon" height="1em" viewBox="0 0 74 79" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M73.7014 17.4323C72.5616 9.05152 65.1774 2.4469 56.424 1.1671C54.9472 0.950843 49.3518 0.163818 36.3901 0.163818H36.2933C23.3281 0.163818 20.5465 0.950843 19.0697 1.1671C10.56 2.41145 2.78877 8.34604 0.903306 16.826C-0.00357854 21.0022 -0.100361 25.6322 0.068112 29.8793C0.308275 35.9699 0.354874 42.0498 0.91406 48.1156C1.30064 52.1448 1.97502 56.1419 2.93215 60.0769C4.72441 67.3445 11.9795 73.3925 19.0876 75.86C26.6979 78.4332 34.8821 78.8603 42.724 77.0937C43.5866 76.8952 44.4398 76.6647 45.2833 76.4024C47.1867 75.8033 49.4199 75.1332 51.0616 73.9562C51.0841 73.9397 51.1026 73.9184 51.1156 73.8938C51.1286 73.8693 51.1359 73.8421 51.1368 73.8144V67.9366C51.1364 67.9107 51.1302 67.8852 51.1186 67.862C51.1069 67.8388 51.0902 67.8184 51.0695 67.8025C51.0489 67.7865 51.0249 67.7753 50.9994 67.7696C50.9738 67.764 50.9473 67.7641 50.9218 67.7699C45.8976 68.9569 40.7491 69.5519 35.5836 69.5425C26.694 69.5425 24.3031 65.3699 23.6184 63.6327C23.0681 62.1314 22.7186 60.5654 22.5789 58.9744C22.5775 58.9477 22.5825 58.921 22.5934 58.8965C22.6043 58.8721 22.621 58.8505 22.6419 58.8336C22.6629 58.8167 22.6876 58.8049 22.714 58.7992C22.7404 58.7934 22.7678 58.794 22.794 58.8007C27.7345 59.9796 32.799 60.5746 37.8813 60.5733C39.1036 60.5733 40.3223 60.5733 41.5447 60.5414C46.6562 60.3996 52.0437 60.1408 57.0728 59.1694C57.1983 59.1446 57.3237 59.1233 57.4313 59.0914C65.3638 57.5847 72.9128 52.8555 73.6799 40.8799C73.7086 40.4084 73.7803 35.9415 73.7803 35.4523C73.7839 33.7896 74.3216 23.6576 73.7014 17.4323ZM61.4925 47.3144H53.1514V27.107C53.1514 22.8528 51.3591 20.6832 47.7136 20.6832C43.7061 20.6832 41.6988 23.2499 41.6988 28.3194V39.3803H33.4078V28.3194C33.4078 23.2499 31.3969 20.6832 27.3894 20.6832C23.7654 20.6832 21.9552 22.8528 21.9516 27.107V47.3144H13.6176V26.4937C13.6176 22.2395 14.7157 18.8598 16.9118 16.3545C19.1772 13.8552 22.1488 12.5719 25.8373 12.5719C30.1064 12.5719 33.3325 14.1955 35.4832 17.4394L37.5587 20.8853L39.6377 17.4394C41.7884 14.1955 45.0145 12.5719 49.2765 12.5719C52.9614 12.5719 55.9329 13.8552 58.2055 16.3545C60.4017 18.8574 61.4997 22.2371 61.4997 26.4937L61.4925 47.3144Z" fill="inherit"/></svg></a>
<section>
<p>Continuing a <a href="https://byorgey.github.io/blog/posts/2025/06/23/range-queries-classified.html">series of
posts</a>
on techniques for calculating <em>range queries</em>, today I will present
the <a href="https://cp-algorithms.com/data_structures/sparse-table.html"><em>sparse table</em> data structure</a>, for doing fast range queries on a
static sequence with an <em>idempotent</em> combining operation.</p>
<section id="motivation" class="level2">
<h2>Motivation</h2>
<p>In my <a href="https://byorgey.github.io/blog/posts/2025/06/27/prefix-sums.html">previous
post</a>,
we saw that if we have a static sequence and a binary operation with a
<em>group</em> structure (<em>i.e.</em> every element has an inverse), we can
precompute a prefix sum table in <span class="math inline">\(O(n)\)</span> time, and then use it to answer
arbitrary range queries in <span class="math inline">\(O(1)\)</span> time.</p>
<p>What if we don’t have inverses? We can’t use prefix sums, but can we
do something else that still allows us to answer range queries in
<span class="math inline">\(O(1)\)</span>? One thing we could always do would be to construct an <span class="math inline">\(n
\times n\)</span> table storing the answer to <em>every possible</em> range
query—that is, <span class="math inline">\(Q[i,j]\)</span> would store the value of the range <span class="math inline">\(a_i
\diamond \dots \diamond a_j\)</span>. Then we could just look up the answer to
any range query in <span class="math inline">\(O(1)\)</span>. Naively computing the value of each
<span class="math inline">\(Q[i,j]\)</span> would take <span class="math inline">\(O(n)\)</span> time, for a total of <span class="math inline">\(O(n^3)\)</span> time to fill
in each of the entries in the table<span class="sidenote-wrapper"><label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote">We only have to fill in <span class="math inline">\(Q[i,j]\)</span>
where <span class="math inline">\(i &lt; j\)</span>, but this is still about <span class="math inline">\(n^2/2\)</span> entries.<br />
<br />
</span></span>, though it’s not
too hard to fill in the table in <span class="math inline">\(O(n^2)\)</span> total time, spending only
<span class="math inline">\(O(1)\)</span> to fill in each entry—I’ll leave this to you as an exercise.</p>
<p>However, <span class="math inline">\(O(n^2)\)</span> is often too big. Can we do better? More
generally, we are looking for a particular <em>subset</em> of range queries
to precompute, such that the total number is asymptotically less than
<span class="math inline">\(n^2\)</span>, but we can still compute the value of any arbitrary range query
by combining some (constant number of) precomputed ranges. In the case
of a group structure, we were able to compute the values for only
prefix ranges of the form <span class="math inline">\(1 \dots k\)</span>, then compute the value of an arbitrary
range using two prefixes, via subtraction.</p>
<p>A sparse table is exactly such a scheme for precomputing a subset of
ranges.<span class="sidenote-wrapper"><label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote">In fact, I believe, but do not know for sure, that this is
where the name “sparse table” comes from—it is “sparse” in the sense
that it only stores a sparse subset of range values.<br />
<br />
</span></span> Rather than only
a linear number of ranges, as with prefix sums, we have to compute
<span class="math inline">\(O(n \lg n)\)</span> of them, but that’s still way better than <span class="math inline">\(O(n^2)\)</span>. Note,
however, that a sparse table only works when the combining operation
is <em>idempotent</em>, that is, when <span class="math inline">\(x \diamond x = x\)</span> for all <span class="math inline">\(x\)</span>. For
example, we can use a sparse table with combining operations such as
<span class="math inline">\(\max\)</span> or <span class="math inline">\(\gcd\)</span>, but not with <span class="math inline">\(+\)</span> or <span class="math inline">\(\times\)</span>. Let’s see how it works.</p>
</section>
<section id="sparse-tables" class="level2">
<h2>Sparse tables</h2>
<p>The basic idea behind a sparse table is that we precompute a series of
“levels”, where level <span class="math inline">\(i\)</span> stores values for ranges of length <span class="math inline">\(2^i\)</span>. So level
<span class="math inline">\(0\)</span> stores “ranges of length <span class="math inline">\(1\)</span>”—that is, the elements of the
original sequence; level <span class="math inline">\(1\)</span> stores ranges of length <span class="math inline">\(2\)</span>; level
<span class="math inline">\(2\)</span> stores ranges of length <span class="math inline">\(4\)</span>; and so on. Formally, <span class="math inline">\(T[i,j]\)</span>
stores the value of the range of length <span class="math inline">\(2^i\)</span> starting at index <span class="math inline">\(j\)</span>.
That is,</p>
<p><span class="math display">\[T[i,j] = a_j \diamond \dots \diamond a_{j+2^i-1}.\]</span></p>
<p>We can see that <span class="math inline">\(i\)</span> only needs to go from <span class="math inline">\(0\)</span> up to <span class="math inline">\(\lfloor \lg n
\rfloor\)</span>; above that and the stored ranges would be larger than
the entire sequence. So this table has size <span class="math inline">\(O(n \lg n)\)</span>.</p>
<p>Two important questions remain: how do we compute this table in the
first place? And once we have it, how do we use it to answer arbitrary
range queries in <span class="math inline">\(O(1)\)</span>?</p>
<p>Computing the table is easy: each range on level <span class="math inline">\(i\)</span>, of length <span class="math inline">\(2^i\)</span>, is the
combination of two length-<span class="math inline">\(2^{i-1}\)</span> ranges from the previous level. That is,</p>
<p><span class="math display">\[T[i,j] = T[i-1, j] \diamond T[i-1, j+2^{i-1}]\]</span></p>
<p>The zeroth level just consists of the elements of the original
sequence, and we can compute each subsequent level using values from
the previous level, so we can fill in the entire table in <span class="math inline">\(O(n \lg n)\)</span>
time, doing just a single combining operation for each value in the table.</p>
<p>Once we have the table, we can compute the value of an arbitrary
range <span class="math inline">\([l,r]\)</span> as follows:</p>
<ul>
<li><p>Compute the biggest power of two that fits within the range, that
is, the largest <span class="math inline">\(k\)</span> such that <span class="math inline">\(2^k \leq r - l + 1\)</span>. We can compute
this simply as <span class="math inline">\(\lfloor \lg (r - l + 1) \rfloor\)</span>.</p></li>
<li><p>Look up two range values of length <span class="math inline">\(2^k\)</span>, one for the range which begins at <span class="math inline">\(l\)</span>
(that is, <span class="math inline">\(T[k, l]\)</span>) and one for the range which ends at <span class="math inline">\(r\)</span> (that is, <span class="math inline">\(T[k, r -
2^k + 1]\)</span>). These two ranges overlap; but because the combining
operation is idempotent, combining the values of the ranges yields
the value for our desired range <span class="math inline">\([l,r]\)</span>.</p>
<p>This is why we require the combining operation to be idempotent:
otherwise the values in the overlap would be overrepresented in the
final, combined value.</p></li>
</ul>
</section>
<section id="haskell-code" class="level2">
<h2>Haskell code</h2>
<p>Let’s write some Haskell code! First, a little module for idempotent
semigroups. Note that we couch everything in terms of <em>semigroups</em>,
not monoids, because we have no particular need of an identity
element; indeed, some of the most important examples like <span class="math inline">\(\min\)</span> and
<span class="math inline">\(\max\)</span> don’t have an identity element. The <code>IdempotentSemigroup</code>
class has no methods, since as compared to <code>Semigroup</code> it only adds a
law. However, it’s still helpful to signal the requirement. You
might like to convince yourself that all the instances listed below
really are idempotent.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">IdempotentSemigroup</span> <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Bits</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Semigroup</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- | An idempotent semigroup is one where the binary operation</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="co">--   satisfies the law @x &lt;&gt; x = x@ for all @x@.</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Semigroup</span> m <span class="ot">=&gt;</span> <span class="dt">IdempotentSemigroup</span> m</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> <span class="dt">IdempotentSemigroup</span> (<span class="dt">Min</span> a)</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> <span class="dt">IdempotentSemigroup</span> (<span class="dt">Max</span> a)</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">IdempotentSemigroup</span> <span class="dt">All</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">IdempotentSemigroup</span> <span class="dt">Any</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">IdempotentSemigroup</span> <span class="dt">Ordering</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">IdempotentSemigroup</span> ()</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">IdempotentSemigroup</span> (<span class="dt">First</span> a)</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">IdempotentSemigroup</span> (<span class="dt">Last</span> a)</span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Bits</span> a <span class="ot">=&gt;</span> <span class="dt">IdempotentSemigroup</span> (<span class="dt">And</span> a)</span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Bits</span> a <span class="ot">=&gt;</span> <span class="dt">IdempotentSemigroup</span> (<span class="dt">Ior</span> a)</span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">IdempotentSemigroup</span> a, <span class="dt">IdempotentSemigroup</span> b) <span class="ot">=&gt;</span> <span class="dt">IdempotentSemigroup</span> (a,b)</span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">IdempotentSemigroup</span> b <span class="ot">=&gt;</span> <span class="dt">IdempotentSemigroup</span> (a <span class="ot">-&gt;</span> b)</span></code></pre></div>
<p>Now, some code for sparse tables. First, a few imports.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE TupleSections #-}</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">SparseTable</span> <span class="kw">where</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Array</span> (<span class="dt">Array</span>, array, (!))</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Bits</span> (countLeadingZeros, finiteBitSize, (!&lt;&lt;.))</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">IdempotentSemigroup</span></span></code></pre></div>
<p>The sparse table data structure itself is just a 2D array over some
idempotent semigroup <code>m</code>. Note that <code>UArray</code> would be more efficient,
but (1) that would make the code for building the sparse table more
annoying (more on this later), and (2) it would require a bunch of
tedious additional constraints on <code>m</code>.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">SparseTable</span> m <span class="ot">=</span> <span class="dt">SparseTable</span> (<span class="dt">Array</span> (<span class="dt">Int</span>, <span class="dt">Int</span>) m)</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Show</span>)</span></code></pre></div>
<p>We will frequently need to compute rounded-down base-two logarithms,
so we define a function for it. A straightforward implementation
would be to repeatedly shift right by one bit and count the number of
shifts needed to reach zero; however, there is a better way, using
<code>Data.Bits.countLeadingZeros</code>. It has a naive default implementation
which counts right bit shifts, but in most cases it compiles down to
much more efficient machine instructions.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Logarithm base 2, rounded down to the nearest integer.  Computed</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="co">--   efficiently using primitive bitwise instructions, when available.</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="ot">lg ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>lg n <span class="ot">=</span> finiteBitSize n <span class="op">-</span> <span class="dv">1</span> <span class="op">-</span> countLeadingZeros n</span></code></pre></div>
<p>Now let’s write a function to construct a sparse table, given a
sequence of values. Notice how the sparse table array <code>st</code> is <a href="https://byorgey.github.io/blog/posts/2023/06/02/dynamic-programming-in-haskell-lazy-immutable-arrays.html">defined
recursively</a>.
This works because the <code>Array</code> type is lazy in the stored values, with
the added benefit that only the array values we end up actually
needing will be computed. However, this comes with a decent amount of
overhead. If we wanted to use an unboxed array instead, we wouldn’t
be able to use
the recursive definition trick; instead, we would have to <a href="https://byorgey.github.io/blog/posts/2021/11/17/competitive-programming-in-haskell-bfs-part-4-implementation-via-stuarray.html">use an
<code>STUArray</code></a>
and fill in the values in a specific order. The code for this would
be longer and much more tedious, but could be faster if we end up
needing all the values in the array anyway.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Construct a sparse table which can answer range queries over the</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="co">--   given list in $O(1)$ time.  Constructing the sparse table takes</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="co">--   $O(n \lg n)$ time and space, where $n$ is the length of the list.</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="ot">fromList ::</span> <span class="dt">IdempotentSemigroup</span> m <span class="ot">=&gt;</span> [m] <span class="ot">-&gt;</span> <span class="dt">SparseTable</span> m</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>fromList ms <span class="ot">=</span> <span class="dt">SparseTable</span> st</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>  n <span class="ot">=</span> <span class="fu">length</span> ms</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>  lgn <span class="ot">=</span> lg n</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>  st <span class="ot">=</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>    array ((<span class="dv">0</span>, <span class="dv">0</span>), (lgn, n <span class="op">-</span> <span class="dv">1</span>)) <span class="op">$</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>      <span class="fu">zip</span> ((<span class="dv">0</span>,) <span class="op">&lt;$&gt;</span> [<span class="dv">0</span> <span class="op">..</span>]) ms</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">++</span> [ ((i, j), st <span class="op">!</span> (i <span class="op">-</span> <span class="dv">1</span>, j) <span class="op">&lt;&gt;</span> st <span class="op">!</span> (i <span class="op">-</span> <span class="dv">1</span>, j <span class="op">+</span> <span class="dv">1</span> <span class="op">!&lt;&lt;.</span> (i <span class="op">-</span> <span class="dv">1</span>)))</span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a>           <span class="op">|</span> i <span class="ot">&lt;-</span> [<span class="dv">1</span> <span class="op">..</span> lgn]</span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>           , j <span class="ot">&lt;-</span> [<span class="dv">0</span> <span class="op">..</span> n <span class="op">-</span> <span class="dv">1</span> <span class="op">!&lt;&lt;.</span> i]</span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a>           ]</span></code></pre></div>
<p>Finally, we can write a function to answer range queries.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- | \$O(1)$. @range st l r@ computes the range query which is the</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="co">--   @sconcat@ of all the elements from index @l@ to @r@ (inclusive).</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="fu">range</span><span class="ot"> ::</span> <span class="dt">IdempotentSemigroup</span> m <span class="ot">=&gt;</span> <span class="dt">SparseTable</span> m <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> m</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="fu">range</span> (<span class="dt">SparseTable</span> st) l r <span class="ot">=</span> st <span class="op">!</span> (k, l) <span class="op">&lt;&gt;</span> st <span class="op">!</span> (k, r <span class="op">-</span> (<span class="dv">1</span> <span class="op">!&lt;&lt;.</span> k) <span class="op">+</span> <span class="dv">1</span>)</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>  k <span class="ot">=</span> lg (r <span class="op">-</span> l <span class="op">+</span> <span class="dv">1</span>)</span></code></pre></div>
</section>
<section id="applications" class="level2">
<h2>Applications</h2>
<p>Most commonly, we can use a sparse table to find the minimum or
maximum values on a range, <span class="math inline">\(\min\)</span> and <span class="math inline">\(\max\)</span> being the quintessential
idempotent operations. For example, this plays a key role in a
solution to the (quite tricky) problem
<a href="https://open.kattis.com/problems/ograda">Ograda</a>.<span class="sidenote-wrapper"><label for="sn-2" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-2" class="margin-toggle"/><span class="sidenote">At first it
seemed like that problem should be solvable with some kind of <a href="https://byorgey.github.io/blog/posts/2024/11/27/stacks-queues.html">sliding
window</a> approach, but I couldn’t figure out how to make it work!<br />
<br />
</span></span></p>
<p>What if we want to find the <em>index of</em> the minimum or maximum value in
a given range (see, for example, <a href="https://open.kattis.com/problems/worstweather">Worst Weather</a>)? We can easily accomplish this using the semigroup <code>Min (Arg m i)</code> (or <code>Max (Arg m i)</code>), where <code>m</code> is the type of the values and <code>i</code> is
the index type. <code>Arg</code>, from <code>Data.Semigroup</code>, is just a pair which uses only the first value
for its <code>Eq</code> and <code>Ord</code> instances, and carries along the second value
(which is also exposed via <code>Functor</code>, <code>Foldable</code>, and <code>Traversable</code>
instances). In the example below, we can see that the call to <code>range st 0 3</code> returns both the max value on the range (<code>4</code>) and its index
(<code>2</code>) which got carried along for the ride:</p>
<pre><code>λ&gt; :m +Data.Semigroup
λ&gt; st = fromList (map Max (zipWith Arg [2, 3, 4, 2, 7, 4, 9] [0..]))
λ&gt; range st 0 3
Max {getMax = Arg 4 2}</code></pre>
<p>Finally, I will mention that being able to compute range minimum
queries is one way to compute lowest common ancestors for a (static,
rooted) tree. First, walk the tree via a depth-first search and
record the depth of each node encountered in sequence, a so-called
<a href="https://en.wikipedia.org/wiki/Euler_tour_technique">Euler tour</a> (note
that you must record <em>every</em> visit to a node—before visiting any of
its children, in between each child, and after visiting all the
children). Now the minimum depth recorded between visits to any two
nodes will correspond to their lowest common ancestor.</p>
<p>Here are a few problems that involve computing least common ancestors
in a tree, though note there are also other techniques for computing
LCAs (such as binary jumping) which I plan to write about eventually.</p>
<ul>
<li><a href="https://open.kattis.com/problems/tourists">Tourists</a></li>
<li><a href="https://open.kattis.com/problems/stogovi">Stogovi</a></li>
<li><a href="https://open.kattis.com/problems/windiesel">Win Diesel</a></li>
</ul>
</section>

</section>

<script data-isso="https://comments.byorgey.com/" src="https://comments.byorgey.com/js/embed.min.js"></script>
<section id="isso-thread"  data-title="Competitive programming in Haskell: sparse tables" >
  <noscript>Javascript needs to be activated to view comments.</noscript>
</section>

]]></description>
    <pubDate>Fri, 18 Jul 2025 00:00:00 UT</pubDate>
    <guid>http://byorgey.github.io/blog/posts/2025/07/18/sparse-table.html</guid>
    <dc:creator>Brent Yorgey</dc:creator>
</item>
<item>
    <title>Competitive programming in Haskell: prefix sums</title>
    <link>http://byorgey.github.io/blog/posts/2025/06/27/prefix-sums.html</link>
    <description><![CDATA[
<h1>Competitive programming in Haskell: prefix sums</h1>

<div class="info">
  Posted on June 27, 2025
  
  
  <br />
  Tagged <a title="All pages tagged &#39;monoid&#39;." href="/tag/monoid.html" rel="tag">monoid</a>, <a title="All pages tagged &#39;range&#39;." href="/tag/range.html" rel="tag">range</a>, <a title="All pages tagged &#39;query&#39;." href="/tag/query.html" rel="tag">query</a>, <a title="All pages tagged &#39;prefix&#39;." href="/tag/prefix.html" rel="tag">prefix</a>, <a title="All pages tagged &#39;sum&#39;." href="/tag/sum.html" rel="tag">sum</a>, <a title="All pages tagged &#39;Haskell&#39;." href="/tag/Haskell.html" rel="tag">Haskell</a>, <a title="All pages tagged &#39;competitive programming&#39;." href="/tag/competitive%20programming.html" rel="tag">competitive programming</a>
  
</div>

<a href="https://share.joinmastodon.org/#text=Competitive programming in Haskell: prefix sums https://byorgey.github.io/blog/posts/2025/06/27/prefix-sums.html" target="_blank" rel="noopener">Share on <svg role="img" aria-label="Mastodon" height="1em" viewBox="0 0 74 79" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M73.7014 17.4323C72.5616 9.05152 65.1774 2.4469 56.424 1.1671C54.9472 0.950843 49.3518 0.163818 36.3901 0.163818H36.2933C23.3281 0.163818 20.5465 0.950843 19.0697 1.1671C10.56 2.41145 2.78877 8.34604 0.903306 16.826C-0.00357854 21.0022 -0.100361 25.6322 0.068112 29.8793C0.308275 35.9699 0.354874 42.0498 0.91406 48.1156C1.30064 52.1448 1.97502 56.1419 2.93215 60.0769C4.72441 67.3445 11.9795 73.3925 19.0876 75.86C26.6979 78.4332 34.8821 78.8603 42.724 77.0937C43.5866 76.8952 44.4398 76.6647 45.2833 76.4024C47.1867 75.8033 49.4199 75.1332 51.0616 73.9562C51.0841 73.9397 51.1026 73.9184 51.1156 73.8938C51.1286 73.8693 51.1359 73.8421 51.1368 73.8144V67.9366C51.1364 67.9107 51.1302 67.8852 51.1186 67.862C51.1069 67.8388 51.0902 67.8184 51.0695 67.8025C51.0489 67.7865 51.0249 67.7753 50.9994 67.7696C50.9738 67.764 50.9473 67.7641 50.9218 67.7699C45.8976 68.9569 40.7491 69.5519 35.5836 69.5425C26.694 69.5425 24.3031 65.3699 23.6184 63.6327C23.0681 62.1314 22.7186 60.5654 22.5789 58.9744C22.5775 58.9477 22.5825 58.921 22.5934 58.8965C22.6043 58.8721 22.621 58.8505 22.6419 58.8336C22.6629 58.8167 22.6876 58.8049 22.714 58.7992C22.7404 58.7934 22.7678 58.794 22.794 58.8007C27.7345 59.9796 32.799 60.5746 37.8813 60.5733C39.1036 60.5733 40.3223 60.5733 41.5447 60.5414C46.6562 60.3996 52.0437 60.1408 57.0728 59.1694C57.1983 59.1446 57.3237 59.1233 57.4313 59.0914C65.3638 57.5847 72.9128 52.8555 73.6799 40.8799C73.7086 40.4084 73.7803 35.9415 73.7803 35.4523C73.7839 33.7896 74.3216 23.6576 73.7014 17.4323ZM61.4925 47.3144H53.1514V27.107C53.1514 22.8528 51.3591 20.6832 47.7136 20.6832C43.7061 20.6832 41.6988 23.2499 41.6988 28.3194V39.3803H33.4078V28.3194C33.4078 23.2499 31.3969 20.6832 27.3894 20.6832C23.7654 20.6832 21.9552 22.8528 21.9516 27.107V47.3144H13.6176V26.4937C13.6176 22.2395 14.7157 18.8598 16.9118 16.3545C19.1772 13.8552 22.1488 12.5719 25.8373 12.5719C30.1064 12.5719 33.3325 14.1955 35.4832 17.4394L37.5587 20.8853L39.6377 17.4394C41.7884 14.1955 45.0145 12.5719 49.2765 12.5719C52.9614 12.5719 55.9329 13.8552 58.2055 16.3545C60.4017 18.8574 61.4997 22.2371 61.4997 26.4937L61.4925 47.3144Z" fill="inherit"/></svg></a>
<section>
<p>In a <a href="https://byorgey.github.io/blog/posts/2025/06/23/range-queries-classified.html">previous blog
post</a>
I categorized a number of different techniques for calculating <em>range queries</em>.
Today, I will discuss one of those techniques which is simple but frequently
useful.</p>
<section id="precomputing-prefix-sums" class="level2">
<h2>Precomputing prefix sums</h2>
<p>Suppose we have a static sequence of values <span class="math inline">\(a_1, a_2, a_3, \dots,
a_n\)</span> drawn from some
<a href="https://en.wikipedia.org/wiki/Group_(mathematics)">group</a><span class="sidenote-wrapper"><label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote">That is,
there is an associative binary operation with an identity element, and
every element has an inverse.<br />
<br />
</span></span>, and want
to be able to compute the total value (according to the group
operation) of any contiguous subrange. That is, given a range
<span class="math inline">\([i,j]\)</span>, we want to compute <span class="math inline">\(a_i \diamond a_{i+1} \diamond \dots
\diamond a_j\)</span> (where <span class="math inline">\(\diamond\)</span> is the group operation). For example,
we might have a sequence of integers and want to compute the sum, or
perhaps the bitwise xor (but not the maximum) of all the values in any particular
subrange.</p>
<p>Of course, we could simply compute <span class="math inline">\(a_i \diamond \dots \diamond a_j\)</span>
directly, but that takes <span class="math inline">\(O(n)\)</span> time. With some simple preprocessing,
it’s possible to compute the value of any range in constant time.</p>
<p>The key idea is to precompute an array <span class="math inline">\(P\)</span> of <em>prefix sums</em>, so <span class="math inline">\(P_i =
a_1 \diamond \dots \diamond a_i\)</span>. This can be computed in linear time
via a <em>scan</em>; for example:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Array</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.List</span> (scanl&#39;)</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="ot">prefix ::</span> <span class="dt">Monoid</span> a <span class="ot">=&gt;</span> [a] <span class="ot">-&gt;</span> <span class="dt">Array</span> <span class="dt">Int</span> a</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>prefix a <span class="ot">=</span> listArray (<span class="dv">0</span>, <span class="fu">length</span> a) <span class="op">$</span> scanl&#39; (<span class="op">&lt;&gt;</span>) <span class="fu">mempty</span> a</span></code></pre></div>
<p><span class="sidenote-wrapper"><label for="sn-1" class="margin-toggle">&#8853;</label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="marginnote">Actually, I would typically use an <em>unboxed</em> array, which is
faster but slightly more limited in its uses: import
<code>Data.Array.Unboxed</code>, use <code>UArray</code> instead of <code>Array</code>, and add an
<code>IArray UArray a</code> constraint.<br />
<br />
</span></span></p>
<p>Note that we set <span class="math inline">\(P_0 = 0\)</span> (or whatever the identity element is for
the group); this is why I had the sequence of values indexed starting
from <span class="math inline">\(1\)</span>, so <span class="math inline">\(P_0\)</span> corresponds to the empty sum, <span class="math inline">\(P_1 = a_1\)</span>, <span class="math inline">\(P_2 =
a_1 \diamond a_2\)</span>, and so on.</p>
<p>Now, for the value of the range <span class="math inline">\([i,j]\)</span>, just compute <span class="math inline">\(P_j \diamond
P_{i-1}^{-1}\)</span>—that is, we start with a prefix that ends at the right place, then
cancel or “subtract” the prefix that ends right before the range we
want. For example, to find the sum of the integers <span class="math inline">\(a_5 + \dots +
a_{10}\)</span>, we can compute <span class="math inline">\(P_{10} - P_4\)</span>.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">range</span><span class="ot"> ::</span> <span class="dt">Group</span> a <span class="ot">=&gt;</span> <span class="dt">Array</span> <span class="dt">Int</span> a <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> a</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="fu">range</span> p i j <span class="ot">=</span> p<span class="op">!</span>j <span class="op">&lt;&gt;</span> inv (p<span class="op">!</span>(i<span class="op">-</span><span class="dv">1</span>))</span></code></pre></div>
<p>That’s why this only works for groups but not for general monoids:
only in a group can we <em>cancel</em> unwanted values. So, for example,
this works for finding the sum of any range, but not the maximum.</p>
</section>
<section id="practice-problems" class="level2">
<h2>Practice problems</h2>
<p>Want to practice? Here are a few problems that can be solved using
techniques discussed in this post:</p>
<ul>
<li><a href="https://open.kattis.com/problems/nucleotides">Determining Nucleotide Assortments</a></li>
<li><a href="https://open.kattis.com/problems/einvigi">Einvígi</a></li>
<li><a href="https://open.kattis.com/problems/srednji">Srednji</a></li>
<li><a href="https://open.kattis.com/problems/veggjakalli">Veggja Kalli</a></li>
</ul>
<p>It is possible to generalize this scheme to 2D—that is, to compute
the value of any <em>subrectangle</em> of a <em>2D grid</em> of values from some
group in only <span class="math inline">\(O(1)\)</span> time. I will leave you the fun of figuring out
the details.</p>
<ul>
<li><a href="https://open.kattis.com/problems/prozor">Prozor</a></li>
<li><a href="https://open.kattis.com/problems/rust">Rust</a></li>
</ul>
<p>If you’re looking for an extra challenge, here are a few harder
problems which use techniques from this post as an important
component, but require some additional nontrivial ingredients:</p>
<ul>
<li><a href="https://open.kattis.com/problems/killingchaos">Killing Chaos</a></li>
<li><a href="https://open.kattis.com/problems/ozljeda">Ozljeda</a></li>
<li><a href="https://open.kattis.com/problems/vudu">Vudu</a></li>
</ul>
</section>

</section>

<script data-isso="https://comments.byorgey.com/" src="https://comments.byorgey.com/js/embed.min.js"></script>
<section id="isso-thread"  data-title="Competitive programming in Haskell: prefix sums" >
  <noscript>Javascript needs to be activated to view comments.</noscript>
</section>

]]></description>
    <pubDate>Fri, 27 Jun 2025 00:00:00 UT</pubDate>
    <guid>http://byorgey.github.io/blog/posts/2025/06/27/prefix-sums.html</guid>
    <dc:creator>Brent Yorgey</dc:creator>
</item>
<item>
    <title>Competitive programming in Haskell: range queries, classified</title>
    <link>http://byorgey.github.io/blog/posts/2025/06/23/range-queries-classified.html</link>
    <description><![CDATA[
<h1>Competitive programming in Haskell: range queries, classified</h1>

<div class="info">
  Posted on June 23, 2025
  
  
  <br />
  Tagged <a title="All pages tagged &#39;semigroup&#39;." href="/tag/semigroup.html" rel="tag">semigroup</a>, <a title="All pages tagged &#39;monoid&#39;." href="/tag/monoid.html" rel="tag">monoid</a>, <a title="All pages tagged &#39;range&#39;." href="/tag/range.html" rel="tag">range</a>, <a title="All pages tagged &#39;query&#39;." href="/tag/query.html" rel="tag">query</a>, <a title="All pages tagged &#39;Haskell&#39;." href="/tag/Haskell.html" rel="tag">Haskell</a>, <a title="All pages tagged &#39;competitive programming&#39;." href="/tag/competitive%20programming.html" rel="tag">competitive programming</a>
  
</div>

<a href="https://share.joinmastodon.org/#text=Competitive programming in Haskell: range queries, classified https://byorgey.github.io/blog/posts/2025/06/23/range-queries-classified.html" target="_blank" rel="noopener">Share on <svg role="img" aria-label="Mastodon" height="1em" viewBox="0 0 74 79" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M73.7014 17.4323C72.5616 9.05152 65.1774 2.4469 56.424 1.1671C54.9472 0.950843 49.3518 0.163818 36.3901 0.163818H36.2933C23.3281 0.163818 20.5465 0.950843 19.0697 1.1671C10.56 2.41145 2.78877 8.34604 0.903306 16.826C-0.00357854 21.0022 -0.100361 25.6322 0.068112 29.8793C0.308275 35.9699 0.354874 42.0498 0.91406 48.1156C1.30064 52.1448 1.97502 56.1419 2.93215 60.0769C4.72441 67.3445 11.9795 73.3925 19.0876 75.86C26.6979 78.4332 34.8821 78.8603 42.724 77.0937C43.5866 76.8952 44.4398 76.6647 45.2833 76.4024C47.1867 75.8033 49.4199 75.1332 51.0616 73.9562C51.0841 73.9397 51.1026 73.9184 51.1156 73.8938C51.1286 73.8693 51.1359 73.8421 51.1368 73.8144V67.9366C51.1364 67.9107 51.1302 67.8852 51.1186 67.862C51.1069 67.8388 51.0902 67.8184 51.0695 67.8025C51.0489 67.7865 51.0249 67.7753 50.9994 67.7696C50.9738 67.764 50.9473 67.7641 50.9218 67.7699C45.8976 68.9569 40.7491 69.5519 35.5836 69.5425C26.694 69.5425 24.3031 65.3699 23.6184 63.6327C23.0681 62.1314 22.7186 60.5654 22.5789 58.9744C22.5775 58.9477 22.5825 58.921 22.5934 58.8965C22.6043 58.8721 22.621 58.8505 22.6419 58.8336C22.6629 58.8167 22.6876 58.8049 22.714 58.7992C22.7404 58.7934 22.7678 58.794 22.794 58.8007C27.7345 59.9796 32.799 60.5746 37.8813 60.5733C39.1036 60.5733 40.3223 60.5733 41.5447 60.5414C46.6562 60.3996 52.0437 60.1408 57.0728 59.1694C57.1983 59.1446 57.3237 59.1233 57.4313 59.0914C65.3638 57.5847 72.9128 52.8555 73.6799 40.8799C73.7086 40.4084 73.7803 35.9415 73.7803 35.4523C73.7839 33.7896 74.3216 23.6576 73.7014 17.4323ZM61.4925 47.3144H53.1514V27.107C53.1514 22.8528 51.3591 20.6832 47.7136 20.6832C43.7061 20.6832 41.6988 23.2499 41.6988 28.3194V39.3803H33.4078V28.3194C33.4078 23.2499 31.3969 20.6832 27.3894 20.6832C23.7654 20.6832 21.9552 22.8528 21.9516 27.107V47.3144H13.6176V26.4937C13.6176 22.2395 14.7157 18.8598 16.9118 16.3545C19.1772 13.8552 22.1488 12.5719 25.8373 12.5719C30.1064 12.5719 33.3325 14.1955 35.4832 17.4394L37.5587 20.8853L39.6377 17.4394C41.7884 14.1955 45.0145 12.5719 49.2765 12.5719C52.9614 12.5719 55.9329 13.8552 58.2055 16.3545C60.4017 18.8574 61.4997 22.2371 61.4997 26.4937L61.4925 47.3144Z" fill="inherit"/></svg></a>
<section>
<section id="static-range-queries" class="level2">
<h2>Static range queries</h2>
<p>Suppose we have a sequence of values, which is <em>static</em> in the sense
that the values in the sequence will never change, and we want to
perform <em>range queries</em>, that is, for various ranges we want to
compute the total of all consecutive values in the range, according to
some binary combining operation. For example, we might want to
compute the maximum, sum, or product of all the consecutive values in
a certain subrange. We have various options depending on the kind of
ranges we want and the algebraic properties of the operation.</p>
<ul>
<li><p>If we want ranges corresponding to a <em>sliding window</em>, we can use
<a href="https://byorgey.github.io/blog/posts/2024/11/27/stacks-queues.html">an amortized queue
structure</a>
to find the total of each range in <span class="math inline">\(O(1)\)</span>, for an arbitrary
monoid.
<!-- ^[If we have a group, then no special data structure is -->
<!-- needed: just keep track of the value of the current window, and add -->
<!-- and subtract values as they enter and leave the window, -->
<!-- respectively.] --></p></li>
<li><p>If we want arbitrary ranges but the operation is a <em>group</em>, the
solution is relatively straightforward: we can precompute all
<em><a href="https://byorgey.github.io/blog/posts/2025/06/27/prefix-sums.html">prefix sums</a></em>, and subtract to find the result for an arbitrary
range in <span class="math inline">\(O(1)\)</span>.</p></li>
<li><p>If the operation is an <em>idempotent semigroup</em> (that is, it has the
property that <span class="math inline">\(x \diamond x = x\)</span> for all <span class="math inline">\(x\)</span>), we can use a <em><a href="https://byorgey.github.io/blog/posts/2025/07/18/sparse-table.html">sparse
table</a></em>, which takes <span class="math inline">\(O(n \lg n)\)</span> time and space for precomputation,
and then allows us to answer arbitrary range queries in <span class="math inline">\(O(1)\)</span>.</p></li>
<li><p>If the operation is an arbitrary monoid, we can use a <em><a href="https://cp-algorithms.com/data_structures/sqrt-tree.html">sqrt tree</a></em>,
which uses <span class="math inline">\(O(n \lg \lg n)\)</span> precomputed time and space, and allows
answering arbitrary range queries in <span class="math inline">\(O(\lg \lg n)\)</span>. I will write
about this in a future post.</p></li>
</ul>
</section>
<section id="dynamic-range-queries" class="level2">
<h2>Dynamic range queries</h2>
<p>What if we want <em>dynamic</em> range queries, that is, we want to be able
to interleave range queries with arbitrary updates to the values of
the sequence?</p>
<ul>
<li>If the operation is an arbitrary monoid, we can use a segment
tree.</li>
<li>If the operation is a group, we can use a <a href="https://cp-algorithms.com/data_structures/fenwick.html">Fenwick tree</a>.</li>
</ul>
<p>I published <a href="https://byorgey.github.io/blog/posts/2025/01/23/Fenwick.html">a paper about Fenwick
trees</a>,
which also discusses segment trees, but I should write more about
them here!</p>
</section>
<section id="table" class="level2">
<h2>Table</h2>
<p>Here’s a table summarizing the above classification scheme. I plan to
fill in links as I write blog posts about each row.</p>
<figure class="fullwidth">
<table>
<colgroup>
<col style="width: 9%" />
<col style="width: 14%" />
<col style="width: 20%" />
<col style="width: 23%" />
<col style="width: 16%" />
<col style="width: 14%" />
</colgroup>
<thead>
<tr>
<th style="text-align: left;">Sequence</th>
<th style="text-align: left;">Ranges</th>
<th style="text-align: left;">Operation</th>
<th style="text-align: left;">Solution</th>
<th style="text-align: left;">Precomputation</th>
<th style="text-align: left;">Queries</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">Static</td>
<td style="text-align: left;">Sliding window</td>
<td style="text-align: left;">Monoid</td>
<td style="text-align: left;"><a href="https://byorgey.github.io/blog/posts/2024/11/27/stacks-queues.html">Amortized queue</a></td>
<td style="text-align: left;"><span class="math inline">\(O(1)\)</span></td>
<td style="text-align: left;"><span class="math inline">\(O(1)\)</span></td>
</tr>
<tr>
<td style="text-align: left;">Static</td>
<td style="text-align: left;">Arbitrary</td>
<td style="text-align: left;">Group</td>
<td style="text-align: left;"><a href="https://byorgey.github.io/blog/posts/2025/06/27/prefix-sums.html">Prefix sum table</a></td>
<td style="text-align: left;"><span class="math inline">\(O(n)\)</span></td>
<td style="text-align: left;"><span class="math inline">\(O(1)\)</span></td>
</tr>
<tr>
<td style="text-align: left;">Static</td>
<td style="text-align: left;">Arbitrary</td>
<td style="text-align: left;">Idempotent semigroup</td>
<td style="text-align: left;"><a href="https://byorgey.github.io/blog/posts/2025/07/18/sparse-table.html">Sparse table</a></td>
<td style="text-align: left;"><span class="math inline">\(O(n \lg n)\)</span></td>
<td style="text-align: left;"><span class="math inline">\(O(1)\)</span></td>
</tr>
<tr>
<td style="text-align: left;">Static</td>
<td style="text-align: left;">Arbitrary</td>
<td style="text-align: left;">Monoid</td>
<td style="text-align: left;">Sqrt tree</td>
<td style="text-align: left;"><span class="math inline">\(O(n \lg \lg n)\)</span></td>
<td style="text-align: left;"><span class="math inline">\(O(\lg \lg n)\)</span></td>
</tr>
<tr>
<td style="text-align: left;">Dynamic</td>
<td style="text-align: left;">Arbitrary</td>
<td style="text-align: left;">Group</td>
<td style="text-align: left;">Fenwick tree</td>
<td style="text-align: left;"><span class="math inline">\(O(n)\)</span></td>
<td style="text-align: left;"><span class="math inline">\(O(\lg n)\)</span></td>
</tr>
<tr>
<td style="text-align: left;">Dynamic</td>
<td style="text-align: left;">Arbitrary</td>
<td style="text-align: left;">Monoid</td>
<td style="text-align: left;">Segment tree</td>
<td style="text-align: left;"><span class="math inline">\(O(n)\)</span></td>
<td style="text-align: left;"><span class="math inline">\(O(\lg n)\)</span></td>
</tr>
</tbody>
</table>
</figure>
</section>

</section>

<script data-isso="https://comments.byorgey.com/" src="https://comments.byorgey.com/js/embed.min.js"></script>
<section id="isso-thread"  data-title="Competitive programming in Haskell: range queries, classified" >
  <noscript>Javascript needs to be activated to view comments.</noscript>
</section>

]]></description>
    <pubDate>Mon, 23 Jun 2025 00:00:00 UT</pubDate>
    <guid>http://byorgey.github.io/blog/posts/2025/06/23/range-queries-classified.html</guid>
    <dc:creator>Brent Yorgey</dc:creator>
</item>
<item>
    <title>Monads are not like burritos</title>
    <link>http://byorgey.github.io/blog/posts/2025/06/16/monads-are-not-burritos.html</link>
    <description><![CDATA[
<h1>Monads are not like burritos</h1>

<div class="info">
  Posted on June 16, 2025
  
  
  <br />
  Tagged <a title="All pages tagged &#39;monad&#39;." href="/tag/monad.html" rel="tag">monad</a>, <a title="All pages tagged &#39;pedagogy&#39;." href="/tag/pedagogy.html" rel="tag">pedagogy</a>, <a title="All pages tagged &#39;meme&#39;." href="/tag/meme.html" rel="tag">meme</a>, <a title="All pages tagged &#39;burrito&#39;." href="/tag/burrito.html" rel="tag">burrito</a>, <a title="All pages tagged &#39;analogy&#39;." href="/tag/analogy.html" rel="tag">analogy</a>, <a title="All pages tagged &#39;Haskell&#39;." href="/tag/Haskell.html" rel="tag">Haskell</a>
  
</div>

<a href="https://share.joinmastodon.org/#text=Monads are not like burritos https://byorgey.github.io/blog/posts/2025/06/16/monads-are-not-burritos.html" target="_blank" rel="noopener">Share on <svg role="img" aria-label="Mastodon" height="1em" viewBox="0 0 74 79" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M73.7014 17.4323C72.5616 9.05152 65.1774 2.4469 56.424 1.1671C54.9472 0.950843 49.3518 0.163818 36.3901 0.163818H36.2933C23.3281 0.163818 20.5465 0.950843 19.0697 1.1671C10.56 2.41145 2.78877 8.34604 0.903306 16.826C-0.00357854 21.0022 -0.100361 25.6322 0.068112 29.8793C0.308275 35.9699 0.354874 42.0498 0.91406 48.1156C1.30064 52.1448 1.97502 56.1419 2.93215 60.0769C4.72441 67.3445 11.9795 73.3925 19.0876 75.86C26.6979 78.4332 34.8821 78.8603 42.724 77.0937C43.5866 76.8952 44.4398 76.6647 45.2833 76.4024C47.1867 75.8033 49.4199 75.1332 51.0616 73.9562C51.0841 73.9397 51.1026 73.9184 51.1156 73.8938C51.1286 73.8693 51.1359 73.8421 51.1368 73.8144V67.9366C51.1364 67.9107 51.1302 67.8852 51.1186 67.862C51.1069 67.8388 51.0902 67.8184 51.0695 67.8025C51.0489 67.7865 51.0249 67.7753 50.9994 67.7696C50.9738 67.764 50.9473 67.7641 50.9218 67.7699C45.8976 68.9569 40.7491 69.5519 35.5836 69.5425C26.694 69.5425 24.3031 65.3699 23.6184 63.6327C23.0681 62.1314 22.7186 60.5654 22.5789 58.9744C22.5775 58.9477 22.5825 58.921 22.5934 58.8965C22.6043 58.8721 22.621 58.8505 22.6419 58.8336C22.6629 58.8167 22.6876 58.8049 22.714 58.7992C22.7404 58.7934 22.7678 58.794 22.794 58.8007C27.7345 59.9796 32.799 60.5746 37.8813 60.5733C39.1036 60.5733 40.3223 60.5733 41.5447 60.5414C46.6562 60.3996 52.0437 60.1408 57.0728 59.1694C57.1983 59.1446 57.3237 59.1233 57.4313 59.0914C65.3638 57.5847 72.9128 52.8555 73.6799 40.8799C73.7086 40.4084 73.7803 35.9415 73.7803 35.4523C73.7839 33.7896 74.3216 23.6576 73.7014 17.4323ZM61.4925 47.3144H53.1514V27.107C53.1514 22.8528 51.3591 20.6832 47.7136 20.6832C43.7061 20.6832 41.6988 23.2499 41.6988 28.3194V39.3803H33.4078V28.3194C33.4078 23.2499 31.3969 20.6832 27.3894 20.6832C23.7654 20.6832 21.9552 22.8528 21.9516 27.107V47.3144H13.6176V26.4937C13.6176 22.2395 14.7157 18.8598 16.9118 16.3545C19.1772 13.8552 22.1488 12.5719 25.8373 12.5719C30.1064 12.5719 33.3325 14.1955 35.4832 17.4394L37.5587 20.8853L39.6377 17.4394C41.7884 14.1955 45.0145 12.5719 49.2765 12.5719C52.9614 12.5719 55.9329 13.8552 58.2055 16.3545C60.4017 18.8574 61.4997 22.2371 61.4997 26.4937L61.4925 47.3144Z" fill="inherit"/></svg></a>
<section>
<p>In January 2009, while just a baby first-year PhD student, I wrote a
blog post titled <a href="https://byorgey.github.io/blog/posts/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy.html">Abstraction, intuition, and the “monad tutorial
fallacy”</a>.
In it, I made the argument that humans tend to learn best by first
grappling with concrete examples, and only later proceeding to
higher-level intuition and analogies; hence, it’s a mistake to
think that clearly presenting your intuition for a topic will help
other people understand it. Analogies and intuition can help, but
only when accompanied by concrete examples and active engagement. To
illustrate the point, I made up a fictitious programmer with a
fictitious analogy.</p>
<blockquote>
<p>But now Joe goes and writes a monad tutorial called “Monads are
Burritos,” under the well-intentioned but mistaken assumption that
if other people read his magical insight, learning about monads will
be a snap for them. “Monads are easy,” Joe writes. “Think of them as
burritos.” Joe hides all the actual details about types and such
because those are scary, and people will learn better if they can
avoid all that difficult and confusing stuff. Of course, exactly
the opposite is true, and all Joe has done is make it <em>harder</em> for
people to learn about monads…</p>
</blockquote>
<p>My intention was to choose a fictitious analogy which was obviously
ridiculous and silly, as a parody of many of the monad tutorials which
existed at the time (and still do). <a href="https://blog.plover.com/meta/about-me.html">Mark Jason Dominus</a>
then wrote a blog post, <a href="https://blog.plover.com/prog/burritos.html">Monads are like
burritos</a>, pointing out
that actually, monads <em>are</em> kinda like burritos. It’s really funny,
though I don’t think it’s actually a very good analogy, and my guess
is that Mark would agree: it was clearly written as a silly joke and
not as a real way to explain monads.</p>
<p>In any case, from that point the “monads are burritos” meme took on a
life of its own. For example:</p>
<ul>
<li><a href="https://chrisdone.com/posts/monads-are-burritos/">Chris Done made a webcomic about
it</a></li>
<li><a href="https://edwardmorehouse.github.io/silliness/burrito_monads.pdf">Ed Morehouse wrote a ridiculous paper exploring the categorical
foundations of burritos</a></li>
<li><a href="https://github.com/withoutboats/burrito">Someone made a <code>burrito</code> library in Rust</a></li>
<li><a href="https://x.com/DrEugeniaCheng/status/1316817271961116679">Dr Eugenia Cheng tweeted about it</a></li>
</ul>
<p>I even joined in the fun and made this meme image about bad monad
tutorials:</p>
<p><img src="images/monad_tutorial.jpg" /></p>
<p>Of course there are <a href="https://www.reddit.com/r/haskell/comments/6bxk1v/why_monads_always_get_compared_to_burritos/">lots of people who still understand that it was all just a silly joke</a>.
Recently, however, I’ve seen several instances where people apparently
believe “monads are burritos” is a real, helpful thing and not just a
joke meme. For example, see <a href="https://lobste.rs/s/xmpj1p/you_probably_wrote_half_monad_by_accident">this thread on
lobste.rs</a>,
or <a href="https://mathstodon.xyz/@CubeRootOfTrue/114404282908533701">this Mastodon post</a>.</p>
<p>So, to set the record straight: “monads are burritos” is <em>not</em> a helpful
analogy!<span class="sidenote-wrapper"><label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote">Yes, I am writing a blog post because <a href="https://xkcd.com/386/">People Are Wrong On
The Internet</a>, and I know it probably won’t
make any difference, but here we are.<br />
<br />
</span></span> Why not, you ask?
To expand on my reasons from a <a href="https://www.reddit.com/r/haskell/comments/3bdrlj/comment/ct24jmc/">10-year-old Reddit
comment</a>:</p>
<ul>
<li>The burrito analogy strongly implies that a value of type <code>m a</code>
somehow “contains” a value (or values) of type <code>a</code>. But that is not
true for all monads (e.g. there is no sense in which a value of type
<code>IO String</code> contains a <code>String</code>).</li>
<li>Relatedly, the analogy also implies that a value of type <code>m a</code> can
be “unwrapped” to get an <code>a</code>, but this is impossible for many monads.</li>
<li>It is not actually very easy to take a burrito containing a burrito
and merge it into a single-level burrito. At least this is not in
any sense a natural operation on burritos. Perhaps you could argue
that it is always easy to remove outer tortilla layers (but not the
innermost one since the food will all fall out), but this is a bad
analogy, since in general <code>join</code> does not just “remove” an outer
layer, but somehow merges the effects of two layers into one.</li>
</ul>
<p>Actually, burritos are a great analogy for the <code>Identity</code> monad!
…but not much beyond that.</p>
<p>On a more positive note, my sense is that the average
pedagogical quality of Haskell materials, and monad tutorials in
particular, has indeed gone up significantly since 2009. I’d love to
think this can be at least partially attributed to my original blog
post, though of course it’s impossible to know that for sure.</p>

</section>

<script data-isso="https://comments.byorgey.com/" src="https://comments.byorgey.com/js/embed.min.js"></script>
<section id="isso-thread"  data-title="Monads are not like burritos" >
  <noscript>Javascript needs to be activated to view comments.</noscript>
</section>

]]></description>
    <pubDate>Mon, 16 Jun 2025 00:00:00 UT</pubDate>
    <guid>http://byorgey.github.io/blog/posts/2025/06/16/monads-are-not-burritos.html</guid>
    <dc:creator>Brent Yorgey</dc:creator>
</item>
<item>
    <title>Introduction to competitive programming in Haskell</title>
    <link>http://byorgey.github.io/blog/posts/2025/06/10/comprog-hs-intro.html</link>
    <description><![CDATA[
<h1>Introduction to competitive programming in Haskell</h1>

<div class="info">
  Posted on June 10, 2025
  
  
  <br />
  Tagged <a title="All pages tagged &#39;Kattis&#39;." href="/tag/Kattis.html" rel="tag">Kattis</a>, <a title="All pages tagged &#39;competitive programming&#39;." href="/tag/competitive%20programming.html" rel="tag">competitive programming</a>, <a title="All pages tagged &#39;haskell&#39;." href="/tag/haskell.html" rel="tag">haskell</a>
  
</div>

<a href="https://share.joinmastodon.org/#text=Introduction to competitive programming in Haskell https://byorgey.github.io/blog/posts/2025/06/10/comprog-hs-intro.html" target="_blank" rel="noopener">Share on <svg role="img" aria-label="Mastodon" height="1em" viewBox="0 0 74 79" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M73.7014 17.4323C72.5616 9.05152 65.1774 2.4469 56.424 1.1671C54.9472 0.950843 49.3518 0.163818 36.3901 0.163818H36.2933C23.3281 0.163818 20.5465 0.950843 19.0697 1.1671C10.56 2.41145 2.78877 8.34604 0.903306 16.826C-0.00357854 21.0022 -0.100361 25.6322 0.068112 29.8793C0.308275 35.9699 0.354874 42.0498 0.91406 48.1156C1.30064 52.1448 1.97502 56.1419 2.93215 60.0769C4.72441 67.3445 11.9795 73.3925 19.0876 75.86C26.6979 78.4332 34.8821 78.8603 42.724 77.0937C43.5866 76.8952 44.4398 76.6647 45.2833 76.4024C47.1867 75.8033 49.4199 75.1332 51.0616 73.9562C51.0841 73.9397 51.1026 73.9184 51.1156 73.8938C51.1286 73.8693 51.1359 73.8421 51.1368 73.8144V67.9366C51.1364 67.9107 51.1302 67.8852 51.1186 67.862C51.1069 67.8388 51.0902 67.8184 51.0695 67.8025C51.0489 67.7865 51.0249 67.7753 50.9994 67.7696C50.9738 67.764 50.9473 67.7641 50.9218 67.7699C45.8976 68.9569 40.7491 69.5519 35.5836 69.5425C26.694 69.5425 24.3031 65.3699 23.6184 63.6327C23.0681 62.1314 22.7186 60.5654 22.5789 58.9744C22.5775 58.9477 22.5825 58.921 22.5934 58.8965C22.6043 58.8721 22.621 58.8505 22.6419 58.8336C22.6629 58.8167 22.6876 58.8049 22.714 58.7992C22.7404 58.7934 22.7678 58.794 22.794 58.8007C27.7345 59.9796 32.799 60.5746 37.8813 60.5733C39.1036 60.5733 40.3223 60.5733 41.5447 60.5414C46.6562 60.3996 52.0437 60.1408 57.0728 59.1694C57.1983 59.1446 57.3237 59.1233 57.4313 59.0914C65.3638 57.5847 72.9128 52.8555 73.6799 40.8799C73.7086 40.4084 73.7803 35.9415 73.7803 35.4523C73.7839 33.7896 74.3216 23.6576 73.7014 17.4323ZM61.4925 47.3144H53.1514V27.107C53.1514 22.8528 51.3591 20.6832 47.7136 20.6832C43.7061 20.6832 41.6988 23.2499 41.6988 28.3194V39.3803H33.4078V28.3194C33.4078 23.2499 31.3969 20.6832 27.3894 20.6832C23.7654 20.6832 21.9552 22.8528 21.9516 27.107V47.3144H13.6176V26.4937C13.6176 22.2395 14.7157 18.8598 16.9118 16.3545C19.1772 13.8552 22.1488 12.5719 25.8373 12.5719C30.1064 12.5719 33.3325 14.1955 35.4832 17.4394L37.5587 20.8853L39.6377 17.4394C41.7884 14.1955 45.0145 12.5719 49.2765 12.5719C52.9614 12.5719 55.9329 13.8552 58.2055 16.3545C60.4017 18.8574 61.4997 22.2371 61.4997 26.4937L61.4925 47.3144Z" fill="inherit"/></svg></a>
<section>
<p>A few days ago I gave a talk at <a href="https://zfoh.ch/zurihac2025/">ZuriHac
2025</a> entitled <em>Haskell for Competitive
Programming</em>, a basic introduction to competitive programming in
general, and the joy of using Haskell for competitive programming in
particular. This is an expanded version of my talk in blog post form.
(For an even gentler introduction to competitive programming in
Haskell, see <a href="https://byorgey.github.io/blog/posts/2019/04/24/competitive-programming-in-haskell-basic-setup.html">this old blog post from
2019</a>.)</p>
<section id="competitive-programming" class="level2">
<h2>Competitive Programming</h2>
<p>First of all, what is <em>competitive programming</em>? It’s a broad term,
but when I talk about competitive programming I have something in mind
along the following lines:</p>
<ul>
<li>There are well-specified input and output formats, usually with a
few examples, and a precise specification of what the output should
be for a given input.</li>
<li>Your job is to write a program which transforms input meeting the
specification into a correct output.</li>
<li>You submit your program, which is tested on a number of inputs and
declared correct if and only if it yields the correct output for all
the tested inputs.</li>
<li>There is often time pressure involved—that is, you have a limited
amount of time in which to write your program. However, it is also
possible to participate “recreationally”, simply for the joy of
problem-solving, without time pressure (in fact, the vast majority
of the competitive programming I do is of this form, though I have
occasionally participated in timed contests).</li>
</ul>
<p>There are many variations: whether you are allowed to use code
libraries prepared ahead of time, or must type everything from
scratch; outputs can be scored according to some criteria rather
than simply being judged right or wrong; and so on.</p>
<p>There are many sites which allow you to participate in contests and/or
solve competitive programming problems recreationally. My favorite is
<a href="https://open.kattis.com">Open Kattis</a>; I mention some others at the
end of this post.</p>
</section>
<section id="pot-a-first-example" class="level2">
<h2>Pot: a first example</h2>
<p>As an introductory example, let’s look at
<a href="https://open.kattis.com/problems/pot">Pot</a>. As usual, there’s a silly
story, but what it boils down to is that we will be given a sequence
of numbers, and we should interpret the last digit of each number as an
exponent, then sum the results. For example, if given <code>125</code>, we
should interpret it as <span class="math inline">\(12^5\)</span>, and so on.</p>
<section id="dealing-with-io-via-interact" class="level3">
<h3>Dealing with I/O via <code>interact</code></h3>
<p>An imperative approach to such a problem would involve doing a
sequence of input commands, some computation, and a sequence of output
commands—possibly interleaved with one another—and we might
immediately think to start using functions like <code>getLine</code> and
<code>putStrLn</code> to do the required I/O in Haskell. However, there is a
much more fruitful functional perspective: we are simply being asked
to implement a particular (partial) function of type <code>String -&gt; String</code>. The fact that the function’s input and output should be
hooked up to the program’s standard input and output is just an
implementation detail. Competitive programming is functional at
heart!</p>
<p>It turns out that Haskell’s standard library already has the perfect
built-in function for this scenario:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">interact</span><span class="ot"> ::</span> (<span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span>) <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span></code></pre></div>
<p><code>interact</code> takes a pure <code>String -&gt; String</code> function and turns it into
an <code>IO</code> action which reads from standard input, passes the input to
the given <code>String -&gt; String</code> function, and prints the result to standard output. It even
does this using <em>lazy</em> I/O—that is, the input is
read lazily, as demanded by the function, so that the output and input
can be automatically interleaved depending on which parts of the
output depend on which parts of the input. In particular, this means
that that the entire input need not be stored in memory at once. If
the inputs can be processed into outputs in a streaming fashion—as
is the case in the example problem we are currently
considering—then the input and output will be interleaved. In
general, this kind of lazy I/O is
<a href="https://stackoverflow.com/questions/5892653/whats-so-bad-about-lazy-i-o">problematic</a>
and even unsafe, but it’s perfect for this scenario.</p>
</section>
<section id="solving-the-problem-with-a-pipeline" class="level3">
<h3>Solving the problem with a pipeline</h3>
<p>So <code>interact</code> does all the <code>IO</code> for us, and all we have to do is write
a pure <code>String -&gt; String</code> function which transforms the input to the
output. In this case, we can split the input into <code>lines</code>, <code>drop</code> the
first line (we don’t need to know how many lines of input there
are—we just get a list of all of them, since <code>interact</code> will read
until EOF), <code>read</code> each number and turn it into the first digits
raised to the power of the last digit, then <code>sum</code> them and <code>show</code> the
result. The full solution is below. Notice how I use the “backwards
composition” operator <code>(&gt;&gt;&gt;)</code>, since I find it more convenient to type
from left to right as I’m thinking about transforming from input to
output.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Category</span> ((&gt;&gt;&gt;))</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="fu">interact</span> <span class="op">$</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">lines</span> <span class="op">&gt;&gt;&gt;</span> <span class="fu">drop</span> <span class="dv">1</span> <span class="op">&gt;&gt;&gt;</span> <span class="fu">map</span> (<span class="fu">read</span> <span class="op">&gt;&gt;&gt;</span> process) <span class="op">&gt;&gt;&gt;</span> <span class="fu">sum</span> <span class="op">&gt;&gt;&gt;</span> <span class="fu">show</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="ot">process ::</span> <span class="dt">Integer</span> <span class="ot">-&gt;</span> <span class="dt">Integer</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>process n <span class="ot">=</span> (n <span class="ot">`div`</span> <span class="dv">10</span>) <span class="op">^</span> (n <span class="ot">`mod`</span> <span class="dv">10</span>)</span></code></pre></div>
<p>I use <code>Integer</code> here since raw performance doesn’t matter much for
this easy problem, and <code>Integer</code> avoids any potential problems with
overflow. However, using <code>Int</code> instead of <code>Integer</code> can make a big
difference for some compute-intensive problems. On Kattis, <code>Int</code> will
always be 64 bits, but last time I checked <code>Int</code> can be 32 bits on
Codeforces.</p>
</section>
</section>
<section id="shopping-list-wholemeal-programming-and-bytestring" class="level2">
<h2>Shopping List: wholemeal programming and ByteString</h2>
<p>Let’s consider <a href="https://open.kattis.com/problems/shoppinglist">Shopping List</a> as a second example. In this
problem, we are given a list of shopping lists, where each shopping
list consists of a list of space-separated items on a single line. We
are asked to find the items which are common to all the shopping
lists, and print them in alphabetical order.</p>
<section id="wholemeal-programming-with-standard-data-structures" class="level3">
<h3>Wholemeal programming with standard data structures</h3>
<p>This problem is very amenable to a <a href="https://www.cs.ox.ac.uk/ralf.hinze/publications/ICFP09.pdf">“wholemeal programming”
approach</a>,
where we work entirely at the level of whole data structure
transformations rather than looping over individual elements. We can
turn each shopping list into a set, then find the intersection of all
the sets. Moreover, if we use <code>Data.Set</code>, which uses an ordering on
the elements, we will get the result in alphabetical order “for free”
(“free” as in the amount of code we have to write, not necessarily
runtime cost). Haskell has a decent collection of data structures in
the <code>containers</code> library (<code>(Int)Set</code>, <code>(Int)Map</code>, <code>Seq</code>, <code>Tree</code>, and
even <code>Graph</code>) with a large collection of standard methods to construct
and manipulate them, which are bread and butter for many competitive
programming problems.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE ImportQualifiedPost #-}</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Category</span> ((&gt;&gt;&gt;))</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Set</span> (<span class="dt">Set</span>)</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Set</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">S</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="fu">interact</span> <span class="op">$</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>  <span class="fu">lines</span> <span class="op">&gt;&gt;&gt;</span> <span class="fu">drop</span> <span class="dv">1</span> <span class="op">&gt;&gt;&gt;</span> <span class="fu">map</span> (<span class="fu">words</span> <span class="op">&gt;&gt;&gt;</span> S.fromList) <span class="op">&gt;&gt;&gt;</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>  <span class="fu">foldr1</span> S.intersection <span class="op">&gt;&gt;&gt;</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>  (\s <span class="ot">-&gt;</span> <span class="fu">show</span> (S.size s) <span class="op">:</span> S.toList s) <span class="op">&gt;&gt;&gt;</span> <span class="fu">unlines</span></span></code></pre></div>
</section>
<section id="bytestring-vs-string" class="level3">
<h3><code>ByteString</code> vs <code>String</code></h3>
<p>Unfortunately, when we try submitting this code, we get a Time Limit
Exceeded error! What’s wrong?</p>
<p>The issue is our use of <code>String</code>, which is an actual linked list of
characters and is very slow, especially when we have many short
strings, as in this problem. In the worst case, we could have 100
shopping lists, each with 5000 items of length 10, for a total of up
to 5 MB of input; with that much input data to read, any overhead
associated with reading and parsing the input can make a significant
difference.</p>
<p>Switching to <code>ByteString</code> is much faster. Why not <code>Text</code>, you ask?
Well, <code>Text</code> has to do a bunch of extra work to deal properly with
Unicode encodings, but in 99.99% of all competitive programming problems
I’ve ever seen, the input is guaranteed to be ASCII. So not
only do we not need <code>Text</code>, we can get away with a version of
<code>ByteString</code> that simply assumes every character is a single 8-bit
byte!</p>
<p>Once we import it, all we need to do is replace a bunch of
<code>String</code> operations with corresponding <code>ByteString</code> ones.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE ImportQualifiedPost #-}</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Category</span> ((&gt;&gt;&gt;))</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Set</span> (<span class="dt">Set</span>)</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Set</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">S</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.ByteString.Lazy.Char8</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">BS</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> BS.interact <span class="op">$</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>  BS.lines <span class="op">&gt;&gt;&gt;</span> <span class="fu">drop</span> <span class="dv">1</span> <span class="op">&gt;&gt;&gt;</span> <span class="fu">map</span> (BS.words <span class="op">&gt;&gt;&gt;</span> S.fromList) <span class="op">&gt;&gt;&gt;</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>  <span class="fu">foldr1</span> S.intersection <span class="op">&gt;&gt;&gt;</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>  (\s <span class="ot">-&gt;</span> BS.pack (<span class="fu">show</span> (S.size s)) <span class="op">:</span> S.toList s) <span class="op">&gt;&gt;&gt;</span> BS.unlines</span></code></pre></div>
</section>
</section>
<section id="a-favourable-ending-input-parsing-and-lazy-recursive-structures" class="level2">
<h2>A Favourable Ending: input parsing and lazy recursive structures</h2>
<p>As a last example, let’s look at <a href="https://open.kattis.com/problems/favourable">A Favourable
Ending</a>. This problem
consists of a number of test cases; each test case describes a
choose-your-own-adventure book with a number of sections, where each
section is either an ending (either good or bad), or allows the reader
to choose among three sections to proceed to next. For each test case,
we are asked how many distinct stories there are with good endings.</p>
<p>More abstractly, since we are guaranteed that there are no loops, the
sections of the book form a
<a href="https://en.wikipedia.org/wiki/Directed_acyclic_graph">DAG</a>, and we
are asked to count the number of distinct paths in a DAG from a
distinguished start node to any of a distinguished set of “good”
leaves.</p>
<section id="parsing-with-scanner" class="level3">
<h3>Parsing with Scanner</h3>
<p>Parsing the input for this problem is trickier than the other
examples so far. In theory, we could still ignore the first number
specifying the number of test cases, and just continue reading test
cases until EOF. However, each test case begins with a number
specifying the number of sections in the book, and we cannot ignore
this number: we need to know how many lines to read before the start
of the next test case. Doing this manually involves pattern-matching
on a list of lines, using <code>splitAt</code> to split off the lines for each
test case, and manually passing around the list of the remaining
lines: tedious.</p>
<p>Fortunately, Haskell is great at building abstractions to insulate us
from such tedium. I’ve developed a <a href="https://byorgey.github.io/blog/posts/2019/05/22/competitive-programming-in-haskell-scanner.html">simple <code>Scanner</code>
abstraction</a>
which works well in this context.</p>
<p>We begin by creating some data types to represent the input in
structured form:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Book</span> <span class="ot">=</span> <span class="dt">Map</span> <span class="dt">Int</span> <span class="dt">Section</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Section</span> <span class="ot">=</span> <span class="dt">End</span> <span class="dt">Disposition</span> <span class="op">|</span> <span class="dt">Choice</span> [<span class="dt">Int</span>]</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Eq</span>, <span class="dt">Show</span>)</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Disposition</span> <span class="ot">=</span> <span class="dt">Favourably</span> <span class="op">|</span> <span class="dt">Catastrophically</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Eq</span>, <span class="dt">Show</span>, <span class="dt">Read</span>)</span></code></pre></div>
<p>Now we can write a <code>Scanner</code> to read a <code>Book</code>:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ot">book ::</span> <span class="dt">Scanner</span> <span class="dt">Book</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>book <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  s <span class="ot">&lt;-</span> int</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  M.fromList <span class="op">&lt;$&gt;</span> s <span class="op">&gt;&lt;</span> ((,) <span class="op">&lt;$&gt;</span> int <span class="op">&lt;*&gt;</span> section)</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="ot">section ::</span> <span class="dt">Scanner</span> <span class="dt">Section</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>section <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>  t <span class="ot">&lt;-</span> peek</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">if</span> <span class="fu">isDigit</span> (BS.head t)</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">then</span> <span class="dt">Choice</span> <span class="op">&lt;$&gt;</span> (<span class="dv">3</span> <span class="op">&gt;&lt;</span> int)</span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">else</span> <span class="dt">End</span> <span class="op">.</span> readLower <span class="op">.</span> BS.unpack <span class="op">&lt;$&gt;</span> str</span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a><span class="ot">readLower ::</span> <span class="dt">Read</span> a <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> a</span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>readLower <span class="ot">=</span> <span class="fu">read</span> <span class="op">.</span> onHead <span class="fu">toUpper</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a><span class="ot">onHead ::</span> (a <span class="ot">-&gt;</span> a) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> [a]</span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a>onHead _ [] <span class="ot">=</span> []</span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a>onHead f (x <span class="op">:</span> xs) <span class="ot">=</span> f x <span class="op">:</span> xs</span></code></pre></div>
<p>(<code>readLower</code> and <code>onHead</code> are functions in my personal competitive
programming template, included here for completeness).</p>
<p>One more piece of boilerplate we can write at this point is the <code>main</code>
function, which simply consists of running the <code>Scanner</code> to read all the
test cases, solving each test case, and formatting the output.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> BS.interact <span class="op">$</span> runScanner (numberOf book) <span class="op">&gt;&gt;&gt;</span> <span class="fu">map</span> (solve <span class="op">&gt;&gt;&gt;</span> showB) <span class="op">&gt;&gt;&gt;</span> BS.unlines</span></code></pre></div>
</section>
<section id="dp-topsort-with-a-lazy-recursive-map" class="level3">
<h3>DP + topsort with a lazy recursive map</h3>
<p>With all that framework out of the way, we can turn to actually
solving the problem. And here is where something really fun happens.
In a typical imperative language, we would have to first topologically
sort the book sections, then use dynamic programming to compute the
number of good stories beginning at each section, starting with the
leaves and proceeding backwards through the topological sort to the
start—dozens of lines of code. However, in Haskell we can get all
of this for free, just by defining a lazy, recursive map!</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ot">solve ::</span> <span class="dt">Book</span> <span class="ot">-&gt;</span> <span class="dt">Int</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>solve book <span class="ot">=</span> endings <span class="op">!</span> <span class="dv">1</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>    endings <span class="ot">=</span> M.fromList [(p, endingsFrom (book<span class="op">!</span>p)) <span class="op">|</span> p <span class="ot">&lt;-</span> M.keys book]</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>    endingsFrom (<span class="dt">End</span> d) <span class="ot">=</span> <span class="kw">if</span> d <span class="op">==</span> <span class="dt">Favourably</span> <span class="kw">then</span> <span class="dv">1</span> <span class="kw">else</span> <span class="dv">0</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>    endingsFrom (<span class="dt">Choice</span> ps) <span class="ot">=</span> <span class="fu">sum</span> <span class="op">$</span> <span class="fu">map</span> (endings <span class="op">!</span>) ps</span></code></pre></div>
<p><code>endings</code> is a <code>Map</code> from each book section to the number of favorable
stories starting with that section. Notice how its values are defined
via the <code>endingsFrom</code> function, which is in turn defined, in the
<code>Choice</code> case, by looking up the values of the choices in the
<code>endings</code> map and summing them. <code>endings</code> is thus defined
recursively, which works because it is lazy in the values. When we
demand the value of <code>endings ! 1</code>, the runtime system starts evaluating
thunks in the map as needed, implicitly doing a topological sort for us.</p>
<p>Here’s another way to think about this: what we really want is the
function <code>endingsFrom : Section -&gt; Int</code>, which tells us how many good
endings there are starting at a given section. It can be defined via a
recurrence; however, if we were to literally implement it as a
recursive function, our program would spend a ridiculous amount of
time recomputing the same values over and over again. So, we insert a
lazy map in the middle to memoize it (there are <a href="https://byorgey.github.io/blog/posts/2023/06/06/dynamic-programming-in-haskell-automatic-memoization.html">other data
structures</a>
that can be used for this purpose as well).</p>
</section>
</section>
<section id="resources" class="level2">
<h2>Resources</h2>
<p>Here are some resources in case you’re interested in exploring more.</p>
<ul>
<li><a href="https://open.kattis.com">Open Kattis</a> has a collection of thousands
of high-quality problems which can be solved in Haskell (or many
other languages). If you just want to try solving some problems for
fun, it’s a great place to start.</li>
<li>There are also other sites which accept Haskell, such as
<a href="https://codeforces.com/">Codeforces</a>. Check these out if you want
to actually participate in timed contests.</li>
<li>My public <a href="http://ozark.hendrix.edu/~yorgey/kattis.html">listing of Kattis problems I have solved</a>, with my own personal
rating system.</li>
<li>I’ve written a series of <a href="https://byorgey.github.io/blog/tag/competitive%20programming.html">blog posts</a> about competitive
programming in Haskell, on a variety of topics.</li>
<li>I also have a <a href="https://github.com/byorgey/comprog-hs/">repository of modules</a> I’ve developed
specifically for competitive programming. Many of the modules are
documented in one or more blog posts.</li>
<li>Soumik Sarkar has an even <a href="https://github.com/meooow25/haccepted">larger collection of Haskell libraries for
competitive programming</a>.</li>
</ul>
</section>

</section>

<script data-isso="https://comments.byorgey.com/" src="https://comments.byorgey.com/js/embed.min.js"></script>
<section id="isso-thread"  data-title="Introduction to competitive programming in Haskell" >
  <noscript>Javascript needs to be activated to view comments.</noscript>
</section>

]]></description>
    <pubDate>Tue, 10 Jun 2025 00:00:00 UT</pubDate>
    <guid>http://byorgey.github.io/blog/posts/2025/06/10/comprog-hs-intro.html</guid>
    <dc:creator>Brent Yorgey</dc:creator>
</item>
<item>
    <title>Hendrix College Programming Contest 2025</title>
    <link>http://byorgey.github.io/blog/posts/2025/03/13/HCPC25.html</link>
    <description><![CDATA[
<h1>Hendrix College Programming Contest 2025</h1>

<div class="info">
  Posted on March 13, 2025
  
  
  <br />
  Tagged <a title="All pages tagged &#39;competitive programming&#39;." href="/tag/competitive%20programming.html" rel="tag">competitive programming</a>, <a title="All pages tagged &#39;Hendrix&#39;." href="/tag/Hendrix.html" rel="tag">Hendrix</a>, <a title="All pages tagged &#39;programming&#39;." href="/tag/programming.html" rel="tag">programming</a>, <a title="All pages tagged &#39;contest&#39;." href="/tag/contest.html" rel="tag">contest</a>, <a title="All pages tagged &#39;HCPC&#39;." href="/tag/HCPC.html" rel="tag">HCPC</a>, <a title="All pages tagged &#39;Kattis&#39;." href="/tag/Kattis.html" rel="tag">Kattis</a>
  
</div>

<a href="https://share.joinmastodon.org/#text=Hendrix College Programming Contest 2025 https://byorgey.github.io/blog/posts/2025/03/13/HCPC25.html" target="_blank" rel="noopener">Share on <svg role="img" aria-label="Mastodon" height="1em" viewBox="0 0 74 79" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M73.7014 17.4323C72.5616 9.05152 65.1774 2.4469 56.424 1.1671C54.9472 0.950843 49.3518 0.163818 36.3901 0.163818H36.2933C23.3281 0.163818 20.5465 0.950843 19.0697 1.1671C10.56 2.41145 2.78877 8.34604 0.903306 16.826C-0.00357854 21.0022 -0.100361 25.6322 0.068112 29.8793C0.308275 35.9699 0.354874 42.0498 0.91406 48.1156C1.30064 52.1448 1.97502 56.1419 2.93215 60.0769C4.72441 67.3445 11.9795 73.3925 19.0876 75.86C26.6979 78.4332 34.8821 78.8603 42.724 77.0937C43.5866 76.8952 44.4398 76.6647 45.2833 76.4024C47.1867 75.8033 49.4199 75.1332 51.0616 73.9562C51.0841 73.9397 51.1026 73.9184 51.1156 73.8938C51.1286 73.8693 51.1359 73.8421 51.1368 73.8144V67.9366C51.1364 67.9107 51.1302 67.8852 51.1186 67.862C51.1069 67.8388 51.0902 67.8184 51.0695 67.8025C51.0489 67.7865 51.0249 67.7753 50.9994 67.7696C50.9738 67.764 50.9473 67.7641 50.9218 67.7699C45.8976 68.9569 40.7491 69.5519 35.5836 69.5425C26.694 69.5425 24.3031 65.3699 23.6184 63.6327C23.0681 62.1314 22.7186 60.5654 22.5789 58.9744C22.5775 58.9477 22.5825 58.921 22.5934 58.8965C22.6043 58.8721 22.621 58.8505 22.6419 58.8336C22.6629 58.8167 22.6876 58.8049 22.714 58.7992C22.7404 58.7934 22.7678 58.794 22.794 58.8007C27.7345 59.9796 32.799 60.5746 37.8813 60.5733C39.1036 60.5733 40.3223 60.5733 41.5447 60.5414C46.6562 60.3996 52.0437 60.1408 57.0728 59.1694C57.1983 59.1446 57.3237 59.1233 57.4313 59.0914C65.3638 57.5847 72.9128 52.8555 73.6799 40.8799C73.7086 40.4084 73.7803 35.9415 73.7803 35.4523C73.7839 33.7896 74.3216 23.6576 73.7014 17.4323ZM61.4925 47.3144H53.1514V27.107C53.1514 22.8528 51.3591 20.6832 47.7136 20.6832C43.7061 20.6832 41.6988 23.2499 41.6988 28.3194V39.3803H33.4078V28.3194C33.4078 23.2499 31.3969 20.6832 27.3894 20.6832C23.7654 20.6832 21.9552 22.8528 21.9516 27.107V47.3144H13.6176V26.4937C13.6176 22.2395 14.7157 18.8598 16.9118 16.3545C19.1772 13.8552 22.1488 12.5719 25.8373 12.5719C30.1064 12.5719 33.3325 14.1955 35.4832 17.4394L37.5587 20.8853L39.6377 17.4394C41.7884 14.1955 45.0145 12.5719 49.2765 12.5719C52.9614 12.5719 55.9329 13.8552 58.2055 16.3545C60.4017 18.8574 61.4997 22.2371 61.4997 26.4937L61.4925 47.3144Z" fill="inherit"/></svg></a>
<section>
<p>I haven’t written on here in a while, mostly because a lot of my time
has gone into preparing for the second annual <a href="https://hendrix-cs.github.io/hcpc/">Hendrix College
Programming Contest</a>, which will
take place this <a href="https://www.timeanddate.com/worldclock/fixedtime.html?msg=Hendrix+College+Programming+Contest+2025&amp;iso=20250315T1230&amp;p1=134&amp;ah=5">Saturday, March 15, from 12:30-5:30pm CDT (17:30-22:30 UTC)</a>.</p>
<p>I’ve created an <a href="https://hcpc25.kattis.com/contests/vxtved">open mirror
contest</a> which will run in
parallel to the official contest, so if you want to grab some friends
and try solving some of the problems together using your favorite
language, be my guest!</p>

</section>

<script data-isso="https://comments.byorgey.com/" src="https://comments.byorgey.com/js/embed.min.js"></script>
<section id="isso-thread"  data-title="Hendrix College Programming Contest 2025" >
  <noscript>Javascript needs to be activated to view comments.</noscript>
</section>

]]></description>
    <pubDate>Thu, 13 Mar 2025 00:00:00 UT</pubDate>
    <guid>http://byorgey.github.io/blog/posts/2025/03/13/HCPC25.html</guid>
    <dc:creator>Brent Yorgey</dc:creator>
</item>
<item>
    <title>You could have invented Fenwick trees</title>
    <link>http://byorgey.github.io/blog/posts/2025/01/23/Fenwick.html</link>
    <description><![CDATA[
<h1>You could have invented Fenwick trees</h1>

<div class="info">
  Posted on January 23, 2025
  
  
  <br />
  Tagged <a title="All pages tagged &#39;Haskell&#39;." href="/tag/Haskell.html" rel="tag">Haskell</a>, <a title="All pages tagged &#39;segment&#39;." href="/tag/segment.html" rel="tag">segment</a>, <a title="All pages tagged &#39;Fenwick&#39;." href="/tag/Fenwick.html" rel="tag">Fenwick</a>, <a title="All pages tagged &#39;tree&#39;." href="/tag/tree.html" rel="tag">tree</a>, <a title="All pages tagged &#39;JFP&#39;." href="/tag/JFP.html" rel="tag">JFP</a>, <a title="All pages tagged &#39;journal&#39;." href="/tag/journal.html" rel="tag">journal</a>, <a title="All pages tagged &#39;paper&#39;." href="/tag/paper.html" rel="tag">paper</a>
  
</div>

<a href="https://share.joinmastodon.org/#text=You could have invented Fenwick trees https://byorgey.github.io/blog/posts/2025/01/23/Fenwick.html" target="_blank" rel="noopener">Share on <svg role="img" aria-label="Mastodon" height="1em" viewBox="0 0 74 79" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M73.7014 17.4323C72.5616 9.05152 65.1774 2.4469 56.424 1.1671C54.9472 0.950843 49.3518 0.163818 36.3901 0.163818H36.2933C23.3281 0.163818 20.5465 0.950843 19.0697 1.1671C10.56 2.41145 2.78877 8.34604 0.903306 16.826C-0.00357854 21.0022 -0.100361 25.6322 0.068112 29.8793C0.308275 35.9699 0.354874 42.0498 0.91406 48.1156C1.30064 52.1448 1.97502 56.1419 2.93215 60.0769C4.72441 67.3445 11.9795 73.3925 19.0876 75.86C26.6979 78.4332 34.8821 78.8603 42.724 77.0937C43.5866 76.8952 44.4398 76.6647 45.2833 76.4024C47.1867 75.8033 49.4199 75.1332 51.0616 73.9562C51.0841 73.9397 51.1026 73.9184 51.1156 73.8938C51.1286 73.8693 51.1359 73.8421 51.1368 73.8144V67.9366C51.1364 67.9107 51.1302 67.8852 51.1186 67.862C51.1069 67.8388 51.0902 67.8184 51.0695 67.8025C51.0489 67.7865 51.0249 67.7753 50.9994 67.7696C50.9738 67.764 50.9473 67.7641 50.9218 67.7699C45.8976 68.9569 40.7491 69.5519 35.5836 69.5425C26.694 69.5425 24.3031 65.3699 23.6184 63.6327C23.0681 62.1314 22.7186 60.5654 22.5789 58.9744C22.5775 58.9477 22.5825 58.921 22.5934 58.8965C22.6043 58.8721 22.621 58.8505 22.6419 58.8336C22.6629 58.8167 22.6876 58.8049 22.714 58.7992C22.7404 58.7934 22.7678 58.794 22.794 58.8007C27.7345 59.9796 32.799 60.5746 37.8813 60.5733C39.1036 60.5733 40.3223 60.5733 41.5447 60.5414C46.6562 60.3996 52.0437 60.1408 57.0728 59.1694C57.1983 59.1446 57.3237 59.1233 57.4313 59.0914C65.3638 57.5847 72.9128 52.8555 73.6799 40.8799C73.7086 40.4084 73.7803 35.9415 73.7803 35.4523C73.7839 33.7896 74.3216 23.6576 73.7014 17.4323ZM61.4925 47.3144H53.1514V27.107C53.1514 22.8528 51.3591 20.6832 47.7136 20.6832C43.7061 20.6832 41.6988 23.2499 41.6988 28.3194V39.3803H33.4078V28.3194C33.4078 23.2499 31.3969 20.6832 27.3894 20.6832C23.7654 20.6832 21.9552 22.8528 21.9516 27.107V47.3144H13.6176V26.4937C13.6176 22.2395 14.7157 18.8598 16.9118 16.3545C19.1772 13.8552 22.1488 12.5719 25.8373 12.5719C30.1064 12.5719 33.3325 14.1955 35.4832 17.4394L37.5587 20.8853L39.6377 17.4394C41.7884 14.1955 45.0145 12.5719 49.2765 12.5719C52.9614 12.5719 55.9329 13.8552 58.2055 16.3545C60.4017 18.8574 61.4997 22.2371 61.4997 26.4937L61.4925 47.3144Z" fill="inherit"/></svg></a>
<section>
<p>My paper, <a href="http://ozark.hendrix.edu/~yorgey/pub/Fenwick-ext.pdf">You could have invented Fenwick
trees</a>, has just
been published as a <a href="https://www.cambridge.org/core/services/aop-cambridge-core/content/view/B4628279D4E54229CED97249E96F721D/S0956796824000169a.pdf/you-could-have-invented-fenwick-trees.pdf">Functional Pearl in the Journal of Functional
Programming</a>.
This blog post is an advertisement for the paper, which presents a
novel way to derive the <em>Fenwick tree</em> data structure from first
principles.</p>
<p>Suppose we have a sequence of integers <span class="math inline">\(a_1, \dots, a_n\)</span> and want to be
able to perform two operations:</p>
<ul>
<li>we can <em>update</em> any <span class="math inline">\(a_i\)</span> by adding some value <span class="math inline">\(v\)</span> to it; or</li>
<li>we can perform a <em>range query</em>, which asks for the sum of the values
<span class="math inline">\(a_i + \dots + a_j\)</span> for any range <span class="math inline">\([i,j]\)</span>.</li>
</ul>
<p>There are several ways to solve this problem. For example:</p>
<ol type="1">
<li>We could just keep the sequence of integers in a mutable array.
Updating is <span class="math inline">\(O(1)\)</span>, but range queries are <span class="math inline">\(O(n)\)</span> since we must
actually loop through the range and add up all the values.</li>
<li>We could keep a separate array of <em>prefix sums</em> on the side, so
that <span class="math inline">\(P_i\)</span> stores the sum <span class="math inline">\(a_1 + \dots + a_i\)</span>. Then the range
query on <span class="math inline">\([i,j]\)</span> can be computed as <span class="math inline">\(P_j - P_{i-1}\)</span>, which only
takes <span class="math inline">\(O(1)\)</span>; however, updates now take <span class="math inline">\(O(n)\)</span> since we must also
update all the prefix sums which include the updated element.</li>
<li>We can get the best of both worlds using a <em>segment tree</em>, a binary
tree storing the elements at the leaves, with each internal node
caching the sum of its children. Then both update and range query
can be done in <span class="math inline">\(O(\lg n)\)</span>.</li>
</ol>
<p>I won’t go through the details of this third solution here, but it is
relatively straightforward to understand and implement, especially in
a functional language.</p>
<p>However, there is a fourth solution, known as a <em>Fenwick tree</em> or
<em>Fenwick array</em>, independently invented by <span class="citation" data-cites="ryabko1989fast">Ryabko (1989)</span> and
<span class="citation" data-cites="fenwick1994new">Fenwick (1994)</span>. Here’s a typical Java implementation of a Fenwick
tree:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode .java"><code class="sourceCode java"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> FenwickTree <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">private</span> <span class="dt">long</span><span class="op">[]</span> a<span class="op">;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">public</span> <span class="fu">FenwickTree</span><span class="op">(</span><span class="dt">int</span> n<span class="op">)</span> <span class="op">{</span> a <span class="op">=</span> <span class="kw">new</span> <span class="dt">long</span><span class="op">[</span>n<span class="op">+</span><span class="dv">1</span><span class="op">];</span> <span class="op">}</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">public</span> <span class="dt">long</span> <span class="fu">prefix</span><span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>        <span class="dt">long</span> s <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(;</span> i <span class="op">&gt;</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">-=</span> <span class="fu">LSB</span><span class="op">(</span>i<span class="op">))</span> s <span class="op">+=</span> a<span class="op">[</span>i<span class="op">];</span> <span class="cf">return</span> s<span class="op">;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">public</span> <span class="dt">void</span> <span class="fu">update</span><span class="op">(</span><span class="dt">int</span> i<span class="op">,</span> <span class="dt">long</span> delta<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(;</span> i <span class="op">&lt;</span> a<span class="op">.</span><span class="fu">length</span><span class="op">;</span> i <span class="op">+=</span> <span class="fu">LSB</span><span class="op">(</span>i<span class="op">))</span> a<span class="op">[</span>i<span class="op">]</span> <span class="op">+=</span> delta<span class="op">;</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">public</span> <span class="dt">long</span> <span class="fu">range</span><span class="op">(</span><span class="dt">int</span> i<span class="op">,</span> <span class="dt">int</span> j<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="fu">prefix</span><span class="op">(</span>j<span class="op">)</span> <span class="op">-</span> <span class="fu">prefix</span><span class="op">(</span>i<span class="op">-</span><span class="dv">1</span><span class="op">);</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">public</span> <span class="dt">long</span> <span class="fu">get</span><span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="fu">range</span><span class="op">(</span>i<span class="op">,</span>i<span class="op">);</span> <span class="op">}</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>    <span class="kw">public</span> <span class="dt">void</span> <span class="fu">set</span><span class="op">(</span><span class="dt">int</span> i<span class="op">,</span> <span class="dt">long</span> v<span class="op">)</span> <span class="op">{</span> <span class="fu">update</span><span class="op">(</span>i<span class="op">,</span> v <span class="op">-</span> <span class="fu">get</span><span class="op">(</span>i<span class="op">));</span> <span class="op">}</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>    <span class="kw">private</span> <span class="dt">int</span> <span class="fu">LSB</span><span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> i <span class="op">&amp;</span> <span class="op">(-</span>i<span class="op">);</span> <span class="op">}</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>I know what you’re thinking: what the heck!? There are some loops adding and
subtracting <code>LSB(i)</code>, which is defined as the bitwise AND of <code>i</code> and
<code>-i</code>? What on earth is this doing? Unless you have seen this
before, this code is probably a complete mystery, as it was for me the
first time I encountered it.</p>
<p>However, from the right point of view, we can derive this mysterious imperative
code as an optimization of segment trees. In particular, in my
paper I show how we can:</p>
<ol type="1">
<li>Start with a segment tree.</li>
<li>Delete some redundant info from the segment tree, and shove the
remaining values into an array in a systematic way.</li>
<li>Define operations for moving around in the resulting Fenwick array by
converting array indices to indices in a segment tree, moving
around the tree appropriately, and converting back.</li>
<li>Describe these operations using a Haskell EDSL for
infinite-precision 2’s complement binary arithmetic, and fuse away
all the intermediate conversion steps, until the above mysterious
implementation pops out.</li>
<li>Profit.</li>
</ol>
<p>I may be exaggerating step 5 a teensy bit. But you’ll find everything
else described in much greater detail, with pretty pictures, in the
paper! The <a href="https://www.cambridge.org/core/journals/journal-of-functional-programming/article/you-could-have-invented-fenwick-trees/B4628279D4E54229CED97249E96F721D">official JFP version is here</a>, and here’s an <a href="http://ozark.hendrix.edu/~yorgey/pub/Fenwick-ext.pdf">extended
version with an appendix containing an omitted proof</a>.</p>
<section id="references" class="level2 unnumbered">
<h2 class="unnumbered">References</h2>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="0" role="list">
<div id="ref-fenwick1994new" class="csl-entry" role="listitem">
Fenwick, Peter M. 1994. <span>“A New Data Structure for Cumulative Frequency Tables.”</span> <em>Software: Practice and <span>E</span>xperience</em> 24 (3): 327–36.
</div>
<div id="ref-ryabko1989fast" class="csl-entry" role="listitem">
Ryabko, Boris Yakovlevich. 1989. <span>“A Fast on-Line Code.”</span> In <em>Doklady Akademii Nauk</em>, 306:548–52. 3. Russian Academy of Sciences.
</div>
</div>
</section>

</section>

<script data-isso="https://comments.byorgey.com/" src="https://comments.byorgey.com/js/embed.min.js"></script>
<section id="isso-thread"  data-title="You could have invented Fenwick trees" >
  <noscript>Javascript needs to be activated to view comments.</noscript>
</section>

]]></description>
    <pubDate>Thu, 23 Jan 2025 00:00:00 UT</pubDate>
    <guid>http://byorgey.github.io/blog/posts/2025/01/23/Fenwick.html</guid>
    <dc:creator>Brent Yorgey</dc:creator>
</item>

    </channel>
</rss>
