Jekyll2024-02-07T17:44:47+00:00https://grahamenos.com/feed.xmlGraham Enosmath, programming, statistics, and dataGraham EnosEvaluating quantum generative models via imbalanced data classification benchmarks2023-08-22T00:00:00+00:002023-08-22T00:00:00+00:00https://grahamenos.com/gb-paper-announcement<h1 id="new-paper-who-dis">New paper, who dis?</h1>
<p>I’m excited to announce that our paper on using classification performance on
imbalanced datasets as a proxy for measuring generative model quality <a href="https://arxiv.org/abs/2308.10847">up on
the arXiv</a>!
It combines a lot of interesting techniques, like post-hoc testing, the
Bayesian boostrap, and explainable AI techniques, all to get an idea of how
well a quantum generative model performs.
Please check it out!</p>Graham EnosNew paper, who dis?A Rusty Quantum Interpreter2023-08-14T00:00:00+00:002023-08-14T00:00:00+00:00https://grahamenos.com/quantum-interpreter<h1 id="the-original">The Original</h1>
<p>Robert Smith, a.k.a. <code class="language-plaintext highlighter-rouge">stylewarning</code>, has a <a href="https://www.stylewarning.com/posts/quantum-interpreter/">lovely blog
post</a> that walks
through implementing an interpreter for a “general-purpose quantum programming
language called \( \mathscr{L} \).”
In only 150 lines of Common Lisp, <a href="https://github.com/stylewarning/quantum-interpreter/">the
implementation</a> is
featureful, self-contained, and a delight to read.</p>
<h1 id="imitation-is-the-highest-form-of-flattery">Imitation is the highest form of flattery</h1>
<p>At first I was content with only reading the post and code, but then <a href="https://twitter.com/Sheganinans/status/1683875551587741703">I
saw</a> someone else
had put together an OCaml implementation as well.
The game was afoot!</p>
<h1 id="carcinization">Carcinization</h1>
<p>Eventually I put together a <a href="https://github.com/genos/Workbench/tree/main/quantum-interpreter">Rust
implementation</a>.
This version weights in at more than twice the line count as the
original—even though it relies on
<a href="https://docs.rs/ndarray/latest/ndarray/index.html"><code class="language-plaintext highlighter-rouge">ndarray</code></a> for linear
algebra instead of implementing it by hand!
However, it does have a couple of features not present in the original (or
OCaml) implementation(s):</p>
<ul>
<li>constructing a <code class="language-plaintext highlighter-rouge">Machine</code> takes an unsigned 64-bit <code class="language-plaintext highlighter-rouge">seed</code> for repeatable PRNG
behavior; and</li>
<li>with the help of the <a href="https://docs.rs/peg/latest/peg/"><code class="language-plaintext highlighter-rouge">peg</code>
crate</a>, I added parsing, so one can pass
<code class="language-plaintext highlighter-rouge">"H 0\nMEASURE"</code> as a string and get an interpretable quantum program.</li>
</ul>
<h1 id="code-or-it-didnt-happen">Code or it didn’t happen</h1>
<p>The implementation is
<a href="https://github.com/genos/Workbench/tree/main/quantum-interpreter">here</a> in my
catch-all “workbench” repository.
It’s definitely <em>not</em> production-worthy code; it’s got an <code class="language-plaintext highlighter-rouge">assert!</code> that will
panic if not met, and it uses <code class="language-plaintext highlighter-rouge">expect</code> to pave over some errors.
Please feel free to take a look and let me know what you think!</p>Graham EnosThe OriginalRandom Art with a Tiny Language2023-06-02T00:00:00+00:002023-06-02T00:00:00+00:00https://grahamenos.com/random-art<h1 id="pl-resources-everywhere">PL Resources Everywhere</h1>
<p>In <a href="/kompreni.html">playing around with OCaml</a>, I’ve
spent some spare time perusing more programming language resources.
There are a bunch out there, especially in this era of online learning; for
instance, Cornell has made some
<a href="https://www.cs.cornell.edu/courses/cs6120/2020fa/lesson/">great</a>
<a href="https://www.cs.cornell.edu/courses/cs6110/2019sp/schedule.html">resources</a>
available.
In looking specifically for more ML-ish<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> flavored ones, I came across
<a href="https://ucsd-progsys.github.io/cse130/homeworks/hw2.html">this</a> fun undergrad
homework set.
In the second problem, it asks you to implement a tiny (recursively
defined) language of expressions encoding functions from the unit square to the
unit interval, \( [0, 1]^2 \mapsto [0, 1] \).</p>
<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">expr</span> <span class="o">=</span> <span class="nc">VarX</span>
<span class="o">|</span> <span class="nc">VarY</span>
<span class="o">|</span> <span class="nc">Sine</span> <span class="k">of</span> <span class="n">expr</span>
<span class="o">|</span> <span class="nc">Cosine</span> <span class="k">of</span> <span class="n">expr</span>
<span class="o">|</span> <span class="nc">Average</span> <span class="k">of</span> <span class="n">expr</span> <span class="o">*</span> <span class="n">expr</span>
<span class="o">|</span> <span class="nc">Times</span> <span class="k">of</span> <span class="n">expr</span> <span class="o">*</span> <span class="n">expr</span>
<span class="o">|</span> <span class="nc">Thresh</span> <span class="k">of</span> <span class="n">expr</span> <span class="o">*</span> <span class="n">expr</span> <span class="o">*</span> <span class="n">expr</span> <span class="o">*</span> <span class="n">expr</span>
</code></pre></div></div>
<p>After you learn to build them up randomly, you can evaluate them across the
unit square to generate pictures—have each output value encode either a
greyscale value, or one of an RGB triple.
Note to undergrads: <em>please</em> don’t cheat off me; you’ll only rob yourself of a
fun learning experience.</p>
<h1 id="no-peeking">No Peeking!</h1>
<p>This was a fun exercise in OCaml, but I also found it instructive to tackle it
<a href="https://github.com/genos/Workbench/tree/main/ra">in Rust</a> and compare.
Besides the superficial differences, Rust’s concern with and ability to control
memory usage is apparent.
I defined the core enumeration thusly:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">enum</span> <span class="n">Expr</span> <span class="p">{</span>
<span class="n">X</span><span class="p">,</span>
<span class="n">Y</span><span class="p">,</span>
<span class="nf">SinPi</span><span class="p">(</span><span class="nb">Box</span><span class="o"><</span><span class="n">Expr</span><span class="o">></span><span class="p">),</span>
<span class="nf">CosPi</span><span class="p">(</span><span class="nb">Box</span><span class="o"><</span><span class="n">Expr</span><span class="o">></span><span class="p">),</span>
<span class="nf">Mul</span><span class="p">(</span><span class="nb">Box</span><span class="o"><</span><span class="nb">Mul</span><span class="o">></span><span class="p">),</span>
<span class="nf">Avg</span><span class="p">(</span><span class="nb">Box</span><span class="o"><</span><span class="n">Avg</span><span class="o">></span><span class="p">),</span>
<span class="nf">Thresh</span><span class="p">(</span><span class="nb">Box</span><span class="o"><</span><span class="n">Thresh</span><span class="o">></span><span class="p">),</span>
<span class="p">}</span>
</code></pre></div></div>
<p>I renamed some variants to more accurately express their intent; e.g.
<code class="language-plaintext highlighter-rouge">SinPi(expr)</code> evaluates to \( sin(\pi \cdot \) <code class="language-plaintext highlighter-rouge">expr</code> \(\!)\).
More importantly, I reworked the recursive variants to each contain (at most) a
single <code class="language-plaintext highlighter-rouge">Box</code> (i.e. unique pointer to a heap allocated value); for instance,
<code class="language-plaintext highlighter-rouge">Expr::Mul</code> contains a <code class="language-plaintext highlighter-rouge">Box<Mul></code>, where <code class="language-plaintext highlighter-rouge">Mul</code> is defined as</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">struct</span> <span class="nb">Mul</span> <span class="p">{</span>
<span class="n">e1</span><span class="p">:</span> <span class="n">Expr</span><span class="p">,</span>
<span class="n">e2</span><span class="p">:</span> <span class="n">Expr</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>
<p>I took up this trick after
<a href="https://users.rust-lang.org/t/is-there-a-better-way-to-represent-an-abstract-syntax-tree/9549/4">learning</a>
more about it from the inimitable <a href="https://matklad.github.io/">matklad</a>.
As the linked response says, this keeps the size of the base enum smaller.
In the source code, I’ve got a <a href="https://github.com/genos/Workbench/blob/main/ra/src/lib.rs#L230-L233">property
test</a>
that asserts the size of an arbitrary<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> <code class="language-plaintext highlighter-rouge">Expr</code> is exactly 16 bytes<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup>:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[test]</span>
<span class="k">fn</span> <span class="nf">size_of</span><span class="p">(</span><span class="n">e</span> <span class="n">in</span> <span class="nf">arb_expr</span><span class="p">())</span> <span class="p">{</span>
<span class="nd">assert_eq!</span><span class="p">(</span><span class="nf">size_of_val</span><span class="p">(</span><span class="o">&</span><span class="n">e</span><span class="p">),</span> <span class="mi">16</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>If we instead went with a more direct translation of the OCaml code, like</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/src/lib.rs b/src/lib.rs
index 3b04a74..68c600c 100644
</span><span class="gd">--- a/src/lib.rs
</span><span class="gi">+++ b/src/lib.rs
</span><span class="p">@@ -7,9 +7,9 @@</span> pub enum Expr {
Y,
SinPi(Box<Expr>),
CosPi(Box<Expr>),
<span class="gd">- Mul(Box<Mul>),
- Avg(Box<Avg>),
- Thresh(Box<Thresh>),
</span><span class="gi">+ Mul { e1: Box<Expr>, e2: Box<Expr> },
+ Avg { e1: Box<Expr>, e2: Box<Expr> },
+ Thresh { e1: Box<Expr, e2: Box<Expr>, e3: Box<Expr>, e4: Box<Expr> },
</span> }
</code></pre></div></div>
<p>then this property test would no longer pass, as the enum needs to be large
enough to contain its largest variant.</p>
<h1 id="pretty-pics-plz">Pretty Pics Plz</h1>
<p>Once I coded up the library, I also put together a small
<a href="https://github.com/genos/Workbench/blob/main/ra/src/main.rs">executable</a> to
take in some parameters and generate greyscale or RGB pictures, similar to the
original exercise.
With that defined, I could run it a bunch of times using
<a href="https://www.oreilly.com/library/view/mac-os-x/0596003706/re254.html"><code class="language-plaintext highlighter-rouge">jot</code></a> to
generate random seeds and <a href="https://www.gnu.org/software/parallel/"><code class="language-plaintext highlighter-rouge">parallel</code></a>
to use multiple cores:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">jot</span> <span class="o">-</span><span class="n">w</span> <span class="o">%</span><span class="n">i</span> <span class="o">-</span><span class="n">r</span> <span class="mi">20</span> <span class="mi">0</span> <span class="mi">1000000000</span> <span class="p">|</span> <span class="n">parallel</span> <span class="o">--</span><span class="n">bar</span> <span class="err">.</span><span class="o">/</span><span class="n">target</span><span class="o">/</span><span class="n">release</span><span class="o">/</span><span class="n">ra</span> <span class="o">-</span><span class="n">s</span> <span class="p">{}</span> <span class="o">-</span><span class="n">d</span> <span class="mi">7</span> <span class="o">-</span><span class="n">r</span>
</code></pre></div></div>
<p>Here are some gems I found combing through the PNGs:</p>
<table>
<tr>
<td><img src="https://grahamenos.com/public/126089461_7_512_512_rgb.png " width="66" alt="RGB Image for seed=126089461, depth=7 width & height=512" /></td>
<td><img src="https://grahamenos.com/public/208259458_7_512_512_rgb.png " width="66" alt="RGB Image for seed=208259458, depth=7 width & height=512" /></td>
<td><img src="https://grahamenos.com/public/347723950_7_512_512_rgb.png " width="66" alt="RGB Image for seed=347723950, depth=7 width & height=512" /></td>
</tr>
<tr>
<td><img src="https://grahamenos.com/public/765744456_7_512_512_rgb.png " width="66" alt="RGB Image for seed=765744456, depth=7 width & height=512" /></td>
<td><img src="https://grahamenos.com/public/983185677_6_512_512_rgb.png " width="66" alt="RGB Image for seed=983185677, depth=6 width & height=512" /></td>
<td><img src="https://grahamenos.com/public/161582962_7_512_512_rgb.png " width="66" alt="RGB Image for seed=161582962, depth=7 width & height=512" /></td>
</tr>
<tr>
<td><img src="https://grahamenos.com/public/176235008_7_512_512_rgb.png " width="66" alt="RGB Image for seed=176235008, depth=7 width & height=512" /></td>
<td><img src="https://grahamenos.com/public/61786666_7_512_512_rgb.png " width="66" alt="RGB Image for seed=61786666, depth=6 width & height=512" /></td>
<td><img src="https://grahamenos.com/public/627656271_7_512_512_rgb.png " width="66" alt="RGB Image for seed=627656271, depth=7 width & height=512" /></td>
</tr>
</table>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p><a href="https://en.wikipedia.org/wiki/ML_(programming_language)">ML</a> as in OCaml
and SML, not machine learning. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>I <em>really</em> like property-based testing, in this case with
<a href="https://docs.rs/proptest/latest/proptest/"><code class="language-plaintext highlighter-rouge">proptest</code></a>. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>Since
<a href="https://doc.rust-lang.org/std/mem/fn.size_of_val.html"><code class="language-plaintext highlighter-rouge">size_of_val</code></a>
returns the size of the pointed-to value in bytes, this test returns 16 on
my 64-bit laptop; it will probably fail on a 32-bit architecture. Be sure
to check out
<a href="https://fasterthanli.me/articles/peeking-inside-a-rust-enum">this</a> awesome
article for more on Rust enums. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>Graham EnosPL Resources EverywhereKompreni: Understanding OCaml with Abstract Algebra Examples2023-05-11T00:00:00+00:002023-05-11T00:00:00+00:00https://grahamenos.com/kompreni<h1 id="why-and-wherefore">Why and wherefore</h1>
<p>I’ve wanted to level up my <a href="https://ocaml.org/">OCaml</a> understanding for a
while now, but between doing a fair amount of work in Rust at my current job
and already having a bit of Haskell, I wasn’t sure I could justify the
“distraction.”
But between some <a href="https://cs3110.github.io/textbook/cover.html">excellent</a>
resources available <a href="https://dev.realworldocaml.org/index.html">online</a>, some
interesting reading (more on that in a moment), and the newest <a href="https://ocaml.org/releases/5.0.0">5.0.0
release</a>, I decided it was time to dig in!</p>
<h1 id="oleg-kiselyov-does-something-cool-news-at-11">Oleg Kiselyov does something cool, news at 11</h1>
<p>The first reading topic I’ve stumbled across recently come from an extremely
prolific CS researcher, <a href="https://okmij.org/ftp/">Oleg Kiselyov</a> who has written
a lot of amazing papers and code.
One such project is the <a href="https://okmij.org/ftp/tagless-final/">tagless-final</a>
style of embedding domain-specific languages in a typed functional language
like Haskell or OCaml.
I can’t do it justice, it’s truly amazing stuff, you should go read it
yourself.
But!
Having seen some of the work before in Haskell, it was intriguing to look
through this work and compare and contrast Haskell and OCaml versions.</p>
<h1 id="modules-modules-modules">Modules modules modules</h1>
<p>The second topic is modules, as in <a href="https://www.stephendiehl.com/posts/exotic01.html">“module systems” and “modular
programming”</a>.<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>
They’re really interesting; indeed, some say <a href="https://existentialtype.wordpress.com/2011/04/16/modules-matter-most/">modules matter
most</a>.
OCaml (like SML and other related languages) allow for some really interesting
flexibility around designing and implementing interfaces.
I won’t be able to explain as well as the above link or
<a href="https://www.pathsensitive.com/2023/03/modules-matter-most-for-masses.html">this</a>
more verbose and less esoteric explanation.</p>
<h1 id="algebraic-building-blocks">Algebraic building blocks</h1>
<p>Which leads me to the point of my little
project named <a href="https://github.com/genos/kompreni/"><code class="language-plaintext highlighter-rouge">kompreni</code></a>.
While it is certainly nowhere near as complete as, say,
<a href="https://github.com/Risto-Stevcev/bastet/"><code class="language-plaintext highlighter-rouge">bastet</code></a>,<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> I wanted to use
describing abstract algebra ideas as a way to explore expressing things in
OCaml.</p>
<p>We’ll start with a <a href="https://en.wikipedia.org/wiki/Semigroup">semigroup</a>; a
semigroup consists of a set \( S \) and an associative binary operation \( \cdot \)
on that set; that is, for any \(x\), \(y\), and \(z\) in \(S\), it must be the
case that \( x \cdot (y \cdot z) = (x \cdot y) \cdot z \).</p>
<p>In <code class="language-plaintext highlighter-rouge">kompreni</code>, I’ve written a <code class="language-plaintext highlighter-rouge">Signature</code> for semigroups:</p>
<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="k">type</span> <span class="nc">Signature</span> <span class="o">=</span> <span class="k">sig</span>
<span class="k">type</span> <span class="n">t</span>
<span class="k">val</span> <span class="p">(</span> <span class="o">+&</span> <span class="p">)</span> <span class="o">:</span> <span class="n">t</span> <span class="o">-></span> <span class="n">t</span> <span class="o">-></span> <span class="n">t</span>
<span class="k">end</span>
</code></pre></div></div>
<p>along with an accompanying <code class="language-plaintext highlighter-rouge">Laws</code> functor, a function which takes <em>any</em> module
implementing the above <code class="language-plaintext highlighter-rouge">Signature</code> and creates a new module:</p>
<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nc">Laws</span> <span class="p">(</span><span class="nc">S</span> <span class="o">:</span> <span class="nc">Signature</span><span class="p">)</span> <span class="o">=</span> <span class="k">struct</span>
<span class="k">open</span> <span class="nc">S</span>
<span class="k">let</span> <span class="n">associative</span> <span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">=</span> <span class="n">x</span> <span class="o">+&</span> <span class="p">(</span><span class="n">y</span> <span class="o">+&</span> <span class="n">z</span><span class="p">)</span> <span class="o">=</span> <span class="n">x</span> <span class="o">+&</span> <span class="n">y</span> <span class="o">+&</span> <span class="n">z</span>
<span class="k">end</span>
</code></pre></div></div>
<p>One thing I miss compared to Haskell is being able to specify the precedence
and associativity of user-defined operators like <code class="language-plaintext highlighter-rouge">+&</code>.
Since it begins with the plus symbol, OCaml treats it like a plus; ah well.
That means that this expression above, when formatted with <a href="https://github.com/ocaml/dune"><code class="language-plaintext highlighter-rouge">dune
fmt</code></a>, looks like it’s missing some parentheses;
OCaml says <code class="language-plaintext highlighter-rouge">+</code> is left-associative, so it says <code class="language-plaintext highlighter-rouge">+&</code> is too.</p>
<p>With that signature and functor together, I’ve next turned to
<a href="https://github.com/c-cube/qcheck"><code class="language-plaintext highlighter-rouge">qcheck</code></a> for property-based testing in
OCaml.
For instance, in <code class="language-plaintext highlighter-rouge">kompreni</code>’s test suite I’ve got the following.
First we define a base signature for testing:</p>
<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="k">type</span> <span class="nc">Testable</span> <span class="o">=</span> <span class="k">sig</span>
<span class="k">type</span> <span class="n">t</span>
<span class="k">val</span> <span class="n">gen</span> <span class="o">:</span> <span class="n">t</span> <span class="nn">QCheck2</span><span class="p">.</span><span class="nn">Gen</span><span class="p">.</span><span class="n">t</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Then we combine it with the <code class="language-plaintext highlighter-rouge">Signature</code> above to actually test the <code class="language-plaintext highlighter-rouge">associative</code> property:</p>
<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nc">SemigroupLaws</span> <span class="p">(</span><span class="nc">X</span> <span class="o">:</span> <span class="nc">Testable</span><span class="p">)</span> <span class="p">(</span><span class="nc">S</span> <span class="o">:</span> <span class="nn">Semigroup</span><span class="p">.</span><span class="nc">Signature</span> <span class="k">with</span> <span class="k">type</span> <span class="n">t</span> <span class="o">=</span> <span class="nn">X</span><span class="p">.</span><span class="n">t</span><span class="p">)</span> <span class="o">=</span>
<span class="k">struct</span>
<span class="k">include</span> <span class="nn">Semigroup</span><span class="p">.</span><span class="nc">Laws</span> <span class="p">(</span><span class="nc">S</span><span class="p">)</span>
<span class="k">let</span> <span class="n">tests</span> <span class="o">=</span>
<span class="p">[</span>
<span class="n">make_test</span>
<span class="nn">QCheck2</span><span class="p">.</span><span class="nn">Gen</span><span class="p">.(</span><span class="n">triple</span> <span class="nn">X</span><span class="p">.</span><span class="n">gen</span> <span class="nn">X</span><span class="p">.</span><span class="n">gen</span> <span class="nn">X</span><span class="p">.</span><span class="n">gen</span><span class="p">)</span>
<span class="s2">"associative"</span> <span class="p">(</span><span class="n">uncurry3</span> <span class="n">associative</span><span class="p">);</span>
<span class="p">]</span>
<span class="k">end</span>
</code></pre></div></div>
<p>With other scaffolding (like <code class="language-plaintext highlighter-rouge">uncurry3</code>) defined elsewhere, this takes two
modules—one implementing the testable interface and another that is a
<code class="language-plaintext highlighter-rouge">Semigroup</code> with the <em>same</em> internal type <code class="language-plaintext highlighter-rouge">t</code>—and defines a list of <code class="language-plaintext highlighter-rouge">qcheck</code> tests.</p>
<p><code class="language-plaintext highlighter-rouge">kompreni</code> also contains <a href="https://en.wikipedia.org/wiki/Monoid">monoids</a>,
semigroups with an identity element we’ll call <code class="language-plaintext highlighter-rouge">zero</code>:</p>
<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="k">type</span> <span class="nc">Signature</span> <span class="o">=</span> <span class="k">sig</span>
<span class="k">include</span> <span class="nn">Semigroup</span><span class="p">.</span><span class="nc">Signature</span>
<span class="k">val</span> <span class="n">zero</span> <span class="o">:</span> <span class="n">t</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Note that <code class="language-plaintext highlighter-rouge">include</code> statement, which says “bring in the body of the <code class="language-plaintext highlighter-rouge">Semigroup</code>
signature, too.”
We also have more <code class="language-plaintext highlighter-rouge">Laws</code> for monoids to fulfill, in addition to <code class="language-plaintext highlighter-rouge">associative</code>:</p>
<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nc">Laws</span> <span class="p">(</span><span class="nc">M</span> <span class="o">:</span> <span class="nc">Signature</span><span class="p">)</span> <span class="o">=</span> <span class="k">struct</span>
<span class="k">open</span> <span class="nc">M</span>
<span class="k">include</span> <span class="nn">Semigroup</span><span class="p">.</span><span class="nc">Laws</span> <span class="p">(</span><span class="nc">M</span><span class="p">)</span>
<span class="k">let</span> <span class="n">left_id</span> <span class="n">x</span> <span class="o">=</span> <span class="n">zero</span> <span class="o">+&</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span>
<span class="k">let</span> <span class="n">right_id</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span> <span class="o">+&</span> <span class="n">zero</span> <span class="o">=</span> <span class="n">x</span>
<span class="k">end</span>
</code></pre></div></div>
<p>which we can also test:</p>
<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nc">MonoidLaws</span> <span class="p">(</span><span class="nc">X</span> <span class="o">:</span> <span class="nc">Testable</span><span class="p">)</span> <span class="p">(</span><span class="nc">M</span> <span class="o">:</span> <span class="nn">Monoid</span><span class="p">.</span><span class="nc">Signature</span> <span class="k">with</span> <span class="k">type</span> <span class="n">t</span> <span class="o">=</span> <span class="nn">X</span><span class="p">.</span><span class="n">t</span><span class="p">)</span> <span class="o">=</span>
<span class="k">struct</span>
<span class="k">include</span> <span class="nn">Monoid</span><span class="p">.</span><span class="nc">Laws</span> <span class="p">(</span><span class="nc">M</span><span class="p">)</span>
<span class="k">let</span> <span class="n">tests</span> <span class="o">=</span>
<span class="k">let</span> <span class="k">module</span> <span class="nc">SL</span> <span class="o">=</span> <span class="nc">SemigroupLaws</span> <span class="p">(</span><span class="nc">X</span><span class="p">)</span> <span class="p">(</span><span class="nc">M</span><span class="p">)</span> <span class="k">in</span>
<span class="nn">List</span><span class="p">.</span><span class="n">map</span> <span class="p">(</span><span class="n">uncurry2</span> <span class="p">(</span><span class="n">make_test</span> <span class="nn">X</span><span class="p">.</span><span class="n">gen</span><span class="p">))</span>
<span class="p">[</span> <span class="p">(</span><span class="s2">"left id"</span><span class="o">,</span> <span class="n">left_id</span><span class="p">);</span> <span class="p">(</span><span class="s2">"right id"</span><span class="o">,</span> <span class="n">right_id</span><span class="p">)</span> <span class="p">]</span>
<span class="o">@</span> <span class="nn">SL</span><span class="p">.</span><span class="n">tests</span>
<span class="k">end</span>
</code></pre></div></div>
<h1 id="semirings-in-paradise">Semirings in paradise</h1>
<p>This post is already getting too long, so I’ll finish with my favorite example.
I think this setup shows the power of OCaml modules, but also shows a place
where either I don’t know how to use them well enough (<em>very</em> plausible!) or
they fall just a tad short of what I’d like.</p>
<p>Consider <a href="https://en.wikipedia.org/wiki/Semiring">semirings</a>, which consist of
a set of elements \( S \), <em>two</em> operations \( + \) and \( \cdot \), and
two special elements \(0\) and \(1\) such that:</p>
<ul>
<li>\((S, +, 0)\) forms a commutative (i.e. \(x + y = y + x\)) monoid,</li>
<li>\((S, \cdot, 1)\) is a monoid,</li>
<li>multiplication of anything by \(0\) returns \(0\), and</li>
<li>multiplication \(\cdot\) distributes over \(+\).</li>
</ul>
<p>My absolute favorite semiring is the <a href="https://en.wikipedia.org/wiki/Tropical_semiring">Tropical
semiring</a>, also known as the
min-plus semiring, which consists of:</p>
<ul>
<li>\( \mathbb{R} \cup \infty \), numbers that are either finite real numbers or infinite,</li>
<li>\(x + y\) is defined to be \(\min(x, y)\) wiht identity element \(\infty\), and</li>
<li>\(x \cdot y\) is defined to be \(x + y\) in the usual sense, so its identity is zero.</li>
</ul>
<p>Here’s <code class="language-plaintext highlighter-rouge">kompreni</code>’s implementation<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup>:</p>
<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nc">MinPlus</span> <span class="o">=</span> <span class="k">struct</span>
<span class="k">type</span> <span class="n">t</span> <span class="o">=</span> <span class="nc">Finite</span> <span class="k">of</span> <span class="nn">Q</span><span class="p">.</span><span class="n">t</span> <span class="o">|</span> <span class="nc">Infinite</span>
<span class="k">let</span> <span class="p">(</span> <span class="o">+&</span> <span class="p">)</span> <span class="n">a</span> <span class="n">b</span> <span class="o">=</span>
<span class="k">match</span> <span class="p">(</span><span class="n">a</span><span class="o">,</span> <span class="n">b</span><span class="p">)</span> <span class="k">with</span>
<span class="o">|</span> <span class="nc">Finite</span> <span class="n">x</span><span class="o">,</span> <span class="nc">Finite</span> <span class="n">y</span> <span class="o">-></span> <span class="nc">Finite</span> <span class="p">(</span><span class="nn">Q</span><span class="p">.</span><span class="n">max</span> <span class="n">x</span> <span class="n">y</span><span class="p">)</span>
<span class="o">|</span> <span class="nc">Finite</span> <span class="n">_</span><span class="o">,</span> <span class="n">_</span> <span class="o">-></span> <span class="n">a</span>
<span class="o">|</span> <span class="n">_</span><span class="o">,</span> <span class="nc">Finite</span> <span class="n">_</span> <span class="o">-></span> <span class="n">b</span>
<span class="o">|</span> <span class="n">_</span><span class="o">,</span> <span class="n">_</span> <span class="o">-></span> <span class="nc">Infinite</span>
<span class="k">let</span> <span class="n">zero</span> <span class="o">=</span> <span class="nc">Infinite</span>
<span class="k">let</span> <span class="p">(</span> <span class="o">*&</span> <span class="p">)</span> <span class="n">a</span> <span class="n">b</span> <span class="o">=</span>
<span class="k">match</span> <span class="p">(</span><span class="n">a</span><span class="o">,</span> <span class="n">b</span><span class="p">)</span> <span class="k">with</span>
<span class="o">|</span> <span class="nc">Finite</span> <span class="n">x</span><span class="o">,</span> <span class="nc">Finite</span> <span class="n">y</span> <span class="o">-></span> <span class="nc">Finite</span> <span class="p">(</span><span class="nn">Q</span><span class="p">.</span><span class="n">add</span> <span class="n">x</span> <span class="n">y</span><span class="p">)</span>
<span class="o">|</span> <span class="n">_</span><span class="o">,</span> <span class="n">_</span> <span class="o">-></span> <span class="nc">Infinite</span>
<span class="k">let</span> <span class="n">one</span> <span class="o">=</span> <span class="nc">Finite</span> <span class="nn">Q</span><span class="p">.</span><span class="n">zero</span>
<span class="k">end</span>
</code></pre></div></div>
<p>And here are the laws that a <code class="language-plaintext highlighter-rouge">Semiring</code> must abide by in <code class="language-plaintext highlighter-rouge">kompreni</code>:</p>
<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nc">Laws</span> <span class="p">(</span><span class="nc">S</span> <span class="o">:</span> <span class="nc">Signature</span><span class="p">)</span> <span class="o">=</span> <span class="k">struct</span>
<span class="k">open</span> <span class="nc">S</span>
<span class="k">include</span> <span class="nn">Commutative_monoid</span><span class="p">.</span><span class="nc">Laws</span> <span class="p">(</span><span class="nc">S</span><span class="p">)</span>
<span class="c">(* (S, 1, *&) is also a Monoid *)</span>
<span class="k">let</span> <span class="n">times_associative</span> <span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">=</span> <span class="n">x</span> <span class="o">*&</span> <span class="p">(</span><span class="n">y</span> <span class="o">*&</span> <span class="n">z</span><span class="p">)</span> <span class="o">=</span> <span class="n">x</span> <span class="o">*&</span> <span class="n">y</span> <span class="o">*&</span> <span class="n">z</span>
<span class="k">let</span> <span class="n">times_left_one</span> <span class="n">x</span> <span class="o">=</span> <span class="n">one</span> <span class="o">*&</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span>
<span class="k">let</span> <span class="n">times_right_one</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span> <span class="o">*&</span> <span class="n">one</span> <span class="o">=</span> <span class="n">x</span>
<span class="c">(* Zero annihilates *)</span>
<span class="k">let</span> <span class="n">zero_annihilates_left</span> <span class="n">x</span> <span class="o">=</span> <span class="n">zero</span> <span class="o">*&</span> <span class="n">x</span> <span class="o">=</span> <span class="n">zero</span>
<span class="k">let</span> <span class="n">zero_annihilates_right</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span> <span class="o">*&</span> <span class="n">zero</span> <span class="o">=</span> <span class="n">zero</span>
<span class="c">(* Distributivity *)</span>
<span class="k">let</span> <span class="n">left_distributive</span> <span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">=</span> <span class="n">x</span> <span class="o">*&</span> <span class="p">(</span><span class="n">y</span> <span class="o">+&</span> <span class="n">z</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span> <span class="o">*&</span> <span class="n">y</span><span class="p">)</span> <span class="o">+&</span> <span class="p">(</span><span class="n">x</span> <span class="o">*&</span> <span class="n">z</span><span class="p">)</span>
<span class="k">let</span> <span class="n">right_distributive</span> <span class="n">x</span> <span class="n">y</span> <span class="n">z</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span> <span class="o">+&</span> <span class="n">y</span><span class="p">)</span> <span class="o">*&</span> <span class="n">z</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span> <span class="o">*&</span> <span class="n">z</span><span class="p">)</span> <span class="o">+&</span> <span class="p">(</span><span class="n">y</span> <span class="o">*&</span> <span class="n">z</span><span class="p">)</span>
<span class="k">end</span>
</code></pre></div></div>
<p>I <em>really</em> like being able to include previous law definitions in new ones; for
instance, having defined the <code class="language-plaintext highlighter-rouge">Commutative_monoid.Laws</code> functor, the line
<code class="language-plaintext highlighter-rouge">include Commutative_monoid.Laws (S)</code> ensures that I include all those laws
into my tests for almost free—ensuring that I test \((S, +, 0)\) is indeed
a commutative monoid.
However, I don’t see a way to cleverly check \((S, ⋅, 1)\) is also a monoid
without writing out the <code class="language-plaintext highlighter-rouge">times_</code> rules explicitly.
Maybe I need more OCaml module & functor goodness?
<code class="language-plaintext highlighter-rouge">bastet</code> forgoes wrapping the monoid definitions and laws into the semiring one, for what it’s worth.</p>
<h1 id="fin">Fin.</h1>
<p>While I miss the usability of <code class="language-plaintext highlighter-rouge">cargo</code> from Rust and some fun things from
Haskell, OCaml is fun and eye-opening!
Please feel free to head to <a href="https://github.com/genos/kompreni/">GitHub</a> to
check out the code.</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>Not to be confused with a <a href="https://en.wikipedia.org/wiki/Module_(mathematics)">module over a ring</a> or one of the <a href="https://en.wikipedia.org/wiki/Module">many other</a> definitions of “module.” <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Nor will it likely <em>ever</em> be. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>Rather than floats, this uses rational numbers from <a href="https://github.com/ocaml/Zarith"><code class="language-plaintext highlighter-rouge">zarith</code></a> for finite values. Using \(\mathbb{Q}\) is not the same as using \(\mathbb{R}\), but this still forms a semiring! Also it’s really, <em>really</em> hard to represent arbitrary real numbers in software. For instance, the associativity tests fail if you use OCaml floats, because <a href="https://www.quora.com/Why-are-floating-point-numbers-defined-as-float-instead-of-real">floating point numbers aren’t real</a>. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>Graham EnosWhy and whereforeScum: write me a Scheme-ish2023-04-20T00:00:00+00:002023-04-20T00:00:00+00:00https://grahamenos.com/scum<h1 id="a-wretched-hive-of-scum-and-villainy">A wretched hive of scum and villainy</h1>
<p>With it being my birthday today, I took a little bit of time to noodle on a pet project.
For all the computer science classes I’ve taken, books I’ve read, course notes I’ve looked through, and code I’ve written, reviewed, or perused, I had yet to implement any sort of Lisp-like language myself.
Having decided to change that, I’ve been toying around for the last month or so on <a href="https://github.com/genos/scum"><code class="language-plaintext highlighter-rouge">scum</code></a>, a Scheme-ish, Lisp-like language implementation.
It’s by no means good<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> in any sense of the word; it’s incomplete, under-commented, probably loaded with bugs, undoubtedly slow, and profligate with its memory usage.
However, as of today, it’s cleared the bar I set for myself for being a reasonable-ish implementation: I can define and call <a href="https://en.wikipedia.org/wiki/Lambda_calculus">lambdas</a> from the REPL!</p>
<h1 id="how-long-is-a-piece-of-string">How long is a piece of string</h1>
<p>There’s not a lot of code currently, so feel free to peruse the <a href="https://github.com/genos/scum">repo</a> yourself:</p>
<div class="language-zsh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/github/scum ∃ l
Permissions Size User Date Modified Git Name
.rw-r--r--@ 25k genos 13 Apr 14:58 <span class="nt">--</span> Cargo.lock
.rw-r--r--@ 94 genos 13 Apr 14:58 <span class="nt">--</span> Cargo.toml
.rw-r--r--@ 1.1k genos 13 Apr 14:58 <span class="nt">--</span> LICENSE
.rw-r--r--@ 56 genos 13 Apr 14:58 <span class="nt">--</span> README.md
drwxr-xr-x@ - genos 20 Apr 15:18 <span class="nt">--</span> scum-lib
drwxr-xr-x@ - genos 13 Apr 14:58 <span class="nt">--</span> scum-repl
drwxr-xr-x@ - genos 20 Apr 13:22 <span class="nt">-I</span> target
~/github/scum ∃ tokei
<span class="o">===============================================================================</span>
Language Files Lines Code Comments Blanks
<span class="o">===============================================================================</span>
Markdown 1 3 0 2 1
Pest 1 38 26 8 4
Rust 8 628 577 9 42
TOML 3 27 23 0 4
<span class="o">===============================================================================</span>
Total 13 696 626 19 51
<span class="o">===============================================================================</span>
</code></pre></div></div>
<p>By no means as succinct as, say <a href="https://github.com/Robert-van-Engelen/tinylisp"><code class="language-plaintext highlighter-rouge">tinylisp</code></a>, nor as complete as the <a href="https://github.com/kanaka/mal"><code class="language-plaintext highlighter-rouge">mal</code> implementations</a>, <code class="language-plaintext highlighter-rouge">scum</code> consists of</p>
<ul>
<li>a Rust library which defines the basic expression type, as well as a single step of the read-eval-print loop, and</li>
<li>a Rust executable which does little more than reach out to <a href="https://docs.rs/rustyline/latest/rustyline/"><code class="language-plaintext highlighter-rouge">rustyline</code></a> to provide an interactive REPL:</li>
</ul>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">λ</span><span class="nv">></span> <span class="p">(</span><span class="k">define</span> <span class="nv">square</span> <span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">x</span><span class="p">)</span> <span class="p">(</span><span class="nb">*</span> <span class="nv">x</span> <span class="nv">x</span><span class="p">)))</span>
<span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">x</span><span class="p">)</span> <span class="p">(</span><span class="nb">*</span> <span class="nv">x</span> <span class="nv">x</span><span class="p">))</span>
<span class="err">λ</span><span class="nv">></span> <span class="p">(</span><span class="nf">square</span> <span class="mi">39</span><span class="p">)</span>
<span class="mi">1521</span>
</code></pre></div></div>
<p>I originally started in Haskell, but decided to shift to Rust because I kind of wanted this to be an exercise in satisfying an annoying pedant; Haskell provides so much already, it almost felt like cheating to use it.
Besides the aforementioned <code class="language-plaintext highlighter-rouge">rustyline</code> crate in <code class="language-plaintext highlighter-rouge">scum-repl</code>, I’ve used <a href="https://pest.rs/"><code class="language-plaintext highlighter-rouge">pest</code> and <code class="language-plaintext highlighter-rouge">pest_derive</code></a> for parsing and <a href="https://docs.rs/crate/thiserror/latest"><code class="language-plaintext highlighter-rouge">thiserror</code></a> for organizing the sundry reasons things can go wrong.
While <code class="language-plaintext highlighter-rouge">pest</code> was new to me and has been fun, I’ve used <code class="language-plaintext highlighter-rouge">thiserror</code> on other projects at <code class="language-plaintext highlighter-rouge">$WORK</code> before; I absolutely would <em>not</em> write any substantial Rust project without it at this point.</p>
<h1 id="inspirations">Inspirations</h1>
<p>I wouldn’t have gotten even this far on <code class="language-plaintext highlighter-rouge">scum</code><sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> without the help of</p>
<ul>
<li><a href="https://github.com/kanaka/mal"><code class="language-plaintext highlighter-rouge">mal</code></a>,</li>
<li>“Write you a Scheme,” the <a href="https://wespiser.com/writings/wyas/00_overview.html">2.0 update</a> and the <a href="https://en.wikibooks.org/wiki/Write_Yourself_a_Scheme_in_48_Hours">OG version</a>,</li>
<li>SICP, both the <a href="https://en.wikipedia.org/wiki/Structure_and_Interpretation_of_Computer_Programs">book</a> and the <a href="https://ocw.mit.edu/courses/6-001-structure-and-interpretation-of-computer-programs-spring-2005/video_galleries/video-lectures/">video lectures</a>,</li>
<li>Peter Norvig’s <a href="https://norvig.com/lispy.html">beautifully</a> clean <a href="https://norvig.com/lispy2.html">Python</a> implementations.</li>
</ul>
<h1 id="postscript">Postscript</h1>
<p>👋 to the former coworker who enjoined me to blog more!
I miss working with you, friend.</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>It’s the exact <em>opposite</em> of <a href="https://news.ycombinator.com/item?id=3067434"><code class="language-plaintext highlighter-rouge">raganwald</code>’s</a> README section, inspiration <a href="https://github.com/glenjamin/node-fib#is-it-any-good">here</a>. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩︎</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>I didn’t consume all of this recently in my quest to put <code class="language-plaintext highlighter-rouge">scum</code> together, but I would almost certainly be remiss in not mentioning these; in fact, I’m probably leaving lots out! <a href="#fnref:2" class="reversefootnote" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>Graham EnosA wretched hive of scum and villainyAlgebraic Structure ⇒ Computational Benefits, Now With 100% More Oxidization2022-09-13T00:00:00+00:002022-09-13T00:00:00+00:00https://grahamenos.com/ascb-in-rust<h1 id="code-or-it-didnt-happen">Code or it didn’t happen</h1>
<p>I’ve been noodling with a Rust implementation of the ideas from <a href="/algebraic-structure.html">this talk</a>, and decided I should probably share it—or at least put it up online in case my laptop crashes.
The repo is available <a href="https://github.com/genos/ascb">here</a>.</p>Graham EnosCode or it didn’t happenTime Traveling Key-Value Store, This Time in Rust2022-04-21T00:00:00+00:002022-04-21T00:00:00+00:00https://grahamenos.com/ttkv-rs<h1 id="previously">Previously…</h1>
<p>We’ve <a href="/time-traveling-kv-store.html">talked</a>
<a href="/ttkv-again.html">previously</a> about implementing a
time-traveling key-value store.
Having worked more with <a href="https://www.rust-lang.org/">Rust</a> in the interim, I
tried my hand at a Rust implementation.
Rust’s type system, standard library, and attention to pedantic details make
this my favorite version yet.</p>
<h1 id="implementation">Implementation</h1>
<p>The standard library provides everything we need:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">collections</span><span class="p">::</span><span class="n">BTreeMap</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">time</span><span class="p">::</span><span class="n">Instant</span><span class="p">;</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">Ttkv</span><span class="o"><</span><span class="n">K</span><span class="p">,</span> <span class="n">V</span><span class="o">></span> <span class="p">{</span>
<span class="n">started</span><span class="p">:</span> <span class="n">Instant</span><span class="p">,</span>
<span class="n">mapping</span><span class="p">:</span> <span class="n">BTreeMap</span><span class="o"><</span><span class="n">u128</span><span class="p">,</span> <span class="p">(</span><span class="n">K</span><span class="p">,</span> <span class="n">V</span><span class="p">)</span><span class="o">></span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Recording the <code class="language-plaintext highlighter-rouge">std::time::Instant</code> when we created our store allows us to
monotonically record insertion timestamps—on most hardware, at least—and we
can still check if this assumption is violated.</p>
<p>We build a new store via implementing <code class="language-plaintext highlighter-rouge">Default</code>:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span><span class="o"><</span><span class="n">K</span><span class="p">,</span> <span class="n">V</span><span class="o">></span> <span class="n">Default</span> <span class="k">for</span> <span class="n">Ttkv</span><span class="o"><</span><span class="n">K</span><span class="p">,</span> <span class="n">V</span><span class="o">></span> <span class="p">{</span>
<span class="k">fn</span> <span class="nf">default</span><span class="p">()</span> <span class="k">-></span> <span class="n">Self</span> <span class="p">{</span>
<span class="n">Self</span> <span class="p">{</span>
<span class="n">started</span><span class="p">:</span> <span class="nn">Instant</span><span class="p">::</span><span class="nf">now</span><span class="p">(),</span>
<span class="n">mapping</span><span class="p">:</span> <span class="nn">BTreeMap</span><span class="p">::</span><span class="nf">default</span><span class="p">(),</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Digging into the implementation (the following snippets are all wrapped in an
<code class="language-plaintext highlighter-rouge">impl</code> block), it’s straightforward to check for emptiness:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">is_empty</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="nb">bool</span> <span class="p">{</span>
<span class="k">self</span><span class="py">.mapping</span><span class="nf">.is_empty</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Adding a pair to our store gives us an opportunity to assert that time is
monotonic:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">put</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="n">K</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">V</span><span class="p">,</span> <span class="n">timestamp</span><span class="p">:</span> <span class="nb">Option</span><span class="o"><</span><span class="n">u128</span><span class="o">></span><span class="p">)</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">t</span> <span class="o">=</span> <span class="n">timestamp</span><span class="nf">.unwrap_or_else</span><span class="p">(||</span> <span class="p">{</span>
<span class="nn">Instant</span><span class="p">::</span><span class="nf">now</span><span class="p">()</span>
<span class="nf">.checked_duration_since</span><span class="p">(</span><span class="k">self</span><span class="py">.started</span><span class="p">)</span>
<span class="nf">.unwrap_or_else</span><span class="p">(||</span> <span class="nd">panic!</span><span class="p">(</span><span class="s">"non-monotonic insertion"</span><span class="p">))</span>
<span class="nf">.as_nanos</span><span class="p">()</span>
<span class="p">});</span>
<span class="k">self</span><span class="py">.mapping</span><span class="nf">.insert</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Retrieval from the store is similar to previous implementations:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">get</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="o">&</span><span class="n">K</span><span class="p">,</span> <span class="n">timestamp</span><span class="p">:</span> <span class="nb">Option</span><span class="o"><</span><span class="n">u128</span><span class="o">></span><span class="p">)</span> <span class="k">-></span> <span class="nb">Option</span><span class="o"><&</span><span class="n">V</span><span class="o">></span>
<span class="k">where</span>
<span class="n">K</span><span class="p">:</span> <span class="n">PartialEq</span><span class="p">,</span>
<span class="p">{</span>
<span class="k">self</span><span class="py">.mapping</span>
<span class="nf">.range</span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="n">timestamp</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="nn">u128</span><span class="p">::</span><span class="n">MAX</span><span class="p">))</span>
<span class="nf">.filter</span><span class="p">(|(</span><span class="mi">_</span><span class="p">,</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="mi">_</span><span class="p">))|</span> <span class="n">k</span> <span class="o">==</span> <span class="n">key</span><span class="p">)</span>
<span class="nf">.last</span><span class="p">()</span>
<span class="nf">.map</span><span class="p">(|(</span><span class="mi">_</span><span class="p">,</span> <span class="p">(</span><span class="mi">_</span><span class="p">,</span> <span class="n">v</span><span class="p">))|</span> <span class="n">v</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Finally, collecting the insertion times in order:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">times</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="nb">Vec</span><span class="o"><</span><span class="n">u128</span><span class="o">></span> <span class="p">{</span>
<span class="k">self</span><span class="py">.mapping</span><span class="nf">.keys</span><span class="p">()</span><span class="nf">.cloned</span><span class="p">()</span><span class="nf">.collect</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>
<h1 id="testing">Testing</h1>
<p>Rust’s (and <code class="language-plaintext highlighter-rouge">cargo</code>’s) approach to testing is a pleasure to use.
We can do regular unit-style tests:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[test]</span>
<span class="k">fn</span> <span class="nf">initially_empty</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">t</span> <span class="o">=</span> <span class="nn">Ttkv</span><span class="p">::</span><span class="o"><</span><span class="nb">String</span><span class="p">,</span> <span class="nb">String</span><span class="o">></span><span class="p">::</span><span class="nf">default</span><span class="p">();</span>
<span class="k">assert</span><span class="o">!</span><span class="p">(</span><span class="n">t</span><span class="nf">.is_empty</span><span class="p">());</span>
<span class="k">assert</span><span class="o">!</span><span class="p">(</span><span class="n">t</span><span class="nf">.times</span><span class="p">()</span><span class="nf">.is_empty</span><span class="p">());</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And with the help of
<a href="https://docs.rs/proptest/latest/proptest/index.html"><code class="language-plaintext highlighter-rouge">proptest</code></a> we can do
property-based testing:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[test]</span>
<span class="k">fn</span> <span class="nf">two_gets_different_keys</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="nb">String</span><span class="p">)</span> <span class="p">{</span>
<span class="nd">prop_assume!</span><span class="p">(</span><span class="n">a</span> <span class="o">!=</span> <span class="n">b</span><span class="p">);</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">t</span> <span class="o">=</span> <span class="nn">Ttkv</span><span class="p">::</span><span class="nf">default</span><span class="p">();</span>
<span class="n">t</span><span class="nf">.put</span><span class="p">(</span><span class="n">a</span><span class="nf">.clone</span><span class="p">(),</span> <span class="n">x</span><span class="nf">.clone</span><span class="p">(),</span> <span class="nb">None</span><span class="p">);</span>
<span class="n">t</span><span class="nf">.put</span><span class="p">(</span><span class="n">b</span><span class="nf">.clone</span><span class="p">(),</span> <span class="n">y</span><span class="nf">.clone</span><span class="p">(),</span> <span class="nb">None</span><span class="p">);</span>
<span class="nd">prop_assert_eq!</span><span class="p">(</span><span class="n">t</span><span class="nf">.times</span><span class="p">()</span><span class="nf">.len</span><span class="p">(),</span> <span class="mi">2</span><span class="p">);</span>
<span class="nd">prop_assert_eq!</span><span class="p">(</span><span class="n">t</span><span class="nf">.get</span><span class="p">(</span><span class="o">&</span><span class="n">a</span><span class="p">,</span> <span class="nb">None</span><span class="p">),</span> <span class="nf">Some</span><span class="p">(</span><span class="o">&</span><span class="n">x</span><span class="p">));</span>
<span class="nd">prop_assert_eq!</span><span class="p">(</span><span class="n">t</span><span class="nf">.get</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">,</span> <span class="nb">None</span><span class="p">),</span> <span class="nf">Some</span><span class="p">(</span><span class="o">&</span><span class="n">y</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>
<p>As a side note, this test originally failed for me in an early draft where the
timestamping mechanism wasn’t monotonic.</p>
<h1 id="fin">Fin.</h1>
<p>This was a fun exercise, and again is probably my favorite implementation.
See <a href="https://github.com/genos/ttkv/tree/main/ttkv_rs">the repo</a> for the full
code!</p>Graham EnosPreviously…Synthetic weather radar using hybrid quantum-classical machine learning2021-12-01T00:00:00+00:002021-12-01T00:00:00+00:00https://grahamenos.com/paper-announcement<h1 id="new-paper">New paper</h1>
<p>I’m excited to announce that our paper on using quantum ML to predict
weather radar products is <a href="https://arxiv.org/abs/2111.15605">up on the arXiv</a>!
What’s more, per the <a href="https://www.globenewswire.com/news-release/2021/12/01/2344216/0/en/Rigetti-Enhances-Predictive-Weather-Modeling-with-Quantum-Machine-Learning.html">press
release</a>,
we’ll be presenting the paper at the <a href="https://www.hadr.ai/">Artificial Intelligence for Humanitarian
Assistance and Disaster Response Workshop</a> at <a href="https://neurips.cc/Conferences/2021/Schedule?showEvent=21858">NeurIPS
2021</a>.</p>Graham EnosNew paperCvRDT Exposition in Rust2020-09-01T00:00:00+00:002020-09-01T00:00:00+00:00https://grahamenos.com/cvrdt-exposition<h1 id="programming-with-types-for-understanding">Programming with types for understanding</h1>
<p>One of the best uses of the type system I’ve seen is the <a href="https://www.microsoft.com/en-us/research/publication/build-systems-la-carte/">Build systems a la carte</a> paper.
In it, the authors use Haskell’s types to outline and explore the problem domain in really novel ways.
I wanted to understand <a href="https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type">CRDTs</a> more, so I made a thing.
It’s nowhere near the level of <em>Build systems a la carte</em>, but I found it useful.</p>
<h1 id="understanding-cvrdts">Understanding CvRDTs</h1>
<p>CRDTs are important to modern distributed programming; as the above Wikipedia article explains, they are</p>
<blockquote>
<p>data structure[s] which can be replicated across multiple computers in a network, where the replicas can be updated independently and concurrently without coordination between the replicas, and where it is always mathematically possible to resolve inconsistencies that might come up.</p>
</blockquote>
<p>In reading about CRDTs, I came across the phenomenal paper <a href="https://hal.inria.fr/inria-00555588/">A comprehensive study of Convergent and Commutative Replicated Data Types</a>.
With this paper, Wikipedia, and some other references as my guide, I made a <a href="https://docs.rs/cvrdt-exposition/">Rust crate</a> to understand state-based CRDTs (a.k.a. convergent replicated data types or CvRDTs).
I really like how this crate uses two traits with associated types to describe CvRDTs, fitting them into a common framework.</p>
<p>The first trait is for CvRDTs that can only grow, i.e. only add items.
Here’s an slightly modified version of it; the code (on <a href="https://github.com/genos/cvrdt-exposition">GitHub</a>, with documentation on <a href="https://docs.rs/cvrdt-exposition/">docs.rs</a>) has more:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">trait</span> <span class="n">Grow</span><span class="p">:</span> <span class="n">Clone</span> <span class="p">{</span>
<span class="k">type</span> <span class="n">Payload</span><span class="p">:</span> <span class="nb">Eq</span><span class="p">;</span> <span class="c">// Internal state</span>
<span class="k">type</span> <span class="n">Update</span><span class="p">;</span> <span class="c">// Message to update internal state</span>
<span class="k">type</span> <span class="n">Query</span><span class="p">;</span> <span class="c">// Query message</span>
<span class="k">type</span> <span class="n">Value</span><span class="p">;</span> <span class="c">// Query response</span>
<span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">payload</span><span class="p">:</span> <span class="nn">Self</span><span class="p">::</span><span class="n">Payload</span><span class="p">)</span> <span class="k">-></span> <span class="n">Self</span><span class="p">;</span> <span class="c">// Create a new version of our CvRDT from Payload</span>
<span class="k">fn</span> <span class="nf">payload</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">)</span> <span class="k">-></span> <span class="nn">Self</span><span class="p">::</span><span class="n">Payload</span><span class="p">;</span> <span class="c">// Retrieve Payload</span>
<span class="k">fn</span> <span class="nf">add</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">update</span><span class="p">:</span> <span class="nn">Self</span><span class="p">::</span><span class="n">Update</span><span class="p">);</span> <span class="c">// Add item, mutating in-place</span>
<span class="k">fn</span> <span class="nf">le</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="o">&</span><span class="n">Self</span><span class="p">)</span> <span class="k">-></span> <span class="nb">bool</span><span class="p">;</span> <span class="c">// Is this ≤ other in semilattice's partial order?</span>
<span class="k">fn</span> <span class="nf">merge</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="o">&</span><span class="n">Self</span><span class="p">)</span> <span class="k">-></span> <span class="n">Self</span><span class="p">;</span> <span class="c">// Merge this and other into new CvRDT</span>
<span class="k">fn</span> <span class="nf">query</span><span class="p">(</span><span class="o">&</span><span class="k">self</span><span class="p">,</span> <span class="n">query</span><span class="p">:</span> <span class="o">&</span><span class="nn">Self</span><span class="p">::</span><span class="n">Query</span><span class="p">)</span> <span class="k">-></span> <span class="nn">Self</span><span class="p">::</span><span class="n">Value</span><span class="p">;</span> <span class="c">// Query to get some Value</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Our rigorous typing does make for one difference from the aforementioned <a href="https://hal.inria.fr/inria-00555588/">paper</a> and Wikipedia.
When implementing <a href="https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type#G-Counter_(Grow-only_Counter)"><code class="language-plaintext highlighter-rouge">GCounter</code>s</a> and <a href="https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type#PN-Counter_(Positive-Negative_Counter)"><code class="language-plaintext highlighter-rouge">PNCounter</code>s</a>, we no longer have an unspecified <code class="language-plaintext highlighter-rouge">myId()</code> function giving the current node’s index.
In order for the <code class="language-plaintext highlighter-rouge">Payload</code> type to fully specify their internal state, these classes require that index be part of the payload.</p>
<p>Other CvRDTs can also shrink, i.e. remove items.
Here’s a slightly modified version of <code class="language-plaintext highlighter-rouge">cvrdt-exposition</code>’s trait:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">trait</span> <span class="n">Shrink</span><span class="p">:</span> <span class="n">Grow</span> <span class="p">{</span>
<span class="k">fn</span> <span class="nf">del</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">update</span><span class="p">:</span> <span class="nn">Self</span><span class="p">::</span><span class="n">Update</span><span class="p">);</span> <span class="c">// Delete item, mutating in-place</span>
<span class="p">}</span>
</code></pre></div></div>
<h1 id="testing-and-verification">Testing and Verification</h1>
<p>We have the <code class="language-plaintext highlighter-rouge">Eq</code> bound on the <code class="language-plaintext highlighter-rouge">Payload</code> type for verification and testing.
In order to verify that my CvRDT implementations behave as required, i.e. that their merge functions are commutative, associative, and idempotent, I turned to the <a href="https://crates.io/crates/proptest"><code class="language-plaintext highlighter-rouge">proptest</code></a> crate for property-based testing, via <code class="language-plaintext highlighter-rouge">assert_eq!</code> calls.
I turned to Rust’s macro system to generate some of these tests for me; see <a href="https://github.com/genos/cvrdt-exposition/blob/main/src/properties.rs"><code class="language-plaintext highlighter-rouge">properties.rs</code></a> in the GitHub source and the <code class="language-plaintext highlighter-rouge">test</code> sub-modules of the <a href="https://github.com/genos/cvrdt-exposition/tree/main/src">implementation modules</a> for more.</p>Graham EnosProgramming with types for understandingTiny REST API Demo in Python2020-08-17T00:00:00+00:002020-08-17T00:00:00+00:00https://grahamenos.com/tiny-api-demo<h1 id="introduction">Introduction</h1>
<p>The other day, someone asked me about the difference between “an API and a regular webpage.”
After understanding more about the context of their question, I tried to come up with a decent explanation about the differences between a server sending HTML pages and one handling REST API requests.
As <a href="https://en.wikipedia.org/wiki/A_picture_is_worth_a_thousand_words#History">a thousand words leave not the same deep impression as does a single deed</a>, I thought I’d put together a tiny demonstration that serves HTML to a web browser and JSON over a REST endpoint.
My demo uses the <a href="https://flask.palletsprojects.com/">Flask</a> microframework to handle the details; you can find a copy <a href="https://github.com/genos/tiny_api_demo">here</a>, though we’ll go through some of it below.</p>
<h1 id="how-smol">How smol?</h1>
<p>Before we get into the specifics, here’s how tiny the demo is: the whole thing, including a <code class="language-plaintext highlighter-rouge">flake.nix</code> file to set the stage, is under 115 lines.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/github/tiny_api_demo ∃ tokei
===============================================================================
Language Files Lines Code Comments Blanks
===============================================================================
CSS 1 10 10 0 0
HTML 3 41 41 0 0
Markdown 1 10 0 6 4
Nix 1 25 23 0 2
Python 2 54 40 2 12
===============================================================================
Total 8 140 114 8 18
===============================================================================
</code></pre></div></div>
<p>This whole thing cuts so many corners it might as well be a sphere.
It’s <em>certainly</em> not a production-ready example by <em>any</em> stretch of the imagination; it’s only enough for demonstration purposes.</p>
<h1 id="preliminaries">Preliminaries</h1>
<p>First, we need some data.
Pretend we’re creating the <em>School Reporter 5000™</em>, wherein we have student information that consists of a collection of <code class="language-plaintext highlighter-rouge">(timestamp, person, activity)</code> tuples.
In <code class="language-plaintext highlighter-rouge">data.py</code>, we generate some fake data.
Our application code will interface with this data via <code class="language-plaintext highlighter-rouge">NAMES</code> and <code class="language-plaintext highlighter-rouge">SELECT</code>; pretend this stands in for a proper database.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from datetime import datetime, timedelta
from itertools import accumulate
from operator import add
import random
random.seed(1729)
NAMES = ["Alice", "Bob", "Carol", "Dave"]
_ACTIVITIES = ["Reading", "Writing", "Arithmetic"]
_DATA = [
{
"timestamp": ts.time().isoformat(timespec="minutes"),
"person": random.choice(NAMES),
"activity": random.choice(_ACTIVITIES),
}
for ts in accumulate(
(timedelta(minutes=random.randrange(17)) for _ in range(42)),
func=add,
initial=datetime.today().replace(hour=9),
)
]
SELECT = {name: [x for x in _DATA if x["person"] == name] for name in NAMES}
</code></pre></div></div>
<h1 id="app">App</h1>
<p>The <em>School Reporter 5000™</em> has three routes, all described in <code class="language-plaintext highlighter-rouge">app.py</code>.
We serve HTML for the homepage at <code class="language-plaintext highlighter-rouge">/index.html</code> and individual person pages at <code class="language-plaintext highlighter-rouge">/person/<name></code> for each of the names in <code class="language-plaintext highlighter-rouge">NAMES</code>.
We also serve JSON in response to GET requests via the <code class="language-plaintext highlighter-rouge">/api/<name></code> route.
Thanks to <a href="https://flask.palletsprojects.com/">Flask</a>, we even have rudimentary error handling.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from flask import Flask, jsonify, render_template
from data import NAMES, SELECT
app = Flask(__name__)
@app.route("/")
def home():
return render_template("index.html", names=NAMES)
@app.route("/person/<string:name>")
def person(name):
try:
return render_template("person.html", name=name, data=SELECT[name], error=False)
except KeyError:
return render_template("person.html", name=name, error=True), 400
@app.route("/api/<string:name>")
def api(name):
try:
return jsonify(SELECT[name])
except KeyError:
return {"error": f"Unknown person {name}"}, 400
</code></pre></div></div>
<p>With the server running, we can visit the home page:</p>
<p><img src="https://grahamenos.com/public/tiny_api_demo_index.png" alt="Homepage" /></p>
<p>Or report pages for any specific student:</p>
<p><img src="https://grahamenos.com/public/tiny_api_demo_alice.png" alt="Alice's page" /></p>
<p>However, we can also get JSON data for individual students by pinging the REST endpoint; using, e.g. <a href="https://httpie.org">HTTPie</a> to query the endpoint via <code class="language-plaintext highlighter-rouge">http --body :5000/api/Dave</code>, we get</p>
<p><img src="https://grahamenos.com/public/tiny_api_demo_dave.png " alt="Dave's JSON" /></p>
<h1 id="everything-else">Everything Else</h1>
<p>To round out the example, we also have <a href="https://github.com/genos/tiny_api_demo/blob/main/static/styles.css">some minimal CSS</a> and <a href="https://github.com/genos/tiny_api_demo/blob/main/templates">two other HTML templates</a>.
Here’s the <code class="language-plaintext highlighter-rouge">flake.nix</code> to specify the W O R L D:</p>
<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span>
<span class="nv">description</span> <span class="o">=</span> <span class="s2">"Tiny API Demo"</span><span class="p">;</span>
<span class="nv">inputs</span> <span class="o">=</span> <span class="p">{</span>
<span class="nv">flake-utils</span><span class="o">.</span><span class="nv">url</span> <span class="o">=</span> <span class="s2">"github:numtide/flake-utils"</span><span class="p">;</span>
<span class="nv">nixpkgs</span><span class="o">.</span><span class="nv">url</span> <span class="o">=</span> <span class="s2">"github:NixOS/nixpkgs/nixos-22.11"</span><span class="p">;</span>
<span class="p">};</span>
<span class="nv">outputs</span> <span class="o">=</span> <span class="p">{</span>
<span class="nv">self</span><span class="p">,</span>
<span class="nv">flake-utils</span><span class="p">,</span>
<span class="nv">nixpkgs</span><span class="p">,</span>
<span class="p">}:</span>
<span class="nv">flake-utils</span><span class="o">.</span><span class="nv">lib</span><span class="o">.</span><span class="nv">eachDefaultSystem</span> <span class="p">(</span><span class="nv">system</span><span class="p">:</span> <span class="kd">let</span>
<span class="nv">pkgs</span> <span class="o">=</span> <span class="kr">import</span> <span class="nv">nixpkgs</span> <span class="p">{</span><span class="kn">inherit</span> <span class="nv">system</span><span class="p">;};</span>
<span class="nv">py</span> <span class="o">=</span> <span class="nv">pkgs</span><span class="o">.</span><span class="nv">python310</span><span class="o">.</span><span class="nv">withPackages</span> <span class="p">(</span><span class="nv">p</span><span class="p">:</span> <span class="p">[</span><span class="nv">p</span><span class="o">.</span><span class="nv">flask</span><span class="p">]);</span>
<span class="kn">in</span> <span class="p">{</span>
<span class="nv">packages</span><span class="o">.</span><span class="nv">default</span> <span class="o">=</span> <span class="nv">pkgs</span><span class="o">.</span><span class="nv">writeShellApplication</span> <span class="p">{</span>
<span class="nv">name</span> <span class="o">=</span> <span class="s2">"tiny_api_demo"</span><span class="p">;</span>
<span class="nv">text</span> <span class="o">=</span> <span class="s2">''</span><span class="err">
</span><span class="s2"> FLASK_APP=app.py </span><span class="si">${</span><span class="nv">py</span><span class="si">}</span><span class="s2">/bin/python -m flask run</span><span class="err">
</span><span class="s2"> ''</span><span class="p">;</span>
<span class="p">};</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<p>From the base directory, one can run <code class="language-plaintext highlighter-rouge">nix run</code> to set up the environment and kick off the server.</p>Graham EnosIntroduction